1
2 // Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // Clear11.cpp: Framebuffer clear utility class.
8
9 #include "libANGLE/renderer/d3d/d3d11/Clear11.h"
10
11 #include <algorithm>
12
13 #include "libANGLE/FramebufferAttachment.h"
14 #include "libANGLE/formatutils.h"
15 #include "libANGLE/renderer/d3d/FramebufferD3D.h"
16 #include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
17 #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
18 #include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h"
19 #include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
20 #include "third_party/trace_event/trace_event.h"
21
22 // Precompiled shaders
23 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clear11_fl9vs.h"
24 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clear11multiviewgs.h"
25 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clear11multiviewvs.h"
26 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clear11vs.h"
27 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/cleardepth11ps.h"
28 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11_fl9ps.h"
29 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps1.h"
30 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps2.h"
31 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps3.h"
32 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps4.h"
33 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps5.h"
34 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps6.h"
35 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps7.h"
36 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps8.h"
37 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps1.h"
38 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps2.h"
39 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps3.h"
40 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps4.h"
41 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps5.h"
42 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps6.h"
43 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps7.h"
44 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps8.h"
45 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps1.h"
46 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps2.h"
47 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps3.h"
48 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps4.h"
49 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps5.h"
50 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps6.h"
51 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps7.h"
52 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps8.h"
53
54 namespace rx
55 {
56
57 namespace
58 {
59 constexpr uint32_t g_ConstantBufferSize = sizeof(RtvDsvClearInfo<float>);
60 constexpr uint32_t g_VertexSize = sizeof(d3d11::PositionVertex);
61
62 // Updates color, depth and alpha components of cached CB if necessary.
63 // Returns true if any constants are updated, false otherwise.
64 template <typename T>
UpdateDataCache(RtvDsvClearInfo<T> * dataCache,const gl::Color<T> & color,const float * zValue,const uint32_t numRtvs,const uint8_t writeMask)65 bool UpdateDataCache(RtvDsvClearInfo<T> *dataCache,
66 const gl::Color<T> &color,
67 const float *zValue,
68 const uint32_t numRtvs,
69 const uint8_t writeMask)
70 {
71 bool cacheDirty = false;
72
73 if (numRtvs > 0)
74 {
75 const bool writeRGB = (writeMask & ~D3D11_COLOR_WRITE_ENABLE_ALPHA) != 0;
76 if (writeRGB && memcmp(&dataCache->r, &color.red, sizeof(T) * 3) != 0)
77 {
78 dataCache->r = color.red;
79 dataCache->g = color.green;
80 dataCache->b = color.blue;
81 cacheDirty = true;
82 }
83
84 const bool writeAlpha = (writeMask & D3D11_COLOR_WRITE_ENABLE_ALPHA) != 0;
85 if (writeAlpha && (dataCache->a != color.alpha))
86 {
87 dataCache->a = color.alpha;
88 cacheDirty = true;
89 }
90 }
91
92 if (zValue)
93 {
94 const float clampedZValue = gl::clamp01(*zValue);
95
96 if (clampedZValue != dataCache->z)
97 {
98 dataCache->z = clampedZValue;
99 cacheDirty = true;
100 }
101 }
102
103 return cacheDirty;
104 }
105
AllOffsetsAreNonNegative(const std::vector<gl::Offset> & viewportOffsets)106 bool AllOffsetsAreNonNegative(const std::vector<gl::Offset> &viewportOffsets)
107 {
108 for (size_t i = 0u; i < viewportOffsets.size(); ++i)
109 {
110 const auto &offset = viewportOffsets[i];
111 if (offset.x < 0 || offset.y < 0)
112 {
113 return false;
114 }
115 }
116 return true;
117 }
118 } // anonymous namespace
119
120 #define CLEARPS(Index) \
121 d3d11::LazyShader<ID3D11PixelShader>(g_PS_Clear##Index, ArraySize(g_PS_Clear##Index), \
122 "Clear11 PS " ANGLE_STRINGIFY(Index))
123
ShaderManager()124 Clear11::ShaderManager::ShaderManager()
125 : mIl9(),
126 mVs9(g_VS_Clear_FL9, ArraySize(g_VS_Clear_FL9), "Clear11 VS FL9"),
127 mPsFloat9(g_PS_ClearFloat_FL9, ArraySize(g_PS_ClearFloat_FL9), "Clear11 PS FloatFL9"),
128 mVs(g_VS_Clear, ArraySize(g_VS_Clear), "Clear11 VS"),
129 mVsMultiview(g_VS_Multiview_Clear, ArraySize(g_VS_Multiview_Clear), "Clear11 VS Multiview"),
130 mGsMultiview(g_GS_Multiview_Clear, ArraySize(g_GS_Multiview_Clear), "Clear11 GS Multiview"),
131 mPsDepth(g_PS_ClearDepth, ArraySize(g_PS_ClearDepth), "Clear11 PS Depth"),
132 mPsFloat{{CLEARPS(Float1), CLEARPS(Float2), CLEARPS(Float3), CLEARPS(Float4), CLEARPS(Float5),
133 CLEARPS(Float6), CLEARPS(Float7), CLEARPS(Float8)}},
134 mPsUInt{{CLEARPS(Uint1), CLEARPS(Uint2), CLEARPS(Uint3), CLEARPS(Uint4), CLEARPS(Uint5),
135 CLEARPS(Uint6), CLEARPS(Uint7), CLEARPS(Uint8)}},
136 mPsSInt{{CLEARPS(Sint1), CLEARPS(Sint2), CLEARPS(Sint3), CLEARPS(Sint4), CLEARPS(Sint5),
137 CLEARPS(Sint6), CLEARPS(Sint7), CLEARPS(Sint8)}}
138 {
139 }
140
141 #undef CLEARPS
142
~ShaderManager()143 Clear11::ShaderManager::~ShaderManager()
144 {
145 }
146
getShadersAndLayout(Renderer11 * renderer,const INT clearType,const uint32_t numRTs,const bool hasLayeredLayout,const d3d11::InputLayout ** il,const d3d11::VertexShader ** vs,const d3d11::GeometryShader ** gs,const d3d11::PixelShader ** ps)147 gl::Error Clear11::ShaderManager::getShadersAndLayout(Renderer11 *renderer,
148 const INT clearType,
149 const uint32_t numRTs,
150 const bool hasLayeredLayout,
151 const d3d11::InputLayout **il,
152 const d3d11::VertexShader **vs,
153 const d3d11::GeometryShader **gs,
154 const d3d11::PixelShader **ps)
155 {
156 if (renderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3)
157 {
158 ASSERT(clearType == GL_FLOAT);
159
160 ANGLE_TRY(mVs9.resolve(renderer));
161 ANGLE_TRY(mPsFloat9.resolve(renderer));
162
163 if (!mIl9.valid())
164 {
165 const D3D11_INPUT_ELEMENT_DESC ilDesc[] = {
166 {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}};
167
168 InputElementArray ilDescArray(ilDesc);
169 ShaderData vertexShader(g_VS_Clear_FL9);
170
171 ANGLE_TRY(renderer->allocateResource(ilDescArray, &vertexShader, &mIl9));
172 }
173
174 *vs = &mVs9.getObj();
175 *gs = nullptr;
176 *il = &mIl9;
177 *ps = &mPsFloat9.getObj();
178 return gl::NoError();
179 }
180 if (!hasLayeredLayout)
181 {
182 ANGLE_TRY(mVs.resolve(renderer));
183 *vs = &mVs.getObj();
184 *gs = nullptr;
185 }
186 else
187 {
188 // For layered framebuffers we have to use the multi-view versions of the VS and GS.
189 ANGLE_TRY(mVsMultiview.resolve(renderer));
190 ANGLE_TRY(mGsMultiview.resolve(renderer));
191 *vs = &mVsMultiview.getObj();
192 *gs = &mGsMultiview.getObj();
193 }
194
195 *il = nullptr;
196
197 if (numRTs == 0)
198 {
199 ANGLE_TRY(mPsDepth.resolve(renderer));
200 *ps = &mPsDepth.getObj();
201 return gl::NoError();
202 }
203
204 switch (clearType)
205 {
206 case GL_FLOAT:
207 ANGLE_TRY(mPsFloat[numRTs - 1].resolve(renderer));
208 *ps = &mPsFloat[numRTs - 1].getObj();
209 break;
210 case GL_UNSIGNED_INT:
211 ANGLE_TRY(mPsUInt[numRTs - 1].resolve(renderer));
212 *ps = &mPsUInt[numRTs - 1].getObj();
213 break;
214 case GL_INT:
215 ANGLE_TRY(mPsSInt[numRTs - 1].resolve(renderer));
216 *ps = &mPsSInt[numRTs - 1].getObj();
217 break;
218 default:
219 UNREACHABLE();
220 break;
221 }
222
223 return gl::NoError();
224 }
225
Clear11(Renderer11 * renderer)226 Clear11::Clear11(Renderer11 *renderer)
227 : mRenderer(renderer),
228 mResourcesInitialized(false),
229 mScissorEnabledRasterizerState(),
230 mScissorDisabledRasterizerState(),
231 mShaderManager(),
232 mConstantBuffer(),
233 mVertexBuffer(),
234 mShaderData({})
235 {
236 }
237
~Clear11()238 Clear11::~Clear11()
239 {
240 }
241
ensureResourcesInitialized()242 gl::Error Clear11::ensureResourcesInitialized()
243 {
244 if (mResourcesInitialized)
245 {
246 return gl::NoError();
247 }
248
249 TRACE_EVENT0("gpu.angle", "Clear11::ensureResourcesInitialized");
250
251 static_assert((sizeof(RtvDsvClearInfo<float>) == sizeof(RtvDsvClearInfo<int>)),
252 "Size of rx::RtvDsvClearInfo<float> is not equal to rx::RtvDsvClearInfo<int>");
253
254 static_assert(
255 (sizeof(RtvDsvClearInfo<float>) == sizeof(RtvDsvClearInfo<uint32_t>)),
256 "Size of rx::RtvDsvClearInfo<float> is not equal to rx::RtvDsvClearInfo<uint32_t>");
257
258 static_assert((sizeof(RtvDsvClearInfo<float>) % 16 == 0),
259 "The size of RtvDsvClearInfo<float> should be a multiple of 16bytes.");
260
261 // Create Rasterizer States
262 D3D11_RASTERIZER_DESC rsDesc;
263 rsDesc.FillMode = D3D11_FILL_SOLID;
264 rsDesc.CullMode = D3D11_CULL_NONE;
265 rsDesc.FrontCounterClockwise = FALSE;
266 rsDesc.DepthBias = 0;
267 rsDesc.DepthBiasClamp = 0.0f;
268 rsDesc.SlopeScaledDepthBias = 0.0f;
269 rsDesc.DepthClipEnable = TRUE;
270 rsDesc.ScissorEnable = FALSE;
271 rsDesc.MultisampleEnable = FALSE;
272 rsDesc.AntialiasedLineEnable = FALSE;
273
274 ANGLE_TRY(mRenderer->allocateResource(rsDesc, &mScissorDisabledRasterizerState));
275 mScissorDisabledRasterizerState.setDebugName("Clear11 Rasterizer State with scissor disabled");
276
277 rsDesc.ScissorEnable = TRUE;
278 ANGLE_TRY(mRenderer->allocateResource(rsDesc, &mScissorEnabledRasterizerState));
279 mScissorEnabledRasterizerState.setDebugName("Clear11 Rasterizer State with scissor enabled");
280
281 // Initialize Depthstencil state with defaults
282 mDepthStencilStateKey.depthTest = false;
283 mDepthStencilStateKey.depthMask = false;
284 mDepthStencilStateKey.depthFunc = GL_ALWAYS;
285 mDepthStencilStateKey.stencilWritemask = static_cast<GLuint>(-1);
286 mDepthStencilStateKey.stencilBackWritemask = static_cast<GLuint>(-1);
287 mDepthStencilStateKey.stencilBackMask = 0;
288 mDepthStencilStateKey.stencilTest = false;
289 mDepthStencilStateKey.stencilMask = 0;
290 mDepthStencilStateKey.stencilFail = GL_REPLACE;
291 mDepthStencilStateKey.stencilPassDepthFail = GL_REPLACE;
292 mDepthStencilStateKey.stencilPassDepthPass = GL_REPLACE;
293 mDepthStencilStateKey.stencilFunc = GL_ALWAYS;
294 mDepthStencilStateKey.stencilBackFail = GL_REPLACE;
295 mDepthStencilStateKey.stencilBackPassDepthFail = GL_REPLACE;
296 mDepthStencilStateKey.stencilBackPassDepthPass = GL_REPLACE;
297 mDepthStencilStateKey.stencilBackFunc = GL_ALWAYS;
298
299 // Initialize BlendStateKey with defaults
300 mBlendStateKey.blendState.blend = false;
301 mBlendStateKey.blendState.sourceBlendRGB = GL_ONE;
302 mBlendStateKey.blendState.sourceBlendAlpha = GL_ONE;
303 mBlendStateKey.blendState.destBlendRGB = GL_ZERO;
304 mBlendStateKey.blendState.destBlendAlpha = GL_ZERO;
305 mBlendStateKey.blendState.blendEquationRGB = GL_FUNC_ADD;
306 mBlendStateKey.blendState.blendEquationAlpha = GL_FUNC_ADD;
307 mBlendStateKey.blendState.sampleAlphaToCoverage = false;
308 mBlendStateKey.blendState.dither = true;
309
310 mResourcesInitialized = true;
311 return gl::NoError();
312 }
313
useVertexBuffer() const314 bool Clear11::useVertexBuffer() const
315 {
316 return (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3);
317 }
318
ensureConstantBufferCreated()319 gl::Error Clear11::ensureConstantBufferCreated()
320 {
321 if (mConstantBuffer.valid())
322 {
323 return gl::NoError();
324 }
325
326 // Create constant buffer for color & depth data
327
328 D3D11_BUFFER_DESC bufferDesc;
329 bufferDesc.ByteWidth = g_ConstantBufferSize;
330 bufferDesc.Usage = D3D11_USAGE_DYNAMIC;
331 bufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
332 bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
333 bufferDesc.MiscFlags = 0;
334 bufferDesc.StructureByteStride = 0;
335
336 D3D11_SUBRESOURCE_DATA initialData;
337 initialData.pSysMem = &mShaderData;
338 initialData.SysMemPitch = g_ConstantBufferSize;
339 initialData.SysMemSlicePitch = g_ConstantBufferSize;
340
341 ANGLE_TRY(mRenderer->allocateResource(bufferDesc, &initialData, &mConstantBuffer));
342 mConstantBuffer.setDebugName("Clear11 Constant Buffer");
343 return gl::NoError();
344 }
345
ensureVertexBufferCreated()346 gl::Error Clear11::ensureVertexBufferCreated()
347 {
348 ASSERT(useVertexBuffer());
349
350 if (mVertexBuffer.valid())
351 {
352 return gl::NoError();
353 }
354
355 // Create vertex buffer with vertices for a quad covering the entire surface
356
357 static_assert((sizeof(d3d11::PositionVertex) % 16) == 0,
358 "d3d11::PositionVertex should be a multiple of 16 bytes");
359 const d3d11::PositionVertex vbData[6] = {{-1.0f, 1.0f, 0.0f, 1.0f}, {1.0f, -1.0f, 0.0f, 1.0f},
360 {-1.0f, -1.0f, 0.0f, 1.0f}, {-1.0f, 1.0f, 0.0f, 1.0f},
361 {1.0f, 1.0f, 0.0f, 1.0f}, {1.0f, -1.0f, 0.0f, 1.0f}};
362
363 const UINT vbSize = sizeof(vbData);
364
365 D3D11_BUFFER_DESC bufferDesc;
366 bufferDesc.ByteWidth = vbSize;
367 bufferDesc.Usage = D3D11_USAGE_IMMUTABLE;
368 bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
369 bufferDesc.CPUAccessFlags = 0;
370 bufferDesc.MiscFlags = 0;
371 bufferDesc.StructureByteStride = 0;
372
373 D3D11_SUBRESOURCE_DATA initialData;
374 initialData.pSysMem = vbData;
375 initialData.SysMemPitch = vbSize;
376 initialData.SysMemSlicePitch = initialData.SysMemPitch;
377
378 ANGLE_TRY(mRenderer->allocateResource(bufferDesc, &initialData, &mVertexBuffer));
379 mVertexBuffer.setDebugName("Clear11 Vertex Buffer");
380 return gl::NoError();
381 }
382
clearFramebuffer(const gl::Context * context,const ClearParameters & clearParams,const gl::FramebufferState & fboData)383 gl::Error Clear11::clearFramebuffer(const gl::Context *context,
384 const ClearParameters &clearParams,
385 const gl::FramebufferState &fboData)
386 {
387 ANGLE_TRY(ensureResourcesInitialized());
388
389 // Iterate over the color buffers which require clearing and determine if they can be
390 // cleared with ID3D11DeviceContext::ClearRenderTargetView or ID3D11DeviceContext1::ClearView.
391 // This requires:
392 // 1) The render target is being cleared to a float value (will be cast to integer when clearing
393 // integer render targets as expected but does not work the other way around)
394 // 2) The format of the render target has no color channels that are currently masked out.
395 // Clear the easy-to-clear buffers on the spot and accumulate the ones that require special
396 // work.
397 //
398 // If these conditions are met, and:
399 // - No scissored clear is needed, then clear using ID3D11DeviceContext::ClearRenderTargetView.
400 // - A scissored clear is needed then clear using ID3D11DeviceContext1::ClearView if available.
401 // Otherwise perform a shader based clear.
402 //
403 // Also determine if the DSV can be cleared withID3D11DeviceContext::ClearDepthStencilView by
404 // checking if the stencil write mask covers the entire stencil.
405 //
406 // To clear the remaining buffers, a shader based clear is performed:
407 // - The appropriate ShaderManagers (VS & PS) for the clearType is set
408 // - A CB containing the clear color and Z values is bound
409 // - An IL and VB are bound (for FL93 and below)
410 // - ScissorRect/Raststate/Viewport set as required
411 // - Blendstate set containing appropriate colorMasks
412 // - DepthStencilState set with appropriate parameters for a z or stencil clear if required
413 // - Color and/or Z buffers to be cleared are bound
414 // - Primitive covering entire clear area is drawn
415
416 gl::Extents framebufferSize;
417
418 const auto *depthStencilAttachment = fboData.getDepthOrStencilAttachment();
419 if (depthStencilAttachment != nullptr)
420 {
421 framebufferSize = depthStencilAttachment->getSize();
422 }
423 else
424 {
425 const gl::FramebufferAttachment *colorAttachment = fboData.getFirstColorAttachment();
426
427 if (!colorAttachment)
428 {
429 UNREACHABLE();
430 return gl::InternalError();
431 }
432
433 framebufferSize = colorAttachment->getSize();
434 }
435
436 const bool isSideBySideFBO =
437 (fboData.getMultiviewLayout() == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE);
438 bool needScissoredClear = false;
439 std::vector<D3D11_RECT> scissorRects;
440 if (clearParams.scissorEnabled)
441 {
442 const std::vector<gl::Offset> *viewportOffsets = fboData.getViewportOffsets();
443 ASSERT(viewportOffsets != nullptr);
444 ASSERT(AllOffsetsAreNonNegative(*fboData.getViewportOffsets()));
445
446 if (clearParams.scissor.x >= framebufferSize.width ||
447 clearParams.scissor.y >= framebufferSize.height || clearParams.scissor.width == 0 ||
448 clearParams.scissor.height == 0)
449 {
450 // The check assumes that the viewport offsets are not negative as according to the
451 // ANGLE_multiview spec.
452 // Scissor rect is outside the renderbuffer or is an empty rect.
453 return gl::NoError();
454 }
455
456 if (isSideBySideFBO)
457 {
458 // We always have to do a scissor clear for side-by-side framebuffers.
459 needScissoredClear = true;
460 }
461 else
462 {
463 // Because the viewport offsets can generate scissor rectangles within the framebuffer's
464 // bounds, we can do this check only for non-side-by-side framebuffers.
465 if (clearParams.scissor.x + clearParams.scissor.width <= 0 ||
466 clearParams.scissor.y + clearParams.scissor.height <= 0)
467 {
468 // Scissor rect is outside the renderbuffer.
469 return gl::NoError();
470 }
471 needScissoredClear =
472 clearParams.scissor.x > 0 || clearParams.scissor.y > 0 ||
473 clearParams.scissor.x + clearParams.scissor.width < framebufferSize.width ||
474 clearParams.scissor.y + clearParams.scissor.height < framebufferSize.height;
475 }
476
477 if (needScissoredClear)
478 {
479 // Apply viewport offsets to compute the final scissor rectangles. This is valid also
480 // for non-side-by-side framebuffers, because the default viewport offset is {0,0}.
481 const size_t numViews = viewportOffsets->size();
482 scissorRects.reserve(numViews);
483 for (size_t i = 0u; i < numViews; ++i)
484 {
485 const gl::Offset &offset = (*viewportOffsets)[i];
486 D3D11_RECT rect;
487 int x = clearParams.scissor.x + offset.x;
488 int y = clearParams.scissor.y + offset.y;
489 rect.left = x;
490 rect.right = x + clearParams.scissor.width;
491 rect.top = y;
492 rect.bottom = y + clearParams.scissor.height;
493 scissorRects.emplace_back(rect);
494 }
495 }
496 }
497
498 ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
499 ID3D11DeviceContext1 *deviceContext1 = mRenderer->getDeviceContext1IfSupported();
500
501 std::array<ID3D11RenderTargetView *, D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT> rtvs;
502 std::array<uint8_t, D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT> rtvMasks = {};
503
504 uint32_t numRtvs = 0;
505 const uint8_t colorMask =
506 gl_d3d11::ConvertColorMask(clearParams.colorMaskRed, clearParams.colorMaskGreen,
507 clearParams.colorMaskBlue, clearParams.colorMaskAlpha);
508
509 const auto &colorAttachments = fboData.getColorAttachments();
510 for (auto colorAttachmentIndex : fboData.getEnabledDrawBuffers())
511 {
512 const gl::FramebufferAttachment &attachment = colorAttachments[colorAttachmentIndex];
513
514 if (!clearParams.clearColor[colorAttachmentIndex])
515 {
516 continue;
517 }
518
519 RenderTarget11 *renderTarget = nullptr;
520 ANGLE_TRY(attachment.getRenderTarget(context, &renderTarget));
521
522 const gl::InternalFormat &formatInfo = *attachment.getFormat().info;
523
524 if (clearParams.colorType == GL_FLOAT &&
525 !(formatInfo.componentType == GL_FLOAT ||
526 formatInfo.componentType == GL_UNSIGNED_NORMALIZED ||
527 formatInfo.componentType == GL_SIGNED_NORMALIZED))
528 {
529 ERR() << "It is undefined behaviour to clear a render buffer which is not "
530 "normalized fixed point or floating-point to floating point values (color "
531 "attachment "
532 << colorAttachmentIndex << " has internal format " << attachment.getFormat()
533 << ").";
534 }
535
536 if ((formatInfo.redBits == 0 || !clearParams.colorMaskRed) &&
537 (formatInfo.greenBits == 0 || !clearParams.colorMaskGreen) &&
538 (formatInfo.blueBits == 0 || !clearParams.colorMaskBlue) &&
539 (formatInfo.alphaBits == 0 || !clearParams.colorMaskAlpha))
540 {
541 // Every channel either does not exist in the render target or is masked out
542 continue;
543 }
544
545 const auto &framebufferRTV = renderTarget->getRenderTargetView();
546 ASSERT(framebufferRTV.valid());
547
548 if ((!(mRenderer->getRenderer11DeviceCaps().supportsClearView) && needScissoredClear) ||
549 clearParams.colorType != GL_FLOAT ||
550 (formatInfo.redBits > 0 && !clearParams.colorMaskRed) ||
551 (formatInfo.greenBits > 0 && !clearParams.colorMaskGreen) ||
552 (formatInfo.blueBits > 0 && !clearParams.colorMaskBlue) ||
553 (formatInfo.alphaBits > 0 && !clearParams.colorMaskAlpha))
554 {
555 rtvs[numRtvs] = framebufferRTV.get();
556 rtvMasks[numRtvs] = gl_d3d11::GetColorMask(formatInfo) & colorMask;
557 numRtvs++;
558 }
559 else
560 {
561 // ID3D11DeviceContext::ClearRenderTargetView or ID3D11DeviceContext1::ClearView is
562 // possible
563
564 const auto &nativeFormat = renderTarget->getFormatSet().format();
565
566 // Check if the actual format has a channel that the internal format does not and
567 // set them to the default values
568 float clearValues[4] = {
569 ((formatInfo.redBits == 0 && nativeFormat.redBits > 0) ? 0.0f
570 : clearParams.colorF.red),
571 ((formatInfo.greenBits == 0 && nativeFormat.greenBits > 0)
572 ? 0.0f
573 : clearParams.colorF.green),
574 ((formatInfo.blueBits == 0 && nativeFormat.blueBits > 0) ? 0.0f
575 : clearParams.colorF.blue),
576 ((formatInfo.alphaBits == 0 && nativeFormat.alphaBits > 0)
577 ? 1.0f
578 : clearParams.colorF.alpha),
579 };
580
581 if (formatInfo.alphaBits == 1)
582 {
583 // Some drivers do not correctly handle calling Clear() on a format with 1-bit
584 // alpha. They can incorrectly round all non-zero values up to 1.0f. Note that
585 // WARP does not do this. We should handle the rounding for them instead.
586 clearValues[3] = (clearParams.colorF.alpha >= 0.5f) ? 1.0f : 0.0f;
587 }
588
589 if (needScissoredClear)
590 {
591 // We shouldn't reach here if deviceContext1 is unavailable.
592 ASSERT(deviceContext1);
593 // There must be at least one scissor rectangle.
594 ASSERT(!scissorRects.empty());
595 deviceContext1->ClearView(framebufferRTV.get(), clearValues, scissorRects.data(),
596 static_cast<UINT>(scissorRects.size()));
597 if (mRenderer->getWorkarounds().callClearTwice)
598 {
599 deviceContext1->ClearView(framebufferRTV.get(), clearValues,
600 scissorRects.data(),
601 static_cast<UINT>(scissorRects.size()));
602 }
603 }
604 else
605 {
606 deviceContext->ClearRenderTargetView(framebufferRTV.get(), clearValues);
607 if (mRenderer->getWorkarounds().callClearTwice)
608 {
609 deviceContext->ClearRenderTargetView(framebufferRTV.get(), clearValues);
610 }
611 }
612 }
613 }
614
615 ID3D11DepthStencilView *dsv = nullptr;
616
617 if (clearParams.clearDepth || clearParams.clearStencil)
618 {
619 RenderTarget11 *depthStencilRenderTarget = nullptr;
620
621 ASSERT(depthStencilAttachment != nullptr);
622 ANGLE_TRY(depthStencilAttachment->getRenderTarget(context, &depthStencilRenderTarget));
623
624 dsv = depthStencilRenderTarget->getDepthStencilView().get();
625 ASSERT(dsv != nullptr);
626
627 const auto &nativeFormat = depthStencilRenderTarget->getFormatSet().format();
628 const auto *stencilAttachment = fboData.getStencilAttachment();
629
630 uint32_t stencilUnmasked =
631 (stencilAttachment != nullptr) ? (1 << nativeFormat.stencilBits) - 1 : 0;
632 bool needMaskedStencilClear =
633 clearParams.clearStencil &&
634 (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked;
635
636 if (!needScissoredClear && !needMaskedStencilClear)
637 {
638 const UINT clearFlags = (clearParams.clearDepth ? D3D11_CLEAR_DEPTH : 0) |
639 (clearParams.clearStencil ? D3D11_CLEAR_STENCIL : 0);
640 const FLOAT depthClear = gl::clamp01(clearParams.depthValue);
641 const UINT8 stencilClear = clearParams.stencilValue & 0xFF;
642
643 deviceContext->ClearDepthStencilView(dsv, clearFlags, depthClear, stencilClear);
644
645 dsv = nullptr;
646 }
647 }
648
649 if (numRtvs == 0 && dsv == nullptr)
650 {
651 return gl::NoError();
652 }
653
654 // Clear the remaining render targets and depth stencil in one pass by rendering a quad:
655 //
656 // IA/VS: Vertices containing position and color members are passed through to the next stage.
657 // The vertex position has XY coordinates equal to clip extents and a Z component equal to the
658 // Z clear value. The vertex color contains the clear color.
659 //
660 // Rasterizer: Viewport scales the VS output over the entire surface and depending on whether
661 // or not scissoring is enabled the appropriate scissor rect and rasterizerState with or without
662 // the scissor test enabled is set as well.
663 //
664 // DepthStencilTest: DepthTesting, DepthWrites, StencilMask and StencilWrites will be enabled or
665 // disabled or set depending on what the input depthStencil clear parameters are. Since the PS
666 // is not writing out depth or rejecting pixels, this should happen prior to the PS stage.
667 //
668 // PS: Will write out the color values passed through from the previous stage to all outputs.
669 //
670 // OM: BlendState will perform the required color masking and output to RTV(s).
671
672 //
673 // ======================================================================================
674 //
675 // Luckily, the gl spec (ES 3.0.2 pg 183) states that the results of clearing a render-
676 // buffer that is not normalized fixed point or floating point with floating point values
677 // are undefined so we can just write floats to them and D3D11 will bit cast them to
678 // integers.
679 //
680 // Also, we don't have to worry about attempting to clear a normalized fixed/floating point
681 // buffer with integer values because there is no gl API call which would allow it,
682 // glClearBuffer* calls only clear a single renderbuffer at a time which is verified to
683 // be a compatible clear type.
684
685 ASSERT(numRtvs <= mRenderer->getNativeCaps().maxDrawBuffers);
686
687 // Setup BlendStateKey parameters
688 mBlendStateKey.blendState.colorMaskRed = clearParams.colorMaskRed;
689 mBlendStateKey.blendState.colorMaskGreen = clearParams.colorMaskGreen;
690 mBlendStateKey.blendState.colorMaskBlue = clearParams.colorMaskBlue;
691 mBlendStateKey.blendState.colorMaskAlpha = clearParams.colorMaskAlpha;
692 mBlendStateKey.rtvMax = numRtvs;
693 memcpy(mBlendStateKey.rtvMasks, &rtvMasks[0], sizeof(mBlendStateKey.rtvMasks));
694
695 // Get BlendState
696 const d3d11::BlendState *blendState = nullptr;
697 ANGLE_TRY(mRenderer->getBlendState(mBlendStateKey, &blendState));
698
699 const d3d11::DepthStencilState *dsState = nullptr;
700 const float *zValue = nullptr;
701
702 if (dsv)
703 {
704 // Setup DepthStencilStateKey
705 mDepthStencilStateKey.depthTest = clearParams.clearDepth;
706 mDepthStencilStateKey.depthMask = clearParams.clearDepth;
707 mDepthStencilStateKey.stencilWritemask = clearParams.stencilWriteMask;
708 mDepthStencilStateKey.stencilTest = clearParams.clearStencil;
709
710 // Get DepthStencilState
711 ANGLE_TRY(mRenderer->getDepthStencilState(mDepthStencilStateKey, &dsState));
712 zValue = clearParams.clearDepth ? &clearParams.depthValue : nullptr;
713 }
714
715 bool dirtyCb = false;
716
717 // Compare the input color/z values against the CB cache and update it if necessary
718 switch (clearParams.colorType)
719 {
720 case GL_FLOAT:
721 dirtyCb = UpdateDataCache(reinterpret_cast<RtvDsvClearInfo<float> *>(&mShaderData),
722 clearParams.colorF, zValue, numRtvs, colorMask);
723 break;
724 case GL_UNSIGNED_INT:
725 dirtyCb = UpdateDataCache(reinterpret_cast<RtvDsvClearInfo<uint32_t> *>(&mShaderData),
726 clearParams.colorUI, zValue, numRtvs, colorMask);
727 break;
728 case GL_INT:
729 dirtyCb = UpdateDataCache(reinterpret_cast<RtvDsvClearInfo<int> *>(&mShaderData),
730 clearParams.colorI, zValue, numRtvs, colorMask);
731 break;
732 default:
733 UNREACHABLE();
734 break;
735 }
736
737 ANGLE_TRY(ensureConstantBufferCreated());
738
739 if (dirtyCb)
740 {
741 // Update the constant buffer with the updated cache contents
742 // TODO(Shahmeer): Consider using UpdateSubresource1 D3D11_COPY_DISCARD where possible.
743 D3D11_MAPPED_SUBRESOURCE mappedResource;
744 HRESULT result = deviceContext->Map(mConstantBuffer.get(), 0, D3D11_MAP_WRITE_DISCARD, 0,
745 &mappedResource);
746 if (FAILED(result))
747 {
748 return gl::OutOfMemory() << "Clear11: Failed to map CB, " << gl::FmtHR(result);
749 }
750
751 memcpy(mappedResource.pData, &mShaderData, g_ConstantBufferSize);
752 deviceContext->Unmap(mConstantBuffer.get(), 0);
753 }
754
755 auto *stateManager = mRenderer->getStateManager();
756
757 // Set the viewport to be the same size as the framebuffer.
758 stateManager->setSimpleViewport(framebufferSize);
759
760 // Apply state
761 stateManager->setSimpleBlendState(blendState);
762
763 const UINT stencilValue = clearParams.stencilValue & 0xFF;
764 stateManager->setDepthStencilState(dsState, stencilValue);
765
766 if (needScissoredClear)
767 {
768 stateManager->setRasterizerState(&mScissorEnabledRasterizerState);
769 }
770 else
771 {
772 stateManager->setRasterizerState(&mScissorDisabledRasterizerState);
773 }
774
775 // Get Shaders
776 const d3d11::VertexShader *vs = nullptr;
777 const d3d11::GeometryShader *gs = nullptr;
778 const d3d11::InputLayout *il = nullptr;
779 const d3d11::PixelShader *ps = nullptr;
780 const bool hasLayeredLayout =
781 (fboData.getMultiviewLayout() == GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE);
782 ANGLE_TRY(mShaderManager.getShadersAndLayout(mRenderer, clearParams.colorType, numRtvs,
783 hasLayeredLayout, &il, &vs, &gs, &ps));
784
785 // Apply Shaders
786 stateManager->setDrawShaders(vs, gs, ps);
787 stateManager->setPixelConstantBuffer(0, &mConstantBuffer);
788
789 // Bind IL & VB if needed
790 stateManager->setIndexBuffer(nullptr, DXGI_FORMAT_UNKNOWN, 0);
791 stateManager->setInputLayout(il);
792
793 if (useVertexBuffer())
794 {
795 ANGLE_TRY(ensureVertexBufferCreated());
796 stateManager->setSingleVertexBuffer(&mVertexBuffer, g_VertexSize, 0);
797 }
798 else
799 {
800 stateManager->setSingleVertexBuffer(nullptr, 0, 0);
801 }
802
803 stateManager->setPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
804
805 // Apply render targets
806 stateManager->setRenderTargets(&rtvs[0], numRtvs, dsv);
807
808 // If scissors are necessary to be applied, then the number of clears is the number of scissor
809 // rects. If no scissors are necessary, then a single full-size clear is enough.
810 size_t necessaryNumClears = needScissoredClear ? scissorRects.size() : 1u;
811 for (size_t i = 0u; i < necessaryNumClears; ++i)
812 {
813 if (needScissoredClear)
814 {
815 ASSERT(i < scissorRects.size());
816 stateManager->setScissorRectD3D(scissorRects[i]);
817 }
818 // Draw the fullscreen quad.
819 if (!hasLayeredLayout || isSideBySideFBO)
820 {
821 deviceContext->Draw(6, 0);
822 }
823 else
824 {
825 ASSERT(hasLayeredLayout);
826 deviceContext->DrawInstanced(6, static_cast<UINT>(fboData.getNumViews()), 0, 0);
827 }
828 }
829
830 return gl::NoError();
831 }
832
833 } // namespace rx
834