void ContainerLayer::DefaultComputeSupportsComponentAlphaChildren(bool* aNeedsSurfaceCopy) { bool supportsComponentAlphaChildren = false; bool needsSurfaceCopy = false; CompositionOp blendMode = GetEffectiveMixBlendMode(); if (UseIntermediateSurface()) { if (GetEffectiveVisibleRegion().GetNumRects() == 1 && (GetContentFlags() & Layer::CONTENT_OPAQUE)) { supportsComponentAlphaChildren = true; } else { gfx::Matrix transform; if (HasOpaqueAncestorLayer(this) && GetEffectiveTransform().Is2D(&transform) && !gfx::ThebesMatrix(transform).HasNonIntegerTranslation() && blendMode == gfx::CompositionOp::OP_OVER) { supportsComponentAlphaChildren = true; needsSurfaceCopy = true; } } } else if (blendMode == gfx::CompositionOp::OP_OVER) { supportsComponentAlphaChildren = (GetContentFlags() & Layer::CONTENT_OPAQUE) || (GetParent() && GetParent()->SupportsComponentAlphaChildren()); } mSupportsComponentAlphaChildren = supportsComponentAlphaChildren && gfxPrefs::ComponentAlphaEnabled(); if (aNeedsSurfaceCopy) { *aNeedsSurfaceCopy = mSupportsComponentAlphaChildren && needsSurfaceCopy; } }
nsACString& Layer::PrintInfo(nsACString& aTo, const char* aPrefix) { aTo += aPrefix; aTo += nsPrintfCString(64, "%s%s (0x%p)", mManager->Name(), Name(), this); ::PrintInfo(aTo, AsShadowLayer()); if (mUseClipRect) { AppendToString(aTo, mClipRect, " [clip=", "]"); } if (!mTransform.IsIdentity()) { AppendToString(aTo, mTransform, " [transform=", "]"); } if (!mVisibleRegion.IsEmpty()) { AppendToString(aTo, mVisibleRegion, " [visible=", "]"); } if (1.0 != mOpacity) { aTo.AppendPrintf(" [opacity=%g]", mOpacity); } if (const nsIntRect* tileSourceRect = GetTileSourceRect()) { AppendToString(aTo, *tileSourceRect, " [tileSrc=", "]"); } if (GetContentFlags() & CONTENT_OPAQUE) { aTo += " [opaqueContent]"; } if (GetContentFlags() & CONTENT_COMPONENT_ALPHA) { aTo += " [componentAlpha]"; } return aTo; }
void BasicCanvasLayer::PaintWithOpacity(gfxContext* aContext, float aOpacity, Layer* aMaskLayer) { NS_ASSERTION(BasicManager()->InDrawing(), "Can only draw in drawing phase"); if (!mSurface) { NS_WARNING("No valid surface to draw!"); return; } nsRefPtr<gfxPattern> pat = new gfxPattern(mSurface); pat->SetFilter(mFilter); pat->SetExtend(gfxPattern::EXTEND_PAD); gfxMatrix m; if (mNeedsYFlip) { m = aContext->CurrentMatrix(); aContext->Translate(gfxPoint(0.0, mBounds.height)); aContext->Scale(1.0, -1.0); } // If content opaque, then save off current operator and set to source. // This ensures that alpha is not applied even if the source surface // has an alpha channel gfxContext::GraphicsOperator savedOp; if (GetContentFlags() & CONTENT_OPAQUE) { savedOp = aContext->CurrentOperator(); aContext->SetOperator(gfxContext::OPERATOR_SOURCE); } AutoSetOperator setOperator(aContext, GetOperator()); aContext->NewPath(); // No need to snap here; our transform is already set up to snap our rect aContext->Rectangle(gfxRect(0, 0, mBounds.width, mBounds.height)); aContext->SetPattern(pat); FillWithMask(aContext, aOpacity, aMaskLayer); #if defined (MOZ_X11) && defined (MOZ_EGL_XRENDER_COMPOSITE) if (mGLContext && !mForceReadback) { // Wait for X to complete all operations before continuing // Otherwise gl context could get cleared before X is done. mGLContext->WaitNative(); } #endif // Restore surface operator if (GetContentFlags() & CONTENT_OPAQUE) { aContext->SetOperator(savedOp); } if (mNeedsYFlip) { aContext->SetMatrix(m); } }
void CopyableCanvasLayer::PaintWithOpacity(gfxContext* aContext, float aOpacity, Layer* aMaskLayer, gfxContext::GraphicsOperator aOperator) { if (!mSurface) { NS_WARNING("No valid surface to draw!"); return; } nsRefPtr<gfxPattern> pat = new gfxPattern(mSurface); pat->SetFilter(mFilter); pat->SetExtend(gfxPattern::EXTEND_PAD); gfxMatrix m; if (mNeedsYFlip) { m = aContext->CurrentMatrix(); aContext->Translate(gfxPoint(0.0, mBounds.height)); aContext->Scale(1.0, -1.0); } // If content opaque, then save off current operator and set to source. // This ensures that alpha is not applied even if the source surface // has an alpha channel gfxContext::GraphicsOperator savedOp; if (GetContentFlags() & CONTENT_OPAQUE) { savedOp = aContext->CurrentOperator(); aContext->SetOperator(gfxContext::OPERATOR_SOURCE); } AutoSetOperator setOperator(aContext, aOperator); aContext->NewPath(); // No need to snap here; our transform is already set up to snap our rect aContext->Rectangle(gfxRect(0, 0, mBounds.width, mBounds.height)); aContext->SetPattern(pat); FillWithMask(aContext, aOpacity, aMaskLayer); // Restore surface operator if (GetContentFlags() & CONTENT_OPAQUE) { aContext->SetOperator(savedOp); } if (mNeedsYFlip) { aContext->SetMatrix(m); } }
void ContainerLayerD3D10::Validate() { nsIntRect visibleRect = mVisibleRegion.GetBounds(); mSupportsComponentAlphaChildren = false; if (UseIntermediateSurface()) { const gfx3DMatrix& transform3D = GetEffectiveTransform(); gfxMatrix transform; if (mVisibleRegion.GetNumRects() == 1 && (GetContentFlags() & CONTENT_OPAQUE)) { // don't need a background, we're going to paint all opaque stuff mSupportsComponentAlphaChildren = true; } else { if (HasOpaqueAncestorLayer(this) && transform3D.Is2D(&transform) && !transform.HasNonIntegerTranslation() && GetParent()->GetEffectiveVisibleRegion().GetBounds().Contains(visibleRect)) { // In this case we can copy up the background. See RenderLayer. mSupportsComponentAlphaChildren = true; } } } else { mSupportsComponentAlphaChildren = (GetContentFlags() & CONTENT_OPAQUE) || (mParent && mParent->SupportsComponentAlphaChildren()); } ReadbackProcessor readback; readback.BuildUpdates(this); Layer *layer = GetFirstChild(); while (layer) { if (layer->GetType() == TYPE_THEBES) { static_cast<ThebesLayerD3D10*>(layer)->Validate(&readback); } else { static_cast<LayerD3D10*>(layer->ImplData())->Validate(); } layer = layer->GetNextSibling(); } }
bool Layer::CanUseOpaqueSurface() { // If the visible content in the layer is opaque, there is no need // for an alpha channel. if (GetContentFlags() & CONTENT_OPAQUE) return true; // Also, if this layer is the bottommost layer in a container which // doesn't need an alpha channel, we can use an opaque surface for this // layer too. Any transparent areas must be covered by something else // in the container. ContainerLayer* parent = GetParent(); return parent && parent->GetFirstChild() == this && parent->CanUseOpaqueSurface(); }
void ClientCanvasLayer::Initialize(const Data& aData) { CopyableCanvasLayer::Initialize(aData); mCanvasClient = nullptr; if (mGLContext) { GLScreenBuffer* screen = mGLContext->Screen(); SurfaceCaps caps = screen->Caps(); if (mStream) { // The screen caps are irrelevant if we're using a separate stream caps = GetContentFlags() & CONTENT_OPAQUE ? SurfaceCaps::ForRGB() : SurfaceCaps::ForRGBA(); } SurfaceStreamType streamType = SurfaceStream::ChooseGLStreamType(SurfaceStream::OffMainThread, screen->PreserveBuffer()); SurfaceFactory_GL* factory = nullptr; if (!gfxPrefs::WebGLForceLayersReadback()) { if (ClientManager()->AsShadowForwarder()->GetCompositorBackendType() == mozilla::layers::LayersBackend::LAYERS_OPENGL) { if (mGLContext->GetContextType() == GLContextType::EGL) { bool isCrossProcess = !(XRE_GetProcessType() == GeckoProcessType_Default); if (!isCrossProcess) { // [Basic/OGL Layers, OMTC] WebGL layer init. factory = SurfaceFactory_EGLImage::Create(mGLContext, caps); } else { // [Basic/OGL Layers, OOPC] WebGL layer init. (Out Of Process Compositing) #ifdef MOZ_WIDGET_GONK factory = new SurfaceFactory_Gralloc(mGLContext, caps, ClientManager()->AsShadowForwarder()); #else // we could do readback here maybe NS_NOTREACHED("isCrossProcess but not on native B2G!"); #endif } } else { // [Basic Layers, OMTC] WebGL layer init. // Well, this *should* work... #ifdef XP_MACOSX factory = new SurfaceFactory_IOSurface(mGLContext, caps); #else factory = new SurfaceFactory_GLTexture(mGLContext, nullptr, caps); #endif } } } if (mStream) { // We're using a stream other than the one in the default screen mFactory = factory; if (!mFactory) { // Absolutely must have a factory here, so create a basic one mFactory = new SurfaceFactory_Basic(mGLContext, caps); } gfx::IntSize size = gfx::IntSize(aData.mSize.width, aData.mSize.height); mTextureSurface = SharedSurface_GLTexture::Create(mGLContext, mGLContext, mGLContext->GetGLFormats(), size, caps.alpha, aData.mTexID); SharedSurface* producer = mStream->SwapProducer(mFactory, size); if (!producer) { // Fallback to basic factory delete mFactory; mFactory = new SurfaceFactory_Basic(mGLContext, caps); producer = mStream->SwapProducer(mFactory, size); MOZ_ASSERT(producer, "Failed to create initial canvas surface with basic factory"); } } else if (factory) { screen->Morph(factory, streamType); } } }
void ContainerLayerD3D10::RenderLayer() { float renderTargetOffset[] = { 0, 0 }; nsIntRect visibleRect = mVisibleRegion.GetBounds(); float opacity = GetEffectiveOpacity(); bool useIntermediate = UseIntermediateSurface(); nsRefPtr<ID3D10RenderTargetView> previousRTView; nsRefPtr<ID3D10Texture2D> renderTexture; nsRefPtr<ID3D10RenderTargetView> rtView; float previousRenderTargetOffset[2]; nsIntSize previousViewportSize; gfx3DMatrix oldViewMatrix; if (useIntermediate) { device()->OMGetRenderTargets(1, getter_AddRefs(previousRTView), NULL); D3D10_TEXTURE2D_DESC desc; memset(&desc, 0, sizeof(D3D10_TEXTURE2D_DESC)); desc.ArraySize = 1; desc.MipLevels = 1; desc.Width = visibleRect.width; desc.Height = visibleRect.height; desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE; desc.SampleDesc.Count = 1; desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; HRESULT hr; hr = device()->CreateTexture2D(&desc, NULL, getter_AddRefs(renderTexture)); if (FAILED(hr)) { LayerManagerD3D10::ReportFailure(NS_LITERAL_CSTRING("Failed to create new texture for ContainerLayerD3D10!"), hr); return; } hr = device()->CreateRenderTargetView(renderTexture, NULL, getter_AddRefs(rtView)); NS_ASSERTION(SUCCEEDED(hr), "Failed to create render target view for ContainerLayerD3D10!"); effect()->GetVariableByName("vRenderTargetOffset")-> GetRawValue(previousRenderTargetOffset, 0, 8); previousViewportSize = mD3DManager->GetViewport(); if (mVisibleRegion.GetNumRects() != 1 || !(GetContentFlags() & CONTENT_OPAQUE)) { const gfx3DMatrix& transform3D = GetEffectiveTransform(); gfxMatrix transform; // If we have an opaque ancestor layer, then we can be sure that // all the pixels we draw into are either opaque already or will be // covered by something opaque. Otherwise copying up the background is // not safe. if (mSupportsComponentAlphaChildren) { bool is2d = transform3D.Is2D(&transform); NS_ASSERTION(is2d, "Transform should be 2d when mSupportsComponentAlphaChildren."); // Copy background up from below. This applies any 2D transform that is // applied to use relative to our parent, and compensates for the offset // that was applied on our parent's rendering. D3D10_BOX srcBox; srcBox.left = std::max<int32_t>(visibleRect.x + int32_t(transform.x0) - int32_t(previousRenderTargetOffset[0]), 0); srcBox.top = std::max<int32_t>(visibleRect.y + int32_t(transform.y0) - int32_t(previousRenderTargetOffset[1]), 0); srcBox.right = std::min<int32_t>(srcBox.left + visibleRect.width, previousViewportSize.width); srcBox.bottom = std::min<int32_t>(srcBox.top + visibleRect.height, previousViewportSize.height); srcBox.back = 1; srcBox.front = 0; nsRefPtr<ID3D10Resource> srcResource; previousRTView->GetResource(getter_AddRefs(srcResource)); device()->CopySubresourceRegion(renderTexture, 0, 0, 0, 0, srcResource, 0, &srcBox); } else { float black[] = { 0, 0, 0, 0}; device()->ClearRenderTargetView(rtView, black); } } ID3D10RenderTargetView *rtViewPtr = rtView; device()->OMSetRenderTargets(1, &rtViewPtr, NULL); renderTargetOffset[0] = (float)visibleRect.x; renderTargetOffset[1] = (float)visibleRect.y; effect()->GetVariableByName("vRenderTargetOffset")-> SetRawValue(renderTargetOffset, 0, 8); mD3DManager->SetViewport(nsIntSize(visibleRect.Size())); } D3D10_RECT oldD3D10Scissor; UINT numRects = 1; device()->RSGetScissorRects(&numRects, &oldD3D10Scissor); // Convert scissor to an nsIntRect. D3D10_RECT's are exclusive // on the bottom and right values. nsIntRect oldScissor(oldD3D10Scissor.left, oldD3D10Scissor.top, oldD3D10Scissor.right - oldD3D10Scissor.left, oldD3D10Scissor.bottom - oldD3D10Scissor.top); nsAutoTArray<Layer*, 12> children; SortChildrenBy3DZOrder(children); /* * Render this container's contents. */ for (uint32_t i = 0; i < children.Length(); i++) { LayerD3D10* layerToRender = static_cast<LayerD3D10*>(children.ElementAt(i)->ImplData()); if (layerToRender->GetLayer()->GetEffectiveVisibleRegion().IsEmpty()) { continue; } nsIntRect scissorRect = layerToRender->GetLayer()->CalculateScissorRect(oldScissor, nullptr); if (scissorRect.IsEmpty()) { continue; } D3D10_RECT d3drect; d3drect.left = scissorRect.x; d3drect.top = scissorRect.y; d3drect.right = scissorRect.x + scissorRect.width; d3drect.bottom = scissorRect.y + scissorRect.height; device()->RSSetScissorRects(1, &d3drect); layerToRender->RenderLayer(); } device()->RSSetScissorRects(1, &oldD3D10Scissor); if (useIntermediate) { mD3DManager->SetViewport(previousViewportSize); ID3D10RenderTargetView *rtView = previousRTView; device()->OMSetRenderTargets(1, &rtView, NULL); effect()->GetVariableByName("vRenderTargetOffset")-> SetRawValue(previousRenderTargetOffset, 0, 8); SetEffectTransformAndOpacity(); ID3D10EffectTechnique *technique; if (LoadMaskTexture()) { if (GetTransform().CanDraw2D()) { technique = SelectShader(SHADER_RGBA | SHADER_PREMUL | SHADER_MASK); } else { technique = SelectShader(SHADER_RGBA | SHADER_PREMUL | SHADER_MASK_3D); } } else { technique = SelectShader(SHADER_RGBA | SHADER_PREMUL | SHADER_NO_MASK); } effect()->GetVariableByName("vLayerQuad")->AsVector()->SetFloatVector( ShaderConstantRectD3D10( (float)visibleRect.x, (float)visibleRect.y, (float)visibleRect.width, (float)visibleRect.height) ); technique->GetPassByIndex(0)->Apply(0); ID3D10ShaderResourceView *view; device()->CreateShaderResourceView(renderTexture, NULL, &view); device()->PSSetShaderResources(0, 1, &view); device()->Draw(4, 0); view->Release(); } }
void ContainerLayerD3D9::RenderLayer() { nsRefPtr<IDirect3DSurface9> previousRenderTarget; nsRefPtr<IDirect3DTexture9> renderTexture; float previousRenderTargetOffset[4]; float renderTargetOffset[] = { 0, 0, 0, 0 }; float oldViewMatrix[4][4]; RECT containerD3D9ClipRect; device()->GetScissorRect(&containerD3D9ClipRect); // Convert scissor to an nsIntRect. RECT's are exclusive on the bottom and // right values. nsIntRect oldScissor(containerD3D9ClipRect.left, containerD3D9ClipRect.top, containerD3D9ClipRect.right - containerD3D9ClipRect.left, containerD3D9ClipRect.bottom - containerD3D9ClipRect.top); ReadbackProcessor readback; readback.BuildUpdates(this); nsIntRect visibleRect = GetEffectiveVisibleRegion().GetBounds(); bool useIntermediate = UseIntermediateSurface(); mSupportsComponentAlphaChildren = false; if (useIntermediate) { nsRefPtr<IDirect3DSurface9> renderSurface; if (!mD3DManager->CompositingDisabled()) { device()->GetRenderTarget(0, getter_AddRefs(previousRenderTarget)); HRESULT hr = device()->CreateTexture(visibleRect.width, visibleRect.height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, getter_AddRefs(renderTexture), nullptr); if (FAILED(hr)) { ReportFailure(NS_LITERAL_CSTRING("ContainerLayerD3D9::ContainerRender(): Failed to create texture"), hr); return; } nsRefPtr<IDirect3DSurface9> renderSurface; renderTexture->GetSurfaceLevel(0, getter_AddRefs(renderSurface)); device()->SetRenderTarget(0, renderSurface); } if (mVisibleRegion.GetNumRects() == 1 && (GetContentFlags() & CONTENT_OPAQUE)) { // don't need a background, we're going to paint all opaque stuff mSupportsComponentAlphaChildren = true; } else { Matrix4x4 transform3D = GetEffectiveTransform(); Matrix transform; // If we have an opaque ancestor layer, then we can be sure that // all the pixels we draw into are either opaque already or will be // covered by something opaque. Otherwise copying up the background is // not safe. HRESULT hr = E_FAIL; if (HasOpaqueAncestorLayer(this) && transform3D.Is2D(&transform) && !ThebesMatrix(transform).HasNonIntegerTranslation()) { // Copy background up from below RECT dest = { 0, 0, visibleRect.width, visibleRect.height }; RECT src = dest; ::OffsetRect(&src, visibleRect.x + int32_t(transform._31), visibleRect.y + int32_t(transform._32)); if (!mD3DManager->CompositingDisabled()) { hr = device()-> StretchRect(previousRenderTarget, &src, renderSurface, &dest, D3DTEXF_NONE); } } if (hr == S_OK) { mSupportsComponentAlphaChildren = true; } else if (!mD3DManager->CompositingDisabled()) { device()-> Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0, 0, 0, 0), 0, 0); } } device()-> GetVertexShaderConstantF(CBvRenderTargetOffset, previousRenderTargetOffset, 1); renderTargetOffset[0] = (float)visibleRect.x; renderTargetOffset[1] = (float)visibleRect.y; device()-> SetVertexShaderConstantF(CBvRenderTargetOffset, renderTargetOffset, 1); gfx3DMatrix viewMatrix; /* * Matrix to transform to viewport space ( <-1.0, 1.0> topleft, * <1.0, -1.0> bottomright) */ viewMatrix._11 = 2.0f / visibleRect.width; viewMatrix._22 = -2.0f / visibleRect.height; viewMatrix._41 = -1.0f; viewMatrix._42 = 1.0f; device()-> GetVertexShaderConstantF(CBmProjection, &oldViewMatrix[0][0], 4); device()-> SetVertexShaderConstantF(CBmProjection, &viewMatrix._11, 4); } else { mSupportsComponentAlphaChildren = (GetContentFlags() & CONTENT_OPAQUE) || (mParent && mParent->SupportsComponentAlphaChildren()); } nsAutoTArray<Layer*, 12> children; SortChildrenBy3DZOrder(children); /* * Render this container's contents. */ for (uint32_t i = 0; i < children.Length(); i++) { LayerD3D9* layerToRender = static_cast<LayerD3D9*>(children.ElementAt(i)->ImplData()); if (layerToRender->GetLayer()->GetEffectiveVisibleRegion().IsEmpty()) { continue; } nsIntRect scissorRect = RenderTargetPixel::ToUntyped(layerToRender->GetLayer()->CalculateScissorRect(RenderTargetPixel::FromUntyped(oldScissor), nullptr)); if (scissorRect.IsEmpty()) { continue; } RECT d3drect; d3drect.left = scissorRect.x; d3drect.top = scissorRect.y; d3drect.right = scissorRect.x + scissorRect.width; d3drect.bottom = scissorRect.y + scissorRect.height; device()->SetScissorRect(&d3drect); if (layerToRender->GetLayer()->GetType() == TYPE_THEBES) { static_cast<ThebesLayerD3D9*>(layerToRender)->RenderThebesLayer(&readback); } else { layerToRender->RenderLayer(); } } if (useIntermediate && !mD3DManager->CompositingDisabled()) { device()->SetRenderTarget(0, previousRenderTarget); device()->SetVertexShaderConstantF(CBvRenderTargetOffset, previousRenderTargetOffset, 1); device()->SetVertexShaderConstantF(CBmProjection, &oldViewMatrix[0][0], 4); device()->SetVertexShaderConstantF(CBvLayerQuad, ShaderConstantRect(visibleRect.x, visibleRect.y, visibleRect.width, visibleRect.height), 1); SetShaderTransformAndOpacity(); mD3DManager->SetShaderMode(DeviceManagerD3D9::RGBALAYER, GetMaskLayer(), GetTransform().CanDraw2D()); device()->SetTexture(0, renderTexture); device()->SetScissorRect(&containerD3D9ClipRect); device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); } else { device()->SetScissorRect(&containerD3D9ClipRect); } }
void CopyableCanvasLayer::UpdateSurface(gfxASurface* aDestSurface, Layer* aMaskLayer) { if (!IsDirty()) return; Painted(); if (mDrawTarget) { mDrawTarget->Flush(); if (mDrawTarget->GetType() == BACKEND_COREGRAPHICS_ACCELERATED) { // We have an accelerated CG context which has changed, unlike a bitmap surface // where we can alias the bits on initializing the mDrawTarget, we need to readback // and copy the accelerated surface each frame. We want to support this for quick // thumbnail but if we're going to be doing this every frame it likely is better // to use a non accelerated (bitmap) canvas. mSurface = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mDrawTarget); } } if (!mGLContext && aDestSurface) { nsRefPtr<gfxContext> tmpCtx = new gfxContext(aDestSurface); tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE); CopyableCanvasLayer::PaintWithOpacity(tmpCtx, 1.0f, aMaskLayer); return; } if (mGLContext) { if (aDestSurface && aDestSurface->GetType() != gfxASurface::SurfaceTypeImage) { MOZ_ASSERT(false, "Destination surface must be ImageSurface type."); return; } nsRefPtr<gfxImageSurface> readSurf; nsRefPtr<gfxImageSurface> resultSurf; SharedSurface* sharedSurf = mGLContext->RequestFrame(); if (!sharedSurf) { NS_WARNING("Null frame received."); return; } gfxIntSize readSize(sharedSurf->Size()); gfxImageFormat format = (GetContentFlags() & CONTENT_OPAQUE) ? gfxASurface::ImageFormatRGB24 : gfxASurface::ImageFormatARGB32; if (aDestSurface) { resultSurf = static_cast<gfxImageSurface*>(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) { SharedSurface_Basic* sharedSurf_Basic = SharedSurface_Basic::Cast(surfGL); readSurf = sharedSurf_Basic->GetData(); } else { if (resultSurf->Format() == format && resultSurf->GetSize() == readSize) { readSurf = resultSurf; } else { readSurf = GetTempSurface(readSize, format); } // Readback handles Flush/MarkDirty. mGLContext->Screen()->Readback(surfGL, readSurf); } MOZ_ASSERT(readSurf); bool needsPremult = surfGL->HasAlpha() && !mIsGLAlphaPremult; if (needsPremult) { gfxImageSurface* sizedReadSurf = nullptr; if (readSurf->Format() == resultSurf->Format() && readSurf->GetSize() == resultSurf->GetSize()) { sizedReadSurf = readSurf; } else { readSurf->Flush(); nsRefPtr<gfxContext> ctx = new gfxContext(resultSurf); ctx->SetOperator(gfxContext::OPERATOR_SOURCE); ctx->SetSource(readSurf); ctx->Paint(); sizedReadSurf = resultSurf; } MOZ_ASSERT(sizedReadSurf); readSurf->Flush(); resultSurf->Flush(); gfxUtils::PremultiplyImageSurface(readSurf, resultSurf); resultSurf->MarkDirty(); } else if (resultSurf != readSurf) { // Didn't need premult, but we do need to blit to resultSurf readSurf->Flush(); nsRefPtr<gfxContext> ctx = new gfxContext(resultSurf); ctx->SetOperator(gfxContext::OPERATOR_SOURCE); ctx->SetSource(readSurf); ctx->Paint(); } // stick our surface into mSurface, so that the Paint() path is the same if (!aDestSurface) { mSurface = resultSurf; } } }
void CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget) { if (!IsDirty()) return; Painted(); if (mDrawTarget) { mDrawTarget->Flush(); mSurface = mDrawTarget->Snapshot(); } if (!mGLContext && aDestTarget) { NS_ASSERTION(mSurface, "Must have surface to draw!"); if (mSurface) { aDestTarget->CopySurface(mSurface, IntRect(0, 0, mBounds.width, mBounds.height), IntPoint(0, 0)); mSurface = nullptr; } return; } if (mGLContext) { SharedSurface_GL* sharedSurf = nullptr; if (mStream) { sharedSurf = SharedSurface_GL::Cast(mStream->SwapConsumer()); } else { sharedSurf = mGLContext->RequestFrame(); } if (!sharedSurf) { NS_WARNING("Null frame received."); return; } IntSize readSize(sharedSurf->Size()); SurfaceFormat format = (GetContentFlags() & CONTENT_OPAQUE) ? SurfaceFormat::B8G8R8X8 : SurfaceFormat::B8G8R8A8; bool needsPremult = sharedSurf->HasAlpha() && !mIsGLAlphaPremult; // Try to read back directly into aDestTarget's output buffer if (aDestTarget) { uint8_t* destData; IntSize destSize; int32_t destStride; SurfaceFormat destFormat; if (aDestTarget->LockBits(&destData, &destSize, &destStride, &destFormat)) { if (destSize == readSize && destFormat == format) { RefPtr<DataSourceSurface> data = Factory::CreateWrappingDataSourceSurface(destData, destStride, destSize, destFormat); mGLContext->Screen()->Readback(sharedSurf, data); if (needsPremult) { PremultiplySurface(data); } aDestTarget->ReleaseBits(destData); return; } aDestTarget->ReleaseBits(destData); } } RefPtr<SourceSurface> resultSurf; if (sharedSurf->Type() == SharedSurfaceType::Basic && !needsPremult) { SharedSurface_Basic* sharedSurf_Basic = SharedSurface_Basic::Cast(sharedSurf); resultSurf = sharedSurf_Basic->GetData(); } else { RefPtr<DataSourceSurface> data = GetTempSurface(readSize, format); // Readback handles Flush/MarkDirty. mGLContext->Screen()->Readback(sharedSurf, data); if (needsPremult) { PremultiplySurface(data); } resultSurf = data; } MOZ_ASSERT(resultSurf); if (aDestTarget) { aDestTarget->CopySurface(resultSurf, IntRect(0, 0, readSize.width, readSize.height), IntPoint(0, 0)); } else { // If !aDestSurface then we will end up painting using mSurface, so // stick our surface into mSurface, so that the Paint() path is the same. mSurface = resultSurf; } } }
nsACString& Layer::PrintInfo(nsACString& aTo, const char* aPrefix) { aTo += aPrefix; aTo += nsPrintfCString("%s%s (0x%p)", mManager->Name(), Name(), this); layers::PrintInfo(aTo, AsLayerComposite()); if (mUseClipRect) { AppendToString(aTo, mClipRect, " [clip=", "]"); } if (1.0 != mPostXScale || 1.0 != mPostYScale) { aTo.AppendPrintf(" [postScale=%g, %g]", mPostXScale, mPostYScale); } if (!mTransform.IsIdentity()) { AppendToString(aTo, mTransform, " [transform=", "]"); } if (!mVisibleRegion.IsEmpty()) { AppendToString(aTo, mVisibleRegion, " [visible=", "]"); } else { aTo += " [not visible]"; } if (!mEventRegions.mHitRegion.IsEmpty()) { AppendToString(aTo, mEventRegions.mHitRegion, " [hitregion=", "]"); } if (!mEventRegions.mDispatchToContentHitRegion.IsEmpty()) { AppendToString(aTo, mEventRegions.mDispatchToContentHitRegion, " [dispatchtocontentregion=", "]"); } if (1.0 != mOpacity) { aTo.AppendPrintf(" [opacity=%g]", mOpacity); } if (GetContentFlags() & CONTENT_OPAQUE) { aTo += " [opaqueContent]"; } if (GetContentFlags() & CONTENT_COMPONENT_ALPHA) { aTo += " [componentAlpha]"; } if (GetScrollbarDirection() == VERTICAL) { aTo.AppendPrintf(" [vscrollbar=%lld]", GetScrollbarTargetContainerId()); } if (GetScrollbarDirection() == HORIZONTAL) { aTo.AppendPrintf(" [hscrollbar=%lld]", GetScrollbarTargetContainerId()); } if (GetIsFixedPosition()) { aTo.AppendPrintf(" [isFixedPosition anchor=%f,%f margin=%f,%f,%f,%f]", mAnchor.x, mAnchor.y, mMargins.top, mMargins.right, mMargins.bottom, mMargins.left); } if (GetIsStickyPosition()) { aTo.AppendPrintf(" [isStickyPosition scrollId=%d outer=%f,%f %fx%f " "inner=%f,%f %fx%f]", mStickyPositionData->mScrollId, mStickyPositionData->mOuter.x, mStickyPositionData->mOuter.y, mStickyPositionData->mOuter.width, mStickyPositionData->mOuter.height, mStickyPositionData->mInner.x, mStickyPositionData->mInner.y, mStickyPositionData->mInner.width, mStickyPositionData->mInner.height); } if (mMaskLayer) { aTo.AppendPrintf(" [mMaskLayer=%p]", mMaskLayer.get()); } return aTo; }
void CopyableCanvasLayer::UpdateSurface(gfxASurface* aDestSurface, Layer* aMaskLayer) { if (!IsDirty()) return; Painted(); if (mDrawTarget) { mDrawTarget->Flush(); mSurface = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mDrawTarget); } if (!mGLContext && aDestSurface) { nsRefPtr<gfxContext> tmpCtx = new gfxContext(aDestSurface); tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE); CopyableCanvasLayer::PaintWithOpacity(tmpCtx, 1.0f, aMaskLayer); return; } if (mGLContext) { if (aDestSurface && aDestSurface->GetType() != gfxASurface::SurfaceTypeImage) { MOZ_ASSERT(false, "Destination surface must be ImageSurface type."); return; } nsRefPtr<gfxImageSurface> readSurf; nsRefPtr<gfxImageSurface> resultSurf; SharedSurface* sharedSurf = mGLContext->RequestFrame(); if (!sharedSurf) { NS_WARNING("Null frame received."); return; } gfxIntSize readSize(sharedSurf->Size()); gfxImageFormat format = (GetContentFlags() & CONTENT_OPAQUE) ? gfxASurface::ImageFormatRGB24 : gfxASurface::ImageFormatARGB32; if (aDestSurface) { resultSurf = static_cast<gfxImageSurface*>(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) { SharedSurface_Basic* sharedSurf_Basic = SharedSurface_Basic::Cast(surfGL); readSurf = sharedSurf_Basic->GetData(); } else { if (resultSurf->Format() == format && resultSurf->GetSize() == readSize) { readSurf = resultSurf; } else { readSurf = GetTempSurface(readSize, format); } // Readback handles Flush/MarkDirty. mGLContext->Screen()->Readback(surfGL, readSurf); } MOZ_ASSERT(readSurf); bool needsPremult = surfGL->HasAlpha() && !mIsGLAlphaPremult; if (needsPremult) { gfxImageSurface* sizedReadSurf = nullptr; if (readSurf->Format() == resultSurf->Format() && readSurf->GetSize() == resultSurf->GetSize()) { sizedReadSurf = readSurf; } else { readSurf->Flush(); nsRefPtr<gfxContext> ctx = new gfxContext(resultSurf); ctx->SetOperator(gfxContext::OPERATOR_SOURCE); ctx->SetSource(readSurf); ctx->Paint(); sizedReadSurf = resultSurf; } MOZ_ASSERT(sizedReadSurf); readSurf->Flush(); resultSurf->Flush(); gfxUtils::PremultiplyImageSurface(readSurf, resultSurf); resultSurf->MarkDirty(); } else if (resultSurf != readSurf) { // Didn't need premult, but we do need to blit to resultSurf readSurf->Flush(); nsRefPtr<gfxContext> ctx = new gfxContext(resultSurf); ctx->SetOperator(gfxContext::OPERATOR_SOURCE); ctx->SetSource(readSurf); ctx->Paint(); } // stick our surface into mSurface, so that the Paint() path is the same if (!aDestSurface) { mSurface = resultSurf; } } }
void BasicCanvasLayer::UpdateSurface(gfxASurface* aDestSurface, Layer* aMaskLayer) { if (!IsDirty()) return; Painted(); if (mDrawTarget) { mDrawTarget->Flush(); // TODO Fix me before turning accelerated quartz canvas by default //mSurface = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mDrawTarget); } if (!mGLContext && aDestSurface) { nsRefPtr<gfxContext> tmpCtx = new gfxContext(aDestSurface); tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE); BasicCanvasLayer::PaintWithOpacity(tmpCtx, 1.0f, aMaskLayer); return; } if (mGLContext) { if (aDestSurface && aDestSurface->GetType() != gfxASurface::SurfaceTypeImage) { NS_ASSERTION(aDestSurface->GetType() == gfxASurface::SurfaceTypeImage, "Destination surface must be ImageSurface type"); return; } // We need to read from the GLContext mGLContext->MakeCurrent(); #if defined (MOZ_X11) && defined (MOZ_EGL_XRENDER_COMPOSITE) if (!mForceReadback) { mGLContext->GuaranteeResolve(); gfxASurface* offscreenSurface = mGLContext->GetOffscreenPixmapSurface(); // XRender can only blend premuliplied alpha, so only allow xrender // path if we have premultiplied alpha or opaque content. if (offscreenSurface && (mGLBufferIsPremultiplied || (GetContentFlags() & CONTENT_OPAQUE))) { mSurface = offscreenSurface; mNeedsYFlip = false; return; } } #endif gfxIntSize readSize(mBounds.width, mBounds.height); gfxImageFormat format = (GetContentFlags() & CONTENT_OPAQUE) ? gfxASurface::ImageFormatRGB24 : gfxASurface::ImageFormatARGB32; nsRefPtr<gfxImageSurface> readSurf; nsRefPtr<gfxImageSurface> resultSurf; bool usingTempSurface = false; if (aDestSurface) { resultSurf = static_cast<gfxImageSurface*>(aDestSurface); if (resultSurf->GetSize() != readSize || resultSurf->Stride() != resultSurf->Width() * 4) { readSurf = GetTempSurface(readSize, format); usingTempSurface = true; } } else { resultSurf = GetTempSurface(readSize, format); usingTempSurface = true; } if (!usingTempSurface) DiscardTempSurface(); if (!readSurf) readSurf = resultSurf; if (!resultSurf || resultSurf->CairoStatus() != 0) return; MOZ_ASSERT(readSurf); MOZ_ASSERT(readSurf->Stride() == mBounds.width * 4, "gfxImageSurface stride isn't what we expect!"); // We need to Flush() the surface before modifying it outside of cairo. readSurf->Flush(); mGLContext->ReadScreenIntoImageSurface(readSurf); readSurf->MarkDirty(); // If the underlying GLContext doesn't have a framebuffer into which // premultiplied values were written, we have to do this ourselves here. // Note that this is a WebGL attribute; GL itself has no knowledge of // premultiplied or unpremultiplied alpha. if (!mGLBufferIsPremultiplied) gfxUtils::PremultiplyImageSurface(readSurf); if (readSurf != resultSurf) { MOZ_ASSERT(resultSurf->Width() >= readSurf->Width()); MOZ_ASSERT(resultSurf->Height() >= readSurf->Height()); resultSurf->Flush(); resultSurf->CopyFrom(readSurf); resultSurf->MarkDirty(); } // stick our surface into mSurface, so that the Paint() path is the same if (!aDestSurface) { mSurface = resultSurf; } } }
void CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget) { if (!IsDirty()) return; Painted(); if (mDrawTarget) { mDrawTarget->Flush(); mSurface = mDrawTarget->Snapshot(); } if (!mGLContext && aDestTarget) { NS_ASSERTION(mSurface, "Must have surface to draw!"); if (mSurface) { aDestTarget->CopySurface(mSurface, IntRect(0, 0, mBounds.width, mBounds.height), IntPoint(0, 0)); } return; } if (mGLContext) { RefPtr<DataSourceSurface> readSurf; RefPtr<SourceSurface> resultSurf; SharedSurface_GL* sharedSurf = nullptr; if (mStream) { sharedSurf = SharedSurface_GL::Cast(mStream->SwapConsumer()); } else { sharedSurf = mGLContext->RequestFrame(); } if (!sharedSurf) { NS_WARNING("Null frame received."); return; } IntSize readSize(sharedSurf->Size()); SurfaceFormat format = (GetContentFlags() & CONTENT_OPAQUE) ? SurfaceFormat::B8G8R8X8 : SurfaceFormat::B8G8R8A8; if (aDestTarget) { resultSurf = aDestTarget->Snapshot(); if (!resultSurf) { resultSurf = GetTempSurface(readSize, format); } } else { resultSurf = GetTempSurface(readSize, format); } MOZ_ASSERT(resultSurf); MOZ_ASSERT(sharedSurf->APIType() == APITypeT::OpenGL); SharedSurface_GL* surfGL = SharedSurface_GL::Cast(sharedSurf); if (surfGL->Type() == SharedSurfaceType::Basic) { // sharedSurf_Basic->mData must outlive readSurf. Alas, readSurf may not // leave the scope it was declared in. SharedSurface_Basic* sharedSurf_Basic = SharedSurface_Basic::Cast(surfGL); readSurf = sharedSurf_Basic->GetData(); } else { if (resultSurf->GetSize() != readSize || !(readSurf = resultSurf->GetDataSurface()) || readSurf->GetFormat() != format) { readSurf = GetTempSurface(readSize, format); } // Readback handles Flush/MarkDirty. mGLContext->Screen()->Readback(surfGL, readSurf); } MOZ_ASSERT(readSurf); bool needsPremult = surfGL->HasAlpha() && !mIsGLAlphaPremult; if (needsPremult) { PremultiplySurface(readSurf); } if (readSurf != resultSurf) { RefPtr<DataSourceSurface> resultDataSurface = resultSurf->GetDataSurface(); RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(BackendType::CAIRO, resultDataSurface->GetData(), resultDataSurface->GetSize(), resultDataSurface->Stride(), resultDataSurface->GetFormat()); IntSize readSize = readSurf->GetSize(); dt->CopySurface(readSurf, IntRect(0, 0, readSize.width, readSize.height), IntPoint(0, 0)); } // 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 (!aDestTarget) { mSurface = resultSurf; } } }
void ContainerLayerOGL::RenderLayer(int aPreviousFrameBuffer, const nsIntPoint& aOffset) { /** * Setup our temporary texture for rendering the contents of this container. */ GLuint containerSurface; GLuint frameBuffer; nsIntPoint childOffset(aOffset); nsIntRect visibleRect = GetEffectiveVisibleRegion().GetBounds(); nsIntRect cachedScissor = gl()->ScissorRect(); gl()->PushScissorRect(); mSupportsComponentAlphaChildren = false; float opacity = GetEffectiveOpacity(); const gfx3DMatrix& transform = GetEffectiveTransform(); bool needsFramebuffer = UseIntermediateSurface(); if (needsFramebuffer) { nsIntRect framebufferRect = visibleRect; // we're about to create a framebuffer backed by textures to use as an intermediate // surface. What to do if its size (as given by framebufferRect) would exceed the // maximum texture size supported by the GL? The present code chooses the compromise // of just clamping the framebuffer's size to the max supported size. // This gives us a lower resolution rendering of the intermediate surface (children layers). // See bug 827170 for a discussion. GLint maxTexSize; gl()->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &maxTexSize); framebufferRect.width = std::min(framebufferRect.width, maxTexSize); framebufferRect.height = std::min(framebufferRect.height, maxTexSize); LayerManagerOGL::InitMode mode = LayerManagerOGL::InitModeClear; if (GetEffectiveVisibleRegion().GetNumRects() == 1 && (GetContentFlags() & Layer::CONTENT_OPAQUE)) { // don't need a background, we're going to paint all opaque stuff mSupportsComponentAlphaChildren = true; mode = LayerManagerOGL::InitModeNone; } else { const gfx3DMatrix& transform3D = GetEffectiveTransform(); gfxMatrix transform; // If we have an opaque ancestor layer, then we can be sure that // all the pixels we draw into are either opaque already or will be // covered by something opaque. Otherwise copying up the background is // not safe. if (HasOpaqueAncestorLayer(this) && transform3D.Is2D(&transform) && !transform.HasNonIntegerTranslation()) { mode = gfxPlatform::ComponentAlphaEnabled() ? LayerManagerOGL::InitModeCopy : LayerManagerOGL::InitModeClear; framebufferRect.x += transform.x0; framebufferRect.y += transform.y0; mSupportsComponentAlphaChildren = gfxPlatform::ComponentAlphaEnabled(); } } gl()->PushViewportRect(); framebufferRect -= childOffset; if (!mOGLManager->CompositingDisabled()) { if (!mOGLManager->CreateFBOWithTexture(framebufferRect, mode, aPreviousFrameBuffer, &frameBuffer, &containerSurface)) { gl()->PopViewportRect(); gl()->PopScissorRect(); gl()->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aPreviousFrameBuffer); return; } } childOffset.x = visibleRect.x; childOffset.y = visibleRect.y; } else { frameBuffer = aPreviousFrameBuffer; mSupportsComponentAlphaChildren = (GetContentFlags() & Layer::CONTENT_OPAQUE) || (GetParent() && GetParent()->SupportsComponentAlphaChildren()); } nsAutoTArray<Layer*, 12> children; SortChildrenBy3DZOrder(children); /** * Render this container's contents. */ for (uint32_t i = 0; i < children.Length(); i++) { LayerOGL* layerToRender = static_cast<LayerOGL*>(children.ElementAt(i)->ImplData()); if (layerToRender->GetLayer()->GetEffectiveVisibleRegion().IsEmpty()) { continue; } nsIntRect scissorRect = layerToRender->GetLayer()-> CalculateScissorRect(cachedScissor, &mOGLManager->GetWorldTransform()); if (scissorRect.IsEmpty()) { continue; } gl()->fScissor(scissorRect.x, scissorRect.y, scissorRect.width, scissorRect.height); layerToRender->RenderLayer(frameBuffer, childOffset); gl()->MakeCurrent(); } if (needsFramebuffer) { // Unbind the current framebuffer and rebind the previous one. #ifdef MOZ_DUMP_PAINTING if (gfxUtils::sDumpPainting) { nsRefPtr<gfxImageSurface> surf = gl()->GetTexImage(containerSurface, true, mOGLManager->GetFBOTextureFormat()); WriteSnapshotToDumpFile(this, surf); } #endif // Restore the viewport gl()->PopViewportRect(); nsIntRect viewport = gl()->ViewportRect(); mOGLManager->SetupPipeline(viewport.width, viewport.height, LayerManagerOGL::ApplyWorldTransform); gl()->PopScissorRect(); if (!mOGLManager->CompositingDisabled()) { gl()->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aPreviousFrameBuffer); gl()->fDeleteFramebuffers(1, &frameBuffer); gl()->fActiveTexture(LOCAL_GL_TEXTURE0); gl()->fBindTexture(mOGLManager->FBOTextureTarget(), containerSurface); MaskType maskType = MaskNone; if (GetMaskLayer()) { if (!GetTransform().CanDraw2D()) { maskType = Mask3d; } else { maskType = Mask2d; } } ShaderProgramOGL *rgb = mOGLManager->GetFBOLayerProgram(maskType); rgb->Activate(); rgb->SetLayerQuadRect(visibleRect); rgb->SetLayerTransform(transform); rgb->SetTextureTransform(gfx3DMatrix()); rgb->SetLayerOpacity(opacity); rgb->SetRenderOffset(aOffset); rgb->SetTextureUnit(0); rgb->LoadMask(GetMaskLayer()); if (rgb->GetTexCoordMultiplierUniformLocation() != -1) { // 2DRect case, get the multiplier right for a sampler2DRect rgb->SetTexCoordMultiplier(visibleRect.width, visibleRect.height); } // Drawing is always flipped, but when copying between surfaces we want to avoid // this. Pass true for the flip parameter to introduce a second flip // that cancels the other one out. mOGLManager->BindAndDrawQuad(rgb, true); // Clean up resources. This also unbinds the texture. gl()->fDeleteTextures(1, &containerSurface); } } else { gl()->PopScissorRect(); } }
void ContainerLayerD3D9::RenderLayer() { nsRefPtr<IDirect3DSurface9> previousRenderTarget; nsRefPtr<IDirect3DTexture9> renderTexture; float previousRenderTargetOffset[4]; RECT containerClipRect; float renderTargetOffset[] = { 0, 0, 0, 0 }; float oldViewMatrix[4][4]; device()->GetScissorRect(&containerClipRect); ReadbackProcessor readback; readback.BuildUpdates(this); nsIntRect visibleRect = mVisibleRegion.GetBounds(); PRBool useIntermediate = UseIntermediateSurface(); mSupportsComponentAlphaChildren = PR_FALSE; gfxMatrix contTransform; if (useIntermediate) { device()->GetRenderTarget(0, getter_AddRefs(previousRenderTarget)); device()->CreateTexture(visibleRect.width, visibleRect.height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, getter_AddRefs(renderTexture), NULL); nsRefPtr<IDirect3DSurface9> renderSurface; renderTexture->GetSurfaceLevel(0, getter_AddRefs(renderSurface)); device()->SetRenderTarget(0, renderSurface); if (mVisibleRegion.GetNumRects() == 1 && (GetContentFlags() & CONTENT_OPAQUE)) { // don't need a background, we're going to paint all opaque stuff mSupportsComponentAlphaChildren = PR_TRUE; } else { const gfx3DMatrix& transform3D = GetEffectiveTransform(); gfxMatrix transform; // If we have an opaque ancestor layer, then we can be sure that // all the pixels we draw into are either opaque already or will be // covered by something opaque. Otherwise copying up the background is // not safe. HRESULT hr = E_FAIL; if (HasOpaqueAncestorLayer(this) && transform3D.Is2D(&transform) && !transform.HasNonIntegerTranslation()) { // Copy background up from below RECT dest = { 0, 0, visibleRect.width, visibleRect.height }; RECT src = dest; ::OffsetRect(&src, visibleRect.x + PRInt32(transform.x0), visibleRect.y + PRInt32(transform.y0)); hr = device()-> StretchRect(previousRenderTarget, &src, renderSurface, &dest, D3DTEXF_NONE); } if (hr == S_OK) { mSupportsComponentAlphaChildren = PR_TRUE; } else { device()->Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0, 0, 0, 0), 0, 0); } } device()->GetVertexShaderConstantF(CBvRenderTargetOffset, previousRenderTargetOffset, 1); renderTargetOffset[0] = (float)visibleRect.x; renderTargetOffset[1] = (float)visibleRect.y; device()->SetVertexShaderConstantF(CBvRenderTargetOffset, renderTargetOffset, 1); gfx3DMatrix viewMatrix; /* * Matrix to transform to viewport space ( <-1.0, 1.0> topleft, * <1.0, -1.0> bottomright) */ viewMatrix._11 = 2.0f / visibleRect.width; viewMatrix._22 = -2.0f / visibleRect.height; viewMatrix._41 = -1.0f; viewMatrix._42 = 1.0f; device()->GetVertexShaderConstantF(CBmProjection, &oldViewMatrix[0][0], 4); device()->SetVertexShaderConstantF(CBmProjection, &viewMatrix._11, 4); } else { #ifdef DEBUG PRBool is2d = #endif GetEffectiveTransform().Is2D(&contTransform); NS_ASSERTION(is2d, "Transform must be 2D"); mSupportsComponentAlphaChildren = (GetContentFlags() & CONTENT_OPAQUE) || (mParent && mParent->SupportsComponentAlphaChildren()); } /* * Render this container's contents. */ for (LayerD3D9* layerToRender = GetFirstChildD3D9(); layerToRender != nsnull; layerToRender = GetNextSiblingD3D9(layerToRender)) { const nsIntRect* clipRect = layerToRender->GetLayer()->GetClipRect(); if ((clipRect && clipRect->IsEmpty()) || layerToRender->GetLayer()->GetEffectiveVisibleRegion().IsEmpty()) { continue; } if (clipRect || useIntermediate) { RECT r; if (clipRect) { r.left = (LONG)(clipRect->x - renderTargetOffset[0]); r.top = (LONG)(clipRect->y - renderTargetOffset[1]); r.right = (LONG)(clipRect->x - renderTargetOffset[0] + clipRect->width); r.bottom = (LONG)(clipRect->y - renderTargetOffset[1] + clipRect->height); } else { r.left = 0; r.top = 0; r.right = visibleRect.width; r.bottom = visibleRect.height; } nsRefPtr<IDirect3DSurface9> renderSurface; device()->GetRenderTarget(0, getter_AddRefs(renderSurface)); D3DSURFACE_DESC desc; renderSurface->GetDesc(&desc); if (!useIntermediate) { // Transform clip rect if (clipRect) { gfxRect cliprect(r.left, r.top, r.right - r.left, r.bottom - r.top); gfxRect trScissor = contTransform.TransformBounds(cliprect); trScissor.Round(); nsIntRect trIntScissor; if (gfxUtils::GfxRectToIntRect(trScissor, &trIntScissor)) { r.left = trIntScissor.x; r.top = trIntScissor.y; r.right = trIntScissor.XMost(); r.bottom = trIntScissor.YMost(); } else { r.left = 0; r.top = 0; r.right = visibleRect.width; r.bottom = visibleRect.height; clipRect = nsnull; } } // Intersect with current clip rect. r.left = NS_MAX<PRInt32>(containerClipRect.left, r.left); r.right = NS_MIN<PRInt32>(containerClipRect.right, r.right); r.top = NS_MAX<PRInt32>(containerClipRect.top, r.top); r.bottom = NS_MIN<PRInt32>(containerClipRect.bottom, r.bottom); } else { // > 0 is implied during the intersection when useIntermediate == true; r.left = NS_MAX<LONG>(0, r.left); r.top = NS_MAX<LONG>(0, r.top); } r.bottom = NS_MIN<LONG>(r.bottom, desc.Height); r.right = NS_MIN<LONG>(r.right, desc.Width); device()->SetScissorRect(&r); } if (layerToRender->GetLayer()->GetType() == TYPE_THEBES) { static_cast<ThebesLayerD3D9*>(layerToRender)->RenderThebesLayer(&readback); } else { layerToRender->RenderLayer(); } if (clipRect && !useIntermediate) { // In this situation we've set a new scissor rect and we will continue // to render directly to our container. We need to restore its scissor. // Not setting this when useIntermediate is true is an optimization since // we'll get a new one set anyway. device()->SetScissorRect(&containerClipRect); } } if (useIntermediate) { device()->SetRenderTarget(0, previousRenderTarget); device()->SetVertexShaderConstantF(CBvRenderTargetOffset, previousRenderTargetOffset, 1); device()->SetVertexShaderConstantF(CBmProjection, &oldViewMatrix[0][0], 4); device()->SetVertexShaderConstantF(CBvLayerQuad, ShaderConstantRect(visibleRect.x, visibleRect.y, visibleRect.width, visibleRect.height), 1); SetShaderTransformAndOpacity(); mD3DManager->SetShaderMode(DeviceManagerD3D9::RGBALAYER); device()->SetScissorRect(&containerClipRect); device()->SetTexture(0, renderTexture); device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); } }
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; nsRefPtr<gfxASurface> resultSurf; SharedSurface* sharedSurf = mGLContext->RequestFrame(); if (!sharedSurf) { NS_WARNING("Null frame received."); return; } IntSize readSize(ToIntSize(sharedSurf->Size())); gfxImageFormat format = (GetContentFlags() & CONTENT_OPAQUE) ? gfxImageFormatRGB24 : gfxImageFormatARGB32; 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) { SharedSurface_Basic* sharedSurf_Basic = SharedSurface_Basic::Cast(surfGL); readSurf = sharedSurf_Basic->GetData(); } 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; } } }
void BasicShadowableCanvasLayer::Paint(gfxContext* aContext, Layer* aMaskLayer) { if (!HasShadow()) { BasicCanvasLayer::Paint(aContext, aMaskLayer); return; } if (!IsDirty()) return; if (mGLContext && !mForceReadback && BasicManager()->GetParentBackendType() == mozilla::layers::LAYERS_OPENGL) { TextureImage::TextureShareType flags; // if process type is default, then it is single-process (non-e10s) if (XRE_GetProcessType() == GeckoProcessType_Default) flags = TextureImage::ThreadShared; else flags = TextureImage::ProcessShared; SharedTextureHandle handle = GetSharedBackBufferHandle(); if (!handle) { handle = mGLContext->CreateSharedHandle(flags); if (handle) { mBackBuffer = SharedTextureDescriptor(flags, handle, mBounds.Size(), false); } } if (handle) { mGLContext->MakeCurrent(); mGLContext->UpdateSharedHandle(flags, handle); // call Painted() to reset our dirty 'bit' Painted(); FireDidTransactionCallback(); BasicManager()->PaintedCanvas(BasicManager()->Hold(this), mNeedsYFlip, mBackBuffer); // Move SharedTextureHandle ownership to ShadowLayer mBackBuffer = SurfaceDescriptor(); return; } } bool isOpaque = (GetContentFlags() & CONTENT_OPAQUE); if (!IsSurfaceDescriptorValid(mBackBuffer) || isOpaque != mBufferIsOpaque) { DestroyBackBuffer(); mBufferIsOpaque = isOpaque; gfxIntSize size(mBounds.width, mBounds.height); gfxASurface::gfxContentType type = isOpaque ? gfxASurface::CONTENT_COLOR : gfxASurface::CONTENT_COLOR_ALPHA; if (!BasicManager()->AllocBuffer(size, type, &mBackBuffer)) { NS_RUNTIMEABORT("creating CanvasLayer back buffer failed!"); } } AutoOpenSurface autoBackSurface(OPEN_READ_WRITE, mBackBuffer); if (aMaskLayer) { static_cast<BasicImplData*>(aMaskLayer->ImplData()) ->Paint(aContext, nullptr); } UpdateSurface(autoBackSurface.Get(), nullptr); FireDidTransactionCallback(); BasicManager()->PaintedCanvas(BasicManager()->Hold(this), mNeedsYFlip, mBackBuffer); }