• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2016 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 // Context11:
7 //   D3D11-specific functionality associated with a GL Context.
8 //
9 
10 #include "libANGLE/renderer/d3d/d3d11/Context11.h"
11 
12 #include "common/entry_points_enum_autogen.h"
13 #include "common/string_utils.h"
14 #include "libANGLE/Context.h"
15 #include "libANGLE/Context.inl.h"
16 #include "libANGLE/MemoryProgramCache.h"
17 #include "libANGLE/renderer/OverlayImpl.h"
18 #include "libANGLE/renderer/d3d/CompilerD3D.h"
19 #include "libANGLE/renderer/d3d/RenderbufferD3D.h"
20 #include "libANGLE/renderer/d3d/SamplerD3D.h"
21 #include "libANGLE/renderer/d3d/ShaderD3D.h"
22 #include "libANGLE/renderer/d3d/TextureD3D.h"
23 #include "libANGLE/renderer/d3d/d3d11/Buffer11.h"
24 #include "libANGLE/renderer/d3d/d3d11/Fence11.h"
25 #include "libANGLE/renderer/d3d/d3d11/Framebuffer11.h"
26 #include "libANGLE/renderer/d3d/d3d11/IndexBuffer11.h"
27 #include "libANGLE/renderer/d3d/d3d11/Program11.h"
28 #include "libANGLE/renderer/d3d/d3d11/ProgramPipeline11.h"
29 #include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
30 #include "libANGLE/renderer/d3d/d3d11/StateManager11.h"
31 #include "libANGLE/renderer/d3d/d3d11/TransformFeedback11.h"
32 #include "libANGLE/renderer/d3d/d3d11/VertexArray11.h"
33 #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
34 
35 namespace rx
36 {
37 
38 namespace
39 {
DrawCallHasDynamicAttribs(const gl::Context * context)40 ANGLE_INLINE bool DrawCallHasDynamicAttribs(const gl::Context *context)
41 {
42     VertexArray11 *vertexArray11 = GetImplAs<VertexArray11>(context->getState().getVertexArray());
43     return vertexArray11->hasActiveDynamicAttrib(context);
44 }
45 
DrawCallHasStreamingVertexArrays(const gl::Context * context,gl::PrimitiveMode mode)46 bool DrawCallHasStreamingVertexArrays(const gl::Context *context, gl::PrimitiveMode mode)
47 {
48     // Direct drawing doesn't support dynamic attribute storage since it needs the first and count
49     // to translate when applyVertexBuffer. GL_LINE_LOOP and GL_TRIANGLE_FAN are not supported
50     // either since we need to simulate them in D3D.
51     if (DrawCallHasDynamicAttribs(context) || mode == gl::PrimitiveMode::LineLoop ||
52         mode == gl::PrimitiveMode::TriangleFan)
53     {
54         return true;
55     }
56 
57     ProgramD3D *programD3D = GetImplAs<ProgramD3D>(context->getState().getProgram());
58     if (InstancedPointSpritesActive(programD3D, mode))
59     {
60         return true;
61     }
62 
63     return false;
64 }
65 
DrawCallHasStreamingElementArray(const gl::Context * context,gl::DrawElementsType srcType)66 bool DrawCallHasStreamingElementArray(const gl::Context *context, gl::DrawElementsType srcType)
67 {
68     const gl::State &glState       = context->getState();
69     gl::Buffer *elementArrayBuffer = glState.getVertexArray()->getElementArrayBuffer();
70 
71     bool primitiveRestartWorkaround =
72         UsePrimitiveRestartWorkaround(glState.isPrimitiveRestartEnabled(), srcType);
73     const gl::DrawElementsType dstType =
74         (srcType == gl::DrawElementsType::UnsignedInt || primitiveRestartWorkaround)
75             ? gl::DrawElementsType::UnsignedInt
76             : gl::DrawElementsType::UnsignedShort;
77 
78     // Not clear where the offset comes from here.
79     switch (ClassifyIndexStorage(glState, elementArrayBuffer, srcType, dstType, 0))
80     {
81         case IndexStorageType::Dynamic:
82             return true;
83         case IndexStorageType::Direct:
84             return false;
85         case IndexStorageType::Static:
86         {
87             BufferD3D *bufferD3D                     = GetImplAs<BufferD3D>(elementArrayBuffer);
88             StaticIndexBufferInterface *staticBuffer = bufferD3D->getStaticIndexBuffer();
89             return (staticBuffer->getBufferSize() == 0 || staticBuffer->getIndexType() != dstType);
90         }
91         default:
92             UNREACHABLE();
93             return true;
94     }
95 }
96 
97 template <typename IndirectBufferT>
ReadbackIndirectBuffer(const gl::Context * context,const void * indirect,const IndirectBufferT ** bufferPtrOut)98 angle::Result ReadbackIndirectBuffer(const gl::Context *context,
99                                      const void *indirect,
100                                      const IndirectBufferT **bufferPtrOut)
101 {
102     const gl::State &glState       = context->getState();
103     gl::Buffer *drawIndirectBuffer = glState.getTargetBuffer(gl::BufferBinding::DrawIndirect);
104     ASSERT(drawIndirectBuffer);
105     Buffer11 *storage = GetImplAs<Buffer11>(drawIndirectBuffer);
106     uintptr_t offset  = reinterpret_cast<uintptr_t>(indirect);
107 
108     const uint8_t *bufferData = nullptr;
109     ANGLE_TRY(storage->getData(context, &bufferData));
110     ASSERT(bufferData);
111 
112     *bufferPtrOut = reinterpret_cast<const IndirectBufferT *>(bufferData + offset);
113     return angle::Result::Continue;
114 }
115 }  // anonymous namespace
116 
Context11(const gl::State & state,gl::ErrorSet * errorSet,Renderer11 * renderer)117 Context11::Context11(const gl::State &state, gl::ErrorSet *errorSet, Renderer11 *renderer)
118     : ContextD3D(state, errorSet), mRenderer(renderer)
119 {}
120 
~Context11()121 Context11::~Context11() {}
122 
initialize()123 angle::Result Context11::initialize()
124 {
125     return angle::Result::Continue;
126 }
127 
onDestroy(const gl::Context * context)128 void Context11::onDestroy(const gl::Context *context)
129 {
130     mIncompleteTextures.onDestroy(context);
131 }
132 
createCompiler()133 CompilerImpl *Context11::createCompiler()
134 {
135     if (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3)
136     {
137         return new CompilerD3D(SH_HLSL_4_0_FL9_3_OUTPUT);
138     }
139     else
140     {
141         return new CompilerD3D(SH_HLSL_4_1_OUTPUT);
142     }
143 }
144 
createShader(const gl::ShaderState & data)145 ShaderImpl *Context11::createShader(const gl::ShaderState &data)
146 {
147     return new ShaderD3D(data, mRenderer->getFeatures(), mRenderer->getNativeExtensions());
148 }
149 
createProgram(const gl::ProgramState & data)150 ProgramImpl *Context11::createProgram(const gl::ProgramState &data)
151 {
152     return new Program11(data, mRenderer);
153 }
154 
createFramebuffer(const gl::FramebufferState & data)155 FramebufferImpl *Context11::createFramebuffer(const gl::FramebufferState &data)
156 {
157     return new Framebuffer11(data, mRenderer);
158 }
159 
createTexture(const gl::TextureState & state)160 TextureImpl *Context11::createTexture(const gl::TextureState &state)
161 {
162     switch (state.getType())
163     {
164         case gl::TextureType::_2D:
165         // GL_TEXTURE_VIDEO_IMAGE_WEBGL maps to native 2D texture on Windows platform
166         case gl::TextureType::VideoImage:
167             return new TextureD3D_2D(state, mRenderer);
168         case gl::TextureType::CubeMap:
169             return new TextureD3D_Cube(state, mRenderer);
170         case gl::TextureType::_3D:
171             return new TextureD3D_3D(state, mRenderer);
172         case gl::TextureType::_2DArray:
173             return new TextureD3D_2DArray(state, mRenderer);
174         case gl::TextureType::External:
175             return new TextureD3D_External(state, mRenderer);
176         case gl::TextureType::_2DMultisample:
177             return new TextureD3D_2DMultisample(state, mRenderer);
178         case gl::TextureType::_2DMultisampleArray:
179             return new TextureD3D_2DMultisampleArray(state, mRenderer);
180         default:
181             UNREACHABLE();
182     }
183 
184     return nullptr;
185 }
186 
createRenderbuffer(const gl::RenderbufferState & state)187 RenderbufferImpl *Context11::createRenderbuffer(const gl::RenderbufferState &state)
188 {
189     return new RenderbufferD3D(state, mRenderer);
190 }
191 
createBuffer(const gl::BufferState & state)192 BufferImpl *Context11::createBuffer(const gl::BufferState &state)
193 {
194     Buffer11 *buffer = new Buffer11(state, mRenderer);
195     mRenderer->onBufferCreate(buffer);
196     return buffer;
197 }
198 
createVertexArray(const gl::VertexArrayState & data)199 VertexArrayImpl *Context11::createVertexArray(const gl::VertexArrayState &data)
200 {
201     return new VertexArray11(data);
202 }
203 
createQuery(gl::QueryType type)204 QueryImpl *Context11::createQuery(gl::QueryType type)
205 {
206     return new Query11(mRenderer, type);
207 }
208 
createFenceNV()209 FenceNVImpl *Context11::createFenceNV()
210 {
211     return new FenceNV11(mRenderer);
212 }
213 
createSync()214 SyncImpl *Context11::createSync()
215 {
216     return new Sync11(mRenderer);
217 }
218 
createTransformFeedback(const gl::TransformFeedbackState & state)219 TransformFeedbackImpl *Context11::createTransformFeedback(const gl::TransformFeedbackState &state)
220 {
221     return new TransformFeedback11(state, mRenderer);
222 }
223 
createSampler(const gl::SamplerState & state)224 SamplerImpl *Context11::createSampler(const gl::SamplerState &state)
225 {
226     return new SamplerD3D(state);
227 }
228 
createProgramPipeline(const gl::ProgramPipelineState & data)229 ProgramPipelineImpl *Context11::createProgramPipeline(const gl::ProgramPipelineState &data)
230 {
231     return new ProgramPipeline11(data);
232 }
233 
createMemoryObject()234 MemoryObjectImpl *Context11::createMemoryObject()
235 {
236     UNREACHABLE();
237     return nullptr;
238 }
239 
createSemaphore()240 SemaphoreImpl *Context11::createSemaphore()
241 {
242     UNREACHABLE();
243     return nullptr;
244 }
245 
createOverlay(const gl::OverlayState & state)246 OverlayImpl *Context11::createOverlay(const gl::OverlayState &state)
247 {
248     // Not implemented.
249     return new OverlayImpl(state);
250 }
251 
flush(const gl::Context * context)252 angle::Result Context11::flush(const gl::Context *context)
253 {
254     return mRenderer->flush(this);
255 }
256 
finish(const gl::Context * context)257 angle::Result Context11::finish(const gl::Context *context)
258 {
259     return mRenderer->finish(this);
260 }
261 
drawArrays(const gl::Context * context,gl::PrimitiveMode mode,GLint first,GLsizei count)262 angle::Result Context11::drawArrays(const gl::Context *context,
263                                     gl::PrimitiveMode mode,
264                                     GLint first,
265                                     GLsizei count)
266 {
267     ASSERT(count > 0);
268     ANGLE_TRY(mRenderer->getStateManager()->updateState(
269         context, mode, first, count, gl::DrawElementsType::InvalidEnum, nullptr, 0, 0, 0, true));
270     return mRenderer->drawArrays(context, mode, first, count, 0, 0, false);
271 }
272 
drawArraysInstanced(const gl::Context * context,gl::PrimitiveMode mode,GLint first,GLsizei count,GLsizei instanceCount)273 angle::Result Context11::drawArraysInstanced(const gl::Context *context,
274                                              gl::PrimitiveMode mode,
275                                              GLint first,
276                                              GLsizei count,
277                                              GLsizei instanceCount)
278 {
279     ASSERT(count > 0);
280     ANGLE_TRY(mRenderer->getStateManager()->updateState(context, mode, first, count,
281                                                         gl::DrawElementsType::InvalidEnum, nullptr,
282                                                         instanceCount, 0, 0, true));
283     return mRenderer->drawArrays(context, mode, first, count, instanceCount, 0, true);
284 }
285 
drawArraysInstancedBaseInstance(const gl::Context * context,gl::PrimitiveMode mode,GLint first,GLsizei count,GLsizei instanceCount,GLuint baseInstance)286 angle::Result Context11::drawArraysInstancedBaseInstance(const gl::Context *context,
287                                                          gl::PrimitiveMode mode,
288                                                          GLint first,
289                                                          GLsizei count,
290                                                          GLsizei instanceCount,
291                                                          GLuint baseInstance)
292 {
293     ASSERT(count > 0);
294     ANGLE_TRY(mRenderer->getStateManager()->updateState(context, mode, first, count,
295                                                         gl::DrawElementsType::InvalidEnum, nullptr,
296                                                         instanceCount, 0, baseInstance, true));
297     return mRenderer->drawArrays(context, mode, first, count, instanceCount, baseInstance, true);
298 }
299 
drawElementsImpl(const gl::Context * context,gl::PrimitiveMode mode,GLsizei indexCount,gl::DrawElementsType indexType,const void * indices,GLsizei instanceCount,GLint baseVertex,GLuint baseInstance,bool promoteDynamic,bool isInstancedDraw)300 ANGLE_INLINE angle::Result Context11::drawElementsImpl(const gl::Context *context,
301                                                        gl::PrimitiveMode mode,
302                                                        GLsizei indexCount,
303                                                        gl::DrawElementsType indexType,
304                                                        const void *indices,
305                                                        GLsizei instanceCount,
306                                                        GLint baseVertex,
307                                                        GLuint baseInstance,
308                                                        bool promoteDynamic,
309                                                        bool isInstancedDraw)
310 {
311     ASSERT(indexCount > 0);
312 
313     if (DrawCallHasDynamicAttribs(context))
314     {
315         gl::IndexRange indexRange;
316         ANGLE_TRY(context->getState().getVertexArray()->getIndexRange(
317             context, indexType, indexCount, indices, &indexRange));
318         GLint startVertex;
319         ANGLE_TRY(ComputeStartVertex(GetImplAs<Context11>(context), indexRange, baseVertex,
320                                      &startVertex));
321         ANGLE_TRY(mRenderer->getStateManager()->updateState(
322             context, mode, startVertex, indexCount, indexType, indices, instanceCount, baseVertex,
323             baseInstance, promoteDynamic));
324         return mRenderer->drawElements(context, mode, startVertex, indexCount, indexType, indices,
325                                        instanceCount, baseVertex, baseInstance, isInstancedDraw);
326     }
327     else
328     {
329         ANGLE_TRY(mRenderer->getStateManager()->updateState(context, mode, 0, indexCount, indexType,
330                                                             indices, instanceCount, baseVertex,
331                                                             baseInstance, promoteDynamic));
332         return mRenderer->drawElements(context, mode, 0, indexCount, indexType, indices,
333                                        instanceCount, baseVertex, baseInstance, isInstancedDraw);
334     }
335 }
336 
drawElements(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices)337 angle::Result Context11::drawElements(const gl::Context *context,
338                                       gl::PrimitiveMode mode,
339                                       GLsizei count,
340                                       gl::DrawElementsType type,
341                                       const void *indices)
342 {
343     return drawElementsImpl(context, mode, count, type, indices, 0, 0, 0, true, false);
344 }
345 
drawElementsBaseVertex(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices,GLint baseVertex)346 angle::Result Context11::drawElementsBaseVertex(const gl::Context *context,
347                                                 gl::PrimitiveMode mode,
348                                                 GLsizei count,
349                                                 gl::DrawElementsType type,
350                                                 const void *indices,
351                                                 GLint baseVertex)
352 {
353     return drawElementsImpl(context, mode, count, type, indices, 0, baseVertex, 0, true, false);
354 }
355 
drawElementsInstanced(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices,GLsizei instances)356 angle::Result Context11::drawElementsInstanced(const gl::Context *context,
357                                                gl::PrimitiveMode mode,
358                                                GLsizei count,
359                                                gl::DrawElementsType type,
360                                                const void *indices,
361                                                GLsizei instances)
362 {
363     return drawElementsImpl(context, mode, count, type, indices, instances, 0, 0, true, true);
364 }
365 
drawElementsInstancedBaseVertex(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices,GLsizei instances,GLint baseVertex)366 angle::Result Context11::drawElementsInstancedBaseVertex(const gl::Context *context,
367                                                          gl::PrimitiveMode mode,
368                                                          GLsizei count,
369                                                          gl::DrawElementsType type,
370                                                          const void *indices,
371                                                          GLsizei instances,
372                                                          GLint baseVertex)
373 {
374     return drawElementsImpl(context, mode, count, type, indices, instances, baseVertex, 0, true,
375                             true);
376 }
377 
drawElementsInstancedBaseVertexBaseInstance(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices,GLsizei instances,GLint baseVertex,GLuint baseInstance)378 angle::Result Context11::drawElementsInstancedBaseVertexBaseInstance(const gl::Context *context,
379                                                                      gl::PrimitiveMode mode,
380                                                                      GLsizei count,
381                                                                      gl::DrawElementsType type,
382                                                                      const void *indices,
383                                                                      GLsizei instances,
384                                                                      GLint baseVertex,
385                                                                      GLuint baseInstance)
386 {
387     return drawElementsImpl(context, mode, count, type, indices, instances, baseVertex,
388                             baseInstance, true, true);
389 }
390 
drawRangeElements(const gl::Context * context,gl::PrimitiveMode mode,GLuint start,GLuint end,GLsizei count,gl::DrawElementsType type,const void * indices)391 angle::Result Context11::drawRangeElements(const gl::Context *context,
392                                            gl::PrimitiveMode mode,
393                                            GLuint start,
394                                            GLuint end,
395                                            GLsizei count,
396                                            gl::DrawElementsType type,
397                                            const void *indices)
398 {
399     return drawElementsImpl(context, mode, count, type, indices, 0, 0, 0, true, false);
400 }
401 
drawRangeElementsBaseVertex(const gl::Context * context,gl::PrimitiveMode mode,GLuint start,GLuint end,GLsizei count,gl::DrawElementsType type,const void * indices,GLint baseVertex)402 angle::Result Context11::drawRangeElementsBaseVertex(const gl::Context *context,
403                                                      gl::PrimitiveMode mode,
404                                                      GLuint start,
405                                                      GLuint end,
406                                                      GLsizei count,
407                                                      gl::DrawElementsType type,
408                                                      const void *indices,
409                                                      GLint baseVertex)
410 {
411     return drawElementsImpl(context, mode, count, type, indices, 0, baseVertex, 0, true, false);
412 }
413 
drawArraysIndirect(const gl::Context * context,gl::PrimitiveMode mode,const void * indirect)414 angle::Result Context11::drawArraysIndirect(const gl::Context *context,
415                                             gl::PrimitiveMode mode,
416                                             const void *indirect)
417 {
418     if (DrawCallHasStreamingVertexArrays(context, mode))
419     {
420         const gl::DrawArraysIndirectCommand *cmd = nullptr;
421         ANGLE_TRY(ReadbackIndirectBuffer(context, indirect, &cmd));
422 
423         ANGLE_TRY(mRenderer->getStateManager()->updateState(
424             context, mode, cmd->first, cmd->count, gl::DrawElementsType::InvalidEnum, nullptr,
425             cmd->instanceCount, 0, 0, true));
426         return mRenderer->drawArrays(context, mode, cmd->first, cmd->count, cmd->instanceCount,
427                                      cmd->baseInstance, true);
428     }
429     else
430     {
431         ANGLE_TRY(mRenderer->getStateManager()->updateState(
432             context, mode, 0, 0, gl::DrawElementsType::InvalidEnum, nullptr, 0, 0, 0, true));
433         return mRenderer->drawArraysIndirect(context, indirect);
434     }
435 }
436 
drawElementsIndirect(const gl::Context * context,gl::PrimitiveMode mode,gl::DrawElementsType type,const void * indirect)437 angle::Result Context11::drawElementsIndirect(const gl::Context *context,
438                                               gl::PrimitiveMode mode,
439                                               gl::DrawElementsType type,
440                                               const void *indirect)
441 {
442     if (DrawCallHasStreamingVertexArrays(context, mode) ||
443         DrawCallHasStreamingElementArray(context, type))
444     {
445         const gl::DrawElementsIndirectCommand *cmd = nullptr;
446         ANGLE_TRY(ReadbackIndirectBuffer(context, indirect, &cmd));
447 
448         const GLuint typeBytes = gl::GetDrawElementsTypeSize(type);
449         const void *indices =
450             reinterpret_cast<const void *>(static_cast<uintptr_t>(cmd->firstIndex * typeBytes));
451 
452         // We must explicitly resolve the index range for the slow-path indirect drawElements to
453         // make sure we are using the correct 'baseVertex'. This parameter does not exist for the
454         // direct drawElements.
455         gl::IndexRange indexRange;
456         ANGLE_TRY(context->getState().getVertexArray()->getIndexRange(context, type, cmd->count,
457                                                                       indices, &indexRange));
458 
459         GLint startVertex;
460         ANGLE_TRY(ComputeStartVertex(GetImplAs<Context11>(context), indexRange, cmd->baseVertex,
461                                      &startVertex));
462 
463         ANGLE_TRY(mRenderer->getStateManager()->updateState(
464             context, mode, startVertex, cmd->count, type, indices, cmd->primCount, cmd->baseVertex,
465             cmd->baseInstance, true));
466         return mRenderer->drawElements(context, mode, static_cast<GLint>(indexRange.start),
467                                        cmd->count, type, indices, cmd->primCount, 0, 0, true);
468     }
469     else
470     {
471         ANGLE_TRY(mRenderer->getStateManager()->updateState(context, mode, 0, 0, type, nullptr, 0,
472                                                             0, 0, true));
473         return mRenderer->drawElementsIndirect(context, indirect);
474     }
475 }
476 
477 #define DRAW_ARRAYS__                                                                           \
478     {                                                                                           \
479         ANGLE_TRY(mRenderer->getStateManager()->updateState(                                    \
480             context, mode, firsts[drawID], counts[drawID], gl::DrawElementsType::InvalidEnum,   \
481             nullptr, 0, 0, 0, false));                                                          \
482         ANGLE_TRY(                                                                              \
483             mRenderer->drawArrays(context, mode, firsts[drawID], counts[drawID], 0, 0, false)); \
484     }
485 #define DRAW_ARRAYS_INSTANCED_                                                                \
486     {                                                                                         \
487         ANGLE_TRY(mRenderer->getStateManager()->updateState(                                  \
488             context, mode, firsts[drawID], counts[drawID], gl::DrawElementsType::InvalidEnum, \
489             nullptr, instanceCounts[drawID], 0, 0, false));                                   \
490         ANGLE_TRY(mRenderer->drawArrays(context, mode, firsts[drawID], counts[drawID],        \
491                                         instanceCounts[drawID], 0, true));                    \
492     }
493 #define DRAW_ARRAYS_INSTANCED_BASE_INSTANCE                                                    \
494     {                                                                                          \
495         ANGLE_TRY(mRenderer->getStateManager()->updateState(                                   \
496             context, mode, firsts[drawID], counts[drawID], gl::DrawElementsType::InvalidEnum,  \
497             nullptr, instanceCounts[drawID], 0, baseInstances[drawID], false));                \
498         ANGLE_TRY(mRenderer->drawArrays(context, mode, firsts[drawID], counts[drawID],         \
499                                         instanceCounts[drawID], baseInstances[drawID], true)); \
500     }
501 #define DRAW_ELEMENTS__                                                                           \
502     {                                                                                             \
503         ANGLE_TRY(drawElementsImpl(context, mode, counts[drawID], type, indices[drawID], 0, 0, 0, \
504                                    false, false));                                                \
505     }
506 #define DRAW_ELEMENTS_INSTANCED_                                                         \
507     {                                                                                    \
508         ANGLE_TRY(drawElementsImpl(context, mode, counts[drawID], type, indices[drawID], \
509                                    instanceCounts[drawID], 0, 0, false, true));          \
510     }
511 #define DRAW_ELEMENTS_INSTANCED_BASE_VERTEX_BASE_INSTANCE                                \
512     {                                                                                    \
513         ANGLE_TRY(drawElementsImpl(context, mode, counts[drawID], type, indices[drawID], \
514                                    instanceCounts[drawID], baseVertices[drawID],         \
515                                    baseInstances[drawID], false, true));                 \
516     }
517 
518 #define DRAW_CALL(drawType, instanced, bvbi) DRAW_##drawType##instanced##bvbi
519 
520 #define MULTI_DRAW_BLOCK(drawType, instanced, bvbi, hasDrawID, hasBaseVertex, hasBaseInstance) \
521     for (GLsizei drawID = 0; drawID < drawcount; ++drawID)                                     \
522     {                                                                                          \
523         if (ANGLE_NOOP_DRAW(instanced))                                                        \
524         {                                                                                      \
525             continue;                                                                          \
526         }                                                                                      \
527         ANGLE_SET_DRAW_ID_UNIFORM(hasDrawID)(drawID);                                          \
528         ANGLE_SET_BASE_VERTEX_UNIFORM(hasBaseVertex)(baseVertices[drawID]);                    \
529         ANGLE_SET_BASE_INSTANCE_UNIFORM(hasBaseInstance)(baseInstances[drawID]);               \
530         ASSERT(counts[drawID] > 0);                                                            \
531         DRAW_CALL(drawType, instanced, bvbi);                                                  \
532         ANGLE_MARK_TRANSFORM_FEEDBACK_USAGE(instanced);                                        \
533         gl::MarkShaderStorageUsage(context);                                                   \
534     }
535 
multiDrawArrays(const gl::Context * context,gl::PrimitiveMode mode,const GLint * firsts,const GLsizei * counts,GLsizei drawcount)536 angle::Result Context11::multiDrawArrays(const gl::Context *context,
537                                          gl::PrimitiveMode mode,
538                                          const GLint *firsts,
539                                          const GLsizei *counts,
540                                          GLsizei drawcount)
541 {
542     gl::Program *programObject = context->getState().getLinkedProgram(context);
543     const bool hasDrawID       = programObject && programObject->hasDrawIDUniform();
544     if (hasDrawID)
545     {
546         MULTI_DRAW_BLOCK(ARRAYS, _, _, 1, 0, 0)
547     }
548     else
549     {
550         MULTI_DRAW_BLOCK(ARRAYS, _, _, 0, 0, 0)
551     }
552 
553     return angle::Result::Continue;
554 }
555 
multiDrawArraysInstanced(const gl::Context * context,gl::PrimitiveMode mode,const GLint * firsts,const GLsizei * counts,const GLsizei * instanceCounts,GLsizei drawcount)556 angle::Result Context11::multiDrawArraysInstanced(const gl::Context *context,
557                                                   gl::PrimitiveMode mode,
558                                                   const GLint *firsts,
559                                                   const GLsizei *counts,
560                                                   const GLsizei *instanceCounts,
561                                                   GLsizei drawcount)
562 {
563     gl::Program *programObject = context->getState().getLinkedProgram(context);
564     const bool hasDrawID       = programObject && programObject->hasDrawIDUniform();
565     if (hasDrawID)
566     {
567         MULTI_DRAW_BLOCK(ARRAYS, _INSTANCED, _, 1, 0, 0)
568     }
569     else
570     {
571         MULTI_DRAW_BLOCK(ARRAYS, _INSTANCED, _, 0, 0, 0)
572     }
573 
574     return angle::Result::Continue;
575 }
576 
multiDrawArraysIndirect(const gl::Context * context,gl::PrimitiveMode mode,const void * indirect,GLsizei drawcount,GLsizei stride)577 angle::Result Context11::multiDrawArraysIndirect(const gl::Context *context,
578                                                  gl::PrimitiveMode mode,
579                                                  const void *indirect,
580                                                  GLsizei drawcount,
581                                                  GLsizei stride)
582 {
583     return rx::MultiDrawArraysIndirectGeneral(this, context, mode, indirect, drawcount, stride);
584 }
585 
multiDrawElements(const gl::Context * context,gl::PrimitiveMode mode,const GLsizei * counts,gl::DrawElementsType type,const GLvoid * const * indices,GLsizei drawcount)586 angle::Result Context11::multiDrawElements(const gl::Context *context,
587                                            gl::PrimitiveMode mode,
588                                            const GLsizei *counts,
589                                            gl::DrawElementsType type,
590                                            const GLvoid *const *indices,
591                                            GLsizei drawcount)
592 {
593     gl::Program *programObject = context->getState().getLinkedProgram(context);
594     const bool hasDrawID       = programObject && programObject->hasDrawIDUniform();
595     if (hasDrawID)
596     {
597         MULTI_DRAW_BLOCK(ELEMENTS, _, _, 1, 0, 0)
598     }
599     else
600     {
601         MULTI_DRAW_BLOCK(ELEMENTS, _, _, 0, 0, 0)
602     }
603 
604     return angle::Result::Continue;
605 }
606 
multiDrawElementsInstanced(const gl::Context * context,gl::PrimitiveMode mode,const GLsizei * counts,gl::DrawElementsType type,const GLvoid * const * indices,const GLsizei * instanceCounts,GLsizei drawcount)607 angle::Result Context11::multiDrawElementsInstanced(const gl::Context *context,
608                                                     gl::PrimitiveMode mode,
609                                                     const GLsizei *counts,
610                                                     gl::DrawElementsType type,
611                                                     const GLvoid *const *indices,
612                                                     const GLsizei *instanceCounts,
613                                                     GLsizei drawcount)
614 {
615     gl::Program *programObject = context->getState().getLinkedProgram(context);
616     const bool hasDrawID       = programObject && programObject->hasDrawIDUniform();
617     if (hasDrawID)
618     {
619         MULTI_DRAW_BLOCK(ELEMENTS, _INSTANCED, _, 1, 0, 0)
620     }
621     else
622     {
623         MULTI_DRAW_BLOCK(ELEMENTS, _INSTANCED, _, 0, 0, 0)
624     }
625 
626     return angle::Result::Continue;
627 }
628 
multiDrawElementsIndirect(const gl::Context * context,gl::PrimitiveMode mode,gl::DrawElementsType type,const void * indirect,GLsizei drawcount,GLsizei stride)629 angle::Result Context11::multiDrawElementsIndirect(const gl::Context *context,
630                                                    gl::PrimitiveMode mode,
631                                                    gl::DrawElementsType type,
632                                                    const void *indirect,
633                                                    GLsizei drawcount,
634                                                    GLsizei stride)
635 {
636     return rx::MultiDrawElementsIndirectGeneral(this, context, mode, type, indirect, drawcount,
637                                                 stride);
638 }
639 
multiDrawArraysInstancedBaseInstance(const gl::Context * context,gl::PrimitiveMode mode,const GLint * firsts,const GLsizei * counts,const GLsizei * instanceCounts,const GLuint * baseInstances,GLsizei drawcount)640 angle::Result Context11::multiDrawArraysInstancedBaseInstance(const gl::Context *context,
641                                                               gl::PrimitiveMode mode,
642                                                               const GLint *firsts,
643                                                               const GLsizei *counts,
644                                                               const GLsizei *instanceCounts,
645                                                               const GLuint *baseInstances,
646                                                               GLsizei drawcount)
647 {
648     gl::Program *programObject = context->getState().getLinkedProgram(context);
649     const bool hasDrawID       = programObject && programObject->hasDrawIDUniform();
650     const bool hasBaseInstance = programObject && programObject->hasBaseInstanceUniform();
651     ResetBaseVertexBaseInstance resetUniforms(programObject, false, hasBaseInstance);
652 
653     if (hasDrawID && hasBaseInstance)
654     {
655         MULTI_DRAW_BLOCK(ARRAYS, _INSTANCED, _BASE_INSTANCE, 1, 0, 1)
656     }
657     else if (hasDrawID)
658     {
659         MULTI_DRAW_BLOCK(ARRAYS, _INSTANCED, _BASE_INSTANCE, 1, 0, 0)
660     }
661     else if (hasBaseInstance)
662     {
663         MULTI_DRAW_BLOCK(ARRAYS, _INSTANCED, _BASE_INSTANCE, 0, 0, 1)
664     }
665     else
666     {
667         MULTI_DRAW_BLOCK(ARRAYS, _INSTANCED, _BASE_INSTANCE, 0, 0, 0)
668     }
669 
670     return angle::Result::Continue;
671 }
672 
multiDrawElementsInstancedBaseVertexBaseInstance(const gl::Context * context,gl::PrimitiveMode mode,const GLsizei * counts,gl::DrawElementsType type,const GLvoid * const * indices,const GLsizei * instanceCounts,const GLint * baseVertices,const GLuint * baseInstances,GLsizei drawcount)673 angle::Result Context11::multiDrawElementsInstancedBaseVertexBaseInstance(
674     const gl::Context *context,
675     gl::PrimitiveMode mode,
676     const GLsizei *counts,
677     gl::DrawElementsType type,
678     const GLvoid *const *indices,
679     const GLsizei *instanceCounts,
680     const GLint *baseVertices,
681     const GLuint *baseInstances,
682     GLsizei drawcount)
683 {
684     gl::Program *programObject = context->getState().getLinkedProgram(context);
685     const bool hasDrawID       = programObject && programObject->hasDrawIDUniform();
686     const bool hasBaseVertex   = programObject && programObject->hasBaseVertexUniform();
687     const bool hasBaseInstance = programObject && programObject->hasBaseInstanceUniform();
688     ResetBaseVertexBaseInstance resetUniforms(programObject, hasBaseVertex, hasBaseInstance);
689 
690     if (hasDrawID)
691     {
692         if (hasBaseVertex)
693         {
694             if (hasBaseInstance)
695             {
696                 MULTI_DRAW_BLOCK(ELEMENTS, _INSTANCED, _BASE_VERTEX_BASE_INSTANCE, 1, 1, 1)
697             }
698             else
699             {
700                 MULTI_DRAW_BLOCK(ELEMENTS, _INSTANCED, _BASE_VERTEX_BASE_INSTANCE, 1, 1, 0)
701             }
702         }
703         else
704         {
705             if (hasBaseInstance)
706             {
707                 MULTI_DRAW_BLOCK(ELEMENTS, _INSTANCED, _BASE_VERTEX_BASE_INSTANCE, 1, 0, 1)
708             }
709             else
710             {
711                 MULTI_DRAW_BLOCK(ELEMENTS, _INSTANCED, _BASE_VERTEX_BASE_INSTANCE, 1, 0, 0)
712             }
713         }
714     }
715     else
716     {
717         if (hasBaseVertex)
718         {
719             if (hasBaseInstance)
720             {
721                 MULTI_DRAW_BLOCK(ELEMENTS, _INSTANCED, _BASE_VERTEX_BASE_INSTANCE, 0, 1, 1)
722             }
723             else
724             {
725                 MULTI_DRAW_BLOCK(ELEMENTS, _INSTANCED, _BASE_VERTEX_BASE_INSTANCE, 0, 1, 0)
726             }
727         }
728         else
729         {
730             if (hasBaseInstance)
731             {
732                 MULTI_DRAW_BLOCK(ELEMENTS, _INSTANCED, _BASE_VERTEX_BASE_INSTANCE, 0, 0, 1)
733             }
734             else
735             {
736                 MULTI_DRAW_BLOCK(ELEMENTS, _INSTANCED, _BASE_VERTEX_BASE_INSTANCE, 0, 0, 0)
737             }
738         }
739     }
740 
741     return angle::Result::Continue;
742 }
743 
getResetStatus()744 gl::GraphicsResetStatus Context11::getResetStatus()
745 {
746     return mRenderer->getResetStatus();
747 }
748 
insertEventMarker(GLsizei length,const char * marker)749 angle::Result Context11::insertEventMarker(GLsizei length, const char *marker)
750 {
751     mRenderer->getAnnotator()->setMarker(marker);
752     return angle::Result::Continue;
753 }
754 
pushGroupMarker(GLsizei length,const char * marker)755 angle::Result Context11::pushGroupMarker(GLsizei length, const char *marker)
756 {
757     mRenderer->getAnnotator()->beginEvent(nullptr, angle::EntryPoint::GLPushGroupMarkerEXT, marker,
758                                           marker);
759     mMarkerStack.push(std::string(marker));
760     return angle::Result::Continue;
761 }
762 
popGroupMarker()763 angle::Result Context11::popGroupMarker()
764 {
765     const char *marker = nullptr;
766     if (!mMarkerStack.empty())
767     {
768         marker = mMarkerStack.top().c_str();
769         mMarkerStack.pop();
770         mRenderer->getAnnotator()->endEvent(nullptr, marker,
771                                             angle::EntryPoint::GLPopGroupMarkerEXT);
772     }
773     return angle::Result::Continue;
774 }
775 
pushDebugGroup(const gl::Context * context,GLenum source,GLuint id,const std::string & message)776 angle::Result Context11::pushDebugGroup(const gl::Context *context,
777                                         GLenum source,
778                                         GLuint id,
779                                         const std::string &message)
780 {
781     // Fall through to the EXT_debug_marker functions
782     return pushGroupMarker(static_cast<GLsizei>(message.size()), message.c_str());
783 }
784 
popDebugGroup(const gl::Context * context)785 angle::Result Context11::popDebugGroup(const gl::Context *context)
786 {
787     // Fall through to the EXT_debug_marker functions
788     return popGroupMarker();
789 }
790 
syncState(const gl::Context * context,const gl::State::DirtyBits & dirtyBits,const gl::State::DirtyBits & bitMask,gl::Command command)791 angle::Result Context11::syncState(const gl::Context *context,
792                                    const gl::State::DirtyBits &dirtyBits,
793                                    const gl::State::DirtyBits &bitMask,
794                                    gl::Command command)
795 {
796     mRenderer->getStateManager()->syncState(context, dirtyBits, command);
797     return angle::Result::Continue;
798 }
799 
getGPUDisjoint()800 GLint Context11::getGPUDisjoint()
801 {
802     return mRenderer->getGPUDisjoint();
803 }
804 
getTimestamp()805 GLint64 Context11::getTimestamp()
806 {
807     return mRenderer->getTimestamp();
808 }
809 
onMakeCurrent(const gl::Context * context)810 angle::Result Context11::onMakeCurrent(const gl::Context *context)
811 {
812     // Immediately return if the device has been lost.
813     if (!mRenderer->getDevice())
814     {
815         return angle::Result::Continue;
816     }
817 
818     return mRenderer->getStateManager()->onMakeCurrent(context);
819 }
820 
getNativeCaps() const821 gl::Caps Context11::getNativeCaps() const
822 {
823     gl::Caps caps = mRenderer->getNativeCaps();
824 
825     // For pixel shaders, the render targets and unordered access views share the same resource
826     // slots, so the maximum number of fragment shader outputs depends on the current context
827     // version:
828     // - If current context is ES 3.0 and below, we use D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT(8)
829     //   as the value of max draw buffers because UAVs are not used.
830     // - If current context is ES 3.1 and the feature level is 11_0, the RTVs and UAVs share 8
831     //   slots. As ES 3.1 requires at least 1 atomic counter buffer in compute shaders, the value
832     //   of max combined shader output resources is limited to 7, thus only 7 RTV slots can be
833     //   used simultaneously.
834     // - If current context is ES 3.1 and the feature level is 11_1, the RTVs and UAVs share 64
835     //   slots. Currently we allocate 60 slots for combined shader output resources, so we can use
836     //   at most D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT(8) RTVs simultaneously.
837     if (mState.getClientVersion() >= gl::ES_3_1 &&
838         mRenderer->getRenderer11DeviceCaps().featureLevel == D3D_FEATURE_LEVEL_11_0)
839     {
840         caps.maxDrawBuffers      = caps.maxCombinedShaderOutputResources;
841         caps.maxColorAttachments = caps.maxCombinedShaderOutputResources;
842     }
843 
844     return caps;
845 }
846 
getNativeTextureCaps() const847 const gl::TextureCapsMap &Context11::getNativeTextureCaps() const
848 {
849     return mRenderer->getNativeTextureCaps();
850 }
851 
getNativeExtensions() const852 const gl::Extensions &Context11::getNativeExtensions() const
853 {
854     return mRenderer->getNativeExtensions();
855 }
856 
getNativeLimitations() const857 const gl::Limitations &Context11::getNativeLimitations() const
858 {
859     return mRenderer->getNativeLimitations();
860 }
861 
dispatchCompute(const gl::Context * context,GLuint numGroupsX,GLuint numGroupsY,GLuint numGroupsZ)862 angle::Result Context11::dispatchCompute(const gl::Context *context,
863                                          GLuint numGroupsX,
864                                          GLuint numGroupsY,
865                                          GLuint numGroupsZ)
866 {
867     return mRenderer->dispatchCompute(context, numGroupsX, numGroupsY, numGroupsZ);
868 }
869 
dispatchComputeIndirect(const gl::Context * context,GLintptr indirect)870 angle::Result Context11::dispatchComputeIndirect(const gl::Context *context, GLintptr indirect)
871 {
872     return mRenderer->dispatchComputeIndirect(context, indirect);
873 }
874 
triggerDrawCallProgramRecompilation(const gl::Context * context,gl::PrimitiveMode drawMode)875 angle::Result Context11::triggerDrawCallProgramRecompilation(const gl::Context *context,
876                                                              gl::PrimitiveMode drawMode)
877 {
878     const auto &glState    = context->getState();
879     const auto *va11       = GetImplAs<VertexArray11>(glState.getVertexArray());
880     const auto *drawFBO    = glState.getDrawFramebuffer();
881     gl::Program *program   = glState.getProgram();
882     ProgramD3D *programD3D = GetImplAs<ProgramD3D>(program);
883 
884     programD3D->updateCachedInputLayout(va11->getCurrentStateSerial(), glState);
885     programD3D->updateCachedOutputLayout(context, drawFBO);
886 
887     bool recompileVS = !programD3D->hasVertexExecutableForCachedInputLayout();
888     bool recompileGS = !programD3D->hasGeometryExecutableForPrimitiveType(glState, drawMode);
889     bool recompilePS = !programD3D->hasPixelExecutableForCachedOutputLayout();
890 
891     if (!recompileVS && !recompileGS && !recompilePS)
892     {
893         return angle::Result::Continue;
894     }
895 
896     // Load the compiler if necessary and recompile the programs.
897     ANGLE_TRY(mRenderer->ensureHLSLCompilerInitialized(this));
898 
899     gl::InfoLog infoLog;
900 
901     if (recompileVS)
902     {
903         ShaderExecutableD3D *vertexExe = nullptr;
904         ANGLE_TRY(programD3D->getVertexExecutableForCachedInputLayout(this, &vertexExe, &infoLog));
905         if (!programD3D->hasVertexExecutableForCachedInputLayout())
906         {
907             ASSERT(infoLog.getLength() > 0);
908             ERR() << "Error compiling dynamic vertex executable: " << infoLog.str();
909             ANGLE_TRY_HR(this, E_FAIL, "Error compiling dynamic vertex executable");
910         }
911     }
912 
913     if (recompileGS)
914     {
915         ShaderExecutableD3D *geometryExe = nullptr;
916         ANGLE_TRY(programD3D->getGeometryExecutableForPrimitiveType(this, glState, drawMode,
917                                                                     &geometryExe, &infoLog));
918         if (!programD3D->hasGeometryExecutableForPrimitiveType(glState, drawMode))
919         {
920             ASSERT(infoLog.getLength() > 0);
921             ERR() << "Error compiling dynamic geometry executable: " << infoLog.str();
922             ANGLE_TRY_HR(this, E_FAIL, "Error compiling dynamic geometry executable");
923         }
924     }
925 
926     if (recompilePS)
927     {
928         ShaderExecutableD3D *pixelExe = nullptr;
929         ANGLE_TRY(programD3D->getPixelExecutableForCachedOutputLayout(this, &pixelExe, &infoLog));
930         if (!programD3D->hasPixelExecutableForCachedOutputLayout())
931         {
932             ASSERT(infoLog.getLength() > 0);
933             ERR() << "Error compiling dynamic pixel executable: " << infoLog.str();
934             ANGLE_TRY_HR(this, E_FAIL, "Error compiling dynamic pixel executable");
935         }
936     }
937 
938     // Refresh the program cache entry.
939     if (mMemoryProgramCache)
940     {
941         ANGLE_TRY(mMemoryProgramCache->updateProgram(context, program));
942     }
943 
944     return angle::Result::Continue;
945 }
946 
triggerDispatchCallProgramRecompilation(const gl::Context * context)947 angle::Result Context11::triggerDispatchCallProgramRecompilation(const gl::Context *context)
948 {
949     const auto &glState    = context->getState();
950     gl::Program *program   = glState.getProgram();
951     ProgramD3D *programD3D = GetImplAs<ProgramD3D>(program);
952 
953     programD3D->updateCachedComputeImage2DBindLayout(context);
954 
955     bool recompileCS = !programD3D->hasComputeExecutableForCachedImage2DBindLayout();
956 
957     if (!recompileCS)
958     {
959         return angle::Result::Continue;
960     }
961 
962     // Load the compiler if necessary and recompile the programs.
963     ANGLE_TRY(mRenderer->ensureHLSLCompilerInitialized(this));
964 
965     gl::InfoLog infoLog;
966 
967     ShaderExecutableD3D *computeExe = nullptr;
968     ANGLE_TRY(programD3D->getComputeExecutableForImage2DBindLayout(this, &computeExe, &infoLog));
969     if (!programD3D->hasComputeExecutableForCachedImage2DBindLayout())
970     {
971         ASSERT(infoLog.getLength() > 0);
972         ERR() << "Dynamic recompilation error log: " << infoLog.str();
973         ANGLE_TRY_HR(this, E_FAIL, "Error compiling dynamic compute executable");
974     }
975 
976     // Refresh the program cache entry.
977     if (mMemoryProgramCache)
978     {
979         ANGLE_TRY(mMemoryProgramCache->updateProgram(context, program));
980     }
981 
982     return angle::Result::Continue;
983 }
984 
memoryBarrier(const gl::Context * context,GLbitfield barriers)985 angle::Result Context11::memoryBarrier(const gl::Context *context, GLbitfield barriers)
986 {
987     return angle::Result::Continue;
988 }
989 
memoryBarrierByRegion(const gl::Context * context,GLbitfield barriers)990 angle::Result Context11::memoryBarrierByRegion(const gl::Context *context, GLbitfield barriers)
991 {
992     return angle::Result::Continue;
993 }
994 
getIncompleteTexture(const gl::Context * context,gl::TextureType type,gl::Texture ** textureOut)995 angle::Result Context11::getIncompleteTexture(const gl::Context *context,
996                                               gl::TextureType type,
997                                               gl::Texture **textureOut)
998 {
999     return mIncompleteTextures.getIncompleteTexture(context, type, gl::SamplerFormat::Float, this,
1000                                                     textureOut);
1001 }
1002 
initializeMultisampleTextureToBlack(const gl::Context * context,gl::Texture * glTexture)1003 angle::Result Context11::initializeMultisampleTextureToBlack(const gl::Context *context,
1004                                                              gl::Texture *glTexture)
1005 {
1006     ASSERT(glTexture->getType() == gl::TextureType::_2DMultisample);
1007     TextureD3D *textureD3D        = GetImplAs<TextureD3D>(glTexture);
1008     gl::ImageIndex index          = gl::ImageIndex::Make2DMultisample();
1009     RenderTargetD3D *renderTarget = nullptr;
1010     GLsizei texSamples            = textureD3D->getRenderToTextureSamples();
1011     ANGLE_TRY(textureD3D->getRenderTarget(context, index, texSamples, &renderTarget));
1012     return mRenderer->clearRenderTarget(context, renderTarget, gl::ColorF(0.0f, 0.0f, 0.0f, 1.0f),
1013                                         1.0f, 0);
1014 }
1015 
handleResult(HRESULT hr,const char * message,const char * file,const char * function,unsigned int line)1016 void Context11::handleResult(HRESULT hr,
1017                              const char *message,
1018                              const char *file,
1019                              const char *function,
1020                              unsigned int line)
1021 {
1022     ASSERT(FAILED(hr));
1023 
1024     GLenum glErrorCode = DefaultGLErrorCode(hr);
1025 
1026     std::stringstream errorStream;
1027     errorStream << "Internal D3D11 error: " << gl::FmtHR(hr);
1028 
1029     if (d3d11::isDeviceLostError(hr))
1030     {
1031         HRESULT removalReason = mRenderer->getDevice()->GetDeviceRemovedReason();
1032         errorStream << " (removal reason: " << gl::FmtHR(removalReason) << ")";
1033         mRenderer->notifyDeviceLost();
1034     }
1035 
1036     errorStream << ": " << message;
1037 
1038     mErrors->handleError(glErrorCode, errorStream.str().c_str(), file, function, line);
1039 }
1040 }  // namespace rx
1041