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_batch.h" 25#include "d3d12_context.h" 26#include "d3d12_fence.h" 27#include "d3d12_query.h" 28#include "d3d12_resource.h" 29#include "d3d12_screen.h" 30#include "d3d12_surface.h" 31 32#include "util/hash_table.h" 33#include "util/set.h" 34#include "util/u_inlines.h" 35 36#include <dxguids/dxguids.h> 37 38bool 39d3d12_init_batch(struct d3d12_context *ctx, struct d3d12_batch *batch) 40{ 41 struct d3d12_screen *screen = d3d12_screen(ctx->base.screen); 42 43 batch->bos = _mesa_set_create(NULL, _mesa_hash_pointer, 44 _mesa_key_pointer_equal); 45 batch->sampler_views = _mesa_set_create(NULL, _mesa_hash_pointer, 46 _mesa_key_pointer_equal); 47 batch->surfaces = _mesa_set_create(NULL, _mesa_hash_pointer, 48 _mesa_key_pointer_equal); 49 batch->objects = _mesa_set_create(NULL, 50 _mesa_hash_pointer, 51 _mesa_key_pointer_equal); 52 53 if (!batch->bos || !batch->sampler_views || !batch->surfaces || !batch->objects) 54 return false; 55 56 util_dynarray_init(&batch->zombie_samplers, NULL); 57 58 if (FAILED(screen->dev->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, 59 IID_PPV_ARGS(&batch->cmdalloc)))) 60 return false; 61 62 63 batch->sampler_heap = 64 d3d12_descriptor_heap_new(screen->dev, 65 D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, 66 D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE, 67 128); 68 69 batch->view_heap = 70 d3d12_descriptor_heap_new(screen->dev, 71 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 72 D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE, 73 1024); 74 75 if (!batch->sampler_heap && !batch->view_heap) 76 return false; 77 78 return true; 79} 80 81static void 82delete_bo(set_entry *entry) 83{ 84 struct d3d12_bo *bo = (struct d3d12_bo *)entry->key; 85 d3d12_bo_unreference(bo); 86} 87 88static void 89delete_sampler_view(set_entry *entry) 90{ 91 struct pipe_sampler_view *pres = (struct pipe_sampler_view *)entry->key; 92 pipe_sampler_view_reference(&pres, NULL); 93} 94 95static void 96delete_surface(set_entry *entry) 97{ 98 struct pipe_surface *surf = (struct pipe_surface *)entry->key; 99 pipe_surface_reference(&surf, NULL); 100} 101 102static void 103delete_object(set_entry *entry) 104{ 105 ID3D12Object *object = (ID3D12Object *)entry->key; 106 object->Release(); 107} 108 109bool 110d3d12_reset_batch(struct d3d12_context *ctx, struct d3d12_batch *batch, uint64_t timeout_ns) 111{ 112 // batch hasn't been submitted before 113 if (!batch->fence && !batch->has_errors) 114 return true; 115 116 if (batch->fence) { 117 if (!d3d12_fence_finish(batch->fence, timeout_ns)) 118 return false; 119 d3d12_fence_reference(&batch->fence, NULL); 120 } 121 122 _mesa_set_clear(batch->bos, delete_bo); 123 _mesa_set_clear(batch->sampler_views, delete_sampler_view); 124 _mesa_set_clear(batch->surfaces, delete_surface); 125 _mesa_set_clear(batch->objects, delete_object); 126 127 util_dynarray_foreach(&batch->zombie_samplers, d3d12_descriptor_handle, handle) 128 d3d12_descriptor_handle_free(handle); 129 util_dynarray_clear(&batch->zombie_samplers); 130 131 d3d12_descriptor_heap_clear(batch->view_heap); 132 d3d12_descriptor_heap_clear(batch->sampler_heap); 133 134 if (FAILED(batch->cmdalloc->Reset())) { 135 debug_printf("D3D12: resetting ID3D12CommandAllocator failed\n"); 136 return false; 137 } 138 batch->has_errors = false; 139 return true; 140} 141 142void 143d3d12_destroy_batch(struct d3d12_context *ctx, struct d3d12_batch *batch) 144{ 145 d3d12_reset_batch(ctx, batch, PIPE_TIMEOUT_INFINITE); 146 batch->cmdalloc->Release(); 147 d3d12_descriptor_heap_free(batch->sampler_heap); 148 d3d12_descriptor_heap_free(batch->view_heap); 149 _mesa_set_destroy(batch->bos, NULL); 150 _mesa_set_destroy(batch->sampler_views, NULL); 151 _mesa_set_destroy(batch->surfaces, NULL); 152 _mesa_set_destroy(batch->objects, NULL); 153 util_dynarray_fini(&batch->zombie_samplers); 154} 155 156void 157d3d12_start_batch(struct d3d12_context *ctx, struct d3d12_batch *batch) 158{ 159 struct d3d12_screen *screen = d3d12_screen(ctx->base.screen); 160 ID3D12DescriptorHeap* heaps[2] = { d3d12_descriptor_heap_get(batch->view_heap), 161 d3d12_descriptor_heap_get(batch->sampler_heap) }; 162 163 d3d12_reset_batch(ctx, batch, PIPE_TIMEOUT_INFINITE); 164 165 /* Create or reset global command list */ 166 if (ctx->cmdlist) { 167 if (FAILED(ctx->cmdlist->Reset(batch->cmdalloc, NULL))) { 168 debug_printf("D3D12: resetting ID3D12GraphicsCommandList failed\n"); 169 batch->has_errors = true; 170 return; 171 } 172 } else { 173 if (FAILED(screen->dev->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, 174 batch->cmdalloc, NULL, 175 IID_PPV_ARGS(&ctx->cmdlist)))) { 176 debug_printf("D3D12: creating ID3D12GraphicsCommandList failed\n"); 177 batch->has_errors = true; 178 return; 179 } 180 } 181 182 ctx->cmdlist->SetDescriptorHeaps(2, heaps); 183 ctx->cmdlist_dirty = ~0; 184 for (int i = 0; i < D3D12_GFX_SHADER_STAGES; ++i) 185 ctx->shader_dirty[i] = ~0; 186 187 if (!ctx->queries_disabled) 188 d3d12_resume_queries(ctx); 189} 190 191void 192d3d12_end_batch(struct d3d12_context *ctx, struct d3d12_batch *batch) 193{ 194 struct d3d12_screen *screen = d3d12_screen(ctx->base.screen); 195 196 if (!ctx->queries_disabled) 197 d3d12_suspend_queries(ctx); 198 199 if (FAILED(ctx->cmdlist->Close())) { 200 debug_printf("D3D12: closing ID3D12GraphicsCommandList failed\n"); 201 batch->has_errors = true; 202 return; 203 } 204 205 ID3D12CommandList* cmdlists[] = { ctx->cmdlist }; 206 screen->cmdqueue->ExecuteCommandLists(1, cmdlists); 207 batch->fence = d3d12_create_fence(screen, ctx); 208} 209 210bool 211d3d12_batch_has_references(struct d3d12_batch *batch, 212 struct d3d12_bo *bo) 213{ 214 return (_mesa_set_search(batch->bos, bo) != NULL); 215} 216 217void 218d3d12_batch_reference_resource(struct d3d12_batch *batch, 219 struct d3d12_resource *res) 220{ 221 bool found = false; 222 _mesa_set_search_and_add(batch->bos, res->bo, &found); 223 if (!found) 224 d3d12_bo_reference(res->bo); 225} 226 227void 228d3d12_batch_reference_sampler_view(struct d3d12_batch *batch, 229 struct d3d12_sampler_view *sv) 230{ 231 struct set_entry *entry = _mesa_set_search(batch->sampler_views, sv); 232 if (!entry) { 233 entry = _mesa_set_add(batch->sampler_views, sv); 234 pipe_reference(NULL, &sv->base.reference); 235 } 236} 237 238void 239d3d12_batch_reference_surface_texture(struct d3d12_batch *batch, 240 struct d3d12_surface *surf) 241{ 242 d3d12_batch_reference_resource(batch, d3d12_resource(surf->base.texture)); 243} 244 245void 246d3d12_batch_reference_object(struct d3d12_batch *batch, 247 ID3D12Object *object) 248{ 249 struct set_entry *entry = _mesa_set_search(batch->objects, object); 250 if (!entry) { 251 entry = _mesa_set_add(batch->objects, object); 252 object->AddRef(); 253 } 254} 255