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