xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/d3d12/d3d12_context_common.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_blit.h"
25 #include "d3d12_cmd_signature.h"
26 #include "d3d12_context.h"
27 #include "d3d12_compiler.h"
28 #include "d3d12_compute_transforms.h"
29 #include "d3d12_debug.h"
30 #include "d3d12_fence.h"
31 #include "d3d12_format.h"
32 #include "d3d12_query.h"
33 #include "d3d12_resource.h"
34 #include "d3d12_root_signature.h"
35 #include "d3d12_screen.h"
36 #include "d3d12_surface.h"
37 #ifdef HAVE_GALLIUM_D3D12_VIDEO
38 #include "d3d12_video_dec.h"
39 #include "d3d12_video_enc.h"
40 #include "d3d12_video_proc.h"
41 #include "d3d12_video_buffer.h"
42 #endif
43 #include "indices/u_primconvert.h"
44 #include "util/u_atomic.h"
45 #include "util/u_blitter.h"
46 #include "util/u_dual_blend.h"
47 #include "util/u_framebuffer.h"
48 #include "util/u_helpers.h"
49 #include "util/u_inlines.h"
50 #include "util/u_memory.h"
51 #include "util/u_upload_mgr.h"
52 #include "util/u_pstipple.h"
53 #include "util/u_sample_positions.h"
54 #include "util/u_dl.h"
55 #include "nir_to_dxil.h"
56 
57 #include <dxguids/dxguids.h>
58 
59 #include <string.h>
60 
61 #ifdef _WIN32
62 #include "dxil_validator.h"
63 #endif
64 
65 static void
d3d12_context_destroy(struct pipe_context * pctx)66 d3d12_context_destroy(struct pipe_context *pctx)
67 {
68    struct d3d12_context *ctx = d3d12_context(pctx);
69 
70    struct d3d12_screen *screen = d3d12_screen(pctx->screen);
71    mtx_lock(&screen->submit_mutex);
72    list_del(&ctx->context_list_entry);
73    if (ctx->id != D3D12_CONTEXT_NO_ID)
74       screen->context_id_list[screen->context_id_count++] = ctx->id;
75    mtx_unlock(&screen->submit_mutex);
76 
77 
78 #ifdef HAVE_GALLIUM_D3D12_GRAPHICS
79    if ((screen->max_feature_level >= D3D_FEATURE_LEVEL_11_0) && !(ctx->flags & PIPE_CONTEXT_MEDIA_ONLY)) {
80       util_blitter_destroy(ctx->blitter); // Must be called before d3d12_destroy_batch
81    }
82 #endif // HAVE_GALLIUM_D3D12_GRAPHICS
83 
84    // Batch must be destroyed before the rest of the state objects below
85    d3d12_end_batch(ctx, d3d12_current_batch(ctx));
86    for (unsigned i = 0; i < ARRAY_SIZE(ctx->batches); ++i)
87       d3d12_destroy_batch(ctx, &ctx->batches[i]);
88    ctx->cmdlist->Release();
89    if (ctx->cmdlist2)
90       ctx->cmdlist2->Release();
91    if (ctx->cmdlist8)
92       ctx->cmdlist8->Release();
93 
94 #ifdef HAVE_GALLIUM_D3D12_GRAPHICS
95    if ((screen->max_feature_level >= D3D_FEATURE_LEVEL_11_0) && !(ctx->flags & PIPE_CONTEXT_MEDIA_ONLY)) {
96 #ifdef _WIN32
97       dxil_destroy_validator(ctx->dxil_validator);
98 #endif // _WIN32
99 
100 #ifndef _GAMING_XBOX
101       if (ctx->dev_config)
102          ctx->dev_config->Release();
103 #endif // _GAMING_XBOX
104 
105       if (ctx->timestamp_query)
106          pctx->destroy_query(pctx, ctx->timestamp_query);
107 
108       util_unreference_framebuffer_state(&ctx->fb);
109       d3d12_compute_pipeline_state_cache_destroy(ctx);
110       d3d12_root_signature_cache_destroy(ctx);
111       d3d12_cmd_signature_cache_destroy(ctx);
112       d3d12_compute_transform_cache_destroy(ctx);
113       d3d12_descriptor_pool_free(ctx->sampler_pool);
114       d3d12_gs_variant_cache_destroy(ctx);
115       d3d12_tcs_variant_cache_destroy(ctx);
116       d3d12_gfx_pipeline_state_cache_destroy(ctx);
117       util_primconvert_destroy(ctx->primconvert);
118       pipe_resource_reference(&ctx->pstipple.texture, nullptr);
119       pipe_sampler_view_reference(&ctx->pstipple.sampler_view, nullptr);
120       util_dynarray_fini(&ctx->recently_destroyed_bos);
121       FREE(ctx->pstipple.sampler_cso);
122       if (pctx->stream_uploader)
123          u_upload_destroy(pctx->stream_uploader);
124       if (pctx->const_uploader)
125          u_upload_destroy(pctx->const_uploader);
126       if (!ctx->queries_disabled) {
127          u_suballocator_destroy(&ctx->query_allocator);
128       }
129    }
130 #endif // HAVE_GALLIUM_D3D12_GRAPHICS
131 
132    slab_destroy_child(&ctx->transfer_pool);
133    slab_destroy_child(&ctx->transfer_pool_unsync);
134    d3d12_context_state_table_destroy(ctx);
135 
136    FREE(ctx);
137 }
138 
139 void
d3d12_flush_cmdlist(struct d3d12_context * ctx)140 d3d12_flush_cmdlist(struct d3d12_context *ctx)
141 {
142    d3d12_end_batch(ctx, d3d12_current_batch(ctx));
143 
144    ctx->current_batch_idx++;
145    if (ctx->current_batch_idx == ARRAY_SIZE(ctx->batches))
146       ctx->current_batch_idx = 0;
147 
148    d3d12_start_batch(ctx, d3d12_current_batch(ctx));
149 }
150 
151 void
d3d12_flush_cmdlist_and_wait(struct d3d12_context * ctx)152 d3d12_flush_cmdlist_and_wait(struct d3d12_context *ctx)
153 {
154    struct d3d12_batch *batch = d3d12_current_batch(ctx);
155 
156    d3d12_foreach_submitted_batch(ctx, old_batch)
157       d3d12_reset_batch(ctx, old_batch, OS_TIMEOUT_INFINITE);
158    d3d12_flush_cmdlist(ctx);
159    d3d12_reset_batch(ctx, batch, OS_TIMEOUT_INFINITE);
160 }
161 
162 static void
d3d12_flush(struct pipe_context * pipe,struct pipe_fence_handle ** fence,unsigned flags)163 d3d12_flush(struct pipe_context *pipe,
164             struct pipe_fence_handle **fence,
165             unsigned flags)
166 {
167    struct d3d12_context *ctx = d3d12_context(pipe);
168    struct d3d12_batch *batch = d3d12_current_batch(ctx);
169 
170    d3d12_flush_cmdlist(ctx);
171 
172    if (fence)
173       d3d12_fence_reference((struct d3d12_fence **)fence, batch->fence);
174 }
175 
176 static void
d3d12_flush_resource(struct pipe_context * pctx,struct pipe_resource * pres)177 d3d12_flush_resource(struct pipe_context *pctx,
178                      struct pipe_resource *pres)
179 {
180    struct d3d12_context *ctx = d3d12_context(pctx);
181    struct d3d12_resource *res = d3d12_resource(pres);
182 
183    d3d12_transition_resource_state(ctx, res,
184                                    D3D12_RESOURCE_STATE_COMMON,
185                                    D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
186    d3d12_apply_resource_states(ctx, false);
187 }
188 
189 static void
d3d12_signal(struct pipe_context * pipe,struct pipe_fence_handle * pfence)190 d3d12_signal(struct pipe_context *pipe,
191              struct pipe_fence_handle *pfence)
192 {
193    struct d3d12_screen *screen = d3d12_screen(pipe->screen);
194    struct d3d12_fence *fence = d3d12_fence(pfence);
195    d3d12_flush_cmdlist(d3d12_context(pipe));
196    screen->cmdqueue->Signal(fence->cmdqueue_fence, fence->value);
197 }
198 
199 static void
d3d12_wait(struct pipe_context * pipe,struct pipe_fence_handle * pfence)200 d3d12_wait(struct pipe_context *pipe, struct pipe_fence_handle *pfence)
201 {
202    struct d3d12_screen *screen = d3d12_screen(pipe->screen);
203    struct d3d12_fence *fence = d3d12_fence(pfence);
204    d3d12_flush_cmdlist(d3d12_context(pipe));
205    screen->cmdqueue->Wait(fence->cmdqueue_fence, fence->value);
206 }
207 
208 static void
d3d12_replace_buffer_storage(struct pipe_context * pctx,struct pipe_resource * pdst,struct pipe_resource * psrc,unsigned minimum_num_rebinds,uint32_t rebind_mask,uint32_t delete_buffer_id)209 d3d12_replace_buffer_storage(struct pipe_context *pctx,
210    struct pipe_resource *pdst,
211    struct pipe_resource *psrc,
212    unsigned minimum_num_rebinds,
213    uint32_t rebind_mask,
214    uint32_t delete_buffer_id)
215 {
216    struct d3d12_resource *dst = d3d12_resource(pdst);
217    struct d3d12_resource *src = d3d12_resource(psrc);
218 
219    struct d3d12_bo *old_bo = dst->bo;
220    d3d12_bo_reference(src->bo);
221    dst->bo = src->bo;
222    p_atomic_inc(&dst->generation_id);
223 #ifdef HAVE_GALLIUM_D3D12_GRAPHICS
224    struct d3d12_context *ctx = d3d12_context(pctx);
225    if ((d3d12_screen(pctx->screen)->max_feature_level >= D3D_FEATURE_LEVEL_11_0)
226       && !(ctx->flags & PIPE_CONTEXT_MEDIA_ONLY))
227       d3d12_rebind_buffer(ctx, dst);
228 #endif // HAVE_GALLIUM_D3D12_GRAPHICS
229    d3d12_bo_unreference(old_bo);
230 }
231 
232 static void
d3d12_memory_barrier(struct pipe_context * pctx,unsigned flags)233 d3d12_memory_barrier(struct pipe_context *pctx, unsigned flags)
234 {
235 #ifdef HAVE_GALLIUM_D3D12_GRAPHICS
236    struct d3d12_context *ctx = d3d12_context(pctx);
237    if (flags & PIPE_BARRIER_VERTEX_BUFFER)
238       ctx->state_dirty |= D3D12_DIRTY_VERTEX_BUFFERS;
239    if (flags & PIPE_BARRIER_INDEX_BUFFER)
240       ctx->state_dirty |= D3D12_DIRTY_INDEX_BUFFER;
241    if (flags & PIPE_BARRIER_FRAMEBUFFER)
242       ctx->state_dirty |= D3D12_DIRTY_FRAMEBUFFER;
243    if (flags & PIPE_BARRIER_STREAMOUT_BUFFER)
244       ctx->state_dirty |= D3D12_DIRTY_STREAM_OUTPUT;
245 
246    /* TODO:
247     * PIPE_BARRIER_INDIRECT_BUFFER
248     */
249 
250    for (unsigned i = 0; i < D3D12_GFX_SHADER_STAGES; ++i) {
251       if (flags & PIPE_BARRIER_CONSTANT_BUFFER)
252          ctx->shader_dirty[i] |= D3D12_SHADER_DIRTY_CONSTBUF;
253       if (flags & PIPE_BARRIER_TEXTURE)
254          ctx->shader_dirty[i] |= D3D12_SHADER_DIRTY_SAMPLER_VIEWS;
255       if (flags & PIPE_BARRIER_SHADER_BUFFER)
256          ctx->shader_dirty[i] |= D3D12_SHADER_DIRTY_SSBO;
257       if (flags & PIPE_BARRIER_IMAGE)
258          ctx->shader_dirty[i] |= D3D12_SHADER_DIRTY_IMAGE;
259    }
260 
261    /* Indicate that UAVs shouldn't override transitions. Ignore barriers that are only
262     * for UAVs or other fixed-function state that doesn't need a draw to resolve.
263     */
264    const unsigned ignored_barrier_flags =
265       PIPE_BARRIER_IMAGE |
266       PIPE_BARRIER_SHADER_BUFFER |
267       PIPE_BARRIER_UPDATE |
268       PIPE_BARRIER_MAPPED_BUFFER |
269       PIPE_BARRIER_QUERY_BUFFER;
270    d3d12_current_batch(ctx)->pending_memory_barrier = (flags & ~ignored_barrier_flags) != 0;
271 
272    if (flags & (PIPE_BARRIER_IMAGE | PIPE_BARRIER_SHADER_BUFFER)) {
273       D3D12_RESOURCE_BARRIER uavBarrier;
274       uavBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV;
275       uavBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
276       uavBarrier.UAV.pResource = nullptr;
277       ctx->cmdlist->ResourceBarrier(1, &uavBarrier);
278    }
279 #endif // HAVE_GALLIUM_D3D12_GRAPHICS
280 }
281 
282 static void
d3d12_texture_barrier(struct pipe_context * pctx,unsigned flags)283 d3d12_texture_barrier(struct pipe_context *pctx, unsigned flags)
284 {
285    struct d3d12_context *ctx = d3d12_context(pctx);
286 
287    /* D3D doesn't really have an equivalent in the legacy barrier model. When using enhanced barriers,
288     * this could be a more specific global barrier. But for now, just flush the world with an aliasing barrier. */
289    D3D12_RESOURCE_BARRIER aliasingBarrier;
290    aliasingBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_ALIASING;
291    aliasingBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
292    aliasingBarrier.Aliasing.pResourceBefore = nullptr;
293    aliasingBarrier.Aliasing.pResourceAfter = nullptr;
294    ctx->cmdlist->ResourceBarrier(1, &aliasingBarrier);
295 }
296 
297 static enum pipe_reset_status
d3d12_get_reset_status(struct pipe_context * pctx)298 d3d12_get_reset_status(struct pipe_context *pctx)
299 {
300    struct d3d12_screen *screen = d3d12_screen(pctx->screen);
301    HRESULT hr = screen->dev->GetDeviceRemovedReason();
302    switch (hr) {
303    case DXGI_ERROR_DEVICE_HUNG:
304    case DXGI_ERROR_INVALID_CALL:
305       return PIPE_GUILTY_CONTEXT_RESET;
306    case DXGI_ERROR_DEVICE_RESET:
307       return PIPE_INNOCENT_CONTEXT_RESET;
308    default:
309       return SUCCEEDED(hr) ? PIPE_NO_RESET : PIPE_UNKNOWN_CONTEXT_RESET;
310    }
311 }
312 
313 #ifdef HAVE_GALLIUM_D3D12_VIDEO
314 struct pipe_video_codec*
d3d12_video_create_codec(struct pipe_context * context,const struct pipe_video_codec * templat)315 d3d12_video_create_codec(struct pipe_context *context,
316                          const struct pipe_video_codec *templat)
317 {
318     if (templat->entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE) {
319         return d3d12_video_encoder_create_encoder(context, templat);
320     } else if (templat->entrypoint == PIPE_VIDEO_ENTRYPOINT_BITSTREAM) {
321         return d3d12_video_create_decoder(context, templat);
322     } else if (templat->entrypoint == PIPE_VIDEO_ENTRYPOINT_PROCESSING) {
323         return d3d12_video_processor_create(context, templat);
324     } else {
325         debug_printf("D3D12: Unsupported video codec entrypoint %d\n", templat->entrypoint);
326         return nullptr;
327     }
328 }
329 #endif
330 
331 struct pipe_context *
d3d12_context_create(struct pipe_screen * pscreen,void * priv,unsigned flags)332 d3d12_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags)
333 {
334    struct d3d12_screen *screen = d3d12_screen(pscreen);
335    if (FAILED(screen->dev->GetDeviceRemovedReason())) {
336       /* Attempt recovery, but this may fail */
337       screen->deinit(screen);
338       if (!screen->init(screen)) {
339          debug_printf("D3D12: failed to reset screen\n");
340          return nullptr;
341       }
342    }
343 
344    if ((screen->max_feature_level < D3D_FEATURE_LEVEL_11_0) &&
345       !(flags & PIPE_CONTEXT_MEDIA_ONLY))
346    {
347       debug_printf("D3D12: Underlying screen maximum supported feature level is lower than D3D_FEATURE_LEVEL_11_0. The caller to context_create must pass PIPE_CONTEXT_MEDIA_ONLY in flags.\n");
348       return NULL;
349    }
350 
351 #ifndef HAVE_GALLIUM_D3D12_VIDEO
352    if (flags & PIPE_CONTEXT_MEDIA_ONLY)
353    {
354       debug_printf("D3D12: context_create passed PIPE_CONTEXT_MEDIA_ONLY in flags but no media support found.\n");
355       return NULL;
356    }
357 #endif // ifndef HAVE_GALLIUM_D3D12_VIDEO
358 
359    struct d3d12_context *ctx = CALLOC_STRUCT(d3d12_context);
360    if (!ctx)
361       return NULL;
362 
363    ctx->base.screen = pscreen;
364    ctx->base.priv = priv;
365 
366    ctx->base.destroy = d3d12_context_destroy;
367    ctx->base.flush = d3d12_flush;
368    ctx->base.flush_resource = d3d12_flush_resource;
369    ctx->base.fence_server_signal = d3d12_signal;
370    ctx->base.fence_server_sync = d3d12_wait;
371    ctx->base.memory_barrier = d3d12_memory_barrier;
372    ctx->base.texture_barrier = d3d12_texture_barrier;
373 
374    ctx->base.get_device_reset_status = d3d12_get_reset_status;
375    ctx->flags = flags;
376    d3d12_context_resource_init(&ctx->base);
377    d3d12_context_copy_init(&ctx->base);
378 
379 #ifdef HAVE_GALLIUM_D3D12_VIDEO
380    ctx->base.create_video_codec = d3d12_video_create_codec;
381    ctx->base.create_video_buffer = d3d12_video_buffer_create;
382    ctx->base.video_buffer_from_handle = d3d12_video_buffer_from_handle;
383 #endif
384 
385    slab_create_child(&ctx->transfer_pool, &d3d12_screen(pscreen)->transfer_pool);
386    slab_create_child(&ctx->transfer_pool_unsync, &d3d12_screen(pscreen)->transfer_pool);
387 
388    d3d12_context_state_table_init(ctx);
389 
390    ctx->queries_disabled = true; // Disabled by default, re-enable if supported FL below
391 
392 #ifdef HAVE_GALLIUM_D3D12_GRAPHICS
393    if ((screen->max_feature_level >= D3D_FEATURE_LEVEL_11_0) && !(flags & PIPE_CONTEXT_MEDIA_ONLY)) {
394 #ifndef _GAMING_XBOX
395       (void)screen->dev->QueryInterface(&ctx->dev_config);
396 #endif
397 
398       d3d12_context_blit_init(&ctx->base);
399 
400       u_suballocator_init(&ctx->so_allocator, &ctx->base, 4096, 0,
401                      PIPE_USAGE_DEFAULT,
402                      0, false);
403 
404       ctx->has_flat_varyings = false;
405       ctx->missing_dual_src_outputs = false;
406       ctx->manual_depth_range = false;
407 
408       d3d12_compute_pipeline_state_cache_init(ctx);
409       d3d12_root_signature_cache_init(ctx);
410       d3d12_cmd_signature_cache_init(ctx);
411       d3d12_compute_transform_cache_init(ctx);
412 
413       ctx->D3D12SerializeVersionedRootSignature =
414          (PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE)util_dl_get_proc_address(screen->d3d12_mod, "D3D12SerializeVersionedRootSignature");
415 
416       ctx->base.stream_uploader = u_upload_create_default(&ctx->base);
417       ctx->base.const_uploader = u_upload_create_default(&ctx->base);
418 
419       ctx->base.get_sample_position = u_default_get_sample_position;
420       ctx->base.get_sample_position = u_default_get_sample_position;
421 
422      d3d12_init_graphics_context_functions(ctx);
423 
424       ctx->gfx_pipeline_state.sample_mask = ~0;
425 
426       d3d12_context_surface_init(&ctx->base);
427       d3d12_context_query_init(&ctx->base);
428       ctx->queries_disabled = false;
429 
430       struct primconvert_config cfg = {};
431       cfg.primtypes_mask = 1 << MESA_PRIM_POINTS |
432                            1 << MESA_PRIM_LINES |
433                            1 << MESA_PRIM_LINE_STRIP |
434                            1 << MESA_PRIM_TRIANGLES |
435                            1 << MESA_PRIM_TRIANGLE_STRIP;
436       cfg.restart_primtypes_mask = cfg.primtypes_mask;
437       cfg.fixed_prim_restart = true;
438       ctx->primconvert = util_primconvert_create_config(&ctx->base, &cfg);
439       if (!ctx->primconvert) {
440          debug_printf("D3D12: failed to create primconvert\n");
441          return NULL;
442       }
443 
444       d3d12_gfx_pipeline_state_cache_init(ctx);
445       d3d12_gs_variant_cache_init(ctx);
446       d3d12_tcs_variant_cache_init(ctx);
447 
448       ctx->sampler_pool = d3d12_descriptor_pool_new(screen,
449                                                    D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
450                                                    64);
451       if (!ctx->sampler_pool) {
452          FREE(ctx);
453          return NULL;
454       }
455       d3d12_init_null_sampler(ctx);
456 
457       ctx->blitter = util_blitter_create(&ctx->base);
458       if (!ctx->blitter)
459          return NULL;
460 
461       if (!d3d12_init_polygon_stipple(&ctx->base)) {
462          debug_printf("D3D12: failed to initialize polygon stipple resources\n");
463          FREE(ctx);
464          return NULL;
465       }
466 #ifdef _WIN32
467          if (!(d3d12_debug & D3D12_DEBUG_EXPERIMENTAL) ||
468             (d3d12_debug & D3D12_DEBUG_DISASS))
469             ctx->dxil_validator = dxil_create_validator(NULL);
470 #endif
471    }
472 #endif // HAVE_GALLIUM_D3D12_GRAPHICS
473 
474    ctx->submit_id = (uint64_t)p_atomic_add_return(&screen->ctx_count, 1) << 32ull;
475 
476    for (unsigned i = 0; i < ARRAY_SIZE(ctx->batches); ++i) {
477       if (!d3d12_init_batch(ctx, &ctx->batches[i])) {
478          FREE(ctx);
479          return NULL;
480       }
481    }
482    d3d12_start_batch(ctx, &ctx->batches[0]);
483 
484    mtx_lock(&screen->submit_mutex);
485    list_addtail(&ctx->context_list_entry, &screen->context_list);
486    if (screen->context_id_count > 0)
487       ctx->id = screen->context_id_list[--screen->context_id_count];
488    else
489       ctx->id = D3D12_CONTEXT_NO_ID;
490    mtx_unlock(&screen->submit_mutex);
491 
492    for (unsigned i = 0; i < ARRAY_SIZE(ctx->batches); ++i) {
493       ctx->batches[i].ctx_id = ctx->id;
494       ctx->batches[i].ctx_index = i;
495    }
496 
497    if (flags & PIPE_CONTEXT_PREFER_THREADED)
498       return threaded_context_create(&ctx->base,
499          &screen->transfer_pool,
500          d3d12_replace_buffer_storage,
501          NULL,
502          &ctx->threaded_context);
503 
504    return &ctx->base;
505 }
506