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