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(const Renderer11DeviceCaps &caps);
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::BlendStateExt blendStateExt;
152
153 // Use two 16-bit ints to round the struct nicely.
154 uint16_t rtvMax;
155 uint16_t sampleAlphaToCoverage;
156 };
157
158 bool operator==(const BlendStateKey &a, const BlendStateKey &b);
159 bool operator!=(const BlendStateKey &a, const BlendStateKey &b);
160
161 struct RasterizerStateKey final
162 {
163 // This will zero-initialize the struct, including padding.
164 RasterizerStateKey();
165
166 gl::RasterizerState rasterizerState;
167
168 // Use a 32-bit int to round the struct nicely.
169 uint32_t scissorEnabled;
170 };
171
172 bool operator==(const RasterizerStateKey &a, const RasterizerStateKey &b);
173 bool operator!=(const RasterizerStateKey &a, const RasterizerStateKey &b);
174
175 template <typename outType>
DynamicCastComObject(IUnknown * object)176 outType *DynamicCastComObject(IUnknown *object)
177 {
178 outType *outObject = nullptr;
179 HRESULT result =
180 object->QueryInterface(__uuidof(outType), reinterpret_cast<void **>(&outObject));
181 if (SUCCEEDED(result))
182 {
183 return outObject;
184 }
185 else
186 {
187 SafeRelease(outObject);
188 return nullptr;
189 }
190 }
191
192 template <typename outType>
DynamicCastComObjectToComPtr(IUnknown * object)193 angle::ComPtr<outType> DynamicCastComObjectToComPtr(IUnknown *object)
194 {
195 angle::ComPtr<outType> outObject;
196 const HRESULT hr = object->QueryInterface(IID_PPV_ARGS(&outObject));
197 if (SUCCEEDED(hr))
198 {
199 return outObject;
200 }
201 else
202 {
203 return nullptr;
204 }
205 }
206
isDeviceLostError(HRESULT errorCode)207 inline bool isDeviceLostError(HRESULT errorCode)
208 {
209 switch (errorCode)
210 {
211 case DXGI_ERROR_DEVICE_HUNG:
212 case DXGI_ERROR_DEVICE_REMOVED:
213 case DXGI_ERROR_DEVICE_RESET:
214 case DXGI_ERROR_DRIVER_INTERNAL_ERROR:
215 case DXGI_ERROR_NOT_CURRENTLY_AVAILABLE:
216 return true;
217 default:
218 return false;
219 }
220 }
221
222 template <ResourceType ResourceT>
223 class LazyResource : angle::NonCopyable
224 {
225 public:
LazyResource()226 constexpr LazyResource() : mResource() {}
~LazyResource()227 virtual ~LazyResource() {}
228
229 virtual angle::Result resolve(d3d::Context *context, Renderer11 *renderer) = 0;
reset()230 void reset() { mResource.reset(); }
get()231 GetD3D11Type<ResourceT> *get() const
232 {
233 ASSERT(mResource.valid());
234 return mResource.get();
235 }
236
getObj()237 const Resource11<GetD3D11Type<ResourceT>> &getObj() const { return mResource; }
238
239 protected:
LazyResource(LazyResource && other)240 LazyResource(LazyResource &&other) : mResource(std::move(other.mResource)) {}
241
242 // Specialized in the cpp file to avoid MSVS/Clang specific code.
243 angle::Result resolveImpl(d3d::Context *context,
244 Renderer11 *renderer,
245 const GetDescType<ResourceT> &desc,
246 GetInitDataType<ResourceT> *initData,
247 const char *name);
248
249 Resource11<GetD3D11Type<ResourceT>> mResource;
250 };
251
252 template <typename D3D11ShaderType>
253 class LazyShader final : public LazyResource<GetResourceTypeFromD3D11<D3D11ShaderType>()>
254 {
255 public:
256 // All parameters must be constexpr. Not supported in VS2013.
LazyShader(const BYTE * byteCode,size_t byteCodeSize,const char * name)257 constexpr LazyShader(const BYTE *byteCode, size_t byteCodeSize, const char *name)
258 : mByteCode(byteCode, byteCodeSize), mName(name)
259 {}
260
LazyShader(LazyShader && shader)261 constexpr LazyShader(LazyShader &&shader)
262 : LazyResource<GetResourceTypeFromD3D11<D3D11ShaderType>()>(std::move(shader)),
263 mByteCode(std::move(shader.mByteCode)),
264 mName(shader.mName)
265 {}
266
resolve(d3d::Context * context,Renderer11 * renderer)267 angle::Result resolve(d3d::Context *context, Renderer11 *renderer) override
268 {
269 return this->resolveImpl(context, renderer, mByteCode, nullptr, mName);
270 }
271
272 private:
273 ShaderData mByteCode;
274 const char *mName;
275 };
276
277 class LazyInputLayout final : public LazyResource<ResourceType::InputLayout>
278 {
279 public:
280 LazyInputLayout(const D3D11_INPUT_ELEMENT_DESC *inputDesc,
281 size_t inputDescLen,
282 const BYTE *byteCode,
283 size_t byteCodeLen,
284 const char *debugName);
285 ~LazyInputLayout() override;
286
287 angle::Result resolve(d3d::Context *context, Renderer11 *renderer) override;
288
289 private:
290 InputElementArray mInputDesc;
291 ShaderData mByteCode;
292 const char *mDebugName;
293 };
294
295 class LazyBlendState final : public LazyResource<ResourceType::BlendState>
296 {
297 public:
298 LazyBlendState(const D3D11_BLEND_DESC &desc, const char *debugName);
299
300 angle::Result resolve(d3d::Context *context, Renderer11 *renderer) override;
301
302 private:
303 D3D11_BLEND_DESC mDesc;
304 const char *mDebugName;
305 };
306
307 // Copy data to small D3D11 buffers, such as for small constant buffers, which use one struct to
308 // represent an entire buffer.
309 template <class T>
SetBufferData(ID3D11DeviceContext * context,ID3D11Buffer * constantBuffer,const T & value)310 void SetBufferData(ID3D11DeviceContext *context, ID3D11Buffer *constantBuffer, const T &value)
311 {
312 D3D11_MAPPED_SUBRESOURCE mappedResource = {};
313 HRESULT result = context->Map(constantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
314 ASSERT(SUCCEEDED(result));
315 if (SUCCEEDED(result))
316 {
317 memcpy(mappedResource.pData, &value, sizeof(T));
318 context->Unmap(constantBuffer, 0);
319 }
320 }
321
322 void InitializeFeatures(const Renderer11DeviceCaps &deviceCaps,
323 const DXGI_ADAPTER_DESC &adapterDesc,
324 angle::FeaturesD3D *features);
325
326 enum ReservedConstantBufferSlot
327 {
328 RESERVED_CONSTANT_BUFFER_SLOT_DEFAULT_UNIFORM_BLOCK = 0,
329 RESERVED_CONSTANT_BUFFER_SLOT_DRIVER = 1,
330
331 RESERVED_CONSTANT_BUFFER_SLOT_COUNT = 2
332 };
333
334 void InitConstantBufferDesc(D3D11_BUFFER_DESC *constantBufferDescription, size_t byteWidth);
335
336 // Helper class for RAII patterning.
337 template <typename T>
338 class ScopedUnmapper final : angle::NonCopyable
339 {
340 public:
ScopedUnmapper(T * object)341 ScopedUnmapper(T *object) : mObject(object) {}
~ScopedUnmapper()342 ~ScopedUnmapper() { mObject->unmap(); }
343
344 private:
345 T *mObject;
346 };
347 } // namespace d3d11
348
349 struct GenericData
350 {
GenericDataGenericData351 GenericData() {}
~GenericDataGenericData352 ~GenericData()
353 {
354 if (object)
355 {
356 // We can have a nullptr factory when holding passed-in resources.
357 if (manager)
358 {
359 manager->onReleaseGeneric(resourceType, object);
360 manager = nullptr;
361 }
362 object->Release();
363 object = nullptr;
364 }
365 }
366
367 ResourceType resourceType = ResourceType::Last;
368 ID3D11Resource *object = nullptr;
369 ResourceManager11 *manager = nullptr;
370 };
371
372 // A helper class which wraps a 2D or 3D texture.
373 class TextureHelper11 : public Resource11Base<ID3D11Resource, std::shared_ptr, GenericData>
374 {
375 public:
376 TextureHelper11();
377 TextureHelper11(TextureHelper11 &&other);
378 TextureHelper11(const TextureHelper11 &other);
379 ~TextureHelper11() override;
380 TextureHelper11 &operator=(TextureHelper11 &&other);
381 TextureHelper11 &operator=(const TextureHelper11 &other);
382
is2D()383 bool is2D() const { return mData->resourceType == ResourceType::Texture2D; }
is3D()384 bool is3D() const { return mData->resourceType == ResourceType::Texture3D; }
getTextureType()385 ResourceType getTextureType() const { return mData->resourceType; }
getExtents()386 gl::Extents getExtents() const { return mExtents; }
getFormat()387 DXGI_FORMAT getFormat() const { return mFormatSet->texFormat; }
getFormatSet()388 const d3d11::Format &getFormatSet() const { return *mFormatSet; }
getSampleCount()389 int getSampleCount() const { return mSampleCount; }
390
391 template <typename DescT, typename ResourceT>
init(Resource11<ResourceT> && texture,const DescT & desc,const d3d11::Format & format)392 void init(Resource11<ResourceT> &&texture, const DescT &desc, const d3d11::Format &format)
393 {
394 std::swap(mData->manager, texture.mData->manager);
395
396 // Can't use std::swap because texture is typed, and here we use ID3D11Resource.
397 ID3D11Resource *temp = mData->object;
398 mData->object = texture.mData->object;
399 texture.mData->object = static_cast<ResourceT *>(temp);
400
401 mFormatSet = &format;
402 initDesc(desc);
403 }
404
405 template <typename ResourceT>
set(ResourceT * object,const d3d11::Format & format)406 void set(ResourceT *object, const d3d11::Format &format)
407 {
408 ASSERT(!valid());
409
410 mFormatSet = &format;
411 mData->object = object;
412 mData->manager = nullptr;
413
414 GetDescFromD3D11<ResourceT> desc;
415 getDesc(&desc);
416 initDesc(desc);
417 }
418
419 bool operator==(const TextureHelper11 &other) const;
420 bool operator!=(const TextureHelper11 &other) const;
421
422 void getDesc(D3D11_TEXTURE2D_DESC *desc) const;
423 void getDesc(D3D11_TEXTURE3D_DESC *desc) const;
424
425 private:
426 void initDesc(const D3D11_TEXTURE2D_DESC &desc2D);
427 void initDesc(const D3D11_TEXTURE3D_DESC &desc3D);
428
429 const d3d11::Format *mFormatSet;
430 gl::Extents mExtents;
431 int mSampleCount;
432 };
433
434 enum class StagingAccess
435 {
436 READ,
437 READ_WRITE,
438 };
439
440 bool UsePresentPathFast(const Renderer11 *renderer, const gl::FramebufferAttachment *colorbuffer);
441 bool UsePrimitiveRestartWorkaround(bool primitiveRestartFixedIndexEnabled,
442 gl::DrawElementsType type);
443
444 enum class IndexStorageType
445 {
446 // Dynamic indexes are re-streamed every frame. They come from a client data pointer or
447 // from buffers that are updated frequently.
448 Dynamic,
449
450 // Static indexes are translated from the original storage once, and re-used multiple times.
451 Static,
452
453 // Direct indexes are never transated and are used directly from the source buffer. They are
454 // the fastest available path.
455 Direct,
456
457 // Not a real storage type.
458 Invalid,
459 };
460
461 IndexStorageType ClassifyIndexStorage(const gl::State &glState,
462 const gl::Buffer *elementArrayBuffer,
463 gl::DrawElementsType elementType,
464 gl::DrawElementsType destElementType,
465 unsigned int offset);
466
467 } // namespace rx
468
469 #endif // LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_UTILS_H_
470