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