| // |
| // Copyright 2012 The ANGLE Project Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| |
| // renderer11_utils.h: Conversion functions and other utility routines |
| // specific to the D3D11 renderer. |
| |
| #ifndef LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_UTILS_H_ |
| #define LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_UTILS_H_ |
| |
| #include <array> |
| #include <functional> |
| #include <vector> |
| |
| #include "common/Color.h" |
| |
| #include "libANGLE/Caps.h" |
| #include "libANGLE/Error.h" |
| #include "libANGLE/renderer/d3d/RendererD3D.h" |
| #include "libANGLE/renderer/d3d/d3d11/ResourceManager11.h" |
| #include "libANGLE/renderer/d3d/d3d11/texture_format_table.h" |
| |
| namespace gl |
| { |
| class FramebufferAttachment; |
| } |
| |
| namespace rx |
| { |
| class Context11; |
| class Renderer11; |
| class RenderTarget11; |
| struct Renderer11DeviceCaps; |
| |
| using RTVArray = std::array<ID3D11RenderTargetView *, gl::IMPLEMENTATION_MAX_DRAW_BUFFERS>; |
| |
| namespace gl_d3d11 |
| { |
| |
| D3D11_BLEND ConvertBlendFunc(GLenum glBlend, bool isAlpha); |
| D3D11_BLEND_OP ConvertBlendOp(GLenum glBlendOp); |
| UINT8 ConvertColorMask(bool maskRed, bool maskGreen, bool maskBlue, bool maskAlpha); |
| |
| D3D11_CULL_MODE ConvertCullMode(bool cullEnabled, gl::CullFaceMode cullMode); |
| |
| D3D11_COMPARISON_FUNC ConvertComparison(GLenum comparison); |
| D3D11_DEPTH_WRITE_MASK ConvertDepthMask(bool depthWriteEnabled); |
| UINT8 ConvertStencilMask(GLuint stencilmask); |
| D3D11_STENCIL_OP ConvertStencilOp(GLenum stencilOp); |
| |
| D3D11_FILTER ConvertFilter(GLenum minFilter, |
| GLenum magFilter, |
| float maxAnisotropy, |
| GLenum comparisonMode); |
| D3D11_TEXTURE_ADDRESS_MODE ConvertTextureWrap(GLenum wrap); |
| UINT ConvertMaxAnisotropy(float maxAnisotropy, D3D_FEATURE_LEVEL featureLevel); |
| |
| D3D11_QUERY ConvertQueryType(gl::QueryType type); |
| |
| UINT8 GetColorMask(const gl::InternalFormat &formatInfo); |
| |
| } // namespace gl_d3d11 |
| |
| namespace d3d11_gl |
| { |
| |
| unsigned int GetReservedVertexUniformVectors(D3D_FEATURE_LEVEL featureLevel); |
| |
| unsigned int GetReservedFragmentUniformVectors(D3D_FEATURE_LEVEL featureLevel); |
| |
| gl::Version GetMaximumClientVersion(D3D_FEATURE_LEVEL featureLevel); |
| void GenerateCaps(ID3D11Device *device, |
| ID3D11DeviceContext *deviceContext, |
| const Renderer11DeviceCaps &renderer11DeviceCaps, |
| const angle::FeaturesD3D &features, |
| gl::Caps *caps, |
| gl::TextureCapsMap *textureCapsMap, |
| gl::Extensions *extensions, |
| gl::Limitations *limitations); |
| |
| void GetSamplePosition(GLsizei sampleCount, size_t index, GLfloat *xy); |
| |
| D3D_FEATURE_LEVEL GetMinimumFeatureLevelForES31(); |
| |
| } // namespace d3d11_gl |
| |
| namespace d3d11 |
| { |
| |
| enum ANGLED3D11DeviceType |
| { |
| ANGLE_D3D11_DEVICE_TYPE_UNKNOWN, |
| ANGLE_D3D11_DEVICE_TYPE_HARDWARE, |
| ANGLE_D3D11_DEVICE_TYPE_SOFTWARE_REF_OR_NULL, |
| ANGLE_D3D11_DEVICE_TYPE_WARP, |
| }; |
| |
| ANGLED3D11DeviceType GetDeviceType(ID3D11Device *device); |
| |
| void MakeValidSize(bool isImage, |
| DXGI_FORMAT format, |
| GLsizei *requestWidth, |
| GLsizei *requestHeight, |
| int *levelOffset); |
| |
| angle::Result GenerateInitialTextureData( |
| const gl::Context *context, |
| GLint internalFormat, |
| const Renderer11DeviceCaps &renderer11DeviceCaps, |
| GLuint width, |
| GLuint height, |
| GLuint depth, |
| GLuint mipLevels, |
| gl::TexLevelArray<D3D11_SUBRESOURCE_DATA> *outSubresourceData); |
| |
| UINT GetPrimitiveRestartIndex(); |
| |
| struct PositionTexCoordVertex |
| { |
| float x, y; |
| float u, v; |
| }; |
| void SetPositionTexCoordVertex(PositionTexCoordVertex *vertex, float x, float y, float u, float v); |
| |
| struct PositionLayerTexCoord3DVertex |
| { |
| float x, y; |
| unsigned int l; |
| float u, v, s; |
| }; |
| void SetPositionLayerTexCoord3DVertex(PositionLayerTexCoord3DVertex *vertex, |
| float x, |
| float y, |
| unsigned int layer, |
| float u, |
| float v, |
| float s); |
| |
| struct PositionVertex |
| { |
| float x, y, z, w; |
| }; |
| |
| struct BlendStateKey final |
| { |
| // This will zero-initialize the struct, including padding. |
| BlendStateKey(); |
| |
| gl::BlendState blendState; |
| |
| // An int so struct size rounds nicely. |
| uint32_t rtvMax; |
| |
| uint8_t rtvMasks[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT]; |
| }; |
| |
| bool operator==(const BlendStateKey &a, const BlendStateKey &b); |
| bool operator!=(const BlendStateKey &a, const BlendStateKey &b); |
| |
| struct RasterizerStateKey final |
| { |
| // This will zero-initialize the struct, including padding. |
| RasterizerStateKey(); |
| |
| gl::RasterizerState rasterizerState; |
| |
| // Use a 32-bit int to round the struct nicely. |
| uint32_t scissorEnabled; |
| }; |
| |
| bool operator==(const RasterizerStateKey &a, const RasterizerStateKey &b); |
| bool operator!=(const RasterizerStateKey &a, const RasterizerStateKey &b); |
| |
| template <typename outType> |
| outType *DynamicCastComObject(IUnknown *object) |
| { |
| outType *outObject = nullptr; |
| HRESULT result = |
| object->QueryInterface(__uuidof(outType), reinterpret_cast<void **>(&outObject)); |
| if (SUCCEEDED(result)) |
| { |
| return outObject; |
| } |
| else |
| { |
| SafeRelease(outObject); |
| return nullptr; |
| } |
| } |
| |
| template <typename outType> |
| angle::ComPtr<outType> DynamicCastComObjectToComPtr(IUnknown *object) |
| { |
| angle::ComPtr<outType> outObject; |
| const HRESULT hr = object->QueryInterface(IID_PPV_ARGS(&outObject)); |
| if (SUCCEEDED(hr)) |
| { |
| return outObject; |
| } |
| else |
| { |
| return nullptr; |
| } |
| } |
| |
| inline bool isDeviceLostError(HRESULT errorCode) |
| { |
| switch (errorCode) |
| { |
| case DXGI_ERROR_DEVICE_HUNG: |
| case DXGI_ERROR_DEVICE_REMOVED: |
| case DXGI_ERROR_DEVICE_RESET: |
| case DXGI_ERROR_DRIVER_INTERNAL_ERROR: |
| case DXGI_ERROR_NOT_CURRENTLY_AVAILABLE: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| template <ResourceType ResourceT> |
| class LazyResource : angle::NonCopyable |
| { |
| public: |
| constexpr LazyResource() : mResource() {} |
| virtual ~LazyResource() {} |
| |
| virtual angle::Result resolve(d3d::Context *context, Renderer11 *renderer) = 0; |
| void reset() { mResource.reset(); } |
| GetD3D11Type<ResourceT> *get() const |
| { |
| ASSERT(mResource.valid()); |
| return mResource.get(); |
| } |
| |
| const Resource11<GetD3D11Type<ResourceT>> &getObj() const { return mResource; } |
| |
| protected: |
| LazyResource(LazyResource &&other) : mResource(std::move(other.mResource)) {} |
| |
| // Specialized in the cpp file to avoid MSVS/Clang specific code. |
| angle::Result resolveImpl(d3d::Context *context, |
| Renderer11 *renderer, |
| const GetDescType<ResourceT> &desc, |
| GetInitDataType<ResourceT> *initData, |
| const char *name); |
| |
| Resource11<GetD3D11Type<ResourceT>> mResource; |
| }; |
| |
| template <typename D3D11ShaderType> |
| class LazyShader final : public LazyResource<GetResourceTypeFromD3D11<D3D11ShaderType>()> |
| { |
| public: |
| // All parameters must be constexpr. Not supported in VS2013. |
| constexpr LazyShader(const BYTE *byteCode, size_t byteCodeSize, const char *name) |
| : mByteCode(byteCode, byteCodeSize), mName(name) |
| {} |
| |
| constexpr LazyShader(LazyShader &&shader) |
| : LazyResource<GetResourceTypeFromD3D11<D3D11ShaderType>()>(std::move(shader)), |
| mByteCode(std::move(shader.mByteCode)), |
| mName(shader.mName) |
| {} |
| |
| angle::Result resolve(d3d::Context *context, Renderer11 *renderer) override |
| { |
| return this->resolveImpl(context, renderer, mByteCode, nullptr, mName); |
| } |
| |
| private: |
| ShaderData mByteCode; |
| const char *mName; |
| }; |
| |
| class LazyInputLayout final : public LazyResource<ResourceType::InputLayout> |
| { |
| public: |
| LazyInputLayout(const D3D11_INPUT_ELEMENT_DESC *inputDesc, |
| size_t inputDescLen, |
| const BYTE *byteCode, |
| size_t byteCodeLen, |
| const char *debugName); |
| ~LazyInputLayout() override; |
| |
| angle::Result resolve(d3d::Context *context, Renderer11 *renderer) override; |
| |
| private: |
| InputElementArray mInputDesc; |
| ShaderData mByteCode; |
| const char *mDebugName; |
| }; |
| |
| class LazyBlendState final : public LazyResource<ResourceType::BlendState> |
| { |
| public: |
| LazyBlendState(const D3D11_BLEND_DESC &desc, const char *debugName); |
| |
| angle::Result resolve(d3d::Context *context, Renderer11 *renderer) override; |
| |
| private: |
| D3D11_BLEND_DESC mDesc; |
| const char *mDebugName; |
| }; |
| |
| // Copy data to small D3D11 buffers, such as for small constant buffers, which use one struct to |
| // represent an entire buffer. |
| template <class T> |
| void SetBufferData(ID3D11DeviceContext *context, ID3D11Buffer *constantBuffer, const T &value) |
| { |
| D3D11_MAPPED_SUBRESOURCE mappedResource = {}; |
| HRESULT result = context->Map(constantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); |
| ASSERT(SUCCEEDED(result)); |
| if (SUCCEEDED(result)) |
| { |
| memcpy(mappedResource.pData, &value, sizeof(T)); |
| context->Unmap(constantBuffer, 0); |
| } |
| } |
| |
| void InitializeFeatures(const Renderer11DeviceCaps &deviceCaps, |
| const DXGI_ADAPTER_DESC &adapterDesc, |
| angle::FeaturesD3D *features); |
| |
| enum ReservedConstantBufferSlot |
| { |
| RESERVED_CONSTANT_BUFFER_SLOT_DEFAULT_UNIFORM_BLOCK = 0, |
| RESERVED_CONSTANT_BUFFER_SLOT_DRIVER = 1, |
| |
| RESERVED_CONSTANT_BUFFER_SLOT_COUNT = 2 |
| }; |
| |
| void InitConstantBufferDesc(D3D11_BUFFER_DESC *constantBufferDescription, size_t byteWidth); |
| |
| // Helper class for RAII patterning. |
| template <typename T> |
| class ScopedUnmapper final : angle::NonCopyable |
| { |
| public: |
| ScopedUnmapper(T *object) : mObject(object) {} |
| ~ScopedUnmapper() { mObject->unmap(); } |
| |
| private: |
| T *mObject; |
| }; |
| } // namespace d3d11 |
| |
| struct GenericData |
| { |
| GenericData() {} |
| ~GenericData() |
| { |
| if (object) |
| { |
| // We can have a nullptr factory when holding passed-in resources. |
| if (manager) |
| { |
| manager->onReleaseGeneric(resourceType, object); |
| manager = nullptr; |
| } |
| object->Release(); |
| object = nullptr; |
| } |
| } |
| |
| ResourceType resourceType = ResourceType::Last; |
| ID3D11Resource *object = nullptr; |
| ResourceManager11 *manager = nullptr; |
| }; |
| |
| // A helper class which wraps a 2D or 3D texture. |
| class TextureHelper11 : public Resource11Base<ID3D11Resource, std::shared_ptr, GenericData> |
| { |
| public: |
| TextureHelper11(); |
| TextureHelper11(TextureHelper11 &&other); |
| TextureHelper11(const TextureHelper11 &other); |
| ~TextureHelper11() override; |
| TextureHelper11 &operator=(TextureHelper11 &&other); |
| TextureHelper11 &operator=(const TextureHelper11 &other); |
| |
| bool is2D() const { return mData->resourceType == ResourceType::Texture2D; } |
| bool is3D() const { return mData->resourceType == ResourceType::Texture3D; } |
| ResourceType getTextureType() const { return mData->resourceType; } |
| gl::Extents getExtents() const { return mExtents; } |
| DXGI_FORMAT getFormat() const { return mFormatSet->texFormat; } |
| const d3d11::Format &getFormatSet() const { return *mFormatSet; } |
| int getSampleCount() const { return mSampleCount; } |
| |
| template <typename DescT, typename ResourceT> |
| void init(Resource11<ResourceT> &&texture, const DescT &desc, const d3d11::Format &format) |
| { |
| std::swap(mData->manager, texture.mData->manager); |
| |
| // Can't use std::swap because texture is typed, and here we use ID3D11Resource. |
| ID3D11Resource *temp = mData->object; |
| mData->object = texture.mData->object; |
| texture.mData->object = static_cast<ResourceT *>(temp); |
| |
| mFormatSet = &format; |
| initDesc(desc); |
| } |
| |
| template <typename ResourceT> |
| void set(ResourceT *object, const d3d11::Format &format) |
| { |
| ASSERT(!valid()); |
| |
| mFormatSet = &format; |
| mData->object = object; |
| mData->manager = nullptr; |
| |
| GetDescFromD3D11<ResourceT> desc; |
| getDesc(&desc); |
| initDesc(desc); |
| } |
| |
| bool operator==(const TextureHelper11 &other) const; |
| bool operator!=(const TextureHelper11 &other) const; |
| |
| void getDesc(D3D11_TEXTURE2D_DESC *desc) const; |
| void getDesc(D3D11_TEXTURE3D_DESC *desc) const; |
| |
| private: |
| void initDesc(const D3D11_TEXTURE2D_DESC &desc2D); |
| void initDesc(const D3D11_TEXTURE3D_DESC &desc3D); |
| |
| const d3d11::Format *mFormatSet; |
| gl::Extents mExtents; |
| int mSampleCount; |
| }; |
| |
| enum class StagingAccess |
| { |
| READ, |
| READ_WRITE, |
| }; |
| |
| bool UsePresentPathFast(const Renderer11 *renderer, const gl::FramebufferAttachment *colorbuffer); |
| bool UsePrimitiveRestartWorkaround(bool primitiveRestartFixedIndexEnabled, |
| gl::DrawElementsType type); |
| |
| enum class IndexStorageType |
| { |
| // Dynamic indexes are re-streamed every frame. They come from a client data pointer or |
| // from buffers that are updated frequently. |
| Dynamic, |
| |
| // Static indexes are translated from the original storage once, and re-used multiple times. |
| Static, |
| |
| // Direct indexes are never transated and are used directly from the source buffer. They are |
| // the fastest available path. |
| Direct, |
| |
| // Not a real storage type. |
| Invalid, |
| }; |
| |
| IndexStorageType ClassifyIndexStorage(const gl::State &glState, |
| const gl::Buffer *elementArrayBuffer, |
| gl::DrawElementsType elementType, |
| gl::DrawElementsType destElementType, |
| unsigned int offset); |
| |
| } // namespace rx |
| |
| #endif // LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_UTILS_H_ |