xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/d3d12/d3d12_resource_state.cpp (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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_bufmgr.h"
25 #include "d3d12_context.h"
26 #include "d3d12_format.h"
27 #include "d3d12_resource.h"
28 #include "d3d12_resource_state.h"
29 #include "d3d12_screen.h"
30 
31 #include <dxguids/dxguids.h>
32 
33 #include <assert.h>
34 
35 #define UNKNOWN_RESOURCE_STATE (D3D12_RESOURCE_STATES) 0x8000u
36 
37 static bool
desired_resource_state_init(d3d12_desired_resource_state * state,uint32_t subresource_count)38 desired_resource_state_init(d3d12_desired_resource_state *state, uint32_t subresource_count)
39 {
40    state->homogenous = true;
41    state->num_subresources = subresource_count;
42    state->subresource_states = (D3D12_RESOURCE_STATES *)calloc(subresource_count, sizeof(D3D12_RESOURCE_STATES));
43    return state->subresource_states != nullptr;
44 }
45 
46 static void
desired_resource_state_cleanup(d3d12_desired_resource_state * state)47 desired_resource_state_cleanup(d3d12_desired_resource_state *state)
48 {
49    free(state->subresource_states);
50 }
51 
52 static D3D12_RESOURCE_STATES
get_desired_subresource_state(const d3d12_desired_resource_state * state,uint32_t subresource_index)53 get_desired_subresource_state(const d3d12_desired_resource_state *state, uint32_t subresource_index)
54 {
55    if (state->homogenous)
56       subresource_index = 0;
57    return state->subresource_states[subresource_index];
58 }
59 
60 static void
update_subresource_state(D3D12_RESOURCE_STATES * existing_state,D3D12_RESOURCE_STATES new_state)61 update_subresource_state(D3D12_RESOURCE_STATES *existing_state, D3D12_RESOURCE_STATES new_state)
62 {
63    if (*existing_state == UNKNOWN_RESOURCE_STATE || new_state == UNKNOWN_RESOURCE_STATE ||
64        d3d12_is_write_state(new_state)) {
65       *existing_state = new_state;
66    } else {
67       /* Accumulate read state state bits */
68       *existing_state |= new_state;
69    }
70 }
71 
72 static void
set_desired_resource_state(d3d12_desired_resource_state * state_obj,D3D12_RESOURCE_STATES state,bool pending_memory_barrier)73 set_desired_resource_state(d3d12_desired_resource_state *state_obj, D3D12_RESOURCE_STATES state, bool pending_memory_barrier)
74 {
75    state_obj->homogenous = true;
76    state_obj->pending_memory_barrier |= pending_memory_barrier;
77    update_subresource_state(&state_obj->subresource_states[0], state);
78 }
79 
80 static void
set_desired_subresource_state(d3d12_desired_resource_state * state_obj,uint32_t subresource,D3D12_RESOURCE_STATES state,bool pending_memory_barrier)81 set_desired_subresource_state(d3d12_desired_resource_state *state_obj,
82                               uint32_t subresource,
83                               D3D12_RESOURCE_STATES state,
84                               bool pending_memory_barrier)
85 {
86    state_obj->pending_memory_barrier |= pending_memory_barrier;
87    if (state_obj->homogenous && state_obj->num_subresources > 1) {
88       for (unsigned i = 1; i < state_obj->num_subresources; ++i) {
89          state_obj->subresource_states[i] = state_obj->subresource_states[0];
90       }
91       state_obj->homogenous = false;
92    }
93 
94    update_subresource_state(&state_obj->subresource_states[subresource], state);
95 }
96 
97 static void
reset_desired_resource_state(d3d12_desired_resource_state * state_obj)98 reset_desired_resource_state(d3d12_desired_resource_state *state_obj)
99 {
100    set_desired_resource_state(state_obj, UNKNOWN_RESOURCE_STATE, false);
101    state_obj->pending_memory_barrier = false;
102 }
103 
104 bool
d3d12_resource_state_init(d3d12_resource_state * state,uint32_t subresource_count,bool simultaneous_access)105 d3d12_resource_state_init(d3d12_resource_state *state, uint32_t subresource_count, bool simultaneous_access)
106 {
107    state->homogenous = true;
108    state->supports_simultaneous_access = simultaneous_access;
109    state->num_subresources = subresource_count;
110    state->subresource_states = (d3d12_subresource_state *)calloc(subresource_count, sizeof(d3d12_subresource_state));
111    return state->subresource_states != nullptr;
112 }
113 
114 void
d3d12_resource_state_cleanup(d3d12_resource_state * state)115 d3d12_resource_state_cleanup(d3d12_resource_state *state)
116 {
117    free(state->subresource_states);
118 }
119 
120 static const d3d12_subresource_state *
get_subresource_state(const d3d12_resource_state * state,uint32_t subresource)121 get_subresource_state(const d3d12_resource_state *state, uint32_t subresource)
122 {
123    if (state->homogenous)
124       subresource = 0;
125    return &state->subresource_states[subresource];
126 }
127 
128 static void
set_resource_state(d3d12_resource_state * state_obj,const d3d12_subresource_state * state)129 set_resource_state(d3d12_resource_state *state_obj, const d3d12_subresource_state *state)
130 {
131    state_obj->homogenous = true;
132    state_obj->subresource_states[0] = *state;
133 }
134 
135 static void
set_subresource_state(d3d12_resource_state * state_obj,uint32_t subresource,const d3d12_subresource_state * state)136 set_subresource_state(d3d12_resource_state *state_obj, uint32_t subresource, const d3d12_subresource_state *state)
137 {
138    if (state_obj->homogenous && state_obj->num_subresources > 1) {
139       for (unsigned i = 1; i < state_obj->num_subresources; ++i) {
140          state_obj->subresource_states[i] = state_obj->subresource_states[0];
141       }
142       state_obj->homogenous = false;
143    }
144 
145    state_obj->subresource_states[subresource] = *state;
146 }
147 
148 static void
reset_resource_state(d3d12_resource_state * state)149 reset_resource_state(d3d12_resource_state *state)
150 {
151    d3d12_subresource_state subres_state = {};
152    set_resource_state(state, &subres_state);
153 }
154 
155 static D3D12_RESOURCE_STATES
resource_state_if_promoted(D3D12_RESOURCE_STATES desired_state,bool simultaneous_access,const d3d12_subresource_state * current_state)156 resource_state_if_promoted(D3D12_RESOURCE_STATES desired_state,
157                            bool simultaneous_access,
158                            const d3d12_subresource_state *current_state)
159 {
160    if (simultaneous_access) {
161       // If the current state is COMMON...
162       if (current_state->state == D3D12_RESOURCE_STATE_COMMON)
163          // ...then promotion is allowed
164          return desired_state;
165 
166       // If the current state is a read state resulting from previous promotion...
167       if (current_state->is_promoted &&
168           (current_state->state & D3D12_RESOURCE_STATE_GENERIC_READ) != D3D12_RESOURCE_STATE_COMMON)
169          // ...then (accumulated) promotion is allowed
170          return desired_state | current_state->state;
171    }
172 
173    return D3D12_RESOURCE_STATE_COMMON;
174 }
175 
176 static void
copy_resource_state(d3d12_resource_state * dest,d3d12_resource_state * src)177 copy_resource_state(d3d12_resource_state *dest, d3d12_resource_state *src)
178 {
179    assert(dest->num_subresources == src->num_subresources);
180    if (src->homogenous)
181       set_resource_state(dest, &src->subresource_states[0]);
182    else {
183       dest->homogenous = false;
184       for (unsigned i = 0; i < src->num_subresources; ++i)
185          dest->subresource_states[i] = src->subresource_states[i];
186    }
187 }
188 
189 void
d3d12_destroy_context_state_table_entry(d3d12_context_state_table_entry * entry)190 d3d12_destroy_context_state_table_entry(d3d12_context_state_table_entry *entry)
191 {
192    desired_resource_state_cleanup(&entry->desired);
193    d3d12_resource_state_cleanup(&entry->batch_begin);
194    d3d12_resource_state_cleanup(&entry->batch_end);
195 }
196 
197 void
d3d12_context_state_table_init(struct d3d12_context * ctx)198 d3d12_context_state_table_init(struct d3d12_context *ctx)
199 {
200    ctx->bo_state_table = _mesa_hash_table_u64_create(nullptr);
201    ctx->pending_barriers_bos = _mesa_pointer_set_create(nullptr);
202    util_dynarray_init(&ctx->local_pending_barriers_bos, nullptr);
203 }
204 
205 void
d3d12_context_state_table_destroy(struct d3d12_context * ctx)206 d3d12_context_state_table_destroy(struct d3d12_context *ctx)
207 {
208    hash_table_foreach(ctx->bo_state_table->table, entry) {
209       d3d12_destroy_context_state_table_entry((d3d12_context_state_table_entry *)entry->data);
210       free(entry->data);
211    }
212    _mesa_hash_table_u64_destroy(ctx->bo_state_table);
213    util_dynarray_fini(&ctx->barrier_scratch);
214    if (ctx->state_fixup_cmdlist)
215       ctx->state_fixup_cmdlist->Release();
216 
217    _mesa_set_destroy(ctx->pending_barriers_bos, nullptr);
218    util_dynarray_fini(&ctx->local_pending_barriers_bos);
219 }
220 
221 static unsigned
get_subresource_count(const D3D12_RESOURCE_DESC * desc)222 get_subresource_count(const D3D12_RESOURCE_DESC *desc)
223 {
224    unsigned array_size = desc->Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D ? 1 : desc->DepthOrArraySize;
225    return desc->MipLevels * array_size * d3d12_non_opaque_plane_count(desc->Format);
226 }
227 
228 static void
init_state_table_entry(d3d12_context_state_table_entry * bo_state,d3d12_bo * bo)229 init_state_table_entry(d3d12_context_state_table_entry *bo_state, d3d12_bo *bo)
230 {
231    /* Default parameters for bos for suballocated buffers */
232    unsigned subresource_count = 1;
233    bool supports_simultaneous_access = true;
234    if (bo->res) {
235       D3D12_RESOURCE_DESC desc = GetDesc(bo->res);
236       subresource_count = get_subresource_count(&desc);
237       supports_simultaneous_access = d3d12_resource_supports_simultaneous_access(&desc);
238    }
239 
240    desired_resource_state_init(&bo_state->desired, subresource_count);
241    d3d12_resource_state_init(&bo_state->batch_end, subresource_count, supports_simultaneous_access);
242 
243    /* We'll never need state fixups for simultaneous access resources, so don't bother initializing this second state */
244    if (!supports_simultaneous_access)
245       d3d12_resource_state_init(&bo_state->batch_begin, subresource_count, supports_simultaneous_access);
246    else
247       memset(&bo_state->batch_begin, 0, sizeof(bo_state->batch_begin));
248 }
249 
250 static d3d12_context_state_table_entry *
find_or_create_state_entry(struct d3d12_context * ctx,d3d12_bo * bo)251 find_or_create_state_entry(struct d3d12_context *ctx, d3d12_bo *bo)
252 {
253    if (ctx->id != D3D12_CONTEXT_NO_ID) {
254       unsigned context_bit = 1 << ctx->id;
255       if ((bo->local_context_state_mask & context_bit) == 0) {
256          init_state_table_entry(&bo->local_context_states[ctx->id], bo);
257          bo->local_context_state_mask |= context_bit;
258       }
259       return &bo->local_context_states[ctx->id];
260    }
261 
262    d3d12_context_state_table_entry *bo_state =
263       (d3d12_context_state_table_entry *) _mesa_hash_table_u64_search(ctx->bo_state_table, bo->unique_id);
264    if (!bo_state) {
265       bo_state = CALLOC_STRUCT(d3d12_context_state_table_entry);
266       init_state_table_entry(bo_state, bo);
267       _mesa_hash_table_u64_insert(ctx->bo_state_table, bo->unique_id, bo_state);
268    }
269    return bo_state;
270 }
271 
272 static ID3D12GraphicsCommandList *
ensure_state_fixup_cmdlist(struct d3d12_context * ctx,ID3D12CommandAllocator * alloc)273 ensure_state_fixup_cmdlist(struct d3d12_context *ctx, ID3D12CommandAllocator *alloc)
274 {
275    if (!ctx->state_fixup_cmdlist) {
276       struct d3d12_screen *screen = d3d12_screen(ctx->base.screen);
277       screen->dev->CreateCommandList(0,
278                                      screen->queue_type,
279                                      alloc,
280                                      nullptr,
281                                      IID_PPV_ARGS(&ctx->state_fixup_cmdlist));
282    } else if (FAILED(ctx->state_fixup_cmdlist->Reset(alloc, nullptr))) {
283       ctx->state_fixup_cmdlist->Release();
284       ctx->state_fixup_cmdlist = nullptr;
285    }
286 
287    return ctx->state_fixup_cmdlist;
288 }
289 
290 static bool
transition_required(D3D12_RESOURCE_STATES current_state,D3D12_RESOURCE_STATES * destination_state)291 transition_required(D3D12_RESOURCE_STATES current_state, D3D12_RESOURCE_STATES *destination_state)
292 {
293    // An exact match never needs a transition.
294    if (current_state == *destination_state) {
295       return false;
296    }
297 
298    if (current_state == D3D12_RESOURCE_STATE_COMMON || *destination_state == D3D12_RESOURCE_STATE_COMMON) {
299       return true;
300    }
301 
302    // Current state already contains the destination state, we're good.
303    if ((current_state & *destination_state) == *destination_state) {
304       *destination_state = current_state;
305       return false;
306    }
307 
308    // If the transition involves a write state, then the destination should just be the requested destination.
309    // Otherwise, accumulate read states to minimize future transitions (by triggering the above condition).
310    if (!d3d12_is_write_state(*destination_state) && !d3d12_is_write_state(current_state)) {
311       *destination_state |= current_state;
312    }
313    return true;
314 }
315 
316 static void
resolve_global_state(struct d3d12_context * ctx,ID3D12Resource * res,d3d12_resource_state * batch_state,d3d12_resource_state * res_state)317 resolve_global_state(struct d3d12_context *ctx, ID3D12Resource *res, d3d12_resource_state *batch_state, d3d12_resource_state *res_state)
318 {
319    assert(batch_state->num_subresources == res_state->num_subresources);
320    unsigned num_subresources = batch_state->homogenous && res_state->homogenous ? 1 : batch_state->num_subresources;
321    for (unsigned i = 0; i < num_subresources; ++i) {
322       const d3d12_subresource_state *current_state = get_subresource_state(res_state, i);
323       const d3d12_subresource_state *target_state = get_subresource_state(batch_state, i);
324       D3D12_RESOURCE_STATES promotable_state =
325          resource_state_if_promoted(target_state->state, false, current_state);
326 
327       D3D12_RESOURCE_STATES after = target_state->state;
328       if ((promotable_state & target_state->state) == target_state->state ||
329           !transition_required(current_state->state, &after))
330          continue;
331 
332       D3D12_RESOURCE_BARRIER barrier = { D3D12_RESOURCE_BARRIER_TYPE_TRANSITION };
333       barrier.Transition.pResource = res;
334       barrier.Transition.StateBefore = current_state->state;
335       barrier.Transition.StateAfter = after;
336       barrier.Transition.Subresource = num_subresources == 1 ? D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES : i;
337       util_dynarray_append(&ctx->barrier_scratch, D3D12_RESOURCE_BARRIER, barrier);
338    }
339 }
340 
341 static void
context_state_resolve_submission(struct d3d12_context * ctx,d3d12_bo * bo)342 context_state_resolve_submission(struct d3d12_context *ctx, d3d12_bo *bo)
343 {
344    d3d12_context_state_table_entry *bo_state = find_or_create_state_entry(ctx, bo);
345    if (!bo_state->batch_end.supports_simultaneous_access) {
346       assert(bo->res && bo->global_state.subresource_states);
347 
348       resolve_global_state(ctx, bo->res, &bo_state->batch_begin, &bo->global_state);
349 
350       copy_resource_state(&bo_state->batch_begin, &bo_state->batch_end);
351       copy_resource_state(&bo->global_state, &bo_state->batch_end);
352    } else {
353       reset_resource_state(&bo_state->batch_end);
354    }
355 }
356 
357 bool
d3d12_context_state_resolve_submission(struct d3d12_context * ctx,struct d3d12_batch * batch)358 d3d12_context_state_resolve_submission(struct d3d12_context *ctx, struct d3d12_batch *batch)
359 {
360    util_dynarray_foreach(&ctx->recently_destroyed_bos, uint64_t, id) {
361       void *data = _mesa_hash_table_u64_search(ctx->bo_state_table, *id);
362       if (data)
363          d3d12_destroy_context_state_table_entry((d3d12_context_state_table_entry *)data);
364       _mesa_hash_table_u64_remove(ctx->bo_state_table, *id);
365    }
366 
367    util_dynarray_clear(&ctx->recently_destroyed_bos);
368 
369 
370    util_dynarray_foreach(&batch->local_bos, d3d12_bo*, bo)
371       context_state_resolve_submission(ctx, *bo);
372    hash_table_foreach(batch->bos, bo_entry)
373       context_state_resolve_submission(ctx, (d3d12_bo *)bo_entry->key);
374 
375 
376    bool needs_execute_fixup = false;
377    if (ctx->barrier_scratch.size) {
378       ID3D12GraphicsCommandList *cmdlist = ensure_state_fixup_cmdlist(ctx, batch->cmdalloc);
379       if (cmdlist) {
380          cmdlist->ResourceBarrier(util_dynarray_num_elements(&ctx->barrier_scratch, D3D12_RESOURCE_BARRIER),
381                                   (D3D12_RESOURCE_BARRIER *)ctx->barrier_scratch.data);
382          needs_execute_fixup = SUCCEEDED(cmdlist->Close());
383       }
384 
385       util_dynarray_clear(&ctx->barrier_scratch);
386    }
387    return needs_execute_fixup;
388 }
389 
390 static void
append_barrier(struct d3d12_context * ctx,d3d12_bo * bo,d3d12_context_state_table_entry * state_entry,D3D12_RESOURCE_STATES after,UINT subresource,bool is_implicit_dispatch,bool pending_memory_barrier)391 append_barrier(struct d3d12_context *ctx,
392                d3d12_bo *bo,
393                d3d12_context_state_table_entry *state_entry,
394                D3D12_RESOURCE_STATES after,
395                UINT subresource,
396                bool is_implicit_dispatch,
397                bool pending_memory_barrier)
398 {
399    uint64_t offset;
400    ID3D12Resource *res = d3d12_bo_get_base(bo, &offset)->res;
401    d3d12_resource_state *current_state = &state_entry->batch_end;
402 
403    D3D12_RESOURCE_BARRIER transition_desc = { D3D12_RESOURCE_BARRIER_TYPE_TRANSITION };
404    transition_desc.Transition.pResource = res;
405    transition_desc.Transition.Subresource = subresource;
406 
407    // This is a transition into a state that is both write and non-write.
408    // This is invalid according to D3D12. If there's a pending memory barrier that
409    // indicates we'll be reading from such a resource, then let the read state win.
410    // Otherwise, pick the write state.
411    if (d3d12_is_write_state(after) && (after & ~RESOURCE_STATE_ALL_WRITE_BITS) != 0) {
412       if (pending_memory_barrier) {
413          after &= ~RESOURCE_STATE_ALL_WRITE_BITS;
414       } else {
415          after &= RESOURCE_STATE_ALL_WRITE_BITS;
416 
417          // For now, this is the only way I've seen where this can happen.
418          assert(after == D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
419       }
420    }
421 
422    assert((subresource == D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES && current_state->homogenous) ||
423           subresource < current_state->num_subresources);
424    d3d12_subresource_state current_subresource_state = *get_subresource_state(current_state, subresource);
425 
426    // If the last time this state was set was in a different execution
427    // period and is decayable then decay the current state to COMMON
428    if (ctx->submit_id != current_subresource_state.execution_id && current_subresource_state.may_decay) {
429       current_subresource_state.state = D3D12_RESOURCE_STATE_COMMON;
430       current_subresource_state.is_promoted = false;
431    }
432    bool may_decay = false;
433    bool is_promotion = false;
434 
435    D3D12_RESOURCE_STATES state_if_promoted =
436       resource_state_if_promoted(after, current_state->supports_simultaneous_access, &current_subresource_state);
437 
438    if (D3D12_RESOURCE_STATE_COMMON == state_if_promoted) {
439       // No promotion
440       if (current_subresource_state.state == D3D12_RESOURCE_STATE_UNORDERED_ACCESS &&
441             after == D3D12_RESOURCE_STATE_UNORDERED_ACCESS &&
442             is_implicit_dispatch) {
443          D3D12_RESOURCE_BARRIER uav_barrier = { D3D12_RESOURCE_BARRIER_TYPE_UAV };
444          uav_barrier.UAV.pResource = res;
445          util_dynarray_append(&ctx->barrier_scratch, D3D12_RESOURCE_BARRIER, uav_barrier);
446       } else if (transition_required(current_subresource_state.state, /*inout*/ &after)) {
447          // Insert a single concrete barrier (for non-simultaneous access resources).
448          transition_desc.Transition.StateBefore = current_subresource_state.state;
449          transition_desc.Transition.StateAfter = after;
450          assert(transition_desc.Transition.StateBefore != transition_desc.Transition.StateAfter);
451          util_dynarray_append(&ctx->barrier_scratch, D3D12_RESOURCE_BARRIER, transition_desc);
452 
453          may_decay = current_state->supports_simultaneous_access && !d3d12_is_write_state(after);
454          is_promotion = false;
455       }
456    } else if (after != state_if_promoted) {
457       after = state_if_promoted;
458       may_decay = !d3d12_is_write_state(after);
459       is_promotion = true;
460    }
461 
462    d3d12_subresource_state new_subresource_state { after, ctx->submit_id, is_promotion, may_decay };
463    if (subresource == D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES)
464       set_resource_state(current_state, &new_subresource_state);
465    else
466       set_subresource_state(current_state, subresource, &new_subresource_state);
467 }
468 
469 void
d3d12_transition_resource_state(struct d3d12_context * ctx,struct d3d12_resource * res,D3D12_RESOURCE_STATES state,d3d12_transition_flags flags)470 d3d12_transition_resource_state(struct d3d12_context *ctx,
471                                 struct d3d12_resource *res,
472                                 D3D12_RESOURCE_STATES state,
473                                 d3d12_transition_flags flags)
474 {
475 
476 #ifdef HAVE_GALLIUM_D3D12_GRAPHICS
477    if (flags & D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS)
478       d3d12_invalidate_context_bindings(ctx, res);
479 #endif // HAVE_GALLIUM_D3D12_GRAPHICS
480 
481    d3d12_context_state_table_entry *state_entry = find_or_create_state_entry(ctx, res->bo);
482    bool pending_memory_barrier = (flags & D3D12_TRANSITION_FLAG_PENDING_MEMORY_BARRIER) != 0;
483    if (flags & D3D12_TRANSITION_FLAG_ACCUMULATE_STATE) {
484       set_desired_resource_state(&state_entry->desired, state, pending_memory_barrier);
485 
486       if (ctx->id != D3D12_CONTEXT_NO_ID) {
487          if ((res->bo->local_needs_resolve_state & (1 << ctx->id)) == 0) {
488             util_dynarray_append(&ctx->local_pending_barriers_bos, struct d3d12_bo*, res->bo);
489             res->bo->local_needs_resolve_state |= (1 << ctx->id);
490          }
491       }
492       else
493          _mesa_set_add(ctx->pending_barriers_bos, res->bo);
494 
495    } else if (state_entry->batch_end.homogenous) {
496       append_barrier(ctx, res->bo, state_entry, state, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, false, pending_memory_barrier);
497    } else {
498       for (unsigned i = 0; i < state_entry->batch_end.num_subresources; ++i) {
499          append_barrier(ctx, res->bo, state_entry, state, i, false, pending_memory_barrier);
500       }
501    }
502 }
503 
504 void
d3d12_transition_subresources_state(struct d3d12_context * ctx,struct d3d12_resource * res,uint32_t start_level,uint32_t num_levels,uint32_t start_layer,uint32_t num_layers,uint32_t start_plane,uint32_t num_planes,D3D12_RESOURCE_STATES state,d3d12_transition_flags flags)505 d3d12_transition_subresources_state(struct d3d12_context *ctx,
506                                     struct d3d12_resource *res,
507                                     uint32_t start_level, uint32_t num_levels,
508                                     uint32_t start_layer, uint32_t num_layers,
509                                     uint32_t start_plane, uint32_t num_planes,
510                                     D3D12_RESOURCE_STATES state,
511                                     d3d12_transition_flags flags)
512 {
513 
514 #ifdef HAVE_GALLIUM_D3D12_GRAPHICS
515    if(flags & D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS)
516       d3d12_invalidate_context_bindings(ctx, res);
517 #endif // HAVE_GALLIUM_D3D12_GRAPHICS
518 
519    d3d12_context_state_table_entry *state_entry = find_or_create_state_entry(ctx, res->bo);
520    bool is_whole_resource = num_levels * num_layers * num_planes == state_entry->batch_end.num_subresources;
521    bool is_accumulate = (flags & D3D12_TRANSITION_FLAG_ACCUMULATE_STATE) != 0;
522    bool pending_memory_barrier = (flags & D3D12_TRANSITION_FLAG_PENDING_MEMORY_BARRIER) != 0;
523 
524    if (is_whole_resource && is_accumulate) {
525       set_desired_resource_state(&state_entry->desired, state, pending_memory_barrier);
526    } else if (is_whole_resource && state_entry->batch_end.homogenous) {
527       append_barrier(ctx, res->bo, state_entry, state, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, false, pending_memory_barrier);
528    } else {
529       for (uint32_t l = 0; l < num_levels; l++) {
530          const uint32_t level = start_level + l;
531          for (uint32_t a = 0; a < num_layers; a++) {
532             const uint32_t layer = start_layer + a;
533             for (uint32_t p = 0; p < num_planes; p++) {
534                const uint32_t plane = start_plane + p;
535                uint32_t subres_id =
536                   level + (layer * res->mip_levels) + plane * (res->mip_levels * res->base.b.array_size);
537                assert(subres_id < state_entry->desired.num_subresources);
538                if (is_accumulate)
539                   set_desired_subresource_state(&state_entry->desired, subres_id, state, pending_memory_barrier);
540                else
541                   append_barrier(ctx, res->bo, state_entry, state, subres_id, false, pending_memory_barrier);
542             }
543          }
544       }
545    }
546 
547    if (is_accumulate) {
548       if (ctx->id != D3D12_CONTEXT_NO_ID) {
549          if ((res->bo->local_needs_resolve_state & (1 << ctx->id)) == 0) {
550             util_dynarray_append(&ctx->local_pending_barriers_bos, struct d3d12_bo*, res->bo);
551             res->bo->local_needs_resolve_state |= (1 << ctx->id);
552          }
553       }
554       else
555          _mesa_set_add(ctx->pending_barriers_bos, res->bo);
556    }
557 }
558 
apply_resource_state(struct d3d12_context * ctx,bool is_implicit_dispatch,d3d12_bo * bo)559 static void apply_resource_state(struct d3d12_context *ctx, bool is_implicit_dispatch, d3d12_bo *bo)
560 {
561    d3d12_context_state_table_entry* state_entry = find_or_create_state_entry(ctx, bo);
562    d3d12_desired_resource_state* destination_state = &state_entry->desired;
563    d3d12_resource_state* current_state = &state_entry->batch_end;
564 
565    // Figure out the set of subresources that are transitioning
566    bool all_resources_at_once = current_state->homogenous && destination_state->homogenous;
567 
568    UINT num_subresources = all_resources_at_once ? 1 : current_state->num_subresources;
569    for (UINT i = 0; i < num_subresources; ++i) {
570       D3D12_RESOURCE_STATES after = get_desired_subresource_state(destination_state, i);
571       UINT subresource = num_subresources == 1 ? D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES : i;
572 
573       // Is this subresource currently being used, or is it just being iterated over?
574       if (after == UNKNOWN_RESOURCE_STATE) {
575          // This subresource doesn't have any transition requested - move on to the next.
576          continue;
577       }
578 
579       append_barrier(ctx, bo, state_entry, after, subresource, is_implicit_dispatch, state_entry->desired.pending_memory_barrier);
580    }
581 
582    // Update destination states.
583    reset_desired_resource_state(destination_state);
584 }
585 
586 void
d3d12_apply_resource_states(struct d3d12_context * ctx,bool is_implicit_dispatch)587 d3d12_apply_resource_states(struct d3d12_context *ctx, bool is_implicit_dispatch)
588 {
589    set_foreach_remove(ctx->pending_barriers_bos, entry)
590       apply_resource_state(ctx, is_implicit_dispatch, (d3d12_bo *)entry->key);
591 
592    util_dynarray_foreach(&ctx->local_pending_barriers_bos, struct d3d12_bo*, bo) {
593       apply_resource_state(ctx, is_implicit_dispatch, *bo);
594       (*bo)->local_needs_resolve_state &= ~(1 << ctx->id);
595    }
596    util_dynarray_clear(&ctx->local_pending_barriers_bos);
597 
598    if (ctx->barrier_scratch.size) {
599       ctx->cmdlist->ResourceBarrier(util_dynarray_num_elements(&ctx->barrier_scratch, D3D12_RESOURCE_BARRIER),
600                                     (D3D12_RESOURCE_BARRIER *) ctx->barrier_scratch.data);
601       util_dynarray_clear(&ctx->barrier_scratch);
602    }
603 }
604