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