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