1 //
2 // Copyright 2012 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_utils.h: Conversion functions and other utility routines
8 // specific to the D3D11 renderer.
9
10 #ifndef LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_UTILS_H_
11 #define LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_UTILS_H_
12
13 #include <array>
14 #include <functional>
15 #include <vector>
16
17 #include "common/Color.h"
18
19 #include "libANGLE/Caps.h"
20 #include "libANGLE/Error.h"
21 #include "libANGLE/renderer/d3d/RendererD3D.h"
22 #include "libANGLE/renderer/d3d/d3d11/ResourceManager11.h"
23 #include "libANGLE/renderer/d3d/d3d11/texture_format_table.h"
24
25 namespace gl
26 {
27 class FramebufferAttachment;
28 }
29
30 namespace rx
31 {
32 class Context11;
33 class Renderer11;
34 class RenderTarget11;
35 struct Renderer11DeviceCaps;
36
37 using RTVArray = std::array<ID3D11RenderTargetView *, gl::IMPLEMENTATION_MAX_DRAW_BUFFERS>;
38
39 namespace gl_d3d11
40 {
41
42 D3D11_BLEND ConvertBlendFunc(GLenum glBlend, bool isAlpha);
43 D3D11_BLEND_OP ConvertBlendOp(GLenum glBlendOp);
44 UINT8 ConvertColorMask(bool maskRed, bool maskGreen, bool maskBlue, bool maskAlpha);
45
46 D3D11_CULL_MODE ConvertCullMode(bool cullEnabled, gl::CullFaceMode cullMode);
47
48 D3D11_COMPARISON_FUNC ConvertComparison(GLenum comparison);
49 D3D11_DEPTH_WRITE_MASK ConvertDepthMask(bool depthWriteEnabled);
50 UINT8 ConvertStencilMask(GLuint stencilmask);
51 D3D11_STENCIL_OP ConvertStencilOp(GLenum stencilOp);
52
53 D3D11_FILTER ConvertFilter(GLenum minFilter,
54 GLenum magFilter,
55 float maxAnisotropy,
56 GLenum comparisonMode);
57 D3D11_TEXTURE_ADDRESS_MODE ConvertTextureWrap(GLenum wrap);
58 UINT ConvertMaxAnisotropy(float maxAnisotropy, D3D_FEATURE_LEVEL featureLevel);
59
60 D3D11_QUERY ConvertQueryType(gl::QueryType type);
61
62 UINT8 GetColorMask(const gl::InternalFormat &formatInfo);
63
64 } // namespace gl_d3d11
65
66 namespace d3d11_gl
67 {
68
69 unsigned int GetReservedVertexUniformVectors(D3D_FEATURE_LEVEL featureLevel);
70
71 unsigned int GetReservedFragmentUniformVectors(D3D_FEATURE_LEVEL featureLevel);
72
73 gl::Version GetMaximumClientVersion(D3D_FEATURE_LEVEL featureLevel);
74 void GenerateCaps(ID3D11Device *device,
75 ID3D11DeviceContext *deviceContext,
76 const Renderer11DeviceCaps &renderer11DeviceCaps,
77 const angle::FeaturesD3D &features,
78 const char *description,
79 gl::Caps *caps,
80 gl::TextureCapsMap *textureCapsMap,
81 gl::Extensions *extensions,
82 gl::Limitations *limitations);
83
84 D3D_FEATURE_LEVEL GetMinimumFeatureLevelForES31();
85
86 } // namespace d3d11_gl
87
88 namespace d3d11
89 {
90
91 enum ANGLED3D11DeviceType
92 {
93 ANGLE_D3D11_DEVICE_TYPE_UNKNOWN,
94 ANGLE_D3D11_DEVICE_TYPE_HARDWARE,
95 ANGLE_D3D11_DEVICE_TYPE_SOFTWARE_REF_OR_NULL,
96 ANGLE_D3D11_DEVICE_TYPE_WARP,
97 };
98
99 ANGLED3D11DeviceType GetDeviceType(ID3D11Device *device);
100
101 void MakeValidSize(bool isImage,
102 DXGI_FORMAT format,
103 GLsizei *requestWidth,
104 GLsizei *requestHeight,
105 int *levelOffset);
106
107 angle::Result GenerateInitialTextureData(
108 const gl::Context *context,
109 GLint internalFormat,
110 const Renderer11DeviceCaps &renderer11DeviceCaps,
111 GLuint width,
112 GLuint height,
113 GLuint depth,
114 GLuint mipLevels,
115 gl::TexLevelArray<D3D11_SUBRESOURCE_DATA> *outSubresourceData);
116
117 UINT GetPrimitiveRestartIndex();
118
119 struct PositionTexCoordVertex
120 {
121 float x, y;
122 float u, v;
123 };
124 void SetPositionTexCoordVertex(PositionTexCoordVertex *vertex, float x, float y, float u, float v);
125
126 struct PositionLayerTexCoord3DVertex
127 {
128 float x, y;
129 unsigned int l;
130 float u, v, s;
131 };
132 void SetPositionLayerTexCoord3DVertex(PositionLayerTexCoord3DVertex *vertex,
133 float x,
134 float y,
135 unsigned int layer,
136 float u,
137 float v,
138 float s);
139
140 struct PositionVertex
141 {
142 float x, y, z, w;
143 };
144
145 struct BlendStateKey final
146 {
147 // This will zero-initialize the struct, including padding.
148 BlendStateKey();
149 BlendStateKey(const BlendStateKey &other);
150
151 gl::BlendStateArray blendStateArray;
152
153 uint8_t rtvMasks[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT];
154
155 // Use two 16-bit ints to round the struct nicely.
156 uint16_t rtvMax;
157 uint16_t sampleAlphaToCoverage;
158 };
159
160 bool operator==(const BlendStateKey &a, const BlendStateKey &b);
161 bool operator!=(const BlendStateKey &a, const BlendStateKey &b);
162
163 struct RasterizerStateKey final
164 {
165 // This will zero-initialize the struct, including padding.
166 RasterizerStateKey();
167
168 gl::RasterizerState rasterizerState;
169
170 // Use a 32-bit int to round the struct nicely.
171 uint32_t scissorEnabled;
172 };
173
174 bool operator==(const RasterizerStateKey &a, const RasterizerStateKey &b);
175 bool operator!=(const RasterizerStateKey &a, const RasterizerStateKey &b);
176
177 template <typename outType>
DynamicCastComObject(IUnknown * object)178 outType *DynamicCastComObject(IUnknown *object)
179 {
180 outType *outObject = nullptr;
181 HRESULT result =
182 object->QueryInterface(__uuidof(outType), reinterpret_cast<void **>(&outObject));
183 if (SUCCEEDED(result))
184 {
185 return outObject;
186 }
187 else
188 {
189 SafeRelease(outObject);
190 return nullptr;
191 }
192 }
193
194 template <typename outType>
DynamicCastComObjectToComPtr(IUnknown * object)195 angle::ComPtr<outType> DynamicCastComObjectToComPtr(IUnknown *object)
196 {
197 angle::ComPtr<outType> outObject;
198 const HRESULT hr = object->QueryInterface(IID_PPV_ARGS(&outObject));
199 if (SUCCEEDED(hr))
200 {
201 return outObject;
202 }
203 else
204 {
205 return nullptr;
206 }
207 }
208
isDeviceLostError(HRESULT errorCode)209 inline bool isDeviceLostError(HRESULT errorCode)
210 {
211 switch (errorCode)
212 {
213 case DXGI_ERROR_DEVICE_HUNG:
214 case DXGI_ERROR_DEVICE_REMOVED:
215 case DXGI_ERROR_DEVICE_RESET:
216 case DXGI_ERROR_DRIVER_INTERNAL_ERROR:
217 case DXGI_ERROR_NOT_CURRENTLY_AVAILABLE:
218 return true;
219 default:
220 return false;
221 }
222 }
223
224 template <ResourceType ResourceT>
225 class LazyResource : angle::NonCopyable
226 {
227 public:
LazyResource()228 constexpr LazyResource() : mResource() {}
~LazyResource()229 virtual ~LazyResource() {}
230
231 virtual angle::Result resolve(d3d::Context *context, Renderer11 *renderer) = 0;
reset()232 void reset() { mResource.reset(); }
get()233 GetD3D11Type<ResourceT> *get() const
234 {
235 ASSERT(mResource.valid());
236 return mResource.get();
237 }
238
getObj()239 const Resource11<GetD3D11Type<ResourceT>> &getObj() const { return mResource; }
240
241 protected:
LazyResource(LazyResource && other)242 LazyResource(LazyResource &&other) : mResource(std::move(other.mResource)) {}
243
244 // Specialized in the cpp file to avoid MSVS/Clang specific code.
245 angle::Result resolveImpl(d3d::Context *context,
246 Renderer11 *renderer,
247 const GetDescType<ResourceT> &desc,
248 GetInitDataType<ResourceT> *initData,
249 const char *name);
250
251 Resource11<GetD3D11Type<ResourceT>> mResource;
252 };
253
254 template <typename D3D11ShaderType>
255 class LazyShader final : public LazyResource<GetResourceTypeFromD3D11<D3D11ShaderType>()>
256 {
257 public:
258 // All parameters must be constexpr. Not supported in VS2013.
LazyShader(const BYTE * byteCode,size_t byteCodeSize,const char * name)259 constexpr LazyShader(const BYTE *byteCode, size_t byteCodeSize, const char *name)
260 : mByteCode(byteCode, byteCodeSize), mName(name)
261 {}
262
LazyShader(LazyShader && shader)263 constexpr LazyShader(LazyShader &&shader)
264 : LazyResource<GetResourceTypeFromD3D11<D3D11ShaderType>()>(std::move(shader)),
265 mByteCode(std::move(shader.mByteCode)),
266 mName(shader.mName)
267 {}
268
resolve(d3d::Context * context,Renderer11 * renderer)269 angle::Result resolve(d3d::Context *context, Renderer11 *renderer) override
270 {
271 return this->resolveImpl(context, renderer, mByteCode, nullptr, mName);
272 }
273
274 private:
275 ShaderData mByteCode;
276 const char *mName;
277 };
278
279 class LazyInputLayout final : public LazyResource<ResourceType::InputLayout>
280 {
281 public:
282 LazyInputLayout(const D3D11_INPUT_ELEMENT_DESC *inputDesc,
283 size_t inputDescLen,
284 const BYTE *byteCode,
285 size_t byteCodeLen,
286 const char *debugName);
287 ~LazyInputLayout() override;
288
289 angle::Result resolve(d3d::Context *context, Renderer11 *renderer) override;
290
291 private:
292 InputElementArray mInputDesc;
293 ShaderData mByteCode;
294 const char *mDebugName;
295 };
296
297 class LazyBlendState final : public LazyResource<ResourceType::BlendState>
298 {
299 public:
300 LazyBlendState(const D3D11_BLEND_DESC &desc, const char *debugName);
301
302 angle::Result resolve(d3d::Context *context, Renderer11 *renderer) override;
303
304 private:
305 D3D11_BLEND_DESC mDesc;
306 const char *mDebugName;
307 };
308
309 // Copy data to small D3D11 buffers, such as for small constant buffers, which use one struct to
310 // represent an entire buffer.
311 template <class T>
SetBufferData(ID3D11DeviceContext * context,ID3D11Buffer * constantBuffer,const T & value)312 void SetBufferData(ID3D11DeviceContext *context, ID3D11Buffer *constantBuffer, const T &value)
313 {
314 D3D11_MAPPED_SUBRESOURCE mappedResource = {};
315 HRESULT result = context->Map(constantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
316 ASSERT(SUCCEEDED(result));
317 if (SUCCEEDED(result))
318 {
319 memcpy(mappedResource.pData, &value, sizeof(T));
320 context->Unmap(constantBuffer, 0);
321 }
322 }
323
324 void InitializeFeatures(const Renderer11DeviceCaps &deviceCaps,
325 const DXGI_ADAPTER_DESC &adapterDesc,
326 angle::FeaturesD3D *features);
327
328 enum ReservedConstantBufferSlot
329 {
330 RESERVED_CONSTANT_BUFFER_SLOT_DEFAULT_UNIFORM_BLOCK = 0,
331 RESERVED_CONSTANT_BUFFER_SLOT_DRIVER = 1,
332
333 RESERVED_CONSTANT_BUFFER_SLOT_COUNT = 2
334 };
335
336 void InitConstantBufferDesc(D3D11_BUFFER_DESC *constantBufferDescription, size_t byteWidth);
337
338 // Helper class for RAII patterning.
339 template <typename T>
340 class ScopedUnmapper final : angle::NonCopyable
341 {
342 public:
ScopedUnmapper(T * object)343 ScopedUnmapper(T *object) : mObject(object) {}
~ScopedUnmapper()344 ~ScopedUnmapper() { mObject->unmap(); }
345
346 private:
347 T *mObject;
348 };
349 } // namespace d3d11
350
351 struct GenericData
352 {
GenericDataGenericData353 GenericData() {}
~GenericDataGenericData354 ~GenericData()
355 {
356 if (object)
357 {
358 // We can have a nullptr factory when holding passed-in resources.
359 if (manager)
360 {
361 manager->onReleaseGeneric(resourceType, object);
362 manager = nullptr;
363 }
364 object->Release();
365 object = nullptr;
366 }
367 }
368
369 ResourceType resourceType = ResourceType::Last;
370 ID3D11Resource *object = nullptr;
371 ResourceManager11 *manager = nullptr;
372 };
373
374 // A helper class which wraps a 2D or 3D texture.
375 class TextureHelper11 : public Resource11Base<ID3D11Resource, std::shared_ptr, GenericData>
376 {
377 public:
378 TextureHelper11();
379 TextureHelper11(TextureHelper11 &&other);
380 TextureHelper11(const TextureHelper11 &other);
381 ~TextureHelper11() override;
382 TextureHelper11 &operator=(TextureHelper11 &&other);
383 TextureHelper11 &operator=(const TextureHelper11 &other);
384
is2D()385 bool is2D() const { return mData->resourceType == ResourceType::Texture2D; }
is3D()386 bool is3D() const { return mData->resourceType == ResourceType::Texture3D; }
getTextureType()387 ResourceType getTextureType() const { return mData->resourceType; }
getExtents()388 gl::Extents getExtents() const { return mExtents; }
getFormat()389 DXGI_FORMAT getFormat() const { return mFormatSet->texFormat; }
getFormatSet()390 const d3d11::Format &getFormatSet() const { return *mFormatSet; }
getSampleCount()391 int getSampleCount() const { return mSampleCount; }
392
393 template <typename DescT, typename ResourceT>
init(Resource11<ResourceT> && texture,const DescT & desc,const d3d11::Format & format)394 void init(Resource11<ResourceT> &&texture, const DescT &desc, const d3d11::Format &format)
395 {
396 std::swap(mData->manager, texture.mData->manager);
397
398 // Can't use std::swap because texture is typed, and here we use ID3D11Resource.
399 ID3D11Resource *temp = mData->object;
400 mData->object = texture.mData->object;
401 texture.mData->object = static_cast<ResourceT *>(temp);
402
403 mFormatSet = &format;
404 initDesc(desc);
405 }
406
407 template <typename ResourceT>
set(ResourceT * object,const d3d11::Format & format)408 void set(ResourceT *object, const d3d11::Format &format)
409 {
410 ASSERT(!valid());
411
412 mFormatSet = &format;
413 mData->object = object;
414 mData->manager = nullptr;
415
416 GetDescFromD3D11<ResourceT> desc;
417 getDesc(&desc);
418 initDesc(desc);
419 }
420
421 bool operator==(const TextureHelper11 &other) const;
422 bool operator!=(const TextureHelper11 &other) const;
423
424 void getDesc(D3D11_TEXTURE2D_DESC *desc) const;
425 void getDesc(D3D11_TEXTURE3D_DESC *desc) const;
426
427 private:
428 void initDesc(const D3D11_TEXTURE2D_DESC &desc2D);
429 void initDesc(const D3D11_TEXTURE3D_DESC &desc3D);
430
431 const d3d11::Format *mFormatSet;
432 gl::Extents mExtents;
433 int mSampleCount;
434 };
435
436 enum class StagingAccess
437 {
438 READ,
439 READ_WRITE,
440 };
441
442 bool UsePresentPathFast(const Renderer11 *renderer, const gl::FramebufferAttachment *colorbuffer);
443 bool UsePrimitiveRestartWorkaround(bool primitiveRestartFixedIndexEnabled,
444 gl::DrawElementsType type);
445
446 enum class IndexStorageType
447 {
448 // Dynamic indexes are re-streamed every frame. They come from a client data pointer or
449 // from buffers that are updated frequently.
450 Dynamic,
451
452 // Static indexes are translated from the original storage once, and re-used multiple times.
453 Static,
454
455 // Direct indexes are never transated and are used directly from the source buffer. They are
456 // the fastest available path.
457 Direct,
458
459 // Not a real storage type.
460 Invalid,
461 };
462
463 IndexStorageType ClassifyIndexStorage(const gl::State &glState,
464 const gl::Buffer *elementArrayBuffer,
465 gl::DrawElementsType elementType,
466 gl::DrawElementsType destElementType,
467 unsigned int offset);
468
469 } // namespace rx
470
471 #endif // LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_UTILS_H_
472