1 //
2 // Copyright 2017 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 // ResourceManager11:
7 //   Centralized point of allocation for all D3D11 Resources.
8 
9 #ifndef LIBANGLE_RENDERER_D3D_D3D11_RESOURCEFACTORY11_H_
10 #define LIBANGLE_RENDERER_D3D_D3D11_RESOURCEFACTORY11_H_
11 
12 #include <array>
13 #include <memory>
14 
15 #include "common/MemoryBuffer.h"
16 #include "common/angleutils.h"
17 #include "common/debug.h"
18 #include "libANGLE/Error.h"
19 #include "libANGLE/renderer/renderer_utils.h"
20 
21 namespace rx
22 {
23 // These two methods are declared here to prevent circular includes.
24 namespace d3d11
25 {
26 HRESULT SetDebugName(ID3D11DeviceChild *resource, const char *name);
27 
28 template <typename T>
SetDebugName(angle::ComPtr<T> & resource,const char * name)29 HRESULT SetDebugName(angle::ComPtr<T> &resource, const char *name)
30 {
31     return SetDebugName(resource.Get(), name);
32 }
33 }  // namespace d3d11
34 
35 class Renderer11;
36 class ResourceManager11;
37 template <typename T>
38 class SharedResource11;
39 class TextureHelper11;
40 
41 using InputElementArray = WrappedArray<D3D11_INPUT_ELEMENT_DESC>;
42 using ShaderData        = WrappedArray<uint8_t>;
43 
44 // Format: ResourceType, D3D11 type, DESC type, init data type.
45 #define ANGLE_RESOURCE_TYPE_OP(NAME, OP)                                                     \
46     OP(NAME, BlendState, ID3D11BlendState, D3D11_BLEND_DESC, void)                           \
47     OP(NAME, Buffer, ID3D11Buffer, D3D11_BUFFER_DESC, const D3D11_SUBRESOURCE_DATA)          \
48     OP(NAME, ComputeShader, ID3D11ComputeShader, ShaderData, void)                           \
49     OP(NAME, DepthStencilState, ID3D11DepthStencilState, D3D11_DEPTH_STENCIL_DESC, void)     \
50     OP(NAME, DepthStencilView, ID3D11DepthStencilView, D3D11_DEPTH_STENCIL_VIEW_DESC,        \
51        ID3D11Resource)                                                                       \
52     OP(NAME, GeometryShader, ID3D11GeometryShader, ShaderData,                               \
53        const std::vector<D3D11_SO_DECLARATION_ENTRY>)                                        \
54     OP(NAME, InputLayout, ID3D11InputLayout, InputElementArray, const ShaderData)            \
55     OP(NAME, PixelShader, ID3D11PixelShader, ShaderData, void)                               \
56     OP(NAME, Query, ID3D11Query, D3D11_QUERY_DESC, void)                                     \
57     OP(NAME, RasterizerState, ID3D11RasterizerState, D3D11_RASTERIZER_DESC, void)            \
58     OP(NAME, RenderTargetView, ID3D11RenderTargetView, D3D11_RENDER_TARGET_VIEW_DESC,        \
59        ID3D11Resource)                                                                       \
60     OP(NAME, SamplerState, ID3D11SamplerState, D3D11_SAMPLER_DESC, void)                     \
61     OP(NAME, ShaderResourceView, ID3D11ShaderResourceView, D3D11_SHADER_RESOURCE_VIEW_DESC,  \
62        ID3D11Resource)                                                                       \
63     OP(NAME, Texture2D, ID3D11Texture2D, D3D11_TEXTURE2D_DESC, const D3D11_SUBRESOURCE_DATA) \
64     OP(NAME, Texture3D, ID3D11Texture3D, D3D11_TEXTURE3D_DESC, const D3D11_SUBRESOURCE_DATA) \
65     OP(NAME, VertexShader, ID3D11VertexShader, ShaderData, void)
66 
67 #define ANGLE_RESOURCE_TYPE_LIST(NAME, RESTYPE, D3D11TYPE, DESCTYPE, INITDATATYPE) RESTYPE,
68 
69 enum class ResourceType
70 {
71     ANGLE_RESOURCE_TYPE_OP(List, ANGLE_RESOURCE_TYPE_LIST) Last
72 };
73 
74 #undef ANGLE_RESOURCE_TYPE_LIST
75 
ResourceTypeIndex(ResourceType resourceType)76 constexpr size_t ResourceTypeIndex(ResourceType resourceType)
77 {
78     return static_cast<size_t>(resourceType);
79 }
80 
81 constexpr size_t NumResourceTypes = ResourceTypeIndex(ResourceType::Last);
82 
83 #define ANGLE_RESOURCE_TYPE_TO_D3D11(NAME, RESTYPE, D3D11TYPE, DESCTYPE, INITDATATYPE) \
84     \
85 template<> struct NAME<ResourceType::RESTYPE>                                          \
86     {                                                                                  \
87         using Value = D3D11TYPE;                                                       \
88     };
89 
90 #define ANGLE_RESOURCE_TYPE_TO_DESC(NAME, RESTYPE, D3D11TYPE, DESCTYPE, INITDATATYPE) \
91     \
92 template<> struct NAME<ResourceType::RESTYPE>                                         \
93     {                                                                                 \
94         using Value = DESCTYPE;                                                       \
95     };
96 
97 #define ANGLE_RESOURCE_TYPE_TO_INIT_DATA(NAME, RESTYPE, D3D11TYPE, DESCTYPE, INITDATATYPE) \
98     \
99 template<> struct NAME<ResourceType::RESTYPE>                                              \
100     {                                                                                      \
101         using Value = INITDATATYPE;                                                        \
102     };
103 
104 #define ANGLE_RESOURCE_TYPE_TO_TYPE(NAME, OP) \
105     template <ResourceType Param>             \
106     struct NAME;                              \
107     ANGLE_RESOURCE_TYPE_OP(NAME, OP)          \
108     \
109 template<ResourceType Param> struct NAME      \
110     {                                         \
111     };                                        \
112     \
113 template<ResourceType Param> using Get##NAME = typename NAME<Param>::Value;
114 
115 ANGLE_RESOURCE_TYPE_TO_TYPE(D3D11Type, ANGLE_RESOURCE_TYPE_TO_D3D11)
116 ANGLE_RESOURCE_TYPE_TO_TYPE(DescType, ANGLE_RESOURCE_TYPE_TO_DESC)
117 ANGLE_RESOURCE_TYPE_TO_TYPE(InitDataType, ANGLE_RESOURCE_TYPE_TO_INIT_DATA)
118 
119 #undef ANGLE_RESOURCE_TYPE_TO_D3D11
120 #undef ANGLE_RESOURCE_TYPE_TO_DESC
121 #undef ANGLE_RESOURCE_TYPE_TO_INIT_DATA
122 #undef ANGLE_RESOURCE_TYPE_TO_TYPE
123 
124 #define ANGLE_TYPE_TO_RESOURCE_TYPE(NAME, OP)               \
125     template <typename Param>                               \
126     struct NAME;                                            \
127     ANGLE_RESOURCE_TYPE_OP(NAME, OP)                        \
128     \
129 template<typename Param> struct NAME                        \
130     {                                                       \
131     };                                                      \
132     \
133 template<typename Param> constexpr ResourceType Get##NAME() \
134     {                                                       \
135         return NAME<Param>::Value;                          \
136     }
137 
138 #define ANGLE_D3D11_TO_RESOURCE_TYPE(NAME, RESTYPE, D3D11TYPE, DESCTYPE, INITDATATYPE) \
139     \
140 template<> struct NAME<D3D11TYPE>                                                      \
141     {                                                                                  \
142         static constexpr ResourceType Value = ResourceType::RESTYPE;                   \
143     };
144 
145 ANGLE_TYPE_TO_RESOURCE_TYPE(ResourceTypeFromD3D11, ANGLE_D3D11_TO_RESOURCE_TYPE)
146 
147 #undef ANGLE_D3D11_TO_RESOURCE_TYPE
148 #undef ANGLE_TYPE_TO_RESOURCE_TYPE
149 
150 template <typename T>
151 using GetDescFromD3D11 = GetDescType<ResourceTypeFromD3D11<T>::Value>;
152 
153 template <typename T>
154 using GetInitDataFromD3D11 = GetInitDataType<ResourceTypeFromD3D11<T>::Value>;
155 
156 template <typename T>
ResourceTypeIndex()157 constexpr size_t ResourceTypeIndex()
158 {
159     return static_cast<size_t>(GetResourceTypeFromD3D11<T>());
160 }
161 
162 template <typename T>
163 struct TypedData
164 {
TypedDataTypedData165     TypedData() {}
166     ~TypedData();
167 
168     T *object                  = nullptr;
169     ResourceManager11 *manager = nullptr;
170 };
171 
172 // Smart pointer type. Wraps the resource and a factory for safe deletion.
173 template <typename T, template <class> class Pointer, typename DataT>
174 class Resource11Base : angle::NonCopyable
175 {
176   public:
get()177     T *get() const { return mData->object; }
getPointer()178     T *const *getPointer() const { return &mData->object; }
179 
setDebugName(const char * name)180     void setDebugName(const char *name) { d3d11::SetDebugName(mData->object, name); }
181 
set(T * object)182     void set(T *object)
183     {
184         ASSERT(!valid());
185         mData->object = object;
186     }
187 
valid()188     bool valid() const { return (mData->object != nullptr); }
189 
reset()190     void reset()
191     {
192         if (valid())
193             mData.reset(new DataT());
194     }
195 
getSerial()196     ResourceSerial getSerial() const
197     {
198         return ResourceSerial(reinterpret_cast<uintptr_t>(mData->object));
199     }
200 
201   protected:
202     friend class TextureHelper11;
203 
Resource11Base()204     Resource11Base() : mData(new DataT()) {}
205 
Resource11Base(Resource11Base && movedObj)206     Resource11Base(Resource11Base &&movedObj) : mData(new DataT())
207     {
208         std::swap(mData, movedObj.mData);
209     }
210 
~Resource11Base()211     virtual ~Resource11Base() { mData.reset(); }
212 
213     Resource11Base &operator=(Resource11Base &&movedObj)
214     {
215         std::swap(mData, movedObj.mData);
216         return *this;
217     }
218 
219     Pointer<DataT> mData;
220 };
221 
222 template <typename T>
223 using UniquePtr = typename std::unique_ptr<T, std::default_delete<T>>;
224 
225 template <typename ResourceT>
226 class Resource11 : public Resource11Base<ResourceT, UniquePtr, TypedData<ResourceT>>
227 {
228   public:
Resource11()229     Resource11() {}
Resource11(Resource11 && other)230     Resource11(Resource11 &&other)
231         : Resource11Base<ResourceT, UniquePtr, TypedData<ResourceT>>(std::move(other))
232     {
233     }
234     Resource11 &operator=(Resource11 &&other)
235     {
236         std::swap(this->mData, other.mData);
237         return *this;
238     }
239 
240   private:
241     template <typename T>
242     friend class SharedResource11;
243     friend class ResourceManager11;
244 
Resource11(ResourceT * object,ResourceManager11 * manager)245     Resource11(ResourceT *object, ResourceManager11 *manager)
246     {
247         this->mData->object  = object;
248         this->mData->manager = manager;
249     }
250 };
251 
252 template <typename T>
253 class SharedResource11 : public Resource11Base<T, std::shared_ptr, TypedData<T>>
254 {
255   public:
SharedResource11()256     SharedResource11() {}
SharedResource11(SharedResource11 && movedObj)257     SharedResource11(SharedResource11 &&movedObj)
258         : Resource11Base<T, std::shared_ptr, TypedData<T>>(std::move(movedObj))
259     {
260     }
261 
262     SharedResource11 &operator=(SharedResource11 &&other)
263     {
264         std::swap(this->mData, other.mData);
265         return *this;
266     }
267 
makeCopy()268     SharedResource11 makeCopy() const
269     {
270         SharedResource11 copy;
271         copy.mData = this->mData;
272         return std::move(copy);
273     }
274 
275   private:
276     friend class ResourceManager11;
SharedResource11(Resource11<T> && obj)277     SharedResource11(Resource11<T> &&obj) : Resource11Base<T, std::shared_ptr, TypedData<T>>()
278     {
279         std::swap(this->mData->manager, obj.mData->manager);
280 
281         // Can't use std::swap because of ID3D11Resource.
282         auto temp           = this->mData->object;
283         this->mData->object = obj.mData->object;
284         obj.mData->object   = static_cast<T *>(temp);
285     }
286 };
287 
288 class ResourceManager11 final : angle::NonCopyable
289 {
290   public:
291     ResourceManager11();
292     ~ResourceManager11();
293 
294     template <typename T>
295     gl::Error allocate(Renderer11 *renderer,
296                        const GetDescFromD3D11<T> *desc,
297                        GetInitDataFromD3D11<T> *initData,
298                        Resource11<T> *resourceOut);
299 
300     template <typename T>
allocate(Renderer11 * renderer,const GetDescFromD3D11<T> * desc,GetInitDataFromD3D11<T> * initData,SharedResource11<T> * sharedRes)301     gl::Error allocate(Renderer11 *renderer,
302                        const GetDescFromD3D11<T> *desc,
303                        GetInitDataFromD3D11<T> *initData,
304                        SharedResource11<T> *sharedRes)
305     {
306         Resource11<T> res;
307         ANGLE_TRY(allocate(renderer, desc, initData, &res));
308         *sharedRes = std::move(res);
309         return gl::NoError();
310     }
311 
312     template <typename T>
onRelease(T * resource)313     void onRelease(T *resource)
314     {
315         onReleaseGeneric(GetResourceTypeFromD3D11<T>(), resource);
316     }
317 
318     void onReleaseGeneric(ResourceType resourceType, ID3D11DeviceChild *resource);
319 
320     void setAllocationsInitialized(bool initialize);
321 
322   private:
323     void incrResource(ResourceType resourceType, uint64_t memorySize);
324     void decrResource(ResourceType resourceType, uint64_t memorySize);
325 
326     template <typename T>
327     GetInitDataFromD3D11<T> *createInitDataIfNeeded(const GetDescFromD3D11<T> *desc);
328 
329     bool mInitializeAllocations;
330 
331     std::array<size_t, NumResourceTypes> mAllocatedResourceCounts;
332     std::array<uint64_t, NumResourceTypes> mAllocatedResourceDeviceMemory;
333     angle::MemoryBuffer mZeroMemory;
334 
335     std::vector<D3D11_SUBRESOURCE_DATA> mShadowInitData;
336 };
337 
338 template <typename ResourceT>
~TypedData()339 TypedData<ResourceT>::~TypedData()
340 {
341     if (object)
342     {
343         // We can have a nullptr factory when holding passed-in resources.
344         if (manager)
345         {
346             manager->onRelease(object);
347         }
348         object->Release();
349     }
350 }
351 
352 #define ANGLE_RESOURCE_TYPE_CLASS(NAME, RESTYPE, D3D11TYPE, DESCTYPE, INITDATATYPE) \
353     using RESTYPE = Resource11<D3D11TYPE>;
354 
355 namespace d3d11
356 {
357 ANGLE_RESOURCE_TYPE_OP(ClassList, ANGLE_RESOURCE_TYPE_CLASS)
358 
359 using SharedSRV = SharedResource11<ID3D11ShaderResourceView>;
360 }  // namespace d3d11
361 
362 #undef ANGLE_RESOURCE_TYPE_CLASS
363 
364 }  // namespace rx
365 
366 #endif  // LIBANGLE_RENDERER_D3D_D3D11_RESOURCEFACTORY11_H_
367