1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © Microsoft Corporation 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21bf215546Sopenharmony_ci * IN THE SOFTWARE. 22bf215546Sopenharmony_ci */ 23bf215546Sopenharmony_ci 24bf215546Sopenharmony_ci#include "d3d12_bufmgr.h" 25bf215546Sopenharmony_ci#include "d3d12_context.h" 26bf215546Sopenharmony_ci#include "d3d12_format.h" 27bf215546Sopenharmony_ci#include "d3d12_resource.h" 28bf215546Sopenharmony_ci#include "d3d12_resource_state.h" 29bf215546Sopenharmony_ci#include "d3d12_screen.h" 30bf215546Sopenharmony_ci 31bf215546Sopenharmony_ci#include <dxguids/dxguids.h> 32bf215546Sopenharmony_ci 33bf215546Sopenharmony_ci#include <assert.h> 34bf215546Sopenharmony_ci 35bf215546Sopenharmony_ci#define UNKNOWN_RESOURCE_STATE (D3D12_RESOURCE_STATES) 0x8000u 36bf215546Sopenharmony_ci 37bf215546Sopenharmony_ci/* Stores the current desired state of either an entire resource, or each subresource. */ 38bf215546Sopenharmony_cistruct desired_resource_state 39bf215546Sopenharmony_ci{ 40bf215546Sopenharmony_ci bool homogenous; 41bf215546Sopenharmony_ci uint32_t num_subresources; 42bf215546Sopenharmony_ci D3D12_RESOURCE_STATES *subresource_states; 43bf215546Sopenharmony_ci}; 44bf215546Sopenharmony_ci 45bf215546Sopenharmony_cistatic bool 46bf215546Sopenharmony_cidesired_resource_state_init(desired_resource_state *state, uint32_t subresource_count) 47bf215546Sopenharmony_ci{ 48bf215546Sopenharmony_ci state->homogenous = true; 49bf215546Sopenharmony_ci state->num_subresources = subresource_count; 50bf215546Sopenharmony_ci state->subresource_states = (D3D12_RESOURCE_STATES *)calloc(subresource_count, sizeof(D3D12_RESOURCE_STATES)); 51bf215546Sopenharmony_ci return state->subresource_states != nullptr; 52bf215546Sopenharmony_ci} 53bf215546Sopenharmony_ci 54bf215546Sopenharmony_cistatic void 55bf215546Sopenharmony_cidesired_resource_state_cleanup(desired_resource_state *state) 56bf215546Sopenharmony_ci{ 57bf215546Sopenharmony_ci free(state->subresource_states); 58bf215546Sopenharmony_ci} 59bf215546Sopenharmony_ci 60bf215546Sopenharmony_cistatic D3D12_RESOURCE_STATES 61bf215546Sopenharmony_ciget_desired_subresource_state(const desired_resource_state *state, uint32_t subresource_index) 62bf215546Sopenharmony_ci{ 63bf215546Sopenharmony_ci if (state->homogenous) 64bf215546Sopenharmony_ci subresource_index = 0; 65bf215546Sopenharmony_ci return state->subresource_states[subresource_index]; 66bf215546Sopenharmony_ci} 67bf215546Sopenharmony_ci 68bf215546Sopenharmony_cistatic void 69bf215546Sopenharmony_ciupdate_subresource_state(D3D12_RESOURCE_STATES *existing_state, D3D12_RESOURCE_STATES new_state) 70bf215546Sopenharmony_ci{ 71bf215546Sopenharmony_ci if (*existing_state == UNKNOWN_RESOURCE_STATE || new_state == UNKNOWN_RESOURCE_STATE || 72bf215546Sopenharmony_ci d3d12_is_write_state(new_state)) { 73bf215546Sopenharmony_ci *existing_state = new_state; 74bf215546Sopenharmony_ci } else { 75bf215546Sopenharmony_ci /* Accumulate read state state bits */ 76bf215546Sopenharmony_ci *existing_state |= new_state; 77bf215546Sopenharmony_ci } 78bf215546Sopenharmony_ci} 79bf215546Sopenharmony_ci 80bf215546Sopenharmony_cistatic void 81bf215546Sopenharmony_ciset_desired_resource_state(desired_resource_state *state_obj, D3D12_RESOURCE_STATES state) 82bf215546Sopenharmony_ci{ 83bf215546Sopenharmony_ci state_obj->homogenous = true; 84bf215546Sopenharmony_ci update_subresource_state(&state_obj->subresource_states[0], state); 85bf215546Sopenharmony_ci} 86bf215546Sopenharmony_ci 87bf215546Sopenharmony_cistatic void 88bf215546Sopenharmony_ciset_desired_subresource_state(desired_resource_state *state_obj, 89bf215546Sopenharmony_ci uint32_t subresource, 90bf215546Sopenharmony_ci D3D12_RESOURCE_STATES state) 91bf215546Sopenharmony_ci{ 92bf215546Sopenharmony_ci if (state_obj->homogenous && state_obj->num_subresources > 1) { 93bf215546Sopenharmony_ci for (unsigned i = 1; i < state_obj->num_subresources; ++i) { 94bf215546Sopenharmony_ci state_obj->subresource_states[i] = state_obj->subresource_states[0]; 95bf215546Sopenharmony_ci } 96bf215546Sopenharmony_ci state_obj->homogenous = false; 97bf215546Sopenharmony_ci } 98bf215546Sopenharmony_ci 99bf215546Sopenharmony_ci update_subresource_state(&state_obj->subresource_states[subresource], state); 100bf215546Sopenharmony_ci} 101bf215546Sopenharmony_ci 102bf215546Sopenharmony_cistatic void 103bf215546Sopenharmony_cireset_desired_resource_state(desired_resource_state *state_obj) 104bf215546Sopenharmony_ci{ 105bf215546Sopenharmony_ci set_desired_resource_state(state_obj, UNKNOWN_RESOURCE_STATE); 106bf215546Sopenharmony_ci} 107bf215546Sopenharmony_ci 108bf215546Sopenharmony_cibool 109bf215546Sopenharmony_cid3d12_resource_state_init(d3d12_resource_state *state, uint32_t subresource_count, bool simultaneous_access) 110bf215546Sopenharmony_ci{ 111bf215546Sopenharmony_ci state->homogenous = true; 112bf215546Sopenharmony_ci state->supports_simultaneous_access = simultaneous_access; 113bf215546Sopenharmony_ci state->num_subresources = subresource_count; 114bf215546Sopenharmony_ci state->subresource_states = (d3d12_subresource_state *)calloc(subresource_count, sizeof(d3d12_subresource_state)); 115bf215546Sopenharmony_ci return state->subresource_states != nullptr; 116bf215546Sopenharmony_ci} 117bf215546Sopenharmony_ci 118bf215546Sopenharmony_civoid 119bf215546Sopenharmony_cid3d12_resource_state_cleanup(d3d12_resource_state *state) 120bf215546Sopenharmony_ci{ 121bf215546Sopenharmony_ci free(state->subresource_states); 122bf215546Sopenharmony_ci} 123bf215546Sopenharmony_ci 124bf215546Sopenharmony_cistatic const d3d12_subresource_state * 125bf215546Sopenharmony_ciget_subresource_state(const d3d12_resource_state *state, uint32_t subresource) 126bf215546Sopenharmony_ci{ 127bf215546Sopenharmony_ci if (state->homogenous) 128bf215546Sopenharmony_ci subresource = 0; 129bf215546Sopenharmony_ci return &state->subresource_states[subresource]; 130bf215546Sopenharmony_ci} 131bf215546Sopenharmony_ci 132bf215546Sopenharmony_cistatic void 133bf215546Sopenharmony_ciset_resource_state(d3d12_resource_state *state_obj, const d3d12_subresource_state *state) 134bf215546Sopenharmony_ci{ 135bf215546Sopenharmony_ci state_obj->homogenous = true; 136bf215546Sopenharmony_ci state_obj->subresource_states[0] = *state; 137bf215546Sopenharmony_ci} 138bf215546Sopenharmony_ci 139bf215546Sopenharmony_cistatic void 140bf215546Sopenharmony_ciset_subresource_state(d3d12_resource_state *state_obj, uint32_t subresource, const d3d12_subresource_state *state) 141bf215546Sopenharmony_ci{ 142bf215546Sopenharmony_ci if (state_obj->homogenous && state_obj->num_subresources > 1) { 143bf215546Sopenharmony_ci for (unsigned i = 1; i < state_obj->num_subresources; ++i) { 144bf215546Sopenharmony_ci state_obj->subresource_states[i] = state_obj->subresource_states[0]; 145bf215546Sopenharmony_ci } 146bf215546Sopenharmony_ci state_obj->homogenous = false; 147bf215546Sopenharmony_ci } 148bf215546Sopenharmony_ci 149bf215546Sopenharmony_ci state_obj->subresource_states[subresource] = *state; 150bf215546Sopenharmony_ci} 151bf215546Sopenharmony_ci 152bf215546Sopenharmony_cistatic void 153bf215546Sopenharmony_cireset_resource_state(d3d12_resource_state *state) 154bf215546Sopenharmony_ci{ 155bf215546Sopenharmony_ci d3d12_subresource_state subres_state = {}; 156bf215546Sopenharmony_ci set_resource_state(state, &subres_state); 157bf215546Sopenharmony_ci} 158bf215546Sopenharmony_ci 159bf215546Sopenharmony_cistatic D3D12_RESOURCE_STATES 160bf215546Sopenharmony_ciresource_state_if_promoted(D3D12_RESOURCE_STATES desired_state, 161bf215546Sopenharmony_ci bool simultaneous_access, 162bf215546Sopenharmony_ci const d3d12_subresource_state *current_state) 163bf215546Sopenharmony_ci{ 164bf215546Sopenharmony_ci const D3D12_RESOURCE_STATES promotable_states = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | 165bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE | 166bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_COPY_SOURCE | D3D12_RESOURCE_STATE_COPY_DEST; 167bf215546Sopenharmony_ci 168bf215546Sopenharmony_ci if (simultaneous_access || 169bf215546Sopenharmony_ci (desired_state & promotable_states) != D3D12_RESOURCE_STATE_COMMON) { 170bf215546Sopenharmony_ci // If the current state is COMMON... 171bf215546Sopenharmony_ci if (current_state->state == D3D12_RESOURCE_STATE_COMMON) 172bf215546Sopenharmony_ci // ...then promotion is allowed 173bf215546Sopenharmony_ci return desired_state; 174bf215546Sopenharmony_ci 175bf215546Sopenharmony_ci // If the current state is a read state resulting from previous promotion... 176bf215546Sopenharmony_ci if (current_state->is_promoted && 177bf215546Sopenharmony_ci (current_state->state & D3D12_RESOURCE_STATE_GENERIC_READ) != D3D12_RESOURCE_STATE_COMMON) 178bf215546Sopenharmony_ci // ...then (accumulated) promotion is allowed 179bf215546Sopenharmony_ci return desired_state | current_state->state; 180bf215546Sopenharmony_ci } 181bf215546Sopenharmony_ci 182bf215546Sopenharmony_ci return D3D12_RESOURCE_STATE_COMMON; 183bf215546Sopenharmony_ci} 184bf215546Sopenharmony_ci 185bf215546Sopenharmony_cistatic void 186bf215546Sopenharmony_cicopy_resource_state(d3d12_resource_state *dest, d3d12_resource_state *src) 187bf215546Sopenharmony_ci{ 188bf215546Sopenharmony_ci assert(dest->num_subresources == src->num_subresources); 189bf215546Sopenharmony_ci if (src->homogenous) 190bf215546Sopenharmony_ci set_resource_state(dest, &src->subresource_states[0]); 191bf215546Sopenharmony_ci else { 192bf215546Sopenharmony_ci dest->homogenous = false; 193bf215546Sopenharmony_ci for (unsigned i = 0; i < src->num_subresources; ++i) 194bf215546Sopenharmony_ci dest->subresource_states[i] = src->subresource_states[i]; 195bf215546Sopenharmony_ci } 196bf215546Sopenharmony_ci} 197bf215546Sopenharmony_ci 198bf215546Sopenharmony_cistruct d3d12_context_state_table_entry 199bf215546Sopenharmony_ci{ 200bf215546Sopenharmony_ci struct desired_resource_state desired; 201bf215546Sopenharmony_ci struct d3d12_resource_state batch_begin, batch_end; 202bf215546Sopenharmony_ci}; 203bf215546Sopenharmony_ci 204bf215546Sopenharmony_cistatic void 205bf215546Sopenharmony_cidestroy_context_state_table_entry(d3d12_context_state_table_entry *entry) 206bf215546Sopenharmony_ci{ 207bf215546Sopenharmony_ci desired_resource_state_cleanup(&entry->desired); 208bf215546Sopenharmony_ci d3d12_resource_state_cleanup(&entry->batch_begin); 209bf215546Sopenharmony_ci d3d12_resource_state_cleanup(&entry->batch_end); 210bf215546Sopenharmony_ci free(entry); 211bf215546Sopenharmony_ci} 212bf215546Sopenharmony_ci 213bf215546Sopenharmony_civoid 214bf215546Sopenharmony_cid3d12_context_state_table_init(struct d3d12_context *ctx) 215bf215546Sopenharmony_ci{ 216bf215546Sopenharmony_ci ctx->bo_state_table = _mesa_hash_table_u64_create(nullptr); 217bf215546Sopenharmony_ci ctx->pending_barriers_bos = _mesa_pointer_set_create(nullptr); 218bf215546Sopenharmony_ci} 219bf215546Sopenharmony_ci 220bf215546Sopenharmony_civoid 221bf215546Sopenharmony_cid3d12_context_state_table_destroy(struct d3d12_context *ctx) 222bf215546Sopenharmony_ci{ 223bf215546Sopenharmony_ci hash_table_foreach(ctx->bo_state_table->table, entry) 224bf215546Sopenharmony_ci destroy_context_state_table_entry((d3d12_context_state_table_entry *)entry->data); 225bf215546Sopenharmony_ci _mesa_hash_table_u64_destroy(ctx->bo_state_table); 226bf215546Sopenharmony_ci util_dynarray_fini(&ctx->barrier_scratch); 227bf215546Sopenharmony_ci if (ctx->state_fixup_cmdlist) 228bf215546Sopenharmony_ci ctx->state_fixup_cmdlist->Release(); 229bf215546Sopenharmony_ci _mesa_set_destroy(ctx->pending_barriers_bos, nullptr); 230bf215546Sopenharmony_ci} 231bf215546Sopenharmony_ci 232bf215546Sopenharmony_cistatic unsigned 233bf215546Sopenharmony_ciget_subresource_count(const D3D12_RESOURCE_DESC *desc) 234bf215546Sopenharmony_ci{ 235bf215546Sopenharmony_ci unsigned array_size = desc->Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D ? 1 : desc->DepthOrArraySize; 236bf215546Sopenharmony_ci return desc->MipLevels * array_size * d3d12_non_opaque_plane_count(desc->Format); 237bf215546Sopenharmony_ci} 238bf215546Sopenharmony_ci 239bf215546Sopenharmony_cistatic void 240bf215546Sopenharmony_ciinit_state_table_entry(d3d12_context_state_table_entry *bo_state, d3d12_bo *bo) 241bf215546Sopenharmony_ci{ 242bf215546Sopenharmony_ci /* Default parameters for bos for suballocated buffers */ 243bf215546Sopenharmony_ci unsigned subresource_count = 1; 244bf215546Sopenharmony_ci bool supports_simultaneous_access = true; 245bf215546Sopenharmony_ci if (bo->res) { 246bf215546Sopenharmony_ci D3D12_RESOURCE_DESC desc = GetDesc(bo->res); 247bf215546Sopenharmony_ci subresource_count = get_subresource_count(&desc); 248bf215546Sopenharmony_ci supports_simultaneous_access = d3d12_resource_supports_simultaneous_access(&desc); 249bf215546Sopenharmony_ci } 250bf215546Sopenharmony_ci 251bf215546Sopenharmony_ci desired_resource_state_init(&bo_state->desired, subresource_count); 252bf215546Sopenharmony_ci d3d12_resource_state_init(&bo_state->batch_end, subresource_count, supports_simultaneous_access); 253bf215546Sopenharmony_ci 254bf215546Sopenharmony_ci /* We'll never need state fixups for simultaneous access resources, so don't bother initializing this second state */ 255bf215546Sopenharmony_ci if (!supports_simultaneous_access) 256bf215546Sopenharmony_ci d3d12_resource_state_init(&bo_state->batch_begin, subresource_count, supports_simultaneous_access); 257bf215546Sopenharmony_ci} 258bf215546Sopenharmony_ci 259bf215546Sopenharmony_cistatic d3d12_context_state_table_entry * 260bf215546Sopenharmony_cifind_or_create_state_entry(struct hash_table_u64 *table, d3d12_bo *bo) 261bf215546Sopenharmony_ci{ 262bf215546Sopenharmony_ci d3d12_context_state_table_entry *bo_state = 263bf215546Sopenharmony_ci (d3d12_context_state_table_entry *) _mesa_hash_table_u64_search(table, bo->unique_id); 264bf215546Sopenharmony_ci if (!bo_state) { 265bf215546Sopenharmony_ci bo_state = CALLOC_STRUCT(d3d12_context_state_table_entry); 266bf215546Sopenharmony_ci init_state_table_entry(bo_state, bo); 267bf215546Sopenharmony_ci _mesa_hash_table_u64_insert(table, bo->unique_id, bo_state); 268bf215546Sopenharmony_ci } 269bf215546Sopenharmony_ci return bo_state; 270bf215546Sopenharmony_ci} 271bf215546Sopenharmony_ci 272bf215546Sopenharmony_cistatic ID3D12GraphicsCommandList * 273bf215546Sopenharmony_ciensure_state_fixup_cmdlist(struct d3d12_context *ctx, ID3D12CommandAllocator *alloc) 274bf215546Sopenharmony_ci{ 275bf215546Sopenharmony_ci if (!ctx->state_fixup_cmdlist) { 276bf215546Sopenharmony_ci struct d3d12_screen *screen = d3d12_screen(ctx->base.screen); 277bf215546Sopenharmony_ci screen->dev->CreateCommandList(0, 278bf215546Sopenharmony_ci D3D12_COMMAND_LIST_TYPE_DIRECT, 279bf215546Sopenharmony_ci alloc, 280bf215546Sopenharmony_ci nullptr, 281bf215546Sopenharmony_ci IID_PPV_ARGS(&ctx->state_fixup_cmdlist)); 282bf215546Sopenharmony_ci } else if (FAILED(ctx->state_fixup_cmdlist->Reset(alloc, nullptr))) { 283bf215546Sopenharmony_ci ctx->state_fixup_cmdlist->Release(); 284bf215546Sopenharmony_ci ctx->state_fixup_cmdlist = nullptr; 285bf215546Sopenharmony_ci } 286bf215546Sopenharmony_ci 287bf215546Sopenharmony_ci return ctx->state_fixup_cmdlist; 288bf215546Sopenharmony_ci} 289bf215546Sopenharmony_ci 290bf215546Sopenharmony_cistatic bool 291bf215546Sopenharmony_citransition_required(D3D12_RESOURCE_STATES current_state, D3D12_RESOURCE_STATES *destination_state) 292bf215546Sopenharmony_ci{ 293bf215546Sopenharmony_ci // An exact match never needs a transition. 294bf215546Sopenharmony_ci if (current_state == *destination_state) { 295bf215546Sopenharmony_ci return false; 296bf215546Sopenharmony_ci } 297bf215546Sopenharmony_ci 298bf215546Sopenharmony_ci if (current_state == D3D12_RESOURCE_STATE_COMMON || *destination_state == D3D12_RESOURCE_STATE_COMMON) { 299bf215546Sopenharmony_ci return true; 300bf215546Sopenharmony_ci } 301bf215546Sopenharmony_ci 302bf215546Sopenharmony_ci // Current state already contains the destination state, we're good. 303bf215546Sopenharmony_ci if ((current_state & *destination_state) == *destination_state) { 304bf215546Sopenharmony_ci *destination_state = current_state; 305bf215546Sopenharmony_ci return false; 306bf215546Sopenharmony_ci } 307bf215546Sopenharmony_ci 308bf215546Sopenharmony_ci // If the transition involves a write state, then the destination should just be the requested destination. 309bf215546Sopenharmony_ci // Otherwise, accumulate read states to minimize future transitions (by triggering the above condition). 310bf215546Sopenharmony_ci if (!d3d12_is_write_state(*destination_state) && !d3d12_is_write_state(current_state)) { 311bf215546Sopenharmony_ci *destination_state |= current_state; 312bf215546Sopenharmony_ci } 313bf215546Sopenharmony_ci return true; 314bf215546Sopenharmony_ci} 315bf215546Sopenharmony_ci 316bf215546Sopenharmony_cistatic void 317bf215546Sopenharmony_ciresolve_global_state(struct d3d12_context *ctx, ID3D12Resource *res, d3d12_resource_state *batch_state, d3d12_resource_state *res_state) 318bf215546Sopenharmony_ci{ 319bf215546Sopenharmony_ci assert(batch_state->num_subresources == res_state->num_subresources); 320bf215546Sopenharmony_ci unsigned num_subresources = batch_state->homogenous && res_state->homogenous ? 1 : batch_state->num_subresources; 321bf215546Sopenharmony_ci for (unsigned i = 0; i < num_subresources; ++i) { 322bf215546Sopenharmony_ci const d3d12_subresource_state *current_state = get_subresource_state(res_state, i); 323bf215546Sopenharmony_ci const d3d12_subresource_state *target_state = get_subresource_state(batch_state, i); 324bf215546Sopenharmony_ci D3D12_RESOURCE_STATES promotable_state = 325bf215546Sopenharmony_ci resource_state_if_promoted(target_state->state, false, current_state); 326bf215546Sopenharmony_ci 327bf215546Sopenharmony_ci D3D12_RESOURCE_STATES after = target_state->state; 328bf215546Sopenharmony_ci if ((promotable_state & target_state->state) == target_state->state || 329bf215546Sopenharmony_ci !transition_required(current_state->state, &after)) 330bf215546Sopenharmony_ci continue; 331bf215546Sopenharmony_ci 332bf215546Sopenharmony_ci D3D12_RESOURCE_BARRIER barrier = { D3D12_RESOURCE_BARRIER_TYPE_TRANSITION }; 333bf215546Sopenharmony_ci barrier.Transition.pResource = res; 334bf215546Sopenharmony_ci barrier.Transition.StateBefore = current_state->state; 335bf215546Sopenharmony_ci barrier.Transition.StateAfter = after; 336bf215546Sopenharmony_ci barrier.Transition.Subresource = num_subresources == 1 ? D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES : i; 337bf215546Sopenharmony_ci util_dynarray_append(&ctx->barrier_scratch, D3D12_RESOURCE_BARRIER, barrier); 338bf215546Sopenharmony_ci } 339bf215546Sopenharmony_ci} 340bf215546Sopenharmony_ci 341bf215546Sopenharmony_cibool 342bf215546Sopenharmony_cid3d12_context_state_resolve_submission(struct d3d12_context *ctx, struct d3d12_batch *batch) 343bf215546Sopenharmony_ci{ 344bf215546Sopenharmony_ci util_dynarray_foreach(&ctx->recently_destroyed_bos, uint64_t, id) { 345bf215546Sopenharmony_ci void *data = _mesa_hash_table_u64_search(ctx->bo_state_table, *id); 346bf215546Sopenharmony_ci if (data) 347bf215546Sopenharmony_ci destroy_context_state_table_entry((d3d12_context_state_table_entry *)data); 348bf215546Sopenharmony_ci _mesa_hash_table_u64_remove(ctx->bo_state_table, *id); 349bf215546Sopenharmony_ci } 350bf215546Sopenharmony_ci 351bf215546Sopenharmony_ci util_dynarray_clear(&ctx->recently_destroyed_bos); 352bf215546Sopenharmony_ci 353bf215546Sopenharmony_ci hash_table_foreach(batch->bos, bo_entry) { 354bf215546Sopenharmony_ci d3d12_bo *bo = (d3d12_bo *)bo_entry->key; 355bf215546Sopenharmony_ci d3d12_context_state_table_entry *bo_state = find_or_create_state_entry(ctx->bo_state_table, bo); 356bf215546Sopenharmony_ci if (!bo_state->batch_end.supports_simultaneous_access) { 357bf215546Sopenharmony_ci assert(bo->res && bo->global_state.subresource_states); 358bf215546Sopenharmony_ci 359bf215546Sopenharmony_ci resolve_global_state(ctx, bo->res, &bo_state->batch_begin, &bo->global_state); 360bf215546Sopenharmony_ci 361bf215546Sopenharmony_ci copy_resource_state(&bo_state->batch_begin, &bo_state->batch_end); 362bf215546Sopenharmony_ci copy_resource_state(&bo->global_state, &bo_state->batch_end); 363bf215546Sopenharmony_ci } else { 364bf215546Sopenharmony_ci reset_resource_state(&bo_state->batch_end); 365bf215546Sopenharmony_ci } 366bf215546Sopenharmony_ci } 367bf215546Sopenharmony_ci 368bf215546Sopenharmony_ci bool needs_execute_fixup = false; 369bf215546Sopenharmony_ci if (ctx->barrier_scratch.size) { 370bf215546Sopenharmony_ci ID3D12GraphicsCommandList *cmdlist = ensure_state_fixup_cmdlist(ctx, batch->cmdalloc); 371bf215546Sopenharmony_ci if (cmdlist) { 372bf215546Sopenharmony_ci cmdlist->ResourceBarrier(util_dynarray_num_elements(&ctx->barrier_scratch, D3D12_RESOURCE_BARRIER), 373bf215546Sopenharmony_ci (D3D12_RESOURCE_BARRIER *)ctx->barrier_scratch.data); 374bf215546Sopenharmony_ci needs_execute_fixup = SUCCEEDED(cmdlist->Close()); 375bf215546Sopenharmony_ci } 376bf215546Sopenharmony_ci 377bf215546Sopenharmony_ci util_dynarray_clear(&ctx->barrier_scratch); 378bf215546Sopenharmony_ci } 379bf215546Sopenharmony_ci return needs_execute_fixup; 380bf215546Sopenharmony_ci} 381bf215546Sopenharmony_ci 382bf215546Sopenharmony_cistatic void 383bf215546Sopenharmony_ciappend_barrier(struct d3d12_context *ctx, 384bf215546Sopenharmony_ci d3d12_bo *bo, 385bf215546Sopenharmony_ci d3d12_context_state_table_entry *state_entry, 386bf215546Sopenharmony_ci D3D12_RESOURCE_STATES after, 387bf215546Sopenharmony_ci UINT subresource, 388bf215546Sopenharmony_ci bool is_implicit_dispatch) 389bf215546Sopenharmony_ci{ 390bf215546Sopenharmony_ci uint64_t offset; 391bf215546Sopenharmony_ci ID3D12Resource *res = d3d12_bo_get_base(bo, &offset)->res; 392bf215546Sopenharmony_ci d3d12_resource_state *current_state = &state_entry->batch_end; 393bf215546Sopenharmony_ci 394bf215546Sopenharmony_ci D3D12_RESOURCE_BARRIER transition_desc = { D3D12_RESOURCE_BARRIER_TYPE_TRANSITION }; 395bf215546Sopenharmony_ci transition_desc.Transition.pResource = res; 396bf215546Sopenharmony_ci transition_desc.Transition.Subresource = subresource; 397bf215546Sopenharmony_ci 398bf215546Sopenharmony_ci // This is a transition into a state that is both write and non-write. 399bf215546Sopenharmony_ci // This is invalid according to D3D12. We're venturing into undefined behavior 400bf215546Sopenharmony_ci // land, but let's just pick the write state. 401bf215546Sopenharmony_ci if (d3d12_is_write_state(after) && (after & ~RESOURCE_STATE_ALL_WRITE_BITS) != 0) { 402bf215546Sopenharmony_ci after &= RESOURCE_STATE_ALL_WRITE_BITS; 403bf215546Sopenharmony_ci 404bf215546Sopenharmony_ci // For now, this is the only way I've seen where this can happen. 405bf215546Sopenharmony_ci assert(after == D3D12_RESOURCE_STATE_UNORDERED_ACCESS); 406bf215546Sopenharmony_ci } 407bf215546Sopenharmony_ci 408bf215546Sopenharmony_ci assert((subresource == D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES && current_state->homogenous) || 409bf215546Sopenharmony_ci subresource < current_state->num_subresources); 410bf215546Sopenharmony_ci d3d12_subresource_state current_subresource_state = *get_subresource_state(current_state, subresource); 411bf215546Sopenharmony_ci 412bf215546Sopenharmony_ci // If the last time this state was set was in a different execution 413bf215546Sopenharmony_ci // period and is decayable then decay the current state to COMMON 414bf215546Sopenharmony_ci if (ctx->submit_id != current_subresource_state.execution_id && current_subresource_state.may_decay) { 415bf215546Sopenharmony_ci current_subresource_state.state = D3D12_RESOURCE_STATE_COMMON; 416bf215546Sopenharmony_ci current_subresource_state.is_promoted = false; 417bf215546Sopenharmony_ci } 418bf215546Sopenharmony_ci bool may_decay = false; 419bf215546Sopenharmony_ci bool is_promotion = false; 420bf215546Sopenharmony_ci 421bf215546Sopenharmony_ci D3D12_RESOURCE_STATES state_if_promoted = 422bf215546Sopenharmony_ci resource_state_if_promoted(after, current_state->supports_simultaneous_access, ¤t_subresource_state); 423bf215546Sopenharmony_ci 424bf215546Sopenharmony_ci if (D3D12_RESOURCE_STATE_COMMON == state_if_promoted) { 425bf215546Sopenharmony_ci // No promotion 426bf215546Sopenharmony_ci if (current_subresource_state.state == D3D12_RESOURCE_STATE_UNORDERED_ACCESS && 427bf215546Sopenharmony_ci after == D3D12_RESOURCE_STATE_UNORDERED_ACCESS && 428bf215546Sopenharmony_ci is_implicit_dispatch) { 429bf215546Sopenharmony_ci D3D12_RESOURCE_BARRIER uav_barrier = { D3D12_RESOURCE_BARRIER_TYPE_UAV }; 430bf215546Sopenharmony_ci uav_barrier.UAV.pResource = res; 431bf215546Sopenharmony_ci util_dynarray_append(&ctx->barrier_scratch, D3D12_RESOURCE_BARRIER, uav_barrier); 432bf215546Sopenharmony_ci } else if (transition_required(current_subresource_state.state, /*inout*/ &after)) { 433bf215546Sopenharmony_ci // Insert a single concrete barrier (for non-simultaneous access resources). 434bf215546Sopenharmony_ci transition_desc.Transition.StateBefore = current_subresource_state.state; 435bf215546Sopenharmony_ci transition_desc.Transition.StateAfter = after; 436bf215546Sopenharmony_ci assert(transition_desc.Transition.StateBefore != transition_desc.Transition.StateAfter); 437bf215546Sopenharmony_ci util_dynarray_append(&ctx->barrier_scratch, D3D12_RESOURCE_BARRIER, transition_desc); 438bf215546Sopenharmony_ci 439bf215546Sopenharmony_ci may_decay = current_state->supports_simultaneous_access && !d3d12_is_write_state(after); 440bf215546Sopenharmony_ci is_promotion = false; 441bf215546Sopenharmony_ci } 442bf215546Sopenharmony_ci } else if (after != state_if_promoted) { 443bf215546Sopenharmony_ci after = state_if_promoted; 444bf215546Sopenharmony_ci may_decay = !d3d12_is_write_state(after); 445bf215546Sopenharmony_ci is_promotion = true; 446bf215546Sopenharmony_ci } 447bf215546Sopenharmony_ci 448bf215546Sopenharmony_ci d3d12_subresource_state new_subresource_state { after, ctx->submit_id, is_promotion, may_decay }; 449bf215546Sopenharmony_ci if (subresource == D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES) 450bf215546Sopenharmony_ci set_resource_state(current_state, &new_subresource_state); 451bf215546Sopenharmony_ci else 452bf215546Sopenharmony_ci set_subresource_state(current_state, subresource, &new_subresource_state); 453bf215546Sopenharmony_ci} 454bf215546Sopenharmony_ci 455bf215546Sopenharmony_civoid 456bf215546Sopenharmony_cid3d12_transition_resource_state(struct d3d12_context *ctx, 457bf215546Sopenharmony_ci struct d3d12_resource *res, 458bf215546Sopenharmony_ci D3D12_RESOURCE_STATES state, 459bf215546Sopenharmony_ci d3d12_transition_flags flags) 460bf215546Sopenharmony_ci{ 461bf215546Sopenharmony_ci if (flags & D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS) 462bf215546Sopenharmony_ci d3d12_invalidate_context_bindings(ctx, res); 463bf215546Sopenharmony_ci 464bf215546Sopenharmony_ci d3d12_context_state_table_entry *state_entry = find_or_create_state_entry(ctx->bo_state_table, res->bo); 465bf215546Sopenharmony_ci if (flags & D3D12_TRANSITION_FLAG_ACCUMULATE_STATE) { 466bf215546Sopenharmony_ci set_desired_resource_state(&state_entry->desired, state); 467bf215546Sopenharmony_ci _mesa_set_add(ctx->pending_barriers_bos, res->bo); 468bf215546Sopenharmony_ci } else if (state_entry->batch_end.homogenous) { 469bf215546Sopenharmony_ci append_barrier(ctx, res->bo, state_entry, state, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, false); 470bf215546Sopenharmony_ci } else { 471bf215546Sopenharmony_ci for (unsigned i = 0; i < state_entry->batch_end.num_subresources; ++i) { 472bf215546Sopenharmony_ci append_barrier(ctx, res->bo, state_entry, state, i, false); 473bf215546Sopenharmony_ci } 474bf215546Sopenharmony_ci } 475bf215546Sopenharmony_ci} 476bf215546Sopenharmony_ci 477bf215546Sopenharmony_civoid 478bf215546Sopenharmony_cid3d12_transition_subresources_state(struct d3d12_context *ctx, 479bf215546Sopenharmony_ci struct d3d12_resource *res, 480bf215546Sopenharmony_ci uint32_t start_level, uint32_t num_levels, 481bf215546Sopenharmony_ci uint32_t start_layer, uint32_t num_layers, 482bf215546Sopenharmony_ci uint32_t start_plane, uint32_t num_planes, 483bf215546Sopenharmony_ci D3D12_RESOURCE_STATES state, 484bf215546Sopenharmony_ci d3d12_transition_flags flags) 485bf215546Sopenharmony_ci{ 486bf215546Sopenharmony_ci if(flags & D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS) 487bf215546Sopenharmony_ci d3d12_invalidate_context_bindings(ctx, res); 488bf215546Sopenharmony_ci 489bf215546Sopenharmony_ci d3d12_context_state_table_entry *state_entry = find_or_create_state_entry(ctx->bo_state_table, res->bo); 490bf215546Sopenharmony_ci bool is_whole_resource = num_levels * num_layers * num_planes == state_entry->batch_end.num_subresources; 491bf215546Sopenharmony_ci bool is_accumulate = (flags & D3D12_TRANSITION_FLAG_ACCUMULATE_STATE) != 0; 492bf215546Sopenharmony_ci 493bf215546Sopenharmony_ci if (is_whole_resource && is_accumulate) { 494bf215546Sopenharmony_ci set_desired_resource_state(&state_entry->desired, state); 495bf215546Sopenharmony_ci } else if (is_whole_resource && state_entry->batch_end.homogenous) { 496bf215546Sopenharmony_ci append_barrier(ctx, res->bo, state_entry, state, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, false); 497bf215546Sopenharmony_ci } else { 498bf215546Sopenharmony_ci for (uint32_t l = 0; l < num_levels; l++) { 499bf215546Sopenharmony_ci const uint32_t level = start_level + l; 500bf215546Sopenharmony_ci for (uint32_t a = 0; a < num_layers; a++) { 501bf215546Sopenharmony_ci const uint32_t layer = start_layer + a; 502bf215546Sopenharmony_ci for (uint32_t p = 0; p < num_planes; p++) { 503bf215546Sopenharmony_ci const uint32_t plane = start_plane + p; 504bf215546Sopenharmony_ci uint32_t subres_id = 505bf215546Sopenharmony_ci level + (layer * res->mip_levels) + plane * (res->mip_levels * res->base.b.array_size); 506bf215546Sopenharmony_ci assert(subres_id < state_entry->desired.num_subresources); 507bf215546Sopenharmony_ci if (is_accumulate) 508bf215546Sopenharmony_ci set_desired_subresource_state(&state_entry->desired, subres_id, state); 509bf215546Sopenharmony_ci else 510bf215546Sopenharmony_ci append_barrier(ctx, res->bo, state_entry, state, subres_id, false); 511bf215546Sopenharmony_ci } 512bf215546Sopenharmony_ci } 513bf215546Sopenharmony_ci } 514bf215546Sopenharmony_ci } 515bf215546Sopenharmony_ci 516bf215546Sopenharmony_ci if (is_accumulate) 517bf215546Sopenharmony_ci _mesa_set_add(ctx->pending_barriers_bos, res->bo); 518bf215546Sopenharmony_ci} 519bf215546Sopenharmony_ci 520bf215546Sopenharmony_civoid 521bf215546Sopenharmony_cid3d12_apply_resource_states(struct d3d12_context *ctx, bool is_implicit_dispatch) 522bf215546Sopenharmony_ci{ 523bf215546Sopenharmony_ci set_foreach_remove(ctx->pending_barriers_bos, entry) { 524bf215546Sopenharmony_ci d3d12_bo *bo = (d3d12_bo *)entry->key; 525bf215546Sopenharmony_ci 526bf215546Sopenharmony_ci d3d12_context_state_table_entry *state_entry = find_or_create_state_entry(ctx->bo_state_table, bo); 527bf215546Sopenharmony_ci desired_resource_state *destination_state = &state_entry->desired; 528bf215546Sopenharmony_ci d3d12_resource_state *current_state = &state_entry->batch_end; 529bf215546Sopenharmony_ci 530bf215546Sopenharmony_ci // Figure out the set of subresources that are transitioning 531bf215546Sopenharmony_ci bool all_resources_at_once = current_state->homogenous && destination_state->homogenous; 532bf215546Sopenharmony_ci 533bf215546Sopenharmony_ci UINT num_subresources = all_resources_at_once ? 1 : current_state->num_subresources; 534bf215546Sopenharmony_ci for (UINT i = 0; i < num_subresources; ++i) { 535bf215546Sopenharmony_ci D3D12_RESOURCE_STATES after = get_desired_subresource_state(destination_state, i); 536bf215546Sopenharmony_ci UINT subresource = num_subresources == 1 ? D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES : i; 537bf215546Sopenharmony_ci 538bf215546Sopenharmony_ci // Is this subresource currently being used, or is it just being iterated over? 539bf215546Sopenharmony_ci if (after == UNKNOWN_RESOURCE_STATE) { 540bf215546Sopenharmony_ci // This subresource doesn't have any transition requested - move on to the next. 541bf215546Sopenharmony_ci continue; 542bf215546Sopenharmony_ci } 543bf215546Sopenharmony_ci 544bf215546Sopenharmony_ci append_barrier(ctx, bo, state_entry, after, subresource, is_implicit_dispatch); 545bf215546Sopenharmony_ci } 546bf215546Sopenharmony_ci 547bf215546Sopenharmony_ci // Update destination states. 548bf215546Sopenharmony_ci reset_desired_resource_state(destination_state); 549bf215546Sopenharmony_ci } 550bf215546Sopenharmony_ci 551bf215546Sopenharmony_ci if (ctx->barrier_scratch.size) { 552bf215546Sopenharmony_ci ctx->cmdlist->ResourceBarrier(util_dynarray_num_elements(&ctx->barrier_scratch, D3D12_RESOURCE_BARRIER), 553bf215546Sopenharmony_ci (D3D12_RESOURCE_BARRIER *) ctx->barrier_scratch.data); 554bf215546Sopenharmony_ci util_dynarray_clear(&ctx->barrier_scratch); 555bf215546Sopenharmony_ci } 556bf215546Sopenharmony_ci} 557