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 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 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(); } }