michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "ContainerLayerD3D10.h" michael@0: michael@0: #include "ThebesLayerD3D10.h" michael@0: #include "ReadbackProcessor.h" michael@0: michael@0: using namespace mozilla::gfx; michael@0: michael@0: namespace mozilla { michael@0: namespace layers { michael@0: michael@0: ContainerLayerD3D10::ContainerLayerD3D10(LayerManagerD3D10 *aManager) michael@0: : ContainerLayer(aManager, nullptr) michael@0: , LayerD3D10(aManager) michael@0: { michael@0: mImplData = static_cast(this); michael@0: } michael@0: michael@0: ContainerLayerD3D10::~ContainerLayerD3D10() michael@0: { michael@0: while (mFirstChild) { michael@0: RemoveChild(mFirstChild); michael@0: } michael@0: } michael@0: michael@0: Layer* michael@0: ContainerLayerD3D10::GetLayer() michael@0: { michael@0: return this; michael@0: } michael@0: michael@0: LayerD3D10* michael@0: ContainerLayerD3D10::GetFirstChildD3D10() michael@0: { michael@0: if (!mFirstChild) { michael@0: return nullptr; michael@0: } michael@0: return static_cast(mFirstChild->ImplData()); michael@0: } michael@0: michael@0: static inline LayerD3D10* michael@0: GetNextSiblingD3D10(LayerD3D10* aLayer) michael@0: { michael@0: Layer* layer = aLayer->GetLayer()->GetNextSibling(); michael@0: return layer ? static_cast(layer-> michael@0: ImplData()) michael@0: : nullptr; michael@0: } michael@0: michael@0: void michael@0: ContainerLayerD3D10::RenderLayer() michael@0: { michael@0: float renderTargetOffset[] = { 0, 0 }; michael@0: michael@0: nsIntRect visibleRect = mVisibleRegion.GetBounds(); michael@0: float opacity = GetEffectiveOpacity(); michael@0: bool useIntermediate = UseIntermediateSurface(); michael@0: michael@0: nsRefPtr previousRTView; michael@0: nsRefPtr renderTexture; michael@0: nsRefPtr rtView; michael@0: float previousRenderTargetOffset[2]; michael@0: nsIntSize previousViewportSize; michael@0: michael@0: gfx3DMatrix oldViewMatrix; michael@0: michael@0: if (useIntermediate) { michael@0: device()->OMGetRenderTargets(1, getter_AddRefs(previousRTView), nullptr); michael@0: michael@0: D3D10_TEXTURE2D_DESC desc; michael@0: memset(&desc, 0, sizeof(D3D10_TEXTURE2D_DESC)); michael@0: desc.ArraySize = 1; michael@0: desc.MipLevels = 1; michael@0: desc.Width = visibleRect.width; michael@0: desc.Height = visibleRect.height; michael@0: desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE; michael@0: desc.SampleDesc.Count = 1; michael@0: desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; michael@0: HRESULT hr; michael@0: hr = device()->CreateTexture2D(&desc, nullptr, getter_AddRefs(renderTexture)); michael@0: michael@0: if (FAILED(hr)) { michael@0: LayerManagerD3D10::ReportFailure(NS_LITERAL_CSTRING("Failed to create new texture for ContainerLayerD3D10!"), michael@0: hr); michael@0: return; michael@0: } michael@0: michael@0: hr = device()->CreateRenderTargetView(renderTexture, nullptr, getter_AddRefs(rtView)); michael@0: NS_ASSERTION(SUCCEEDED(hr), "Failed to create render target view for ContainerLayerD3D10!"); michael@0: michael@0: effect()->GetVariableByName("vRenderTargetOffset")-> michael@0: GetRawValue(previousRenderTargetOffset, 0, 8); michael@0: michael@0: previousViewportSize = mD3DManager->GetViewport(); michael@0: michael@0: if (mVisibleRegion.GetNumRects() != 1 || !(GetContentFlags() & CONTENT_OPAQUE)) { michael@0: Matrix4x4 transform3D = GetEffectiveTransform(); michael@0: Matrix transform; michael@0: // If we have an opaque ancestor layer, then we can be sure that michael@0: // all the pixels we draw into are either opaque already or will be michael@0: // covered by something opaque. Otherwise copying up the background is michael@0: // not safe. michael@0: if (mSupportsComponentAlphaChildren) { michael@0: bool is2d = transform3D.Is2D(&transform); michael@0: NS_ASSERTION(is2d, "Transform should be 2d when mSupportsComponentAlphaChildren."); michael@0: michael@0: // Copy background up from below. This applies any 2D transform that is michael@0: // applied to use relative to our parent, and compensates for the offset michael@0: // that was applied on our parent's rendering. michael@0: D3D10_BOX srcBox; michael@0: srcBox.left = std::max(visibleRect.x + int32_t(transform._31) - int32_t(previousRenderTargetOffset[0]), 0); michael@0: srcBox.top = std::max(visibleRect.y + int32_t(transform._32) - int32_t(previousRenderTargetOffset[1]), 0); michael@0: srcBox.right = std::min(srcBox.left + visibleRect.width, previousViewportSize.width); michael@0: srcBox.bottom = std::min(srcBox.top + visibleRect.height, previousViewportSize.height); michael@0: srcBox.back = 1; michael@0: srcBox.front = 0; michael@0: michael@0: nsRefPtr srcResource; michael@0: previousRTView->GetResource(getter_AddRefs(srcResource)); michael@0: michael@0: device()->CopySubresourceRegion(renderTexture, 0, michael@0: 0, 0, 0, michael@0: srcResource, 0, michael@0: &srcBox); michael@0: } else { michael@0: float black[] = { 0, 0, 0, 0}; michael@0: device()->ClearRenderTargetView(rtView, black); michael@0: } michael@0: } michael@0: michael@0: ID3D10RenderTargetView *rtViewPtr = rtView; michael@0: device()->OMSetRenderTargets(1, &rtViewPtr, nullptr); michael@0: michael@0: renderTargetOffset[0] = (float)visibleRect.x; michael@0: renderTargetOffset[1] = (float)visibleRect.y; michael@0: effect()->GetVariableByName("vRenderTargetOffset")-> michael@0: SetRawValue(renderTargetOffset, 0, 8); michael@0: michael@0: mD3DManager->SetViewport(nsIntSize(visibleRect.Size())); michael@0: } michael@0: michael@0: D3D10_RECT oldD3D10Scissor; michael@0: UINT numRects = 1; michael@0: device()->RSGetScissorRects(&numRects, &oldD3D10Scissor); michael@0: // Convert scissor to an nsIntRect. D3D10_RECT's are exclusive michael@0: // on the bottom and right values. michael@0: nsIntRect oldScissor(oldD3D10Scissor.left, michael@0: oldD3D10Scissor.top, michael@0: oldD3D10Scissor.right - oldD3D10Scissor.left, michael@0: oldD3D10Scissor.bottom - oldD3D10Scissor.top); michael@0: michael@0: nsAutoTArray children; michael@0: SortChildrenBy3DZOrder(children); michael@0: michael@0: /* michael@0: * Render this container's contents. michael@0: */ michael@0: for (uint32_t i = 0; i < children.Length(); i++) { michael@0: LayerD3D10* layerToRender = static_cast(children.ElementAt(i)->ImplData()); michael@0: michael@0: if (layerToRender->GetLayer()->GetEffectiveVisibleRegion().IsEmpty()) { michael@0: continue; michael@0: } michael@0: michael@0: nsIntRect scissorRect = michael@0: layerToRender->GetLayer()->CalculateScissorRect(oldScissor, nullptr); michael@0: if (scissorRect.IsEmpty()) { michael@0: continue; michael@0: } michael@0: michael@0: D3D10_RECT d3drect; michael@0: d3drect.left = scissorRect.x; michael@0: d3drect.top = scissorRect.y; michael@0: d3drect.right = scissorRect.x + scissorRect.width; michael@0: d3drect.bottom = scissorRect.y + scissorRect.height; michael@0: device()->RSSetScissorRects(1, &d3drect); michael@0: michael@0: layerToRender->RenderLayer(); michael@0: } michael@0: michael@0: device()->RSSetScissorRects(1, &oldD3D10Scissor); michael@0: michael@0: if (useIntermediate) { michael@0: mD3DManager->SetViewport(previousViewportSize); michael@0: ID3D10RenderTargetView *rtView = previousRTView; michael@0: device()->OMSetRenderTargets(1, &rtView, nullptr); michael@0: effect()->GetVariableByName("vRenderTargetOffset")-> michael@0: SetRawValue(previousRenderTargetOffset, 0, 8); michael@0: michael@0: SetEffectTransformAndOpacity(); michael@0: michael@0: ID3D10EffectTechnique *technique; michael@0: if (LoadMaskTexture()) { michael@0: if (GetTransform().CanDraw2D()) { michael@0: technique = SelectShader(SHADER_RGBA | SHADER_PREMUL | SHADER_MASK); michael@0: } else { michael@0: technique = SelectShader(SHADER_RGBA | SHADER_PREMUL | SHADER_MASK_3D); michael@0: } michael@0: } else { michael@0: technique = SelectShader(SHADER_RGBA | SHADER_PREMUL | SHADER_NO_MASK); michael@0: } michael@0: michael@0: effect()->GetVariableByName("vLayerQuad")->AsVector()->SetFloatVector( michael@0: ShaderConstantRectD3D10( michael@0: (float)visibleRect.x, michael@0: (float)visibleRect.y, michael@0: (float)visibleRect.width, michael@0: (float)visibleRect.height) michael@0: ); michael@0: michael@0: technique->GetPassByIndex(0)->Apply(0); michael@0: michael@0: ID3D10ShaderResourceView *view; michael@0: device()->CreateShaderResourceView(renderTexture, nullptr, &view); michael@0: device()->PSSetShaderResources(0, 1, &view); michael@0: device()->Draw(4, 0); michael@0: view->Release(); michael@0: } michael@0: } michael@0: michael@0: void michael@0: ContainerLayerD3D10::LayerManagerDestroyed() michael@0: { michael@0: while (mFirstChild) { michael@0: GetFirstChildD3D10()->LayerManagerDestroyed(); michael@0: RemoveChild(mFirstChild); michael@0: } michael@0: } michael@0: michael@0: void michael@0: ContainerLayerD3D10::Validate() michael@0: { michael@0: nsIntRect visibleRect = mVisibleRegion.GetBounds(); michael@0: michael@0: mSupportsComponentAlphaChildren = false; michael@0: michael@0: if (UseIntermediateSurface()) { michael@0: Matrix4x4 transform3D = GetEffectiveTransform(); michael@0: Matrix transform; michael@0: michael@0: if (mVisibleRegion.GetNumRects() == 1 && (GetContentFlags() & CONTENT_OPAQUE)) { michael@0: // don't need a background, we're going to paint all opaque stuff michael@0: mSupportsComponentAlphaChildren = true; michael@0: } else { michael@0: if (HasOpaqueAncestorLayer(this) && michael@0: transform3D.Is2D(&transform) && !ThebesMatrix(transform).HasNonIntegerTranslation() && michael@0: GetParent()->GetEffectiveVisibleRegion().GetBounds().Contains(visibleRect)) michael@0: { michael@0: // In this case we can copy up the background. See RenderLayer. michael@0: mSupportsComponentAlphaChildren = true; michael@0: } michael@0: } michael@0: } else { michael@0: mSupportsComponentAlphaChildren = (GetContentFlags() & CONTENT_OPAQUE) || michael@0: (mParent && mParent->SupportsComponentAlphaChildren()); michael@0: } michael@0: michael@0: ReadbackProcessor readback; michael@0: readback.BuildUpdates(this); michael@0: michael@0: Layer *layer = GetFirstChild(); michael@0: while (layer) { michael@0: if (layer->GetType() == TYPE_THEBES) { michael@0: static_cast(layer)->Validate(&readback); michael@0: } else { michael@0: static_cast(layer->ImplData())->Validate(); michael@0: } michael@0: layer = layer->GetNextSibling(); michael@0: } michael@0: } michael@0: michael@0: } /* layers */ michael@0: } /* mozilla */