• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <directx/d3d12.h>
36 #include <dxguids/dxguids.h>
37 
38 struct d3d12_descriptor_pool {
39    ID3D12Device *dev;
40    D3D12_DESCRIPTOR_HEAP_TYPE type;
41    uint32_t num_descriptors;
42    list_head heaps;
43 };
44 
45 struct d3d12_descriptor_heap {
46    struct d3d12_descriptor_pool *pool;
47 
48    D3D12_DESCRIPTOR_HEAP_DESC desc;
49    ID3D12Device *dev;
50    ID3D12DescriptorHeap *heap;
51    uint32_t desc_size;
52    uint64_t cpu_base;
53    uint64_t gpu_base;
54    uint32_t size;
55    uint32_t next;
56    util_dynarray free_list;
57    list_head link;
58 };
59 
60 struct d3d12_descriptor_heap*
d3d12_descriptor_heap_new(ID3D12Device * dev,D3D12_DESCRIPTOR_HEAP_TYPE type,D3D12_DESCRIPTOR_HEAP_FLAGS flags,uint32_t num_descriptors)61 d3d12_descriptor_heap_new(ID3D12Device *dev,
62                           D3D12_DESCRIPTOR_HEAP_TYPE type,
63                           D3D12_DESCRIPTOR_HEAP_FLAGS flags,
64                           uint32_t num_descriptors)
65 {
66    struct d3d12_descriptor_heap *heap = CALLOC_STRUCT(d3d12_descriptor_heap);
67 
68    heap->desc.NumDescriptors = num_descriptors;
69    heap->desc.Type = type;
70    heap->desc.Flags = flags;
71    if (FAILED(dev->CreateDescriptorHeap(&heap->desc,
72                                         IID_PPV_ARGS(&heap->heap)))) {
73       FREE(heap);
74       return NULL;
75    }
76 
77    heap->dev = dev;
78    heap->desc_size = dev->GetDescriptorHandleIncrementSize(type);
79    heap->size = num_descriptors * heap->desc_size;
80    heap->cpu_base = heap->heap->GetCPUDescriptorHandleForHeapStart().ptr;
81    if (flags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)
82       heap->gpu_base = heap->heap->GetGPUDescriptorHandleForHeapStart().ptr;
83    util_dynarray_init(&heap->free_list, NULL);
84 
85    return heap;
86 }
87 
88 void
d3d12_descriptor_heap_free(struct d3d12_descriptor_heap * heap)89 d3d12_descriptor_heap_free(struct d3d12_descriptor_heap *heap)
90 {
91    heap->heap->Release();
92    util_dynarray_fini(&heap->free_list);
93    FREE(heap);
94 }
95 
96 ID3D12DescriptorHeap*
d3d12_descriptor_heap_get(struct d3d12_descriptor_heap * heap)97 d3d12_descriptor_heap_get(struct d3d12_descriptor_heap *heap)
98 {
99    return heap->heap;
100 }
101 
102 static uint32_t
d3d12_descriptor_heap_is_online(struct d3d12_descriptor_heap * heap)103 d3d12_descriptor_heap_is_online(struct d3d12_descriptor_heap *heap)
104 {
105    return (heap->desc.Flags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE) ? 1 : 0;
106 }
107 
108 static uint32_t
d3d12_descriptor_heap_can_allocate(struct d3d12_descriptor_heap * heap)109 d3d12_descriptor_heap_can_allocate(struct d3d12_descriptor_heap *heap)
110 {
111    return (heap->free_list.size > 0 ||
112            heap->size >= heap->next + heap->desc_size);
113 }
114 
115 uint32_t
d3d12_descriptor_heap_get_remaining_handles(struct d3d12_descriptor_heap * heap)116 d3d12_descriptor_heap_get_remaining_handles(struct d3d12_descriptor_heap *heap)
117 {
118    return (heap->size - heap->next) / heap->desc_size;
119 }
120 
121 void
d2d12_descriptor_heap_get_next_handle(struct d3d12_descriptor_heap * heap,struct d3d12_descriptor_handle * handle)122 d2d12_descriptor_heap_get_next_handle(struct d3d12_descriptor_heap *heap,
123                                       struct d3d12_descriptor_handle *handle)
124 {
125    handle->heap = heap;
126    handle->cpu_handle.ptr = heap->cpu_base + heap->next;
127    handle->gpu_handle.ptr = d3d12_descriptor_heap_is_online(heap) ?
128                             heap->gpu_base + heap->next : 0;
129 }
130 
131 uint32_t
d3d12_descriptor_heap_alloc_handle(struct d3d12_descriptor_heap * heap,struct d3d12_descriptor_handle * handle)132 d3d12_descriptor_heap_alloc_handle(struct d3d12_descriptor_heap *heap,
133                                    struct d3d12_descriptor_handle *handle)
134 {
135    uint32_t offset = 0;
136 
137    assert(handle != NULL);
138 
139    if (heap->free_list.size > 0) {
140       offset = util_dynarray_pop(&heap->free_list, uint32_t);
141    } else if (heap->size >= heap->next + heap->desc_size) {
142       offset = heap->next;
143       heap->next += heap->desc_size;
144    } else {
145       /* Todo: we should add a new descriptor heap to get more handles */
146       assert(0 && "No handles available in descriptor heap");
147       return 0;
148    }
149 
150    handle->heap = heap;
151    handle->cpu_handle.ptr = heap->cpu_base + offset;
152    handle->gpu_handle.ptr = d3d12_descriptor_heap_is_online(heap) ?
153                             heap->gpu_base + offset : 0;
154 
155    return 1;
156 }
157 
158 void
d3d12_descriptor_handle_free(struct d3d12_descriptor_handle * handle)159 d3d12_descriptor_handle_free(struct d3d12_descriptor_handle *handle)
160 {
161    const uint32_t index = handle->cpu_handle.ptr - handle->heap->cpu_base;
162    if (index + handle->heap->desc_size == handle->heap->next) {
163       handle->heap->next = index;
164    } else {
165       util_dynarray_append(&handle->heap->free_list, uint32_t, index);
166    }
167 
168    handle->heap = NULL;
169    handle->cpu_handle.ptr = 0;
170    handle->gpu_handle.ptr = 0;
171 }
172 
173 void
d3d12_descriptor_heap_append_handles(struct d3d12_descriptor_heap * heap,D3D12_CPU_DESCRIPTOR_HANDLE * handles,unsigned num_handles)174 d3d12_descriptor_heap_append_handles(struct d3d12_descriptor_heap *heap,
175                                      D3D12_CPU_DESCRIPTOR_HANDLE *handles,
176                                      unsigned num_handles)
177 {
178    D3D12_CPU_DESCRIPTOR_HANDLE dst;
179 
180    assert(heap->next + (num_handles * heap->desc_size) <= heap->size);
181    dst.ptr = heap->cpu_base + heap->next;
182    heap->dev->CopyDescriptors(1, &dst, &num_handles,
183                               num_handles, handles, NULL,
184                               heap->desc.Type);
185    heap->next += num_handles * heap->desc_size;
186 }
187 
188 void
d3d12_descriptor_heap_clear(struct d3d12_descriptor_heap * heap)189 d3d12_descriptor_heap_clear(struct d3d12_descriptor_heap *heap)
190 {
191    heap->next = 0;
192    util_dynarray_clear(&heap->free_list);
193 }
194 
195 struct d3d12_descriptor_pool*
d3d12_descriptor_pool_new(struct d3d12_screen * screen,D3D12_DESCRIPTOR_HEAP_TYPE type,uint32_t num_descriptors)196 d3d12_descriptor_pool_new(struct d3d12_screen *screen,
197                           D3D12_DESCRIPTOR_HEAP_TYPE type,
198                           uint32_t num_descriptors)
199 {
200    struct d3d12_descriptor_pool *pool = CALLOC_STRUCT(d3d12_descriptor_pool);
201    if (!pool)
202       return NULL;
203 
204    pool->dev = screen->dev;
205    pool->type = type;
206    pool->num_descriptors = num_descriptors;
207    list_inithead(&pool->heaps);
208 
209    return pool;
210 }
211 
212 void
d3d12_descriptor_pool_free(struct d3d12_descriptor_pool * pool)213 d3d12_descriptor_pool_free(struct d3d12_descriptor_pool *pool)
214 {
215    list_for_each_entry_safe(struct d3d12_descriptor_heap, heap, &pool->heaps, link) {
216       list_del(&heap->link);
217       d3d12_descriptor_heap_free(heap);
218    }
219    FREE(pool);
220 }
221 
222 uint32_t
d3d12_descriptor_pool_alloc_handle(struct d3d12_descriptor_pool * pool,struct d3d12_descriptor_handle * handle)223 d3d12_descriptor_pool_alloc_handle(struct d3d12_descriptor_pool *pool,
224                                    struct d3d12_descriptor_handle *handle)
225 {
226    struct d3d12_descriptor_heap *valid_heap = NULL;
227 
228    list_for_each_entry(struct d3d12_descriptor_heap, heap, &pool->heaps, link) {
229       if (d3d12_descriptor_heap_can_allocate(heap)) {
230          valid_heap = heap;
231          break;
232       }
233    }
234 
235    if (!valid_heap) {
236       valid_heap = d3d12_descriptor_heap_new(pool->dev,
237                                              pool->type,
238                                              D3D12_DESCRIPTOR_HEAP_FLAG_NONE,
239                                              pool->num_descriptors);
240       list_addtail(&valid_heap->link, &pool->heaps);
241    }
242 
243    return d3d12_descriptor_heap_alloc_handle(valid_heap, handle);
244 }
245