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