Bug 1239152 Memset RGBX surfaces to opaque white. r=nical
authorMason Chang <mchang@mozilla.com>
Wed, 17 Feb 2016 07:34:37 -0800
changeset 331621 266e1a6642b10ac593587674119db65f6aeb0da5
parent 331620 6bb9aa94a48eb0a7d69d9b07d8bf10400861a6a9
child 331622 22d0921df35a835486e42e258487bcb1d82567af
push id11020
push userjolesen@mozilla.com
push dateWed, 17 Feb 2016 18:16:38 +0000
reviewersnical
bugs1239152
milestone47.0a1
Bug 1239152 Memset RGBX surfaces to opaque white. r=nical
gfx/2d/DrawTargetSkia.cpp
gfx/layers/BufferTexture.cpp
gfx/layers/client/ContentClient.cpp
gfx/layers/client/TextureClient.cpp
gfx/layers/client/TextureClient.h
widget/nsShmImage.cpp
--- a/gfx/2d/DrawTargetSkia.cpp
+++ b/gfx/2d/DrawTargetSkia.cpp
@@ -904,23 +904,45 @@ DrawTargetSkia::InitWithGrContext(GrCont
 
   mCanvas = gpuSurface->getCanvas();
 
   return true;
 }
 
 #endif
 
+#ifdef DEBUG
+bool
+VerifyRGBXFormat(uint8_t* aData, const IntSize &aSize, const int32_t aStride, SurfaceFormat aFormat)
+{
+  // We should've initialized the data to be opaque already
+  // On debug builds, verify that this is actually true.
+  int height = aSize.height;
+  int width = aSize.width;
+
+  for (int row = 0; row < height; ++row) {
+    for (int column = 0; column < width; column += 4) {
+#ifdef IS_BIG_ENDIAN
+      MOZ_ASSERT(aData[column] == 0xFF);
+#else
+      MOZ_ASSERT(aData[column + 3] == 0xFF);
+#endif
+    }
+    aData += aStride;
+  }
+
+  return true;
+}
+#endif
+
 void
 DrawTargetSkia::Init(unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat)
 {
-  if (aFormat == SurfaceFormat::B8G8R8X8) {
-    // We have to manually set the A channel to be 255 as Skia doesn't understand BGRX
-    ConvertBGRXToBGRA(aData, aSize, aStride);
-  }
+  MOZ_ASSERT((aFormat != SurfaceFormat::B8G8R8X8) ||
+              VerifyRGBXFormat(aData, aSize, aStride, aFormat));
 
   SkBitmap bitmap;
   bitmap.setInfo(MakeSkiaImageInfo(aSize, aFormat), aStride);
   bitmap.setPixels(aData);
 
   mCanvas.adopt(new SkCanvas(bitmap));
 
   mSize = aSize;
--- a/gfx/layers/BufferTexture.cpp
+++ b/gfx/layers/BufferTexture.cpp
@@ -364,19 +364,21 @@ MemoryTextureData::Serialize(SurfaceDesc
 
 static bool InitBuffer(uint8_t* buf, size_t bufSize, TextureAllocationFlags aAllocFlags)
 {
   if (!buf) {
     gfxDebug() << "BufferTextureData: Failed to allocate " << bufSize << " bytes";
     return false;
   }
 
-  if (aAllocFlags & ALLOC_CLEAR_BUFFER) {
+  if ((aAllocFlags & ALLOC_CLEAR_BUFFER) ||
+      (aAllocFlags & ALLOC_CLEAR_BUFFER_BLACK)) {
     memset(buf, 0, bufSize);
   }
+
   if (aAllocFlags & ALLOC_CLEAR_BUFFER_WHITE) {
     memset(buf, 0xFF, bufSize);
   }
 
   return true;
 }
 
 MemoryTextureData*
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -285,20 +285,25 @@ ContentClientRemoteBuffer::BuildTextureC
 
   CreateBackBuffer(mBufferRect);
 }
 
 void
 ContentClientRemoteBuffer::CreateBackBuffer(const IntRect& aBufferRect)
 {
   // gfx::BackendType::NONE means fallback to the content backend
+  TextureAllocationFlags textureAllocFlags
+                         = (mTextureFlags & TextureFlags::COMPONENT_ALPHA) ?
+                            TextureAllocationFlags::ALLOC_CLEAR_BUFFER_BLACK :
+                            TextureAllocationFlags::ALLOC_CLEAR_BUFFER;
+
   mTextureClient = CreateTextureClientForDrawing(
     mSurfaceFormat, mSize, BackendSelector::Content,
     mTextureFlags | ExtraTextureFlags(),
-    TextureAllocationFlags::ALLOC_CLEAR_BUFFER
+    textureAllocFlags
   );
   if (!mTextureClient || !AddTextureClient(mTextureClient)) {
     AbortTextureClientCreation();
     return;
   }
 
   if (mTextureFlags & TextureFlags::COMPONENT_ALPHA) {
     mTextureClientOnWhite = mTextureClient->CreateSimilar(
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -828,16 +828,23 @@ TextureClient::CreateForRawBufferAccess(
   if (aAllocFlags & ALLOC_DISALLOW_BUFFERTEXTURECLIENT) {
     return nullptr;
   }
 
   if (!gfx::Factory::AllowedSurfaceSize(aSize)) {
     return nullptr;
   }
 
+  if (aFormat == SurfaceFormat::B8G8R8X8 &&
+      (aAllocFlags != TextureAllocationFlags::ALLOC_CLEAR_BUFFER_BLACK) &&
+      aMoz2DBackend == gfx::BackendType::SKIA) {
+    // skia requires alpha component of RGBX textures to be 255.
+    aAllocFlags = TextureAllocationFlags::ALLOC_CLEAR_BUFFER_WHITE;
+  }
+
   TextureData* texData = BufferTextureData::Create(aSize, aFormat, aMoz2DBackend,
                                                    aTextureFlags, aAllocFlags,
                                                    aAllocator);
   if (!texData) {
     return nullptr;
   }
 
   return MakeAndAddRef<TextureClient>(texData, aTextureFlags, aAllocator);
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -64,25 +64,26 @@ class TextureClientPool;
 class KeepAlive;
 
 /**
  * TextureClient is the abstraction that allows us to share data between the
  * content and the compositor side.
  */
 
 enum TextureAllocationFlags {
-  ALLOC_DEFAULT = 0x0,
-  ALLOC_CLEAR_BUFFER = 0x1,
-  ALLOC_CLEAR_BUFFER_WHITE = 0x2,
-  ALLOC_DISALLOW_BUFFERTEXTURECLIENT = 0x4,
+  ALLOC_DEFAULT = 0,
+  ALLOC_CLEAR_BUFFER = 1 << 1,  // Clear the buffer to whatever is best for the draw target
+  ALLOC_CLEAR_BUFFER_WHITE = 1 << 2,  // explicit all white
+  ALLOC_CLEAR_BUFFER_BLACK = 1 << 3,  // explicit all black
+  ALLOC_DISALLOW_BUFFERTEXTURECLIENT = 1 << 4,
 
   // Allocate the texture for out-of-band content updates. This is mostly for
   // TextureClientD3D11, which may otherwise choose D3D10 or non-KeyedMutex
   // surfaces when used on the main thread.
-  ALLOC_FOR_OUT_OF_BAND_CONTENT = 0x8
+  ALLOC_FOR_OUT_OF_BAND_CONTENT = 1 << 5,
 };
 
 #ifdef XP_WIN
 typedef void* SyncHandle;
 #else
 typedef uintptr_t SyncHandle;
 #endif // XP_WIN
 
--- a/widget/nsShmImage.cpp
+++ b/widget/nsShmImage.cpp
@@ -94,30 +94,33 @@ nsShmImage::Create(const LayoutDeviceInt
     shm->mXAttached = true;
     shm->mSize = aSize;
     switch (shm->mImage->depth) {
     case 32:
         if ((shm->mImage->red_mask == 0xff0000) &&
             (shm->mImage->green_mask == 0xff00) &&
             (shm->mImage->blue_mask == 0xff)) {
             shm->mFormat = SurfaceFormat::B8G8R8A8;
+            memset(shm->mSegment->memory(), 0, size);
             break;
         }
         goto unsupported;
     case 24:
         // Only xRGB is supported.
         if ((shm->mImage->red_mask == 0xff0000) &&
             (shm->mImage->green_mask == 0xff00) &&
             (shm->mImage->blue_mask == 0xff)) {
             shm->mFormat = SurfaceFormat::B8G8R8X8;
+            memset(shm->mSegment->memory(), 0xFF, size);
             break;
         }
         goto unsupported;
     case 16:
         shm->mFormat = SurfaceFormat::R5G6B5_UINT16;
+        memset(shm->mSegment->memory(), 0, size);
         break;
     unsupported:
     default:
         NS_WARNING("Unsupported XShm Image format!");
         gShmAvailable = false;
         return nullptr;
     }
     return shm.forget();