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, &current_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