xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/zink/zink_batch.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 #include "zink_batch.h"
2 #include "zink_context.h"
3 #include "zink_descriptors.h"
4 #include "zink_framebuffer.h"
5 #include "zink_kopper.h"
6 #include "zink_program.h"
7 #include "zink_query.h"
8 #include "zink_resource.h"
9 #include "zink_screen.h"
10 #include "zink_surface.h"
11 
12 #ifdef VK_USE_PLATFORM_METAL_EXT
13 #include "QuartzCore/CAMetalLayer.h"
14 #endif
15 
16 #define MAX_VIEW_COUNT 500
17 
18 void
debug_describe_zink_batch_state(char * buf,const struct zink_batch_state * ptr)19 debug_describe_zink_batch_state(char *buf, const struct zink_batch_state *ptr)
20 {
21    sprintf(buf, "zink_batch_state");
22 }
23 
24 /* this resets the batch usage and tracking for a resource object */
25 static void
reset_obj(struct zink_screen * screen,struct zink_batch_state * bs,struct zink_resource_object * obj)26 reset_obj(struct zink_screen *screen, struct zink_batch_state *bs, struct zink_resource_object *obj)
27 {
28    /* if no batch usage exists after removing the usage from 'bs', this resource is considered fully idle */
29    if (!zink_resource_object_usage_unset(obj, bs)) {
30       /* the resource is idle, so reset all access/reordering info */
31       obj->unordered_read = true;
32       obj->unordered_write = true;
33       obj->access = 0;
34       obj->unordered_access = 0;
35       obj->last_write = 0;
36       obj->access_stage = 0;
37       obj->unordered_access_stage = 0;
38       obj->copies_need_reset = true;
39       obj->unsync_access = true;
40       /* also prune dead view objects */
41       simple_mtx_lock(&obj->view_lock);
42       if (obj->is_buffer) {
43          while (util_dynarray_contains(&obj->views, VkBufferView))
44             VKSCR(DestroyBufferView)(screen->dev, util_dynarray_pop(&obj->views, VkBufferView), NULL);
45       } else {
46          while (util_dynarray_contains(&obj->views, VkImageView))
47             VKSCR(DestroyImageView)(screen->dev, util_dynarray_pop(&obj->views, VkImageView), NULL);
48       }
49       obj->view_prune_count = 0;
50       obj->view_prune_timeline = 0;
51       simple_mtx_unlock(&obj->view_lock);
52       if (obj->dt)
53          zink_kopper_prune_batch_usage(obj->dt, &bs->usage);
54    } else if (util_dynarray_num_elements(&obj->views, VkBufferView) > MAX_VIEW_COUNT && !zink_bo_has_unflushed_usage(obj->bo)) {
55       /* avoid ballooning from too many views on always-used resources: */
56       simple_mtx_lock(&obj->view_lock);
57       /* ensure no existing view pruning is queued, double check elements in case pruning just finished */
58       if (!obj->view_prune_timeline && util_dynarray_num_elements(&obj->views, VkBufferView) > MAX_VIEW_COUNT) {
59          /* prune all existing views */
60          obj->view_prune_count = util_dynarray_num_elements(&obj->views, VkBufferView);
61          /* prune them when the views will definitely not be in use */
62          obj->view_prune_timeline = MAX2(obj->bo->reads.u ? obj->bo->reads.u->usage : 0,
63                                          obj->bo->writes.u ? obj->bo->writes.u->usage : 0);
64       }
65       simple_mtx_unlock(&obj->view_lock);
66    }
67    /* resource objects are not unrefed here;
68     * this is typically the last ref on a resource object, and destruction will
69     * usually trigger an ioctl, so defer deletion to the submit thread to avoid blocking
70     */
71    util_dynarray_append(&bs->unref_resources, struct zink_resource_object*, obj);
72 }
73 
74 /* reset all the resource objects in a given batch object list */
75 static void
reset_obj_list(struct zink_screen * screen,struct zink_batch_state * bs,struct zink_batch_obj_list * list)76 reset_obj_list(struct zink_screen *screen, struct zink_batch_state *bs, struct zink_batch_obj_list *list)
77 {
78    for (unsigned i = 0; i < list->num_buffers; i++)
79       reset_obj(screen, bs, list->objs[i]);
80    list->num_buffers = 0;
81 }
82 
83 /* reset a given batch state */
84 void
zink_reset_batch_state(struct zink_context * ctx,struct zink_batch_state * bs)85 zink_reset_batch_state(struct zink_context *ctx, struct zink_batch_state *bs)
86 {
87    struct zink_screen *screen = zink_screen(ctx->base.screen);
88 
89    VkResult result = VKSCR(ResetCommandPool)(screen->dev, bs->cmdpool, 0);
90    if (result != VK_SUCCESS)
91       mesa_loge("ZINK: vkResetCommandPool failed (%s)", vk_Result_to_str(result));
92    result = VKSCR(ResetCommandPool)(screen->dev, bs->unsynchronized_cmdpool, 0);
93    if (result != VK_SUCCESS)
94       mesa_loge("ZINK: vkResetCommandPool failed (%s)", vk_Result_to_str(result));
95 
96    /* unref/reset all used resources */
97    reset_obj_list(screen, bs, &bs->real_objs);
98    reset_obj_list(screen, bs, &bs->slab_objs);
99    reset_obj_list(screen, bs, &bs->sparse_objs);
100    while (util_dynarray_contains(&bs->swapchain_obj, struct zink_resource_object*)) {
101       struct zink_resource_object *obj = util_dynarray_pop(&bs->swapchain_obj, struct zink_resource_object*);
102       reset_obj(screen, bs, obj);
103    }
104 
105    /* this is where bindless texture/buffer ids get recycled */
106    for (unsigned i = 0; i < 2; i++) {
107       while (util_dynarray_contains(&bs->bindless_releases[i], uint32_t)) {
108          uint32_t handle = util_dynarray_pop(&bs->bindless_releases[i], uint32_t);
109          bool is_buffer = ZINK_BINDLESS_IS_BUFFER(handle);
110          struct util_idalloc *ids = i ? &ctx->di.bindless[is_buffer].img_slots : &ctx->di.bindless[is_buffer].tex_slots;
111          util_idalloc_free(ids, is_buffer ? handle - ZINK_MAX_BINDLESS_HANDLES : handle);
112       }
113    }
114 
115    /* queries must only be destroyed once they are inactive */
116    set_foreach_remove(&bs->active_queries, entry) {
117       struct zink_query *query = (void*)entry->key;
118       zink_prune_query(bs, query);
119    }
120    util_dynarray_foreach(&bs->dead_querypools, VkQueryPool, pool)
121       VKSCR(DestroyQueryPool)(screen->dev, *pool, NULL);
122    util_dynarray_clear(&bs->dead_querypools);
123 
124    /* samplers are appended to the batch state in which they are destroyed
125     * to ensure deferred deletion without destroying in-use objects
126     */
127    util_dynarray_foreach(&bs->zombie_samplers, VkSampler, samp) {
128       VKSCR(DestroySampler)(screen->dev, *samp, NULL);
129    }
130    util_dynarray_clear(&bs->zombie_samplers);
131 
132    zink_batch_descriptor_reset(screen, bs);
133 
134    while (util_dynarray_contains(&bs->freed_sparse_backing_bos, struct zink_bo*)) {
135       struct zink_bo *bo = util_dynarray_pop(&bs->freed_sparse_backing_bos, struct zink_bo*);
136       zink_bo_unref(screen, bo);
137    }
138 
139    /* programs are refcounted and batch-tracked */
140    set_foreach_remove(&bs->programs, entry) {
141       struct zink_program *pg = (struct zink_program*)entry->key;
142       zink_batch_usage_unset(&pg->batch_uses, bs);
143       zink_program_reference(screen, &pg, NULL);
144    }
145 
146    bs->resource_size = 0;
147    bs->signal_semaphore = VK_NULL_HANDLE;
148    bs->sparse_semaphore = VK_NULL_HANDLE;
149    util_dynarray_clear(&bs->wait_semaphore_stages);
150 
151    bs->present = VK_NULL_HANDLE;
152    /* check the arrays first to avoid locking unnecessarily */
153    if (util_dynarray_contains(&bs->acquires, VkSemaphore) || util_dynarray_contains(&bs->wait_semaphores, VkSemaphore) || util_dynarray_contains(&bs->tracked_semaphores, VkSemaphore)) {
154       simple_mtx_lock(&screen->semaphores_lock);
155       util_dynarray_append_dynarray(&screen->semaphores, &bs->acquires);
156       util_dynarray_clear(&bs->acquires);
157       util_dynarray_append_dynarray(&screen->semaphores, &bs->wait_semaphores);
158       util_dynarray_clear(&bs->wait_semaphores);
159       util_dynarray_append_dynarray(&screen->semaphores, &bs->tracked_semaphores);
160       util_dynarray_clear(&bs->tracked_semaphores);
161       simple_mtx_unlock(&screen->semaphores_lock);
162    }
163    if (util_dynarray_contains(&bs->signal_semaphores, VkSemaphore) || util_dynarray_contains(&bs->fd_wait_semaphores, VkSemaphore)) {
164       simple_mtx_lock(&screen->semaphores_lock);
165       util_dynarray_append_dynarray(&screen->fd_semaphores, &bs->signal_semaphores);
166       util_dynarray_clear(&bs->signal_semaphores);
167       util_dynarray_append_dynarray(&screen->fd_semaphores, &bs->fd_wait_semaphores);
168       util_dynarray_clear(&bs->fd_wait_semaphores);
169       simple_mtx_unlock(&screen->semaphores_lock);
170    }
171    bs->swapchain = NULL;
172 
173    util_dynarray_foreach(&bs->fences, struct zink_tc_fence*, mfence)
174       zink_fence_reference(screen, mfence, NULL);
175    util_dynarray_clear(&bs->fences);
176 
177    bs->unordered_write_access = VK_ACCESS_NONE;
178    bs->unordered_write_stages = VK_PIPELINE_STAGE_NONE;
179 
180    /* only increment batch generation if previously in-use to avoid false detection of batch completion */
181    if (bs->fence.submitted)
182       bs->usage.submit_count++;
183    /* only reset submitted here so that tc fence desync can pick up the 'completed' flag
184     * before the state is reused
185     */
186    bs->fence.submitted = false;
187    if (bs->fence.batch_id)
188       zink_screen_update_last_finished(screen, bs->fence.batch_id);
189    bs->fence.batch_id = 0;
190    bs->usage.usage = 0;
191    bs->next = NULL;
192    bs->last_added_obj = NULL;
193 
194    bs->has_work = false;
195    bs->has_reordered_work = false;
196    bs->has_unsync = false;
197 }
198 
199 /* this is where deferred resource unrefs occur */
200 static void
unref_resources(struct zink_screen * screen,struct zink_batch_state * bs)201 unref_resources(struct zink_screen *screen, struct zink_batch_state *bs)
202 {
203    while (util_dynarray_contains(&bs->unref_resources, struct zink_resource_object*)) {
204       struct zink_resource_object *obj = util_dynarray_pop(&bs->unref_resources, struct zink_resource_object*);
205       /* view pruning may be deferred to avoid ballooning */
206       if (obj->view_prune_timeline && zink_screen_check_last_finished(screen, obj->view_prune_timeline)) {
207          simple_mtx_lock(&obj->view_lock);
208          /* check again under lock in case multi-context use is in the same place */
209          if (obj->view_prune_timeline && zink_screen_check_last_finished(screen, obj->view_prune_timeline)) {
210             /* prune `view_prune_count` views */
211             if (obj->is_buffer) {
212                VkBufferView *views = obj->views.data;
213                for (unsigned i = 0; i < obj->view_prune_count; i++)
214                   VKSCR(DestroyBufferView)(screen->dev, views[i], NULL);
215             } else {
216                VkImageView *views = obj->views.data;
217                for (unsigned i = 0; i < obj->view_prune_count; i++)
218                   VKSCR(DestroyImageView)(screen->dev, views[i], NULL);
219             }
220             size_t offset = obj->view_prune_count * sizeof(VkBufferView);
221             uint8_t *data = obj->views.data;
222             /* shift the view array to the start */
223             memcpy(data, data + offset, obj->views.size - offset);
224             /* adjust the array size */
225             obj->views.size -= offset;
226             obj->view_prune_count = 0;
227             obj->view_prune_timeline = 0;
228          }
229          simple_mtx_unlock(&obj->view_lock);
230       }
231       /* this is typically where resource objects get destroyed */
232       zink_resource_object_reference(screen, &obj, NULL);
233    }
234 }
235 
236 /* utility for resetting a batch state; called on context destruction */
237 void
zink_clear_batch_state(struct zink_context * ctx,struct zink_batch_state * bs)238 zink_clear_batch_state(struct zink_context *ctx, struct zink_batch_state *bs)
239 {
240    bs->fence.completed = true;
241    zink_reset_batch_state(ctx, bs);
242    unref_resources(zink_screen(ctx->base.screen), bs);
243 }
244 
245 /* utility for managing the singly-linked batch state list */
246 static void
pop_batch_state(struct zink_context * ctx)247 pop_batch_state(struct zink_context *ctx)
248 {
249    const struct zink_batch_state *bs = ctx->batch_states;
250    ctx->batch_states = bs->next;
251    ctx->batch_states_count--;
252    if (ctx->last_batch_state == bs)
253       ctx->last_batch_state = NULL;
254 }
255 
256 /* reset all batch states and append to the free state list
257  * only usable after a full stall
258  */
259 void
zink_batch_reset_all(struct zink_context * ctx)260 zink_batch_reset_all(struct zink_context *ctx)
261 {
262    while (ctx->batch_states) {
263       struct zink_batch_state *bs = ctx->batch_states;
264       bs->fence.completed = true;
265       pop_batch_state(ctx);
266       zink_reset_batch_state(ctx, bs);
267       if (ctx->last_free_batch_state)
268          ctx->last_free_batch_state->next = bs;
269       else
270          ctx->free_batch_states = bs;
271       ctx->last_free_batch_state = bs;
272    }
273 }
274 
275 /* called only on context destruction */
276 void
zink_batch_state_destroy(struct zink_screen * screen,struct zink_batch_state * bs)277 zink_batch_state_destroy(struct zink_screen *screen, struct zink_batch_state *bs)
278 {
279    if (!bs)
280       return;
281 
282    util_queue_fence_destroy(&bs->flush_completed);
283 
284    cnd_destroy(&bs->usage.flush);
285    mtx_destroy(&bs->usage.mtx);
286 
287    if (bs->cmdbuf)
288       VKSCR(FreeCommandBuffers)(screen->dev, bs->cmdpool, 1, &bs->cmdbuf);
289    if (bs->reordered_cmdbuf)
290       VKSCR(FreeCommandBuffers)(screen->dev, bs->cmdpool, 1, &bs->reordered_cmdbuf);
291    if (bs->cmdpool)
292       VKSCR(DestroyCommandPool)(screen->dev, bs->cmdpool, NULL);
293    if (bs->unsynchronized_cmdbuf)
294       VKSCR(FreeCommandBuffers)(screen->dev, bs->unsynchronized_cmdpool, 1, &bs->unsynchronized_cmdbuf);
295    if (bs->unsynchronized_cmdpool)
296       VKSCR(DestroyCommandPool)(screen->dev, bs->unsynchronized_cmdpool, NULL);
297    free(bs->real_objs.objs);
298    free(bs->slab_objs.objs);
299    free(bs->sparse_objs.objs);
300    util_dynarray_fini(&bs->freed_sparse_backing_bos);
301    util_dynarray_fini(&bs->dead_querypools);
302    util_dynarray_fini(&bs->swapchain_obj);
303    util_dynarray_fini(&bs->zombie_samplers);
304    util_dynarray_fini(&bs->unref_resources);
305    util_dynarray_fini(&bs->bindless_releases[0]);
306    util_dynarray_fini(&bs->bindless_releases[1]);
307    util_dynarray_fini(&bs->acquires);
308    util_dynarray_fini(&bs->signal_semaphores);
309    util_dynarray_fini(&bs->wait_semaphores);
310    util_dynarray_fini(&bs->wait_semaphore_stages);
311    util_dynarray_fini(&bs->fd_wait_semaphores);
312    util_dynarray_fini(&bs->fd_wait_semaphore_stages);
313    util_dynarray_fini(&bs->tracked_semaphores);
314    util_dynarray_fini(&bs->acquire_flags);
315    unsigned num_mfences = util_dynarray_num_elements(&bs->fence.mfences, void *);
316    struct zink_tc_fence **mfence = bs->fence.mfences.data;
317    for (unsigned i = 0; i < num_mfences; i++) {
318       mfence[i]->fence = NULL;
319    }
320    util_dynarray_fini(&bs->fence.mfences);
321    zink_batch_descriptor_deinit(screen, bs);
322    ralloc_free(bs);
323 }
324 
325 /* batch states are created:
326  * - on context creation
327  * - dynamically up to a threshold if no free ones are available
328  */
329 static struct zink_batch_state *
create_batch_state(struct zink_context * ctx)330 create_batch_state(struct zink_context *ctx)
331 {
332    struct zink_screen *screen = zink_screen(ctx->base.screen);
333    struct zink_batch_state *bs = rzalloc(NULL, struct zink_batch_state);
334    VkCommandPoolCreateInfo cpci = {0};
335    cpci.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
336    cpci.queueFamilyIndex = screen->gfx_queue;
337    VkResult result;
338 
339    VRAM_ALLOC_LOOP(result,
340       VKSCR(CreateCommandPool)(screen->dev, &cpci, NULL, &bs->cmdpool),
341       if (result != VK_SUCCESS) {
342          mesa_loge("ZINK: vkCreateCommandPool failed (%s)", vk_Result_to_str(result));
343          goto fail;
344       }
345    );
346    VRAM_ALLOC_LOOP(result,
347       VKSCR(CreateCommandPool)(screen->dev, &cpci, NULL, &bs->unsynchronized_cmdpool),
348       if (result != VK_SUCCESS) {
349          mesa_loge("ZINK: vkCreateCommandPool failed (%s)", vk_Result_to_str(result));
350          goto fail;
351       }
352    );
353 
354    VkCommandBuffer cmdbufs[2];
355    VkCommandBufferAllocateInfo cbai = {0};
356    cbai.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
357    cbai.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
358    cbai.commandPool = bs->cmdpool;
359    cbai.commandBufferCount = 2;
360 
361    VRAM_ALLOC_LOOP(result,
362       VKSCR(AllocateCommandBuffers)(screen->dev, &cbai, cmdbufs),
363       if (result != VK_SUCCESS) {
364          mesa_loge("ZINK: vkAllocateCommandBuffers failed (%s)", vk_Result_to_str(result));
365          goto fail;
366       }
367    );
368 
369    bs->cmdbuf = cmdbufs[0];
370    bs->reordered_cmdbuf = cmdbufs[1];
371 
372    cbai.commandPool = bs->unsynchronized_cmdpool;
373    cbai.commandBufferCount = 1;
374    VRAM_ALLOC_LOOP(result,
375       VKSCR(AllocateCommandBuffers)(screen->dev, &cbai, &bs->unsynchronized_cmdbuf);,
376       if (result != VK_SUCCESS) {
377          mesa_loge("ZINK: vkAllocateCommandBuffers failed (%s)", vk_Result_to_str(result));
378          goto fail;
379       }
380    );
381 
382 #define SET_CREATE_OR_FAIL(ptr) \
383    if (!_mesa_set_init(ptr, bs, _mesa_hash_pointer, _mesa_key_pointer_equal)) \
384       goto fail
385 
386    bs->ctx = ctx;
387 
388    SET_CREATE_OR_FAIL(&bs->programs);
389    SET_CREATE_OR_FAIL(&bs->active_queries);
390    SET_CREATE_OR_FAIL(&bs->dmabuf_exports);
391    util_dynarray_init(&bs->signal_semaphores, NULL);
392    util_dynarray_init(&bs->wait_semaphores, NULL);
393    util_dynarray_init(&bs->tracked_semaphores, NULL);
394    util_dynarray_init(&bs->fd_wait_semaphores, NULL);
395    util_dynarray_init(&bs->fences, NULL);
396    util_dynarray_init(&bs->dead_querypools, NULL);
397    util_dynarray_init(&bs->wait_semaphore_stages, NULL);
398    util_dynarray_init(&bs->fd_wait_semaphore_stages, NULL);
399    util_dynarray_init(&bs->zombie_samplers, NULL);
400    util_dynarray_init(&bs->freed_sparse_backing_bos, NULL);
401    util_dynarray_init(&bs->unref_resources, NULL);
402    util_dynarray_init(&bs->acquires, NULL);
403    util_dynarray_init(&bs->acquire_flags, NULL);
404    util_dynarray_init(&bs->bindless_releases[0], NULL);
405    util_dynarray_init(&bs->bindless_releases[1], NULL);
406    util_dynarray_init(&bs->swapchain_obj, NULL);
407    util_dynarray_init(&bs->fence.mfences, NULL);
408 
409    cnd_init(&bs->usage.flush);
410    mtx_init(&bs->usage.mtx, mtx_plain);
411    simple_mtx_init(&bs->ref_lock, mtx_plain);
412    simple_mtx_init(&bs->exportable_lock, mtx_plain);
413    memset(&bs->buffer_indices_hashlist, -1, sizeof(bs->buffer_indices_hashlist));
414 
415    if (!zink_batch_descriptor_init(screen, bs))
416       goto fail;
417 
418    util_queue_fence_init(&bs->flush_completed);
419 
420    return bs;
421 fail:
422    zink_batch_state_destroy(screen, bs);
423    return NULL;
424 }
425 
426 /* a batch state is considered "free" if it is both submitted and completed */
427 static inline bool
find_unused_state(struct zink_batch_state * bs)428 find_unused_state(struct zink_batch_state *bs)
429 {
430    struct zink_fence *fence = &bs->fence;
431    /* we can't reset these from fence_finish because threads */
432    bool completed = p_atomic_read(&fence->completed);
433    bool submitted = p_atomic_read(&fence->submitted);
434    return submitted && completed;
435 }
436 
437 /* find a "free" batch state */
438 static struct zink_batch_state *
get_batch_state(struct zink_context * ctx)439 get_batch_state(struct zink_context *ctx)
440 {
441    struct zink_screen *screen = zink_screen(ctx->base.screen);
442    struct zink_batch_state *bs = NULL;
443 
444    /* try from the ones that are known to be free first */
445    if (ctx->free_batch_states) {
446       bs = ctx->free_batch_states;
447       ctx->free_batch_states = bs->next;
448       if (bs == ctx->last_free_batch_state)
449          ctx->last_free_batch_state = NULL;
450    }
451    /* try from the ones that are given back to the screen next */
452    if (!bs) {
453       simple_mtx_lock(&screen->free_batch_states_lock);
454       if (screen->free_batch_states) {
455          bs = screen->free_batch_states;
456          bs->ctx = ctx;
457          screen->free_batch_states = bs->next;
458          if (bs == screen->last_free_batch_state)
459             screen->last_free_batch_state = NULL;
460       }
461       simple_mtx_unlock(&screen->free_batch_states_lock);
462    }
463    /* states are stored sequentially, so if the first one doesn't work, none of them will */
464    if (!bs && ctx->batch_states && ctx->batch_states->next) {
465       /* only a submitted state can be reused */
466       if (p_atomic_read(&ctx->batch_states->fence.submitted) &&
467           /* a submitted state must have completed before it can be reused */
468           (zink_screen_check_last_finished(screen, ctx->batch_states->fence.batch_id) ||
469            p_atomic_read(&ctx->batch_states->fence.completed))) {
470          bs = ctx->batch_states;
471          pop_batch_state(ctx);
472       }
473    }
474    if (bs) {
475       zink_reset_batch_state(ctx, bs);
476    } else {
477       if (!ctx->bs) {
478          /* this is batch init, so create a few more states for later use */
479          for (int i = 0; i < 3; i++) {
480             struct zink_batch_state *state = create_batch_state(ctx);
481             if (ctx->last_free_batch_state)
482                ctx->last_free_batch_state->next = state;
483             else
484                ctx->free_batch_states = state;
485             ctx->last_free_batch_state = state;
486          }
487       }
488       /* no batch states were available: make a new one */
489       bs = create_batch_state(ctx);
490    }
491    return bs;
492 }
493 
494 /* reset the batch object: get a new state and unset 'state->has_work' to disable flushing */
495 void
zink_reset_batch(struct zink_context * ctx)496 zink_reset_batch(struct zink_context *ctx)
497 {
498    ctx->bs = get_batch_state(ctx);
499    assert(ctx->bs);
500 }
501 
502 void
zink_batch_bind_db(struct zink_context * ctx)503 zink_batch_bind_db(struct zink_context *ctx)
504 {
505    struct zink_screen *screen = zink_screen(ctx->base.screen);
506    struct zink_batch_state *bs = ctx->bs;
507    unsigned count = 1;
508    VkDescriptorBufferBindingInfoEXT infos[2] = {0};
509    infos[0].sType = VK_STRUCTURE_TYPE_DESCRIPTOR_BUFFER_BINDING_INFO_EXT;
510    infos[0].address = bs->dd.db->obj->bda;
511    infos[0].usage = bs->dd.db->obj->vkusage;
512    assert(infos[0].usage);
513 
514    if (ctx->dd.bindless_init) {
515       infos[1].sType = VK_STRUCTURE_TYPE_DESCRIPTOR_BUFFER_BINDING_INFO_EXT;
516       infos[1].address = ctx->dd.db.bindless_db->obj->bda;
517       infos[1].usage = ctx->dd.db.bindless_db->obj->vkusage;
518       assert(infos[1].usage);
519       count++;
520    }
521    VKSCR(CmdBindDescriptorBuffersEXT)(bs->cmdbuf, count, infos);
522    VKSCR(CmdBindDescriptorBuffersEXT)(bs->reordered_cmdbuf, count, infos);
523    bs->dd.db_bound = true;
524 }
525 
526 /* called on context creation and after flushing an old batch */
527 void
zink_start_batch(struct zink_context * ctx)528 zink_start_batch(struct zink_context *ctx)
529 {
530    struct zink_screen *screen = zink_screen(ctx->base.screen);
531    zink_reset_batch(ctx);
532    struct zink_batch_state *bs = ctx->bs;
533 
534    bs->usage.unflushed = true;
535 
536    VkCommandBufferBeginInfo cbbi = {0};
537    cbbi.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
538    cbbi.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
539 
540    VkResult result;
541    VRAM_ALLOC_LOOP(result,
542       VKCTX(BeginCommandBuffer)(bs->cmdbuf, &cbbi),
543       if (result != VK_SUCCESS)
544          mesa_loge("ZINK: vkBeginCommandBuffer failed (%s)", vk_Result_to_str(result));
545    );
546    VRAM_ALLOC_LOOP(result,
547       VKCTX(BeginCommandBuffer)(bs->reordered_cmdbuf, &cbbi),
548       if (result != VK_SUCCESS)
549          mesa_loge("ZINK: vkBeginCommandBuffer failed (%s)", vk_Result_to_str(result));
550    );
551    VRAM_ALLOC_LOOP(result,
552       VKCTX(BeginCommandBuffer)(bs->unsynchronized_cmdbuf, &cbbi),
553       if (result != VK_SUCCESS)
554          mesa_loge("ZINK: vkBeginCommandBuffer failed (%s)", vk_Result_to_str(result));
555    );
556 
557    bs->fence.completed = false;
558 
559    if (VKCTX(CmdInsertDebugUtilsLabelEXT) && screen->renderdoc_api) {
560       VkDebugUtilsLabelEXT capture_label;
561       /* Magic fallback which lets us bridge the Wine barrier over to Linux RenderDoc. */
562       capture_label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
563       capture_label.pNext = NULL;
564       capture_label.pLabelName = "vr-marker,frame_end,type,application";
565       memset(capture_label.color, 0, sizeof(capture_label.color));
566       VKCTX(CmdInsertDebugUtilsLabelEXT)(bs->unsynchronized_cmdbuf, &capture_label);
567       VKCTX(CmdInsertDebugUtilsLabelEXT)(bs->reordered_cmdbuf, &capture_label);
568       VKCTX(CmdInsertDebugUtilsLabelEXT)(bs->cmdbuf, &capture_label);
569    }
570 
571    unsigned renderdoc_frame = p_atomic_read(&screen->renderdoc_frame);
572    if (!(ctx->flags & ZINK_CONTEXT_COPY_ONLY) && screen->renderdoc_api && !screen->renderdoc_capturing &&
573         ((screen->renderdoc_capture_all && screen->screen_id == 1) || (renderdoc_frame >= screen->renderdoc_capture_start && renderdoc_frame <= screen->renderdoc_capture_end))) {
574       screen->renderdoc_api->StartFrameCapture(RENDERDOC_DEVICEPOINTER_FROM_VKINSTANCE(screen->instance), NULL);
575       screen->renderdoc_capturing = true;
576    }
577 
578    /* descriptor buffers must always be bound at the start of a batch */
579    if (zink_descriptor_mode == ZINK_DESCRIPTOR_MODE_DB && !(ctx->flags & ZINK_CONTEXT_COPY_ONLY))
580       zink_batch_bind_db(ctx);
581    /* zero init for unordered blits */
582    if (screen->info.have_EXT_attachment_feedback_loop_dynamic_state) {
583       VKCTX(CmdSetAttachmentFeedbackLoopEnableEXT)(ctx->bs->cmdbuf, 0);
584       VKCTX(CmdSetAttachmentFeedbackLoopEnableEXT)(ctx->bs->reordered_cmdbuf, 0);
585       VKCTX(CmdSetAttachmentFeedbackLoopEnableEXT)(ctx->bs->unsynchronized_cmdbuf, 0);
586    }
587 }
588 
589 /* common operations to run post submit; split out for clarity */
590 static void
post_submit(void * data,void * gdata,int thread_index)591 post_submit(void *data, void *gdata, int thread_index)
592 {
593    struct zink_batch_state *bs = data;
594    struct zink_screen *screen = zink_screen(bs->ctx->base.screen);
595 
596    if (bs->is_device_lost) {
597       if (bs->ctx->reset.reset)
598          bs->ctx->reset.reset(bs->ctx->reset.data, PIPE_GUILTY_CONTEXT_RESET);
599       else if (screen->abort_on_hang && !screen->robust_ctx_count)
600          /* if nothing can save us, abort */
601          abort();
602       screen->device_lost = true;
603    } else if (bs->ctx->batch_states_count > 5000) {
604       /* throttle in case something crazy is happening */
605       zink_screen_timeline_wait(screen, bs->fence.batch_id - 2500, OS_TIMEOUT_INFINITE);
606    }
607    /* this resets the buffer hashlist for the state's next use */
608    if (bs->hashlist_min != UINT16_MAX)
609       /* only reset a min/max region */
610       memset(&bs->buffer_indices_hashlist[bs->hashlist_min], -1, (bs->hashlist_max - bs->hashlist_min + 1) * sizeof(int16_t));
611    bs->hashlist_min = bs->hashlist_max = UINT16_MAX;
612 }
613 
614 typedef enum {
615    ZINK_SUBMIT_WAIT_ACQUIRE,
616    ZINK_SUBMIT_WAIT_FD,
617    ZINK_SUBMIT_CMDBUF,
618    ZINK_SUBMIT_SIGNAL,
619    ZINK_SUBMIT_MAX
620 } zink_submit;
621 
622 static void
submit_queue(void * data,void * gdata,int thread_index)623 submit_queue(void *data, void *gdata, int thread_index)
624 {
625    struct zink_batch_state *bs = data;
626    struct zink_context *ctx = bs->ctx;
627    struct zink_screen *screen = zink_screen(ctx->base.screen);
628    VkSubmitInfo si[ZINK_SUBMIT_MAX] = {0};
629    VkSubmitInfo *submit = si;
630    int num_si = ZINK_SUBMIT_MAX;
631    while (!bs->fence.batch_id)
632       bs->fence.batch_id = (uint32_t)p_atomic_inc_return(&screen->curr_batch);
633    bs->usage.usage = bs->fence.batch_id;
634    bs->usage.unflushed = false;
635 
636    uint64_t batch_id = bs->fence.batch_id;
637    /* first submit is just for acquire waits since they have a separate array */
638    for (unsigned i = 0; i < ARRAY_SIZE(si); i++)
639       si[i].sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
640    if (bs->sparse_semaphore)
641       util_dynarray_append(&ctx->bs->acquires, VkSemaphore, bs->sparse_semaphore);
642    si[ZINK_SUBMIT_WAIT_ACQUIRE].waitSemaphoreCount = util_dynarray_num_elements(&bs->acquires, VkSemaphore);
643    si[ZINK_SUBMIT_WAIT_ACQUIRE].pWaitSemaphores = bs->acquires.data;
644    while (util_dynarray_num_elements(&bs->acquire_flags, VkPipelineStageFlags) < si[ZINK_SUBMIT_WAIT_ACQUIRE].waitSemaphoreCount) {
645       VkPipelineStageFlags mask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
646       util_dynarray_append(&bs->acquire_flags, VkPipelineStageFlags, mask);
647    }
648    assert(util_dynarray_num_elements(&bs->acquires, VkSemaphore) <= util_dynarray_num_elements(&bs->acquire_flags, VkPipelineStageFlags));
649    si[ZINK_SUBMIT_WAIT_ACQUIRE].pWaitDstStageMask = bs->acquire_flags.data;
650 
651    si[ZINK_SUBMIT_WAIT_FD].waitSemaphoreCount = util_dynarray_num_elements(&bs->fd_wait_semaphores, VkSemaphore);
652    si[ZINK_SUBMIT_WAIT_FD].pWaitSemaphores = bs->fd_wait_semaphores.data;
653    while (util_dynarray_num_elements(&bs->fd_wait_semaphore_stages, VkPipelineStageFlags) < si[ZINK_SUBMIT_WAIT_FD].waitSemaphoreCount) {
654       VkPipelineStageFlags mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
655       util_dynarray_append(&bs->fd_wait_semaphore_stages, VkPipelineStageFlags, mask);
656    }
657    assert(util_dynarray_num_elements(&bs->fd_wait_semaphores, VkSemaphore) <= util_dynarray_num_elements(&bs->fd_wait_semaphore_stages, VkPipelineStageFlags));
658    si[ZINK_SUBMIT_WAIT_FD].pWaitDstStageMask = bs->fd_wait_semaphore_stages.data;
659 
660    if (si[ZINK_SUBMIT_WAIT_ACQUIRE].waitSemaphoreCount == 0) {
661       num_si--;
662       submit++;
663       if (si[ZINK_SUBMIT_WAIT_FD].waitSemaphoreCount == 0) {
664          num_si--;
665          submit++;
666       }
667    }
668 
669    /* then the real submit */
670    si[ZINK_SUBMIT_CMDBUF].waitSemaphoreCount = util_dynarray_num_elements(&bs->wait_semaphores, VkSemaphore);
671    si[ZINK_SUBMIT_CMDBUF].pWaitSemaphores = bs->wait_semaphores.data;
672    si[ZINK_SUBMIT_CMDBUF].pWaitDstStageMask = bs->wait_semaphore_stages.data;
673    VkCommandBuffer cmdbufs[3];
674    unsigned c = 0;
675    if (bs->has_unsync)
676       cmdbufs[c++] = bs->unsynchronized_cmdbuf;
677    if (bs->has_reordered_work)
678       cmdbufs[c++] = bs->reordered_cmdbuf;
679    if (bs->has_work)
680       cmdbufs[c++] = bs->cmdbuf;
681    si[ZINK_SUBMIT_CMDBUF].pCommandBuffers = cmdbufs;
682    si[ZINK_SUBMIT_CMDBUF].commandBufferCount = c;
683    /* assorted signal submit from wsi/externals */
684    si[ZINK_SUBMIT_CMDBUF].signalSemaphoreCount = util_dynarray_num_elements(&bs->signal_semaphores, VkSemaphore);
685    si[ZINK_SUBMIT_CMDBUF].pSignalSemaphores = bs->signal_semaphores.data;
686 
687    /* then the signal submit with the timeline (fence) semaphore */
688    VkSemaphore signals[3];
689    si[ZINK_SUBMIT_SIGNAL].signalSemaphoreCount = !!bs->signal_semaphore;
690    signals[0] = bs->signal_semaphore;
691    si[ZINK_SUBMIT_SIGNAL].pSignalSemaphores = signals;
692    VkTimelineSemaphoreSubmitInfo tsi = {0};
693    uint64_t signal_values[2] = {0};
694    tsi.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO;
695    si[ZINK_SUBMIT_SIGNAL].pNext = &tsi;
696    tsi.pSignalSemaphoreValues = signal_values;
697    signal_values[si[ZINK_SUBMIT_SIGNAL].signalSemaphoreCount] = batch_id;
698    signals[si[ZINK_SUBMIT_SIGNAL].signalSemaphoreCount++] = screen->sem;
699    tsi.signalSemaphoreValueCount = si[ZINK_SUBMIT_SIGNAL].signalSemaphoreCount;
700 
701    if (bs->present)
702       signals[si[ZINK_SUBMIT_SIGNAL].signalSemaphoreCount++] = bs->present;
703    tsi.signalSemaphoreValueCount = si[ZINK_SUBMIT_SIGNAL].signalSemaphoreCount;
704 
705 
706    VkResult result;
707    if (bs->has_work) {
708       VRAM_ALLOC_LOOP(result,
709          VKSCR(EndCommandBuffer)(bs->cmdbuf),
710          if (result != VK_SUCCESS) {
711             mesa_loge("ZINK: vkEndCommandBuffer failed (%s)", vk_Result_to_str(result));
712             bs->is_device_lost = true;
713             goto end;
714          }
715       );
716    }
717    if (bs->has_reordered_work) {
718       if (bs->unordered_write_access) {
719          VkMemoryBarrier mb;
720          mb.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
721          mb.pNext = NULL;
722          mb.srcAccessMask = bs->unordered_write_access;
723          mb.dstAccessMask = VK_ACCESS_NONE;
724          VKSCR(CmdPipelineBarrier)(bs->reordered_cmdbuf,
725                                    bs->unordered_write_stages,
726                                    screen->info.have_KHR_synchronization2 ? VK_PIPELINE_STAGE_NONE : VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
727                                    0, 1, &mb, 0, NULL, 0, NULL);
728       }
729       VRAM_ALLOC_LOOP(result,
730          VKSCR(EndCommandBuffer)(bs->reordered_cmdbuf),
731          if (result != VK_SUCCESS) {
732             mesa_loge("ZINK: vkEndCommandBuffer failed (%s)", vk_Result_to_str(result));
733             bs->is_device_lost = true;
734             goto end;
735          }
736       );
737    }
738    if (bs->has_unsync) {
739       VRAM_ALLOC_LOOP(result,
740          VKSCR(EndCommandBuffer)(bs->unsynchronized_cmdbuf),
741          if (result != VK_SUCCESS) {
742             mesa_loge("ZINK: vkEndCommandBuffer failed (%s)", vk_Result_to_str(result));
743             bs->is_device_lost = true;
744             goto end;
745          }
746       );
747    }
748 
749    if (!si[ZINK_SUBMIT_SIGNAL].signalSemaphoreCount)
750       num_si--;
751 
752    simple_mtx_lock(&screen->queue_lock);
753    VRAM_ALLOC_LOOP(result,
754       VKSCR(QueueSubmit)(screen->queue, num_si, submit, VK_NULL_HANDLE),
755       if (result != VK_SUCCESS) {
756          mesa_loge("ZINK: vkQueueSubmit failed (%s)", vk_Result_to_str(result));
757          bs->is_device_lost = true;
758       }
759    );
760    simple_mtx_unlock(&screen->queue_lock);
761 
762    unsigned i = 0;
763    VkSemaphore *sem = bs->signal_semaphores.data;
764    set_foreach(&bs->dmabuf_exports, entry) {
765       struct zink_resource *res = (void*)entry->key;
766       for (; res; res = zink_resource(res->base.b.next))
767          zink_screen_import_dmabuf_semaphore(screen, res, sem[i++]);
768 
769       struct pipe_resource *pres = (void*)entry->key;
770       pipe_resource_reference(&pres, NULL);
771    }
772    _mesa_set_clear(&bs->dmabuf_exports, NULL);
773 
774    if (bs->sparse_semaphore)
775       (void)util_dynarray_pop(&ctx->bs->acquires, VkSemaphore);
776 
777    bs->usage.submit_count++;
778 end:
779    cnd_broadcast(&bs->usage.flush);
780 
781    p_atomic_set(&bs->fence.submitted, true);
782    unref_resources(screen, bs);
783 }
784 
785 /* called during flush */
786 void
zink_end_batch(struct zink_context * ctx)787 zink_end_batch(struct zink_context *ctx)
788 {
789    if (!ctx->queries_disabled)
790       zink_suspend_queries(ctx);
791 
792 
793    struct zink_screen *screen = zink_screen(ctx->base.screen);
794    if (ctx->tc && !ctx->track_renderpasses)
795       tc_driver_internal_flush_notify(ctx->tc);
796    struct zink_batch_state *bs;
797 
798    /* oom flushing is triggered to handle stupid piglit tests like streaming-texture-leak */
799    if (ctx->oom_flush || ctx->batch_states_count > 25) {
800       assert(!ctx->batch_states_count || ctx->batch_states);
801       while (ctx->batch_states) {
802          bs = ctx->batch_states;
803          struct zink_fence *fence = &bs->fence;
804          /* once an incomplete state is reached, no more will be complete */
805          if (!zink_check_batch_completion(ctx, fence->batch_id))
806             break;
807 
808          pop_batch_state(ctx);
809          zink_reset_batch_state(ctx, bs);
810          if (ctx->last_free_batch_state)
811             ctx->last_free_batch_state->next = bs;
812          else
813             ctx->free_batch_states = bs;
814          ctx->last_free_batch_state = bs;
815       }
816       if (ctx->batch_states_count > 50)
817          ctx->oom_flush = true;
818    }
819 
820    bs = ctx->bs;
821    if (ctx->last_batch_state)
822       ctx->last_batch_state->next = bs;
823    else {
824       assert(!ctx->batch_states);
825       ctx->batch_states = bs;
826    }
827    ctx->last_batch_state = bs;
828    ctx->batch_states_count++;
829    ctx->work_count = 0;
830 
831    /* this is swapchain presentation semaphore handling */
832    if (ctx->swapchain) {
833       if (zink_kopper_acquired(ctx->swapchain->obj->dt, ctx->swapchain->obj->dt_idx) && !ctx->swapchain->obj->present) {
834          bs->present = zink_kopper_present(screen, ctx->swapchain);
835          bs->swapchain = ctx->swapchain;
836       }
837       ctx->swapchain = NULL;
838    }
839 
840    if (screen->device_lost)
841       return;
842 
843    if (ctx->tc) {
844       set_foreach(&bs->active_queries, entry)
845          zink_query_sync(ctx, (void*)entry->key);
846    }
847 
848    set_foreach(&bs->dmabuf_exports, entry) {
849       struct zink_resource *res = (void*)entry->key;
850       if (screen->info.have_KHR_synchronization2) {
851          VkImageMemoryBarrier2 imb;
852          zink_resource_image_barrier2_init(&imb, res, res->layout, 0, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
853          imb.srcQueueFamilyIndex = screen->gfx_queue;
854          imb.dstQueueFamilyIndex = VK_QUEUE_FAMILY_FOREIGN_EXT;
855          VkDependencyInfo dep = {
856             VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
857             NULL,
858             0,
859             0,
860             NULL,
861             0,
862             NULL,
863             1,
864             &imb
865          };
866          VKCTX(CmdPipelineBarrier2)(bs->cmdbuf, &dep);
867       } else {
868          VkImageMemoryBarrier imb;
869          zink_resource_image_barrier_init(&imb, res, res->layout, 0, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
870          imb.srcQueueFamilyIndex = screen->gfx_queue;
871          imb.dstQueueFamilyIndex = VK_QUEUE_FAMILY_FOREIGN_EXT;
872          VKCTX(CmdPipelineBarrier)(
873             bs->cmdbuf,
874             res->obj->access_stage,
875             VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
876             0,
877             0, NULL,
878             0, NULL,
879             1, &imb
880          );
881       }
882       res->queue = VK_QUEUE_FAMILY_FOREIGN_EXT;
883 
884       for (; res; res = zink_resource(res->base.b.next)) {
885          VkSemaphore sem = zink_create_exportable_semaphore(screen);
886          if (sem)
887             util_dynarray_append(&ctx->bs->signal_semaphores, VkSemaphore, sem);
888       }
889       bs->has_work = true;
890    }
891 
892    if (screen->threaded_submit) {
893       util_queue_add_job(&screen->flush_queue, bs, &bs->flush_completed,
894                          submit_queue, post_submit, 0);
895    } else {
896       submit_queue(bs, NULL, 0);
897       post_submit(bs, NULL, 0);
898    }
899 
900    if (!(ctx->flags & ZINK_CONTEXT_COPY_ONLY) && screen->renderdoc_capturing && p_atomic_read(&screen->renderdoc_frame) > screen->renderdoc_capture_end) {
901       screen->renderdoc_api->EndFrameCapture(RENDERDOC_DEVICEPOINTER_FROM_VKINSTANCE(screen->instance), NULL);
902       screen->renderdoc_capturing = false;
903    }
904 }
905 
906 ALWAYS_INLINE static void
batch_hashlist_update(struct zink_batch_state * bs,unsigned hash)907 batch_hashlist_update(struct zink_batch_state *bs, unsigned hash)
908 {
909    bs->hashlist_min = bs->hashlist_min == UINT16_MAX ? hash : MIN2(hash, bs->hashlist_min);
910    bs->hashlist_max = bs->hashlist_max == UINT16_MAX ? hash : MAX2(hash, bs->hashlist_max);
911 }
912 
913 static int
batch_find_resource(struct zink_batch_state * bs,struct zink_resource_object * obj,struct zink_batch_obj_list * list)914 batch_find_resource(struct zink_batch_state *bs, struct zink_resource_object *obj, struct zink_batch_obj_list *list)
915 {
916    unsigned hash = obj->bo->unique_id & (BUFFER_HASHLIST_SIZE-1);
917    int buffer_index = bs->buffer_indices_hashlist[hash];
918 
919    /* not found or found */
920    if (buffer_index < 0 || (buffer_index < list->num_buffers && list->objs[buffer_index] == obj))
921       return buffer_index;
922 
923    /* Hash collision, look for the BO in the list of list->objs linearly. */
924    for (int i = list->num_buffers - 1; i >= 0; i--) {
925       if (list->objs[i] == obj) {
926          /* Put this buffer in the hash list.
927           * This will prevent additional hash collisions if there are
928           * several consecutive lookup_buffer calls for the same buffer.
929           *
930           * Example: Assuming list->objs A,B,C collide in the hash list,
931           * the following sequence of list->objs:
932           *         AAAAAAAAAAABBBBBBBBBBBBBBCCCCCCCC
933           * will collide here: ^ and here:   ^,
934           * meaning that we should get very few collisions in the end. */
935          bs->buffer_indices_hashlist[hash] = i & (BUFFER_HASHLIST_SIZE-1);
936          batch_hashlist_update(bs, hash);
937          return i;
938       }
939    }
940    return -1;
941 }
942 
943 void
zink_batch_reference_resource_rw(struct zink_context * ctx,struct zink_resource * res,bool write)944 zink_batch_reference_resource_rw(struct zink_context *ctx, struct zink_resource *res, bool write)
945 {
946    /* if the resource already has usage of any sort set for this batch, */
947    if (!zink_resource_usage_matches(res, ctx->bs) ||
948        /* or if it's bound somewhere */
949        !zink_resource_has_binds(res))
950       /* then it already has a batch ref and doesn't need one here */
951       zink_batch_reference_resource(ctx, res);
952    zink_batch_resource_usage_set(ctx->bs, res, write, res->obj->is_buffer);
953 }
954 
955 static bool
batch_ptr_add_usage(struct zink_context * ctx,struct set * s,void * ptr)956 batch_ptr_add_usage(struct zink_context *ctx, struct set *s, void *ptr)
957 {
958    bool found = false;
959    _mesa_set_search_or_add(s, ptr, &found);
960    return !found;
961 }
962 
963 /* this is a vague, handwave-y estimate */
964 ALWAYS_INLINE static void
check_oom_flush(struct zink_context * ctx)965 check_oom_flush(struct zink_context *ctx)
966 {
967    const VkDeviceSize resource_size = ctx->bs->resource_size;
968    if (resource_size >= zink_screen(ctx->base.screen)->clamp_video_mem) {
969        ctx->oom_flush = true;
970        ctx->oom_stall = true;
971     }
972 }
973 
974 /* this adds a ref (batch tracking) */
975 void
zink_batch_reference_resource(struct zink_context * ctx,struct zink_resource * res)976 zink_batch_reference_resource(struct zink_context *ctx, struct zink_resource *res)
977 {
978    if (!zink_batch_reference_resource_move(ctx, res))
979       zink_resource_object_reference(NULL, NULL, res->obj);
980 }
981 
982 /* this adds batch usage */
983 bool
zink_batch_reference_resource_move(struct zink_context * ctx,struct zink_resource * res)984 zink_batch_reference_resource_move(struct zink_context *ctx, struct zink_resource *res)
985 {
986    struct zink_batch_state *bs = ctx->bs;
987 
988    simple_mtx_lock(&bs->ref_lock);
989    /* swapchains are special */
990    if (zink_is_swapchain(res)) {
991       struct zink_resource_object **swapchains = bs->swapchain_obj.data;
992       unsigned count = util_dynarray_num_elements(&bs->swapchain_obj, struct zink_resource_object*);
993       for (unsigned i = 0; i < count; i++) {
994          if (swapchains[i] == res->obj) {
995             simple_mtx_unlock(&bs->ref_lock);
996             return true;
997          }
998       }
999       util_dynarray_append(&bs->swapchain_obj, struct zink_resource_object*, res->obj);
1000       simple_mtx_unlock(&bs->ref_lock);
1001       return false;
1002    }
1003    /* Fast exit for no-op calls.
1004     * This is very effective with suballocators and linear uploaders that
1005     * are outside of the winsys.
1006     */
1007    if (res->obj == bs->last_added_obj) {
1008       simple_mtx_unlock(&bs->ref_lock);
1009       return true;
1010    }
1011 
1012    struct zink_bo *bo = res->obj->bo;
1013    struct zink_batch_obj_list *list;
1014    if (!(res->base.b.flags & PIPE_RESOURCE_FLAG_SPARSE)) {
1015       if (!bo->mem) {
1016          list = &bs->slab_objs;
1017       } else {
1018          list = &bs->real_objs;
1019       }
1020    } else {
1021       list = &bs->sparse_objs;
1022    }
1023    int idx = batch_find_resource(bs, res->obj, list);
1024    if (idx >= 0) {
1025       simple_mtx_unlock(&bs->ref_lock);
1026       return true;
1027    }
1028 
1029    if (list->num_buffers >= list->max_buffers) {
1030       unsigned new_max = MAX2(list->max_buffers + 16, (unsigned)(list->max_buffers * 1.3));
1031       struct zink_resource_object **objs = realloc(list->objs, new_max * sizeof(void*));
1032       if (!objs) {
1033          /* things are about to go dramatically wrong anyway */
1034          mesa_loge("zink: buffer list realloc failed due to oom!\n");
1035          abort();
1036       }
1037       list->objs = objs;
1038       list->max_buffers = new_max;
1039    }
1040    idx = list->num_buffers++;
1041    list->objs[idx] = res->obj;
1042    unsigned hash = bo->unique_id & (BUFFER_HASHLIST_SIZE-1);
1043    bs->buffer_indices_hashlist[hash] = idx & 0x7fff;
1044    batch_hashlist_update(bs, hash);
1045    bs->last_added_obj = res->obj;
1046    if (!(res->base.b.flags & PIPE_RESOURCE_FLAG_SPARSE)) {
1047       bs->resource_size += res->obj->size;
1048    } else {
1049       /* Sparse backing pages are not directly referenced by the batch as
1050        * there can be a lot of them.
1051        * Instead, they are kept referenced in one of two ways:
1052        * - While they are committed, they are directly referenced from the
1053        *   resource's state.
1054        * - Upon de-commit, they are added to the freed_sparse_backing_bos
1055        *   list, which will defer destroying the resource until the batch
1056        *   performing unbind finishes.
1057        */
1058    }
1059    check_oom_flush(bs->ctx);
1060    simple_mtx_unlock(&bs->ref_lock);
1061    return false;
1062 }
1063 
1064 /* this is how programs achieve deferred deletion */
1065 void
zink_batch_reference_program(struct zink_context * ctx,struct zink_program * pg)1066 zink_batch_reference_program(struct zink_context *ctx,
1067                              struct zink_program *pg)
1068 {
1069    struct zink_batch_state *bs = ctx->bs;
1070    if (zink_batch_usage_matches(pg->batch_uses, bs) ||
1071        !batch_ptr_add_usage(ctx, &bs->programs, pg))
1072       return;
1073    pipe_reference(NULL, &pg->reference);
1074    zink_batch_usage_set(&pg->batch_uses, bs);
1075    bs->has_work = true;
1076 }
1077 
1078 /* a fast (hopefully) way to check whether a given batch has completed */
1079 bool
zink_screen_usage_check_completion(struct zink_screen * screen,const struct zink_batch_usage * u)1080 zink_screen_usage_check_completion(struct zink_screen *screen, const struct zink_batch_usage *u)
1081 {
1082    if (!zink_batch_usage_exists(u))
1083       return true;
1084    if (zink_batch_usage_is_unflushed(u))
1085       return false;
1086 
1087    return zink_screen_timeline_wait(screen, u->usage, 0);
1088 }
1089 
1090 /* an even faster check that doesn't ioctl */
1091 bool
zink_screen_usage_check_completion_fast(struct zink_screen * screen,const struct zink_batch_usage * u)1092 zink_screen_usage_check_completion_fast(struct zink_screen *screen, const struct zink_batch_usage *u)
1093 {
1094    if (!zink_batch_usage_exists(u))
1095       return true;
1096    if (zink_batch_usage_is_unflushed(u))
1097       return false;
1098 
1099    return zink_screen_check_last_finished(screen, u->usage);
1100 }
1101 
1102 bool
zink_batch_usage_check_completion(struct zink_context * ctx,const struct zink_batch_usage * u)1103 zink_batch_usage_check_completion(struct zink_context *ctx, const struct zink_batch_usage *u)
1104 {
1105    if (!zink_batch_usage_exists(u))
1106       return true;
1107    if (zink_batch_usage_is_unflushed(u))
1108       return false;
1109    return zink_check_batch_completion(ctx, u->usage);
1110 }
1111 
1112 static void
batch_usage_wait(struct zink_context * ctx,struct zink_batch_usage * u,bool trywait)1113 batch_usage_wait(struct zink_context *ctx, struct zink_batch_usage *u, bool trywait)
1114 {
1115    if (!zink_batch_usage_exists(u))
1116       return;
1117    if (zink_batch_usage_is_unflushed(u)) {
1118       if (likely(u == &ctx->bs->usage))
1119          ctx->base.flush(&ctx->base, NULL, PIPE_FLUSH_HINT_FINISH);
1120       else { //multi-context
1121          mtx_lock(&u->mtx);
1122          if (trywait) {
1123             struct timespec ts = {0, 10000};
1124             cnd_timedwait(&u->flush, &u->mtx, &ts);
1125          } else
1126             cnd_wait(&u->flush, &u->mtx);
1127          mtx_unlock(&u->mtx);
1128       }
1129    }
1130    zink_wait_on_batch(ctx, u->usage);
1131 }
1132 
1133 void
zink_batch_usage_wait(struct zink_context * ctx,struct zink_batch_usage * u)1134 zink_batch_usage_wait(struct zink_context *ctx, struct zink_batch_usage *u)
1135 {
1136    batch_usage_wait(ctx, u, false);
1137 }
1138 
1139 void
zink_batch_usage_try_wait(struct zink_context * ctx,struct zink_batch_usage * u)1140 zink_batch_usage_try_wait(struct zink_context *ctx, struct zink_batch_usage *u)
1141 {
1142    batch_usage_wait(ctx, u, true);
1143 }
1144