1 //
2 // Copyright (c) 2012-2014 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 // Renderer11.cpp: Implements a back-end specific class for the D3D11 renderer.
8
9 #include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
10
11 #include <EGL/eglext.h>
12 #include <versionhelpers.h>
13 #include <sstream>
14
15 #include "common/tls.h"
16 #include "common/utilities.h"
17 #include "libANGLE/Buffer.h"
18 #include "libANGLE/Context.h"
19 #include "libANGLE/Display.h"
20 #include "libANGLE/Framebuffer.h"
21 #include "libANGLE/FramebufferAttachment.h"
22 #include "libANGLE/Program.h"
23 #include "libANGLE/State.h"
24 #include "libANGLE/Surface.h"
25 #include "libANGLE/formatutils.h"
26 #include "libANGLE/histogram_macros.h"
27 #include "libANGLE/renderer/d3d/CompilerD3D.h"
28 #include "libANGLE/renderer/d3d/DeviceD3D.h"
29 #include "libANGLE/renderer/d3d/DisplayD3D.h"
30 #include "libANGLE/renderer/d3d/FramebufferD3D.h"
31 #include "libANGLE/renderer/d3d/IndexDataManager.h"
32 #include "libANGLE/renderer/d3d/ProgramD3D.h"
33 #include "libANGLE/renderer/d3d/RenderbufferD3D.h"
34 #include "libANGLE/renderer/d3d/ShaderD3D.h"
35 #include "libANGLE/renderer/d3d/SurfaceD3D.h"
36 #include "libANGLE/renderer/d3d/TextureD3D.h"
37 #include "libANGLE/renderer/d3d/VertexDataManager.h"
38 #include "libANGLE/renderer/d3d/d3d11/Blit11.h"
39 #include "libANGLE/renderer/d3d/d3d11/Buffer11.h"
40 #include "libANGLE/renderer/d3d/d3d11/Clear11.h"
41 #include "libANGLE/renderer/d3d/d3d11/Context11.h"
42 #include "libANGLE/renderer/d3d/d3d11/Fence11.h"
43 #include "libANGLE/renderer/d3d/d3d11/Framebuffer11.h"
44 #include "libANGLE/renderer/d3d/d3d11/Image11.h"
45 #include "libANGLE/renderer/d3d/d3d11/IndexBuffer11.h"
46 #include "libANGLE/renderer/d3d/d3d11/PixelTransfer11.h"
47 #include "libANGLE/renderer/d3d/d3d11/Query11.h"
48 #include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h"
49 #include "libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h"
50 #include "libANGLE/renderer/d3d/d3d11/StreamProducerD3DTexture.h"
51 #include "libANGLE/renderer/d3d/d3d11/SwapChain11.h"
52 #include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h"
53 #include "libANGLE/renderer/d3d/d3d11/TransformFeedback11.h"
54 #include "libANGLE/renderer/d3d/d3d11/Trim11.h"
55 #include "libANGLE/renderer/d3d/d3d11/VertexArray11.h"
56 #include "libANGLE/renderer/d3d/d3d11/VertexBuffer11.h"
57 #include "libANGLE/renderer/d3d/d3d11/dxgi_support_table.h"
58 #include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
59 #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
60 #include "libANGLE/renderer/d3d/d3d11/texture_format_table.h"
61 #include "libANGLE/renderer/renderer_utils.h"
62 #include "third_party/trace_event/trace_event.h"
63
64 #ifdef ANGLE_ENABLE_WINDOWS_STORE
65 #include "libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.h"
66 #else
67 #include "libANGLE/renderer/d3d/d3d11/win32/NativeWindow11Win32.h"
68 #endif
69
70 // Include the D3D9 debug annotator header for use by the desktop D3D11 renderer
71 // because the D3D11 interface method ID3DUserDefinedAnnotation::GetStatus
72 // doesn't work with the Graphics Diagnostics tools in Visual Studio 2013.
73 #ifdef ANGLE_ENABLE_D3D9
74 #include "libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h"
75 #endif
76
77 // Enable ANGLE_SKIP_DXGI_1_2_CHECK if there is not a possibility of using cross-process
78 // HWNDs or the Windows 7 Platform Update (KB2670838) is expected to be installed.
79 #ifndef ANGLE_SKIP_DXGI_1_2_CHECK
80 #define ANGLE_SKIP_DXGI_1_2_CHECK 0
81 #endif
82
83 namespace rx
84 {
85
86 namespace
87 {
88
89 enum
90 {
91 MAX_TEXTURE_IMAGE_UNITS_VTF_SM4 = 16
92 };
93
94 enum ANGLEFeatureLevel
95 {
96 ANGLE_FEATURE_LEVEL_INVALID,
97 ANGLE_FEATURE_LEVEL_9_3,
98 ANGLE_FEATURE_LEVEL_10_0,
99 ANGLE_FEATURE_LEVEL_10_1,
100 ANGLE_FEATURE_LEVEL_11_0,
101 ANGLE_FEATURE_LEVEL_11_1,
102 NUM_ANGLE_FEATURE_LEVELS
103 };
104
GetANGLEFeatureLevel(D3D_FEATURE_LEVEL d3dFeatureLevel)105 ANGLEFeatureLevel GetANGLEFeatureLevel(D3D_FEATURE_LEVEL d3dFeatureLevel)
106 {
107 switch (d3dFeatureLevel)
108 {
109 case D3D_FEATURE_LEVEL_9_3:
110 return ANGLE_FEATURE_LEVEL_9_3;
111 case D3D_FEATURE_LEVEL_10_0:
112 return ANGLE_FEATURE_LEVEL_10_0;
113 case D3D_FEATURE_LEVEL_10_1:
114 return ANGLE_FEATURE_LEVEL_10_1;
115 case D3D_FEATURE_LEVEL_11_0:
116 return ANGLE_FEATURE_LEVEL_11_0;
117 case D3D_FEATURE_LEVEL_11_1:
118 return ANGLE_FEATURE_LEVEL_11_1;
119 default:
120 return ANGLE_FEATURE_LEVEL_INVALID;
121 }
122 }
123
SetLineLoopIndices(GLuint * dest,size_t count)124 void SetLineLoopIndices(GLuint *dest, size_t count)
125 {
126 for (size_t i = 0; i < count; i++)
127 {
128 dest[i] = static_cast<GLuint>(i);
129 }
130 dest[count] = 0;
131 }
132
133 template <typename T>
CopyLineLoopIndices(const void * indices,GLuint * dest,size_t count)134 void CopyLineLoopIndices(const void *indices, GLuint *dest, size_t count)
135 {
136 const T *srcPtr = static_cast<const T *>(indices);
137 for (size_t i = 0; i < count; ++i)
138 {
139 dest[i] = static_cast<GLuint>(srcPtr[i]);
140 }
141 dest[count] = static_cast<GLuint>(srcPtr[0]);
142 }
143
SetTriangleFanIndices(GLuint * destPtr,size_t numTris)144 void SetTriangleFanIndices(GLuint *destPtr, size_t numTris)
145 {
146 for (size_t i = 0; i < numTris; i++)
147 {
148 destPtr[i * 3 + 0] = 0;
149 destPtr[i * 3 + 1] = static_cast<GLuint>(i) + 1;
150 destPtr[i * 3 + 2] = static_cast<GLuint>(i) + 2;
151 }
152 }
153
154 template <typename T>
CopyLineLoopIndicesWithRestart(const void * indices,size_t count,GLenum indexType,std::vector<GLuint> * bufferOut)155 void CopyLineLoopIndicesWithRestart(const void *indices,
156 size_t count,
157 GLenum indexType,
158 std::vector<GLuint> *bufferOut)
159 {
160 GLuint restartIndex = gl::GetPrimitiveRestartIndex(indexType);
161 GLuint d3dRestartIndex = static_cast<GLuint>(d3d11::GetPrimitiveRestartIndex());
162 const T *srcPtr = static_cast<const T *>(indices);
163 Optional<GLuint> currentLoopStart;
164
165 bufferOut->clear();
166
167 for (size_t indexIdx = 0; indexIdx < count; ++indexIdx)
168 {
169 GLuint value = static_cast<GLuint>(srcPtr[indexIdx]);
170
171 if (value == restartIndex)
172 {
173 if (currentLoopStart.valid())
174 {
175 bufferOut->push_back(currentLoopStart.value());
176 bufferOut->push_back(d3dRestartIndex);
177 currentLoopStart.reset();
178 }
179 }
180 else
181 {
182 bufferOut->push_back(value);
183 if (!currentLoopStart.valid())
184 {
185 currentLoopStart = value;
186 }
187 }
188 }
189
190 if (currentLoopStart.valid())
191 {
192 bufferOut->push_back(currentLoopStart.value());
193 }
194 }
195
GetLineLoopIndices(const void * indices,GLenum indexType,GLuint count,bool usePrimitiveRestartFixedIndex,std::vector<GLuint> * bufferOut)196 void GetLineLoopIndices(const void *indices,
197 GLenum indexType,
198 GLuint count,
199 bool usePrimitiveRestartFixedIndex,
200 std::vector<GLuint> *bufferOut)
201 {
202 if (indexType != GL_NONE && usePrimitiveRestartFixedIndex)
203 {
204 switch (indexType)
205 {
206 case GL_UNSIGNED_BYTE:
207 CopyLineLoopIndicesWithRestart<GLubyte>(indices, count, indexType, bufferOut);
208 break;
209 case GL_UNSIGNED_SHORT:
210 CopyLineLoopIndicesWithRestart<GLushort>(indices, count, indexType, bufferOut);
211 break;
212 case GL_UNSIGNED_INT:
213 CopyLineLoopIndicesWithRestart<GLuint>(indices, count, indexType, bufferOut);
214 break;
215 default:
216 UNREACHABLE();
217 break;
218 }
219 return;
220 }
221
222 // For non-primitive-restart draws, the index count is static.
223 bufferOut->resize(static_cast<size_t>(count) + 1);
224
225 switch (indexType)
226 {
227 // Non-indexed draw
228 case GL_NONE:
229 SetLineLoopIndices(&(*bufferOut)[0], count);
230 break;
231 case GL_UNSIGNED_BYTE:
232 CopyLineLoopIndices<GLubyte>(indices, &(*bufferOut)[0], count);
233 break;
234 case GL_UNSIGNED_SHORT:
235 CopyLineLoopIndices<GLushort>(indices, &(*bufferOut)[0], count);
236 break;
237 case GL_UNSIGNED_INT:
238 CopyLineLoopIndices<GLuint>(indices, &(*bufferOut)[0], count);
239 break;
240 default:
241 UNREACHABLE();
242 break;
243 }
244 }
245
246 template <typename T>
CopyTriangleFanIndices(const void * indices,GLuint * destPtr,size_t numTris)247 void CopyTriangleFanIndices(const void *indices, GLuint *destPtr, size_t numTris)
248 {
249 const T *srcPtr = static_cast<const T *>(indices);
250
251 for (size_t i = 0; i < numTris; i++)
252 {
253 destPtr[i * 3 + 0] = static_cast<GLuint>(srcPtr[0]);
254 destPtr[i * 3 + 1] = static_cast<GLuint>(srcPtr[i + 1]);
255 destPtr[i * 3 + 2] = static_cast<GLuint>(srcPtr[i + 2]);
256 }
257 }
258
259 template <typename T>
CopyTriangleFanIndicesWithRestart(const void * indices,GLuint indexCount,GLenum indexType,std::vector<GLuint> * bufferOut)260 void CopyTriangleFanIndicesWithRestart(const void *indices,
261 GLuint indexCount,
262 GLenum indexType,
263 std::vector<GLuint> *bufferOut)
264 {
265 GLuint restartIndex = gl::GetPrimitiveRestartIndex(indexType);
266 GLuint d3dRestartIndex = gl::GetPrimitiveRestartIndex(GL_UNSIGNED_INT);
267 const T *srcPtr = static_cast<const T *>(indices);
268 Optional<GLuint> vertexA;
269 Optional<GLuint> vertexB;
270
271 bufferOut->clear();
272
273 for (size_t indexIdx = 0; indexIdx < indexCount; ++indexIdx)
274 {
275 GLuint value = static_cast<GLuint>(srcPtr[indexIdx]);
276
277 if (value == restartIndex)
278 {
279 bufferOut->push_back(d3dRestartIndex);
280 vertexA.reset();
281 vertexB.reset();
282 }
283 else
284 {
285 if (!vertexA.valid())
286 {
287 vertexA = value;
288 }
289 else if (!vertexB.valid())
290 {
291 vertexB = value;
292 }
293 else
294 {
295 bufferOut->push_back(vertexA.value());
296 bufferOut->push_back(vertexB.value());
297 bufferOut->push_back(value);
298 vertexB = value;
299 }
300 }
301 }
302 }
303
GetTriFanIndices(const void * indices,GLenum indexType,GLuint count,bool usePrimitiveRestartFixedIndex,std::vector<GLuint> * bufferOut)304 void GetTriFanIndices(const void *indices,
305 GLenum indexType,
306 GLuint count,
307 bool usePrimitiveRestartFixedIndex,
308 std::vector<GLuint> *bufferOut)
309 {
310 if (indexType != GL_NONE && usePrimitiveRestartFixedIndex)
311 {
312 switch (indexType)
313 {
314 case GL_UNSIGNED_BYTE:
315 CopyTriangleFanIndicesWithRestart<GLubyte>(indices, count, indexType, bufferOut);
316 break;
317 case GL_UNSIGNED_SHORT:
318 CopyTriangleFanIndicesWithRestart<GLushort>(indices, count, indexType, bufferOut);
319 break;
320 case GL_UNSIGNED_INT:
321 CopyTriangleFanIndicesWithRestart<GLuint>(indices, count, indexType, bufferOut);
322 break;
323 default:
324 UNREACHABLE();
325 break;
326 }
327 return;
328 }
329
330 // For non-primitive-restart draws, the index count is static.
331 GLuint numTris = count - 2;
332 bufferOut->resize(numTris * 3);
333
334 switch (indexType)
335 {
336 // Non-indexed draw
337 case GL_NONE:
338 SetTriangleFanIndices(&(*bufferOut)[0], numTris);
339 break;
340 case GL_UNSIGNED_BYTE:
341 CopyTriangleFanIndices<GLubyte>(indices, &(*bufferOut)[0], numTris);
342 break;
343 case GL_UNSIGNED_SHORT:
344 CopyTriangleFanIndices<GLushort>(indices, &(*bufferOut)[0], numTris);
345 break;
346 case GL_UNSIGNED_INT:
347 CopyTriangleFanIndices<GLuint>(indices, &(*bufferOut)[0], numTris);
348 break;
349 default:
350 UNREACHABLE();
351 break;
352 }
353 }
354
DrawCallNeedsTranslation(const gl::Context * context,GLenum mode)355 bool DrawCallNeedsTranslation(const gl::Context *context, GLenum mode)
356 {
357 const auto &glState = context->getGLState();
358 const gl::VertexArray *vertexArray = glState.getVertexArray();
359 VertexArray11 *vertexArray11 = GetImplAs<VertexArray11>(vertexArray);
360 // Direct drawing doesn't support dynamic attribute storage since it needs the first and count
361 // to translate when applyVertexBuffer. GL_LINE_LOOP and GL_TRIANGLE_FAN are not supported
362 // either since we need to simulate them in D3D.
363 if (vertexArray11->hasActiveDynamicAttrib(context) || mode == GL_LINE_LOOP ||
364 mode == GL_TRIANGLE_FAN)
365 {
366 return true;
367 }
368
369 ProgramD3D *programD3D = GetImplAs<ProgramD3D>(glState.getProgram());
370 if (InstancedPointSpritesActive(programD3D, mode))
371 {
372 return true;
373 }
374
375 return false;
376 }
377
IsArrayRTV(ID3D11RenderTargetView * rtv)378 bool IsArrayRTV(ID3D11RenderTargetView *rtv)
379 {
380 D3D11_RENDER_TARGET_VIEW_DESC desc;
381 rtv->GetDesc(&desc);
382 if (desc.ViewDimension == D3D11_RTV_DIMENSION_TEXTURE1DARRAY &&
383 desc.Texture1DArray.ArraySize > 1)
384 return true;
385 if (desc.ViewDimension == D3D11_RTV_DIMENSION_TEXTURE2DARRAY &&
386 desc.Texture2DArray.ArraySize > 1)
387 return true;
388 if (desc.ViewDimension == D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY &&
389 desc.Texture2DMSArray.ArraySize > 1)
390 return true;
391 return false;
392 }
393
GetAdjustedInstanceCount(const gl::Program * program,int instanceCount)394 int GetAdjustedInstanceCount(const gl::Program *program, int instanceCount)
395 {
396 if (!program->usesMultiview())
397 {
398 return instanceCount;
399 }
400 if (instanceCount == 0)
401 {
402 return program->getNumViews();
403 }
404 return program->getNumViews() * instanceCount;
405 }
406
407 const uint32_t ScratchMemoryBufferLifetime = 1000;
408
PopulateFormatDeviceCaps(ID3D11Device * device,DXGI_FORMAT format,UINT * outSupport,UINT * outMaxSamples)409 void PopulateFormatDeviceCaps(ID3D11Device *device,
410 DXGI_FORMAT format,
411 UINT *outSupport,
412 UINT *outMaxSamples)
413 {
414 if (FAILED(device->CheckFormatSupport(format, outSupport)))
415 {
416 *outSupport = 0;
417 }
418
419 *outMaxSamples = 0;
420 for (UINT sampleCount = 2; sampleCount <= D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; sampleCount *= 2)
421 {
422 UINT qualityCount = 0;
423 if (FAILED(device->CheckMultisampleQualityLevels(format, sampleCount, &qualityCount)) ||
424 qualityCount == 0)
425 {
426 break;
427 }
428
429 *outMaxSamples = sampleCount;
430 }
431 }
432
CullsEverything(const gl::State & glState)433 bool CullsEverything(const gl::State &glState)
434 {
435 return (glState.getRasterizerState().cullFace &&
436 glState.getRasterizerState().cullMode == gl::CullFaceMode::FrontAndBack);
437 }
438
439 } // anonymous namespace
440
441 Renderer11DeviceCaps::Renderer11DeviceCaps() = default;
442
Renderer11(egl::Display * display)443 Renderer11::Renderer11(egl::Display *display)
444 : RendererD3D(display),
445 mCreateDebugDevice(false),
446 mStateCache(),
447 mStateManager(this),
448 mLastHistogramUpdateTime(
449 ANGLEPlatformCurrent()->monotonicallyIncreasingTime(ANGLEPlatformCurrent())),
450 mDebug(nullptr),
451 mScratchMemoryBuffer(ScratchMemoryBufferLifetime),
452 mAnnotator(nullptr)
453 {
454 mLineLoopIB = nullptr;
455 mTriangleFanIB = nullptr;
456
457 mBlit = nullptr;
458 mPixelTransfer = nullptr;
459
460 mClear = nullptr;
461
462 mTrim = nullptr;
463
464 mRenderer11DeviceCaps.supportsClearView = false;
465 mRenderer11DeviceCaps.supportsConstantBufferOffsets = false;
466 mRenderer11DeviceCaps.supportsVpRtIndexWriteFromVertexShader = false;
467 mRenderer11DeviceCaps.supportsDXGI1_2 = false;
468 mRenderer11DeviceCaps.B5G6R5support = 0;
469 mRenderer11DeviceCaps.B4G4R4A4support = 0;
470 mRenderer11DeviceCaps.B5G5R5A1support = 0;
471
472 mD3d11Module = nullptr;
473 mDxgiModule = nullptr;
474 mDCompModule = nullptr;
475 mCreatedWithDeviceEXT = false;
476
477 mDevice = nullptr;
478 mDeviceContext = nullptr;
479 mDeviceContext1 = nullptr;
480 mDeviceContext3 = nullptr;
481 mDxgiAdapter = nullptr;
482 mDxgiFactory = nullptr;
483
484 ZeroMemory(&mAdapterDescription, sizeof(mAdapterDescription));
485
486 const auto &attributes = mDisplay->getAttributeMap();
487
488 if (mDisplay->getPlatform() == EGL_PLATFORM_ANGLE_ANGLE)
489 {
490 EGLint requestedMajorVersion = static_cast<EGLint>(
491 attributes.get(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, EGL_DONT_CARE));
492 EGLint requestedMinorVersion = static_cast<EGLint>(
493 attributes.get(EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, EGL_DONT_CARE));
494
495 if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 11)
496 {
497 if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 1)
498 {
499 // This could potentially lead to failed context creation if done on a system
500 // without the platform update which installs DXGI 1.2. Currently, for Chrome users
501 // D3D11 contexts are only created if the platform update is available, so this
502 // should not cause any issues.
503 mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_11_1);
504 }
505 if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 0)
506 {
507 mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_11_0);
508 }
509 }
510
511 if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 10)
512 {
513 if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 1)
514 {
515 mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_10_1);
516 }
517 if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 0)
518 {
519 mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_10_0);
520 }
521 }
522
523 if (requestedMajorVersion == 9 && requestedMinorVersion == 3)
524 {
525 mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_9_3);
526 }
527
528 EGLint requestedDeviceType = static_cast<EGLint>(attributes.get(
529 EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE));
530 switch (requestedDeviceType)
531 {
532 case EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE:
533 mRequestedDriverType = D3D_DRIVER_TYPE_HARDWARE;
534 break;
535
536 case EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_WARP_ANGLE:
537 mRequestedDriverType = D3D_DRIVER_TYPE_WARP;
538 break;
539
540 case EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_REFERENCE_ANGLE:
541 mRequestedDriverType = D3D_DRIVER_TYPE_REFERENCE;
542 break;
543
544 case EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE:
545 mRequestedDriverType = D3D_DRIVER_TYPE_NULL;
546 break;
547
548 default:
549 UNREACHABLE();
550 }
551
552 mCreateDebugDevice = ShouldUseDebugLayers(attributes);
553 }
554 else if (mDisplay->getPlatform() == EGL_PLATFORM_DEVICE_EXT)
555 {
556 ASSERT(mDisplay->getDevice() != nullptr);
557 mCreatedWithDeviceEXT = true;
558
559 // Also set EGL_PLATFORM_ANGLE_ANGLE variables, in case they're used elsewhere in ANGLE
560 // mAvailableFeatureLevels defaults to empty
561 mRequestedDriverType = D3D_DRIVER_TYPE_UNKNOWN;
562 }
563
564 const EGLenum presentPath = static_cast<EGLenum>(attributes.get(
565 EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE, EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE));
566 mPresentPathFastEnabled = (presentPath == EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE);
567
568 // The D3D11 renderer must choose the D3D9 debug annotator because the D3D11 interface
569 // method ID3DUserDefinedAnnotation::GetStatus on desktop builds doesn't work with the Graphics
570 // Diagnostics tools in Visual Studio 2013.
571 // The D3D9 annotator works properly for both D3D11 and D3D9.
572 // Incorrect status reporting can cause ANGLE to log unnecessary debug events.
573 #ifdef ANGLE_ENABLE_D3D9
574 mAnnotator = new DebugAnnotator9();
575 #else
576 mAnnotator = new DebugAnnotator11();
577 #endif
578 ASSERT(mAnnotator);
579 gl::InitializeDebugAnnotations(mAnnotator);
580 }
581
~Renderer11()582 Renderer11::~Renderer11()
583 {
584 release();
585 }
586
587 #ifndef __d3d11_1_h__
588 #define D3D11_MESSAGE_ID_DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET ((D3D11_MESSAGE_ID)3146081)
589 #endif
590
initialize()591 egl::Error Renderer11::initialize()
592 {
593 HRESULT result = S_OK;
594
595 ANGLE_TRY(initializeD3DDevice());
596
597 #if !defined(ANGLE_ENABLE_WINDOWS_STORE)
598 #if !ANGLE_SKIP_DXGI_1_2_CHECK
599 {
600 TRACE_EVENT0("gpu.angle", "Renderer11::initialize (DXGICheck)");
601 // In order to create a swap chain for an HWND owned by another process, DXGI 1.2 is
602 // required.
603 // The easiest way to check is to query for a IDXGIDevice2.
604 bool requireDXGI1_2 = false;
605 HWND hwnd = WindowFromDC(mDisplay->getNativeDisplayId());
606 if (hwnd)
607 {
608 DWORD currentProcessId = GetCurrentProcessId();
609 DWORD wndProcessId;
610 GetWindowThreadProcessId(hwnd, &wndProcessId);
611 requireDXGI1_2 = (currentProcessId != wndProcessId);
612 }
613 else
614 {
615 requireDXGI1_2 = true;
616 }
617
618 if (requireDXGI1_2)
619 {
620 IDXGIDevice2 *dxgiDevice2 = nullptr;
621 result = mDevice->QueryInterface(__uuidof(IDXGIDevice2), (void **)&dxgiDevice2);
622 if (FAILED(result))
623 {
624 return egl::EglNotInitialized(D3D11_INIT_INCOMPATIBLE_DXGI)
625 << "DXGI 1.2 required to present to HWNDs owned by another process.";
626 }
627 SafeRelease(dxgiDevice2);
628 }
629 }
630 #endif
631 #endif
632
633 {
634 TRACE_EVENT0("gpu.angle", "Renderer11::initialize (ComQueries)");
635 // Cast the DeviceContext to a DeviceContext1 and DeviceContext3.
636 // This could fail on Windows 7 without the Platform Update.
637 // Don't error in this case- just don't use mDeviceContext1 or mDeviceContext3.
638 mDeviceContext1 = d3d11::DynamicCastComObject<ID3D11DeviceContext1>(mDeviceContext);
639 mDeviceContext3 = d3d11::DynamicCastComObject<ID3D11DeviceContext3>(mDeviceContext);
640
641 IDXGIDevice *dxgiDevice = nullptr;
642 result = mDevice->QueryInterface(__uuidof(IDXGIDevice), (void **)&dxgiDevice);
643
644 if (FAILED(result))
645 {
646 return egl::EglNotInitialized(D3D11_INIT_OTHER_ERROR) << "Could not query DXGI device.";
647 }
648
649 result = dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void **)&mDxgiAdapter);
650
651 if (FAILED(result))
652 {
653 return egl::EglNotInitialized(D3D11_INIT_OTHER_ERROR)
654 << "Could not retrieve DXGI adapter";
655 }
656
657 SafeRelease(dxgiDevice);
658
659 IDXGIAdapter2 *dxgiAdapter2 = d3d11::DynamicCastComObject<IDXGIAdapter2>(mDxgiAdapter);
660
661 // On D3D_FEATURE_LEVEL_9_*, IDXGIAdapter::GetDesc returns "Software Adapter" for the
662 // description string.
663 // If DXGI1.2 is available then IDXGIAdapter2::GetDesc2 can be used to get the actual
664 // hardware values.
665 if (mRenderer11DeviceCaps.featureLevel <= D3D_FEATURE_LEVEL_9_3 && dxgiAdapter2 != nullptr)
666 {
667 DXGI_ADAPTER_DESC2 adapterDesc2 = {};
668 result = dxgiAdapter2->GetDesc2(&adapterDesc2);
669 if (SUCCEEDED(result))
670 {
671 // Copy the contents of the DXGI_ADAPTER_DESC2 into mAdapterDescription (a
672 // DXGI_ADAPTER_DESC).
673 memcpy(mAdapterDescription.Description, adapterDesc2.Description,
674 sizeof(mAdapterDescription.Description));
675 mAdapterDescription.VendorId = adapterDesc2.VendorId;
676 mAdapterDescription.DeviceId = adapterDesc2.DeviceId;
677 mAdapterDescription.SubSysId = adapterDesc2.SubSysId;
678 mAdapterDescription.Revision = adapterDesc2.Revision;
679 mAdapterDescription.DedicatedVideoMemory = adapterDesc2.DedicatedVideoMemory;
680 mAdapterDescription.DedicatedSystemMemory = adapterDesc2.DedicatedSystemMemory;
681 mAdapterDescription.SharedSystemMemory = adapterDesc2.SharedSystemMemory;
682 mAdapterDescription.AdapterLuid = adapterDesc2.AdapterLuid;
683 }
684 }
685 else
686 {
687 result = mDxgiAdapter->GetDesc(&mAdapterDescription);
688 }
689
690 SafeRelease(dxgiAdapter2);
691
692 if (FAILED(result))
693 {
694 return egl::EglNotInitialized(D3D11_INIT_OTHER_ERROR)
695 << "Could not read DXGI adaptor description.";
696 }
697
698 memset(mDescription, 0, sizeof(mDescription));
699 wcstombs(mDescription, mAdapterDescription.Description, sizeof(mDescription) - 1);
700
701 result = mDxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void **)&mDxgiFactory);
702
703 if (!mDxgiFactory || FAILED(result))
704 {
705 return egl::EglNotInitialized(D3D11_INIT_OTHER_ERROR)
706 << "Could not create DXGI factory.";
707 }
708 }
709
710 // Disable some spurious D3D11 debug warnings to prevent them from flooding the output log
711 if (mCreateDebugDevice)
712 {
713 TRACE_EVENT0("gpu.angle", "Renderer11::initialize (HideWarnings)");
714 ID3D11InfoQueue *infoQueue;
715 result = mDevice->QueryInterface(__uuidof(ID3D11InfoQueue), (void **)&infoQueue);
716
717 if (SUCCEEDED(result))
718 {
719 D3D11_MESSAGE_ID hideMessages[] = {
720 D3D11_MESSAGE_ID_DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET};
721
722 D3D11_INFO_QUEUE_FILTER filter = {};
723 filter.DenyList.NumIDs = static_cast<unsigned int>(ArraySize(hideMessages));
724 filter.DenyList.pIDList = hideMessages;
725
726 infoQueue->AddStorageFilterEntries(&filter);
727 SafeRelease(infoQueue);
728 }
729 }
730
731 #if !defined(NDEBUG)
732 mDebug = d3d11::DynamicCastComObject<ID3D11Debug>(mDevice);
733 #endif
734
735 ANGLE_TRY(initializeDevice());
736
737 return egl::NoError();
738 }
739
callD3D11CreateDevice(PFN_D3D11_CREATE_DEVICE createDevice,bool debug)740 HRESULT Renderer11::callD3D11CreateDevice(PFN_D3D11_CREATE_DEVICE createDevice, bool debug)
741 {
742 return createDevice(
743 nullptr, mRequestedDriverType, nullptr, debug ? D3D11_CREATE_DEVICE_DEBUG : 0,
744 mAvailableFeatureLevels.data(), static_cast<unsigned int>(mAvailableFeatureLevels.size()),
745 D3D11_SDK_VERSION, &mDevice, &(mRenderer11DeviceCaps.featureLevel), &mDeviceContext);
746 }
747
initializeD3DDevice()748 egl::Error Renderer11::initializeD3DDevice()
749 {
750 HRESULT result = S_OK;
751
752 if (!mCreatedWithDeviceEXT)
753 {
754 #if !defined(ANGLE_ENABLE_WINDOWS_STORE)
755 PFN_D3D11_CREATE_DEVICE D3D11CreateDevice = nullptr;
756 {
757 SCOPED_ANGLE_HISTOGRAM_TIMER("GPU.ANGLE.Renderer11InitializeDLLsMS");
758 TRACE_EVENT0("gpu.angle", "Renderer11::initialize (Load DLLs)");
759 mDxgiModule = LoadLibrary(TEXT("dxgi.dll"));
760 mD3d11Module = LoadLibrary(TEXT("d3d11.dll"));
761 mDCompModule = LoadLibrary(TEXT("dcomp.dll"));
762
763 if (mD3d11Module == nullptr || mDxgiModule == nullptr)
764 {
765 return egl::EglNotInitialized(D3D11_INIT_MISSING_DEP)
766 << "Could not load D3D11 or DXGI library.";
767 }
768
769 // create the D3D11 device
770 ASSERT(mDevice == nullptr);
771 D3D11CreateDevice = reinterpret_cast<PFN_D3D11_CREATE_DEVICE>(
772 GetProcAddress(mD3d11Module, "D3D11CreateDevice"));
773
774 if (D3D11CreateDevice == nullptr)
775 {
776 return egl::EglNotInitialized(D3D11_INIT_MISSING_DEP)
777 << "Could not retrieve D3D11CreateDevice address.";
778 }
779 }
780 #endif
781
782 if (mCreateDebugDevice)
783 {
784 TRACE_EVENT0("gpu.angle", "D3D11CreateDevice (Debug)");
785 result = callD3D11CreateDevice(D3D11CreateDevice, true);
786
787 if (result == E_INVALIDARG && mAvailableFeatureLevels.size() > 1u &&
788 mAvailableFeatureLevels[0] == D3D_FEATURE_LEVEL_11_1)
789 {
790 // On older Windows platforms, D3D11.1 is not supported which returns E_INVALIDARG.
791 // Try again without passing D3D_FEATURE_LEVEL_11_1 in case we have other feature
792 // levels to fall back on.
793 mAvailableFeatureLevels.erase(mAvailableFeatureLevels.begin());
794 result = callD3D11CreateDevice(D3D11CreateDevice, true);
795 }
796
797 if (!mDevice || FAILED(result))
798 {
799 WARN() << "Failed creating Debug D3D11 device - falling back to release runtime.";
800 }
801 }
802
803 if (!mDevice || FAILED(result))
804 {
805 SCOPED_ANGLE_HISTOGRAM_TIMER("GPU.ANGLE.D3D11CreateDeviceMS");
806 TRACE_EVENT0("gpu.angle", "D3D11CreateDevice");
807
808 result = callD3D11CreateDevice(D3D11CreateDevice, false);
809
810 if (result == E_INVALIDARG && mAvailableFeatureLevels.size() > 1u &&
811 mAvailableFeatureLevels[0] == D3D_FEATURE_LEVEL_11_1)
812 {
813 // On older Windows platforms, D3D11.1 is not supported which returns E_INVALIDARG.
814 // Try again without passing D3D_FEATURE_LEVEL_11_1 in case we have other feature
815 // levels to fall back on.
816 mAvailableFeatureLevels.erase(mAvailableFeatureLevels.begin());
817 result = callD3D11CreateDevice(D3D11CreateDevice, false);
818 }
819
820 // Cleanup done by destructor
821 if (!mDevice || FAILED(result))
822 {
823 ANGLE_HISTOGRAM_SPARSE_SLOWLY("GPU.ANGLE.D3D11CreateDeviceError",
824 static_cast<int>(result));
825 return egl::EglNotInitialized(D3D11_INIT_CREATEDEVICE_ERROR)
826 << "Could not create D3D11 device.";
827 }
828 }
829 }
830 else
831 {
832 DeviceD3D *deviceD3D = GetImplAs<DeviceD3D>(mDisplay->getDevice());
833 ASSERT(deviceD3D != nullptr);
834
835 // We should use the inputted D3D11 device instead
836 void *device = nullptr;
837 ANGLE_TRY(deviceD3D->getDevice(&device));
838
839 ID3D11Device *d3dDevice = reinterpret_cast<ID3D11Device *>(device);
840 if (FAILED(d3dDevice->GetDeviceRemovedReason()))
841 {
842 return egl::EglNotInitialized() << "Inputted D3D11 device has been lost.";
843 }
844
845 if (d3dDevice->GetFeatureLevel() < D3D_FEATURE_LEVEL_9_3)
846 {
847 return egl::EglNotInitialized()
848 << "Inputted D3D11 device must be Feature Level 9_3 or greater.";
849 }
850
851 // The Renderer11 adds a ref to the inputted D3D11 device, like D3D11CreateDevice does.
852 mDevice = d3dDevice;
853 mDevice->AddRef();
854 mDevice->GetImmediateContext(&mDeviceContext);
855 mRenderer11DeviceCaps.featureLevel = mDevice->GetFeatureLevel();
856 }
857
858 mResourceManager11.setAllocationsInitialized(mCreateDebugDevice);
859
860 d3d11::SetDebugName(mDeviceContext, "DeviceContext");
861
862 return egl::NoError();
863 }
864
865 // do any one-time device initialization
866 // NOTE: this is also needed after a device lost/reset
867 // to reset the scene status and ensure the default states are reset.
initializeDevice()868 egl::Error Renderer11::initializeDevice()
869 {
870 SCOPED_ANGLE_HISTOGRAM_TIMER("GPU.ANGLE.Renderer11InitializeDeviceMS");
871 TRACE_EVENT0("gpu.angle", "Renderer11::initializeDevice");
872
873 populateRenderer11DeviceCaps();
874
875 mStateCache.clear();
876
877 ASSERT(!mBlit);
878 mBlit = new Blit11(this);
879
880 ASSERT(!mClear);
881 mClear = new Clear11(this);
882
883 const auto &attributes = mDisplay->getAttributeMap();
884 // If automatic trim is enabled, DXGIDevice3::Trim( ) is called for the application
885 // automatically when an application is suspended by the OS. This feature is currently
886 // only supported for Windows Store applications.
887 EGLint enableAutoTrim = static_cast<EGLint>(
888 attributes.get(EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_FALSE));
889
890 if (enableAutoTrim == EGL_TRUE)
891 {
892 ASSERT(!mTrim);
893 mTrim = new Trim11(this);
894 }
895
896 ASSERT(!mPixelTransfer);
897 mPixelTransfer = new PixelTransfer11(this);
898
899 const gl::Caps &rendererCaps = getNativeCaps();
900
901 if (mStateManager.initialize(rendererCaps, getNativeExtensions()).isError())
902 {
903 return egl::EglBadAlloc() << "Error initializing state manager.";
904 }
905
906 // Gather stats on DXGI and D3D feature level
907 ANGLE_HISTOGRAM_BOOLEAN("GPU.ANGLE.SupportsDXGI1_2", mRenderer11DeviceCaps.supportsDXGI1_2);
908
909 ANGLEFeatureLevel angleFeatureLevel = GetANGLEFeatureLevel(mRenderer11DeviceCaps.featureLevel);
910
911 // We don't actually request a 11_1 device, because of complications with the platform
912 // update. Instead we check if the mDeviceContext1 pointer cast succeeded.
913 // Note: we should support D3D11_0 always, but we aren't guaranteed to be at FL11_0
914 // because the app can specify a lower version (such as 9_3) on Display creation.
915 if (mDeviceContext1 != nullptr)
916 {
917 angleFeatureLevel = ANGLE_FEATURE_LEVEL_11_1;
918 }
919
920 ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.D3D11FeatureLevel", angleFeatureLevel,
921 NUM_ANGLE_FEATURE_LEVELS);
922
923 return egl::NoError();
924 }
925
populateRenderer11DeviceCaps()926 void Renderer11::populateRenderer11DeviceCaps()
927 {
928 HRESULT hr = S_OK;
929
930 LARGE_INTEGER version;
931 hr = mDxgiAdapter->CheckInterfaceSupport(__uuidof(IDXGIDevice), &version);
932 if (FAILED(hr))
933 {
934 mRenderer11DeviceCaps.driverVersion.reset();
935 ERR() << "Error querying driver version from DXGI Adapter.";
936 }
937 else
938 {
939 mRenderer11DeviceCaps.driverVersion = version;
940 }
941
942 if (mDeviceContext1)
943 {
944 D3D11_FEATURE_DATA_D3D11_OPTIONS d3d11Options;
945 HRESULT result = mDevice->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &d3d11Options,
946 sizeof(D3D11_FEATURE_DATA_D3D11_OPTIONS));
947 if (SUCCEEDED(result))
948 {
949 mRenderer11DeviceCaps.supportsClearView = (d3d11Options.ClearView != FALSE);
950 mRenderer11DeviceCaps.supportsConstantBufferOffsets =
951 (d3d11Options.ConstantBufferOffsetting != FALSE);
952 }
953 }
954
955 if (mDeviceContext3)
956 {
957 D3D11_FEATURE_DATA_D3D11_OPTIONS3 d3d11Options3;
958 HRESULT result = mDevice->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS3, &d3d11Options3,
959 sizeof(D3D11_FEATURE_DATA_D3D11_OPTIONS3));
960 if (SUCCEEDED(result))
961 {
962 mRenderer11DeviceCaps.supportsVpRtIndexWriteFromVertexShader =
963 (d3d11Options3.VPAndRTArrayIndexFromAnyShaderFeedingRasterizer == TRUE);
964 }
965 }
966
967 mRenderer11DeviceCaps.supportsMultisampledDepthStencilSRVs =
968 mRenderer11DeviceCaps.featureLevel > D3D_FEATURE_LEVEL_10_0;
969
970 if (getWorkarounds().disableB5G6R5Support)
971 {
972 mRenderer11DeviceCaps.B5G6R5support = 0;
973 mRenderer11DeviceCaps.B5G6R5maxSamples = 0;
974 }
975 else
976 {
977 PopulateFormatDeviceCaps(mDevice, DXGI_FORMAT_B5G6R5_UNORM,
978 &mRenderer11DeviceCaps.B5G6R5support,
979 &mRenderer11DeviceCaps.B5G6R5maxSamples);
980 }
981
982 PopulateFormatDeviceCaps(mDevice, DXGI_FORMAT_B4G4R4A4_UNORM,
983 &mRenderer11DeviceCaps.B4G4R4A4support,
984 &mRenderer11DeviceCaps.B4G4R4A4maxSamples);
985 PopulateFormatDeviceCaps(mDevice, DXGI_FORMAT_B5G5R5A1_UNORM,
986 &mRenderer11DeviceCaps.B5G5R5A1support,
987 &mRenderer11DeviceCaps.B5G5R5A1maxSamples);
988
989 IDXGIAdapter2 *dxgiAdapter2 = d3d11::DynamicCastComObject<IDXGIAdapter2>(mDxgiAdapter);
990 mRenderer11DeviceCaps.supportsDXGI1_2 = (dxgiAdapter2 != nullptr);
991 SafeRelease(dxgiAdapter2);
992 }
993
generateSampleSetForEGLConfig(const gl::TextureCaps & colorBufferFormatCaps,const gl::TextureCaps & depthStencilBufferFormatCaps) const994 gl::SupportedSampleSet Renderer11::generateSampleSetForEGLConfig(
995 const gl::TextureCaps &colorBufferFormatCaps,
996 const gl::TextureCaps &depthStencilBufferFormatCaps) const
997 {
998 gl::SupportedSampleSet sampleCounts;
999
1000 // Generate a new set from the set intersection of sample counts between the color and depth
1001 // format caps.
1002 std::set_intersection(colorBufferFormatCaps.sampleCounts.begin(),
1003 colorBufferFormatCaps.sampleCounts.end(),
1004 depthStencilBufferFormatCaps.sampleCounts.begin(),
1005 depthStencilBufferFormatCaps.sampleCounts.end(),
1006 std::inserter(sampleCounts, sampleCounts.begin()));
1007
1008 // Format of GL_NONE results in no supported sample counts.
1009 // Add back the color sample counts to the supported sample set.
1010 if (depthStencilBufferFormatCaps.sampleCounts.empty())
1011 {
1012 sampleCounts = colorBufferFormatCaps.sampleCounts;
1013 }
1014 else if (colorBufferFormatCaps.sampleCounts.empty())
1015 {
1016 // Likewise, add back the depth sample counts to the supported sample set.
1017 sampleCounts = depthStencilBufferFormatCaps.sampleCounts;
1018 }
1019
1020 // Always support 0 samples
1021 sampleCounts.insert(0);
1022
1023 return sampleCounts;
1024 }
1025
generateConfigs()1026 egl::ConfigSet Renderer11::generateConfigs()
1027 {
1028 std::vector<GLenum> colorBufferFormats;
1029
1030 // 32-bit supported formats
1031 colorBufferFormats.push_back(GL_BGRA8_EXT);
1032 colorBufferFormats.push_back(GL_RGBA8_OES);
1033
1034 // 24-bit supported formats
1035 colorBufferFormats.push_back(GL_RGB8_OES);
1036
1037 if (mRenderer11DeviceCaps.featureLevel >= D3D_FEATURE_LEVEL_10_0)
1038 {
1039 // Additional high bit depth formats added in D3D 10.0
1040 // https://msdn.microsoft.com/en-us/library/windows/desktop/bb173064.aspx
1041 colorBufferFormats.push_back(GL_RGBA16F);
1042 colorBufferFormats.push_back(GL_RGB10_A2);
1043 }
1044
1045 if (!mPresentPathFastEnabled)
1046 {
1047 // 16-bit supported formats
1048 // These aren't valid D3D11 swapchain formats, so don't expose them as configs
1049 // if present path fast is active
1050 colorBufferFormats.push_back(GL_RGBA4);
1051 colorBufferFormats.push_back(GL_RGB5_A1);
1052 colorBufferFormats.push_back(GL_RGB565);
1053 }
1054
1055 static const GLenum depthStencilBufferFormats[] = {
1056 GL_NONE, GL_DEPTH24_STENCIL8_OES, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT16,
1057 GL_STENCIL_INDEX8,
1058 };
1059
1060 const gl::Caps &rendererCaps = getNativeCaps();
1061 const gl::TextureCapsMap &rendererTextureCaps = getNativeTextureCaps();
1062
1063 const EGLint optimalSurfaceOrientation =
1064 mPresentPathFastEnabled ? 0 : EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE;
1065
1066 egl::ConfigSet configs;
1067 for (GLenum colorBufferInternalFormat : colorBufferFormats)
1068 {
1069 const gl::TextureCaps &colorBufferFormatCaps =
1070 rendererTextureCaps.get(colorBufferInternalFormat);
1071 if (!colorBufferFormatCaps.renderable)
1072 {
1073 continue;
1074 }
1075
1076 for (GLenum depthStencilBufferInternalFormat : depthStencilBufferFormats)
1077 {
1078 const gl::TextureCaps &depthStencilBufferFormatCaps =
1079 rendererTextureCaps.get(depthStencilBufferInternalFormat);
1080 if (!depthStencilBufferFormatCaps.renderable &&
1081 depthStencilBufferInternalFormat != GL_NONE)
1082 {
1083 continue;
1084 }
1085
1086 const gl::InternalFormat &colorBufferFormatInfo =
1087 gl::GetSizedInternalFormatInfo(colorBufferInternalFormat);
1088 const gl::InternalFormat &depthStencilBufferFormatInfo =
1089 gl::GetSizedInternalFormatInfo(depthStencilBufferInternalFormat);
1090 const gl::Version &maxVersion = getMaxSupportedESVersion();
1091
1092 const gl::SupportedSampleSet sampleCounts =
1093 generateSampleSetForEGLConfig(colorBufferFormatCaps, depthStencilBufferFormatCaps);
1094
1095 for (GLuint sampleCount : sampleCounts)
1096 {
1097 egl::Config config;
1098 config.renderTargetFormat = colorBufferInternalFormat;
1099 config.depthStencilFormat = depthStencilBufferInternalFormat;
1100 config.bufferSize = colorBufferFormatInfo.pixelBytes * 8;
1101 config.redSize = colorBufferFormatInfo.redBits;
1102 config.greenSize = colorBufferFormatInfo.greenBits;
1103 config.blueSize = colorBufferFormatInfo.blueBits;
1104 config.luminanceSize = colorBufferFormatInfo.luminanceBits;
1105 config.alphaSize = colorBufferFormatInfo.alphaBits;
1106 config.alphaMaskSize = 0;
1107 config.bindToTextureRGB =
1108 ((colorBufferFormatInfo.format == GL_RGB) && (sampleCount <= 1));
1109 config.bindToTextureRGBA = (((colorBufferFormatInfo.format == GL_RGBA) ||
1110 (colorBufferFormatInfo.format == GL_BGRA_EXT)) &&
1111 (sampleCount <= 1));
1112 config.colorBufferType = EGL_RGB_BUFFER;
1113 config.configCaveat = EGL_NONE;
1114 config.configID = static_cast<EGLint>(configs.size() + 1);
1115
1116 // PresentPathFast may not be conformant
1117 config.conformant = 0;
1118 if (!mPresentPathFastEnabled)
1119 {
1120 // Can only support a conformant ES2 with feature level greater than 10.0.
1121 if (mRenderer11DeviceCaps.featureLevel >= D3D_FEATURE_LEVEL_10_0)
1122 {
1123 config.conformant |= EGL_OPENGL_ES2_BIT;
1124 }
1125
1126 // We can only support conformant ES3 on FL 10.1+
1127 if (maxVersion.major >= 3)
1128 {
1129 config.conformant |= EGL_OPENGL_ES3_BIT_KHR;
1130 }
1131 }
1132
1133 config.depthSize = depthStencilBufferFormatInfo.depthBits;
1134 config.level = 0;
1135 config.matchNativePixmap = EGL_NONE;
1136 config.maxPBufferWidth = rendererCaps.max2DTextureSize;
1137 config.maxPBufferHeight = rendererCaps.max2DTextureSize;
1138 config.maxPBufferPixels =
1139 rendererCaps.max2DTextureSize * rendererCaps.max2DTextureSize;
1140 config.maxSwapInterval = 4;
1141 config.minSwapInterval = 0;
1142 config.nativeRenderable = EGL_FALSE;
1143 config.nativeVisualID = 0;
1144 config.nativeVisualType = EGL_NONE;
1145
1146 // Can't support ES3 at all without feature level 10.1
1147 config.renderableType = EGL_OPENGL_ES2_BIT;
1148 if (maxVersion.major >= 3)
1149 {
1150 config.renderableType |= EGL_OPENGL_ES3_BIT_KHR;
1151 }
1152
1153 config.sampleBuffers = (sampleCount == 0) ? 0 : 1;
1154 config.samples = sampleCount;
1155 config.stencilSize = depthStencilBufferFormatInfo.stencilBits;
1156 config.surfaceType =
1157 EGL_PBUFFER_BIT | EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
1158 config.transparentType = EGL_NONE;
1159 config.transparentRedValue = 0;
1160 config.transparentGreenValue = 0;
1161 config.transparentBlueValue = 0;
1162 config.optimalOrientation = optimalSurfaceOrientation;
1163 config.colorComponentType = gl_egl::GLComponentTypeToEGLColorComponentType(
1164 colorBufferFormatInfo.componentType);
1165
1166 configs.add(config);
1167 }
1168 }
1169 }
1170
1171 ASSERT(configs.size() > 0);
1172 return configs;
1173 }
1174
generateDisplayExtensions(egl::DisplayExtensions * outExtensions) const1175 void Renderer11::generateDisplayExtensions(egl::DisplayExtensions *outExtensions) const
1176 {
1177 outExtensions->createContextRobustness = true;
1178
1179 if (getShareHandleSupport())
1180 {
1181 outExtensions->d3dShareHandleClientBuffer = true;
1182 outExtensions->surfaceD3DTexture2DShareHandle = true;
1183 }
1184 outExtensions->d3dTextureClientBuffer = true;
1185
1186 outExtensions->keyedMutex = true;
1187 outExtensions->querySurfacePointer = true;
1188 outExtensions->windowFixedSize = true;
1189
1190 // If present path fast is active then the surface orientation extension isn't supported
1191 outExtensions->surfaceOrientation = !mPresentPathFastEnabled;
1192
1193 // D3D11 does not support present with dirty rectangles until DXGI 1.2.
1194 outExtensions->postSubBuffer = mRenderer11DeviceCaps.supportsDXGI1_2;
1195
1196 outExtensions->deviceQuery = true;
1197
1198 outExtensions->image = true;
1199 outExtensions->imageBase = true;
1200 outExtensions->glTexture2DImage = true;
1201 outExtensions->glTextureCubemapImage = true;
1202 outExtensions->glRenderbufferImage = true;
1203
1204 outExtensions->stream = true;
1205 outExtensions->streamConsumerGLTexture = true;
1206 outExtensions->streamConsumerGLTextureYUV = true;
1207 outExtensions->streamProducerD3DTexture = true;
1208
1209 outExtensions->flexibleSurfaceCompatibility = true;
1210 outExtensions->directComposition = !!mDCompModule;
1211
1212 // Contexts are virtualized so textures can be shared globally
1213 outExtensions->displayTextureShareGroup = true;
1214
1215 // getSyncValues requires direct composition.
1216 outExtensions->getSyncValues = outExtensions->directComposition;
1217
1218 // D3D11 can be used without a swap chain
1219 outExtensions->surfacelessContext = true;
1220
1221 // All D3D feature levels support robust resource init
1222 outExtensions->robustResourceInitialization = true;
1223 }
1224
flush()1225 gl::Error Renderer11::flush()
1226 {
1227 mDeviceContext->Flush();
1228 return gl::NoError();
1229 }
1230
finish()1231 gl::Error Renderer11::finish()
1232 {
1233 if (!mSyncQuery.valid())
1234 {
1235 D3D11_QUERY_DESC queryDesc;
1236 queryDesc.Query = D3D11_QUERY_EVENT;
1237 queryDesc.MiscFlags = 0;
1238
1239 ANGLE_TRY(allocateResource(queryDesc, &mSyncQuery));
1240 }
1241
1242 mDeviceContext->End(mSyncQuery.get());
1243
1244 HRESULT result = S_OK;
1245 unsigned int attempt = 0;
1246 do
1247 {
1248 unsigned int flushFrequency = 100;
1249 UINT flags = (attempt % flushFrequency == 0) ? 0 : D3D11_ASYNC_GETDATA_DONOTFLUSH;
1250 attempt++;
1251
1252 result = mDeviceContext->GetData(mSyncQuery.get(), nullptr, 0, flags);
1253 if (FAILED(result))
1254 {
1255 return gl::OutOfMemory() << "Failed to get event query data, " << gl::FmtHR(result);
1256 }
1257
1258 if (result == S_FALSE)
1259 {
1260 // Keep polling, but allow other threads to do something useful first
1261 ScheduleYield();
1262 }
1263
1264 if (testDeviceLost())
1265 {
1266 mDisplay->notifyDeviceLost();
1267 return gl::OutOfMemory() << "Device was lost while waiting for sync.";
1268 }
1269 } while (result == S_FALSE);
1270
1271 return gl::NoError();
1272 }
1273
isValidNativeWindow(EGLNativeWindowType window) const1274 bool Renderer11::isValidNativeWindow(EGLNativeWindowType window) const
1275 {
1276 #ifdef ANGLE_ENABLE_WINDOWS_STORE
1277 return NativeWindow11WinRT::IsValidNativeWindow(window);
1278 #else
1279 return NativeWindow11Win32::IsValidNativeWindow(window);
1280 #endif
1281 }
1282
createNativeWindow(EGLNativeWindowType window,const egl::Config * config,const egl::AttributeMap & attribs) const1283 NativeWindowD3D *Renderer11::createNativeWindow(EGLNativeWindowType window,
1284 const egl::Config *config,
1285 const egl::AttributeMap &attribs) const
1286 {
1287 #ifdef ANGLE_ENABLE_WINDOWS_STORE
1288 UNUSED_VARIABLE(attribs);
1289 return new NativeWindow11WinRT(window, config->alphaSize > 0);
1290 #else
1291 return new NativeWindow11Win32(
1292 window, config->alphaSize > 0,
1293 attribs.get(EGL_DIRECT_COMPOSITION_ANGLE, EGL_FALSE) == EGL_TRUE);
1294 #endif
1295 }
1296
getD3DTextureInfo(const egl::Config * configuration,IUnknown * d3dTexture,EGLint * width,EGLint * height,const angle::Format ** angleFormat) const1297 egl::Error Renderer11::getD3DTextureInfo(const egl::Config *configuration,
1298 IUnknown *d3dTexture,
1299 EGLint *width,
1300 EGLint *height,
1301 const angle::Format **angleFormat) const
1302 {
1303 ID3D11Texture2D *texture = d3d11::DynamicCastComObject<ID3D11Texture2D>(d3dTexture);
1304 if (texture == nullptr)
1305 {
1306 return egl::EglBadParameter() << "client buffer is not a ID3D11Texture2D";
1307 }
1308
1309 ID3D11Device *textureDevice = nullptr;
1310 texture->GetDevice(&textureDevice);
1311 if (textureDevice != mDevice)
1312 {
1313 SafeRelease(texture);
1314 return egl::EglBadParameter() << "Texture's device does not match.";
1315 }
1316 SafeRelease(textureDevice);
1317
1318 D3D11_TEXTURE2D_DESC desc = {0};
1319 texture->GetDesc(&desc);
1320 SafeRelease(texture);
1321
1322 if (width)
1323 {
1324 *width = static_cast<EGLint>(desc.Width);
1325 }
1326 if (height)
1327 {
1328 *height = static_cast<EGLint>(desc.Height);
1329 }
1330 if (static_cast<EGLint>(desc.SampleDesc.Count) != configuration->samples)
1331 {
1332 // Both the texture and EGL config sample count may not be the same when multi-sampling
1333 // is disabled. The EGL sample count can be 0 but a D3D texture is always 1. Therefore,
1334 // we must only check for a invalid match when the EGL config is non-zero or the texture is
1335 // not one.
1336 if (configuration->samples != 0 || desc.SampleDesc.Count != 1)
1337 {
1338 return egl::EglBadParameter() << "Texture's sample count does not match.";
1339 }
1340 }
1341 // From table egl.restrictions in EGL_ANGLE_d3d_texture_client_buffer.
1342 switch (desc.Format)
1343 {
1344 case DXGI_FORMAT_R8G8B8A8_UNORM:
1345 case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
1346 case DXGI_FORMAT_R8G8B8A8_TYPELESS:
1347 case DXGI_FORMAT_B8G8R8A8_UNORM:
1348 case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
1349 case DXGI_FORMAT_B8G8R8A8_TYPELESS:
1350 case DXGI_FORMAT_R16G16B16A16_FLOAT:
1351 case DXGI_FORMAT_R32G32B32A32_FLOAT:
1352 break;
1353
1354 default:
1355 return egl::EglBadParameter()
1356 << "Unknown client buffer texture format: " << desc.Format;
1357 }
1358
1359 if (angleFormat)
1360 {
1361 *angleFormat = &d3d11_angle::GetFormat(desc.Format);
1362 }
1363
1364 return egl::NoError();
1365 }
1366
validateShareHandle(const egl::Config * config,HANDLE shareHandle,const egl::AttributeMap & attribs) const1367 egl::Error Renderer11::validateShareHandle(const egl::Config *config,
1368 HANDLE shareHandle,
1369 const egl::AttributeMap &attribs) const
1370 {
1371 if (shareHandle == nullptr)
1372 {
1373 return egl::EglBadParameter() << "NULL share handle.";
1374 }
1375
1376 ID3D11Resource *tempResource11 = nullptr;
1377 HRESULT result = mDevice->OpenSharedResource(shareHandle, __uuidof(ID3D11Resource),
1378 (void **)&tempResource11);
1379 if (FAILED(result))
1380 {
1381 return egl::EglBadParameter() << "Failed to open share handle, " << gl::FmtHR(result);
1382 }
1383
1384 ID3D11Texture2D *texture2D = d3d11::DynamicCastComObject<ID3D11Texture2D>(tempResource11);
1385 SafeRelease(tempResource11);
1386
1387 if (texture2D == nullptr)
1388 {
1389 return egl::EglBadParameter()
1390 << "Failed to query ID3D11Texture2D object from share handle.";
1391 }
1392
1393 D3D11_TEXTURE2D_DESC desc = {0};
1394 texture2D->GetDesc(&desc);
1395 SafeRelease(texture2D);
1396
1397 EGLint width = attribs.getAsInt(EGL_WIDTH, 0);
1398 EGLint height = attribs.getAsInt(EGL_HEIGHT, 0);
1399 ASSERT(width != 0 && height != 0);
1400
1401 const d3d11::Format &backbufferFormatInfo =
1402 d3d11::Format::Get(config->renderTargetFormat, getRenderer11DeviceCaps());
1403
1404 if (desc.Width != static_cast<UINT>(width) || desc.Height != static_cast<UINT>(height) ||
1405 desc.Format != backbufferFormatInfo.texFormat || desc.MipLevels != 1 || desc.ArraySize != 1)
1406 {
1407 return egl::EglBadParameter() << "Invalid texture parameters in share handle texture.";
1408 }
1409
1410 return egl::NoError();
1411 }
1412
createSwapChain(NativeWindowD3D * nativeWindow,HANDLE shareHandle,IUnknown * d3dTexture,GLenum backBufferFormat,GLenum depthBufferFormat,EGLint orientation,EGLint samples)1413 SwapChainD3D *Renderer11::createSwapChain(NativeWindowD3D *nativeWindow,
1414 HANDLE shareHandle,
1415 IUnknown *d3dTexture,
1416 GLenum backBufferFormat,
1417 GLenum depthBufferFormat,
1418 EGLint orientation,
1419 EGLint samples)
1420 {
1421 return new SwapChain11(this, GetAs<NativeWindow11>(nativeWindow), shareHandle, d3dTexture,
1422 backBufferFormat, depthBufferFormat, orientation, samples);
1423 }
1424
getD3DDevice()1425 void *Renderer11::getD3DDevice()
1426 {
1427 return reinterpret_cast<void *>(mDevice);
1428 }
1429
applyPrimitiveType(const gl::State & glState,GLenum mode,GLsizei count)1430 bool Renderer11::applyPrimitiveType(const gl::State &glState, GLenum mode, GLsizei count)
1431 {
1432 D3D11_PRIMITIVE_TOPOLOGY primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED;
1433
1434 GLsizei minCount = 0;
1435
1436 switch (mode)
1437 {
1438 case GL_POINTS:
1439 {
1440 bool usesPointSize = GetImplAs<ProgramD3D>(glState.getProgram())->usesPointSize();
1441
1442 // ProgramBinary assumes non-point rendering if gl_PointSize isn't written,
1443 // which affects varying interpolation. Since the value of gl_PointSize is
1444 // undefined when not written, just skip drawing to avoid unexpected results.
1445 if (!usesPointSize && !glState.isTransformFeedbackActiveUnpaused())
1446 {
1447 // Notify developers of risking undefined behavior.
1448 WARN() << "Point rendering without writing to gl_PointSize.";
1449 return false;
1450 }
1451
1452 // If instanced pointsprites are enabled and the shader uses gl_PointSize, the topology
1453 // must be D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST.
1454 if (usesPointSize && getWorkarounds().useInstancedPointSpriteEmulation)
1455 {
1456 primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
1457 }
1458 else
1459 {
1460 primitiveTopology = D3D11_PRIMITIVE_TOPOLOGY_POINTLIST;
1461 }
1462 minCount = 1;
1463 break;
1464 }
1465 case GL_LINES:
1466 primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINELIST;
1467 minCount = 2;
1468 break;
1469 case GL_LINE_LOOP:
1470 primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
1471 minCount = 2;
1472 break;
1473 case GL_LINE_STRIP:
1474 primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
1475 minCount = 2;
1476 break;
1477 case GL_TRIANGLES:
1478 primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
1479 minCount = CullsEverything(glState) ? std::numeric_limits<GLsizei>::max() : 3;
1480 break;
1481 case GL_TRIANGLE_STRIP:
1482 primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
1483 minCount = CullsEverything(glState) ? std::numeric_limits<GLsizei>::max() : 3;
1484 break;
1485 // emulate fans via rewriting index buffer
1486 case GL_TRIANGLE_FAN:
1487 primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
1488 minCount = CullsEverything(glState) ? std::numeric_limits<GLsizei>::max() : 3;
1489 break;
1490 default:
1491 UNREACHABLE();
1492 return false;
1493 }
1494
1495 mStateManager.setPrimitiveTopology(primitiveTopology);
1496
1497 return count >= minCount;
1498 }
1499
drawArrays(const gl::Context * context,GLenum mode,GLint startVertex,GLsizei count,GLsizei instances)1500 gl::Error Renderer11::drawArrays(const gl::Context *context,
1501 GLenum mode,
1502 GLint startVertex,
1503 GLsizei count,
1504 GLsizei instances)
1505 {
1506 const auto &glState = context->getGLState();
1507
1508 if (!applyPrimitiveType(glState, mode, count))
1509 {
1510 return gl::NoError();
1511 }
1512
1513 DrawCallVertexParams vertexParams(startVertex, count, instances);
1514 ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, false));
1515
1516 if (glState.isTransformFeedbackActiveUnpaused())
1517 {
1518 ANGLE_TRY(markTransformFeedbackUsage(context));
1519 }
1520
1521 gl::Program *program = glState.getProgram();
1522 ASSERT(program != nullptr);
1523 GLsizei adjustedInstanceCount = GetAdjustedInstanceCount(program, instances);
1524 ProgramD3D *programD3D = GetImplAs<ProgramD3D>(program);
1525
1526 if (programD3D->usesGeometryShader(mode) && glState.isTransformFeedbackActiveUnpaused())
1527 {
1528 // Since we use a geometry if-and-only-if we rewrite vertex streams, transform feedback
1529 // won't get the correct output. To work around this, draw with *only* the stream out
1530 // first (no pixel shader) to feed the stream out buffers and then draw again with the
1531 // geometry shader + pixel shader to rasterize the primitives.
1532 mStateManager.setPixelShader(nullptr);
1533
1534 if (adjustedInstanceCount > 0)
1535 {
1536 mDeviceContext->DrawInstanced(count, adjustedInstanceCount, 0, 0);
1537 }
1538 else
1539 {
1540 mDeviceContext->Draw(count, 0);
1541 }
1542
1543 rx::ShaderExecutableD3D *pixelExe = nullptr;
1544 ANGLE_TRY(programD3D->getPixelExecutableForCachedOutputLayout(&pixelExe, nullptr));
1545
1546 // Skip the draw call if rasterizer discard is enabled (or no fragment shader).
1547 if (!pixelExe || glState.getRasterizerState().rasterizerDiscard)
1548 {
1549 return gl::NoError();
1550 }
1551
1552 mStateManager.setPixelShader(&GetAs<ShaderExecutable11>(pixelExe)->getPixelShader());
1553
1554 // Retrieve the geometry shader.
1555 rx::ShaderExecutableD3D *geometryExe = nullptr;
1556 ANGLE_TRY(programD3D->getGeometryExecutableForPrimitiveType(context, mode, &geometryExe,
1557 nullptr));
1558
1559 mStateManager.setGeometryShader(
1560 &GetAs<ShaderExecutable11>(geometryExe)->getGeometryShader());
1561
1562 if (adjustedInstanceCount > 0)
1563 {
1564 mDeviceContext->DrawInstanced(count, adjustedInstanceCount, 0, 0);
1565 }
1566 else
1567 {
1568 mDeviceContext->Draw(count, 0);
1569 }
1570 return gl::NoError();
1571 }
1572
1573 if (mode == GL_LINE_LOOP)
1574 {
1575 return drawLineLoop(context, count, GL_NONE, nullptr, 0, adjustedInstanceCount);
1576 }
1577
1578 if (mode == GL_TRIANGLE_FAN)
1579 {
1580 return drawTriangleFan(context, count, GL_NONE, nullptr, 0, adjustedInstanceCount);
1581 }
1582
1583 bool useInstancedPointSpriteEmulation =
1584 programD3D->usesPointSize() && getWorkarounds().useInstancedPointSpriteEmulation;
1585
1586 if (mode != GL_POINTS || !useInstancedPointSpriteEmulation)
1587 {
1588 if (adjustedInstanceCount == 0)
1589 {
1590 mDeviceContext->Draw(count, 0);
1591 }
1592 else
1593 {
1594 mDeviceContext->DrawInstanced(count, adjustedInstanceCount, 0, 0);
1595 }
1596 return gl::NoError();
1597 }
1598
1599 // This code should not be reachable by multi-view programs.
1600 ASSERT(program->usesMultiview() == false);
1601
1602 // If the shader is writing to gl_PointSize, then pointsprites are being rendered.
1603 // Emulating instanced point sprites for FL9_3 requires the topology to be
1604 // D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST and DrawIndexedInstanced is called instead.
1605 if (adjustedInstanceCount == 0)
1606 {
1607 mDeviceContext->DrawIndexedInstanced(6, count, 0, 0, 0);
1608 return gl::NoError();
1609 }
1610
1611 // If pointsprite emulation is used with glDrawArraysInstanced then we need to take a less
1612 // efficent code path. Instanced rendering of emulated pointsprites requires a loop to draw each
1613 // batch of points. An offset into the instanced data buffer is calculated and applied on each
1614 // iteration to ensure all instances are rendered correctly. Each instance being rendered
1615 // requires the inputlayout cache to reapply buffers and offsets.
1616 for (GLsizei i = 0; i < instances; i++)
1617 {
1618 ANGLE_TRY(mStateManager.updateVertexOffsetsForPointSpritesEmulation(startVertex, i));
1619 mDeviceContext->DrawIndexedInstanced(6, count, 0, 0, 0);
1620 }
1621
1622 // This required by updateVertexOffsets... above but is outside of the loop for speed.
1623 mStateManager.invalidateVertexBuffer();
1624 return gl::NoError();
1625 }
1626
drawElements(const gl::Context * context,GLenum mode,GLsizei count,GLenum type,const void * indices,GLsizei instances)1627 gl::Error Renderer11::drawElements(const gl::Context *context,
1628 GLenum mode,
1629 GLsizei count,
1630 GLenum type,
1631 const void *indices,
1632 GLsizei instances)
1633 {
1634 const auto &glState = context->getGLState();
1635
1636 if (!applyPrimitiveType(glState, mode, count))
1637 {
1638 return gl::NoError();
1639 }
1640
1641 // Transform feedback is not allowed for DrawElements, this error should have been caught at the
1642 // API validation layer.
1643 ASSERT(!glState.isTransformFeedbackActiveUnpaused());
1644
1645 const auto &lazyIndexRange = context->getParams<gl::HasIndexRange>();
1646
1647 bool usePrimitiveRestartWorkaround =
1648 UsePrimitiveRestartWorkaround(glState.isPrimitiveRestartEnabled(), type);
1649 DrawCallVertexParams vertexParams(!usePrimitiveRestartWorkaround, lazyIndexRange, 0, instances);
1650
1651 ANGLE_TRY(mStateManager.applyIndexBuffer(context, indices, count, type, lazyIndexRange,
1652 usePrimitiveRestartWorkaround));
1653 ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, true));
1654
1655 int startVertex = static_cast<int>(vertexParams.firstVertex());
1656 int baseVertex = -startVertex;
1657
1658 const gl::Program *program = glState.getProgram();
1659 GLsizei adjustedInstanceCount = GetAdjustedInstanceCount(program, instances);
1660
1661 if (mode == GL_LINE_LOOP)
1662 {
1663 return drawLineLoop(context, count, type, indices, baseVertex, adjustedInstanceCount);
1664 }
1665
1666 if (mode == GL_TRIANGLE_FAN)
1667 {
1668 return drawTriangleFan(context, count, type, indices, baseVertex, adjustedInstanceCount);
1669 }
1670
1671 const ProgramD3D *programD3D = GetImplAs<ProgramD3D>(glState.getProgram());
1672
1673 if (mode != GL_POINTS || !programD3D->usesInstancedPointSpriteEmulation())
1674 {
1675 if (adjustedInstanceCount == 0)
1676 {
1677 mDeviceContext->DrawIndexed(count, 0, baseVertex);
1678 }
1679 else
1680 {
1681 mDeviceContext->DrawIndexedInstanced(count, adjustedInstanceCount, 0, baseVertex, 0);
1682 }
1683 return gl::NoError();
1684 }
1685
1686 // This code should not be reachable by multi-view programs.
1687 ASSERT(program->usesMultiview() == false);
1688
1689 // If the shader is writing to gl_PointSize, then pointsprites are being rendered.
1690 // Emulating instanced point sprites for FL9_3 requires the topology to be
1691 // D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST and DrawIndexedInstanced is called instead.
1692 //
1693 // The count parameter passed to drawElements represents the total number of instances to be
1694 // rendered. Each instance is referenced by the bound index buffer from the the caller.
1695 //
1696 // Indexed pointsprite emulation replicates data for duplicate entries found in the index
1697 // buffer. This is not an efficent rendering mechanism and is only used on downlevel renderers
1698 // that do not support geometry shaders.
1699 if (instances == 0)
1700 {
1701 mDeviceContext->DrawIndexedInstanced(6, count, 0, 0, 0);
1702 return gl::NoError();
1703 }
1704
1705 // If pointsprite emulation is used with glDrawElementsInstanced then we need to take a less
1706 // efficent code path. Instanced rendering of emulated pointsprites requires a loop to draw each
1707 // batch of points. An offset into the instanced data buffer is calculated and applied on each
1708 // iteration to ensure all instances are rendered correctly.
1709 GLsizei elementsToRender = vertexParams.vertexCount();
1710
1711 // Each instance being rendered requires the inputlayout cache to reapply buffers and offsets.
1712 for (GLsizei i = 0; i < instances; i++)
1713 {
1714 ANGLE_TRY(mStateManager.updateVertexOffsetsForPointSpritesEmulation(startVertex, i));
1715 mDeviceContext->DrawIndexedInstanced(6, elementsToRender, 0, 0, 0);
1716 }
1717 mStateManager.invalidateVertexBuffer();
1718 return gl::NoError();
1719 }
1720
drawArraysIndirect(const gl::Context * context,GLenum mode,const void * indirect)1721 gl::Error Renderer11::drawArraysIndirect(const gl::Context *context,
1722 GLenum mode,
1723 const void *indirect)
1724 {
1725 const auto &glState = context->getGLState();
1726 ASSERT(!glState.isTransformFeedbackActiveUnpaused());
1727
1728 if (!applyPrimitiveType(glState, mode, std::numeric_limits<int>::max() - 1))
1729 {
1730 return gl::NoError();
1731 }
1732
1733 gl::Buffer *drawIndirectBuffer = glState.getTargetBuffer(gl::BufferBinding::DrawIndirect);
1734 ASSERT(drawIndirectBuffer);
1735 Buffer11 *storage = GetImplAs<Buffer11>(drawIndirectBuffer);
1736 uintptr_t offset = reinterpret_cast<uintptr_t>(indirect);
1737
1738 if (!DrawCallNeedsTranslation(context, mode))
1739 {
1740 DrawCallVertexParams vertexParams(0, 0, 0);
1741 ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, false));
1742 ID3D11Buffer *buffer = nullptr;
1743 ANGLE_TRY_RESULT(storage->getBuffer(context, BUFFER_USAGE_INDIRECT), buffer);
1744 mDeviceContext->DrawInstancedIndirect(buffer, static_cast<unsigned int>(offset));
1745 return gl::NoError();
1746 }
1747
1748 const uint8_t *bufferData = nullptr;
1749 ANGLE_TRY(storage->getData(context, &bufferData));
1750 ASSERT(bufferData);
1751 const gl::DrawArraysIndirectCommand *args =
1752 reinterpret_cast<const gl::DrawArraysIndirectCommand *>(bufferData + offset);
1753 GLuint count = args->count;
1754 GLuint instances = args->instanceCount;
1755 GLuint first = args->first;
1756
1757 DrawCallVertexParams vertexParams(first, count, instances);
1758 ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, false));
1759
1760 if (mode == GL_LINE_LOOP)
1761 {
1762 return drawLineLoop(context, count, GL_NONE, nullptr, 0, instances);
1763 }
1764 if (mode == GL_TRIANGLE_FAN)
1765 {
1766 return drawTriangleFan(context, count, GL_NONE, nullptr, 0, instances);
1767 }
1768
1769 mDeviceContext->DrawInstanced(count, instances, 0, 0);
1770 return gl::NoError();
1771 }
1772
drawElementsIndirect(const gl::Context * context,GLenum mode,GLenum type,const void * indirect)1773 gl::Error Renderer11::drawElementsIndirect(const gl::Context *context,
1774 GLenum mode,
1775 GLenum type,
1776 const void *indirect)
1777 {
1778 const auto &glState = context->getGLState();
1779 ASSERT(!glState.isTransformFeedbackActiveUnpaused());
1780
1781 if (!applyPrimitiveType(glState, mode, std::numeric_limits<int>::max() - 1))
1782 {
1783 return gl::NoError();
1784 }
1785
1786 gl::Buffer *drawIndirectBuffer = glState.getTargetBuffer(gl::BufferBinding::DrawIndirect);
1787 ASSERT(drawIndirectBuffer);
1788 Buffer11 *storage = GetImplAs<Buffer11>(drawIndirectBuffer);
1789 uintptr_t offset = reinterpret_cast<uintptr_t>(indirect);
1790
1791 // TODO(jmadill): Remove the if statement and compute indirect parameters lazily.
1792 bool usePrimitiveRestartWorkaround =
1793 UsePrimitiveRestartWorkaround(glState.isPrimitiveRestartEnabled(), type);
1794
1795 if (!DrawCallNeedsTranslation(context, mode) && !IsStreamingIndexData(context, type))
1796 {
1797 ANGLE_TRY(mStateManager.applyIndexBuffer(context, nullptr, 0, type, gl::HasIndexRange(),
1798 usePrimitiveRestartWorkaround));
1799 DrawCallVertexParams vertexParams(0, 0, 0);
1800 ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, true));
1801 ID3D11Buffer *buffer = nullptr;
1802 ANGLE_TRY_RESULT(storage->getBuffer(context, BUFFER_USAGE_INDIRECT), buffer);
1803 mDeviceContext->DrawIndexedInstancedIndirect(buffer, static_cast<unsigned int>(offset));
1804 return gl::NoError();
1805 }
1806
1807 const uint8_t *bufferData = nullptr;
1808 ANGLE_TRY(storage->getData(context, &bufferData));
1809 ASSERT(bufferData);
1810
1811 const gl::DrawElementsIndirectCommand *cmd =
1812 reinterpret_cast<const gl::DrawElementsIndirectCommand *>(bufferData + offset);
1813 GLsizei count = cmd->count;
1814 GLuint instances = cmd->primCount;
1815 GLuint firstIndex = cmd->firstIndex;
1816 GLint baseVertex = cmd->baseVertex;
1817
1818 // TODO(jmadill): Fix const cast.
1819 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1820 const void *indices =
1821 reinterpret_cast<const void *>(static_cast<uintptr_t>(firstIndex * typeInfo.bytes));
1822 gl::HasIndexRange lazyIndexRange(const_cast<gl::Context *>(context), count, type, indices);
1823
1824 ANGLE_TRY(mStateManager.applyIndexBuffer(context, indices, count, type, lazyIndexRange,
1825 usePrimitiveRestartWorkaround));
1826
1827 DrawCallVertexParams vertexParams(false, lazyIndexRange, baseVertex, instances);
1828
1829 ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, true));
1830
1831 int baseVertexLocation = -static_cast<int>(lazyIndexRange.getIndexRange().value().start);
1832
1833 if (mode == GL_LINE_LOOP)
1834 {
1835 return drawLineLoop(context, count, type, indices, baseVertexLocation, instances);
1836 }
1837
1838 if (mode == GL_TRIANGLE_FAN)
1839 {
1840 return drawTriangleFan(context, count, type, indices, baseVertexLocation, instances);
1841 }
1842
1843 mDeviceContext->DrawIndexedInstanced(count, instances, 0, baseVertexLocation, 0);
1844 return gl::NoError();
1845 }
1846
drawLineLoop(const gl::Context * context,GLsizei count,GLenum type,const void * indexPointer,int baseVertex,int instances)1847 gl::Error Renderer11::drawLineLoop(const gl::Context *context,
1848 GLsizei count,
1849 GLenum type,
1850 const void *indexPointer,
1851 int baseVertex,
1852 int instances)
1853 {
1854 const gl::State &glState = context->getGLState();
1855 gl::VertexArray *vao = glState.getVertexArray();
1856 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
1857
1858 const void *indices = indexPointer;
1859
1860 // Get the raw indices for an indexed draw
1861 if (type != GL_NONE && elementArrayBuffer)
1862 {
1863 BufferD3D *storage = GetImplAs<BufferD3D>(elementArrayBuffer);
1864 intptr_t offset = reinterpret_cast<intptr_t>(indices);
1865
1866 const uint8_t *bufferData = nullptr;
1867 ANGLE_TRY(storage->getData(context, &bufferData));
1868
1869 indices = bufferData + offset;
1870 }
1871
1872 if (!mLineLoopIB)
1873 {
1874 mLineLoopIB = new StreamingIndexBufferInterface(this);
1875 gl::Error error =
1876 mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT);
1877 if (error.isError())
1878 {
1879 SafeDelete(mLineLoopIB);
1880 return error;
1881 }
1882 }
1883
1884 // Checked by Renderer11::applyPrimitiveType
1885 ASSERT(count >= 0);
1886
1887 if (static_cast<unsigned int>(count) + 1 >
1888 (std::numeric_limits<unsigned int>::max() / sizeof(unsigned int)))
1889 {
1890 return gl::OutOfMemory() << "Failed to create a 32-bit looping index buffer for "
1891 "GL_LINE_LOOP, too many indices required.";
1892 }
1893
1894 GetLineLoopIndices(indices, type, static_cast<GLuint>(count),
1895 glState.isPrimitiveRestartEnabled(), &mScratchIndexDataBuffer);
1896
1897 unsigned int spaceNeeded =
1898 static_cast<unsigned int>(sizeof(GLuint) * mScratchIndexDataBuffer.size());
1899 ANGLE_TRY(mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT));
1900
1901 void *mappedMemory = nullptr;
1902 unsigned int offset;
1903 ANGLE_TRY(mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory, &offset));
1904
1905 // Copy over the converted index data.
1906 memcpy(mappedMemory, &mScratchIndexDataBuffer[0],
1907 sizeof(GLuint) * mScratchIndexDataBuffer.size());
1908
1909 ANGLE_TRY(mLineLoopIB->unmapBuffer());
1910
1911 IndexBuffer11 *indexBuffer = GetAs<IndexBuffer11>(mLineLoopIB->getIndexBuffer());
1912 const d3d11::Buffer &d3dIndexBuffer = indexBuffer->getBuffer();
1913 DXGI_FORMAT indexFormat = indexBuffer->getIndexFormat();
1914
1915 mStateManager.setIndexBuffer(d3dIndexBuffer.get(), indexFormat, offset);
1916
1917 UINT indexCount = static_cast<UINT>(mScratchIndexDataBuffer.size());
1918
1919 if (instances > 0)
1920 {
1921 mDeviceContext->DrawIndexedInstanced(indexCount, instances, 0, baseVertex, 0);
1922 }
1923 else
1924 {
1925 mDeviceContext->DrawIndexed(indexCount, 0, baseVertex);
1926 }
1927
1928 return gl::NoError();
1929 }
1930
drawTriangleFan(const gl::Context * context,GLsizei count,GLenum type,const void * indices,int baseVertex,int instances)1931 gl::Error Renderer11::drawTriangleFan(const gl::Context *context,
1932 GLsizei count,
1933 GLenum type,
1934 const void *indices,
1935 int baseVertex,
1936 int instances)
1937 {
1938 const gl::State &glState = context->getGLState();
1939 gl::VertexArray *vao = glState.getVertexArray();
1940 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
1941
1942 const void *indexPointer = indices;
1943
1944 // Get the raw indices for an indexed draw
1945 if (type != GL_NONE && elementArrayBuffer)
1946 {
1947 BufferD3D *storage = GetImplAs<BufferD3D>(elementArrayBuffer);
1948 intptr_t offset = reinterpret_cast<intptr_t>(indices);
1949
1950 const uint8_t *bufferData = nullptr;
1951 ANGLE_TRY(storage->getData(context, &bufferData));
1952
1953 indexPointer = bufferData + offset;
1954 }
1955
1956 if (!mTriangleFanIB)
1957 {
1958 mTriangleFanIB = new StreamingIndexBufferInterface(this);
1959 gl::Error error =
1960 mTriangleFanIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT);
1961 if (error.isError())
1962 {
1963 SafeDelete(mTriangleFanIB);
1964 return error;
1965 }
1966 }
1967
1968 // Checked by Renderer11::applyPrimitiveType
1969 ASSERT(count >= 3);
1970
1971 const GLuint numTris = count - 2;
1972
1973 if (numTris > (std::numeric_limits<unsigned int>::max() / (sizeof(unsigned int) * 3)))
1974 {
1975 return gl::OutOfMemory() << "Failed to create a scratch index buffer for GL_TRIANGLE_FAN, "
1976 "too many indices required.";
1977 }
1978
1979 GetTriFanIndices(indexPointer, type, count, glState.isPrimitiveRestartEnabled(),
1980 &mScratchIndexDataBuffer);
1981
1982 const unsigned int spaceNeeded =
1983 static_cast<unsigned int>(mScratchIndexDataBuffer.size() * sizeof(unsigned int));
1984 ANGLE_TRY(mTriangleFanIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT));
1985
1986 void *mappedMemory = nullptr;
1987 unsigned int offset;
1988 ANGLE_TRY(mTriangleFanIB->mapBuffer(spaceNeeded, &mappedMemory, &offset));
1989
1990 memcpy(mappedMemory, &mScratchIndexDataBuffer[0], spaceNeeded);
1991
1992 ANGLE_TRY(mTriangleFanIB->unmapBuffer());
1993
1994 IndexBuffer11 *indexBuffer = GetAs<IndexBuffer11>(mTriangleFanIB->getIndexBuffer());
1995 const d3d11::Buffer &d3dIndexBuffer = indexBuffer->getBuffer();
1996 DXGI_FORMAT indexFormat = indexBuffer->getIndexFormat();
1997
1998 mStateManager.setIndexBuffer(d3dIndexBuffer.get(), indexFormat, offset);
1999
2000 UINT indexCount = static_cast<UINT>(mScratchIndexDataBuffer.size());
2001
2002 if (instances > 0)
2003 {
2004 mDeviceContext->DrawIndexedInstanced(indexCount, instances, 0, baseVertex, 0);
2005 }
2006 else
2007 {
2008 mDeviceContext->DrawIndexed(indexCount, 0, baseVertex);
2009 }
2010
2011 return gl::NoError();
2012 }
2013
releaseDeviceResources()2014 void Renderer11::releaseDeviceResources()
2015 {
2016 mStateManager.deinitialize();
2017 mStateCache.clear();
2018
2019 SafeDelete(mLineLoopIB);
2020 SafeDelete(mTriangleFanIB);
2021 SafeDelete(mBlit);
2022 SafeDelete(mClear);
2023 SafeDelete(mTrim);
2024 SafeDelete(mPixelTransfer);
2025
2026 mSyncQuery.reset();
2027
2028 mCachedResolveTexture.reset();
2029 }
2030
2031 // set notify to true to broadcast a message to all contexts of the device loss
testDeviceLost()2032 bool Renderer11::testDeviceLost()
2033 {
2034 bool isLost = false;
2035
2036 if (!mDevice)
2037 {
2038 return true;
2039 }
2040
2041 // GetRemovedReason is used to test if the device is removed
2042 HRESULT result = mDevice->GetDeviceRemovedReason();
2043 isLost = d3d11::isDeviceLostError(result);
2044
2045 if (isLost)
2046 {
2047 ERR() << "The D3D11 device was removed, " << gl::FmtHR(result);
2048 }
2049
2050 return isLost;
2051 }
2052
testDeviceResettable()2053 bool Renderer11::testDeviceResettable()
2054 {
2055 // determine if the device is resettable by creating a dummy device
2056 PFN_D3D11_CREATE_DEVICE D3D11CreateDevice =
2057 (PFN_D3D11_CREATE_DEVICE)GetProcAddress(mD3d11Module, "D3D11CreateDevice");
2058
2059 if (D3D11CreateDevice == nullptr)
2060 {
2061 return false;
2062 }
2063
2064 ID3D11Device *dummyDevice;
2065 D3D_FEATURE_LEVEL dummyFeatureLevel;
2066 ID3D11DeviceContext *dummyContext;
2067 UINT flags = (mCreateDebugDevice ? D3D11_CREATE_DEVICE_DEBUG : 0);
2068
2069 ASSERT(mRequestedDriverType != D3D_DRIVER_TYPE_UNKNOWN);
2070 HRESULT result = D3D11CreateDevice(
2071 nullptr, mRequestedDriverType, nullptr, flags, mAvailableFeatureLevels.data(),
2072 static_cast<unsigned int>(mAvailableFeatureLevels.size()), D3D11_SDK_VERSION, &dummyDevice,
2073 &dummyFeatureLevel, &dummyContext);
2074
2075 if (!mDevice || FAILED(result))
2076 {
2077 return false;
2078 }
2079
2080 SafeRelease(dummyContext);
2081 SafeRelease(dummyDevice);
2082
2083 return true;
2084 }
2085
release()2086 void Renderer11::release()
2087 {
2088 RendererD3D::cleanup();
2089
2090 mScratchMemoryBuffer.clear();
2091
2092 if (mAnnotator != nullptr)
2093 {
2094 gl::UninitializeDebugAnnotations();
2095 SafeDelete(mAnnotator);
2096 }
2097
2098 releaseDeviceResources();
2099
2100 SafeRelease(mDxgiFactory);
2101 SafeRelease(mDxgiAdapter);
2102
2103 SafeRelease(mDeviceContext3);
2104 SafeRelease(mDeviceContext1);
2105
2106 if (mDeviceContext)
2107 {
2108 mDeviceContext->ClearState();
2109 mDeviceContext->Flush();
2110 SafeRelease(mDeviceContext);
2111 }
2112
2113 SafeRelease(mDevice);
2114 SafeRelease(mDebug);
2115
2116 if (mD3d11Module)
2117 {
2118 FreeLibrary(mD3d11Module);
2119 mD3d11Module = nullptr;
2120 }
2121
2122 if (mDxgiModule)
2123 {
2124 FreeLibrary(mDxgiModule);
2125 mDxgiModule = nullptr;
2126 }
2127
2128 if (mDCompModule)
2129 {
2130 FreeLibrary(mDCompModule);
2131 mDCompModule = nullptr;
2132 }
2133
2134 mCompiler.release();
2135
2136 mSupportsShareHandles.reset();
2137 }
2138
resetDevice()2139 bool Renderer11::resetDevice()
2140 {
2141 // recreate everything
2142 release();
2143 egl::Error result = initialize();
2144
2145 if (result.isError())
2146 {
2147 ERR() << "Could not reinitialize D3D11 device: " << result;
2148 return false;
2149 }
2150
2151 return true;
2152 }
2153
getRendererDescription() const2154 std::string Renderer11::getRendererDescription() const
2155 {
2156 std::ostringstream rendererString;
2157
2158 rendererString << mDescription;
2159 rendererString << " Direct3D11";
2160
2161 rendererString << " vs_" << getMajorShaderModel() << "_" << getMinorShaderModel()
2162 << getShaderModelSuffix();
2163 rendererString << " ps_" << getMajorShaderModel() << "_" << getMinorShaderModel()
2164 << getShaderModelSuffix();
2165
2166 return rendererString.str();
2167 }
2168
getAdapterIdentifier() const2169 DeviceIdentifier Renderer11::getAdapterIdentifier() const
2170 {
2171 // Don't use the AdapterLuid here, since that doesn't persist across reboot.
2172 DeviceIdentifier deviceIdentifier = {0};
2173 deviceIdentifier.VendorId = mAdapterDescription.VendorId;
2174 deviceIdentifier.DeviceId = mAdapterDescription.DeviceId;
2175 deviceIdentifier.SubSysId = mAdapterDescription.SubSysId;
2176 deviceIdentifier.Revision = mAdapterDescription.Revision;
2177 deviceIdentifier.FeatureLevel = static_cast<UINT>(mRenderer11DeviceCaps.featureLevel);
2178
2179 return deviceIdentifier;
2180 }
2181
getReservedVertexUniformVectors() const2182 unsigned int Renderer11::getReservedVertexUniformVectors() const
2183 {
2184 // Driver uniforms are stored in a separate constant buffer
2185 return d3d11_gl::GetReservedVertexUniformVectors(mRenderer11DeviceCaps.featureLevel);
2186 }
2187
getReservedFragmentUniformVectors() const2188 unsigned int Renderer11::getReservedFragmentUniformVectors() const
2189 {
2190 // Driver uniforms are stored in a separate constant buffer
2191 return d3d11_gl::GetReservedFragmentUniformVectors(mRenderer11DeviceCaps.featureLevel);
2192 }
2193
getReservedVertexUniformBuffers() const2194 unsigned int Renderer11::getReservedVertexUniformBuffers() const
2195 {
2196 // we reserve one buffer for the application uniforms, and one for driver uniforms
2197 return 2;
2198 }
2199
getReservedFragmentUniformBuffers() const2200 unsigned int Renderer11::getReservedFragmentUniformBuffers() const
2201 {
2202 // we reserve one buffer for the application uniforms, and one for driver uniforms
2203 return 2;
2204 }
2205
getDeviceType() const2206 d3d11::ANGLED3D11DeviceType Renderer11::getDeviceType() const
2207 {
2208 if (mCreatedWithDeviceEXT)
2209 {
2210 return d3d11::GetDeviceType(mDevice);
2211 }
2212
2213 if ((mRequestedDriverType == D3D_DRIVER_TYPE_SOFTWARE) ||
2214 (mRequestedDriverType == D3D_DRIVER_TYPE_REFERENCE) ||
2215 (mRequestedDriverType == D3D_DRIVER_TYPE_NULL))
2216 {
2217 return d3d11::ANGLE_D3D11_DEVICE_TYPE_SOFTWARE_REF_OR_NULL;
2218 }
2219
2220 if (mRequestedDriverType == D3D_DRIVER_TYPE_WARP)
2221 {
2222 return d3d11::ANGLE_D3D11_DEVICE_TYPE_WARP;
2223 }
2224
2225 return d3d11::ANGLE_D3D11_DEVICE_TYPE_HARDWARE;
2226 }
2227
getShareHandleSupport() const2228 bool Renderer11::getShareHandleSupport() const
2229 {
2230 if (mSupportsShareHandles.valid())
2231 {
2232 return mSupportsShareHandles.value();
2233 }
2234
2235 // We only currently support share handles with BGRA surfaces, because
2236 // chrome needs BGRA. Once chrome fixes this, we should always support them.
2237 if (!getNativeExtensions().textureFormatBGRA8888)
2238 {
2239 mSupportsShareHandles = false;
2240 return false;
2241 }
2242
2243 // PIX doesn't seem to support using share handles, so disable them.
2244 if (gl::DebugAnnotationsActive())
2245 {
2246 mSupportsShareHandles = false;
2247 return false;
2248 }
2249
2250 // Also disable share handles on Feature Level 9_3, since it doesn't support share handles on
2251 // RGBA8 textures/swapchains.
2252 if (mRenderer11DeviceCaps.featureLevel <= D3D_FEATURE_LEVEL_9_3)
2253 {
2254 mSupportsShareHandles = false;
2255 return false;
2256 }
2257
2258 // Find out which type of D3D11 device the Renderer11 is using
2259 d3d11::ANGLED3D11DeviceType deviceType = getDeviceType();
2260 if (deviceType == d3d11::ANGLE_D3D11_DEVICE_TYPE_UNKNOWN)
2261 {
2262 mSupportsShareHandles = false;
2263 return false;
2264 }
2265
2266 if (deviceType == d3d11::ANGLE_D3D11_DEVICE_TYPE_SOFTWARE_REF_OR_NULL)
2267 {
2268 // Software/Reference/NULL devices don't support share handles
2269 mSupportsShareHandles = false;
2270 return false;
2271 }
2272
2273 if (deviceType == d3d11::ANGLE_D3D11_DEVICE_TYPE_WARP)
2274 {
2275 #ifndef ANGLE_ENABLE_WINDOWS_STORE
2276 if (!IsWindows8OrGreater())
2277 {
2278 // WARP on Windows 7 doesn't support shared handles
2279 mSupportsShareHandles = false;
2280 return false;
2281 }
2282 #endif // ANGLE_ENABLE_WINDOWS_STORE
2283
2284 // WARP on Windows 8.0+ supports shared handles when shared with another WARP device
2285 // TODO: allow applications to query for HARDWARE or WARP-specific share handles,
2286 // to prevent them trying to use a WARP share handle with an a HW device (or
2287 // vice-versa)
2288 // e.g. by creating EGL_D3D11_[HARDWARE/WARP]_DEVICE_SHARE_HANDLE_ANGLE
2289 mSupportsShareHandles = true;
2290 return true;
2291 }
2292
2293 ASSERT(mCreatedWithDeviceEXT || mRequestedDriverType == D3D_DRIVER_TYPE_HARDWARE);
2294 mSupportsShareHandles = true;
2295 return true;
2296 }
2297
getMajorShaderModel() const2298 int Renderer11::getMajorShaderModel() const
2299 {
2300 switch (mRenderer11DeviceCaps.featureLevel)
2301 {
2302 case D3D_FEATURE_LEVEL_11_1:
2303 case D3D_FEATURE_LEVEL_11_0:
2304 return D3D11_SHADER_MAJOR_VERSION; // 5
2305 case D3D_FEATURE_LEVEL_10_1:
2306 return D3D10_1_SHADER_MAJOR_VERSION; // 4
2307 case D3D_FEATURE_LEVEL_10_0:
2308 return D3D10_SHADER_MAJOR_VERSION; // 4
2309 case D3D_FEATURE_LEVEL_9_3:
2310 return D3D10_SHADER_MAJOR_VERSION; // 4
2311 default:
2312 UNREACHABLE();
2313 return 0;
2314 }
2315 }
2316
getMinorShaderModel() const2317 int Renderer11::getMinorShaderModel() const
2318 {
2319 switch (mRenderer11DeviceCaps.featureLevel)
2320 {
2321 case D3D_FEATURE_LEVEL_11_1:
2322 case D3D_FEATURE_LEVEL_11_0:
2323 return D3D11_SHADER_MINOR_VERSION; // 0
2324 case D3D_FEATURE_LEVEL_10_1:
2325 return D3D10_1_SHADER_MINOR_VERSION; // 1
2326 case D3D_FEATURE_LEVEL_10_0:
2327 return D3D10_SHADER_MINOR_VERSION; // 0
2328 case D3D_FEATURE_LEVEL_9_3:
2329 return D3D10_SHADER_MINOR_VERSION; // 0
2330 default:
2331 UNREACHABLE();
2332 return 0;
2333 }
2334 }
2335
getShaderModelSuffix() const2336 std::string Renderer11::getShaderModelSuffix() const
2337 {
2338 switch (mRenderer11DeviceCaps.featureLevel)
2339 {
2340 case D3D_FEATURE_LEVEL_11_1:
2341 case D3D_FEATURE_LEVEL_11_0:
2342 return "";
2343 case D3D_FEATURE_LEVEL_10_1:
2344 return "";
2345 case D3D_FEATURE_LEVEL_10_0:
2346 return "";
2347 case D3D_FEATURE_LEVEL_9_3:
2348 return "_level_9_3";
2349 default:
2350 UNREACHABLE();
2351 return "";
2352 }
2353 }
2354
getWorkarounds() const2355 const angle::WorkaroundsD3D &RendererD3D::getWorkarounds() const
2356 {
2357 if (!mWorkaroundsInitialized)
2358 {
2359 mWorkarounds = generateWorkarounds();
2360 mWorkaroundsInitialized = true;
2361 }
2362
2363 return mWorkarounds;
2364 }
2365
copyImageInternal(const gl::Context * context,const gl::Framebuffer * framebuffer,const gl::Rectangle & sourceRect,GLenum destFormat,const gl::Offset & destOffset,RenderTargetD3D * destRenderTarget)2366 gl::Error Renderer11::copyImageInternal(const gl::Context *context,
2367 const gl::Framebuffer *framebuffer,
2368 const gl::Rectangle &sourceRect,
2369 GLenum destFormat,
2370 const gl::Offset &destOffset,
2371 RenderTargetD3D *destRenderTarget)
2372 {
2373 const gl::FramebufferAttachment *colorAttachment = framebuffer->getReadColorbuffer();
2374 ASSERT(colorAttachment);
2375
2376 RenderTarget11 *sourceRenderTarget = nullptr;
2377 ANGLE_TRY(colorAttachment->getRenderTarget(context, &sourceRenderTarget));
2378 ASSERT(sourceRenderTarget);
2379
2380 const d3d11::RenderTargetView &dest =
2381 GetAs<RenderTarget11>(destRenderTarget)->getRenderTargetView();
2382 ASSERT(dest.valid());
2383
2384 gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1);
2385 gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1);
2386
2387 const bool invertSource = UsePresentPathFast(this, colorAttachment);
2388 if (invertSource)
2389 {
2390 sourceArea.y = sourceSize.height - sourceRect.y;
2391 sourceArea.height = -sourceArea.height;
2392 }
2393
2394 gl::Box destArea(destOffset.x, destOffset.y, 0, sourceRect.width, sourceRect.height, 1);
2395 gl::Extents destSize(destRenderTarget->getWidth(), destRenderTarget->getHeight(), 1);
2396
2397 // Use nearest filtering because source and destination are the same size for the direct copy.
2398 // Convert to the unsized format before calling copyTexture.
2399 GLenum sourceFormat = colorAttachment->getFormat().info->format;
2400 if (sourceRenderTarget->getTexture().is2D() && sourceRenderTarget->isMultisampled())
2401 {
2402 TextureHelper11 tex;
2403 ANGLE_TRY_RESULT(
2404 resolveMultisampledTexture(context, sourceRenderTarget, colorAttachment->getDepthSize(),
2405 colorAttachment->getStencilSize()),
2406 tex);
2407
2408 D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc;
2409 viewDesc.Format = sourceRenderTarget->getFormatSet().srvFormat;
2410 viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
2411 viewDesc.Texture2D.MipLevels = 1;
2412 viewDesc.Texture2D.MostDetailedMip = 0;
2413
2414 d3d11::SharedSRV readSRV;
2415 ANGLE_TRY(allocateResource(viewDesc, tex.get(), &readSRV));
2416 ASSERT(readSRV.valid());
2417
2418 ANGLE_TRY(mBlit->copyTexture(context, readSRV, sourceArea, sourceSize, sourceFormat, dest,
2419 destArea, destSize, nullptr, gl::GetUnsizedFormat(destFormat),
2420 GL_NONE, GL_NEAREST, false, false, false));
2421
2422 return gl::NoError();
2423 }
2424
2425 ASSERT(!sourceRenderTarget->isMultisampled());
2426
2427 const d3d11::SharedSRV &source = sourceRenderTarget->getBlitShaderResourceView();
2428 ASSERT(source.valid());
2429
2430 ANGLE_TRY(mBlit->copyTexture(context, source, sourceArea, sourceSize, sourceFormat, dest,
2431 destArea, destSize, nullptr, gl::GetUnsizedFormat(destFormat),
2432 GL_NONE, GL_NEAREST, false, false, false));
2433
2434 return gl::NoError();
2435 }
2436
copyImage2D(const gl::Context * context,const gl::Framebuffer * framebuffer,const gl::Rectangle & sourceRect,GLenum destFormat,const gl::Offset & destOffset,TextureStorage * storage,GLint level)2437 gl::Error Renderer11::copyImage2D(const gl::Context *context,
2438 const gl::Framebuffer *framebuffer,
2439 const gl::Rectangle &sourceRect,
2440 GLenum destFormat,
2441 const gl::Offset &destOffset,
2442 TextureStorage *storage,
2443 GLint level)
2444 {
2445 TextureStorage11_2D *storage11 = GetAs<TextureStorage11_2D>(storage);
2446 ASSERT(storage11);
2447
2448 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
2449 RenderTargetD3D *destRenderTarget = nullptr;
2450 ANGLE_TRY(storage11->getRenderTarget(context, index, &destRenderTarget));
2451 ASSERT(destRenderTarget);
2452
2453 ANGLE_TRY(copyImageInternal(context, framebuffer, sourceRect, destFormat, destOffset,
2454 destRenderTarget));
2455
2456 storage11->markLevelDirty(level);
2457
2458 return gl::NoError();
2459 }
2460
copyImageCube(const gl::Context * context,const gl::Framebuffer * framebuffer,const gl::Rectangle & sourceRect,GLenum destFormat,const gl::Offset & destOffset,TextureStorage * storage,GLenum target,GLint level)2461 gl::Error Renderer11::copyImageCube(const gl::Context *context,
2462 const gl::Framebuffer *framebuffer,
2463 const gl::Rectangle &sourceRect,
2464 GLenum destFormat,
2465 const gl::Offset &destOffset,
2466 TextureStorage *storage,
2467 GLenum target,
2468 GLint level)
2469 {
2470 TextureStorage11_Cube *storage11 = GetAs<TextureStorage11_Cube>(storage);
2471 ASSERT(storage11);
2472
2473 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
2474 RenderTargetD3D *destRenderTarget = nullptr;
2475 ANGLE_TRY(storage11->getRenderTarget(context, index, &destRenderTarget));
2476 ASSERT(destRenderTarget);
2477
2478 ANGLE_TRY(copyImageInternal(context, framebuffer, sourceRect, destFormat, destOffset,
2479 destRenderTarget));
2480
2481 storage11->markLevelDirty(level);
2482
2483 return gl::NoError();
2484 }
2485
copyImage3D(const gl::Context * context,const gl::Framebuffer * framebuffer,const gl::Rectangle & sourceRect,GLenum destFormat,const gl::Offset & destOffset,TextureStorage * storage,GLint level)2486 gl::Error Renderer11::copyImage3D(const gl::Context *context,
2487 const gl::Framebuffer *framebuffer,
2488 const gl::Rectangle &sourceRect,
2489 GLenum destFormat,
2490 const gl::Offset &destOffset,
2491 TextureStorage *storage,
2492 GLint level)
2493 {
2494 TextureStorage11_3D *storage11 = GetAs<TextureStorage11_3D>(storage);
2495 ASSERT(storage11);
2496
2497 gl::ImageIndex index = gl::ImageIndex::Make3D(level, destOffset.z);
2498 RenderTargetD3D *destRenderTarget = nullptr;
2499 ANGLE_TRY(storage11->getRenderTarget(context, index, &destRenderTarget));
2500 ASSERT(destRenderTarget);
2501
2502 ANGLE_TRY(copyImageInternal(context, framebuffer, sourceRect, destFormat, destOffset,
2503 destRenderTarget));
2504
2505 storage11->markLevelDirty(level);
2506
2507 return gl::NoError();
2508 }
2509
copyImage2DArray(const gl::Context * context,const gl::Framebuffer * framebuffer,const gl::Rectangle & sourceRect,GLenum destFormat,const gl::Offset & destOffset,TextureStorage * storage,GLint level)2510 gl::Error Renderer11::copyImage2DArray(const gl::Context *context,
2511 const gl::Framebuffer *framebuffer,
2512 const gl::Rectangle &sourceRect,
2513 GLenum destFormat,
2514 const gl::Offset &destOffset,
2515 TextureStorage *storage,
2516 GLint level)
2517 {
2518 TextureStorage11_2DArray *storage11 = GetAs<TextureStorage11_2DArray>(storage);
2519 ASSERT(storage11);
2520
2521 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, destOffset.z);
2522 RenderTargetD3D *destRenderTarget = nullptr;
2523 ANGLE_TRY(storage11->getRenderTarget(context, index, &destRenderTarget));
2524 ASSERT(destRenderTarget);
2525
2526 ANGLE_TRY(copyImageInternal(context, framebuffer, sourceRect, destFormat, destOffset,
2527 destRenderTarget));
2528 storage11->markLevelDirty(level);
2529
2530 return gl::NoError();
2531 }
2532
copyTexture(const gl::Context * context,const gl::Texture * source,GLint sourceLevel,const gl::Rectangle & sourceRect,GLenum destFormat,GLenum destType,const gl::Offset & destOffset,TextureStorage * storage,GLenum destTarget,GLint destLevel,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha)2533 gl::Error Renderer11::copyTexture(const gl::Context *context,
2534 const gl::Texture *source,
2535 GLint sourceLevel,
2536 const gl::Rectangle &sourceRect,
2537 GLenum destFormat,
2538 GLenum destType,
2539 const gl::Offset &destOffset,
2540 TextureStorage *storage,
2541 GLenum destTarget,
2542 GLint destLevel,
2543 bool unpackFlipY,
2544 bool unpackPremultiplyAlpha,
2545 bool unpackUnmultiplyAlpha)
2546 {
2547 TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source);
2548
2549 TextureStorage *sourceStorage = nullptr;
2550 ANGLE_TRY(sourceD3D->getNativeTexture(context, &sourceStorage));
2551
2552 TextureStorage11_2D *sourceStorage11 = GetAs<TextureStorage11_2D>(sourceStorage);
2553 ASSERT(sourceStorage11);
2554
2555 TextureStorage11 *destStorage11 = GetAs<TextureStorage11>(storage);
2556 ASSERT(destStorage11);
2557
2558 // Check for fast path where a CopySubresourceRegion can be used.
2559 if (unpackPremultiplyAlpha == unpackUnmultiplyAlpha && !unpackFlipY &&
2560 source->getFormat(GL_TEXTURE_2D, sourceLevel).info->format == destFormat &&
2561 sourceStorage11->getFormatSet().internalFormat ==
2562 destStorage11->getFormatSet().internalFormat)
2563 {
2564 const TextureHelper11 *sourceResource = nullptr;
2565 ANGLE_TRY(sourceStorage11->getResource(context, &sourceResource));
2566
2567 gl::ImageIndex sourceIndex = gl::ImageIndex::Make2D(sourceLevel);
2568 UINT sourceSubresource = sourceStorage11->getSubresourceIndex(sourceIndex);
2569
2570 const TextureHelper11 *destResource = nullptr;
2571 ANGLE_TRY(destStorage11->getResource(context, &destResource));
2572
2573 gl::ImageIndex destIndex = gl::ImageIndex::MakeGeneric(destTarget, destLevel);
2574 UINT destSubresource = destStorage11->getSubresourceIndex(destIndex);
2575
2576 D3D11_BOX sourceBox{
2577 static_cast<UINT>(sourceRect.x),
2578 static_cast<UINT>(sourceRect.y),
2579 0u,
2580 static_cast<UINT>(sourceRect.x + sourceRect.width),
2581 static_cast<UINT>(sourceRect.y + sourceRect.height),
2582 1u,
2583 };
2584
2585 mDeviceContext->CopySubresourceRegion(destResource->get(), destSubresource, destOffset.x,
2586 destOffset.y, destOffset.z, sourceResource->get(),
2587 sourceSubresource, &sourceBox);
2588 }
2589 else
2590 {
2591 const d3d11::SharedSRV *sourceSRV = nullptr;
2592 ANGLE_TRY(sourceStorage11->getSRVLevels(context, sourceLevel, sourceLevel, &sourceSRV));
2593
2594 gl::ImageIndex destIndex = gl::ImageIndex::MakeGeneric(destTarget, destLevel);
2595 RenderTargetD3D *destRenderTargetD3D = nullptr;
2596 ANGLE_TRY(destStorage11->getRenderTarget(context, destIndex, &destRenderTargetD3D));
2597
2598 RenderTarget11 *destRenderTarget11 = GetAs<RenderTarget11>(destRenderTargetD3D);
2599
2600 const d3d11::RenderTargetView &destRTV = destRenderTarget11->getRenderTargetView();
2601 ASSERT(destRTV.valid());
2602
2603 gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1);
2604 gl::Extents sourceSize(
2605 static_cast<int>(source->getWidth(source->getTarget(), sourceLevel)),
2606 static_cast<int>(source->getHeight(source->getTarget(), sourceLevel)), 1);
2607 if (unpackFlipY)
2608 {
2609 sourceArea.y += sourceArea.height;
2610 sourceArea.height = -sourceArea.height;
2611 }
2612
2613 gl::Box destArea(destOffset.x, destOffset.y, 0, sourceRect.width, sourceRect.height, 1);
2614 gl::Extents destSize(destRenderTarget11->getWidth(), destRenderTarget11->getHeight(), 1);
2615
2616 // Use nearest filtering because source and destination are the same size for the direct
2617 // copy
2618 GLenum sourceFormat = source->getFormat(GL_TEXTURE_2D, sourceLevel).info->format;
2619 ANGLE_TRY(mBlit->copyTexture(context, *sourceSRV, sourceArea, sourceSize, sourceFormat,
2620 destRTV, destArea, destSize, nullptr, destFormat, destType,
2621 GL_NEAREST, false, unpackPremultiplyAlpha,
2622 unpackUnmultiplyAlpha));
2623 }
2624
2625 destStorage11->markLevelDirty(destLevel);
2626
2627 return gl::NoError();
2628 }
2629
copyCompressedTexture(const gl::Context * context,const gl::Texture * source,GLint sourceLevel,TextureStorage * storage,GLint destLevel)2630 gl::Error Renderer11::copyCompressedTexture(const gl::Context *context,
2631 const gl::Texture *source,
2632 GLint sourceLevel,
2633 TextureStorage *storage,
2634 GLint destLevel)
2635 {
2636 TextureStorage11_2D *destStorage11 = GetAs<TextureStorage11_2D>(storage);
2637 ASSERT(destStorage11);
2638
2639 const TextureHelper11 *destResource = nullptr;
2640 ANGLE_TRY(destStorage11->getResource(context, &destResource));
2641
2642 gl::ImageIndex destIndex = gl::ImageIndex::Make2D(destLevel);
2643 UINT destSubresource = destStorage11->getSubresourceIndex(destIndex);
2644
2645 TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source);
2646 ASSERT(sourceD3D);
2647
2648 TextureStorage *sourceStorage = nullptr;
2649 ANGLE_TRY(sourceD3D->getNativeTexture(context, &sourceStorage));
2650
2651 TextureStorage11_2D *sourceStorage11 = GetAs<TextureStorage11_2D>(sourceStorage);
2652 ASSERT(sourceStorage11);
2653
2654 const TextureHelper11 *sourceResource = nullptr;
2655 ANGLE_TRY(sourceStorage11->getResource(context, &sourceResource));
2656
2657 gl::ImageIndex sourceIndex = gl::ImageIndex::Make2D(sourceLevel);
2658 UINT sourceSubresource = sourceStorage11->getSubresourceIndex(sourceIndex);
2659
2660 mDeviceContext->CopySubresourceRegion(destResource->get(), destSubresource, 0, 0, 0,
2661 sourceResource->get(), sourceSubresource, nullptr);
2662
2663 return gl::NoError();
2664 }
2665
createRenderTarget(int width,int height,GLenum format,GLsizei samples,RenderTargetD3D ** outRT)2666 gl::Error Renderer11::createRenderTarget(int width,
2667 int height,
2668 GLenum format,
2669 GLsizei samples,
2670 RenderTargetD3D **outRT)
2671 {
2672 const d3d11::Format &formatInfo = d3d11::Format::Get(format, mRenderer11DeviceCaps);
2673
2674 const gl::TextureCaps &textureCaps = getNativeTextureCaps().get(format);
2675 GLuint supportedSamples = textureCaps.getNearestSamples(samples);
2676
2677 if (width > 0 && height > 0)
2678 {
2679 // Create texture resource
2680 D3D11_TEXTURE2D_DESC desc;
2681 desc.Width = width;
2682 desc.Height = height;
2683 desc.MipLevels = 1;
2684 desc.ArraySize = 1;
2685 desc.Format = formatInfo.texFormat;
2686 desc.SampleDesc.Count = (supportedSamples == 0) ? 1 : supportedSamples;
2687 desc.SampleDesc.Quality = 0;
2688 desc.Usage = D3D11_USAGE_DEFAULT;
2689 desc.CPUAccessFlags = 0;
2690 desc.MiscFlags = 0;
2691
2692 // If a rendertarget or depthstencil format exists for this texture format,
2693 // we'll flag it to allow binding that way. Shader resource views are a little
2694 // more complicated.
2695 bool bindRTV = false, bindDSV = false, bindSRV = false;
2696 bindRTV = (formatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN);
2697 bindDSV = (formatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN);
2698 bindSRV = (formatInfo.srvFormat != DXGI_FORMAT_UNKNOWN);
2699
2700 bool isMultisampledDepthStencil = bindDSV && desc.SampleDesc.Count > 1;
2701 if (isMultisampledDepthStencil &&
2702 !mRenderer11DeviceCaps.supportsMultisampledDepthStencilSRVs)
2703 {
2704 bindSRV = false;
2705 }
2706
2707 desc.BindFlags = (bindRTV ? D3D11_BIND_RENDER_TARGET : 0) |
2708 (bindDSV ? D3D11_BIND_DEPTH_STENCIL : 0) |
2709 (bindSRV ? D3D11_BIND_SHADER_RESOURCE : 0);
2710
2711 // The format must be either an RTV or a DSV
2712 ASSERT(bindRTV != bindDSV);
2713
2714 TextureHelper11 texture;
2715 ANGLE_TRY(allocateTexture(desc, formatInfo, &texture));
2716
2717 d3d11::SharedSRV srv;
2718 d3d11::SharedSRV blitSRV;
2719 if (bindSRV)
2720 {
2721 D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
2722 srvDesc.Format = formatInfo.srvFormat;
2723 srvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_SRV_DIMENSION_TEXTURE2D
2724 : D3D11_SRV_DIMENSION_TEXTURE2DMS;
2725 srvDesc.Texture2D.MostDetailedMip = 0;
2726 srvDesc.Texture2D.MipLevels = 1;
2727
2728 ANGLE_TRY(allocateResource(srvDesc, texture.get(), &srv));
2729
2730 if (formatInfo.blitSRVFormat != formatInfo.srvFormat)
2731 {
2732 D3D11_SHADER_RESOURCE_VIEW_DESC blitSRVDesc;
2733 blitSRVDesc.Format = formatInfo.blitSRVFormat;
2734 blitSRVDesc.ViewDimension = (supportedSamples == 0)
2735 ? D3D11_SRV_DIMENSION_TEXTURE2D
2736 : D3D11_SRV_DIMENSION_TEXTURE2DMS;
2737 blitSRVDesc.Texture2D.MostDetailedMip = 0;
2738 blitSRVDesc.Texture2D.MipLevels = 1;
2739
2740 ANGLE_TRY(allocateResource(blitSRVDesc, texture.get(), &blitSRV));
2741 }
2742 else
2743 {
2744 blitSRV = srv.makeCopy();
2745 }
2746 }
2747
2748 if (bindDSV)
2749 {
2750 D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc;
2751 dsvDesc.Format = formatInfo.dsvFormat;
2752 dsvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_DSV_DIMENSION_TEXTURE2D
2753 : D3D11_DSV_DIMENSION_TEXTURE2DMS;
2754 dsvDesc.Texture2D.MipSlice = 0;
2755 dsvDesc.Flags = 0;
2756
2757 d3d11::DepthStencilView dsv;
2758 ANGLE_TRY(allocateResource(dsvDesc, texture.get(), &dsv));
2759
2760 *outRT = new TextureRenderTarget11(std::move(dsv), texture, srv, format, formatInfo,
2761 width, height, 1, supportedSamples);
2762 }
2763 else if (bindRTV)
2764 {
2765 D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
2766 rtvDesc.Format = formatInfo.rtvFormat;
2767 rtvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_RTV_DIMENSION_TEXTURE2D
2768 : D3D11_RTV_DIMENSION_TEXTURE2DMS;
2769 rtvDesc.Texture2D.MipSlice = 0;
2770
2771 d3d11::RenderTargetView rtv;
2772 ANGLE_TRY(allocateResource(rtvDesc, texture.get(), &rtv));
2773
2774 if (formatInfo.dataInitializerFunction != nullptr)
2775 {
2776 const float clearValues[4] = {0.0f, 0.0f, 0.0f, 1.0f};
2777 mDeviceContext->ClearRenderTargetView(rtv.get(), clearValues);
2778 }
2779
2780 *outRT = new TextureRenderTarget11(std::move(rtv), texture, srv, blitSRV, format,
2781 formatInfo, width, height, 1, supportedSamples);
2782 }
2783 else
2784 {
2785 UNREACHABLE();
2786 }
2787 }
2788 else
2789 {
2790 *outRT = new TextureRenderTarget11(d3d11::RenderTargetView(), TextureHelper11(),
2791 d3d11::SharedSRV(), d3d11::SharedSRV(), format,
2792 d3d11::Format::Get(GL_NONE, mRenderer11DeviceCaps),
2793 width, height, 1, supportedSamples);
2794 }
2795
2796 return gl::NoError();
2797 }
2798
createRenderTargetCopy(RenderTargetD3D * source,RenderTargetD3D ** outRT)2799 gl::Error Renderer11::createRenderTargetCopy(RenderTargetD3D *source, RenderTargetD3D **outRT)
2800 {
2801 ASSERT(source != nullptr);
2802
2803 RenderTargetD3D *newRT = nullptr;
2804 ANGLE_TRY(createRenderTarget(source->getWidth(), source->getHeight(),
2805 source->getInternalFormat(), source->getSamples(), &newRT));
2806
2807 RenderTarget11 *source11 = GetAs<RenderTarget11>(source);
2808 RenderTarget11 *dest11 = GetAs<RenderTarget11>(newRT);
2809
2810 mDeviceContext->CopySubresourceRegion(dest11->getTexture().get(), dest11->getSubresourceIndex(),
2811 0, 0, 0, source11->getTexture().get(),
2812 source11->getSubresourceIndex(), nullptr);
2813 *outRT = newRT;
2814 return gl::NoError();
2815 }
2816
loadExecutable(const uint8_t * function,size_t length,gl::ShaderType type,const std::vector<D3DVarying> & streamOutVaryings,bool separatedOutputBuffers,ShaderExecutableD3D ** outExecutable)2817 gl::Error Renderer11::loadExecutable(const uint8_t *function,
2818 size_t length,
2819 gl::ShaderType type,
2820 const std::vector<D3DVarying> &streamOutVaryings,
2821 bool separatedOutputBuffers,
2822 ShaderExecutableD3D **outExecutable)
2823 {
2824 ShaderData shaderData(function, length);
2825
2826 switch (type)
2827 {
2828 case gl::SHADER_VERTEX:
2829 {
2830 d3d11::VertexShader vertexShader;
2831 d3d11::GeometryShader streamOutShader;
2832 ANGLE_TRY(allocateResource(shaderData, &vertexShader));
2833
2834 if (!streamOutVaryings.empty())
2835 {
2836 std::vector<D3D11_SO_DECLARATION_ENTRY> soDeclaration;
2837 soDeclaration.reserve(streamOutVaryings.size());
2838
2839 for (const auto &streamOutVarying : streamOutVaryings)
2840 {
2841 D3D11_SO_DECLARATION_ENTRY entry = {0};
2842 entry.Stream = 0;
2843 entry.SemanticName = streamOutVarying.semanticName.c_str();
2844 entry.SemanticIndex = streamOutVarying.semanticIndex;
2845 entry.StartComponent = 0;
2846 entry.ComponentCount = static_cast<BYTE>(streamOutVarying.componentCount);
2847 entry.OutputSlot = static_cast<BYTE>(
2848 (separatedOutputBuffers ? streamOutVarying.outputSlot : 0));
2849 soDeclaration.push_back(entry);
2850 }
2851
2852 ANGLE_TRY(allocateResource(shaderData, &soDeclaration, &streamOutShader));
2853 }
2854
2855 *outExecutable = new ShaderExecutable11(function, length, std::move(vertexShader),
2856 std::move(streamOutShader));
2857 }
2858 break;
2859 case gl::SHADER_FRAGMENT:
2860 {
2861 d3d11::PixelShader pixelShader;
2862 ANGLE_TRY(allocateResource(shaderData, &pixelShader));
2863 *outExecutable = new ShaderExecutable11(function, length, std::move(pixelShader));
2864 }
2865 break;
2866 case gl::SHADER_GEOMETRY:
2867 {
2868 d3d11::GeometryShader geometryShader;
2869 ANGLE_TRY(allocateResource(shaderData, &geometryShader));
2870 *outExecutable = new ShaderExecutable11(function, length, std::move(geometryShader));
2871 }
2872 break;
2873 case gl::SHADER_COMPUTE:
2874 {
2875 d3d11::ComputeShader computeShader;
2876 ANGLE_TRY(allocateResource(shaderData, &computeShader));
2877 *outExecutable = new ShaderExecutable11(function, length, std::move(computeShader));
2878 }
2879 break;
2880 default:
2881 UNREACHABLE();
2882 return gl::InternalError();
2883 }
2884
2885 return gl::NoError();
2886 }
2887
compileToExecutable(gl::InfoLog & infoLog,const std::string & shaderHLSL,gl::ShaderType type,const std::vector<D3DVarying> & streamOutVaryings,bool separatedOutputBuffers,const angle::CompilerWorkaroundsD3D & workarounds,ShaderExecutableD3D ** outExectuable)2888 gl::Error Renderer11::compileToExecutable(gl::InfoLog &infoLog,
2889 const std::string &shaderHLSL,
2890 gl::ShaderType type,
2891 const std::vector<D3DVarying> &streamOutVaryings,
2892 bool separatedOutputBuffers,
2893 const angle::CompilerWorkaroundsD3D &workarounds,
2894 ShaderExecutableD3D **outExectuable)
2895 {
2896 std::stringstream profileStream;
2897
2898 switch (type)
2899 {
2900 case gl::SHADER_VERTEX:
2901 profileStream << "vs";
2902 break;
2903 case gl::SHADER_FRAGMENT:
2904 profileStream << "ps";
2905 break;
2906 case gl::SHADER_GEOMETRY:
2907 profileStream << "gs";
2908 break;
2909 case gl::SHADER_COMPUTE:
2910 profileStream << "cs";
2911 break;
2912 default:
2913 UNREACHABLE();
2914 return gl::InternalError();
2915 }
2916
2917 profileStream << "_" << getMajorShaderModel() << "_" << getMinorShaderModel()
2918 << getShaderModelSuffix();
2919 std::string profile = profileStream.str();
2920
2921 UINT flags = D3DCOMPILE_OPTIMIZATION_LEVEL2;
2922
2923 if (gl::DebugAnnotationsActive())
2924 {
2925 #ifndef NDEBUG
2926 flags = D3DCOMPILE_SKIP_OPTIMIZATION;
2927 #endif
2928
2929 flags |= D3DCOMPILE_DEBUG;
2930 }
2931
2932 if (workarounds.enableIEEEStrictness)
2933 flags |= D3DCOMPILE_IEEE_STRICTNESS;
2934
2935 // Sometimes D3DCompile will fail with the default compilation flags for complicated shaders
2936 // when it would otherwise pass with alternative options.
2937 // Try the default flags first and if compilation fails, try some alternatives.
2938 std::vector<CompileConfig> configs;
2939 configs.push_back(CompileConfig(flags, "default"));
2940 configs.push_back(CompileConfig(flags | D3DCOMPILE_SKIP_VALIDATION, "skip validation"));
2941 configs.push_back(CompileConfig(flags | D3DCOMPILE_SKIP_OPTIMIZATION, "skip optimization"));
2942
2943 if (getMajorShaderModel() == 4 && getShaderModelSuffix() != "")
2944 {
2945 // Some shaders might cause a "blob content mismatch between level9 and d3d10 shader".
2946 // e.g. dEQP-GLES2.functional.shaders.struct.local.loop_nested_struct_array_*.
2947 // Using the [unroll] directive works around this, as does this D3DCompile flag.
2948 configs.push_back(
2949 CompileConfig(flags | D3DCOMPILE_AVOID_FLOW_CONTROL, "avoid flow control"));
2950 }
2951
2952 D3D_SHADER_MACRO loopMacros[] = {{"ANGLE_ENABLE_LOOP_FLATTEN", "1"}, {0, 0}};
2953
2954 // TODO(jmadill): Use ComPtr?
2955 ID3DBlob *binary = nullptr;
2956 std::string debugInfo;
2957 ANGLE_TRY(mCompiler.compileToBinary(infoLog, shaderHLSL, profile, configs, loopMacros, &binary,
2958 &debugInfo));
2959
2960 // It's possible that binary is NULL if the compiler failed in all configurations. Set the
2961 // executable to NULL and return GL_NO_ERROR to signify that there was a link error but the
2962 // internal state is still OK.
2963 if (!binary)
2964 {
2965 *outExectuable = nullptr;
2966 return gl::NoError();
2967 }
2968
2969 gl::Error error = loadExecutable(reinterpret_cast<const uint8_t *>(binary->GetBufferPointer()),
2970 binary->GetBufferSize(), type, streamOutVaryings,
2971 separatedOutputBuffers, outExectuable);
2972
2973 SafeRelease(binary);
2974 if (error.isError())
2975 {
2976 return error;
2977 }
2978
2979 if (!debugInfo.empty())
2980 {
2981 (*outExectuable)->appendDebugInfo(debugInfo);
2982 }
2983
2984 return gl::NoError();
2985 }
2986
ensureHLSLCompilerInitialized()2987 gl::Error Renderer11::ensureHLSLCompilerInitialized()
2988 {
2989 return mCompiler.ensureInitialized();
2990 }
2991
createUniformStorage(size_t storageSize)2992 UniformStorageD3D *Renderer11::createUniformStorage(size_t storageSize)
2993 {
2994 return new UniformStorage11(storageSize);
2995 }
2996
createVertexBuffer()2997 VertexBuffer *Renderer11::createVertexBuffer()
2998 {
2999 return new VertexBuffer11(this);
3000 }
3001
createIndexBuffer()3002 IndexBuffer *Renderer11::createIndexBuffer()
3003 {
3004 return new IndexBuffer11(this);
3005 }
3006
createStreamProducerD3DTexture(egl::Stream::ConsumerType consumerType,const egl::AttributeMap & attribs)3007 StreamProducerImpl *Renderer11::createStreamProducerD3DTexture(
3008 egl::Stream::ConsumerType consumerType,
3009 const egl::AttributeMap &attribs)
3010 {
3011 return new StreamProducerD3DTexture(this);
3012 }
3013
supportsFastCopyBufferToTexture(GLenum internalFormat) const3014 bool Renderer11::supportsFastCopyBufferToTexture(GLenum internalFormat) const
3015 {
3016 ASSERT(getNativeExtensions().pixelBufferObject);
3017
3018 const gl::InternalFormat &internalFormatInfo = gl::GetSizedInternalFormatInfo(internalFormat);
3019 const d3d11::Format &d3d11FormatInfo =
3020 d3d11::Format::Get(internalFormat, mRenderer11DeviceCaps);
3021
3022 // sRGB formats do not work with D3D11 buffer SRVs
3023 if (internalFormatInfo.colorEncoding == GL_SRGB)
3024 {
3025 return false;
3026 }
3027
3028 // We cannot support direct copies to non-color-renderable formats
3029 if (d3d11FormatInfo.rtvFormat == DXGI_FORMAT_UNKNOWN)
3030 {
3031 return false;
3032 }
3033
3034 // We skip all 3-channel formats since sometimes format support is missing
3035 if (internalFormatInfo.componentCount == 3)
3036 {
3037 return false;
3038 }
3039
3040 // We don't support formats which we can't represent without conversion
3041 if (d3d11FormatInfo.format().glInternalFormat != internalFormat)
3042 {
3043 return false;
3044 }
3045
3046 // Buffer SRV creation for this format was not working on Windows 10.
3047 if (d3d11FormatInfo.texFormat == DXGI_FORMAT_B5G5R5A1_UNORM)
3048 {
3049 return false;
3050 }
3051
3052 // This format is not supported as a buffer SRV.
3053 if (d3d11FormatInfo.texFormat == DXGI_FORMAT_A8_UNORM)
3054 {
3055 return false;
3056 }
3057
3058 return true;
3059 }
3060
fastCopyBufferToTexture(const gl::Context * context,const gl::PixelUnpackState & unpack,unsigned int offset,RenderTargetD3D * destRenderTarget,GLenum destinationFormat,GLenum sourcePixelsType,const gl::Box & destArea)3061 gl::Error Renderer11::fastCopyBufferToTexture(const gl::Context *context,
3062 const gl::PixelUnpackState &unpack,
3063 unsigned int offset,
3064 RenderTargetD3D *destRenderTarget,
3065 GLenum destinationFormat,
3066 GLenum sourcePixelsType,
3067 const gl::Box &destArea)
3068 {
3069 ASSERT(supportsFastCopyBufferToTexture(destinationFormat));
3070 return mPixelTransfer->copyBufferToTexture(context, unpack, offset, destRenderTarget,
3071 destinationFormat, sourcePixelsType, destArea);
3072 }
3073
createImage()3074 ImageD3D *Renderer11::createImage()
3075 {
3076 return new Image11(this);
3077 }
3078
generateMipmap(const gl::Context * context,ImageD3D * dest,ImageD3D * src)3079 gl::Error Renderer11::generateMipmap(const gl::Context *context, ImageD3D *dest, ImageD3D *src)
3080 {
3081 Image11 *dest11 = GetAs<Image11>(dest);
3082 Image11 *src11 = GetAs<Image11>(src);
3083 return Image11::GenerateMipmap(context, dest11, src11, mRenderer11DeviceCaps);
3084 }
3085
generateMipmapUsingD3D(const gl::Context * context,TextureStorage * storage,const gl::TextureState & textureState)3086 gl::Error Renderer11::generateMipmapUsingD3D(const gl::Context *context,
3087 TextureStorage *storage,
3088 const gl::TextureState &textureState)
3089 {
3090 TextureStorage11 *storage11 = GetAs<TextureStorage11>(storage);
3091
3092 ASSERT(storage11->isRenderTarget());
3093 ASSERT(storage11->supportsNativeMipmapFunction());
3094
3095 const d3d11::SharedSRV *srv = nullptr;
3096 ANGLE_TRY(storage11->getSRVLevels(context, textureState.getEffectiveBaseLevel(),
3097 textureState.getEffectiveMaxLevel(), &srv));
3098
3099 mDeviceContext->GenerateMips(srv->get());
3100
3101 return gl::NoError();
3102 }
3103
copyImage(const gl::Context * context,ImageD3D * dest,ImageD3D * source,const gl::Rectangle & sourceRect,const gl::Offset & destOffset,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha)3104 gl::Error Renderer11::copyImage(const gl::Context *context,
3105 ImageD3D *dest,
3106 ImageD3D *source,
3107 const gl::Rectangle &sourceRect,
3108 const gl::Offset &destOffset,
3109 bool unpackFlipY,
3110 bool unpackPremultiplyAlpha,
3111 bool unpackUnmultiplyAlpha)
3112 {
3113 Image11 *dest11 = GetAs<Image11>(dest);
3114 Image11 *src11 = GetAs<Image11>(source);
3115 return Image11::CopyImage(context, dest11, src11, sourceRect, destOffset, unpackFlipY,
3116 unpackPremultiplyAlpha, unpackUnmultiplyAlpha, mRenderer11DeviceCaps);
3117 }
3118
createTextureStorage2D(SwapChainD3D * swapChain)3119 TextureStorage *Renderer11::createTextureStorage2D(SwapChainD3D *swapChain)
3120 {
3121 SwapChain11 *swapChain11 = GetAs<SwapChain11>(swapChain);
3122 return new TextureStorage11_2D(this, swapChain11);
3123 }
3124
createTextureStorageEGLImage(EGLImageD3D * eglImage,RenderTargetD3D * renderTargetD3D)3125 TextureStorage *Renderer11::createTextureStorageEGLImage(EGLImageD3D *eglImage,
3126 RenderTargetD3D *renderTargetD3D)
3127 {
3128 return new TextureStorage11_EGLImage(this, eglImage, GetAs<RenderTarget11>(renderTargetD3D));
3129 }
3130
createTextureStorageExternal(egl::Stream * stream,const egl::Stream::GLTextureDescription & desc)3131 TextureStorage *Renderer11::createTextureStorageExternal(
3132 egl::Stream *stream,
3133 const egl::Stream::GLTextureDescription &desc)
3134 {
3135 return new TextureStorage11_External(this, stream, desc);
3136 }
3137
createTextureStorage2D(GLenum internalformat,bool renderTarget,GLsizei width,GLsizei height,int levels,bool hintLevelZeroOnly)3138 TextureStorage *Renderer11::createTextureStorage2D(GLenum internalformat,
3139 bool renderTarget,
3140 GLsizei width,
3141 GLsizei height,
3142 int levels,
3143 bool hintLevelZeroOnly)
3144 {
3145 return new TextureStorage11_2D(this, internalformat, renderTarget, width, height, levels,
3146 hintLevelZeroOnly);
3147 }
3148
createTextureStorageCube(GLenum internalformat,bool renderTarget,int size,int levels,bool hintLevelZeroOnly)3149 TextureStorage *Renderer11::createTextureStorageCube(GLenum internalformat,
3150 bool renderTarget,
3151 int size,
3152 int levels,
3153 bool hintLevelZeroOnly)
3154 {
3155 return new TextureStorage11_Cube(this, internalformat, renderTarget, size, levels,
3156 hintLevelZeroOnly);
3157 }
3158
createTextureStorage3D(GLenum internalformat,bool renderTarget,GLsizei width,GLsizei height,GLsizei depth,int levels)3159 TextureStorage *Renderer11::createTextureStorage3D(GLenum internalformat,
3160 bool renderTarget,
3161 GLsizei width,
3162 GLsizei height,
3163 GLsizei depth,
3164 int levels)
3165 {
3166 return new TextureStorage11_3D(this, internalformat, renderTarget, width, height, depth,
3167 levels);
3168 }
3169
createTextureStorage2DArray(GLenum internalformat,bool renderTarget,GLsizei width,GLsizei height,GLsizei depth,int levels)3170 TextureStorage *Renderer11::createTextureStorage2DArray(GLenum internalformat,
3171 bool renderTarget,
3172 GLsizei width,
3173 GLsizei height,
3174 GLsizei depth,
3175 int levels)
3176 {
3177 return new TextureStorage11_2DArray(this, internalformat, renderTarget, width, height, depth,
3178 levels);
3179 }
3180
createTextureStorage2DMultisample(GLenum internalformat,GLsizei width,GLsizei height,int levels,int samples,bool fixedSampleLocations)3181 TextureStorage *Renderer11::createTextureStorage2DMultisample(GLenum internalformat,
3182 GLsizei width,
3183 GLsizei height,
3184 int levels,
3185 int samples,
3186 bool fixedSampleLocations)
3187 {
3188 return new TextureStorage11_2DMultisample(this, internalformat, width, height, levels, samples,
3189 fixedSampleLocations);
3190 }
3191
readFromAttachment(const gl::Context * context,const gl::FramebufferAttachment & srcAttachment,const gl::Rectangle & sourceArea,GLenum format,GLenum type,GLuint outputPitch,const gl::PixelPackState & pack,uint8_t * pixelsOut)3192 gl::Error Renderer11::readFromAttachment(const gl::Context *context,
3193 const gl::FramebufferAttachment &srcAttachment,
3194 const gl::Rectangle &sourceArea,
3195 GLenum format,
3196 GLenum type,
3197 GLuint outputPitch,
3198 const gl::PixelPackState &pack,
3199 uint8_t *pixelsOut)
3200 {
3201 ASSERT(sourceArea.width >= 0);
3202 ASSERT(sourceArea.height >= 0);
3203
3204 const bool invertTexture = UsePresentPathFast(this, &srcAttachment);
3205
3206 RenderTarget11 *rt11 = nullptr;
3207 ANGLE_TRY(srcAttachment.getRenderTarget(context, &rt11));
3208 ASSERT(rt11->getTexture().valid());
3209
3210 const TextureHelper11 &textureHelper = rt11->getTexture();
3211 unsigned int sourceSubResource = rt11->getSubresourceIndex();
3212
3213 const gl::Extents &texSize = textureHelper.getExtents();
3214
3215 gl::Rectangle actualArea = sourceArea;
3216 if (invertTexture)
3217 {
3218 actualArea.y = texSize.height - actualArea.y - actualArea.height;
3219 }
3220
3221 // Clamp read region to the defined texture boundaries, preventing out of bounds reads
3222 // and reads of uninitialized data.
3223 gl::Rectangle safeArea;
3224 safeArea.x = gl::clamp(actualArea.x, 0, texSize.width);
3225 safeArea.y = gl::clamp(actualArea.y, 0, texSize.height);
3226 safeArea.width =
3227 gl::clamp(actualArea.width + std::min(actualArea.x, 0), 0, texSize.width - safeArea.x);
3228 safeArea.height =
3229 gl::clamp(actualArea.height + std::min(actualArea.y, 0), 0, texSize.height - safeArea.y);
3230
3231 ASSERT(safeArea.x >= 0 && safeArea.y >= 0);
3232 ASSERT(safeArea.x + safeArea.width <= texSize.width);
3233 ASSERT(safeArea.y + safeArea.height <= texSize.height);
3234
3235 if (safeArea.width == 0 || safeArea.height == 0)
3236 {
3237 // no work to do
3238 return gl::NoError();
3239 }
3240
3241 gl::Extents safeSize(safeArea.width, safeArea.height, 1);
3242 TextureHelper11 stagingHelper;
3243 ANGLE_TRY_RESULT(
3244 createStagingTexture(textureHelper.getTextureType(), textureHelper.getFormatSet(), safeSize,
3245 StagingAccess::READ),
3246 stagingHelper);
3247
3248 TextureHelper11 resolvedTextureHelper;
3249
3250 // "srcTexture" usually points to the source texture.
3251 // For 2D multisampled textures, it points to the multisampled resolve texture.
3252 const TextureHelper11 *srcTexture = &textureHelper;
3253
3254 if (textureHelper.is2D() && textureHelper.getSampleCount() > 1)
3255 {
3256 D3D11_TEXTURE2D_DESC resolveDesc;
3257 resolveDesc.Width = static_cast<UINT>(texSize.width);
3258 resolveDesc.Height = static_cast<UINT>(texSize.height);
3259 resolveDesc.MipLevels = 1;
3260 resolveDesc.ArraySize = 1;
3261 resolveDesc.Format = textureHelper.getFormat();
3262 resolveDesc.SampleDesc.Count = 1;
3263 resolveDesc.SampleDesc.Quality = 0;
3264 resolveDesc.Usage = D3D11_USAGE_DEFAULT;
3265 resolveDesc.BindFlags = 0;
3266 resolveDesc.CPUAccessFlags = 0;
3267 resolveDesc.MiscFlags = 0;
3268
3269 ANGLE_TRY(
3270 allocateTexture(resolveDesc, textureHelper.getFormatSet(), &resolvedTextureHelper));
3271
3272 mDeviceContext->ResolveSubresource(resolvedTextureHelper.get(), 0, textureHelper.get(),
3273 sourceSubResource, textureHelper.getFormat());
3274
3275 sourceSubResource = 0;
3276 srcTexture = &resolvedTextureHelper;
3277 }
3278
3279 D3D11_BOX srcBox;
3280 srcBox.left = static_cast<UINT>(safeArea.x);
3281 srcBox.right = static_cast<UINT>(safeArea.x + safeArea.width);
3282 srcBox.top = static_cast<UINT>(safeArea.y);
3283 srcBox.bottom = static_cast<UINT>(safeArea.y + safeArea.height);
3284
3285 // Select the correct layer from a 3D attachment
3286 srcBox.front = 0;
3287 if (textureHelper.is3D())
3288 {
3289 srcBox.front = static_cast<UINT>(srcAttachment.layer());
3290 }
3291 srcBox.back = srcBox.front + 1;
3292
3293 mDeviceContext->CopySubresourceRegion(stagingHelper.get(), 0, 0, 0, 0, srcTexture->get(),
3294 sourceSubResource, &srcBox);
3295
3296 gl::Buffer *packBuffer = context->getGLState().getTargetBuffer(gl::BufferBinding::PixelPack);
3297 if (!invertTexture)
3298 {
3299 PackPixelsParams packParams(safeArea, format, type, outputPitch, pack, packBuffer, 0);
3300 return packPixels(stagingHelper, packParams, pixelsOut);
3301 }
3302
3303 // Create a new PixelPackState with reversed row order. Note that we can't just assign
3304 // 'invertTexturePack' to be 'pack' (or memcpy) since that breaks the ref counting/object
3305 // tracking in the 'pixelBuffer' members, causing leaks. Instead we must use
3306 // pixelBuffer.set() twice, which performs the addRef/release correctly
3307 gl::PixelPackState invertTexturePack;
3308 invertTexturePack.alignment = pack.alignment;
3309 invertTexturePack.reverseRowOrder = !pack.reverseRowOrder;
3310
3311 PackPixelsParams packParams(safeArea, format, type, outputPitch, invertTexturePack, packBuffer,
3312 0);
3313 gl::Error error = packPixels(stagingHelper, packParams, pixelsOut);
3314 ANGLE_TRY(error);
3315 return gl::NoError();
3316 }
3317
packPixels(const TextureHelper11 & textureHelper,const PackPixelsParams & params,uint8_t * pixelsOut)3318 gl::Error Renderer11::packPixels(const TextureHelper11 &textureHelper,
3319 const PackPixelsParams ¶ms,
3320 uint8_t *pixelsOut)
3321 {
3322 ID3D11Resource *readResource = textureHelper.get();
3323
3324 D3D11_MAPPED_SUBRESOURCE mapping;
3325 ANGLE_TRY(mapResource(readResource, 0, D3D11_MAP_READ, 0, &mapping));
3326
3327 uint8_t *source = static_cast<uint8_t *>(mapping.pData);
3328 int inputPitch = static_cast<int>(mapping.RowPitch);
3329
3330 const auto &formatInfo = textureHelper.getFormatSet();
3331 ASSERT(formatInfo.format().glInternalFormat != GL_NONE);
3332
3333 PackPixels(params, formatInfo.format(), inputPitch, source, pixelsOut);
3334
3335 mDeviceContext->Unmap(readResource, 0);
3336
3337 return gl::NoError();
3338 }
3339
blitRenderbufferRect(const gl::Context * context,const gl::Rectangle & readRectIn,const gl::Rectangle & drawRectIn,RenderTargetD3D * readRenderTarget,RenderTargetD3D * drawRenderTarget,GLenum filter,const gl::Rectangle * scissor,bool colorBlit,bool depthBlit,bool stencilBlit)3340 gl::Error Renderer11::blitRenderbufferRect(const gl::Context *context,
3341 const gl::Rectangle &readRectIn,
3342 const gl::Rectangle &drawRectIn,
3343 RenderTargetD3D *readRenderTarget,
3344 RenderTargetD3D *drawRenderTarget,
3345 GLenum filter,
3346 const gl::Rectangle *scissor,
3347 bool colorBlit,
3348 bool depthBlit,
3349 bool stencilBlit)
3350 {
3351 // Since blitRenderbufferRect is called for each render buffer that needs to be blitted,
3352 // it should never be the case that both color and depth/stencil need to be blitted at
3353 // at the same time.
3354 ASSERT(colorBlit != (depthBlit || stencilBlit));
3355
3356 RenderTarget11 *drawRenderTarget11 = GetAs<RenderTarget11>(drawRenderTarget);
3357 if (!drawRenderTarget11)
3358 {
3359 return gl::OutOfMemory()
3360 << "Failed to retrieve the internal draw render target from the draw framebuffer.";
3361 }
3362
3363 const TextureHelper11 &drawTexture = drawRenderTarget11->getTexture();
3364 unsigned int drawSubresource = drawRenderTarget11->getSubresourceIndex();
3365
3366 RenderTarget11 *readRenderTarget11 = GetAs<RenderTarget11>(readRenderTarget);
3367 if (!readRenderTarget11)
3368 {
3369 return gl::OutOfMemory()
3370 << "Failed to retrieve the internal read render target from the read framebuffer.";
3371 }
3372
3373 TextureHelper11 readTexture;
3374 unsigned int readSubresource = 0;
3375 d3d11::SharedSRV readSRV;
3376
3377 if (readRenderTarget->isMultisampled())
3378 {
3379 ANGLE_TRY_RESULT(
3380 resolveMultisampledTexture(context, readRenderTarget11, depthBlit, stencilBlit),
3381 readTexture);
3382
3383 if (!stencilBlit)
3384 {
3385 const auto &readFormatSet = readTexture.getFormatSet();
3386
3387 D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc;
3388 viewDesc.Format = readFormatSet.srvFormat;
3389 viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
3390 viewDesc.Texture2D.MipLevels = 1;
3391 viewDesc.Texture2D.MostDetailedMip = 0;
3392
3393 ANGLE_TRY(allocateResource(viewDesc, readTexture.get(), &readSRV));
3394 }
3395 }
3396 else
3397 {
3398 ASSERT(readRenderTarget11);
3399 readTexture = readRenderTarget11->getTexture();
3400 readSubresource = readRenderTarget11->getSubresourceIndex();
3401 readSRV = readRenderTarget11->getBlitShaderResourceView().makeCopy();
3402 if (!readSRV.valid())
3403 {
3404 ASSERT(depthBlit || stencilBlit);
3405 readSRV = readRenderTarget11->getShaderResourceView().makeCopy();
3406 }
3407 ASSERT(readSRV.valid());
3408 }
3409
3410 // Stencil blits don't use shaders.
3411 ASSERT(readSRV.valid() || stencilBlit);
3412
3413 const gl::Extents readSize(readRenderTarget->getWidth(), readRenderTarget->getHeight(), 1);
3414 const gl::Extents drawSize(drawRenderTarget->getWidth(), drawRenderTarget->getHeight(), 1);
3415
3416 // From the spec:
3417 // "The actual region taken from the read framebuffer is limited to the intersection of the
3418 // source buffers being transferred, which may include the color buffer selected by the read
3419 // buffer, the depth buffer, and / or the stencil buffer depending on mask."
3420 // This means negative x and y are out of bounds, and not to be read from. We handle this here
3421 // by internally scaling the read and draw rectangles.
3422 gl::Rectangle readRect = readRectIn;
3423 gl::Rectangle drawRect = drawRectIn;
3424
3425 auto flip = [](int val) { return val >= 0 ? 1 : -1; };
3426
3427 if (readRect.x > readSize.width && readRect.width < 0)
3428 {
3429 int delta = readRect.x - readSize.width;
3430 readRect.x -= delta;
3431 readRect.width += delta;
3432
3433 int drawDelta = delta * flip(drawRect.width);
3434 drawRect.x += drawDelta;
3435 drawRect.width -= drawDelta;
3436 }
3437
3438 if (readRect.y > readSize.height && readRect.height < 0)
3439 {
3440 int delta = readRect.y - readSize.height;
3441 readRect.y -= delta;
3442 readRect.height += delta;
3443
3444 int drawDelta = delta * flip(drawRect.height);
3445 drawRect.y += drawDelta;
3446 drawRect.height -= drawDelta;
3447 }
3448
3449 auto readToDrawX = [&drawRectIn, &readRectIn](int readOffset) {
3450 double readToDrawScale =
3451 static_cast<double>(drawRectIn.width) / static_cast<double>(readRectIn.width);
3452 return static_cast<int>(round(static_cast<double>(readOffset) * readToDrawScale));
3453 };
3454 if (readRect.x < 0)
3455 {
3456 int readOffset = -readRect.x;
3457 readRect.x += readOffset;
3458 readRect.width -= readOffset;
3459
3460 int drawOffset = readToDrawX(readOffset);
3461 drawRect.x += drawOffset;
3462 drawRect.width -= drawOffset;
3463 }
3464
3465 auto readToDrawY = [&drawRectIn, &readRectIn](int readOffset) {
3466 double readToDrawScale =
3467 static_cast<double>(drawRectIn.height) / static_cast<double>(readRectIn.height);
3468 return static_cast<int>(round(static_cast<double>(readOffset) * readToDrawScale));
3469 };
3470 if (readRect.y < 0)
3471 {
3472 int readOffset = -readRect.y;
3473 readRect.y += readOffset;
3474 readRect.height -= readOffset;
3475
3476 int drawOffset = readToDrawY(readOffset);
3477 drawRect.y += drawOffset;
3478 drawRect.height -= drawOffset;
3479 }
3480
3481 if (readRect.x1() < 0)
3482 {
3483 int readOffset = -readRect.x1();
3484 readRect.width += readOffset;
3485
3486 int drawOffset = readToDrawX(readOffset);
3487 drawRect.width += drawOffset;
3488 }
3489
3490 if (readRect.y1() < 0)
3491 {
3492 int readOffset = -readRect.y1();
3493 readRect.height += readOffset;
3494
3495 int drawOffset = readToDrawY(readOffset);
3496 drawRect.height += drawOffset;
3497 }
3498
3499 if (readRect.x1() > readSize.width)
3500 {
3501 int delta = readRect.x1() - readSize.width;
3502 readRect.width -= delta;
3503 drawRect.width -= delta * flip(drawRect.width);
3504 }
3505
3506 if (readRect.y1() > readSize.height)
3507 {
3508 int delta = readRect.y1() - readSize.height;
3509 readRect.height -= delta;
3510 drawRect.height -= delta * flip(drawRect.height);
3511 }
3512
3513 bool scissorNeeded = scissor && gl::ClipRectangle(drawRect, *scissor, nullptr);
3514
3515 const auto &destFormatInfo =
3516 gl::GetSizedInternalFormatInfo(drawRenderTarget->getInternalFormat());
3517 const auto &srcFormatInfo =
3518 gl::GetSizedInternalFormatInfo(readRenderTarget->getInternalFormat());
3519 const auto &formatSet = drawRenderTarget11->getFormatSet();
3520 const auto &nativeFormat = formatSet.format();
3521
3522 // Some blits require masking off emulated texture channels. eg: from RGBA8 to RGB8, we
3523 // emulate RGB8 with RGBA8, so we need to mask off the alpha channel when we copy.
3524
3525 gl::Color<bool> colorMask;
3526 colorMask.red =
3527 (srcFormatInfo.redBits > 0) && (destFormatInfo.redBits == 0) && (nativeFormat.redBits > 0);
3528 colorMask.green = (srcFormatInfo.greenBits > 0) && (destFormatInfo.greenBits == 0) &&
3529 (nativeFormat.greenBits > 0);
3530 colorMask.blue = (srcFormatInfo.blueBits > 0) && (destFormatInfo.blueBits == 0) &&
3531 (nativeFormat.blueBits > 0);
3532 colorMask.alpha = (srcFormatInfo.alphaBits > 0) && (destFormatInfo.alphaBits == 0) &&
3533 (nativeFormat.alphaBits > 0);
3534
3535 // We only currently support masking off the alpha channel.
3536 bool colorMaskingNeeded = colorMask.alpha;
3537 ASSERT(!colorMask.red && !colorMask.green && !colorMask.blue);
3538
3539 bool wholeBufferCopy = !scissorNeeded && !colorMaskingNeeded && readRect.x == 0 &&
3540 readRect.width == readSize.width && readRect.y == 0 &&
3541 readRect.height == readSize.height && drawRect.x == 0 &&
3542 drawRect.width == drawSize.width && drawRect.y == 0 &&
3543 drawRect.height == drawSize.height;
3544
3545 bool stretchRequired = readRect.width != drawRect.width || readRect.height != drawRect.height;
3546
3547 bool flipRequired =
3548 readRect.width < 0 || readRect.height < 0 || drawRect.width < 0 || drawRect.height < 0;
3549
3550 bool outOfBounds = readRect.x < 0 || readRect.x + readRect.width > readSize.width ||
3551 readRect.y < 0 || readRect.y + readRect.height > readSize.height ||
3552 drawRect.x < 0 || drawRect.x + drawRect.width > drawSize.width ||
3553 drawRect.y < 0 || drawRect.y + drawRect.height > drawSize.height;
3554
3555 bool partialDSBlit =
3556 (nativeFormat.depthBits > 0 && depthBlit) != (nativeFormat.stencilBits > 0 && stencilBlit);
3557
3558 if (readRenderTarget11->getFormatSet().formatID ==
3559 drawRenderTarget11->getFormatSet().formatID &&
3560 !stretchRequired && !outOfBounds && !flipRequired && !partialDSBlit &&
3561 !colorMaskingNeeded && (!(depthBlit || stencilBlit) || wholeBufferCopy))
3562 {
3563 UINT dstX = drawRect.x;
3564 UINT dstY = drawRect.y;
3565
3566 D3D11_BOX readBox;
3567 readBox.left = readRect.x;
3568 readBox.right = readRect.x + readRect.width;
3569 readBox.top = readRect.y;
3570 readBox.bottom = readRect.y + readRect.height;
3571 readBox.front = 0;
3572 readBox.back = 1;
3573
3574 if (scissorNeeded)
3575 {
3576 // drawRect is guaranteed to have positive width and height because stretchRequired is
3577 // false.
3578 ASSERT(drawRect.width >= 0 || drawRect.height >= 0);
3579
3580 if (drawRect.x < scissor->x)
3581 {
3582 dstX = scissor->x;
3583 readBox.left += (scissor->x - drawRect.x);
3584 }
3585 if (drawRect.y < scissor->y)
3586 {
3587 dstY = scissor->y;
3588 readBox.top += (scissor->y - drawRect.y);
3589 }
3590 if (drawRect.x + drawRect.width > scissor->x + scissor->width)
3591 {
3592 readBox.right -= ((drawRect.x + drawRect.width) - (scissor->x + scissor->width));
3593 }
3594 if (drawRect.y + drawRect.height > scissor->y + scissor->height)
3595 {
3596 readBox.bottom -= ((drawRect.y + drawRect.height) - (scissor->y + scissor->height));
3597 }
3598 }
3599
3600 // D3D11 needs depth-stencil CopySubresourceRegions to have a NULL pSrcBox
3601 // We also require complete framebuffer copies for depth-stencil blit.
3602 D3D11_BOX *pSrcBox = wholeBufferCopy ? nullptr : &readBox;
3603
3604 mDeviceContext->CopySubresourceRegion(drawTexture.get(), drawSubresource, dstX, dstY, 0,
3605 readTexture.get(), readSubresource, pSrcBox);
3606 }
3607 else
3608 {
3609 gl::Box readArea(readRect.x, readRect.y, 0, readRect.width, readRect.height, 1);
3610 gl::Box drawArea(drawRect.x, drawRect.y, 0, drawRect.width, drawRect.height, 1);
3611
3612 if (depthBlit && stencilBlit)
3613 {
3614 ANGLE_TRY(mBlit->copyDepthStencil(readTexture, readSubresource, readArea, readSize,
3615 drawTexture, drawSubresource, drawArea, drawSize,
3616 scissor));
3617 }
3618 else if (depthBlit)
3619 {
3620 const d3d11::DepthStencilView &drawDSV = drawRenderTarget11->getDepthStencilView();
3621 ASSERT(readSRV.valid());
3622 ANGLE_TRY(mBlit->copyDepth(context, readSRV, readArea, readSize, drawDSV, drawArea,
3623 drawSize, scissor));
3624 }
3625 else if (stencilBlit)
3626 {
3627 ANGLE_TRY(mBlit->copyStencil(context, readTexture, readSubresource, readArea, readSize,
3628 drawTexture, drawSubresource, drawArea, drawSize,
3629 scissor));
3630 }
3631 else
3632 {
3633 const d3d11::RenderTargetView &drawRTV = drawRenderTarget11->getRenderTargetView();
3634
3635 // We don't currently support masking off any other channel than alpha
3636 bool maskOffAlpha = colorMaskingNeeded && colorMask.alpha;
3637 ASSERT(readSRV.valid());
3638 ANGLE_TRY(mBlit->copyTexture(context, readSRV, readArea, readSize, srcFormatInfo.format,
3639 drawRTV, drawArea, drawSize, scissor,
3640 destFormatInfo.format, GL_NONE, filter, maskOffAlpha,
3641 false, false));
3642 }
3643 }
3644
3645 return gl::NoError();
3646 }
3647
isES3Capable() const3648 bool Renderer11::isES3Capable() const
3649 {
3650 return (d3d11_gl::GetMaximumClientVersion(mRenderer11DeviceCaps.featureLevel).major > 2);
3651 }
3652
getRendererClass() const3653 RendererClass Renderer11::getRendererClass() const
3654 {
3655 return RENDERER_D3D11;
3656 }
3657
onSwap()3658 void Renderer11::onSwap()
3659 {
3660 // Send histogram updates every half hour
3661 const double kHistogramUpdateInterval = 30 * 60;
3662
3663 auto *platform = ANGLEPlatformCurrent();
3664 const double currentTime = platform->monotonicallyIncreasingTime(platform);
3665 const double timeSinceLastUpdate = currentTime - mLastHistogramUpdateTime;
3666
3667 if (timeSinceLastUpdate > kHistogramUpdateInterval)
3668 {
3669 updateHistograms();
3670 mLastHistogramUpdateTime = currentTime;
3671 }
3672 }
3673
updateHistograms()3674 void Renderer11::updateHistograms()
3675 {
3676 // Update the buffer CPU memory histogram
3677 {
3678 size_t sizeSum = 0;
3679 for (const Buffer11 *buffer : mAliveBuffers)
3680 {
3681 sizeSum += buffer->getTotalCPUBufferMemoryBytes();
3682 }
3683 const int kOneMegaByte = 1024 * 1024;
3684 ANGLE_HISTOGRAM_MEMORY_MB("GPU.ANGLE.Buffer11CPUMemoryMB",
3685 static_cast<int>(sizeSum) / kOneMegaByte);
3686 }
3687 }
3688
onBufferCreate(const Buffer11 * created)3689 void Renderer11::onBufferCreate(const Buffer11 *created)
3690 {
3691 mAliveBuffers.insert(created);
3692 }
3693
onBufferDelete(const Buffer11 * deleted)3694 void Renderer11::onBufferDelete(const Buffer11 *deleted)
3695 {
3696 mAliveBuffers.erase(deleted);
3697 }
3698
resolveMultisampledTexture(const gl::Context * context,RenderTarget11 * renderTarget,bool depth,bool stencil)3699 gl::ErrorOrResult<TextureHelper11> Renderer11::resolveMultisampledTexture(
3700 const gl::Context *context,
3701 RenderTarget11 *renderTarget,
3702 bool depth,
3703 bool stencil)
3704 {
3705 if (depth && !stencil)
3706 {
3707 return mBlit->resolveDepth(context, renderTarget);
3708 }
3709
3710 if (stencil)
3711 {
3712 return mBlit->resolveStencil(context, renderTarget, depth);
3713 }
3714
3715 const auto &formatSet = renderTarget->getFormatSet();
3716
3717 ASSERT(renderTarget->isMultisampled());
3718 const d3d11::SharedSRV &sourceSRV = renderTarget->getShaderResourceView();
3719 D3D11_SHADER_RESOURCE_VIEW_DESC sourceSRVDesc;
3720 sourceSRV.get()->GetDesc(&sourceSRVDesc);
3721 ASSERT(sourceSRVDesc.ViewDimension == D3D_SRV_DIMENSION_TEXTURE2DMS);
3722
3723 if (!mCachedResolveTexture.valid() ||
3724 mCachedResolveTexture.getExtents().width != renderTarget->getWidth() ||
3725 mCachedResolveTexture.getExtents().height != renderTarget->getHeight() ||
3726 mCachedResolveTexture.getFormat() != formatSet.texFormat)
3727 {
3728 D3D11_TEXTURE2D_DESC resolveDesc;
3729 resolveDesc.Width = renderTarget->getWidth();
3730 resolveDesc.Height = renderTarget->getHeight();
3731 resolveDesc.MipLevels = 1;
3732 resolveDesc.ArraySize = 1;
3733 resolveDesc.Format = formatSet.texFormat;
3734 resolveDesc.SampleDesc.Count = 1;
3735 resolveDesc.SampleDesc.Quality = 0;
3736 resolveDesc.Usage = D3D11_USAGE_DEFAULT;
3737 resolveDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
3738 resolveDesc.CPUAccessFlags = 0;
3739 resolveDesc.MiscFlags = 0;
3740
3741 ANGLE_TRY(allocateTexture(resolveDesc, formatSet, &mCachedResolveTexture));
3742 }
3743
3744 mDeviceContext->ResolveSubresource(mCachedResolveTexture.get(), 0,
3745 renderTarget->getTexture().get(),
3746 renderTarget->getSubresourceIndex(), formatSet.texFormat);
3747 return mCachedResolveTexture;
3748 }
3749
getLUID(LUID * adapterLuid) const3750 bool Renderer11::getLUID(LUID *adapterLuid) const
3751 {
3752 adapterLuid->HighPart = 0;
3753 adapterLuid->LowPart = 0;
3754
3755 if (!mDxgiAdapter)
3756 {
3757 return false;
3758 }
3759
3760 DXGI_ADAPTER_DESC adapterDesc;
3761 if (FAILED(mDxgiAdapter->GetDesc(&adapterDesc)))
3762 {
3763 return false;
3764 }
3765
3766 *adapterLuid = adapterDesc.AdapterLuid;
3767 return true;
3768 }
3769
getVertexConversionType(gl::VertexFormatType vertexFormatType) const3770 VertexConversionType Renderer11::getVertexConversionType(
3771 gl::VertexFormatType vertexFormatType) const
3772 {
3773 return d3d11::GetVertexFormatInfo(vertexFormatType, mRenderer11DeviceCaps.featureLevel)
3774 .conversionType;
3775 }
3776
getVertexComponentType(gl::VertexFormatType vertexFormatType) const3777 GLenum Renderer11::getVertexComponentType(gl::VertexFormatType vertexFormatType) const
3778 {
3779 const auto &format =
3780 d3d11::GetVertexFormatInfo(vertexFormatType, mRenderer11DeviceCaps.featureLevel);
3781 return d3d11::GetComponentType(format.nativeFormat);
3782 }
3783
getVertexSpaceRequired(const gl::VertexAttribute & attrib,const gl::VertexBinding & binding,GLsizei count,GLsizei instances) const3784 gl::ErrorOrResult<unsigned int> Renderer11::getVertexSpaceRequired(
3785 const gl::VertexAttribute &attrib,
3786 const gl::VertexBinding &binding,
3787 GLsizei count,
3788 GLsizei instances) const
3789 {
3790 if (!attrib.enabled)
3791 {
3792 return 16u;
3793 }
3794
3795 unsigned int elementCount = 0;
3796 const unsigned int divisor = binding.getDivisor();
3797 if (instances == 0 || divisor == 0)
3798 {
3799 elementCount = count;
3800 }
3801 else
3802 {
3803 // Round up to divisor, if possible
3804 elementCount = UnsignedCeilDivide(static_cast<unsigned int>(instances), divisor);
3805 }
3806
3807 gl::VertexFormatType formatType = gl::GetVertexFormatType(attrib);
3808 const D3D_FEATURE_LEVEL featureLevel = mRenderer11DeviceCaps.featureLevel;
3809 const d3d11::VertexFormat &vertexFormatInfo =
3810 d3d11::GetVertexFormatInfo(formatType, featureLevel);
3811 const d3d11::DXGIFormatSize &dxgiFormatInfo =
3812 d3d11::GetDXGIFormatSizeInfo(vertexFormatInfo.nativeFormat);
3813 unsigned int elementSize = dxgiFormatInfo.pixelBytes;
3814 if (elementSize > std::numeric_limits<unsigned int>::max() / elementCount)
3815 {
3816 return gl::OutOfMemory() << "New vertex buffer size would result in an overflow.";
3817 }
3818
3819 return elementSize * elementCount;
3820 }
3821
generateCaps(gl::Caps * outCaps,gl::TextureCapsMap * outTextureCaps,gl::Extensions * outExtensions,gl::Limitations * outLimitations) const3822 void Renderer11::generateCaps(gl::Caps *outCaps,
3823 gl::TextureCapsMap *outTextureCaps,
3824 gl::Extensions *outExtensions,
3825 gl::Limitations *outLimitations) const
3826 {
3827 d3d11_gl::GenerateCaps(mDevice, mDeviceContext, mRenderer11DeviceCaps, getWorkarounds(),
3828 outCaps, outTextureCaps, outExtensions, outLimitations);
3829 }
3830
generateWorkarounds() const3831 angle::WorkaroundsD3D Renderer11::generateWorkarounds() const
3832 {
3833 return d3d11::GenerateWorkarounds(mRenderer11DeviceCaps, mAdapterDescription);
3834 }
3835
createEGLDevice()3836 DeviceImpl *Renderer11::createEGLDevice()
3837 {
3838 return new DeviceD3D(EGL_D3D11_DEVICE_ANGLE, mDevice);
3839 }
3840
createContext(const gl::ContextState & state)3841 ContextImpl *Renderer11::createContext(const gl::ContextState &state)
3842 {
3843 return new Context11(state, this);
3844 }
3845
createDefaultFramebuffer(const gl::FramebufferState & state)3846 FramebufferImpl *Renderer11::createDefaultFramebuffer(const gl::FramebufferState &state)
3847 {
3848 return new Framebuffer11(state, this);
3849 }
3850
getScratchMemoryBuffer(size_t requestedSize,angle::MemoryBuffer ** bufferOut)3851 gl::Error Renderer11::getScratchMemoryBuffer(size_t requestedSize, angle::MemoryBuffer **bufferOut)
3852 {
3853 if (!mScratchMemoryBuffer.get(requestedSize, bufferOut))
3854 {
3855 return gl::OutOfMemory() << "Failed to allocate internal buffer.";
3856 }
3857 return gl::NoError();
3858 }
3859
getMaxSupportedESVersion() const3860 gl::Version Renderer11::getMaxSupportedESVersion() const
3861 {
3862 return d3d11_gl::GetMaximumClientVersion(mRenderer11DeviceCaps.featureLevel);
3863 }
3864
getAnnotator()3865 gl::DebugAnnotator *Renderer11::getAnnotator()
3866 {
3867 return mAnnotator;
3868 }
3869
applyComputeShader(const gl::Context * context)3870 gl::Error Renderer11::applyComputeShader(const gl::Context *context)
3871 {
3872 ANGLE_TRY(ensureHLSLCompilerInitialized());
3873
3874 const auto &glState = context->getGLState();
3875 ProgramD3D *programD3D = GetImplAs<ProgramD3D>(glState.getProgram());
3876
3877 ShaderExecutableD3D *computeExe = nullptr;
3878 ANGLE_TRY(programD3D->getComputeExecutable(&computeExe));
3879 ASSERT(computeExe != nullptr);
3880
3881 mStateManager.setComputeShader(&GetAs<ShaderExecutable11>(computeExe)->getComputeShader());
3882 ANGLE_TRY(mStateManager.applyComputeUniforms(programD3D));
3883
3884 return gl::NoError();
3885 }
3886
dispatchCompute(const gl::Context * context,GLuint numGroupsX,GLuint numGroupsY,GLuint numGroupsZ)3887 gl::Error Renderer11::dispatchCompute(const gl::Context *context,
3888 GLuint numGroupsX,
3889 GLuint numGroupsY,
3890 GLuint numGroupsZ)
3891 {
3892 ANGLE_TRY(mStateManager.updateStateForCompute(context, numGroupsX, numGroupsY, numGroupsZ));
3893 ANGLE_TRY(applyComputeShader(context));
3894
3895 mDeviceContext->Dispatch(numGroupsX, numGroupsY, numGroupsZ);
3896
3897 return gl::NoError();
3898 }
3899
createStagingTexture(ResourceType textureType,const d3d11::Format & formatSet,const gl::Extents & size,StagingAccess readAndWriteAccess)3900 gl::ErrorOrResult<TextureHelper11> Renderer11::createStagingTexture(
3901 ResourceType textureType,
3902 const d3d11::Format &formatSet,
3903 const gl::Extents &size,
3904 StagingAccess readAndWriteAccess)
3905 {
3906 if (textureType == ResourceType::Texture2D)
3907 {
3908 D3D11_TEXTURE2D_DESC stagingDesc;
3909 stagingDesc.Width = size.width;
3910 stagingDesc.Height = size.height;
3911 stagingDesc.MipLevels = 1;
3912 stagingDesc.ArraySize = 1;
3913 stagingDesc.Format = formatSet.texFormat;
3914 stagingDesc.SampleDesc.Count = 1;
3915 stagingDesc.SampleDesc.Quality = 0;
3916 stagingDesc.Usage = D3D11_USAGE_STAGING;
3917 stagingDesc.BindFlags = 0;
3918 stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
3919 stagingDesc.MiscFlags = 0;
3920
3921 if (readAndWriteAccess == StagingAccess::READ_WRITE)
3922 {
3923 stagingDesc.CPUAccessFlags |= D3D11_CPU_ACCESS_WRITE;
3924 }
3925
3926 TextureHelper11 stagingTex;
3927 ANGLE_TRY(allocateTexture(stagingDesc, formatSet, &stagingTex));
3928 return stagingTex;
3929 }
3930 ASSERT(textureType == ResourceType::Texture3D);
3931
3932 D3D11_TEXTURE3D_DESC stagingDesc;
3933 stagingDesc.Width = size.width;
3934 stagingDesc.Height = size.height;
3935 stagingDesc.Depth = 1;
3936 stagingDesc.MipLevels = 1;
3937 stagingDesc.Format = formatSet.texFormat;
3938 stagingDesc.Usage = D3D11_USAGE_STAGING;
3939 stagingDesc.BindFlags = 0;
3940 stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
3941 stagingDesc.MiscFlags = 0;
3942
3943 TextureHelper11 stagingTex;
3944 ANGLE_TRY(allocateTexture(stagingDesc, formatSet, &stagingTex));
3945 return stagingTex;
3946 }
3947
allocateTexture(const D3D11_TEXTURE2D_DESC & desc,const d3d11::Format & format,const D3D11_SUBRESOURCE_DATA * initData,TextureHelper11 * textureOut)3948 gl::Error Renderer11::allocateTexture(const D3D11_TEXTURE2D_DESC &desc,
3949 const d3d11::Format &format,
3950 const D3D11_SUBRESOURCE_DATA *initData,
3951 TextureHelper11 *textureOut)
3952 {
3953 d3d11::Texture2D texture;
3954 ANGLE_TRY(mResourceManager11.allocate(this, &desc, initData, &texture));
3955 textureOut->init(std::move(texture), desc, format);
3956 return gl::NoError();
3957 }
3958
allocateTexture(const D3D11_TEXTURE3D_DESC & desc,const d3d11::Format & format,const D3D11_SUBRESOURCE_DATA * initData,TextureHelper11 * textureOut)3959 gl::Error Renderer11::allocateTexture(const D3D11_TEXTURE3D_DESC &desc,
3960 const d3d11::Format &format,
3961 const D3D11_SUBRESOURCE_DATA *initData,
3962 TextureHelper11 *textureOut)
3963 {
3964 d3d11::Texture3D texture;
3965 ANGLE_TRY(mResourceManager11.allocate(this, &desc, initData, &texture));
3966 textureOut->init(std::move(texture), desc, format);
3967 return gl::NoError();
3968 }
3969
getBlendState(const d3d11::BlendStateKey & key,const d3d11::BlendState ** outBlendState)3970 gl::Error Renderer11::getBlendState(const d3d11::BlendStateKey &key,
3971 const d3d11::BlendState **outBlendState)
3972 {
3973 return mStateCache.getBlendState(this, key, outBlendState);
3974 }
3975
getRasterizerState(const gl::RasterizerState & rasterState,bool scissorEnabled,ID3D11RasterizerState ** outRasterizerState)3976 gl::Error Renderer11::getRasterizerState(const gl::RasterizerState &rasterState,
3977 bool scissorEnabled,
3978 ID3D11RasterizerState **outRasterizerState)
3979 {
3980 return mStateCache.getRasterizerState(this, rasterState, scissorEnabled, outRasterizerState);
3981 }
3982
getDepthStencilState(const gl::DepthStencilState & dsState,const d3d11::DepthStencilState ** outDSState)3983 gl::Error Renderer11::getDepthStencilState(const gl::DepthStencilState &dsState,
3984 const d3d11::DepthStencilState **outDSState)
3985 {
3986 return mStateCache.getDepthStencilState(this, dsState, outDSState);
3987 }
3988
getSamplerState(const gl::SamplerState & samplerState,ID3D11SamplerState ** outSamplerState)3989 gl::Error Renderer11::getSamplerState(const gl::SamplerState &samplerState,
3990 ID3D11SamplerState **outSamplerState)
3991 {
3992 return mStateCache.getSamplerState(this, samplerState, outSamplerState);
3993 }
3994
clearRenderTarget(RenderTargetD3D * renderTarget,const gl::ColorF & clearColorValue,const float clearDepthValue,const unsigned int clearStencilValue)3995 gl::Error Renderer11::clearRenderTarget(RenderTargetD3D *renderTarget,
3996 const gl::ColorF &clearColorValue,
3997 const float clearDepthValue,
3998 const unsigned int clearStencilValue)
3999 {
4000 RenderTarget11 *rt11 = GetAs<RenderTarget11>(renderTarget);
4001
4002 if (rt11->getFormatSet().dsvFormat != DXGI_FORMAT_UNKNOWN)
4003 {
4004 ASSERT(rt11->getDepthStencilView().valid());
4005
4006 const auto &format = rt11->getFormatSet();
4007 const UINT clearFlags = (format.format().depthBits > 0 ? D3D11_CLEAR_DEPTH : 0) |
4008 (format.format().stencilBits ? D3D11_CLEAR_STENCIL : 0);
4009 mDeviceContext->ClearDepthStencilView(rt11->getDepthStencilView().get(), clearFlags,
4010 clearDepthValue,
4011 static_cast<UINT8>(clearStencilValue));
4012 return gl::NoError();
4013 }
4014
4015 ASSERT(rt11->getRenderTargetView().valid());
4016 ID3D11RenderTargetView *rtv = rt11->getRenderTargetView().get();
4017
4018 // There are complications with some types of RTV and FL 9_3 with ClearRenderTargetView.
4019 // See https://msdn.microsoft.com/en-us/library/windows/desktop/ff476388(v=vs.85).aspx
4020 ASSERT(mRenderer11DeviceCaps.featureLevel > D3D_FEATURE_LEVEL_9_3 || !IsArrayRTV(rtv));
4021
4022 const auto &d3d11Format = rt11->getFormatSet();
4023 const auto &glFormat = gl::GetSizedInternalFormatInfo(renderTarget->getInternalFormat());
4024
4025 gl::ColorF safeClearColor = clearColorValue;
4026
4027 if (d3d11Format.format().alphaBits > 0 && glFormat.alphaBits == 0)
4028 {
4029 safeClearColor.alpha = 1.0f;
4030 }
4031
4032 mDeviceContext->ClearRenderTargetView(rtv, &safeClearColor.red);
4033 return gl::NoError();
4034 }
4035
canSelectViewInVertexShader() const4036 bool Renderer11::canSelectViewInVertexShader() const
4037 {
4038 return !getWorkarounds().selectViewInGeometryShader &&
4039 getRenderer11DeviceCaps().supportsVpRtIndexWriteFromVertexShader;
4040 }
4041
mapResource(ID3D11Resource * resource,UINT subResource,D3D11_MAP mapType,UINT mapFlags,D3D11_MAPPED_SUBRESOURCE * mappedResource)4042 gl::Error Renderer11::mapResource(ID3D11Resource *resource,
4043 UINT subResource,
4044 D3D11_MAP mapType,
4045 UINT mapFlags,
4046 D3D11_MAPPED_SUBRESOURCE *mappedResource)
4047 {
4048 HRESULT hr = mDeviceContext->Map(resource, subResource, mapType, mapFlags, mappedResource);
4049 if (FAILED(hr))
4050 {
4051 if (d3d11::isDeviceLostError(hr))
4052 {
4053 this->notifyDeviceLost();
4054 }
4055
4056 // Note: gl::OutOfMemory is used instead of gl::InternalError to avoid requiring
4057 // additional context queries. This is needed as gl::InternalError corresponds to
4058 // GL_INVALID_OPERATION, which does not uniquely identify a device reset error.
4059 return gl::OutOfMemory() << "Failed to map D3D11 resource." << gl::FmtHR(hr);
4060 }
4061
4062 return gl::NoError();
4063 }
4064
markTransformFeedbackUsage(const gl::Context * context)4065 gl::Error Renderer11::markTransformFeedbackUsage(const gl::Context *context)
4066 {
4067 const gl::State &glState = context->getGLState();
4068 const gl::TransformFeedback *transformFeedback = glState.getCurrentTransformFeedback();
4069 for (size_t i = 0; i < transformFeedback->getIndexedBufferCount(); i++)
4070 {
4071 const gl::OffsetBindingPointer<gl::Buffer> &binding =
4072 transformFeedback->getIndexedBuffer(i);
4073 if (binding.get() != nullptr)
4074 {
4075 BufferD3D *bufferD3D = GetImplAs<BufferD3D>(binding.get());
4076 ANGLE_TRY(bufferD3D->markTransformFeedbackUsage(context));
4077 }
4078 }
4079
4080 return gl::NoError();
4081 }
4082
onDirtyUniformBlockBinding(GLuint)4083 void Renderer11::onDirtyUniformBlockBinding(GLuint /*uniformBlockIndex*/)
4084 {
4085 mStateManager.invalidateProgramUniformBuffers();
4086 }
4087
4088 } // namespace rx
4089