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
38struct d3d12_descriptor_pool {
39   ID3D12Device *dev;
40   D3D12_DESCRIPTOR_HEAP_TYPE type;
41   uint32_t num_descriptors;
42   list_head heaps;
43};
44
45struct 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
60struct d3d12_descriptor_heap*
61d3d12_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
88void
89d3d12_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
96ID3D12DescriptorHeap*
97d3d12_descriptor_heap_get(struct d3d12_descriptor_heap *heap)
98{
99   return heap->heap;
100}
101
102static uint32_t
103d3d12_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
108static uint32_t
109d3d12_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
115uint32_t
116d3d12_descriptor_heap_get_remaining_handles(struct d3d12_descriptor_heap *heap)
117{
118   return (heap->size - heap->next) / heap->desc_size;
119}
120
121void
122d2d12_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
131uint32_t
132d3d12_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
158void
159d3d12_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
173void
174d3d12_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
188void
189d3d12_descriptor_heap_clear(struct d3d12_descriptor_heap *heap)
190{
191   heap->next = 0;
192   util_dynarray_clear(&heap->free_list);
193}
194
195struct d3d12_descriptor_pool*
196d3d12_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
212void
213d3d12_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
222uint32_t
223d3d12_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