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 /* Stores the current desired state of either an entire resource, or each subresource. */
38 struct desired_resource_state
39 {
40 bool homogenous;
41 uint32_t num_subresources;
42 D3D12_RESOURCE_STATES *subresource_states;
43 };
44
45 static bool
desired_resource_state_init(desired_resource_state * state,uint32_t subresource_count)46 desired_resource_state_init(desired_resource_state *state, uint32_t subresource_count)
47 {
48 state->homogenous = true;
49 state->num_subresources = subresource_count;
50 state->subresource_states = (D3D12_RESOURCE_STATES *)calloc(subresource_count, sizeof(D3D12_RESOURCE_STATES));
51 return state->subresource_states != nullptr;
52 }
53
54 static void
desired_resource_state_cleanup(desired_resource_state * state)55 desired_resource_state_cleanup(desired_resource_state *state)
56 {
57 free(state->subresource_states);
58 }
59
60 static D3D12_RESOURCE_STATES
get_desired_subresource_state(const desired_resource_state * state,uint32_t subresource_index)61 get_desired_subresource_state(const desired_resource_state *state, uint32_t subresource_index)
62 {
63 if (state->homogenous)
64 subresource_index = 0;
65 return state->subresource_states[subresource_index];
66 }
67
68 static void
update_subresource_state(D3D12_RESOURCE_STATES * existing_state,D3D12_RESOURCE_STATES new_state)69 update_subresource_state(D3D12_RESOURCE_STATES *existing_state, D3D12_RESOURCE_STATES new_state)
70 {
71 if (*existing_state == UNKNOWN_RESOURCE_STATE || new_state == UNKNOWN_RESOURCE_STATE ||
72 d3d12_is_write_state(new_state)) {
73 *existing_state = new_state;
74 } else {
75 /* Accumulate read state state bits */
76 *existing_state |= new_state;
77 }
78 }
79
80 static void
set_desired_resource_state(desired_resource_state * state_obj,D3D12_RESOURCE_STATES state)81 set_desired_resource_state(desired_resource_state *state_obj, D3D12_RESOURCE_STATES state)
82 {
83 state_obj->homogenous = true;
84 update_subresource_state(&state_obj->subresource_states[0], state);
85 }
86
87 static void
set_desired_subresource_state(desired_resource_state * state_obj,uint32_t subresource,D3D12_RESOURCE_STATES state)88 set_desired_subresource_state(desired_resource_state *state_obj,
89 uint32_t subresource,
90 D3D12_RESOURCE_STATES state)
91 {
92 if (state_obj->homogenous && state_obj->num_subresources > 1) {
93 for (unsigned i = 1; i < state_obj->num_subresources; ++i) {
94 state_obj->subresource_states[i] = state_obj->subresource_states[0];
95 }
96 state_obj->homogenous = false;
97 }
98
99 update_subresource_state(&state_obj->subresource_states[subresource], state);
100 }
101
102 static void
reset_desired_resource_state(desired_resource_state * state_obj)103 reset_desired_resource_state(desired_resource_state *state_obj)
104 {
105 set_desired_resource_state(state_obj, UNKNOWN_RESOURCE_STATE);
106 }
107
108 bool
d3d12_resource_state_init(d3d12_resource_state * state,uint32_t subresource_count,bool simultaneous_access)109 d3d12_resource_state_init(d3d12_resource_state *state, uint32_t subresource_count, bool simultaneous_access)
110 {
111 state->homogenous = true;
112 state->supports_simultaneous_access = simultaneous_access;
113 state->num_subresources = subresource_count;
114 state->subresource_states = (d3d12_subresource_state *)calloc(subresource_count, sizeof(d3d12_subresource_state));
115 return state->subresource_states != nullptr;
116 }
117
118 void
d3d12_resource_state_cleanup(d3d12_resource_state * state)119 d3d12_resource_state_cleanup(d3d12_resource_state *state)
120 {
121 free(state->subresource_states);
122 }
123
124 static const d3d12_subresource_state *
get_subresource_state(const d3d12_resource_state * state,uint32_t subresource)125 get_subresource_state(const d3d12_resource_state *state, uint32_t subresource)
126 {
127 if (state->homogenous)
128 subresource = 0;
129 return &state->subresource_states[subresource];
130 }
131
132 static void
set_resource_state(d3d12_resource_state * state_obj,const d3d12_subresource_state * state)133 set_resource_state(d3d12_resource_state *state_obj, const d3d12_subresource_state *state)
134 {
135 state_obj->homogenous = true;
136 state_obj->subresource_states[0] = *state;
137 }
138
139 static void
set_subresource_state(d3d12_resource_state * state_obj,uint32_t subresource,const d3d12_subresource_state * state)140 set_subresource_state(d3d12_resource_state *state_obj, uint32_t subresource, const d3d12_subresource_state *state)
141 {
142 if (state_obj->homogenous && state_obj->num_subresources > 1) {
143 for (unsigned i = 1; i < state_obj->num_subresources; ++i) {
144 state_obj->subresource_states[i] = state_obj->subresource_states[0];
145 }
146 state_obj->homogenous = false;
147 }
148
149 state_obj->subresource_states[subresource] = *state;
150 }
151
152 static void
reset_resource_state(d3d12_resource_state * state)153 reset_resource_state(d3d12_resource_state *state)
154 {
155 d3d12_subresource_state subres_state = {};
156 set_resource_state(state, &subres_state);
157 }
158
159 static D3D12_RESOURCE_STATES
resource_state_if_promoted(D3D12_RESOURCE_STATES desired_state,bool simultaneous_access,const d3d12_subresource_state * current_state)160 resource_state_if_promoted(D3D12_RESOURCE_STATES desired_state,
161 bool simultaneous_access,
162 const d3d12_subresource_state *current_state)
163 {
164 const D3D12_RESOURCE_STATES promotable_states = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE |
165 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE |
166 D3D12_RESOURCE_STATE_COPY_SOURCE | D3D12_RESOURCE_STATE_COPY_DEST;
167
168 if (simultaneous_access ||
169 (desired_state & promotable_states) != D3D12_RESOURCE_STATE_COMMON) {
170 // If the current state is COMMON...
171 if (current_state->state == D3D12_RESOURCE_STATE_COMMON)
172 // ...then promotion is allowed
173 return desired_state;
174
175 // If the current state is a read state resulting from previous promotion...
176 if (current_state->is_promoted &&
177 (current_state->state & D3D12_RESOURCE_STATE_GENERIC_READ) != D3D12_RESOURCE_STATE_COMMON)
178 // ...then (accumulated) promotion is allowed
179 return desired_state | current_state->state;
180 }
181
182 return D3D12_RESOURCE_STATE_COMMON;
183 }
184
185 static void
copy_resource_state(d3d12_resource_state * dest,d3d12_resource_state * src)186 copy_resource_state(d3d12_resource_state *dest, d3d12_resource_state *src)
187 {
188 assert(dest->num_subresources == src->num_subresources);
189 if (src->homogenous)
190 set_resource_state(dest, &src->subresource_states[0]);
191 else {
192 dest->homogenous = false;
193 for (unsigned i = 0; i < src->num_subresources; ++i)
194 dest->subresource_states[i] = src->subresource_states[i];
195 }
196 }
197
198 struct d3d12_context_state_table_entry
199 {
200 struct desired_resource_state desired;
201 struct d3d12_resource_state batch_begin, batch_end;
202 };
203
204 static void
destroy_context_state_table_entry(d3d12_context_state_table_entry * entry)205 destroy_context_state_table_entry(d3d12_context_state_table_entry *entry)
206 {
207 desired_resource_state_cleanup(&entry->desired);
208 d3d12_resource_state_cleanup(&entry->batch_begin);
209 d3d12_resource_state_cleanup(&entry->batch_end);
210 free(entry);
211 }
212
213 void
d3d12_context_state_table_init(struct d3d12_context * ctx)214 d3d12_context_state_table_init(struct d3d12_context *ctx)
215 {
216 ctx->bo_state_table = _mesa_hash_table_u64_create(nullptr);
217 ctx->pending_barriers_bos = _mesa_pointer_set_create(nullptr);
218 }
219
220 void
d3d12_context_state_table_destroy(struct d3d12_context * ctx)221 d3d12_context_state_table_destroy(struct d3d12_context *ctx)
222 {
223 hash_table_foreach(ctx->bo_state_table->table, entry)
224 destroy_context_state_table_entry((d3d12_context_state_table_entry *)entry->data);
225 _mesa_hash_table_u64_destroy(ctx->bo_state_table);
226 util_dynarray_fini(&ctx->barrier_scratch);
227 if (ctx->state_fixup_cmdlist)
228 ctx->state_fixup_cmdlist->Release();
229 _mesa_set_destroy(ctx->pending_barriers_bos, nullptr);
230 }
231
232 static unsigned
get_subresource_count(const D3D12_RESOURCE_DESC * desc)233 get_subresource_count(const D3D12_RESOURCE_DESC *desc)
234 {
235 unsigned array_size = desc->Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D ? 1 : desc->DepthOrArraySize;
236 return desc->MipLevels * array_size * d3d12_non_opaque_plane_count(desc->Format);
237 }
238
239 static void
init_state_table_entry(d3d12_context_state_table_entry * bo_state,d3d12_bo * bo)240 init_state_table_entry(d3d12_context_state_table_entry *bo_state, d3d12_bo *bo)
241 {
242 /* Default parameters for bos for suballocated buffers */
243 unsigned subresource_count = 1;
244 bool supports_simultaneous_access = true;
245 if (bo->res) {
246 D3D12_RESOURCE_DESC desc = GetDesc(bo->res);
247 subresource_count = get_subresource_count(&desc);
248 supports_simultaneous_access = d3d12_resource_supports_simultaneous_access(&desc);
249 }
250
251 desired_resource_state_init(&bo_state->desired, subresource_count);
252 d3d12_resource_state_init(&bo_state->batch_end, subresource_count, supports_simultaneous_access);
253
254 /* We'll never need state fixups for simultaneous access resources, so don't bother initializing this second state */
255 if (!supports_simultaneous_access)
256 d3d12_resource_state_init(&bo_state->batch_begin, subresource_count, supports_simultaneous_access);
257 }
258
259 static d3d12_context_state_table_entry *
find_or_create_state_entry(struct hash_table_u64 * table,d3d12_bo * bo)260 find_or_create_state_entry(struct hash_table_u64 *table, d3d12_bo *bo)
261 {
262 d3d12_context_state_table_entry *bo_state =
263 (d3d12_context_state_table_entry *) _mesa_hash_table_u64_search(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(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 D3D12_COMMAND_LIST_TYPE_DIRECT,
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 bool
d3d12_context_state_resolve_submission(struct d3d12_context * ctx,struct d3d12_batch * batch)342 d3d12_context_state_resolve_submission(struct d3d12_context *ctx, struct d3d12_batch *batch)
343 {
344 util_dynarray_foreach(&ctx->recently_destroyed_bos, uint64_t, id) {
345 void *data = _mesa_hash_table_u64_search(ctx->bo_state_table, *id);
346 if (data)
347 destroy_context_state_table_entry((d3d12_context_state_table_entry *)data);
348 _mesa_hash_table_u64_remove(ctx->bo_state_table, *id);
349 }
350
351 util_dynarray_clear(&ctx->recently_destroyed_bos);
352
353 hash_table_foreach(batch->bos, bo_entry) {
354 d3d12_bo *bo = (d3d12_bo *)bo_entry->key;
355 d3d12_context_state_table_entry *bo_state = find_or_create_state_entry(ctx->bo_state_table, bo);
356 if (!bo_state->batch_end.supports_simultaneous_access) {
357 assert(bo->res && bo->global_state.subresource_states);
358
359 resolve_global_state(ctx, bo->res, &bo_state->batch_begin, &bo->global_state);
360
361 copy_resource_state(&bo_state->batch_begin, &bo_state->batch_end);
362 copy_resource_state(&bo->global_state, &bo_state->batch_end);
363 } else {
364 reset_resource_state(&bo_state->batch_end);
365 }
366 }
367
368 bool needs_execute_fixup = false;
369 if (ctx->barrier_scratch.size) {
370 ID3D12GraphicsCommandList *cmdlist = ensure_state_fixup_cmdlist(ctx, batch->cmdalloc);
371 if (cmdlist) {
372 cmdlist->ResourceBarrier(util_dynarray_num_elements(&ctx->barrier_scratch, D3D12_RESOURCE_BARRIER),
373 (D3D12_RESOURCE_BARRIER *)ctx->barrier_scratch.data);
374 needs_execute_fixup = SUCCEEDED(cmdlist->Close());
375 }
376
377 util_dynarray_clear(&ctx->barrier_scratch);
378 }
379 return needs_execute_fixup;
380 }
381
382 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)383 append_barrier(struct d3d12_context *ctx,
384 d3d12_bo *bo,
385 d3d12_context_state_table_entry *state_entry,
386 D3D12_RESOURCE_STATES after,
387 UINT subresource,
388 bool is_implicit_dispatch)
389 {
390 uint64_t offset;
391 ID3D12Resource *res = d3d12_bo_get_base(bo, &offset)->res;
392 d3d12_resource_state *current_state = &state_entry->batch_end;
393
394 D3D12_RESOURCE_BARRIER transition_desc = { D3D12_RESOURCE_BARRIER_TYPE_TRANSITION };
395 transition_desc.Transition.pResource = res;
396 transition_desc.Transition.Subresource = subresource;
397
398 // This is a transition into a state that is both write and non-write.
399 // This is invalid according to D3D12. We're venturing into undefined behavior
400 // land, but let's just pick the write state.
401 if (d3d12_is_write_state(after) && (after & ~RESOURCE_STATE_ALL_WRITE_BITS) != 0) {
402 after &= RESOURCE_STATE_ALL_WRITE_BITS;
403
404 // For now, this is the only way I've seen where this can happen.
405 assert(after == D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
406 }
407
408 assert((subresource == D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES && current_state->homogenous) ||
409 subresource < current_state->num_subresources);
410 d3d12_subresource_state current_subresource_state = *get_subresource_state(current_state, subresource);
411
412 // If the last time this state was set was in a different execution
413 // period and is decayable then decay the current state to COMMON
414 if (ctx->submit_id != current_subresource_state.execution_id && current_subresource_state.may_decay) {
415 current_subresource_state.state = D3D12_RESOURCE_STATE_COMMON;
416 current_subresource_state.is_promoted = false;
417 }
418 bool may_decay = false;
419 bool is_promotion = false;
420
421 D3D12_RESOURCE_STATES state_if_promoted =
422 resource_state_if_promoted(after, current_state->supports_simultaneous_access, ¤t_subresource_state);
423
424 if (D3D12_RESOURCE_STATE_COMMON == state_if_promoted) {
425 // No promotion
426 if (current_subresource_state.state == D3D12_RESOURCE_STATE_UNORDERED_ACCESS &&
427 after == D3D12_RESOURCE_STATE_UNORDERED_ACCESS &&
428 is_implicit_dispatch) {
429 D3D12_RESOURCE_BARRIER uav_barrier = { D3D12_RESOURCE_BARRIER_TYPE_UAV };
430 uav_barrier.UAV.pResource = res;
431 util_dynarray_append(&ctx->barrier_scratch, D3D12_RESOURCE_BARRIER, uav_barrier);
432 } else if (transition_required(current_subresource_state.state, /*inout*/ &after)) {
433 // Insert a single concrete barrier (for non-simultaneous access resources).
434 transition_desc.Transition.StateBefore = current_subresource_state.state;
435 transition_desc.Transition.StateAfter = after;
436 assert(transition_desc.Transition.StateBefore != transition_desc.Transition.StateAfter);
437 util_dynarray_append(&ctx->barrier_scratch, D3D12_RESOURCE_BARRIER, transition_desc);
438
439 may_decay = current_state->supports_simultaneous_access && !d3d12_is_write_state(after);
440 is_promotion = false;
441 }
442 } else if (after != state_if_promoted) {
443 after = state_if_promoted;
444 may_decay = !d3d12_is_write_state(after);
445 is_promotion = true;
446 }
447
448 d3d12_subresource_state new_subresource_state { after, ctx->submit_id, is_promotion, may_decay };
449 if (subresource == D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES)
450 set_resource_state(current_state, &new_subresource_state);
451 else
452 set_subresource_state(current_state, subresource, &new_subresource_state);
453 }
454
455 void
d3d12_transition_resource_state(struct d3d12_context * ctx,struct d3d12_resource * res,D3D12_RESOURCE_STATES state,d3d12_transition_flags flags)456 d3d12_transition_resource_state(struct d3d12_context *ctx,
457 struct d3d12_resource *res,
458 D3D12_RESOURCE_STATES state,
459 d3d12_transition_flags flags)
460 {
461 if (flags & D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS)
462 d3d12_invalidate_context_bindings(ctx, res);
463
464 d3d12_context_state_table_entry *state_entry = find_or_create_state_entry(ctx->bo_state_table, res->bo);
465 if (flags & D3D12_TRANSITION_FLAG_ACCUMULATE_STATE) {
466 set_desired_resource_state(&state_entry->desired, state);
467 _mesa_set_add(ctx->pending_barriers_bos, res->bo);
468 } else if (state_entry->batch_end.homogenous) {
469 append_barrier(ctx, res->bo, state_entry, state, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, false);
470 } else {
471 for (unsigned i = 0; i < state_entry->batch_end.num_subresources; ++i) {
472 append_barrier(ctx, res->bo, state_entry, state, i, false);
473 }
474 }
475 }
476
477 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)478 d3d12_transition_subresources_state(struct d3d12_context *ctx,
479 struct d3d12_resource *res,
480 uint32_t start_level, uint32_t num_levels,
481 uint32_t start_layer, uint32_t num_layers,
482 uint32_t start_plane, uint32_t num_planes,
483 D3D12_RESOURCE_STATES state,
484 d3d12_transition_flags flags)
485 {
486 if(flags & D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS)
487 d3d12_invalidate_context_bindings(ctx, res);
488
489 d3d12_context_state_table_entry *state_entry = find_or_create_state_entry(ctx->bo_state_table, res->bo);
490 bool is_whole_resource = num_levels * num_layers * num_planes == state_entry->batch_end.num_subresources;
491 bool is_accumulate = (flags & D3D12_TRANSITION_FLAG_ACCUMULATE_STATE) != 0;
492
493 if (is_whole_resource && is_accumulate) {
494 set_desired_resource_state(&state_entry->desired, state);
495 } else if (is_whole_resource && state_entry->batch_end.homogenous) {
496 append_barrier(ctx, res->bo, state_entry, state, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, false);
497 } else {
498 for (uint32_t l = 0; l < num_levels; l++) {
499 const uint32_t level = start_level + l;
500 for (uint32_t a = 0; a < num_layers; a++) {
501 const uint32_t layer = start_layer + a;
502 for (uint32_t p = 0; p < num_planes; p++) {
503 const uint32_t plane = start_plane + p;
504 uint32_t subres_id =
505 level + (layer * res->mip_levels) + plane * (res->mip_levels * res->base.b.array_size);
506 assert(subres_id < state_entry->desired.num_subresources);
507 if (is_accumulate)
508 set_desired_subresource_state(&state_entry->desired, subres_id, state);
509 else
510 append_barrier(ctx, res->bo, state_entry, state, subres_id, false);
511 }
512 }
513 }
514 }
515
516 if (is_accumulate)
517 _mesa_set_add(ctx->pending_barriers_bos, res->bo);
518 }
519
520 void
d3d12_apply_resource_states(struct d3d12_context * ctx,bool is_implicit_dispatch)521 d3d12_apply_resource_states(struct d3d12_context *ctx, bool is_implicit_dispatch)
522 {
523 set_foreach_remove(ctx->pending_barriers_bos, entry) {
524 d3d12_bo *bo = (d3d12_bo *)entry->key;
525
526 d3d12_context_state_table_entry *state_entry = find_or_create_state_entry(ctx->bo_state_table, bo);
527 desired_resource_state *destination_state = &state_entry->desired;
528 d3d12_resource_state *current_state = &state_entry->batch_end;
529
530 // Figure out the set of subresources that are transitioning
531 bool all_resources_at_once = current_state->homogenous && destination_state->homogenous;
532
533 UINT num_subresources = all_resources_at_once ? 1 : current_state->num_subresources;
534 for (UINT i = 0; i < num_subresources; ++i) {
535 D3D12_RESOURCE_STATES after = get_desired_subresource_state(destination_state, i);
536 UINT subresource = num_subresources == 1 ? D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES : i;
537
538 // Is this subresource currently being used, or is it just being iterated over?
539 if (after == UNKNOWN_RESOURCE_STATE) {
540 // This subresource doesn't have any transition requested - move on to the next.
541 continue;
542 }
543
544 append_barrier(ctx, bo, state_entry, after, subresource, is_implicit_dispatch);
545 }
546
547 // Update destination states.
548 reset_desired_resource_state(destination_state);
549 }
550
551 if (ctx->barrier_scratch.size) {
552 ctx->cmdlist->ResourceBarrier(util_dynarray_num_elements(&ctx->barrier_scratch, D3D12_RESOURCE_BARRIER),
553 (D3D12_RESOURCE_BARRIER *) ctx->barrier_scratch.data);
554 util_dynarray_clear(&ctx->barrier_scratch);
555 }
556 }
557