| // |
| // Copyright 2017 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. |
| // |
| // ResourceManager11: |
| // Centralized point of allocation for all D3D11 Resources. |
| |
| #ifndef LIBANGLE_RENDERER_D3D_D3D11_RESOURCEFACTORY11_H_ |
| #define LIBANGLE_RENDERER_D3D_D3D11_RESOURCEFACTORY11_H_ |
| |
| #include <array> |
| #include <atomic> |
| #include <memory> |
| |
| #include "common/MemoryBuffer.h" |
| #include "common/angleutils.h" |
| #include "common/debug.h" |
| #include "libANGLE/Error.h" |
| #include "libANGLE/renderer/renderer_utils.h" |
| |
| namespace rx |
| { |
| // These two methods are declared here to prevent circular includes. |
| namespace d3d11 |
| { |
| HRESULT SetDebugName(ID3D11DeviceChild *resource, const char *name); |
| |
| template <typename T> |
| HRESULT SetDebugName(angle::ComPtr<T> &resource, const char *name) |
| { |
| return SetDebugName(resource.Get(), name); |
| } |
| } // namespace d3d11 |
| |
| namespace d3d |
| { |
| class Context; |
| } // namespace d3d |
| |
| class Renderer11; |
| class ResourceManager11; |
| template <typename T> |
| class SharedResource11; |
| class TextureHelper11; |
| |
| using InputElementArray = WrappedArray<D3D11_INPUT_ELEMENT_DESC>; |
| using ShaderData = WrappedArray<uint8_t>; |
| |
| // Format: ResourceType, D3D11 type, DESC type, init data type. |
| #define ANGLE_RESOURCE_TYPE_OP(NAME, OP) \ |
| OP(NAME, BlendState, ID3D11BlendState, D3D11_BLEND_DESC, void) \ |
| OP(NAME, Buffer, ID3D11Buffer, D3D11_BUFFER_DESC, const D3D11_SUBRESOURCE_DATA) \ |
| OP(NAME, ComputeShader, ID3D11ComputeShader, ShaderData, void) \ |
| OP(NAME, DepthStencilState, ID3D11DepthStencilState, D3D11_DEPTH_STENCIL_DESC, void) \ |
| OP(NAME, DepthStencilView, ID3D11DepthStencilView, D3D11_DEPTH_STENCIL_VIEW_DESC, \ |
| ID3D11Resource) \ |
| OP(NAME, GeometryShader, ID3D11GeometryShader, ShaderData, \ |
| const std::vector<D3D11_SO_DECLARATION_ENTRY>) \ |
| OP(NAME, InputLayout, ID3D11InputLayout, InputElementArray, const ShaderData) \ |
| OP(NAME, PixelShader, ID3D11PixelShader, ShaderData, void) \ |
| OP(NAME, Query, ID3D11Query, D3D11_QUERY_DESC, void) \ |
| OP(NAME, RasterizerState, ID3D11RasterizerState, D3D11_RASTERIZER_DESC, void) \ |
| OP(NAME, RenderTargetView, ID3D11RenderTargetView, D3D11_RENDER_TARGET_VIEW_DESC, \ |
| ID3D11Resource) \ |
| OP(NAME, SamplerState, ID3D11SamplerState, D3D11_SAMPLER_DESC, void) \ |
| OP(NAME, ShaderResourceView, ID3D11ShaderResourceView, D3D11_SHADER_RESOURCE_VIEW_DESC, \ |
| ID3D11Resource) \ |
| OP(NAME, UnorderedAccessView, ID3D11UnorderedAccessView, D3D11_UNORDERED_ACCESS_VIEW_DESC, \ |
| ID3D11Resource) \ |
| OP(NAME, Texture2D, ID3D11Texture2D, D3D11_TEXTURE2D_DESC, const D3D11_SUBRESOURCE_DATA) \ |
| OP(NAME, Texture3D, ID3D11Texture3D, D3D11_TEXTURE3D_DESC, const D3D11_SUBRESOURCE_DATA) \ |
| OP(NAME, VertexShader, ID3D11VertexShader, ShaderData, void) |
| |
| #define ANGLE_RESOURCE_TYPE_LIST(NAME, RESTYPE, D3D11TYPE, DESCTYPE, INITDATATYPE) RESTYPE, |
| |
| enum class ResourceType |
| { |
| ANGLE_RESOURCE_TYPE_OP(List, ANGLE_RESOURCE_TYPE_LIST) Last |
| }; |
| |
| #undef ANGLE_RESOURCE_TYPE_LIST |
| |
| constexpr size_t ResourceTypeIndex(ResourceType resourceType) |
| { |
| return static_cast<size_t>(resourceType); |
| } |
| |
| constexpr size_t NumResourceTypes = ResourceTypeIndex(ResourceType::Last); |
| |
| #define ANGLE_RESOURCE_TYPE_TO_D3D11(NAME, RESTYPE, D3D11TYPE, DESCTYPE, INITDATATYPE) \ |
| \ |
| template <> \ |
| struct NAME<ResourceType::RESTYPE> \ |
| { \ |
| using Value = D3D11TYPE; \ |
| }; |
| |
| #define ANGLE_RESOURCE_TYPE_TO_DESC(NAME, RESTYPE, D3D11TYPE, DESCTYPE, INITDATATYPE) \ |
| \ |
| template <> \ |
| struct NAME<ResourceType::RESTYPE> \ |
| { \ |
| using Value = DESCTYPE; \ |
| }; |
| |
| #define ANGLE_RESOURCE_TYPE_TO_INIT_DATA(NAME, RESTYPE, D3D11TYPE, DESCTYPE, INITDATATYPE) \ |
| \ |
| template <> \ |
| struct NAME<ResourceType::RESTYPE> \ |
| { \ |
| using Value = INITDATATYPE; \ |
| }; |
| |
| #define ANGLE_RESOURCE_TYPE_TO_TYPE(NAME, OP) \ |
| template <ResourceType Param> \ |
| struct NAME; \ |
| ANGLE_RESOURCE_TYPE_OP(NAME, OP) \ |
| \ |
| template <ResourceType Param> \ |
| struct NAME \ |
| {}; \ |
| \ |
| template <ResourceType Param> \ |
| using Get##NAME = typename NAME<Param>::Value; |
| |
| ANGLE_RESOURCE_TYPE_TO_TYPE(D3D11Type, ANGLE_RESOURCE_TYPE_TO_D3D11) |
| ANGLE_RESOURCE_TYPE_TO_TYPE(DescType, ANGLE_RESOURCE_TYPE_TO_DESC) |
| ANGLE_RESOURCE_TYPE_TO_TYPE(InitDataType, ANGLE_RESOURCE_TYPE_TO_INIT_DATA) |
| |
| #undef ANGLE_RESOURCE_TYPE_TO_D3D11 |
| #undef ANGLE_RESOURCE_TYPE_TO_DESC |
| #undef ANGLE_RESOURCE_TYPE_TO_INIT_DATA |
| #undef ANGLE_RESOURCE_TYPE_TO_TYPE |
| |
| #define ANGLE_TYPE_TO_RESOURCE_TYPE(NAME, OP) \ |
| template <typename Param> \ |
| struct NAME; \ |
| ANGLE_RESOURCE_TYPE_OP(NAME, OP) \ |
| \ |
| template <typename Param> \ |
| struct NAME \ |
| {}; \ |
| \ |
| template <typename Param> \ |
| constexpr ResourceType Get##NAME() \ |
| { \ |
| return NAME<Param>::Value; \ |
| } |
| |
| #define ANGLE_D3D11_TO_RESOURCE_TYPE(NAME, RESTYPE, D3D11TYPE, DESCTYPE, INITDATATYPE) \ |
| \ |
| template <> \ |
| struct NAME<D3D11TYPE> \ |
| { \ |
| static constexpr ResourceType Value = ResourceType::RESTYPE; \ |
| }; |
| |
| ANGLE_TYPE_TO_RESOURCE_TYPE(ResourceTypeFromD3D11, ANGLE_D3D11_TO_RESOURCE_TYPE) |
| |
| #undef ANGLE_D3D11_TO_RESOURCE_TYPE |
| #undef ANGLE_TYPE_TO_RESOURCE_TYPE |
| |
| template <typename T> |
| using GetDescFromD3D11 = GetDescType<ResourceTypeFromD3D11<T>::Value>; |
| |
| template <typename T> |
| using GetInitDataFromD3D11 = GetInitDataType<ResourceTypeFromD3D11<T>::Value>; |
| |
| template <typename T> |
| constexpr size_t ResourceTypeIndex() |
| { |
| return static_cast<size_t>(GetResourceTypeFromD3D11<T>()); |
| } |
| |
| template <typename T> |
| struct TypedData |
| { |
| TypedData() {} |
| ~TypedData(); |
| |
| T *object = nullptr; |
| ResourceManager11 *manager = nullptr; |
| }; |
| |
| // Smart pointer type. Wraps the resource and a factory for safe deletion. |
| template <typename T, template <class> class Pointer, typename DataT> |
| class Resource11Base : angle::NonCopyable |
| { |
| public: |
| T *get() const { return mData->object; } |
| T *const *getPointer() const { return &mData->object; } |
| |
| void setDebugName(const char *name) { d3d11::SetDebugName(mData->object, name); } |
| |
| void set(T *object) |
| { |
| ASSERT(!valid()); |
| mData->object = object; |
| } |
| |
| bool valid() const { return (mData->object != nullptr); } |
| |
| void reset() |
| { |
| if (valid()) |
| mData.reset(new DataT()); |
| } |
| |
| ResourceSerial getSerial() const |
| { |
| return ResourceSerial(reinterpret_cast<uintptr_t>(mData->object)); |
| } |
| |
| protected: |
| friend class TextureHelper11; |
| |
| Resource11Base() : mData(new DataT()) {} |
| |
| Resource11Base(Resource11Base &&movedObj) : mData(new DataT()) |
| { |
| std::swap(mData, movedObj.mData); |
| } |
| |
| virtual ~Resource11Base() { mData.reset(); } |
| |
| Resource11Base &operator=(Resource11Base &&movedObj) |
| { |
| std::swap(mData, movedObj.mData); |
| return *this; |
| } |
| |
| Pointer<DataT> mData; |
| }; |
| |
| template <typename T> |
| using UniquePtr = typename std::unique_ptr<T, std::default_delete<T>>; |
| |
| template <typename ResourceT> |
| class Resource11 : public Resource11Base<ResourceT, UniquePtr, TypedData<ResourceT>> |
| { |
| public: |
| Resource11() {} |
| Resource11(Resource11 &&other) |
| : Resource11Base<ResourceT, UniquePtr, TypedData<ResourceT>>(std::move(other)) |
| {} |
| Resource11 &operator=(Resource11 &&other) |
| { |
| std::swap(this->mData, other.mData); |
| return *this; |
| } |
| |
| private: |
| template <typename T> |
| friend class SharedResource11; |
| friend class ResourceManager11; |
| |
| Resource11(ResourceT *object, ResourceManager11 *manager) |
| { |
| this->mData->object = object; |
| this->mData->manager = manager; |
| } |
| }; |
| |
| template <typename T> |
| class SharedResource11 : public Resource11Base<T, std::shared_ptr, TypedData<T>> |
| { |
| public: |
| SharedResource11() {} |
| SharedResource11(SharedResource11 &&movedObj) |
| : Resource11Base<T, std::shared_ptr, TypedData<T>>(std::move(movedObj)) |
| {} |
| |
| SharedResource11 &operator=(SharedResource11 &&other) |
| { |
| std::swap(this->mData, other.mData); |
| return *this; |
| } |
| |
| SharedResource11 makeCopy() const |
| { |
| SharedResource11 copy; |
| copy.mData = this->mData; |
| return std::move(copy); |
| } |
| |
| private: |
| friend class ResourceManager11; |
| SharedResource11(Resource11<T> &&obj) : Resource11Base<T, std::shared_ptr, TypedData<T>>() |
| { |
| std::swap(this->mData->manager, obj.mData->manager); |
| |
| // Can't use std::swap because of ID3D11Resource. |
| auto temp = this->mData->object; |
| this->mData->object = obj.mData->object; |
| obj.mData->object = static_cast<T *>(temp); |
| } |
| }; |
| |
| class ResourceManager11 final : angle::NonCopyable |
| { |
| public: |
| ResourceManager11(); |
| ~ResourceManager11(); |
| |
| template <typename T> |
| angle::Result allocate(d3d::Context *context, |
| Renderer11 *renderer, |
| const GetDescFromD3D11<T> *desc, |
| GetInitDataFromD3D11<T> *initData, |
| Resource11<T> *resourceOut); |
| |
| template <typename T> |
| angle::Result allocate(d3d::Context *context, |
| Renderer11 *renderer, |
| const GetDescFromD3D11<T> *desc, |
| GetInitDataFromD3D11<T> *initData, |
| SharedResource11<T> *sharedRes) |
| { |
| Resource11<T> res; |
| ANGLE_TRY(allocate(context, renderer, desc, initData, &res)); |
| *sharedRes = std::move(res); |
| return angle::Result::Continue; |
| } |
| |
| template <typename T> |
| void onRelease(T *resource) |
| { |
| onReleaseGeneric(GetResourceTypeFromD3D11<T>(), resource); |
| } |
| |
| void onReleaseGeneric(ResourceType resourceType, ID3D11DeviceChild *resource); |
| |
| void setAllocationsInitialized(bool initialize); |
| |
| private: |
| void incrResource(ResourceType resourceType, uint64_t memorySize); |
| void decrResource(ResourceType resourceType, uint64_t memorySize); |
| |
| template <typename T> |
| GetInitDataFromD3D11<T> *createInitDataIfNeeded(const GetDescFromD3D11<T> *desc); |
| |
| bool mInitializeAllocations; |
| |
| std::array<std::atomic_size_t, NumResourceTypes> mAllocatedResourceCounts; |
| std::array<std::atomic_uint64_t, NumResourceTypes> mAllocatedResourceDeviceMemory; |
| angle::MemoryBuffer mZeroMemory; |
| |
| std::vector<D3D11_SUBRESOURCE_DATA> mShadowInitData; |
| }; |
| |
| template <typename ResourceT> |
| TypedData<ResourceT>::~TypedData() |
| { |
| if (object) |
| { |
| // We can have a nullptr factory when holding passed-in resources. |
| if (manager) |
| { |
| manager->onRelease(object); |
| } |
| object->Release(); |
| } |
| } |
| |
| #define ANGLE_RESOURCE_TYPE_CLASS(NAME, RESTYPE, D3D11TYPE, DESCTYPE, INITDATATYPE) \ |
| using RESTYPE = Resource11<D3D11TYPE>; |
| |
| namespace d3d11 |
| { |
| ANGLE_RESOURCE_TYPE_OP(ClassList, ANGLE_RESOURCE_TYPE_CLASS) |
| |
| using SharedSRV = SharedResource11<ID3D11ShaderResourceView>; |
| using SharedUAV = SharedResource11<ID3D11UnorderedAccessView>; |
| } // namespace d3d11 |
| |
| #undef ANGLE_RESOURCE_TYPE_CLASS |
| |
| } // namespace rx |
| |
| #endif // LIBANGLE_RENDERER_D3D_D3D11_RESOURCEFACTORY11_H_ |