/src/mozilla-central/gfx/layers/mlgpu/RenderPassMLGPU.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 "RenderPassMLGPU.h" |
8 | | #include "ContainerLayerMLGPU.h" |
9 | | #include "FrameBuilder.h" |
10 | | #include "ImageLayerMLGPU.h" |
11 | | #include "LayersLogging.h" |
12 | | #include "MaskOperation.h" |
13 | | #include "MLGDevice.h" |
14 | | #include "PaintedLayerMLGPU.h" |
15 | | #include "RenderViewMLGPU.h" |
16 | | #include "ShaderDefinitionsMLGPU.h" |
17 | | #include "ShaderDefinitionsMLGPU-inl.h" |
18 | | #include "SharedBufferMLGPU.h" |
19 | | #include "mozilla/layers/LayersHelpers.h" |
20 | | #include "mozilla/layers/LayersMessages.h" |
21 | | #include "RenderPassMLGPU-inl.h" |
22 | | |
23 | | namespace mozilla { |
24 | | namespace layers { |
25 | | |
26 | | using namespace gfx; |
27 | | |
28 | | ItemInfo::ItemInfo(FrameBuilder* aBuilder, |
29 | | RenderViewMLGPU* aView, |
30 | | LayerMLGPU* aLayer, |
31 | | int32_t aSortOrder, |
32 | | const IntRect& aBounds, |
33 | | Maybe<Polygon>&& aGeometry) |
34 | | : view(aView), |
35 | | layer(aLayer), |
36 | | type(RenderPassType::Unknown), |
37 | | layerIndex(kInvalidResourceIndex), |
38 | | sortOrder(aSortOrder), |
39 | | bounds(aBounds), |
40 | | geometry(std::move(aGeometry)) |
41 | 0 | { |
42 | 0 | const Matrix4x4& transform = aLayer->GetLayer()->GetEffectiveTransform(); |
43 | 0 |
|
44 | 0 | Matrix transform2D; |
45 | 0 | if (!geometry && |
46 | 0 | transform.Is2D(&transform2D) && |
47 | 0 | transform2D.IsRectilinear()) |
48 | 0 | { |
49 | 0 | this->rectilinear = true; |
50 | 0 | if (transform2D.IsIntegerTranslation()) { |
51 | 0 | this->translation = Some(IntPoint::Truncate(transform2D.GetTranslation())); |
52 | 0 | } |
53 | 0 | } else { |
54 | 0 | this->rectilinear = false; |
55 | 0 | } |
56 | 0 |
|
57 | 0 | // Layers can have arbitrary clips or transforms, and we can't use built-in |
58 | 0 | // scissor functionality when batching. Instead, pixel shaders will write |
59 | 0 | // transparent pixels for positions outside of the clip. Unfortunately that |
60 | 0 | // breaks z-buffering because the transparent pixels will still write to |
61 | 0 | // the depth buffer. |
62 | 0 | // |
63 | 0 | // To make this work, we clamp the final vertices in the vertex shader to |
64 | 0 | // the clip rect. We can only do this for rectilinear transforms. If a |
65 | 0 | // transform can produce a rotation or perspective change, then we might |
66 | 0 | // accidentally change the geometry. These items are not treated as |
67 | 0 | // opaque. |
68 | 0 | // |
69 | 0 | // Also, we someday want non-rectilinear items to be antialiased with DEAA, |
70 | 0 | // and we can't do this if the items are rendered front-to-back, since |
71 | 0 | // such items cannot be blended. (Though we could consider adding these |
72 | 0 | // items in two separate draw calls, one for DEAA and for not - that is |
73 | 0 | // definitely future work.) |
74 | 0 | if (aLayer->GetComputedOpacity() != 1.0f || |
75 | 0 | aLayer->GetMask() || |
76 | 0 | !aLayer->IsContentOpaque() || |
77 | 0 | !rectilinear) |
78 | 0 | { |
79 | 0 | this->opaque = false; |
80 | 0 | this->renderOrder = RenderOrder::BackToFront; |
81 | 0 | } else { |
82 | 0 | this->opaque = true; |
83 | 0 | this->renderOrder = aView->HasDepthBuffer() |
84 | 0 | ? RenderOrder::FrontToBack |
85 | 0 | : RenderOrder::BackToFront; |
86 | 0 | } |
87 | 0 |
|
88 | 0 | this->type = RenderPassMLGPU::GetPreferredPassType(aBuilder, *this); |
89 | 0 | } |
90 | | |
91 | | RenderPassType |
92 | | RenderPassMLGPU::GetPreferredPassType(FrameBuilder* aBuilder, const ItemInfo& aItem) |
93 | 0 | { |
94 | 0 | LayerMLGPU* layer = aItem.layer; |
95 | 0 | switch (layer->GetType()) { |
96 | 0 | case Layer::TYPE_COLOR: |
97 | 0 | { |
98 | 0 | if (aBuilder->GetDevice()->CanUseClearView() && |
99 | 0 | aItem.HasRectTransformAndClip() && |
100 | 0 | aItem.translation && |
101 | 0 | aItem.opaque && |
102 | 0 | !aItem.view->HasDepthBuffer()) |
103 | 0 | { |
104 | 0 | // Note: we don't have ClearView set up to do depth buffer writes, so we |
105 | 0 | // exclude depth buffering from the test above. |
106 | 0 | return RenderPassType::ClearView; |
107 | 0 | } |
108 | 0 | return RenderPassType::SolidColor; |
109 | 0 | } |
110 | 0 | case Layer::TYPE_PAINTED: { |
111 | 0 | PaintedLayerMLGPU* painted = layer->AsPaintedLayerMLGPU(); |
112 | 0 | if (painted->HasComponentAlpha()) { |
113 | 0 | return RenderPassType::ComponentAlpha; |
114 | 0 | } |
115 | 0 | return RenderPassType::SingleTexture; |
116 | 0 | } |
117 | 0 | case Layer::TYPE_CANVAS: |
118 | 0 | return RenderPassType::SingleTexture; |
119 | 0 | case Layer::TYPE_IMAGE: { |
120 | 0 | ImageHost* host = layer->AsTexturedLayerMLGPU()->GetImageHost(); |
121 | 0 | TextureHost* texture = host->CurrentTextureHost(); |
122 | 0 | if (texture->GetReadFormat() == SurfaceFormat::YUV || |
123 | 0 | texture->GetReadFormat() == SurfaceFormat::NV12) |
124 | 0 | { |
125 | 0 | return RenderPassType::Video; |
126 | 0 | } |
127 | 0 | return RenderPassType::SingleTexture; |
128 | 0 | } |
129 | 0 | case Layer::TYPE_CONTAINER: |
130 | 0 | return RenderPassType::RenderView; |
131 | 0 | default: |
132 | 0 | return RenderPassType::Unknown; |
133 | 0 | } |
134 | 0 | } |
135 | | |
136 | | RefPtr<RenderPassMLGPU> |
137 | | RenderPassMLGPU::CreatePass(FrameBuilder* aBuilder, const ItemInfo& aItem) |
138 | | { |
139 | | switch (aItem.type) { |
140 | | case RenderPassType::SolidColor: |
141 | | return MakeAndAddRef<SolidColorPass>(aBuilder, aItem); |
142 | | case RenderPassType::SingleTexture: |
143 | | return MakeAndAddRef<SingleTexturePass>(aBuilder, aItem); |
144 | | case RenderPassType::RenderView: |
145 | | return MakeAndAddRef<RenderViewPass>(aBuilder, aItem); |
146 | | case RenderPassType::Video: |
147 | | return MakeAndAddRef<VideoRenderPass>(aBuilder, aItem); |
148 | | case RenderPassType::ComponentAlpha: |
149 | | return MakeAndAddRef<ComponentAlphaPass>(aBuilder, aItem); |
150 | | case RenderPassType::ClearView: |
151 | | return MakeAndAddRef<ClearViewPass>(aBuilder, aItem); |
152 | | default: |
153 | | return nullptr; |
154 | | } |
155 | | } |
156 | | |
157 | | RenderPassMLGPU::RenderPassMLGPU(FrameBuilder* aBuilder, const ItemInfo& aItem) |
158 | | : mBuilder(aBuilder), |
159 | | mDevice(aBuilder->GetDevice()), |
160 | | mLayerBufferIndex(aBuilder->CurrentLayerBufferIndex()), |
161 | | mMaskRectBufferIndex(kInvalidResourceIndex), |
162 | | mPrepared(false) |
163 | 0 | { |
164 | 0 | } |
165 | | |
166 | | RenderPassMLGPU::~RenderPassMLGPU() |
167 | 0 | { |
168 | 0 | } |
169 | | |
170 | | bool |
171 | | RenderPassMLGPU::IsCompatible(const ItemInfo& aItem) |
172 | 0 | { |
173 | 0 | if (GetType() != aItem.type) { |
174 | 0 | return false; |
175 | 0 | } |
176 | 0 | if (mLayerBufferIndex != mBuilder->CurrentLayerBufferIndex()) { |
177 | 0 | return false; |
178 | 0 | } |
179 | 0 | return true; |
180 | 0 | } |
181 | | |
182 | | bool |
183 | | RenderPassMLGPU::AcceptItem(ItemInfo& aInfo) |
184 | 0 | { |
185 | 0 | MOZ_ASSERT(IsCompatible(aInfo)); |
186 | 0 |
|
187 | 0 | if (!AddToPass(aInfo.layer, aInfo)) { |
188 | 0 | return false; |
189 | 0 | } |
190 | 0 | |
191 | 0 | if (aInfo.renderOrder == RenderOrder::BackToFront) { |
192 | 0 | mAffectedRegion.OrWith(aInfo.bounds); |
193 | 0 | mAffectedRegion.SimplifyOutward(4); |
194 | 0 | } |
195 | 0 | return true; |
196 | 0 | } |
197 | | |
198 | | bool |
199 | | RenderPassMLGPU::Intersects(const ItemInfo& aItem) |
200 | 0 | { |
201 | 0 | MOZ_ASSERT(aItem.renderOrder == RenderOrder::BackToFront); |
202 | 0 | return !mAffectedRegion.Intersect(aItem.bounds).IsEmpty(); |
203 | 0 | } |
204 | | |
205 | | void |
206 | | RenderPassMLGPU::PrepareForRendering() |
207 | 0 | { |
208 | 0 | mPrepared = true; |
209 | 0 | } |
210 | | |
211 | | ShaderRenderPass::ShaderRenderPass(FrameBuilder* aBuilder, const ItemInfo& aItem) |
212 | | : RenderPassMLGPU(aBuilder, aItem), |
213 | | mGeometry(GeometryMode::Unknown), |
214 | | mHasRectTransformAndClip(aItem.HasRectTransformAndClip()) |
215 | 0 | { |
216 | 0 | mMask = aItem.layer->GetMask(); |
217 | 0 | if (mMask) { |
218 | 0 | mMaskRectBufferIndex = mBuilder->CurrentMaskRectBufferIndex(); |
219 | 0 | } |
220 | 0 | } |
221 | | |
222 | | bool |
223 | | ShaderRenderPass::IsCompatible(const ItemInfo& aItem) |
224 | 0 | { |
225 | 0 | MOZ_ASSERT(mGeometry != GeometryMode::Unknown); |
226 | 0 |
|
227 | 0 | if (!RenderPassMLGPU::IsCompatible(aItem)) { |
228 | 0 | return false; |
229 | 0 | } |
230 | 0 | |
231 | 0 | // A masked batch cannot accept non-masked items, since the pixel shader |
232 | 0 | // bakes in whether a mask is present. Also, the pixel shader can only bind |
233 | 0 | // one specific mask at a time. |
234 | 0 | if (aItem.layer->GetMask() != mMask) { |
235 | 0 | return false; |
236 | 0 | } |
237 | 0 | if (mMask && mBuilder->CurrentMaskRectBufferIndex() != mMaskRectBufferIndex) { |
238 | 0 | return false; |
239 | 0 | } |
240 | 0 | |
241 | 0 | // We key batches on this property, since we can use more efficient pixel |
242 | 0 | // shaders if we don't need to propagate a clip and a mask. |
243 | 0 | if (mHasRectTransformAndClip != aItem.HasRectTransformAndClip()) { |
244 | 0 | return false; |
245 | 0 | } |
246 | 0 | |
247 | 0 | // We should be assured at this point, that if the item requires complex |
248 | 0 | // geometry, then it should have already been rejected from a unit-quad |
249 | 0 | // batch. Therefore this batch should be in polygon mode. |
250 | 0 | MOZ_ASSERT_IF(aItem.geometry.isSome(), mGeometry == GeometryMode::Polygon); |
251 | 0 | return true; |
252 | 0 | } |
253 | | |
254 | | void |
255 | | ShaderRenderPass::SetGeometry(const ItemInfo& aItem, GeometryMode aMode) |
256 | 0 | { |
257 | 0 | MOZ_ASSERT(mGeometry == GeometryMode::Unknown); |
258 | 0 |
|
259 | 0 | if (aMode == GeometryMode::Unknown) { |
260 | 0 | mGeometry = mHasRectTransformAndClip |
261 | 0 | ? GeometryMode::UnitQuad |
262 | 0 | : GeometryMode::Polygon; |
263 | 0 | } else { |
264 | 0 | mGeometry = aMode; |
265 | 0 | } |
266 | 0 |
|
267 | 0 | // Since we process layers front-to-back, back-to-front items are |
268 | 0 | // in the wrong order. We address this by automatically reversing |
269 | 0 | // the buffers we use to build vertices. |
270 | 0 | if (aItem.renderOrder != RenderOrder::FrontToBack) { |
271 | 0 | mInstances.SetReversed(); |
272 | 0 | } |
273 | 0 | } |
274 | | |
275 | | void |
276 | | ShaderRenderPass::PrepareForRendering() |
277 | 0 | { |
278 | 0 | if (mInstances.IsEmpty()) { |
279 | 0 | return; |
280 | 0 | } |
281 | 0 | if (!mDevice->GetSharedVertexBuffer()->Allocate(&mInstanceBuffer, mInstances) || |
282 | 0 | !SetupPSBuffer0(GetOpacity()) || |
283 | 0 | !OnPrepareBuffers()) |
284 | 0 | { |
285 | 0 | return; |
286 | 0 | } |
287 | 0 | return RenderPassMLGPU::PrepareForRendering(); |
288 | 0 | } |
289 | | |
290 | | bool |
291 | | ShaderRenderPass::SetupPSBuffer0(float aOpacity) |
292 | 0 | { |
293 | 0 | if (aOpacity == 1.0f && !HasMask()) { |
294 | 0 | mPSBuffer0 = mBuilder->GetDefaultMaskInfo(); |
295 | 0 | return true; |
296 | 0 | } |
297 | 0 | |
298 | 0 | MaskInformation cb(aOpacity, HasMask()); |
299 | 0 | return mDevice->GetSharedPSBuffer()->Allocate(&mPSBuffer0, cb); |
300 | 0 | } |
301 | | |
302 | | void |
303 | | ShaderRenderPass::ExecuteRendering() |
304 | 0 | { |
305 | 0 | if (mInstances.IsEmpty()) { |
306 | 0 | return; |
307 | 0 | } |
308 | 0 | |
309 | 0 | // Change the blend state if needed. |
310 | 0 | if (Maybe<MLGBlendState> blendState = GetBlendState()) { |
311 | 0 | mDevice->SetBlendState(blendState.value()); |
312 | 0 | } |
313 | 0 |
|
314 | 0 | mDevice->SetPSConstantBuffer(0, &mPSBuffer0); |
315 | 0 | if (MaskOperation* mask = GetMask()) { |
316 | 0 | mDevice->SetPSTexture(kMaskLayerTextureSlot, mask->GetTexture()); |
317 | 0 | mDevice->SetSamplerMode(kMaskSamplerSlot, SamplerMode::LinearClampToZero); |
318 | 0 | } |
319 | 0 |
|
320 | 0 | SetupPipeline(); |
321 | 0 |
|
322 | 0 | if (mGeometry == GeometryMode::Polygon) { |
323 | 0 | mDevice->SetTopology(MLGPrimitiveTopology::UnitTriangle); |
324 | 0 | } else { |
325 | 0 | mDevice->SetTopology(MLGPrimitiveTopology::UnitQuad); |
326 | 0 | } |
327 | 0 | mDevice->SetVertexBuffer(1, &mInstanceBuffer); |
328 | 0 |
|
329 | 0 | if (mGeometry == GeometryMode::Polygon) { |
330 | 0 | mDevice->DrawInstanced(3, mInstanceBuffer.NumVertices(), 0, 0); |
331 | 0 | } else { |
332 | 0 | mDevice->DrawInstanced(4, mInstanceBuffer.NumVertices(), 0, 0); |
333 | 0 | } |
334 | 0 | } |
335 | | |
336 | | static inline Color |
337 | | ComputeLayerColor(LayerMLGPU* aLayer, const Color& aColor) |
338 | 0 | { |
339 | 0 | float opacity = aLayer->GetComputedOpacity(); |
340 | 0 | return Color( |
341 | 0 | aColor.r * aColor.a * opacity, |
342 | 0 | aColor.g * aColor.a * opacity, |
343 | 0 | aColor.b * aColor.a * opacity, |
344 | 0 | aColor.a * opacity); |
345 | 0 | } |
346 | | |
347 | | ClearViewPass::ClearViewPass(FrameBuilder* aBuilder, const ItemInfo& aItem) |
348 | | : RenderPassMLGPU(aBuilder, aItem), |
349 | | mView(aItem.view) |
350 | 0 | { |
351 | 0 | // Note: we could write to the depth buffer, but since the depth buffer is |
352 | 0 | // disabled by default, we don't bother yet. |
353 | 0 | MOZ_ASSERT(!mView->HasDepthBuffer()); |
354 | 0 |
|
355 | 0 | ColorLayer* colorLayer = aItem.layer->GetLayer()->AsColorLayer(); |
356 | 0 | mColor = ComputeLayerColor(aItem.layer, colorLayer->GetColor()); |
357 | 0 | } |
358 | | |
359 | | bool |
360 | | ClearViewPass::IsCompatible(const ItemInfo& aItem) |
361 | 0 | { |
362 | 0 | if (!RenderPassMLGPU::IsCompatible(aItem)) { |
363 | 0 | return false; |
364 | 0 | } |
365 | 0 | |
366 | 0 | // These should be true if we computed a ClearView pass type. |
367 | 0 | MOZ_ASSERT(aItem.translation); |
368 | 0 | MOZ_ASSERT(aItem.opaque); |
369 | 0 | MOZ_ASSERT(aItem.HasRectTransformAndClip()); |
370 | 0 |
|
371 | 0 | // Each call only supports a single color. |
372 | 0 | ColorLayer* colorLayer = aItem.layer->GetLayer()->AsColorLayer(); |
373 | 0 | if (mColor != ComputeLayerColor(aItem.layer, colorLayer->GetColor())) { |
374 | 0 | return false; |
375 | 0 | } |
376 | 0 | |
377 | 0 | // We don't support opacity here since it would not blend correctly. |
378 | 0 | MOZ_ASSERT(mColor.a == 1.0f); |
379 | 0 | return true; |
380 | 0 | } |
381 | | |
382 | | bool |
383 | | ClearViewPass::AddToPass(LayerMLGPU* aItem, ItemInfo& aInfo) |
384 | 0 | { |
385 | 0 | const LayerIntRegion& region = aItem->GetRenderRegion(); |
386 | 0 | for (auto iter = region.RectIter(); !iter.Done(); iter.Next()) { |
387 | 0 | IntRect rect = iter.Get().ToUnknownRect(); |
388 | 0 | rect += aInfo.translation.value(); |
389 | 0 | rect -= mView->GetTargetOffset(); |
390 | 0 | mRects.AppendElement(rect); |
391 | 0 | } |
392 | 0 | return true; |
393 | 0 | } |
394 | | |
395 | | void |
396 | | ClearViewPass::ExecuteRendering() |
397 | 0 | { |
398 | 0 | mDevice->ClearView(mDevice->GetRenderTarget(), mColor, mRects.Elements(), mRects.Length()); |
399 | 0 | } |
400 | | |
401 | | SolidColorPass::SolidColorPass(FrameBuilder* aBuilder, const ItemInfo& aItem) |
402 | | : BatchRenderPass(aBuilder, aItem) |
403 | 0 | { |
404 | 0 | SetDefaultGeometry(aItem); |
405 | 0 | } |
406 | | |
407 | | bool |
408 | | SolidColorPass::AddToPass(LayerMLGPU* aLayer, ItemInfo& aInfo) |
409 | 0 | { |
410 | 0 | MOZ_ASSERT(aLayer->GetType() == Layer::TYPE_COLOR); |
411 | 0 |
|
412 | 0 | ColorLayer* colorLayer = aLayer->GetLayer()->AsColorLayer(); |
413 | 0 |
|
414 | 0 | Txn txn(this); |
415 | 0 |
|
416 | 0 | gfx::Color color = ComputeLayerColor(aLayer, colorLayer->GetColor()); |
417 | 0 |
|
418 | 0 | const LayerIntRegion& region = aLayer->GetRenderRegion(); |
419 | 0 | for (auto iter = region.RectIter(); !iter.Done(); iter.Next()) { |
420 | 0 | const IntRect rect = iter.Get().ToUnknownRect(); |
421 | 0 | ColorTraits traits(aInfo, Rect(rect), color); |
422 | 0 |
|
423 | 0 | if (!txn.Add(traits)) { |
424 | 0 | return false; |
425 | 0 | } |
426 | 0 | } |
427 | 0 | return txn.Commit(); |
428 | 0 | } |
429 | | |
430 | | float |
431 | | SolidColorPass::GetOpacity() const |
432 | 0 | { |
433 | 0 | // Note our pixel shader just ignores the opacity, since we baked it |
434 | 0 | // into our color values already. Just return 1, which ensures we can |
435 | 0 | // use the default constant buffer binding. |
436 | 0 | return 1.0f; |
437 | 0 | } |
438 | | |
439 | | void |
440 | | SolidColorPass::SetupPipeline() |
441 | 0 | { |
442 | 0 | if (mGeometry == GeometryMode::UnitQuad) { |
443 | 0 | mDevice->SetVertexShader(VertexShaderID::ColoredQuad); |
444 | 0 | mDevice->SetPixelShader(PixelShaderID::ColoredQuad); |
445 | 0 | } else { |
446 | 0 | mDevice->SetVertexShader(VertexShaderID::ColoredVertex); |
447 | 0 | mDevice->SetPixelShader(PixelShaderID::ColoredVertex); |
448 | 0 | } |
449 | 0 | } |
450 | | |
451 | | TexturedRenderPass::TexturedRenderPass(FrameBuilder* aBuilder, const ItemInfo& aItem) |
452 | | : BatchRenderPass(aBuilder, aItem), |
453 | | mTextureFlags(TextureFlags::NO_FLAGS) |
454 | 0 | { |
455 | 0 | } |
456 | | |
457 | | TexturedRenderPass::Info::Info(const ItemInfo& aItem, PaintedLayerMLGPU* aLayer) |
458 | | : item(aItem), |
459 | | textureSize(aLayer->GetTexture()->GetSize()), |
460 | | destOrigin(aLayer->GetDestOrigin()), |
461 | | decomposeIntoNoRepeatRects(aLayer->MayResample()) |
462 | 0 | { |
463 | 0 | } |
464 | | |
465 | | TexturedRenderPass::Info::Info(const ItemInfo& aItem, TexturedLayerMLGPU* aLayer) |
466 | | : item(aItem), |
467 | | textureSize(aLayer->GetTexture()->GetSize()), |
468 | | scale(aLayer->GetPictureScale()), |
469 | | decomposeIntoNoRepeatRects(false) |
470 | 0 | { |
471 | 0 | } |
472 | | |
473 | | TexturedRenderPass::Info::Info(const ItemInfo& aItem, ContainerLayerMLGPU* aLayer) |
474 | | : item(aItem), |
475 | | textureSize(aLayer->GetTargetSize()), |
476 | | destOrigin(aLayer->GetTargetOffset()), |
477 | | decomposeIntoNoRepeatRects(false) |
478 | 0 | { |
479 | 0 | } |
480 | | |
481 | | bool |
482 | | TexturedRenderPass::AddItem(Txn& aTxn, |
483 | | const Info& aInfo, |
484 | | const Rect& aDrawRect) |
485 | 0 | { |
486 | 0 | if (mGeometry == GeometryMode::Polygon) { |
487 | 0 | // This path will not clamp the draw rect to the layer clip, so we can pass |
488 | 0 | // the draw rect texture rects straight through. |
489 | 0 | return AddClippedItem(aTxn, aInfo, aDrawRect); |
490 | 0 | } |
491 | 0 | |
492 | 0 | const ItemInfo& item = aInfo.item; |
493 | 0 |
|
494 | 0 | MOZ_ASSERT(!item.geometry); |
495 | 0 | MOZ_ASSERT(item.HasRectTransformAndClip()); |
496 | 0 | MOZ_ASSERT(mHasRectTransformAndClip); |
497 | 0 |
|
498 | 0 | const Matrix4x4& fullTransform = item.layer->GetLayer()->GetEffectiveTransformForBuffer(); |
499 | 0 | Matrix transform = fullTransform.As2D(); |
500 | 0 | Matrix inverse = transform; |
501 | 0 | if (!inverse.Invert()) { |
502 | 0 | // Degenerate transforms are not visible, since there is no mapping to |
503 | 0 | // screen space. Just return without adding any draws. |
504 | 0 | return true; |
505 | 0 | } |
506 | 0 | MOZ_ASSERT(inverse.IsRectilinear()); |
507 | 0 |
|
508 | 0 | // Transform the clip rect. |
509 | 0 | IntRect clipRect = item.layer->GetComputedClipRect().ToUnknownRect(); |
510 | 0 | clipRect += item.view->GetTargetOffset(); |
511 | 0 |
|
512 | 0 | // Clip and adjust the texture rect. |
513 | 0 | Rect localClip = inverse.TransformBounds(Rect(clipRect)); |
514 | 0 | Rect clippedDrawRect = aDrawRect.Intersect(localClip); |
515 | 0 | if (clippedDrawRect.IsEmpty()) { |
516 | 0 | return true; |
517 | 0 | } |
518 | 0 | |
519 | 0 | return AddClippedItem(aTxn, aInfo, clippedDrawRect); |
520 | 0 | } |
521 | | |
522 | | bool |
523 | | TexturedRenderPass::AddClippedItem(Txn& aTxn, |
524 | | const Info& aInfo, |
525 | | const gfx::Rect& aDrawRect) |
526 | 0 | { |
527 | 0 | float xScale = 1.0; |
528 | 0 | float yScale = 1.0; |
529 | 0 | if (aInfo.scale) { |
530 | 0 | xScale = aInfo.scale->width; |
531 | 0 | yScale = aInfo.scale->height; |
532 | 0 | } |
533 | 0 |
|
534 | 0 | Point offset = aDrawRect.TopLeft() - aInfo.destOrigin; |
535 | 0 | Rect textureRect( |
536 | 0 | offset.x * xScale, |
537 | 0 | offset.y * yScale, |
538 | 0 | aDrawRect.Width() * xScale, |
539 | 0 | aDrawRect.Height() * yScale); |
540 | 0 |
|
541 | 0 | Rect textureCoords = TextureRectToCoords(textureRect, aInfo.textureSize); |
542 | 0 | if (mTextureFlags & TextureFlags::ORIGIN_BOTTOM_LEFT) { |
543 | 0 | textureCoords.MoveToY(1.0 - textureCoords.Y()); |
544 | 0 | textureCoords.SetHeight(-textureCoords.Height()); |
545 | 0 | } |
546 | 0 |
|
547 | 0 | if (!aInfo.decomposeIntoNoRepeatRects) { |
548 | 0 | // Fast, normal case, we can use the texture coordinates as-s and the caller |
549 | 0 | // will use a repeat sampler if needed. |
550 | 0 | TexturedTraits traits(aInfo.item, aDrawRect, textureCoords); |
551 | 0 | if (!aTxn.Add(traits)) { |
552 | 0 | return false; |
553 | 0 | } |
554 | 0 | } else { |
555 | 0 | Rect layerRects[4]; |
556 | 0 | Rect textureRects[4]; |
557 | 0 | size_t numRects = |
558 | 0 | DecomposeIntoNoRepeatRects(aDrawRect, textureCoords, &layerRects, &textureRects); |
559 | 0 |
|
560 | 0 | for (size_t i = 0; i < numRects; i++) { |
561 | 0 | TexturedTraits traits(aInfo.item, layerRects[i], textureRects[i]); |
562 | 0 | if (!aTxn.Add(traits)) { |
563 | 0 | return false; |
564 | 0 | } |
565 | 0 | } |
566 | 0 | } |
567 | 0 | return true; |
568 | 0 | } |
569 | | |
570 | | SingleTexturePass::SingleTexturePass(FrameBuilder* aBuilder, const ItemInfo& aItem) |
571 | | : TexturedRenderPass(aBuilder, aItem), |
572 | | mSamplerMode(SamplerMode::LinearClamp), |
573 | | mOpacity(1.0f) |
574 | 0 | { |
575 | 0 | SetDefaultGeometry(aItem); |
576 | 0 | } |
577 | | |
578 | | bool |
579 | | SingleTexturePass::AddToPass(LayerMLGPU* aLayer, ItemInfo& aItem) |
580 | 0 | { |
581 | 0 | RefPtr<TextureSource> texture; |
582 | 0 |
|
583 | 0 | SamplerMode sampler; |
584 | 0 | TextureFlags flags = TextureFlags::NO_FLAGS; |
585 | 0 | if (PaintedLayerMLGPU* paintedLayer = aLayer->AsPaintedLayerMLGPU()) { |
586 | 0 | if (paintedLayer->HasComponentAlpha()) { |
587 | 0 | return false; |
588 | 0 | } |
589 | 0 | texture = paintedLayer->GetTexture(); |
590 | 0 | sampler = paintedLayer->GetSamplerMode(); |
591 | 0 | } else if (TexturedLayerMLGPU* texLayer = aLayer->AsTexturedLayerMLGPU()) { |
592 | 0 | texture = texLayer->GetTexture(); |
593 | 0 | sampler = FilterToSamplerMode(texLayer->GetSamplingFilter()); |
594 | 0 | TextureHost* host = texLayer->GetImageHost()->CurrentTextureHost(); |
595 | 0 | flags = host->GetFlags(); |
596 | 0 | } else { |
597 | 0 | return false; |
598 | 0 | } |
599 | 0 | |
600 | 0 | // We should not assign a texture-based layer to tiles if it has no texture. |
601 | 0 | MOZ_ASSERT(texture); |
602 | 0 |
|
603 | 0 | float opacity = aLayer->GetComputedOpacity(); |
604 | 0 | if (mTexture) { |
605 | 0 | if (texture != mTexture) { |
606 | 0 | return false; |
607 | 0 | } |
608 | 0 | if (mSamplerMode != sampler) { |
609 | 0 | return false; |
610 | 0 | } |
611 | 0 | if (mOpacity != opacity) { |
612 | 0 | return false; |
613 | 0 | } |
614 | 0 | // Note: premultiplied, origin-bottom-left are already implied by the texture source. |
615 | 0 | } else { |
616 | 0 | mTexture = texture; |
617 | 0 | mSamplerMode = sampler; |
618 | 0 | mOpacity = opacity; |
619 | 0 | mTextureFlags = flags; |
620 | 0 | } |
621 | 0 |
|
622 | 0 | Txn txn(this); |
623 | 0 |
|
624 | 0 | // Note: these are two separate cases since no Info constructor takes in a |
625 | 0 | // base LayerMLGPU class. |
626 | 0 | if (PaintedLayerMLGPU* layer = aLayer->AsPaintedLayerMLGPU()) { |
627 | 0 | Info info(aItem, layer); |
628 | 0 | if (!AddItems(txn, info, layer->GetDrawRects())) { |
629 | 0 | return false; |
630 | 0 | } |
631 | 0 | } else if (TexturedLayerMLGPU* layer = aLayer->AsTexturedLayerMLGPU()) { |
632 | 0 | Info info(aItem, layer); |
633 | 0 | if (!AddItems(txn, info, layer->GetRenderRegion())) { |
634 | 0 | return false; |
635 | 0 | } |
636 | 0 | } |
637 | 0 | |
638 | 0 | return txn.Commit(); |
639 | 0 | } |
640 | | |
641 | | Maybe<MLGBlendState> |
642 | | SingleTexturePass::GetBlendState() const |
643 | 0 | { |
644 | 0 | return (mTextureFlags & TextureFlags::NON_PREMULTIPLIED) |
645 | 0 | ? Some(MLGBlendState::OverAndPremultiply) |
646 | 0 | : Some(MLGBlendState::Over); |
647 | 0 | } |
648 | | |
649 | | void |
650 | | SingleTexturePass::SetupPipeline() |
651 | 0 | { |
652 | 0 | MOZ_ASSERT(mTexture); |
653 | 0 |
|
654 | 0 | if (mGeometry == GeometryMode::UnitQuad) { |
655 | 0 | mDevice->SetVertexShader(VertexShaderID::TexturedQuad); |
656 | 0 | } else { |
657 | 0 | mDevice->SetVertexShader(VertexShaderID::TexturedVertex); |
658 | 0 | } |
659 | 0 |
|
660 | 0 | mDevice->SetPSTexture(0, mTexture); |
661 | 0 | mDevice->SetSamplerMode(kDefaultSamplerSlot, mSamplerMode); |
662 | 0 | switch (mTexture.get()->GetFormat()) { |
663 | 0 | case SurfaceFormat::B8G8R8A8: |
664 | 0 | case SurfaceFormat::R8G8B8A8: |
665 | 0 | if (mGeometry == GeometryMode::UnitQuad) |
666 | 0 | mDevice->SetPixelShader(PixelShaderID::TexturedQuadRGBA); |
667 | 0 | else |
668 | 0 | mDevice->SetPixelShader(PixelShaderID::TexturedVertexRGBA); |
669 | 0 | break; |
670 | 0 | default: |
671 | 0 | if (mGeometry == GeometryMode::UnitQuad) |
672 | 0 | mDevice->SetPixelShader(PixelShaderID::TexturedQuadRGB); |
673 | 0 | else |
674 | 0 | mDevice->SetPixelShader(PixelShaderID::TexturedVertexRGB); |
675 | 0 | break; |
676 | 0 | } |
677 | 0 | } |
678 | | |
679 | | ComponentAlphaPass::ComponentAlphaPass(FrameBuilder* aBuilder, const ItemInfo& aItem) |
680 | | : TexturedRenderPass(aBuilder, aItem), |
681 | | mOpacity(1.0f), |
682 | | mSamplerMode(SamplerMode::LinearClamp) |
683 | 0 | { |
684 | 0 | SetDefaultGeometry(aItem); |
685 | 0 | } |
686 | | |
687 | | bool |
688 | | ComponentAlphaPass::AddToPass(LayerMLGPU* aLayer, ItemInfo& aItem) |
689 | 0 | { |
690 | 0 | PaintedLayerMLGPU* layer = aLayer->AsPaintedLayerMLGPU(); |
691 | 0 | MOZ_ASSERT(layer); |
692 | 0 |
|
693 | 0 | if (mTextureOnBlack) { |
694 | 0 | if (layer->GetTexture() != mTextureOnBlack || |
695 | 0 | layer->GetTextureOnWhite() != mTextureOnWhite || |
696 | 0 | layer->GetOpacity() != mOpacity || |
697 | 0 | layer->GetSamplerMode() != mSamplerMode) |
698 | 0 | { |
699 | 0 | return false; |
700 | 0 | } |
701 | 0 | } else { |
702 | 0 | mOpacity = layer->GetComputedOpacity(); |
703 | 0 | mSamplerMode = layer->GetSamplerMode(); |
704 | 0 | mTextureOnBlack = layer->GetTexture(); |
705 | 0 | mTextureOnWhite = layer->GetTextureOnWhite(); |
706 | 0 | } |
707 | 0 |
|
708 | 0 | Txn txn(this); |
709 | 0 |
|
710 | 0 | Info info(aItem, layer); |
711 | 0 | if (!AddItems(txn, info, layer->GetDrawRects())) { |
712 | 0 | return false; |
713 | 0 | } |
714 | 0 | return txn.Commit(); |
715 | 0 | } |
716 | | |
717 | | float |
718 | | ComponentAlphaPass::GetOpacity() const |
719 | 0 | { |
720 | 0 | return mOpacity; |
721 | 0 | } |
722 | | |
723 | | void |
724 | | ComponentAlphaPass::SetupPipeline() |
725 | 0 | { |
726 | 0 | TextureSource* textures[2] = { |
727 | 0 | mTextureOnBlack, |
728 | 0 | mTextureOnWhite |
729 | 0 | }; |
730 | 0 | MOZ_ASSERT(textures[0]); |
731 | 0 | MOZ_ASSERT(textures[1]); |
732 | 0 |
|
733 | 0 | if (mGeometry == GeometryMode::UnitQuad) { |
734 | 0 | mDevice->SetVertexShader(VertexShaderID::TexturedQuad); |
735 | 0 | mDevice->SetPixelShader(PixelShaderID::ComponentAlphaQuad); |
736 | 0 | } else { |
737 | 0 | mDevice->SetVertexShader(VertexShaderID::TexturedVertex); |
738 | 0 | mDevice->SetPixelShader(PixelShaderID::ComponentAlphaVertex); |
739 | 0 | } |
740 | 0 |
|
741 | 0 | mDevice->SetSamplerMode(kDefaultSamplerSlot, mSamplerMode); |
742 | 0 | mDevice->SetPSTextures(0, 2, textures); |
743 | 0 | } |
744 | | |
745 | | VideoRenderPass::VideoRenderPass(FrameBuilder* aBuilder, const ItemInfo& aItem) |
746 | | : TexturedRenderPass(aBuilder, aItem), |
747 | | mSamplerMode(SamplerMode::LinearClamp), |
748 | | mOpacity(1.0f) |
749 | 0 | { |
750 | 0 | SetDefaultGeometry(aItem); |
751 | 0 | } |
752 | | |
753 | | bool |
754 | | VideoRenderPass::AddToPass(LayerMLGPU* aLayer, ItemInfo& aItem) |
755 | 0 | { |
756 | 0 | ImageLayerMLGPU* layer = aLayer->AsImageLayerMLGPU(); |
757 | 0 | if (!layer) { |
758 | 0 | return false; |
759 | 0 | } |
760 | 0 | |
761 | 0 | RefPtr<TextureHost> host = layer->GetImageHost()->CurrentTextureHost(); |
762 | 0 | RefPtr<TextureSource> source = layer->GetTexture(); |
763 | 0 | float opacity = layer->GetComputedOpacity(); |
764 | 0 | SamplerMode sampler = FilterToSamplerMode(layer->GetSamplingFilter()); |
765 | 0 |
|
766 | 0 | if (mHost) { |
767 | 0 | if (mHost != host) { |
768 | 0 | return false; |
769 | 0 | } |
770 | 0 | if (mTexture != source) { |
771 | 0 | return false; |
772 | 0 | } |
773 | 0 | if (mOpacity != opacity) { |
774 | 0 | return false; |
775 | 0 | } |
776 | 0 | if (mSamplerMode != sampler) { |
777 | 0 | return false; |
778 | 0 | } |
779 | 0 | } else { |
780 | 0 | mHost = host; |
781 | 0 | mTexture = source; |
782 | 0 | mOpacity = opacity; |
783 | 0 | mSamplerMode = sampler; |
784 | 0 | } |
785 | 0 | MOZ_ASSERT(!mTexture->AsBigImageIterator()); |
786 | 0 | MOZ_ASSERT(!(mHost->GetFlags() & TextureFlags::NON_PREMULTIPLIED)); |
787 | 0 | MOZ_ASSERT(!(mHost->GetFlags() & TextureFlags::ORIGIN_BOTTOM_LEFT)); |
788 | 0 |
|
789 | 0 | Txn txn(this); |
790 | 0 |
|
791 | 0 | Info info(aItem, layer); |
792 | 0 | if (!AddItems(txn, info, layer->GetRenderRegion())) { |
793 | 0 | return false; |
794 | 0 | } |
795 | 0 | return txn.Commit(); |
796 | 0 | } |
797 | | |
798 | | void |
799 | | VideoRenderPass::SetupPipeline() |
800 | 0 | { |
801 | 0 | YUVColorSpace colorSpace = YUVColorSpace::UNKNOWN; |
802 | 0 | switch (mHost->GetReadFormat()) { |
803 | 0 | case SurfaceFormat::YUV: { |
804 | 0 | colorSpace = mHost->GetYUVColorSpace(); |
805 | 0 | break; |
806 | 0 | } |
807 | 0 | case SurfaceFormat::NV12: |
808 | 0 | colorSpace = YUVColorSpace::BT601; |
809 | 0 | break; |
810 | 0 | default: |
811 | 0 | MOZ_ASSERT_UNREACHABLE("Unexpected surface format in VideoRenderPass"); |
812 | 0 | break; |
813 | 0 | } |
814 | 0 | MOZ_ASSERT(colorSpace != YUVColorSpace::UNKNOWN); |
815 | 0 |
|
816 | 0 | RefPtr<MLGBuffer> ps1 = mDevice->GetBufferForColorSpace(colorSpace); |
817 | 0 | if (!ps1) { |
818 | 0 | return; |
819 | 0 | } |
820 | 0 | |
821 | 0 | if (mGeometry == GeometryMode::UnitQuad) { |
822 | 0 | mDevice->SetVertexShader(VertexShaderID::TexturedQuad); |
823 | 0 | } else { |
824 | 0 | mDevice->SetVertexShader(VertexShaderID::TexturedVertex); |
825 | 0 | } |
826 | 0 |
|
827 | 0 | switch (mHost->GetReadFormat()) { |
828 | 0 | case SurfaceFormat::YUV: |
829 | 0 | { |
830 | 0 | if (mGeometry == GeometryMode::UnitQuad) |
831 | 0 | mDevice->SetPixelShader(PixelShaderID::TexturedQuadIMC4); |
832 | 0 | else |
833 | 0 | mDevice->SetPixelShader(PixelShaderID::TexturedVertexIMC4); |
834 | 0 | mDevice->SetPSTexturesYUV(0, mTexture); |
835 | 0 | break; |
836 | 0 | } |
837 | 0 | case SurfaceFormat::NV12: |
838 | 0 | if (mGeometry == GeometryMode::UnitQuad) |
839 | 0 | mDevice->SetPixelShader(PixelShaderID::TexturedQuadNV12); |
840 | 0 | else |
841 | 0 | mDevice->SetPixelShader(PixelShaderID::TexturedVertexNV12); |
842 | 0 | mDevice->SetPSTexturesNV12(0, mTexture); |
843 | 0 | break; |
844 | 0 | default: |
845 | 0 | MOZ_ASSERT_UNREACHABLE("Unknown video format"); |
846 | 0 | break; |
847 | 0 | } |
848 | 0 |
|
849 | 0 | mDevice->SetSamplerMode(kDefaultSamplerSlot, mSamplerMode); |
850 | 0 | mDevice->SetPSConstantBuffer(1, ps1); |
851 | 0 | } |
852 | | |
853 | | RenderViewPass::RenderViewPass(FrameBuilder* aBuilder, const ItemInfo& aItem) |
854 | | : TexturedRenderPass(aBuilder, aItem), |
855 | | mParentView(nullptr) |
856 | 0 | { |
857 | 0 | mAssignedLayer = aItem.layer->AsContainerLayerMLGPU(); |
858 | 0 |
|
859 | 0 | CompositionOp blendOp = mAssignedLayer->GetMixBlendMode(); |
860 | 0 | if (BlendOpIsMixBlendMode(blendOp)) { |
861 | 0 | mBlendMode = Some(blendOp); |
862 | 0 | } |
863 | 0 |
|
864 | 0 | if (mBlendMode) { |
865 | 0 | // We do not have fast-path rect shaders for blending. |
866 | 0 | SetGeometry(aItem, GeometryMode::Polygon); |
867 | 0 | } else { |
868 | 0 | SetDefaultGeometry(aItem); |
869 | 0 | } |
870 | 0 | } |
871 | | |
872 | | bool |
873 | | RenderViewPass::AddToPass(LayerMLGPU* aLayer, ItemInfo& aItem) |
874 | 0 | { |
875 | 0 | // We bake in the layer ahead of time, which also guarantees the blend mode |
876 | 0 | // is baked in, as well as the geometry requirement. |
877 | 0 | if (mAssignedLayer != aLayer) { |
878 | 0 | return false; |
879 | 0 | } |
880 | 0 | |
881 | 0 | mSource = mAssignedLayer->GetRenderTarget(); |
882 | 0 | if (!mSource) { |
883 | 0 | return false; |
884 | 0 | } |
885 | 0 | |
886 | 0 | mParentView = aItem.view; |
887 | 0 |
|
888 | 0 | Txn txn(this); |
889 | 0 |
|
890 | 0 | IntPoint offset = mAssignedLayer->GetTargetOffset(); |
891 | 0 | IntSize size = mAssignedLayer->GetTargetSize(); |
892 | 0 |
|
893 | 0 | // Clamp the visible region to the texture size. |
894 | 0 | nsIntRegion visible = mAssignedLayer->GetRenderRegion().ToUnknownRegion(); |
895 | 0 | visible.AndWith(IntRect(offset, size)); |
896 | 0 |
|
897 | 0 | Info info(aItem, mAssignedLayer); |
898 | 0 | if (!AddItems(txn, info, visible)) { |
899 | 0 | return false; |
900 | 0 | } |
901 | 0 | return txn.Commit(); |
902 | 0 | } |
903 | | |
904 | | float |
905 | | RenderViewPass::GetOpacity() const |
906 | 0 | { |
907 | 0 | return mAssignedLayer->GetLayer()->GetEffectiveOpacity(); |
908 | 0 | } |
909 | | |
910 | | bool |
911 | | RenderViewPass::OnPrepareBuffers() |
912 | 0 | { |
913 | 0 | if (mBlendMode && !PrepareBlendState()) { |
914 | 0 | return false; |
915 | 0 | } |
916 | 0 | return true; |
917 | 0 | } |
918 | | |
919 | | static inline PixelShaderID |
920 | | GetShaderForBlendMode(CompositionOp aOp) |
921 | 0 | { |
922 | 0 | switch (aOp) { |
923 | 0 | case CompositionOp::OP_MULTIPLY: return PixelShaderID::BlendMultiply; |
924 | 0 | case CompositionOp::OP_SCREEN: return PixelShaderID::BlendScreen; |
925 | 0 | case CompositionOp::OP_OVERLAY: return PixelShaderID::BlendOverlay; |
926 | 0 | case CompositionOp::OP_DARKEN: return PixelShaderID::BlendDarken; |
927 | 0 | case CompositionOp::OP_LIGHTEN: return PixelShaderID::BlendLighten; |
928 | 0 | case CompositionOp::OP_COLOR_DODGE: return PixelShaderID::BlendColorDodge; |
929 | 0 | case CompositionOp::OP_COLOR_BURN: return PixelShaderID::BlendColorBurn; |
930 | 0 | case CompositionOp::OP_HARD_LIGHT: return PixelShaderID::BlendHardLight; |
931 | 0 | case CompositionOp::OP_SOFT_LIGHT: return PixelShaderID::BlendSoftLight; |
932 | 0 | case CompositionOp::OP_DIFFERENCE: return PixelShaderID::BlendDifference; |
933 | 0 | case CompositionOp::OP_EXCLUSION: return PixelShaderID::BlendExclusion; |
934 | 0 | case CompositionOp::OP_HUE: return PixelShaderID::BlendHue; |
935 | 0 | case CompositionOp::OP_SATURATION: return PixelShaderID::BlendSaturation; |
936 | 0 | case CompositionOp::OP_COLOR: return PixelShaderID::BlendColor; |
937 | 0 | case CompositionOp::OP_LUMINOSITY: return PixelShaderID::BlendLuminosity; |
938 | 0 | default: |
939 | 0 | MOZ_ASSERT_UNREACHABLE("Unexpected blend mode"); |
940 | 0 | return PixelShaderID::TexturedVertexRGBA; |
941 | 0 | } |
942 | 0 | } |
943 | | |
944 | | bool |
945 | | RenderViewPass::PrepareBlendState() |
946 | 0 | { |
947 | 0 | Rect visibleRect(mAssignedLayer->GetRenderRegion().GetBounds().ToUnknownRect()); |
948 | 0 | IntRect clipRect(mAssignedLayer->GetComputedClipRect().ToUnknownRect()); |
949 | 0 | const Matrix4x4& transform = mAssignedLayer->GetLayer()->GetEffectiveTransformForBuffer(); |
950 | 0 |
|
951 | 0 | // Note that we must use our parent RenderView for this calculation, |
952 | 0 | // since we're copying the backdrop, not our actual local target. |
953 | 0 | IntRect rtRect(mParentView->GetTargetOffset(), mParentView->GetSize()); |
954 | 0 |
|
955 | 0 | Matrix4x4 backdropTransform; |
956 | 0 | mBackdropCopyRect = ComputeBackdropCopyRect( |
957 | 0 | visibleRect, |
958 | 0 | clipRect, |
959 | 0 | transform, |
960 | 0 | rtRect, |
961 | 0 | &backdropTransform); |
962 | 0 |
|
963 | 0 | AutoBufferUpload<BlendVertexShaderConstants> cb; |
964 | 0 | if (!mDevice->GetSharedVSBuffer()->Allocate(&mBlendConstants, &cb)) { |
965 | 0 | return false; |
966 | 0 | } |
967 | 0 | memcpy(cb->backdropTransform, &backdropTransform._11, 64); |
968 | 0 | return true; |
969 | 0 | } |
970 | | |
971 | | void |
972 | | RenderViewPass::SetupPipeline() |
973 | 0 | { |
974 | 0 | if (mBlendMode) { |
975 | 0 | RefPtr<MLGRenderTarget> backdrop = mParentView->GetRenderTarget(); |
976 | 0 | MOZ_ASSERT(mDevice->GetRenderTarget() == backdrop); |
977 | 0 |
|
978 | 0 | RefPtr<MLGTexture> copy = mDevice->CreateTexture( |
979 | 0 | mBackdropCopyRect.Size(), |
980 | 0 | SurfaceFormat::B8G8R8A8, |
981 | 0 | MLGUsage::Default, |
982 | 0 | MLGTextureFlags::ShaderResource); |
983 | 0 | if (!copy) { |
984 | 0 | return; |
985 | 0 | } |
986 | 0 | |
987 | 0 | mDevice->CopyTexture( |
988 | 0 | copy, |
989 | 0 | IntPoint(0, 0), |
990 | 0 | backdrop->GetTexture(), |
991 | 0 | mBackdropCopyRect); |
992 | 0 |
|
993 | 0 | MOZ_ASSERT(mGeometry == GeometryMode::Polygon); |
994 | 0 | mDevice->SetVertexShader(VertexShaderID::BlendVertex); |
995 | 0 | mDevice->SetPixelShader(GetShaderForBlendMode(mBlendMode.value())); |
996 | 0 | mDevice->SetVSConstantBuffer(kBlendConstantBufferSlot, &mBlendConstants); |
997 | 0 | mDevice->SetPSTexture(1, copy); |
998 | 0 | } else { |
999 | 0 | if (mGeometry == GeometryMode::UnitQuad) { |
1000 | 0 | mDevice->SetVertexShader(VertexShaderID::TexturedQuad); |
1001 | 0 | mDevice->SetPixelShader(PixelShaderID::TexturedQuadRGBA); |
1002 | 0 | } else { |
1003 | 0 | mDevice->SetVertexShader(VertexShaderID::TexturedVertex); |
1004 | 0 | mDevice->SetPixelShader(PixelShaderID::TexturedVertexRGBA); |
1005 | 0 | } |
1006 | 0 | } |
1007 | 0 |
|
1008 | 0 | mDevice->SetPSTexture(0, mSource->GetTexture()); |
1009 | 0 | mDevice->SetSamplerMode(kDefaultSamplerSlot, SamplerMode::LinearClamp); |
1010 | 0 | } |
1011 | | |
1012 | | void |
1013 | | RenderViewPass::ExecuteRendering() |
1014 | 0 | { |
1015 | 0 | if (mAssignedLayer->NeedsSurfaceCopy()) { |
1016 | 0 | RenderWithBackdropCopy(); |
1017 | 0 | return; |
1018 | 0 | } |
1019 | 0 | |
1020 | 0 | TexturedRenderPass::ExecuteRendering(); |
1021 | 0 | } |
1022 | | |
1023 | | void |
1024 | | RenderViewPass::RenderWithBackdropCopy() |
1025 | 0 | { |
1026 | 0 | MOZ_ASSERT(mAssignedLayer->NeedsSurfaceCopy()); |
1027 | 0 |
|
1028 | 0 | DebugOnly<Matrix> transform2d; |
1029 | 0 | const Matrix4x4& transform = mAssignedLayer->GetEffectiveTransform(); |
1030 | 0 | MOZ_ASSERT(transform.Is2D(&transform2d) && |
1031 | 0 | !gfx::ThebesMatrix(transform2d).HasNonIntegerTranslation()); |
1032 | 0 |
|
1033 | 0 | IntPoint translation = IntPoint::Truncate(transform._41, transform._42); |
1034 | 0 |
|
1035 | 0 | RenderViewMLGPU* childView = mAssignedLayer->GetRenderView(); |
1036 | 0 |
|
1037 | 0 | IntRect visible = mAssignedLayer->GetRenderRegion().GetBounds().ToUnknownRect(); |
1038 | 0 | IntRect sourceRect = visible + translation - mParentView->GetTargetOffset(); |
1039 | 0 | IntPoint destPoint = visible.TopLeft() - childView->GetTargetOffset(); |
1040 | 0 |
|
1041 | 0 | RefPtr<MLGTexture> dest = mAssignedLayer->GetRenderTarget()->GetTexture(); |
1042 | 0 | RefPtr<MLGTexture> source = mParentView->GetRenderTarget()->GetTexture(); |
1043 | 0 |
|
1044 | 0 | // Clamp the source rect to the source texture size. |
1045 | 0 | sourceRect = sourceRect.Intersect(IntRect(IntPoint(0, 0), source->GetSize())); |
1046 | 0 |
|
1047 | 0 | // Clamp the source rect to the destination texture size. |
1048 | 0 | IntRect destRect(destPoint, sourceRect.Size()); |
1049 | 0 | destRect = destRect.Intersect(IntRect(IntPoint(0, 0), dest->GetSize())); |
1050 | 0 | sourceRect = sourceRect.Intersect(IntRect(sourceRect.TopLeft(), destRect.Size())); |
1051 | 0 |
|
1052 | 0 | mDevice->CopyTexture(dest, destPoint, source, sourceRect); |
1053 | 0 | childView->RenderAfterBackdropCopy(); |
1054 | 0 | mParentView->RestoreDeviceState(); |
1055 | 0 | TexturedRenderPass::ExecuteRendering(); |
1056 | 0 | } |
1057 | | |
1058 | | } // namespace layers |
1059 | | } // namespace mozilla |