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