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