Coverage Report

Created: 2018-09-25 14:53

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