1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "MaskOperation.h"
8 #include "FrameBuilder.h"
9 #include "LayerMLGPU.h"
10 #include "mozilla/layers/LayersHelpers.h"
11 #include "MLGDevice.h"
12 #include "TexturedLayerMLGPU.h"
19 MaskOperation::MaskOperation(FrameBuilder
* aBuilder
) {}
21 MaskOperation::MaskOperation(FrameBuilder
* aBuilder
, MLGTexture
* aSource
)
22 : mTexture(aSource
) {}
24 MaskOperation::~MaskOperation() = default;
26 static gfx::Rect
ComputeQuadForMaskLayer(Layer
* aLayer
, const IntSize
& aSize
) {
27 const Matrix4x4
& transform
= aLayer
->GetEffectiveTransform();
28 MOZ_ASSERT(transform
.Is2D(), "Mask layers should not have 3d transforms");
30 Rect
bounds(Point(0, 0), Size(aSize
));
31 return transform
.As2D().TransformBounds(bounds
);
34 Rect
MaskOperation::ComputeMaskRect(Layer
* aLayer
) const {
35 Layer
* maskLayer
= aLayer
->GetMaskLayer() ? aLayer
->GetMaskLayer()
36 : aLayer
->GetAncestorMaskLayerAt(0);
38 (aLayer
->GetAncestorMaskLayerCount() == 0 && aLayer
->GetMaskLayer()) ||
39 (aLayer
->GetAncestorMaskLayerCount() == 1 && !aLayer
->GetMaskLayer()));
41 return ComputeQuadForMaskLayer(maskLayer
, mTexture
->GetSize());
44 // This is only needed for std::map.
45 bool MaskTexture::operator<(const MaskTexture
& aOther
) const {
46 if (mRect
.X() != aOther
.mRect
.X()) {
47 return mRect
.X() < aOther
.mRect
.X();
49 if (mRect
.Y() != aOther
.mRect
.Y()) {
50 return mRect
.Y() < aOther
.mRect
.Y();
52 if (mRect
.Width() != aOther
.mRect
.Width()) {
53 return mRect
.Width() < aOther
.mRect
.Width();
55 if (mRect
.Height() != aOther
.mRect
.Height()) {
56 return mRect
.Height() < aOther
.mRect
.Height();
58 return mSource
< aOther
.mSource
;
61 RefPtr
<TextureSource
> GetMaskLayerTexture(Layer
* aLayer
) {
62 LayerMLGPU
* layer
= aLayer
->AsHostLayer()->AsLayerMLGPU();
63 TexturedLayerMLGPU
* texLayer
= layer
->AsTexturedLayerMLGPU();
65 MOZ_ASSERT_UNREACHABLE("Mask layers should be texture layers");
69 RefPtr
<TextureSource
> source
= texLayer
->BindAndGetTexture();
71 gfxWarning() << "Mask layer does not have a TextureSource";
77 MaskCombineOperation::MaskCombineOperation(FrameBuilder
* aBuilder
)
78 : MaskOperation(aBuilder
), mBuilder(aBuilder
) {}
80 MaskCombineOperation::~MaskCombineOperation() = default;
82 void MaskCombineOperation::Init(const MaskTextureList
& aTextures
) {
83 // All masks for a single layer exist in the same coordinate space. Find the
84 // area that covers all rects.
85 Rect area
= aTextures
[0].mRect
;
86 for (size_t i
= 1; i
< aTextures
.size(); i
++) {
87 area
= area
.Intersect(aTextures
[i
].mRect
);
90 // Go through and decide which areas of the textures are relevant.
91 for (size_t i
= 0; i
< aTextures
.size(); i
++) {
92 Rect rect
= aTextures
[i
].mRect
.Intersect(area
);
97 rect
-= aTextures
[i
].mRect
.TopLeft();
98 mTextures
.push_back(MaskTexture(rect
, aTextures
[i
].mSource
));
104 bounds
.ToIntRect(&size
);
106 if (size
.IsEmpty()) {
110 mTarget
= mBuilder
->GetDevice()->CreateRenderTarget(size
.Size());
112 mTexture
= mTarget
->GetTexture();
117 void MaskCombineOperation::PrepareForRendering() {
118 for (const auto& entry
: mTextures
) {
119 Rect texCoords
= TextureRectToCoords(entry
.mRect
, entry
.mSource
->GetSize());
121 SharedVertexBuffer
* shared
= mBuilder
->GetDevice()->GetSharedVertexBuffer();
123 VertexBufferSection section
;
124 if (!shared
->Allocate(§ion
, 1, sizeof(texCoords
), &texCoords
)) {
127 mInputBuffers
.push_back(section
);
131 void MaskCombineOperation::Render() {
136 RefPtr
<MLGDevice
> device
= mBuilder
->GetDevice();
138 device
->SetTopology(MLGPrimitiveTopology::UnitQuad
);
139 device
->SetVertexShader(VertexShaderID::MaskCombiner
);
141 device
->SetPixelShader(PixelShaderID::MaskCombiner
);
142 device
->SetSamplerMode(0, SamplerMode::LinearClamp
);
143 device
->SetBlendState(MLGBlendState::Min
);
145 // Since the mask operation is effectively an AND operation, we initialize
146 // the entire r-channel to 1.
147 device
->Clear(mTarget
, DeviceColor(1, 0, 0, 1));
148 device
->SetScissorRect(Nothing());
149 device
->SetRenderTarget(mTarget
);
150 device
->SetViewport(IntRect(IntPoint(0, 0), mTarget
->GetSize()));
152 for (size_t i
= 0; i
< mInputBuffers
.size(); i
++) {
153 if (!mInputBuffers
[i
].IsValid()) {
156 device
->SetVertexBuffer(1, &mInputBuffers
[i
]);
157 device
->SetPSTexture(0, mTextures
[i
].mSource
);
158 device
->DrawInstanced(4, mInputBuffers
[i
].NumVertices(), 0, 0);
162 void AppendToMaskTextureList(MaskTextureList
& aList
, Layer
* aLayer
) {
163 RefPtr
<TextureSource
> source
= GetMaskLayerTexture(aLayer
);
168 gfx::Rect rect
= ComputeQuadForMaskLayer(aLayer
, source
->GetSize());
169 aList
.push_back(MaskTexture(rect
, source
));
172 } // namespace layers
173 } // namespace mozilla