1 /*
2 * Copyright © Microsoft Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 #include "d3d12_context.h"
25 #include "d3d12_descriptor_pool.h"
26 #include "d3d12_screen.h"
27
28 #include "pipe/p_context.h"
29 #include "pipe/p_state.h"
30
31 #include "util/list.h"
32 #include "util/u_dynarray.h"
33 #include "util/u_memory.h"
34
35 #include <dxguids/dxguids.h>
36
37 struct d3d12_descriptor_pool {
38 ID3D12Device *dev;
39 D3D12_DESCRIPTOR_HEAP_TYPE type;
40 uint32_t num_descriptors;
41 list_head heaps;
42 };
43
44 struct d3d12_descriptor_heap {
45 struct d3d12_descriptor_pool *pool;
46
47 D3D12_DESCRIPTOR_HEAP_DESC desc;
48 ID3D12Device *dev;
49 ID3D12DescriptorHeap *heap;
50 uint32_t desc_size;
51 uint64_t cpu_base;
52 uint64_t gpu_base;
53 uint32_t size;
54 uint32_t next;
55 util_dynarray free_list;
56 list_head link;
57 };
58
59 struct d3d12_descriptor_heap*
d3d12_descriptor_heap_new(ID3D12Device * dev,D3D12_DESCRIPTOR_HEAP_TYPE type,D3D12_DESCRIPTOR_HEAP_FLAGS flags,uint32_t num_descriptors)60 d3d12_descriptor_heap_new(ID3D12Device *dev,
61 D3D12_DESCRIPTOR_HEAP_TYPE type,
62 D3D12_DESCRIPTOR_HEAP_FLAGS flags,
63 uint32_t num_descriptors)
64 {
65 struct d3d12_descriptor_heap *heap = CALLOC_STRUCT(d3d12_descriptor_heap);
66
67 heap->desc.NumDescriptors = num_descriptors;
68 heap->desc.Type = type;
69 heap->desc.Flags = flags;
70 if (FAILED(dev->CreateDescriptorHeap(&heap->desc,
71 IID_PPV_ARGS(&heap->heap)))) {
72 FREE(heap);
73 return NULL;
74 }
75
76 heap->dev = dev;
77 heap->desc_size = dev->GetDescriptorHandleIncrementSize(type);
78 heap->size = num_descriptors * heap->desc_size;
79 heap->cpu_base = GetCPUDescriptorHandleForHeapStart(heap->heap).ptr;
80 if (flags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)
81 heap->gpu_base = GetGPUDescriptorHandleForHeapStart(heap->heap).ptr;
82 util_dynarray_init(&heap->free_list, NULL);
83
84 return heap;
85 }
86
87 void
d3d12_descriptor_heap_free(struct d3d12_descriptor_heap * heap)88 d3d12_descriptor_heap_free(struct d3d12_descriptor_heap *heap)
89 {
90 heap->heap->Release();
91 util_dynarray_fini(&heap->free_list);
92 FREE(heap);
93 }
94
95 ID3D12DescriptorHeap*
d3d12_descriptor_heap_get(struct d3d12_descriptor_heap * heap)96 d3d12_descriptor_heap_get(struct d3d12_descriptor_heap *heap)
97 {
98 return heap->heap;
99 }
100
101 static uint32_t
d3d12_descriptor_heap_is_online(struct d3d12_descriptor_heap * heap)102 d3d12_descriptor_heap_is_online(struct d3d12_descriptor_heap *heap)
103 {
104 return (heap->desc.Flags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE) ? 1 : 0;
105 }
106
107 static uint32_t
d3d12_descriptor_heap_can_allocate(struct d3d12_descriptor_heap * heap)108 d3d12_descriptor_heap_can_allocate(struct d3d12_descriptor_heap *heap)
109 {
110 return (heap->free_list.size > 0 ||
111 heap->size >= heap->next + heap->desc_size);
112 }
113
114 uint32_t
d3d12_descriptor_heap_get_remaining_handles(struct d3d12_descriptor_heap * heap)115 d3d12_descriptor_heap_get_remaining_handles(struct d3d12_descriptor_heap *heap)
116 {
117 return (heap->size - heap->next) / heap->desc_size;
118 }
119
120 void
d2d12_descriptor_heap_get_next_handle(struct d3d12_descriptor_heap * heap,struct d3d12_descriptor_handle * handle)121 d2d12_descriptor_heap_get_next_handle(struct d3d12_descriptor_heap *heap,
122 struct d3d12_descriptor_handle *handle)
123 {
124 handle->heap = heap;
125 handle->cpu_handle.ptr = heap->cpu_base + heap->next;
126 handle->gpu_handle.ptr = d3d12_descriptor_heap_is_online(heap) ?
127 heap->gpu_base + heap->next : 0;
128 }
129
130 uint32_t
d3d12_descriptor_heap_alloc_handle(struct d3d12_descriptor_heap * heap,struct d3d12_descriptor_handle * handle)131 d3d12_descriptor_heap_alloc_handle(struct d3d12_descriptor_heap *heap,
132 struct d3d12_descriptor_handle *handle)
133 {
134 uint32_t offset = 0;
135
136 assert(handle != NULL);
137
138 if (heap->free_list.size > 0) {
139 offset = util_dynarray_pop(&heap->free_list, uint32_t);
140 } else if (heap->size >= heap->next + heap->desc_size) {
141 offset = heap->next;
142 heap->next += heap->desc_size;
143 } else {
144 /* Todo: we should add a new descriptor heap to get more handles */
145 assert(0 && "No handles available in descriptor heap");
146 return 0;
147 }
148
149 handle->heap = heap;
150 handle->cpu_handle.ptr = heap->cpu_base + offset;
151 handle->gpu_handle.ptr = d3d12_descriptor_heap_is_online(heap) ?
152 heap->gpu_base + offset : 0;
153
154 return 1;
155 }
156
157 void
d3d12_descriptor_handle_free(struct d3d12_descriptor_handle * handle)158 d3d12_descriptor_handle_free(struct d3d12_descriptor_handle *handle)
159 {
160 const uint32_t index = handle->cpu_handle.ptr - handle->heap->cpu_base;
161 if (index + handle->heap->desc_size == handle->heap->next) {
162 handle->heap->next = index;
163 } else {
164 util_dynarray_append(&handle->heap->free_list, uint32_t, index);
165 }
166
167 handle->heap = NULL;
168 handle->cpu_handle.ptr = 0;
169 handle->gpu_handle.ptr = 0;
170 }
171
172 void
d3d12_descriptor_heap_append_handles(struct d3d12_descriptor_heap * heap,D3D12_CPU_DESCRIPTOR_HANDLE * handles,unsigned num_handles)173 d3d12_descriptor_heap_append_handles(struct d3d12_descriptor_heap *heap,
174 D3D12_CPU_DESCRIPTOR_HANDLE *handles,
175 unsigned num_handles)
176 {
177 D3D12_CPU_DESCRIPTOR_HANDLE dst;
178
179 assert(heap->next + (num_handles * heap->desc_size) <= heap->size);
180 dst.ptr = heap->cpu_base + heap->next;
181 heap->dev->CopyDescriptors(1, &dst, &num_handles,
182 num_handles, handles, NULL,
183 heap->desc.Type);
184 heap->next += num_handles * heap->desc_size;
185 }
186
187 void
d3d12_descriptor_heap_clear(struct d3d12_descriptor_heap * heap)188 d3d12_descriptor_heap_clear(struct d3d12_descriptor_heap *heap)
189 {
190 heap->next = 0;
191 util_dynarray_clear(&heap->free_list);
192 }
193
194 struct d3d12_descriptor_pool*
d3d12_descriptor_pool_new(struct d3d12_screen * screen,D3D12_DESCRIPTOR_HEAP_TYPE type,uint32_t num_descriptors)195 d3d12_descriptor_pool_new(struct d3d12_screen *screen,
196 D3D12_DESCRIPTOR_HEAP_TYPE type,
197 uint32_t num_descriptors)
198 {
199 struct d3d12_descriptor_pool *pool = CALLOC_STRUCT(d3d12_descriptor_pool);
200 if (!pool)
201 return NULL;
202
203 pool->dev = screen->dev;
204 pool->type = type;
205 pool->num_descriptors = num_descriptors;
206 list_inithead(&pool->heaps);
207
208 return pool;
209 }
210
211 void
d3d12_descriptor_pool_free(struct d3d12_descriptor_pool * pool)212 d3d12_descriptor_pool_free(struct d3d12_descriptor_pool *pool)
213 {
214 list_for_each_entry_safe(struct d3d12_descriptor_heap, heap, &pool->heaps, link) {
215 list_del(&heap->link);
216 d3d12_descriptor_heap_free(heap);
217 }
218 FREE(pool);
219 }
220
221 uint32_t
d3d12_descriptor_pool_alloc_handle(struct d3d12_descriptor_pool * pool,struct d3d12_descriptor_handle * handle)222 d3d12_descriptor_pool_alloc_handle(struct d3d12_descriptor_pool *pool,
223 struct d3d12_descriptor_handle *handle)
224 {
225 struct d3d12_descriptor_heap *valid_heap = NULL;
226
227 list_for_each_entry(struct d3d12_descriptor_heap, heap, &pool->heaps, link) {
228 if (d3d12_descriptor_heap_can_allocate(heap)) {
229 valid_heap = heap;
230 break;
231 }
232 }
233
234 if (!valid_heap) {
235 valid_heap = d3d12_descriptor_heap_new(pool->dev,
236 pool->type,
237 D3D12_DESCRIPTOR_HEAP_FLAG_NONE,
238 pool->num_descriptors);
239 list_addtail(&valid_heap->link, &pool->heaps);
240 }
241
242 return d3d12_descriptor_heap_alloc_handle(valid_heap, handle);
243 }
244