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