Coverage Report

Created: 2018-09-25 14:53

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