Line data Source code
1 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : * This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #include "MaskOperation.h"
7 : #include "FrameBuilder.h"
8 : #include "LayerMLGPU.h"
9 : #include "mozilla/layers/LayersHelpers.h"
10 : #include "MLGDevice.h"
11 : #include "TexturedLayerMLGPU.h"
12 :
13 : namespace mozilla {
14 : namespace layers {
15 :
16 : using namespace gfx;
17 :
18 0 : MaskOperation::MaskOperation(FrameBuilder* aBuilder)
19 : {
20 0 : }
21 :
22 0 : MaskOperation::MaskOperation(FrameBuilder* aBuilder, MLGTexture* aSource)
23 0 : : mTexture(aSource)
24 : {
25 0 : }
26 :
27 0 : MaskOperation::~MaskOperation()
28 : {
29 0 : }
30 :
31 : static gfx::Rect
32 0 : ComputeQuadForMaskLayer(Layer* aLayer, const IntSize& aSize)
33 : {
34 0 : const Matrix4x4& transform = aLayer->GetEffectiveTransform();
35 0 : MOZ_ASSERT(transform.Is2D(), "Mask layers should not have 3d transforms");
36 :
37 0 : Rect bounds(Point(0, 0), Size(aSize));
38 0 : return transform.As2D().TransformBounds(bounds);
39 : }
40 :
41 : Rect
42 0 : MaskOperation::ComputeMaskRect(Layer* aLayer) const
43 : {
44 0 : Layer* maskLayer = aLayer->GetMaskLayer()
45 0 : ? aLayer->GetMaskLayer()
46 0 : : aLayer->GetAncestorMaskLayerAt(0);
47 0 : MOZ_ASSERT((aLayer->GetAncestorMaskLayerCount() == 0 && aLayer->GetMaskLayer()) ||
48 : (aLayer->GetAncestorMaskLayerCount() == 1 && !aLayer->GetMaskLayer()));
49 :
50 0 : return ComputeQuadForMaskLayer(maskLayer, mTexture->GetSize());
51 : }
52 :
53 : // This is only needed for std::map.
54 : bool
55 0 : MaskTexture::operator <(const MaskTexture& aOther) const
56 : {
57 0 : if (mRect.x != aOther.mRect.x) {
58 0 : return mRect.x < aOther.mRect.x;
59 : }
60 0 : if (mRect.y != aOther.mRect.y) {
61 0 : return mRect.y < aOther.mRect.y;
62 : }
63 0 : if (mRect.width != aOther.mRect.width) {
64 0 : return mRect.width < aOther.mRect.width;
65 : }
66 0 : if (mRect.height != aOther.mRect.height) {
67 0 : return mRect.height < aOther.mRect.height;
68 : }
69 0 : return mSource < aOther.mSource;
70 : }
71 :
72 : RefPtr<TextureSource>
73 0 : GetMaskLayerTexture(Layer* aLayer)
74 : {
75 0 : LayerMLGPU* layer = aLayer->AsHostLayer()->AsLayerMLGPU();
76 0 : TexturedLayerMLGPU* texLayer = layer->AsTexturedLayerMLGPU();
77 0 : if (!texLayer) {
78 0 : MOZ_ASSERT_UNREACHABLE("Mask layers should be texture layers");
79 : return nullptr;
80 : }
81 :
82 0 : RefPtr<TextureSource> source = texLayer->BindAndGetTexture();
83 0 : if (!source) {
84 0 : gfxWarning() << "Mask layer does not have a TextureSource";
85 0 : return nullptr;
86 : }
87 0 : return source.forget();
88 : }
89 :
90 0 : MaskCombineOperation::MaskCombineOperation(FrameBuilder* aBuilder)
91 : : MaskOperation(aBuilder),
92 0 : mBuilder(aBuilder)
93 : {
94 0 : }
95 :
96 0 : MaskCombineOperation::~MaskCombineOperation()
97 : {
98 0 : }
99 :
100 : void
101 0 : MaskCombineOperation::Init(const MaskTextureList& aTextures)
102 : {
103 : // All masks for a single layer exist in the same coordinate space. Find the
104 : // area that covers all rects.
105 0 : Rect area = aTextures[0].mRect;
106 0 : for (size_t i = 1; i < aTextures.size(); i++) {
107 0 : area = area.Intersect(aTextures[i].mRect);
108 : }
109 :
110 : // Go through and decide which areas of the textures are relevant.
111 0 : for (size_t i = 0; i < aTextures.size(); i++) {
112 0 : Rect rect = aTextures[i].mRect.Intersect(area);
113 0 : if (rect.IsEmpty()) {
114 0 : continue;
115 : }
116 :
117 0 : rect -= aTextures[i].mRect.TopLeft();
118 0 : mTextures.push_back(MaskTexture(rect, aTextures[i].mSource));
119 : }
120 :
121 0 : IntRect size;
122 0 : Rect bounds = area;
123 0 : bounds.RoundOut();
124 0 : bounds.ToIntRect(&size);
125 :
126 0 : mTarget = mBuilder->GetDevice()->CreateRenderTarget(size.Size());
127 0 : mArea = area;
128 0 : mTexture = mTarget->GetTexture();
129 0 : }
130 :
131 : void
132 0 : MaskCombineOperation::PrepareForRendering()
133 : {
134 0 : for (const auto& entry : mTextures) {
135 0 : Rect texCoords = TextureRectToCoords(entry.mRect, entry.mSource->GetSize());
136 :
137 0 : SharedVertexBuffer* shared = mBuilder->GetDevice()->GetSharedVertexBuffer();
138 :
139 0 : VertexBufferSection section;
140 0 : if (!shared->Allocate(§ion, 1, sizeof(texCoords), &texCoords)) {
141 0 : continue;
142 : }
143 0 : mInputBuffers.push_back(section);
144 : }
145 0 : }
146 :
147 : void
148 0 : MaskCombineOperation::Render()
149 : {
150 0 : RefPtr<MLGDevice> device = mBuilder->GetDevice();
151 :
152 0 : device->SetTopology(MLGPrimitiveTopology::UnitQuad);
153 0 : device->SetVertexShader(VertexShaderID::MaskCombiner);
154 :
155 0 : device->SetPixelShader(PixelShaderID::MaskCombiner);
156 0 : device->SetSamplerMode(0, SamplerMode::LinearClamp);
157 0 : device->SetBlendState(MLGBlendState::Min);
158 :
159 : // Since the mask operation is effectively an AND operation, we initialize
160 : // the entire r-channel to 1.
161 0 : device->Clear(mTarget, Color(1, 0, 0, 1));
162 0 : device->SetScissorRect(Nothing());
163 0 : device->SetRenderTarget(mTarget);
164 0 : device->SetViewport(IntRect(IntPoint(0, 0), mTarget->GetSize()));
165 :
166 0 : for (size_t i = 0; i < mInputBuffers.size(); i++) {
167 0 : if (!mInputBuffers[i].IsValid()) {
168 0 : continue;
169 : }
170 0 : device->SetVertexBuffer(1, &mInputBuffers[i]);
171 0 : device->SetPSTexture(0, mTextures[i].mSource);
172 0 : device->DrawInstanced(4, mInputBuffers[i].NumVertices(), 0, 0);
173 : }
174 0 : }
175 :
176 : void
177 0 : AppendToMaskTextureList(MaskTextureList& aList, Layer* aLayer)
178 : {
179 0 : RefPtr<TextureSource> source = GetMaskLayerTexture(aLayer);
180 0 : if (!source) {
181 0 : return;
182 : }
183 :
184 0 : gfx::Rect rect = ComputeQuadForMaskLayer(aLayer, source->GetSize());
185 0 : aList.push_back(MaskTexture(rect, source));
186 : }
187 :
188 : } // namespace layers
189 : } // namespace mozilla
|