static TemporaryRef<DataSourceSurface> YInvertImageSurface(DataSourceSurface* aSurf) { RefPtr<DataSourceSurface> temp = Factory::CreateDataSourceSurfaceWithStride(aSurf->GetSize(), aSurf->GetFormat(), aSurf->Stride()); RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(BackendType::CAIRO, temp->GetData(), temp->GetSize(), temp->Stride(), temp->GetFormat()); nsRefPtr<gfxContext> ctx = new gfxContext(dt); ctx->SetOperator(gfxContext::OPERATOR_SOURCE); ctx->Scale(1.0, -1.0); ctx->Translate(-gfxPoint(0.0, aSurf->GetSize().height)); nsRefPtr<gfxImageSurface> thebesSurf = new gfxImageSurface(aSurf->GetData(), ThebesIntSize(aSurf->GetSize()), aSurf->Stride(), SurfaceFormatToImageFormat(aSurf->GetFormat())); ctx->SetSource(thebesSurf); ctx->Paint(); return temp.forget(); }
X11TextureData* X11TextureData::Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat, TextureFlags aFlags, LayersIPCChannel* aAllocator) { MOZ_ASSERT(aSize.width >= 0 && aSize.height >= 0); if (aSize.width <= 0 || aSize.height <= 0 || aSize.width > XLIB_IMAGE_SIDE_SIZE_LIMIT || aSize.height > XLIB_IMAGE_SIDE_SIZE_LIMIT) { gfxDebug() << "Asking for X11 surface of invalid size " << aSize.width << "x" << aSize.height; return nullptr; } gfxImageFormat imageFormat = SurfaceFormatToImageFormat(aFormat); RefPtr<gfxASurface> surface = gfxPlatform::GetPlatform()->CreateOffscreenSurface(aSize, imageFormat); if (!surface || surface->GetType() != gfxSurfaceType::Xlib) { NS_ERROR("creating Xlib surface failed!"); return nullptr; } gfxXlibSurface* xlibSurface = static_cast<gfxXlibSurface*>(surface.get()); bool crossProcess = !aAllocator->IsSameProcess(); X11TextureData* texture = new X11TextureData( aSize, aFormat, !!(aFlags & TextureFlags::DEALLOCATE_CLIENT), crossProcess, xlibSurface); if (crossProcess) { FinishX(DefaultXDisplay()); } return texture; }
void SharedSurface_EGLImage::Fence() { MutexAutoLock lock(mMutex); mGL->MakeCurrent(); if (!mPipeActive) { MOZ_ASSERT(!mSync); MOZ_ASSERT(!mPipeComplete); if (!mPipeFailed) { if (!CreateTexturePipe(mEGL, mGL, mFormats, Size(), &mProdTexForPipe, &mImage)) { mPipeFailed = true; } } if (!mPixels) { SurfaceFormat format = HasAlpha() ? SurfaceFormat::B8G8R8A8 : SurfaceFormat::B8G8R8X8; mPixels = Factory::CreateDataSourceSurface(Size(), format); } nsRefPtr<gfxImageSurface> wrappedData = new gfxImageSurface(mPixels->GetData(), ThebesIntSize(mPixels->GetSize()), mPixels->Stride(), SurfaceFormatToImageFormat(mPixels->GetFormat())); ReadScreenIntoImageSurface(mGL, wrappedData); mPixels->MarkDirty(); return; } MOZ_ASSERT(mPipeActive); MOZ_ASSERT(mCurConsGL); if (mEGL->IsExtensionSupported(GLLibraryEGL::KHR_fence_sync) && mGL->IsExtensionSupported(GLContext::OES_EGL_sync)) { if (mSync) { MOZ_ALWAYS_TRUE( mEGL->fDestroySync(Display(), mSync) ); mSync = 0; } mSync = mEGL->fCreateSync(Display(), LOCAL_EGL_SYNC_FENCE, nullptr); if (mSync) { mGL->fFlush(); return; } } MOZ_ASSERT(!mSync); mGL->fFinish(); }
bool TextureImageTextureSourceOGL::Update(gfx::DataSourceSurface* aSurface, nsIntRegion* aDestRegion, gfx::IntPoint* aSrcOffset) { MOZ_ASSERT(mGL); if (!mGL) { NS_WARNING("trying to update TextureImageTextureSourceOGL without a GLContext"); return false; } MOZ_ASSERT(aSurface); IntSize size = aSurface->GetSize(); if (!mTexImage || (mTexImage->GetSize() != size && !aSrcOffset) || mTexImage->GetContentType() != gfx::ContentForFormat(aSurface->GetFormat())) { if (mFlags & TEXTURE_DISALLOW_BIGIMAGE) { mTexImage = CreateBasicTextureImage(mGL, size, gfx::ContentForFormat(aSurface->GetFormat()), WrapMode(mGL, mFlags & TEXTURE_ALLOW_REPEAT), FlagsToGLFlags(mFlags), SurfaceFormatToImageFormat(aSurface->GetFormat())); } else { // XXX - clarify which size we want to use. IncrementalContentHost will // require the size of the destination surface to be different from // the size of aSurface. // See bug 893300 (tracks the implementation of ContentHost for new textures). mTexImage = CreateTextureImage(mGL, size, gfx::ContentForFormat(aSurface->GetFormat()), WrapMode(mGL, mFlags & TEXTURE_ALLOW_REPEAT), FlagsToGLFlags(mFlags), SurfaceFormatToImageFormat(aSurface->GetFormat())); } ClearCachedFilter(); } mTexImage->UpdateFromDataSource(aSurface, aDestRegion, aSrcOffset); if (mTexImage->InUpdate()) { mTexImage->EndUpdate(); } return true; }
bool X11DataTextureSourceBasic::Update(gfx::DataSourceSurface* aSurface, nsIntRegion* aDestRegion, gfx::IntPoint* aSrcOffset) { // Reallocate our internal X11 surface if we don't have a DrawTarget yet, // or if we changed surface size or format since last update. if (!mBufferDrawTarget || (aSurface->GetSize() != mBufferDrawTarget->GetSize()) || (aSurface->GetFormat() != mBufferDrawTarget->GetFormat())) { nsRefPtr<gfxASurface> surf; gfxImageFormat imageFormat = SurfaceFormatToImageFormat(aSurface->GetFormat()); Display *display = DefaultXDisplay(); Screen *screen = DefaultScreenOfDisplay(display); XRenderPictFormat *xrenderFormat = gfxXlibSurface::FindRenderFormat(display, imageFormat); if (xrenderFormat) { surf = gfxXlibSurface::Create(screen, xrenderFormat, ThebesIntSize(aSurface->GetSize())); } if (!surf) { NS_WARNING("Couldn't create native surface, fallback to image surface"); surf = new gfxImageSurface(ThebesIntSize(aSurface->GetSize()), imageFormat); } mBufferDrawTarget = gfxPlatform::GetPlatform()-> CreateDrawTargetForSurface(surf, aSurface->GetSize()); } // Image contents have changed, upload to our DrawTarget // If aDestRegion is null, means we're updating the whole surface // Note : Incremental update with a source offset is only used on Mac. NS_ASSERTION(!aSrcOffset, "SrcOffset should not be used with linux OMTC basic"); if (aDestRegion) { nsIntRegionRectIterator iter(*aDestRegion); while (const nsIntRect* iterRect = iter.Next()) { IntRect srcRect(iterRect->x, iterRect->y, iterRect->width, iterRect->height); IntPoint dstPoint(iterRect->x, iterRect->y); // We're uploading regions to our buffer, so let's just copy contents over mBufferDrawTarget->CopySurface(aSurface, srcRect, dstPoint); } } else { // We're uploading the whole buffer, so let's just copy the full surface IntSize size = aSurface->GetSize(); mBufferDrawTarget->CopySurface(aSurface, IntRect(0, 0, size.width, size.height), IntPoint(0, 0)); } return true; }
DIBTextureData* MemoryDIBTextureData::Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat) { RefPtr<gfxWindowsSurface> surface = new gfxWindowsSurface(aSize, SurfaceFormatToImageFormat(aFormat)); if (!surface || surface->CairoStatus()) { NS_WARNING("Could not create DIB surface"); return nullptr; } return new MemoryDIBTextureData(aSize, aFormat, surface); }
void GLScreenBuffer::Readback(SharedSurface_GL* src, DataSourceSurface* dest) { MOZ_ASSERT(src && dest); DataSourceSurface::MappedSurface ms; dest->Map(DataSourceSurface::MapType::READ, &ms); nsRefPtr<gfxImageSurface> wrappedDest = new gfxImageSurface(ms.mData, ThebesIntSize(dest->GetSize()), ms.mStride, SurfaceFormatToImageFormat(dest->GetFormat())); DeprecatedReadback(src, wrappedDest); dest->Unmap(); }
// Run the test for a texture client and a surface void TestTextureClientSurface(TextureClient* texture, gfxImageSurface* surface) { // client allocation ASSERT_TRUE(texture->CanExposeDrawTarget()); ASSERT_TRUE(texture->Lock(OpenMode::OPEN_READ_WRITE)); // client painting RefPtr<DrawTarget> dt = texture->BorrowDrawTarget(); RefPtr<SourceSurface> source = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, surface); dt->CopySurface(source, IntRect(IntPoint(), source->GetSize()), IntPoint()); RefPtr<SourceSurface> snapshot = dt->Snapshot(); AssertSurfacesEqual(snapshot, source); dt = nullptr; // drop reference before calling Unlock() texture->Unlock(); // client serialization SurfaceDescriptor descriptor; ASSERT_TRUE(texture->ToSurfaceDescriptor(descriptor)); ASSERT_NE(descriptor.type(), SurfaceDescriptor::Tnull_t); // host deserialization RefPtr<TextureHost> host = CreateBackendIndependentTextureHost(descriptor, nullptr, texture->GetFlags()); ASSERT_TRUE(host.get() != nullptr); ASSERT_EQ(host->GetFlags(), texture->GetFlags()); // host read // XXX - this can fail because lock tries to upload the texture but it needs a // Compositor to do that. We could add a DummyComposior for testing but I am // not sure it'll be worth it. Maybe always test against a BasicCompositor, // but the latter needs a widget... if (host->Lock()) { RefPtr<mozilla::gfx::DataSourceSurface> hostDataSurface = host->GetAsSurface(); RefPtr<gfxImageSurface> hostSurface = new gfxImageSurface(hostDataSurface->GetData(), hostDataSurface->GetSize(), hostDataSurface->Stride(), SurfaceFormatToImageFormat(hostDataSurface->GetFormat())); AssertSurfacesEqual(surface, hostSurface.get()); host->Unlock(); } }
void SharedSurface_Basic::Fence() { mGL->MakeCurrent(); ScopedBindFramebuffer autoFB(mGL, mFB); DataSourceSurface::MappedSurface map; mData->Map(DataSourceSurface::MapType::WRITE, &map); nsRefPtr<gfxImageSurface> wrappedData = new gfxImageSurface(map.mData, ThebesIntSize(mData->GetSize()), map.mStride, SurfaceFormatToImageFormat(mData->GetFormat())); ReadPixelsIntoImageSurface(mGL, wrappedData); mData->Unmap(); }
// Run the test for a texture client and a surface void TestTextureClientSurface(TextureClient* texture, gfxImageSurface* surface) { // client allocation ASSERT_TRUE(texture->CanExposeDrawTarget()); texture->AllocateForSurface(ToIntSize(surface->GetSize())); ASSERT_TRUE(texture->IsAllocated()); ASSERT_TRUE(texture->Lock(OPEN_READ_WRITE)); // client painting RefPtr<DrawTarget> dt = texture->GetAsDrawTarget(); RefPtr<SourceSurface> source = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, surface); dt->CopySurface(source, IntRect(IntPoint(), source->GetSize()), IntPoint()); RefPtr<SourceSurface> snapshot = dt->Snapshot(); AssertSurfacesEqual(snapshot, source); dt = nullptr; // drop reference before calling Unlock() texture->Unlock(); // client serialization SurfaceDescriptor descriptor; ASSERT_TRUE(texture->ToSurfaceDescriptor(descriptor)); ASSERT_NE(descriptor.type(), SurfaceDescriptor::Tnull_t); // host deserialization RefPtr<TextureHost> host = CreateBackendIndependentTextureHost(descriptor, nullptr, texture->GetFlags()); ASSERT_TRUE(host.get() != nullptr); ASSERT_EQ(host->GetFlags(), texture->GetFlags()); // host read ASSERT_TRUE(host->Lock()); RefPtr<mozilla::gfx::DataSourceSurface> hostDataSurface = host->GetAsSurface(); host->Unlock(); nsRefPtr<gfxImageSurface> hostSurface = new gfxImageSurface(hostDataSurface->GetData(), ThebesIntSize(hostDataSurface->GetSize()), hostDataSurface->Stride(), SurfaceFormatToImageFormat(hostDataSurface->GetFormat())); AssertSurfacesEqual(surface, hostSurface.get()); }
bool DIBTextureClient::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlags aFlags) { MOZ_ASSERT(!IsAllocated()); mSize = aSize; mSurface = new gfxWindowsSurface(gfxIntSize(aSize.width, aSize.height), SurfaceFormatToImageFormat(mFormat)); if (!mSurface || mSurface->CairoStatus()) { NS_WARNING("Could not create surface"); mSurface = nullptr; return false; } return true; }
void WriteSnapshotToDumpFile_internal(T* aObj, DataSourceSurface* aSurf) { nsRefPtr<gfxImageSurface> deprecatedSurf = new gfxImageSurface(aSurf->GetData(), ThebesIntSize(aSurf->GetSize()), aSurf->Stride(), SurfaceFormatToImageFormat(aSurf->GetFormat())); nsCString string(aObj->Name()); string.Append('-'); string.AppendInt((uint64_t)aObj); if (gfxUtils::sDumpPaintFile) { fprintf_stderr(gfxUtils::sDumpPaintFile, "array[\"%s\"]=\"", string.BeginReading()); } deprecatedSurf->DumpAsDataURL(gfxUtils::sDumpPaintFile); if (gfxUtils::sDumpPaintFile) { fprintf_stderr(gfxUtils::sDumpPaintFile, "\";"); } }
bool TextureImageTextureSourceOGL::Update(gfx::DataSourceSurface* aSurface, nsIntRegion* aDestRegion, gfx::IntPoint* aSrcOffset) { GLContext *gl = mCompositor->gl(); MOZ_ASSERT(gl); if (!gl) { NS_WARNING("trying to update TextureImageTextureSourceOGL without a GLContext"); return false; } if (!aSurface) { gfxCriticalError() << "Invalid surface for OGL update"; return false; } MOZ_ASSERT(aSurface); IntSize size = aSurface->GetSize(); if (!mTexImage || (mTexImage->GetSize() != size && !aSrcOffset) || mTexImage->GetContentType() != gfx::ContentForFormat(aSurface->GetFormat())) { if (mFlags & TextureFlags::DISALLOW_BIGIMAGE) { GLint maxTextureSize; gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &maxTextureSize); if (size.width > maxTextureSize || size.height > maxTextureSize) { NS_WARNING("Texture exceeds maximum texture size, refusing upload"); return false; } // Explicitly use CreateBasicTextureImage instead of CreateTextureImage, // because CreateTextureImage might still choose to create a tiled // texture image. mTexImage = CreateBasicTextureImage(gl, size, gfx::ContentForFormat(aSurface->GetFormat()), LOCAL_GL_CLAMP_TO_EDGE, FlagsToGLFlags(mFlags), SurfaceFormatToImageFormat(aSurface->GetFormat())); } else { // XXX - clarify which size we want to use. IncrementalContentHost will // require the size of the destination surface to be different from // the size of aSurface. // See bug 893300 (tracks the implementation of ContentHost for new textures). mTexImage = CreateTextureImage(gl, size, gfx::ContentForFormat(aSurface->GetFormat()), LOCAL_GL_CLAMP_TO_EDGE, FlagsToGLFlags(mFlags), SurfaceFormatToImageFormat(aSurface->GetFormat())); } ClearCachedFilter(); if (aDestRegion && !aSrcOffset && !aDestRegion->IsEqual(nsIntRect(0, 0, size.width, size.height))) { // UpdateFromDataSource will ignore our specified aDestRegion since the texture // hasn't been allocated with glTexImage2D yet. Call Resize() to force the // allocation (full size, but no upload), and then we'll only upload the pixels // we care about below. mTexImage->Resize(size); } } mTexImage->UpdateFromDataSource(aSurface, aDestRegion, aSrcOffset); if (mTexImage->InUpdate()) { mTexImage->EndUpdate(); } return true; }
void CanvasLayerD3D9::UpdateSurface() { if (!IsDirty() && mTexture) return; Painted(); if (!mTexture) { CreateTexture(); if (!mTexture) { NS_WARNING("CanvasLayerD3D9::Updated called but no texture present and creation failed!"); return; } } if (mGLContext) { SharedSurface* surf = mGLContext->RequestFrame(); if (!surf) return; SharedSurface_Basic* shareSurf = SharedSurface_Basic::Cast(surf); // WebGL reads entire surface. LockTextureRectD3D9 textureLock(mTexture); if (!textureLock.HasLock()) { NS_WARNING("Failed to lock CanvasLayer texture."); return; } D3DLOCKED_RECT rect = textureLock.GetLockRect(); DataSourceSurface* frameData = shareSurf->GetData(); // Scope for gfxContext, so it's destroyed early. { RefPtr<DrawTarget> mapDt = Factory::CreateDrawTargetForData(BACKEND_CAIRO, (uint8_t*)rect.pBits, shareSurf->Size(), rect.Pitch, FORMAT_B8G8R8A8); nsRefPtr<gfxImageSurface> thebesFrameData = new gfxImageSurface(frameData->GetData(), ThebesIntSize(frameData->GetSize()), frameData->Stride(), SurfaceFormatToImageFormat(frameData->GetFormat())); nsRefPtr<gfxContext> ctx = new gfxContext(mapDt); ctx->SetOperator(gfxContext::OPERATOR_SOURCE); ctx->SetSource(thebesFrameData); ctx->Paint(); mapDt->Flush(); } } else { RECT r; r.left = mBounds.x; r.top = mBounds.y; r.right = mBounds.XMost(); r.bottom = mBounds.YMost(); LockTextureRectD3D9 textureLock(mTexture); if (!textureLock.HasLock()) { NS_WARNING("Failed to lock CanvasLayer texture."); return; } D3DLOCKED_RECT lockedRect = textureLock.GetLockRect(); nsRefPtr<gfxImageSurface> sourceSurface; if (mSurface->GetType() == gfxSurfaceTypeWin32) { sourceSurface = mSurface->GetAsImageSurface(); } else if (mSurface->GetType() == gfxSurfaceTypeImage) { sourceSurface = static_cast<gfxImageSurface*>(mSurface.get()); if (sourceSurface->Format() != gfxImageFormatARGB32 && sourceSurface->Format() != gfxImageFormatRGB24) { return; } } else { sourceSurface = new gfxImageSurface(gfxIntSize(mBounds.width, mBounds.height), gfxImageFormatARGB32); nsRefPtr<gfxContext> ctx = new gfxContext(sourceSurface); ctx->SetOperator(gfxContext::OPERATOR_SOURCE); ctx->SetSource(mSurface); ctx->Paint(); } uint8_t *startBits = sourceSurface->Data(); uint32_t sourceStride = sourceSurface->Stride(); if (sourceSurface->Format() != gfxImageFormatARGB32) { mHasAlpha = false; } else { mHasAlpha = true; } for (int y = 0; y < mBounds.height; y++) { memcpy((uint8_t*)lockedRect.pBits + lockedRect.Pitch * y, startBits + sourceStride * y, mBounds.width * 4); } } }
void ReadPixelsIntoImageSurface(GLContext* gl, gfxImageSurface* dest) { gl->MakeCurrent(); MOZ_ASSERT(dest->GetSize() != gfxIntSize(0, 0)); /* gfxImageFormat::ARGB32: * RGBA+UByte: be[RGBA], le[ABGR] * RGBA+UInt: le[RGBA] * BGRA+UInt: le[BGRA] * BGRA+UIntRev: le[ARGB] * * gfxImageFormat::RGB16_565: * RGB+UShort: le[rrrrrggg,gggbbbbb] */ bool hasAlpha = dest->Format() == gfxImageFormat::ARGB32; int destPixelSize; GLenum destFormat; GLenum destType; switch (dest->Format()) { case gfxImageFormat::RGB24: // XRGB case gfxImageFormat::ARGB32: destPixelSize = 4; // Needs host (little) endian ARGB. destFormat = LOCAL_GL_BGRA; destType = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV; break; case gfxImageFormat::RGB16_565: destPixelSize = 2; destFormat = LOCAL_GL_RGB; destType = LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV; break; default: MOZ_CRASH("Bad format."); } MOZ_ASSERT(dest->Stride() == dest->Width() * destPixelSize); GLenum readFormat = destFormat; GLenum readType = destType; bool needsTempSurf = !GetActualReadFormats(gl, destFormat, destType, readFormat, readType); nsAutoPtr<gfxImageSurface> tempSurf; gfxImageSurface* readSurf = nullptr; int readPixelSize = 0; if (needsTempSurf) { if (gl->DebugMode()) { NS_WARNING("Needing intermediary surface for ReadPixels. This will be slow!"); } SurfaceFormat readFormatGFX; switch (readFormat) { case LOCAL_GL_RGBA: case LOCAL_GL_BGRA: { readFormatGFX = hasAlpha ? SurfaceFormat::B8G8R8A8 : SurfaceFormat::B8G8R8X8; break; } case LOCAL_GL_RGB: { MOZ_ASSERT(readPixelSize == 2); MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV); readFormatGFX = SurfaceFormat::R5G6B5; break; } default: { MOZ_CRASH("Bad read format."); } } switch (readType) { case LOCAL_GL_UNSIGNED_BYTE: { MOZ_ASSERT(readFormat == LOCAL_GL_RGBA); readPixelSize = 4; break; } case LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV: { MOZ_ASSERT(readFormat == LOCAL_GL_BGRA); readPixelSize = 4; break; } case LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV: { MOZ_ASSERT(readFormat == LOCAL_GL_RGB); readPixelSize = 2; break; } default: { MOZ_CRASH("Bad read type."); } } tempSurf = new gfxImageSurface(dest->GetSize(), SurfaceFormatToImageFormat(readFormatGFX), false); readSurf = tempSurf; } else { readPixelSize = destPixelSize; readSurf = dest; } MOZ_ASSERT(readPixelSize); GLint currentPackAlignment = 0; gl->fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, ¤tPackAlignment); if (currentPackAlignment != readPixelSize) gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, readPixelSize); GLsizei width = dest->Width(); GLsizei height = dest->Height(); readSurf->Flush(); gl->fReadPixels(0, 0, width, height, readFormat, readType, readSurf->Data()); readSurf->MarkDirty(); if (currentPackAlignment != readPixelSize) gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, currentPackAlignment); if (readSurf != dest) { MOZ_ASSERT(readFormat == LOCAL_GL_RGBA); MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_BYTE); // So we just copied in RGBA in big endian, or le: 0xAABBGGRR. // We want 0xAARRGGBB, so swap R and B: dest->Flush(); RefPtr<DataSourceSurface> readDSurf = Factory::CreateWrappingDataSourceSurface(readSurf->Data(), readSurf->Stride(), ToIntSize(readSurf->GetSize()), ImageFormatToSurfaceFormat(readSurf->Format())); SwapRAndBComponents(readDSurf); dest->MarkDirty(); gfxContext ctx(dest); ctx.SetOperator(gfxContext::OPERATOR_SOURCE); ctx.SetSource(readSurf); ctx.Paint(); } // Check if GL is giving back 1.0 alpha for // RGBA reads to RGBA images from no-alpha buffers. #ifdef XP_MACOSX if (gl->WorkAroundDriverBugs() && gl->Vendor() == gl::GLVendor::NVIDIA && dest->Format() == gfxImageFormat::ARGB32 && width && height) { GLint alphaBits = 0; gl->fGetIntegerv(LOCAL_GL_ALPHA_BITS, &alphaBits); if (!alphaBits) { const uint32_t alphaMask = gfxPackedPixelNoPreMultiply(0xff,0,0,0); dest->Flush(); uint32_t* itr = (uint32_t*)dest->Data(); uint32_t testPixel = *itr; if ((testPixel & alphaMask) != alphaMask) { // We need to set the alpha channel to 1.0 manually. uint32_t* itrEnd = itr + width*height; // Stride is guaranteed to be width*4. for (; itr != itrEnd; itr++) { *itr |= alphaMask; } } dest->MarkDirty(); } } #endif }
void CopyableCanvasLayer::UpdateSurface(gfxASurface* aDestSurface, Layer* aMaskLayer) { if (!IsDirty()) return; Painted(); if (mDrawTarget) { mDrawTarget->Flush(); mSurface = gfxPlatform::GetPlatform()->CreateThebesSurfaceAliasForDrawTarget_hack(mDrawTarget); } if (!mGLContext && aDestSurface) { nsRefPtr<gfxContext> tmpCtx = new gfxContext(aDestSurface); tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE); CopyableCanvasLayer::PaintWithOpacity(tmpCtx, 1.0f, aMaskLayer); return; } if (mGLContext) { nsRefPtr<gfxImageSurface> readSurf; RefPtr<DataSourceSurface> readDSurf; nsRefPtr<gfxASurface> resultSurf; SharedSurface* sharedSurf = mGLContext->RequestFrame(); if (!sharedSurf) { NS_WARNING("Null frame received."); return; } IntSize readSize(sharedSurf->Size()); gfxImageFormat format = (GetContentFlags() & CONTENT_OPAQUE) ? gfxImageFormat::RGB24 : gfxImageFormat::ARGB32; if (aDestSurface) { resultSurf = aDestSurface; } else { resultSurf = GetTempSurface(readSize, format); } MOZ_ASSERT(resultSurf); if (resultSurf->CairoStatus() != 0) { MOZ_ASSERT(false, "Bad resultSurf->CairoStatus()."); return; } MOZ_ASSERT(sharedSurf->APIType() == APITypeT::OpenGL); SharedSurface_GL* surfGL = SharedSurface_GL::Cast(sharedSurf); if (surfGL->Type() == SharedSurfaceType::Basic) { // sharedSurf_Basic->mData must outlive readSurf and readDSurf. Alas, // readSurf and readDSurf may not leave the scope they were declared in. SharedSurface_Basic* sharedSurf_Basic = SharedSurface_Basic::Cast(surfGL); readDSurf = sharedSurf_Basic->GetData(); readSurf = new gfxImageSurface(readDSurf->GetData(), ThebesIntSize(readDSurf->GetSize()), readDSurf->Stride(), SurfaceFormatToImageFormat(readDSurf->GetFormat())); } else { if (ToIntSize(resultSurf->GetSize()) != readSize || !(readSurf = resultSurf->GetAsImageSurface()) || readSurf->Format() != format) { readSurf = GetTempSurface(readSize, format); } // Readback handles Flush/MarkDirty. mGLContext->Screen()->Readback(surfGL, readSurf); } MOZ_ASSERT(readSurf); bool needsPremult = surfGL->HasAlpha() && !mIsGLAlphaPremult; if (needsPremult) { readSurf->Flush(); gfxUtils::PremultiplyImageSurface(readSurf); readSurf->MarkDirty(); } if (readSurf != resultSurf) { readSurf->Flush(); nsRefPtr<gfxContext> ctx = new gfxContext(resultSurf); ctx->SetOperator(gfxContext::OPERATOR_SOURCE); ctx->SetSource(readSurf); ctx->Paint(); } // If !aDestSurface then we will end up painting using mSurface, so // stick our surface into mSurface, so that the Paint() path is the same. if (!aDestSurface) { mSurface = resultSurf; } } }