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