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