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, ¤t_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