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