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