Path: blob/21.2-virgl/src/gallium/drivers/zink/zink_batch.c
4570 views
#include "zink_batch.h"12#include "zink_context.h"3#include "zink_fence.h"4#include "zink_framebuffer.h"5#include "zink_query.h"6#include "zink_program.h"7#include "zink_render_pass.h"8#include "zink_resource.h"9#include "zink_screen.h"10#include "zink_surface.h"1112#include "util/hash_table.h"13#include "util/u_debug.h"14#include "util/set.h"1516#ifdef VK_USE_PLATFORM_METAL_EXT17#include "QuartzCore/CAMetalLayer.h"18#endif19#include "wsi_common.h"2021void22debug_describe_zink_batch_state(char *buf, const struct zink_batch_state *ptr)23{24sprintf(buf, "zink_batch_state");25}2627void28zink_reset_batch_state(struct zink_context *ctx, struct zink_batch_state *bs)29{30struct zink_screen *screen = zink_screen(ctx->base.screen);3132if (vkResetCommandPool(screen->dev, bs->cmdpool, 0) != VK_SUCCESS)33debug_printf("vkResetCommandPool failed\n");3435/* unref all used resources */36set_foreach_remove(bs->resources, entry) {37struct zink_resource_object *obj = (struct zink_resource_object *)entry->key;38zink_batch_usage_unset(&obj->reads, bs);39zink_batch_usage_unset(&obj->writes, bs);40zink_resource_object_reference(screen, &obj, NULL);41}4243set_foreach_remove(bs->active_queries, entry) {44struct zink_query *query = (void*)entry->key;45zink_prune_query(screen, query);46}4748set_foreach_remove(bs->surfaces, entry) {49struct zink_surface *surf = (struct zink_surface *)entry->key;50zink_batch_usage_unset(&surf->batch_uses, bs);51zink_surface_reference(screen, &surf, NULL);52}53set_foreach_remove(bs->bufferviews, entry) {54struct zink_buffer_view *buffer_view = (struct zink_buffer_view *)entry->key;55zink_batch_usage_unset(&buffer_view->batch_uses, bs);56zink_buffer_view_reference(screen, &buffer_view, NULL);57}5859util_dynarray_foreach(&bs->zombie_samplers, VkSampler, samp) {60vkDestroySampler(screen->dev, *samp, NULL);61}62util_dynarray_clear(&bs->zombie_samplers);63util_dynarray_clear(&bs->persistent_resources);6465screen->batch_descriptor_reset(screen, bs);6667set_foreach_remove(bs->programs, entry) {68struct zink_program *pg = (struct zink_program*)entry->key;69zink_batch_usage_unset(&pg->batch_uses, bs);70if (pg->is_compute) {71struct zink_compute_program *comp = (struct zink_compute_program*)pg;72bool in_use = comp == ctx->curr_compute;73if (zink_compute_program_reference(screen, &comp, NULL) && in_use)74ctx->curr_compute = NULL;75} else {76struct zink_gfx_program *prog = (struct zink_gfx_program*)pg;77bool in_use = prog == ctx->curr_program;78if (zink_gfx_program_reference(screen, &prog, NULL) && in_use)79ctx->curr_program = NULL;80}81}8283set_foreach(bs->fbs, entry) {84struct zink_framebuffer *fb = (void*)entry->key;85zink_framebuffer_reference(screen, &fb, NULL);86_mesa_set_remove(bs->fbs, entry);87}8889pipe_resource_reference(&bs->flush_res, NULL);9091ctx->resource_size -= bs->resource_size;92bs->resource_size = 0;9394/* only reset submitted here so that tc fence desync can pick up the 'completed' flag95* before the state is reused96*/97bs->fence.submitted = false;98bs->has_barriers = false;99bs->scanout_flush = false;100if (bs->fence.batch_id)101zink_screen_update_last_finished(screen, bs->fence.batch_id);102bs->submit_count++;103bs->fence.batch_id = 0;104bs->usage.usage = 0;105bs->draw_count = bs->compute_count = 0;106}107108void109zink_clear_batch_state(struct zink_context *ctx, struct zink_batch_state *bs)110{111bs->fence.completed = true;112zink_reset_batch_state(ctx, bs);113}114115void116zink_batch_reset_all(struct zink_context *ctx)117{118simple_mtx_lock(&ctx->batch_mtx);119hash_table_foreach(&ctx->batch_states, entry) {120struct zink_batch_state *bs = entry->data;121bs->fence.completed = true;122zink_reset_batch_state(ctx, bs);123_mesa_hash_table_remove(&ctx->batch_states, entry);124util_dynarray_append(&ctx->free_batch_states, struct zink_batch_state *, bs);125}126simple_mtx_unlock(&ctx->batch_mtx);127}128129void130zink_batch_state_destroy(struct zink_screen *screen, struct zink_batch_state *bs)131{132if (!bs)133return;134135util_queue_fence_destroy(&bs->flush_completed);136137cnd_destroy(&bs->usage.flush);138mtx_destroy(&bs->usage.mtx);139140if (bs->fence.fence)141vkDestroyFence(screen->dev, bs->fence.fence, NULL);142143if (bs->cmdbuf)144vkFreeCommandBuffers(screen->dev, bs->cmdpool, 1, &bs->cmdbuf);145if (bs->barrier_cmdbuf)146vkFreeCommandBuffers(screen->dev, bs->cmdpool, 1, &bs->barrier_cmdbuf);147if (bs->cmdpool)148vkDestroyCommandPool(screen->dev, bs->cmdpool, NULL);149150_mesa_set_destroy(bs->fbs, NULL);151util_dynarray_fini(&bs->zombie_samplers);152_mesa_set_destroy(bs->surfaces, NULL);153_mesa_set_destroy(bs->bufferviews, NULL);154_mesa_set_destroy(bs->programs, NULL);155_mesa_set_destroy(bs->active_queries, NULL);156screen->batch_descriptor_deinit(screen, bs);157ralloc_free(bs);158}159160static struct zink_batch_state *161create_batch_state(struct zink_context *ctx)162{163struct zink_screen *screen = zink_screen(ctx->base.screen);164struct zink_batch_state *bs = rzalloc(NULL, struct zink_batch_state);165bs->have_timelines = ctx->have_timelines;166VkCommandPoolCreateInfo cpci = {0};167cpci.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;168cpci.queueFamilyIndex = screen->gfx_queue;169cpci.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;170if (vkCreateCommandPool(screen->dev, &cpci, NULL, &bs->cmdpool) != VK_SUCCESS)171goto fail;172173VkCommandBufferAllocateInfo cbai = {0};174cbai.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;175cbai.commandPool = bs->cmdpool;176cbai.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;177cbai.commandBufferCount = 1;178179if (vkAllocateCommandBuffers(screen->dev, &cbai, &bs->cmdbuf) != VK_SUCCESS)180goto fail;181182if (vkAllocateCommandBuffers(screen->dev, &cbai, &bs->barrier_cmdbuf) != VK_SUCCESS)183goto fail;184185#define SET_CREATE_OR_FAIL(ptr) \186ptr = _mesa_pointer_set_create(bs); \187if (!ptr) \188goto fail189190bs->ctx = ctx;191pipe_reference_init(&bs->reference, 1);192193SET_CREATE_OR_FAIL(bs->fbs);194SET_CREATE_OR_FAIL(bs->resources);195SET_CREATE_OR_FAIL(bs->surfaces);196SET_CREATE_OR_FAIL(bs->bufferviews);197SET_CREATE_OR_FAIL(bs->programs);198SET_CREATE_OR_FAIL(bs->active_queries);199util_dynarray_init(&bs->zombie_samplers, NULL);200util_dynarray_init(&bs->persistent_resources, NULL);201202cnd_init(&bs->usage.flush);203mtx_init(&bs->usage.mtx, mtx_plain);204205if (!screen->batch_descriptor_init(screen, bs))206goto fail;207208VkFenceCreateInfo fci = {0};209fci.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;210211if (vkCreateFence(screen->dev, &fci, NULL, &bs->fence.fence) != VK_SUCCESS)212goto fail;213214util_queue_fence_init(&bs->flush_completed);215216return bs;217fail:218zink_batch_state_destroy(screen, bs);219return NULL;220}221222static inline bool223find_unused_state(struct hash_entry *entry)224{225struct zink_fence *fence = entry->data;226/* we can't reset these from fence_finish because threads */227bool completed = p_atomic_read(&fence->completed);228bool submitted = p_atomic_read(&fence->submitted);229return submitted && completed;230}231232static struct zink_batch_state *233get_batch_state(struct zink_context *ctx, struct zink_batch *batch)234{235struct zink_batch_state *bs = NULL;236237simple_mtx_lock(&ctx->batch_mtx);238if (util_dynarray_num_elements(&ctx->free_batch_states, struct zink_batch_state*))239bs = util_dynarray_pop(&ctx->free_batch_states, struct zink_batch_state*);240if (!bs) {241hash_table_foreach(&ctx->batch_states, he) {242struct zink_fence *fence = he->data;243if (zink_screen_check_last_finished(zink_screen(ctx->base.screen), fence->batch_id) || find_unused_state(he)) {244bs = he->data;245_mesa_hash_table_remove(&ctx->batch_states, he);246break;247}248}249}250simple_mtx_unlock(&ctx->batch_mtx);251if (bs) {252if (bs->fence.submitted && !bs->fence.completed)253/* this fence is already done, so we need vulkan to release the cmdbuf */254zink_vkfence_wait(zink_screen(ctx->base.screen), &bs->fence, PIPE_TIMEOUT_INFINITE);255zink_reset_batch_state(ctx, bs);256} else {257if (!batch->state) {258/* this is batch init, so create a few more states for later use */259for (int i = 0; i < 3; i++) {260struct zink_batch_state *state = create_batch_state(ctx);261util_dynarray_append(&ctx->free_batch_states, struct zink_batch_state *, state);262}263}264bs = create_batch_state(ctx);265}266return bs;267}268269void270zink_reset_batch(struct zink_context *ctx, struct zink_batch *batch)271{272struct zink_screen *screen = zink_screen(ctx->base.screen);273274if (ctx->have_timelines && screen->last_finished > ctx->curr_batch && ctx->curr_batch == 1) {275if (!zink_screen_init_semaphore(screen)) {276debug_printf("timeline init failed, things are about to go dramatically wrong.");277ctx->have_timelines = false;278}279}280281batch->state = get_batch_state(ctx, batch);282assert(batch->state);283284batch->has_work = false;285}286287void288zink_start_batch(struct zink_context *ctx, struct zink_batch *batch)289{290zink_reset_batch(ctx, batch);291292batch->state->usage.unflushed = true;293294VkCommandBufferBeginInfo cbbi = {0};295cbbi.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;296cbbi.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;297if (vkBeginCommandBuffer(batch->state->cmdbuf, &cbbi) != VK_SUCCESS)298debug_printf("vkBeginCommandBuffer failed\n");299if (vkBeginCommandBuffer(batch->state->barrier_cmdbuf, &cbbi) != VK_SUCCESS)300debug_printf("vkBeginCommandBuffer failed\n");301302batch->state->fence.batch_id = ctx->curr_batch;303batch->state->fence.completed = false;304if (ctx->last_fence) {305struct zink_batch_state *last_state = zink_batch_state(ctx->last_fence);306batch->last_batch_usage = &last_state->usage;307}308if (!ctx->queries_disabled)309zink_resume_queries(ctx, batch);310}311312static void313post_submit(void *data, void *gdata, int thread_index)314{315struct zink_batch_state *bs = data;316317if (bs->is_device_lost) {318if (bs->ctx->reset.reset)319bs->ctx->reset.reset(bs->ctx->reset.data, PIPE_GUILTY_CONTEXT_RESET);320zink_screen(bs->ctx->base.screen)->device_lost = true;321}322}323324static void325submit_queue(void *data, void *gdata, int thread_index)326{327struct zink_batch_state *bs = data;328struct zink_context *ctx = bs->ctx;329struct zink_screen *screen = zink_screen(ctx->base.screen);330VkSubmitInfo si = {0};331332simple_mtx_lock(&ctx->batch_mtx);333while (!bs->fence.batch_id)334bs->fence.batch_id = p_atomic_inc_return(&screen->curr_batch);335_mesa_hash_table_insert_pre_hashed(&ctx->batch_states, bs->fence.batch_id, (void*)(uintptr_t)bs->fence.batch_id, bs);336bs->usage.usage = bs->fence.batch_id;337bs->usage.unflushed = false;338simple_mtx_unlock(&ctx->batch_mtx);339340vkResetFences(screen->dev, 1, &bs->fence.fence);341342uint64_t batch_id = bs->fence.batch_id;343si.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;344si.waitSemaphoreCount = 0;345si.pWaitSemaphores = NULL;346si.signalSemaphoreCount = 0;347si.pSignalSemaphores = NULL;348si.pWaitDstStageMask = NULL;349si.commandBufferCount = bs->has_barriers ? 2 : 1;350VkCommandBuffer cmdbufs[2] = {351bs->barrier_cmdbuf,352bs->cmdbuf,353};354si.pCommandBuffers = bs->has_barriers ? cmdbufs : &cmdbufs[1];355356VkTimelineSemaphoreSubmitInfo tsi = {0};357if (bs->have_timelines) {358tsi.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO;359si.pNext = &tsi;360tsi.signalSemaphoreValueCount = 1;361tsi.pSignalSemaphoreValues = &batch_id;362si.signalSemaphoreCount = 1;363si.pSignalSemaphores = &screen->sem;364}365366struct wsi_memory_signal_submit_info mem_signal = {367.sType = VK_STRUCTURE_TYPE_WSI_MEMORY_SIGNAL_SUBMIT_INFO_MESA,368.pNext = si.pNext,369};370371if (bs->flush_res && screen->needs_mesa_flush_wsi) {372struct zink_resource *flush_res = zink_resource(bs->flush_res);373mem_signal.memory = flush_res->scanout_obj ? flush_res->scanout_obj->mem : flush_res->obj->mem;374si.pNext = &mem_signal;375}376377if (vkEndCommandBuffer(bs->cmdbuf) != VK_SUCCESS) {378debug_printf("vkEndCommandBuffer failed\n");379bs->is_device_lost = true;380goto end;381}382if (vkEndCommandBuffer(bs->barrier_cmdbuf) != VK_SUCCESS) {383debug_printf("vkEndCommandBuffer failed\n");384bs->is_device_lost = true;385goto end;386}387388while (util_dynarray_contains(&bs->persistent_resources, struct zink_resource_object*)) {389struct zink_resource_object *obj = util_dynarray_pop(&bs->persistent_resources, struct zink_resource_object*);390VkMappedMemoryRange range = zink_resource_init_mem_range(screen, obj, 0, obj->size);391vkFlushMappedMemoryRanges(screen->dev, 1, &range);392}393394if (vkQueueSubmit(bs->queue, 1, &si, bs->fence.fence) != VK_SUCCESS) {395debug_printf("ZINK: vkQueueSubmit() failed\n");396bs->is_device_lost = true;397}398bs->submit_count++;399end:400cnd_broadcast(&bs->usage.flush);401402p_atomic_set(&bs->fence.submitted, true);403}404405406/* TODO: remove for wsi */407static void408copy_scanout(struct zink_batch_state *bs, struct zink_resource *res)409{410if (!bs->scanout_flush)411return;412413VkImageCopy region = {0};414struct pipe_box box = {0, 0, 0,415u_minify(res->base.b.width0, 0),416u_minify(res->base.b.height0, 0), res->base.b.array_size};417box.depth = util_num_layers(&res->base.b, 0);418struct pipe_box *src_box = &box;419unsigned dstz = 0;420421region.srcSubresource.aspectMask = res->aspect;422region.srcSubresource.mipLevel = 0;423switch (res->base.b.target) {424case PIPE_TEXTURE_CUBE:425case PIPE_TEXTURE_CUBE_ARRAY:426case PIPE_TEXTURE_2D_ARRAY:427case PIPE_TEXTURE_1D_ARRAY:428/* these use layer */429region.srcSubresource.baseArrayLayer = src_box->z;430region.srcSubresource.layerCount = src_box->depth;431region.srcOffset.z = 0;432region.extent.depth = 1;433break;434case PIPE_TEXTURE_3D:435/* this uses depth */436region.srcSubresource.baseArrayLayer = 0;437region.srcSubresource.layerCount = 1;438region.srcOffset.z = src_box->z;439region.extent.depth = src_box->depth;440break;441default:442/* these must only copy one layer */443region.srcSubresource.baseArrayLayer = 0;444region.srcSubresource.layerCount = 1;445region.srcOffset.z = 0;446region.extent.depth = 1;447}448449region.srcOffset.x = src_box->x;450region.srcOffset.y = src_box->y;451452region.dstSubresource.aspectMask = res->aspect;453region.dstSubresource.mipLevel = 0;454switch (res->base.b.target) {455case PIPE_TEXTURE_CUBE:456case PIPE_TEXTURE_CUBE_ARRAY:457case PIPE_TEXTURE_2D_ARRAY:458case PIPE_TEXTURE_1D_ARRAY:459/* these use layer */460region.dstSubresource.baseArrayLayer = dstz;461region.dstSubresource.layerCount = src_box->depth;462region.dstOffset.z = 0;463break;464case PIPE_TEXTURE_3D:465/* this uses depth */466region.dstSubresource.baseArrayLayer = 0;467region.dstSubresource.layerCount = 1;468region.dstOffset.z = dstz;469break;470default:471/* these must only copy one layer */472region.dstSubresource.baseArrayLayer = 0;473region.dstSubresource.layerCount = 1;474region.dstOffset.z = 0;475}476477region.dstOffset.x = 0;478region.dstOffset.y = 0;479region.extent.width = src_box->width;480region.extent.height = src_box->height;481482VkImageMemoryBarrier imb1;483zink_resource_image_barrier_init(&imb1, res, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);484vkCmdPipelineBarrier(485bs->cmdbuf,486res->access_stage ? res->access_stage : VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,487VK_PIPELINE_STAGE_TRANSFER_BIT,4880,4890, NULL,4900, NULL,4911, &imb1492);493494VkImageSubresourceRange isr = {495res->aspect,4960, VK_REMAINING_MIP_LEVELS,4970, VK_REMAINING_ARRAY_LAYERS498};499VkImageMemoryBarrier imb = {500VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,501NULL,5020,503VK_ACCESS_TRANSFER_WRITE_BIT,504res->scanout_obj_init ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : VK_IMAGE_LAYOUT_UNDEFINED,505VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,506VK_QUEUE_FAMILY_IGNORED,507VK_QUEUE_FAMILY_IGNORED,508res->scanout_obj->image,509isr510};511vkCmdPipelineBarrier(512bs->cmdbuf,513VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,514VK_PIPELINE_STAGE_TRANSFER_BIT,5150,5160, NULL,5170, NULL,5181, &imb519);520521vkCmdCopyImage(bs->cmdbuf, res->obj->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,522res->scanout_obj->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,5231, ®ion);524imb.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;525imb.dstAccessMask = 0;526imb.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;527imb.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;528vkCmdPipelineBarrier(529bs->cmdbuf,530VK_PIPELINE_STAGE_TRANSFER_BIT,531VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,5320,5330, NULL,5340, NULL,5351, &imb536);537/* separate flag to avoid annoying validation errors for new scanout objs */538res->scanout_obj_init = true;539}540541void542zink_end_batch(struct zink_context *ctx, struct zink_batch *batch)543{544if (batch->state->flush_res)545copy_scanout(batch->state, zink_resource(batch->state->flush_res));546if (!ctx->queries_disabled)547zink_suspend_queries(ctx, batch);548549tc_driver_internal_flush_notify(ctx->tc);550551struct zink_screen *screen = zink_screen(ctx->base.screen);552553ctx->resource_size += batch->state->resource_size;554ctx->last_fence = &batch->state->fence;555556if (screen->device_lost)557return;558559if (screen->threaded) {560batch->state->queue = screen->thread_queue;561util_queue_add_job(&screen->flush_queue, batch->state, &batch->state->flush_completed,562submit_queue, post_submit, 0);563} else {564batch->state->queue = screen->queue;565submit_queue(batch->state, NULL, 0);566post_submit(batch->state, NULL, 0);567}568}569570void571zink_batch_resource_usage_set(struct zink_batch *batch, struct zink_resource *res, bool write)572{573if (write) {574zink_batch_usage_set(&res->obj->writes, batch->state);575if (res->scanout_obj)576batch->state->scanout_flush = true;577} else {578zink_batch_usage_set(&res->obj->reads, batch->state);579}580/* multiple array entries are fine */581if (!res->obj->coherent && res->obj->persistent_maps)582util_dynarray_append(&batch->state->persistent_resources, struct zink_resource_object*, res->obj);583584batch->has_work = true;585}586587void588zink_batch_reference_resource_rw(struct zink_batch *batch, struct zink_resource *res, bool write)589{590/* if the resource already has usage of any sort set for this batch, we can skip hashing */591if (!zink_batch_usage_matches(res->obj->reads, batch->state) &&592!zink_batch_usage_matches(res->obj->writes, batch->state)) {593zink_batch_reference_resource(batch, res);594}595zink_batch_resource_usage_set(batch, res, write);596}597598bool599batch_ptr_add_usage(struct zink_batch *batch, struct set *s, void *ptr)600{601bool found = false;602_mesa_set_search_or_add(s, ptr, &found);603return !found;604}605606void607zink_batch_reference_resource(struct zink_batch *batch, struct zink_resource *res)608{609if (!batch_ptr_add_usage(batch, batch->state->resources, res->obj))610return;611pipe_reference(NULL, &res->obj->reference);612batch->state->resource_size += res->obj->size;613batch->has_work = true;614}615616void617zink_batch_reference_resource_move(struct zink_batch *batch, struct zink_resource *res)618{619if (!batch_ptr_add_usage(batch, batch->state->resources, res->obj))620return;621batch->state->resource_size += res->obj->size;622batch->has_work = true;623}624625void626zink_batch_reference_bufferview(struct zink_batch *batch, struct zink_buffer_view *buffer_view)627{628if (!batch_ptr_add_usage(batch, batch->state->bufferviews, buffer_view))629return;630pipe_reference(NULL, &buffer_view->reference);631batch->has_work = true;632}633634void635zink_batch_reference_surface(struct zink_batch *batch, struct zink_surface *surface)636{637if (!batch_ptr_add_usage(batch, batch->state->surfaces, surface))638return;639struct pipe_surface *surf = NULL;640pipe_surface_reference(&surf, &surface->base);641batch->has_work = true;642}643644void645zink_batch_reference_sampler_view(struct zink_batch *batch,646struct zink_sampler_view *sv)647{648if (sv->base.target == PIPE_BUFFER)649zink_batch_reference_bufferview(batch, sv->buffer_view);650else651zink_batch_reference_surface(batch, sv->image_view);652}653654void655zink_batch_reference_framebuffer(struct zink_batch *batch,656struct zink_framebuffer *fb)657{658bool found;659_mesa_set_search_or_add(batch->state->fbs, fb, &found);660if (!found)661pipe_reference(NULL, &fb->reference);662}663664void665zink_batch_reference_program(struct zink_batch *batch,666struct zink_program *pg)667{668if (zink_batch_usage_matches(pg->batch_uses, batch->state) ||669!batch_ptr_add_usage(batch, batch->state->programs, pg))670return;671pipe_reference(NULL, &pg->reference);672zink_batch_usage_set(&pg->batch_uses, batch->state);673batch->has_work = true;674}675676void677zink_batch_reference_image_view(struct zink_batch *batch,678struct zink_image_view *image_view)679{680if (image_view->base.resource->target == PIPE_BUFFER)681zink_batch_reference_bufferview(batch, image_view->buffer_view);682else683zink_batch_reference_surface(batch, image_view->surface);684}685686bool687zink_batch_usage_check_completion(struct zink_context *ctx, const struct zink_batch_usage *u)688{689if (!zink_batch_usage_exists(u))690return true;691if (zink_batch_usage_is_unflushed(u))692return false;693return zink_check_batch_completion(ctx, u->usage);694}695696void697zink_batch_usage_wait(struct zink_context *ctx, struct zink_batch_usage *u)698{699if (!zink_batch_usage_exists(u))700return;701if (zink_batch_usage_is_unflushed(u)) {702if (likely(u == &ctx->batch.state->usage))703ctx->base.flush(&ctx->base, NULL, PIPE_FLUSH_HINT_FINISH);704else { //multi-context705mtx_lock(&u->mtx);706cnd_wait(&u->flush, &u->mtx);707mtx_unlock(&u->mtx);708}709}710zink_wait_on_batch(ctx, u->usage);711}712713714