Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/layers/mlgpu/MLGDevice.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 "MLGDevice.h"
8
#include "mozilla/layers/TextureHost.h"
9
#include "BufferCache.h"
10
#include "ClearRegionHelper.h"
11
#include "gfxConfig.h"
12
#include "gfxPrefs.h"
13
#include "gfxUtils.h"
14
#include "LayersLogging.h"
15
#include "ShaderDefinitionsMLGPU.h"
16
#include "SharedBufferMLGPU.h"
17
#include "UtilityMLGPU.h"
18
19
namespace mozilla {
20
namespace layers {
21
22
using namespace gfx;
23
using namespace mlg;
24
25
MLGRenderTarget::MLGRenderTarget(MLGRenderTargetFlags aFlags)
26
 : mFlags(aFlags),
27
   mLastDepthStart(-1)
28
0
{
29
0
}
30
31
MLGSwapChain::MLGSwapChain()
32
 : mIsDoubleBuffered(false)
33
0
{
34
0
}
35
36
bool
37
MLGSwapChain::ApplyNewInvalidRegion(nsIntRegion&& aRegion, const Maybe<gfx::IntRect>& aExtraRect)
38
0
{
39
0
  // We clamp the invalid region to the backbuffer size, otherwise the present
40
0
  // can fail.
41
0
  IntRect bounds(IntPoint(0, 0), GetSize());
42
0
  nsIntRegion invalid = std::move(aRegion);
43
0
  invalid.AndWith(bounds);
44
0
  if (invalid.IsEmpty()) {
45
0
    return false;
46
0
  }
47
0
48
0
  if (aExtraRect) {
49
0
    IntRect rect = aExtraRect.value().Intersect(bounds);
50
0
    if (!rect.IsEmpty()) {
51
0
      invalid.OrWith(rect);
52
0
    }
53
0
  }
54
0
55
0
  // This area is now invalid in the back and front buffers. Note that the front
56
0
  // buffer is either totally valid or totally invalid, since either the last
57
0
  // paint succeeded or was thrown out due to a buffer resize. Effectively, it
58
0
  // will now contain the invalid region specific to this frame.
59
0
  mBackBufferInvalid.OrWith(invalid);
60
0
  AL_LOG("Backbuffer invalid region: %s\n", Stringify(mBackBufferInvalid).c_str());
61
0
62
0
  if (mIsDoubleBuffered) {
63
0
    mFrontBufferInvalid.OrWith(invalid);
64
0
    AL_LOG("Frontbuffer invalid region: %s\n", Stringify(mFrontBufferInvalid).c_str());
65
0
  }
66
0
  return true;
67
0
}
68
69
MLGDevice::MLGDevice()
70
 : mTopology(MLGPrimitiveTopology::Unknown),
71
   mInitialized(false),
72
   mIsValid(false),
73
   mCanUseClearView(false),
74
   mCanUseConstantBufferOffsetBinding(false),
75
   mMaxConstantBufferBindSize(0)
76
0
{
77
0
}
78
79
MLGDevice::~MLGDevice()
80
0
{
81
0
}
82
83
bool
84
MLGDevice::Initialize()
85
0
{
86
0
  if (!mMaxConstantBufferBindSize) {
87
0
    return Fail("FEATURE_FAILURE_NO_MAX_CB_BIND_SIZE", "Failed to set a max constant buffer bind size");
88
0
  }
89
0
  if (mMaxConstantBufferBindSize < mlg::kMaxConstantBufferSize) {
90
0
    // StagingBuffer depends on this value being accurate, so for now we just
91
0
    // double-check it here.
92
0
    return Fail("FEATURE_FAILURE_MIN_MAX_CB_BIND_SIZE", "Minimum constant buffer bind size not met");
93
0
  }
94
0
95
0
  // We allow this to be pref'd off for testing. Switching it off enables
96
0
  // Direct3D 11.0/Windows 7/OpenGL-style buffer code paths.
97
0
  if (!gfxPrefs::AdvancedLayersEnableBufferSharing()) {
98
0
    gfxConfig::EnableFallback(Fallback::NO_CONSTANT_BUFFER_OFFSETTING,
99
0
                              "Disabled by pref");
100
0
    mCanUseConstantBufferOffsetBinding = false;
101
0
  }
102
0
  if (mCanUseConstantBufferOffsetBinding && !VerifyConstantBufferOffsetting()) {
103
0
    gfxConfig::EnableFallback(Fallback::NO_CONSTANT_BUFFER_OFFSETTING,
104
0
                              "Constant buffer offset binding does not work");
105
0
    mCanUseConstantBufferOffsetBinding = false;
106
0
  }
107
0
108
0
  // We allow this to be pref'd off for testing. Disabling it turns on
109
0
  // ID3D11DeviceContext1::ClearView support, which is present on
110
0
  // newer Windows 8+ drivers.
111
0
  if (!gfxPrefs::AdvancedLayersEnableClearView()) {
112
0
    mCanUseClearView = false;
113
0
  }
114
0
115
0
  // When compositing normal sized layer trees, we typically have small vertex
116
0
  // buffers. Empirically the vertex and pixel constant buffer sizes are generally
117
0
  // under 1KB and the vertex constant buffer size is under 8KB.
118
0
  static const size_t kDefaultVertexBufferSize = 4096;
119
0
  static const size_t kDefaultVSConstantBufferSize = 512 * kConstantBufferElementSize;
120
0
  static const size_t kDefaultPSConstantBufferSize = 256 * kConstantBufferElementSize;
121
0
122
0
  // Note: we create these after we've verified all the device-specific properties above.
123
0
  mSharedVertexBuffer = MakeUnique<SharedVertexBuffer>(this, kDefaultVertexBufferSize);
124
0
  mSharedVSBuffer = MakeUnique<SharedConstantBuffer>(this, kDefaultVSConstantBufferSize);
125
0
  mSharedPSBuffer = MakeUnique<SharedConstantBuffer>(this, kDefaultPSConstantBufferSize);
126
0
127
0
  if (!mSharedVertexBuffer->Init() ||
128
0
      !mSharedVSBuffer->Init() ||
129
0
      !mSharedPSBuffer->Init())
130
0
  {
131
0
    return Fail("FEATURE_FAILURE_ALLOC_SHARED_BUFFER", "Failed to allocate a shared shader buffer");
132
0
  }
133
0
134
0
  if (gfxPrefs::AdvancedLayersEnableBufferCache()) {
135
0
    mConstantBufferCache = MakeUnique<BufferCache>(this);
136
0
  }
137
0
138
0
  mInitialized = true;
139
0
  mIsValid = true;
140
0
  return true;
141
0
}
142
143
void
144
MLGDevice::BeginFrame()
145
0
{
146
0
  mSharedVertexBuffer->Reset();
147
0
  mSharedPSBuffer->Reset();
148
0
  mSharedVSBuffer->Reset();
149
0
}
150
151
void
152
MLGDevice::EndFrame()
153
0
{
154
0
  if (mConstantBufferCache) {
155
0
    mConstantBufferCache->EndFrame();
156
0
  }
157
0
}
158
159
void
160
MLGDevice::FinishSharedBufferUse()
161
0
{
162
0
  mSharedVertexBuffer->PrepareForUsage();
163
0
  mSharedPSBuffer->PrepareForUsage();
164
0
  mSharedVSBuffer->PrepareForUsage();
165
0
}
166
167
void
168
MLGDevice::SetTopology(MLGPrimitiveTopology aTopology)
169
0
{
170
0
  if (mTopology == aTopology) {
171
0
    return;
172
0
  }
173
0
  SetPrimitiveTopology(aTopology);
174
0
  mTopology = aTopology;
175
0
}
176
177
void
178
MLGDevice::SetVertexBuffer(uint32_t aSlot, const VertexBufferSection* aSection)
179
0
{
180
0
  if (!aSection->IsValid()) {
181
0
    return;
182
0
  }
183
0
  SetVertexBuffer(aSlot, aSection->GetBuffer(), aSection->Stride(), aSection->Offset());
184
0
}
185
186
void
187
MLGDevice::SetPSConstantBuffer(uint32_t aSlot, const ConstantBufferSection* aSection)
188
0
{
189
0
  if (!aSection->IsValid()) {
190
0
    return;
191
0
  }
192
0
193
0
  MLGBuffer* buffer = aSection->GetBuffer();
194
0
195
0
  if (aSection->HasOffset()) {
196
0
    uint32_t first = aSection->Offset();
197
0
    uint32_t numConstants = aSection->NumConstants();
198
0
    SetPSConstantBuffer(aSlot, buffer, first, numConstants);
199
0
  } else {
200
0
    SetPSConstantBuffer(aSlot, buffer);
201
0
  }
202
0
}
203
204
void
205
MLGDevice::SetVSConstantBuffer(uint32_t aSlot, const ConstantBufferSection* aSection)
206
0
{
207
0
  if (!aSection->IsValid()) {
208
0
    return;
209
0
  }
210
0
211
0
  MLGBuffer* buffer = aSection->GetBuffer();
212
0
213
0
  if (aSection->HasOffset()) {
214
0
    uint32_t first = aSection->Offset();
215
0
    uint32_t numConstants = aSection->NumConstants();
216
0
    SetVSConstantBuffer(aSlot, buffer, first, numConstants);
217
0
  } else {
218
0
    SetVSConstantBuffer(aSlot, buffer);
219
0
  }
220
0
}
221
222
void
223
MLGDevice::SetPSTexturesYUV(uint32_t aSlot, TextureSource* aTexture)
224
0
{
225
0
  // Note, we don't support tiled YCbCr textures.
226
0
  const int Y = 0, Cb = 1, Cr = 2;
227
0
  TextureSource* textures[3] = {
228
0
    aTexture->GetSubSource(Y),
229
0
    aTexture->GetSubSource(Cb),
230
0
    aTexture->GetSubSource(Cr)
231
0
  };
232
0
  MOZ_ASSERT(textures[0]);
233
0
  MOZ_ASSERT(textures[1]);
234
0
  MOZ_ASSERT(textures[2]);
235
0
236
0
  SetPSTextures(0, 3, textures);
237
0
}
238
239
void
240
MLGDevice::SetPSTexture(uint32_t aSlot, TextureSource* aSource)
241
0
{
242
0
  SetPSTextures(aSlot, 1, &aSource);
243
0
}
244
245
void
246
MLGDevice::SetSamplerMode(uint32_t aIndex, gfx::SamplingFilter aFilter)
247
0
{
248
0
  SetSamplerMode(aIndex, FilterToSamplerMode(aFilter));
249
0
}
250
251
bool
252
MLGDevice::Fail(const nsCString& aFailureId, const nsCString* aMessage)
253
0
{
254
0
  const char* message = aMessage
255
0
                        ? aMessage->get()
256
0
                        : "Failed initializing MLGDeviceD3D11";
257
0
  gfxWarning() << "Failure initializing MLGDeviceD3D11: " << message;
258
0
  mFailureId = aFailureId;
259
0
  mFailureMessage = message;
260
0
  return false;
261
0
}
262
263
void
264
MLGDevice::UnmapSharedBuffers()
265
0
{
266
0
  mSharedVertexBuffer->Reset();
267
0
  mSharedPSBuffer->Reset();
268
0
  mSharedVSBuffer->Reset();
269
0
}
270
271
RefPtr<MLGBuffer>
272
MLGDevice::GetBufferForColorSpace(YUVColorSpace aColorSpace)
273
0
{
274
0
  if (mColorSpaceBuffers[aColorSpace]) {
275
0
    return mColorSpaceBuffers[aColorSpace];
276
0
  }
277
0
278
0
  YCbCrShaderConstants buffer;
279
0
  memcpy(
280
0
    &buffer.yuvColorMatrix,
281
0
    gfxUtils::YuvToRgbMatrix4x3RowMajor(aColorSpace),
282
0
    sizeof(buffer.yuvColorMatrix));
283
0
284
0
  RefPtr<MLGBuffer> resource = CreateBuffer(
285
0
    MLGBufferType::Constant,
286
0
    sizeof(buffer),
287
0
    MLGUsage::Immutable,
288
0
    &buffer);
289
0
  if (!resource) {
290
0
    return nullptr;
291
0
  }
292
0
293
0
  mColorSpaceBuffers[aColorSpace] = resource;
294
0
  return resource;
295
0
}
296
297
bool
298
MLGDevice::Synchronize()
299
0
{
300
0
  return true;
301
0
}
302
303
void
304
MLGDevice::PrepareClearRegion(ClearRegionHelper* aOut,
305
                              nsTArray<gfx::IntRect>&& aRects,
306
                              const Maybe<int32_t>& aSortIndex)
307
0
{
308
0
  if (CanUseClearView() && !aSortIndex) {
309
0
    aOut->mRects = std::move(aRects);
310
0
    return;
311
0
  }
312
0
313
0
  mSharedVertexBuffer->Allocate(
314
0
    &aOut->mInput,
315
0
    aRects.Length(),
316
0
    sizeof(IntRect),
317
0
    aRects.Elements());
318
0
319
0
  ClearConstants consts(aSortIndex ? aSortIndex.value() : 1);
320
0
  mSharedVSBuffer->Allocate(&aOut->mVSBuffer, consts);
321
0
}
322
323
void
324
MLGDevice::DrawClearRegion(const ClearRegionHelper& aHelper)
325
0
{
326
0
  // If we've set up vertices for a shader-based clear, execute that now.
327
0
  if (aHelper.mInput.IsValid()) {
328
0
    SetTopology(MLGPrimitiveTopology::UnitQuad);
329
0
    SetVertexShader(VertexShaderID::Clear);
330
0
    SetVertexBuffer(1, &aHelper.mInput);
331
0
    SetVSConstantBuffer(kClearConstantBufferSlot, &aHelper.mVSBuffer);
332
0
    SetBlendState(MLGBlendState::Copy);
333
0
    SetPixelShader(PixelShaderID::Clear);
334
0
    DrawInstanced(4, aHelper.mInput.NumVertices(), 0, 0);
335
0
    return;
336
0
  }
337
0
338
0
  // Otherwise, if we have a normal rect list, we wanted to use the faster
339
0
  // ClearView.
340
0
  if (!aHelper.mRects.IsEmpty()) {
341
0
    Color color(0.0, 0.0, 0.0, 0.0);
342
0
    ClearView(mCurrentRT, color, aHelper.mRects.Elements(), aHelper.mRects.Length());
343
0
  }
344
0
}
345
346
void
347
MLGDevice::WriteAsPNG(MLGTexture* aTexture, const char* aPath)
348
0
{
349
0
  MLGMappedResource map;
350
0
  if (!Map(aTexture, MLGMapType::READ, &map)) {
351
0
    return;
352
0
  }
353
0
354
0
  RefPtr<DataSourceSurface> surface = Factory::CreateWrappingDataSourceSurface(
355
0
    map.mData,
356
0
    map.mStride,
357
0
    aTexture->GetSize(),
358
0
    SurfaceFormat::B8G8R8A8);
359
0
  gfxUtils::WriteAsPNG(surface, aPath);
360
0
361
0
  Unmap(aTexture);
362
0
}
363
364
RefPtr<MLGTexture>
365
MLGDevice::CopyAndCreateReadbackTexture(MLGTexture* aTexture)
366
0
{
367
0
  RefPtr<MLGTexture> copy = CreateTexture(
368
0
    aTexture->GetSize(),
369
0
    SurfaceFormat::B8G8R8A8,
370
0
    MLGUsage::Staging,
371
0
    MLGTextureFlags::None);
372
0
  if (!copy) {
373
0
    return nullptr;
374
0
  }
375
0
  CopyTexture(
376
0
    copy,
377
0
    IntPoint(0, 0),
378
0
    aTexture,
379
0
    IntRect(IntPoint(0, 0), aTexture->GetSize()));
380
0
  return copy;
381
0
}
382
383
} // namespace layers
384
} // namespace mozilla