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