Bug 770033 - Part 3: Deal with extend modes for D2D partial bitmap uploads. r=jrmuizel
authorBas Schouten <bschouten@mozilla.com>
Wed, 04 Jul 2012 20:23:16 +0200
changeset 98335 94d461c799fd965451180ed91862b3433c7eb538
parent 98334 a5b33148ae58dcb75935648bde60dab70c4bf8ba
child 98336 555989fb3764d50b107fa7cd49c0f1d4fdfb5622
child 98386 1ccd7094cd5e8ded37777bdd053a47bf47985f46
push id23043
push userryanvm@gmail.com
push dateWed, 04 Jul 2012 23:22:35 +0000
treeherdermozilla-central@555989fb3764 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs770033
milestone16.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 770033 - Part 3: Deal with extend modes for D2D partial bitmap uploads. r=jrmuizel
gfx/2d/DrawTargetD2D.cpp
gfx/2d/DrawTargetD2D.h
--- a/gfx/2d/DrawTargetD2D.cpp
+++ b/gfx/2d/DrawTargetD2D.cpp
@@ -2061,17 +2061,17 @@ DrawTargetD2D::CreateBrushForPattern(con
         bitmap = surf->GetBitmap(mRT);
         AddDependencyOnSource(surf);
       }
       break;
     case SURFACE_DATA:
       {
         DataSourceSurface *dataSurf =
           static_cast<DataSourceSurface*>(pat->mSurface.get());
-        bitmap = CreatePartialBitmapForSurface(dataSurf, mat);
+        bitmap = CreatePartialBitmapForSurface(dataSurf, mat, pat->mExtendMode);
         
         if (!bitmap) {
           return NULL;
         }
       }
       break;
     default:
       break;
@@ -2296,18 +2296,19 @@ DrawTargetD2D::CreateTextureForAnalysis(
   delete [] texture;
 
   if (FAILED(hr)) {
     return NULL;
   }
 
   return tex;
 }
+
 TemporaryRef<ID2D1Bitmap>
-DrawTargetD2D::CreatePartialBitmapForSurface(DataSourceSurface *aSurface, Matrix &aMatrix)
+DrawTargetD2D::CreatePartialBitmapForSurface(DataSourceSurface *aSurface, Matrix &aMatrix, ExtendMode aExtendMode)
 {
   RefPtr<ID2D1Bitmap> bitmap;
 
   // This is where things get complicated. The source surface was
   // created for a surface that was too large to fit in a texture.
   // We'll need to figure out if we can work with a partial upload
   // or downsample in software.
 
@@ -2323,26 +2324,50 @@ DrawTargetD2D::CreatePartialBitmapForSur
   // Calculate the rectangle of the source mapped to our surface.
   rect = invTransform.TransformBounds(rect);
   rect.RoundOut();
 
   IntSize size = aSurface->GetSize();
 
   Rect uploadRect(0, 0, size.width, size.height);
 
-  // Calculate the rectangle on the source bitmap that touches our
-  // surface.
-  uploadRect = uploadRect.Intersect(rect);
-
-  if (uploadRect.IsEmpty()) {
-    // This bitmap does not cover anything on the screen. XXX -
-    // we need to deal with EXTEND modes here!
-    return NULL;
+  // Limit the uploadRect as much as possible without supporting discontiguous uploads 
+  //
+  //                               region we will paint from
+  //   uploadRect
+  //   .---------------.              .---------------.         resulting uploadRect
+  //   |               |rect          |               |
+  //   |          .---------.         .----.     .----.          .---------------.
+  //   |          |         |  ---->  |    |     |    |   ---->  |               |
+  //   |          '---------'         '----'     '----'          '---------------'
+  //   '---------------'              '---------------'
+  //
+  //
+
+  if (uploadRect.Contains(rect)) {
+    // Extend mode is irrelevant, the displayed rect is completely contained
+    // by the source bitmap.
+    uploadRect = rect;
+  } else if (aExtendMode == EXTEND_CLAMP && uploadRect.Intersects(rect)) {
+    // Calculate the rectangle on the source bitmap that touches our
+    // surface, and upload that, for EXTEND_CLAMP we can actually guarantee
+    // correct behaviour in this case.
+    uploadRect = uploadRect.Intersect(rect);
+
+    // We now proceed to check if we can limit at least one dimension of the
+    // upload rect safely without looking at extend mode.
+  } else if (rect.x >= 0 && rect.XMost() < size.width) {
+    uploadRect.x = rect.x;
+    uploadRect.width = rect.width;
+  } else if (rect.y >= 0 && rect.YMost() < size.height) {
+    uploadRect.y = rect.y;
+    uploadRect.height = rect.height;
   }
 
+
   int stride = aSurface->Stride();
 
   if (uploadRect.width <= mRT->GetMaximumBitmapSize() &&
       uploadRect.height <= mRT->GetMaximumBitmapSize()) {
 
     // A partial upload will suffice.
     mRT->CreateBitmap(D2D1::SizeU(uint32_t(uploadRect.width), uint32_t(uploadRect.height)),
                       aSurface->GetData() + int(uploadRect.x) * 4 + int(uploadRect.y) * stride,
--- a/gfx/2d/DrawTargetD2D.h
+++ b/gfx/2d/DrawTargetD2D.h
@@ -187,17 +187,18 @@ private:
   TemporaryRef<ID2D1Brush> CreateBrushForPattern(const Pattern &aPattern, Float aAlpha = 1.0f);
 
   TemporaryRef<ID3D10Texture2D> CreateGradientTexture(const GradientStopsD2D *aStops);
   TemporaryRef<ID3D10Texture2D> CreateTextureForAnalysis(IDWriteGlyphRunAnalysis *aAnalysis, const IntRect &aBounds);
 
   // This creates a (partially) uploaded bitmap for a DataSourceSurface. It
   // uploads the minimum requirement and possibly downscales. It adjusts the
   // input Matrix to compensate.
-  TemporaryRef<ID2D1Bitmap> CreatePartialBitmapForSurface(DataSourceSurface *aSurface, Matrix &aMatrix);
+  TemporaryRef<ID2D1Bitmap> CreatePartialBitmapForSurface(DataSourceSurface *aSurface, Matrix &aMatrix,
+                                                          ExtendMode aExtendMode);
 
   void SetupEffectForRadialGradient(const RadialGradientPattern *aPattern);
   void SetupStateForRendering();
 
   static const uint32_t test = 4;
 
   IntSize mSize;