Home | History | Annotate | Line # | Download | only in d3d12
      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 
     38 bool
     39 d3d12_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 
     81 static void
     82 delete_bo(set_entry *entry)
     83 {
     84    struct d3d12_bo *bo = (struct d3d12_bo *)entry->key;
     85    d3d12_bo_unreference(bo);
     86 }
     87 
     88 static void
     89 delete_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 
     95 static void
     96 delete_surface(set_entry *entry)
     97 {
     98    struct pipe_surface *surf = (struct pipe_surface *)entry->key;
     99    pipe_surface_reference(&surf, NULL);
    100 }
    101 
    102 static void
    103 delete_object(set_entry *entry)
    104 {
    105    ID3D12Object *object = (ID3D12Object *)entry->key;
    106    object->Release();
    107 }
    108 
    109 bool
    110 d3d12_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 
    142 void
    143 d3d12_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 
    156 void
    157 d3d12_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 
    191 void
    192 d3d12_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 
    210 bool
    211 d3d12_batch_has_references(struct d3d12_batch *batch,
    212                            struct d3d12_bo *bo)
    213 {
    214    return (_mesa_set_search(batch->bos, bo) != NULL);
    215 }
    216 
    217 void
    218 d3d12_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 
    227 void
    228 d3d12_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 
    238 void
    239 d3d12_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 
    245 void
    246 d3d12_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