From 7f56fd965504b4c21417e6f54267f7c7b8470caf Mon Sep 17 00:00:00 2001 From: Mike Blumenkrantz Date: Thu, 13 Jan 2022 15:29:54 -0500 Subject: [PATCH] zink: it's kopperin' time Reviewed-by: Adam Jackson Part-of: --- .../target-helpers/inline_sw_helper.h | 2 +- .../auxiliary/target-helpers/sw_helper.h | 4 +- src/gallium/drivers/zink/meson.build | 1 + src/gallium/drivers/zink/zink_batch.c | 194 ++++-------------- src/gallium/drivers/zink/zink_batch.h | 9 +- src/gallium/drivers/zink/zink_blit.c | 22 +- src/gallium/drivers/zink/zink_clear.c | 3 + src/gallium/drivers/zink/zink_context.c | 67 +++++- src/gallium/drivers/zink/zink_context.h | 2 + src/gallium/drivers/zink/zink_framebuffer.c | 4 +- src/gallium/drivers/zink/zink_instance.py | 4 + src/gallium/drivers/zink/zink_public.h | 2 +- src/gallium/drivers/zink/zink_resource.c | 129 ++++++------ src/gallium/drivers/zink/zink_resource.h | 18 +- src/gallium/drivers/zink/zink_screen.c | 80 ++++---- src/gallium/drivers/zink/zink_screen.h | 14 +- src/gallium/drivers/zink/zink_surface.c | 59 +++++- src/gallium/drivers/zink/zink_surface.h | 11 +- src/gallium/frontends/dri/kopper.c | 2 - src/gallium/targets/wgl/wgl.c | 2 +- 20 files changed, 326 insertions(+), 303 deletions(-) diff --git a/src/gallium/auxiliary/target-helpers/inline_sw_helper.h b/src/gallium/auxiliary/target-helpers/inline_sw_helper.h index cd6f1150aae..20cb933fb70 100644 --- a/src/gallium/auxiliary/target-helpers/inline_sw_helper.h +++ b/src/gallium/auxiliary/target-helpers/inline_sw_helper.h @@ -59,7 +59,7 @@ sw_screen_create_named(struct sw_winsys *winsys, const char *driver) #if defined(GALLIUM_ZINK) if (screen == NULL && strcmp(driver, "zink") == 0) - screen = zink_create_screen(winsys); + screen = zink_create_screen(winsys, NULL); #endif #if defined(GALLIUM_D3D12) diff --git a/src/gallium/auxiliary/target-helpers/sw_helper.h b/src/gallium/auxiliary/target-helpers/sw_helper.h index 3ffd9a67877..dcf3a60a913 100644 --- a/src/gallium/auxiliary/target-helpers/sw_helper.h +++ b/src/gallium/auxiliary/target-helpers/sw_helper.h @@ -63,7 +63,7 @@ sw_screen_create_named(struct sw_winsys *winsys, const struct pipe_screen_config #if defined(GALLIUM_ZINK) if (screen == NULL && strcmp(driver, "zink") == 0) - screen = zink_create_screen(winsys); + screen = zink_create_screen(winsys, config); #endif #if defined(GALLIUM_D3D12) @@ -114,7 +114,7 @@ struct pipe_screen * sw_screen_create_zink(struct sw_winsys *winsys, const struct pipe_screen_config *config, bool whatever) { #if defined(GALLIUM_ZINK) - return zink_create_screen(winsys); + return zink_create_screen(winsys, config); #else return NULL; #endif diff --git a/src/gallium/drivers/zink/meson.build b/src/gallium/drivers/zink/meson.build index d4be88f083a..7c82f76217c 100644 --- a/src/gallium/drivers/zink/meson.build +++ b/src/gallium/drivers/zink/meson.build @@ -28,6 +28,7 @@ files_libzink = files( 'zink_clear.c', 'zink_compiler.c', 'zink_context.c', + 'zink_kopper.c', 'zink_descriptors.c', 'zink_descriptors_lazy.c', 'zink_draw.cpp', diff --git a/src/gallium/drivers/zink/zink_batch.c b/src/gallium/drivers/zink/zink_batch.c index 002982abd12..0ddb13308c6 100644 --- a/src/gallium/drivers/zink/zink_batch.c +++ b/src/gallium/drivers/zink/zink_batch.c @@ -1,6 +1,7 @@ #include "zink_batch.h" #include "zink_context.h" +#include "zink_kopper.h" #include "zink_fence.h" #include "zink_framebuffer.h" #include "zink_query.h" @@ -87,19 +88,24 @@ zink_reset_batch_state(struct zink_context *ctx, struct zink_batch_state *bs) zink_program_reference(ctx, &pg, NULL); } - pipe_resource_reference(&bs->flush_res, NULL); - bs->resource_size = 0; bs->signal_semaphore = VK_NULL_HANDLE; util_dynarray_clear(&bs->wait_semaphores); util_dynarray_clear(&bs->wait_semaphore_stages); + bs->present = VK_NULL_HANDLE; + while (util_dynarray_contains(&bs->acquires, VkSemaphore)) + VKSCR(DestroySemaphore)(screen->dev, util_dynarray_pop(&bs->acquires, VkSemaphore), NULL); + bs->swapchain = NULL; + + while (util_dynarray_contains(&bs->dead_swapchains, VkImageView)) + VKSCR(DestroyImageView)(screen->dev, util_dynarray_pop(&bs->dead_swapchains, VkImageView), NULL); + /* only reset submitted here so that tc fence desync can pick up the 'completed' flag * before the state is reused */ bs->fence.submitted = false; bs->has_barriers = false; - bs->scanout_flush = false; if (bs->fence.batch_id) zink_screen_update_last_finished(screen, bs->fence.batch_id); bs->submit_count++; @@ -175,6 +181,8 @@ zink_batch_state_destroy(struct zink_screen *screen, struct zink_batch_state *bs util_dynarray_fini(&bs->unref_resources); util_dynarray_fini(&bs->bindless_releases[0]); util_dynarray_fini(&bs->bindless_releases[1]); + util_dynarray_fini(&bs->acquires); + util_dynarray_fini(&bs->dead_swapchains); _mesa_set_destroy(bs->surfaces, NULL); _mesa_set_destroy(bs->bufferviews, NULL); _mesa_set_destroy(bs->programs, NULL); @@ -225,6 +233,8 @@ create_batch_state(struct zink_context *ctx) util_dynarray_init(&bs->dead_framebuffers, NULL); util_dynarray_init(&bs->persistent_resources, NULL); util_dynarray_init(&bs->unref_resources, NULL); + util_dynarray_init(&bs->acquires, NULL); + util_dynarray_init(&bs->dead_swapchains, NULL); util_dynarray_init(&bs->bindless_releases[0], NULL); util_dynarray_init(&bs->bindless_releases[1], NULL); @@ -369,7 +379,15 @@ submit_queue(void *data, void *gdata, int thread_index) } uint64_t batch_id = bs->fence.batch_id; + /* first submit is just for acquire waits since they have a separate array */ si[0].sType = si[1].sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + si[0].waitSemaphoreCount = util_dynarray_num_elements(&bs->acquires, VkSemaphore); + si[0].pWaitSemaphores = bs->acquires.data; + VkPipelineStageFlags mask[32]; //can't imagine having more dumbass than this + assert(util_dynarray_num_elements(&bs->acquires, VkSemaphore) < ARRAY_SIZE(mask)); + for (unsigned i = 0; i < ARRAY_SIZE(mask); i++) + mask[i] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + si[0].pWaitDstStageMask = mask; /* then the real submit */ si[1].waitSemaphoreCount = util_dynarray_num_elements(&bs->wait_semaphores, VkSemaphore); @@ -382,7 +400,7 @@ submit_queue(void *data, void *gdata, int thread_index) }; si[1].pCommandBuffers = bs->has_barriers ? cmdbufs : &cmdbufs[1]; - VkSemaphore signals[2]; + VkSemaphore signals[3]; si[1].signalSemaphoreCount = !!bs->signal_semaphore; signals[0] = bs->signal_semaphore; si[1].pSignalSemaphores = signals; @@ -397,16 +415,9 @@ submit_queue(void *data, void *gdata, int thread_index) tsi.signalSemaphoreValueCount = si[1].signalSemaphoreCount; } - struct wsi_memory_signal_submit_info mem_signal = { - .sType = VK_STRUCTURE_TYPE_WSI_MEMORY_SIGNAL_SUBMIT_INFO_MESA, - .pNext = si[1].pNext, - }; - - if (bs->flush_res && screen->needs_mesa_flush_wsi) { - struct zink_resource *flush_res = zink_resource(bs->flush_res); - mem_signal.memory = zink_bo_get_mem(flush_res->scanout_obj ? flush_res->scanout_obj->bo : flush_res->obj->bo); - si[1].pNext = &mem_signal; - } + if (bs->present) + signals[si[1].signalSemaphoreCount++] = bs->present; + tsi.signalSemaphoreValueCount = si[1].signalSemaphoreCount; if (VKSCR(EndCommandBuffer)(bs->cmdbuf) != VK_SUCCESS) { mesa_loge("ZINK: vkEndCommandBuffer failed"); @@ -441,149 +452,9 @@ end: unref_resources(screen, bs); } - -/* TODO: remove for wsi */ -static void -copy_scanout(struct zink_batch_state *bs, struct zink_resource *res) -{ - if (!bs->scanout_flush) - return; - struct zink_context *ctx = bs->ctx; - - VkImageCopy region = {0}; - struct pipe_box box = {0, 0, 0, - u_minify(res->base.b.width0, 0), - u_minify(res->base.b.height0, 0), res->base.b.array_size}; - box.depth = util_num_layers(&res->base.b, 0); - struct pipe_box *src_box = &box; - unsigned dstz = 0; - - region.srcSubresource.aspectMask = res->aspect; - region.srcSubresource.mipLevel = 0; - switch (res->base.b.target) { - case PIPE_TEXTURE_CUBE: - case PIPE_TEXTURE_CUBE_ARRAY: - case PIPE_TEXTURE_2D_ARRAY: - case PIPE_TEXTURE_1D_ARRAY: - /* these use layer */ - region.srcSubresource.baseArrayLayer = src_box->z; - region.srcSubresource.layerCount = src_box->depth; - region.srcOffset.z = 0; - region.extent.depth = 1; - break; - case PIPE_TEXTURE_3D: - /* this uses depth */ - region.srcSubresource.baseArrayLayer = 0; - region.srcSubresource.layerCount = 1; - region.srcOffset.z = src_box->z; - region.extent.depth = src_box->depth; - break; - default: - /* these must only copy one layer */ - region.srcSubresource.baseArrayLayer = 0; - region.srcSubresource.layerCount = 1; - region.srcOffset.z = 0; - region.extent.depth = 1; - } - - region.srcOffset.x = src_box->x; - region.srcOffset.y = src_box->y; - - region.dstSubresource.aspectMask = res->aspect; - region.dstSubresource.mipLevel = 0; - switch (res->base.b.target) { - case PIPE_TEXTURE_CUBE: - case PIPE_TEXTURE_CUBE_ARRAY: - case PIPE_TEXTURE_2D_ARRAY: - case PIPE_TEXTURE_1D_ARRAY: - /* these use layer */ - region.dstSubresource.baseArrayLayer = dstz; - region.dstSubresource.layerCount = src_box->depth; - region.dstOffset.z = 0; - break; - case PIPE_TEXTURE_3D: - /* this uses depth */ - region.dstSubresource.baseArrayLayer = 0; - region.dstSubresource.layerCount = 1; - region.dstOffset.z = dstz; - break; - default: - /* these must only copy one layer */ - region.dstSubresource.baseArrayLayer = 0; - region.dstSubresource.layerCount = 1; - region.dstOffset.z = 0; - } - - region.dstOffset.x = 0; - region.dstOffset.y = 0; - region.extent.width = src_box->width; - region.extent.height = src_box->height; - - VkImageMemoryBarrier imb1; - zink_resource_image_barrier_init(&imb1, res, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - VKCTX(CmdPipelineBarrier)( - bs->cmdbuf, - res->obj->access_stage ? res->obj->access_stage : VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, - 0, - 0, NULL, - 0, NULL, - 1, &imb1 - ); - res->layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - - VkImageSubresourceRange isr = { - res->aspect, - 0, VK_REMAINING_MIP_LEVELS, - 0, VK_REMAINING_ARRAY_LAYERS - }; - VkImageMemoryBarrier imb = { - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - NULL, - 0, - VK_ACCESS_TRANSFER_WRITE_BIT, - res->scanout_obj_init ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_QUEUE_FAMILY_IGNORED, - VK_QUEUE_FAMILY_IGNORED, - res->scanout_obj->image, - isr - }; - VKCTX(CmdPipelineBarrier)( - bs->cmdbuf, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, - 0, - 0, NULL, - 0, NULL, - 1, &imb - ); - - VKCTX(CmdCopyImage)(bs->cmdbuf, res->obj->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - res->scanout_obj->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, ®ion); - imb.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - imb.dstAccessMask = 0; - imb.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - imb.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - VKCTX(CmdPipelineBarrier)( - bs->cmdbuf, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, - 0, - 0, NULL, - 0, NULL, - 1, &imb - ); - /* separate flag to avoid annoying validation errors for new scanout objs */ - res->scanout_obj_init = true; -} - void zink_end_batch(struct zink_context *ctx, struct zink_batch *batch) { - if (batch->state->flush_res) - copy_scanout(batch->state, zink_resource(batch->state->flush_res)); if (!ctx->queries_disabled) zink_suspend_queries(ctx, batch); @@ -625,6 +496,12 @@ zink_end_batch(struct zink_context *ctx, struct zink_batch *batch) simple_mtx_unlock(&ctx->batch_mtx); batch->work_count = 0; + if (batch->swapchain) { + batch->state->present = zink_kopper_present(screen, batch->swapchain); + batch->state->swapchain = batch->swapchain; + batch->swapchain = NULL; + } + if (screen->device_lost) return; @@ -640,9 +517,14 @@ zink_end_batch(struct zink_context *ctx, struct zink_batch *batch) void zink_batch_resource_usage_set(struct zink_batch *batch, struct zink_resource *res, bool write) { + if (res->obj->dt) { + VkSemaphore acquire = zink_kopper_acquire_submit(zink_screen(batch->state->ctx->base.screen), res); + if (acquire) { + util_dynarray_append(&batch->state->acquires, VkSemaphore, acquire); + res->obj->dt_has_data = true; + } + } zink_resource_usage_set(res, batch->state, write); - if (write && res->scanout_obj) - batch->state->scanout_flush = true; /* multiple array entries are fine */ if (!res->obj->coherent && res->obj->persistent_maps) util_dynarray_append(&batch->state->persistent_resources, struct zink_resource_object*, res->obj); diff --git a/src/gallium/drivers/zink/zink_batch.h b/src/gallium/drivers/zink/zink_batch.h index 364967a7b39..0cb03edb3eb 100644 --- a/src/gallium/drivers/zink/zink_batch.h +++ b/src/gallium/drivers/zink/zink_batch.h @@ -103,12 +103,13 @@ struct zink_batch_state { struct util_dynarray wait_semaphore_stages; //external wait semaphores VkQueue queue; //duplicated from batch for threading - VkSemaphore sem; + VkSemaphore present; + struct zink_resource *swapchain; + struct util_dynarray acquires; + struct util_dynarray dead_swapchains; struct util_queue_fence flush_completed; - struct pipe_resource *flush_res; - struct set *programs; struct set *resources; @@ -134,13 +135,13 @@ struct zink_batch_state { bool is_device_lost; bool have_timelines; bool has_barriers; - bool scanout_flush; }; struct zink_batch { struct zink_batch_state *state; struct zink_batch_usage *last_batch_usage; + struct zink_resource *swapchain; unsigned work_count; diff --git a/src/gallium/drivers/zink/zink_blit.c b/src/gallium/drivers/zink/zink_blit.c index aeecd5358d7..fa879efb81e 100644 --- a/src/gallium/drivers/zink/zink_blit.c +++ b/src/gallium/drivers/zink/zink_blit.c @@ -1,4 +1,5 @@ #include "zink_context.h" +#include "zink_kopper.h" #include "zink_helpers.h" #include "zink_query.h" #include "zink_resource.h" @@ -21,7 +22,7 @@ apply_dst_clears(struct zink_context *ctx, const struct pipe_blit_info *info, bo } static bool -blit_resolve(struct zink_context *ctx, const struct pipe_blit_info *info) +blit_resolve(struct zink_context *ctx, const struct pipe_blit_info *info, bool *needs_present_readback) { if (util_format_get_mask(info->dst.format) != info->mask || util_format_get_mask(info->src.format) != info->mask || @@ -53,6 +54,9 @@ blit_resolve(struct zink_context *ctx, const struct pipe_blit_info *info) apply_dst_clears(ctx, info, false); zink_fb_clears_apply_region(ctx, info->src.resource, zink_rect_from_box(&info->src.box)); + if (src->obj->dt) + *needs_present_readback = zink_kopper_acquire_readback(ctx, src); + struct zink_batch *batch = &ctx->batch; zink_batch_no_rp(ctx); zink_batch_reference_resource_rw(batch, src, false); @@ -113,7 +117,7 @@ get_resource_features(struct zink_screen *screen, struct zink_resource *res) } static bool -blit_native(struct zink_context *ctx, const struct pipe_blit_info *info) +blit_native(struct zink_context *ctx, const struct pipe_blit_info *info, bool *needs_present_readback) { if (util_format_get_mask(info->dst.format) != info->mask || util_format_get_mask(info->src.format) != info->mask || @@ -159,6 +163,9 @@ blit_native(struct zink_context *ctx, const struct pipe_blit_info *info) apply_dst_clears(ctx, info, false); zink_fb_clears_apply_region(ctx, info->src.resource, zink_rect_from_box(&info->src.box)); + if (src->obj->dt) + *needs_present_readback = zink_kopper_acquire_readback(ctx, src); + struct zink_batch *batch = &ctx->batch; zink_batch_no_rp(ctx); zink_batch_reference_resource_rw(batch, src, false); @@ -266,6 +273,9 @@ zink_blit(struct pipe_context *pctx, struct zink_resource *src = zink_resource(info->src.resource); struct zink_resource *dst = zink_resource(info->dst.resource); + bool needs_present_readback = false; + if (dst->obj->dt) + zink_kopper_acquire(ctx, dst, UINT64_MAX); if (src_desc == dst_desc || src_desc->nr_channels != 4 || src_desc->layout != UTIL_FORMAT_LAYOUT_PLAIN || @@ -275,10 +285,10 @@ zink_blit(struct pipe_context *pctx, */ if (info->src.resource->nr_samples > 1 && info->dst.resource->nr_samples <= 1) { - if (blit_resolve(ctx, info)) + if (blit_resolve(ctx, info, &needs_present_readback)) goto end; } else { - if (blit_native(ctx, info)) + if (blit_native(ctx, info, &needs_present_readback)) goto end; } } @@ -303,6 +313,8 @@ zink_blit(struct pipe_context *pctx, goto end; } + if (src->obj->dt) + needs_present_readback = zink_kopper_acquire_readback(ctx, src); /* this is discard_only because we're about to start a renderpass that will * flush all pending clears anyway */ @@ -315,6 +327,8 @@ zink_blit(struct pipe_context *pctx, util_blitter_blit(ctx->blitter, info); end: + if (needs_present_readback) + zink_kopper_present_readback(ctx, src); } /* similar to radeonsi */ diff --git a/src/gallium/drivers/zink/zink_clear.c b/src/gallium/drivers/zink/zink_clear.c index 6a9e00f92a5..5e974b6ad77 100644 --- a/src/gallium/drivers/zink/zink_clear.c +++ b/src/gallium/drivers/zink/zink_clear.c @@ -22,6 +22,7 @@ */ #include "zink_context.h" +#include "zink_kopper.h" #include "zink_query.h" #include "zink_resource.h" #include "zink_screen.h" @@ -139,6 +140,8 @@ clear_color_no_rp(struct zink_context *ctx, struct zink_resource *res, const uni color.uint32[2] = pcolor->ui[2]; color.uint32[3] = pcolor->ui[3]; + if (res->obj->dt) + zink_kopper_acquire(ctx, res, UINT64_MAX); if (zink_resource_image_needs_barrier(res, VK_IMAGE_LAYOUT_GENERAL, 0, 0) && zink_resource_image_needs_barrier(res, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, 0)) zink_resource_image_barrier(ctx, res, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, 0); diff --git a/src/gallium/drivers/zink/zink_context.c b/src/gallium/drivers/zink/zink_context.c index 8aa1400157d..ae82677cd6a 100644 --- a/src/gallium/drivers/zink/zink_context.c +++ b/src/gallium/drivers/zink/zink_context.c @@ -25,6 +25,7 @@ #include "zink_batch.h" #include "zink_compiler.h" +#include "zink_kopper.h" #include "zink_fence.h" #include "zink_format.h" #include "zink_framebuffer.h" @@ -80,7 +81,7 @@ check_resource_for_batch_ref(struct zink_context *ctx, struct zink_resource *res * - if tracking will be added here, also reapply usage to avoid dangling usage once tracking is removed * TODO: somehow fix this for perf because it's an extra hash lookup */ - if (res->obj->bo->reads || res->obj->bo->writes) + if (!res->obj->dt && (res->obj->bo->reads || res->obj->bo->writes)) zink_batch_reference_resource_rw(&ctx->batch, res, !!res->obj->bo->writes); else zink_batch_reference_resource(&ctx->batch, res); @@ -759,6 +760,9 @@ zink_create_sampler_view(struct pipe_context *pctx, struct pipe_resource *pres, templ.u.tex.last_layer = state->u.tex.last_layer; } + if (res->obj->dt) + zink_kopper_acquire(ctx, res, UINT64_MAX); + ivci = create_ivci(screen, res, &templ, state->target); ivci.subresourceRange.levelCount = state->u.tex.last_level - state->u.tex.first_level + 1; ivci.subresourceRange.aspectMask = sampler_aspect_from_format(state->format); @@ -1883,6 +1887,9 @@ zink_update_fbfetch(struct zink_context *ctx) bool changed = !had_fbfetch; if (ctx->fb_state.cbufs[0]) { VkImageView fbfetch = zink_csurface(ctx->fb_state.cbufs[0])->image_view; + if (!fbfetch) + /* swapchain image: retry later */ + return; changed |= fbfetch != ctx->di.fbfetch.imageView; ctx->di.fbfetch.imageView = zink_csurface(ctx->fb_state.cbufs[0])->image_view; } @@ -1951,7 +1958,7 @@ get_render_pass(struct zink_context *ctx) state.rts[i].samples = MAX3(transient ? transient->base.nr_samples : 0, surf->texture->nr_samples, 1); state.rts[i].clear_color = zink_fb_clear_enabled(ctx, i) && !zink_fb_clear_first_needs_explicit(&ctx->fb_clears[i]); clears |= !!state.rts[i].clear_color ? PIPE_CLEAR_COLOR0 << i : 0; - state.rts[i].swapchain = surf->texture->bind & PIPE_BIND_SCANOUT; + state.rts[i].swapchain = surf->texture->bind & PIPE_BIND_DISPLAY_TARGET; if (transient) { state.num_cresolves++; state.rts[i].resolve = true; @@ -2114,6 +2121,23 @@ setup_framebuffer(struct zink_context *ctx) } ctx->rp_changed = false; + for (unsigned i = 0; i < ctx->fb_state.nr_cbufs; i++) { + if (!ctx->fb_state.cbufs[i]) + continue; + struct zink_resource *res = zink_resource(ctx->fb_state.cbufs[i]->texture); + if (res->obj->dt) { + zink_kopper_acquire(ctx, res, UINT64_MAX); + zink_surface_swapchain_update(ctx, zink_csurface(ctx->fb_state.cbufs[i])); + } + } + if (ctx->swapchain_size.width || ctx->swapchain_size.height) { + unsigned old_w = ctx->fb_state.width; + unsigned old_h = ctx->fb_state.height; + ctx->fb_state.width = ctx->swapchain_size.width; + ctx->fb_state.height = ctx->swapchain_size.height; + update_framebuffer_state(ctx, old_w, old_h); + ctx->swapchain_size.width = ctx->swapchain_size.height = 0; + } if (!ctx->fb_changed) return; @@ -2138,6 +2162,12 @@ prep_fb_attachment(struct zink_context *ctx, struct zink_surface *surf, unsigned VkAccessFlags access; VkPipelineStageFlags pipeline; + if (res->obj->dt) { + zink_kopper_acquire(ctx, res, UINT64_MAX); + zink_surface_swapchain_update(ctx, surf); + if (!i) + zink_update_fbfetch(ctx); + } VkImageLayout layout = zink_render_pass_attachment_get_barrier_info(ctx->gfx_pipeline_state.render_pass, i, &pipeline, &access); zink_resource_image_barrier(ctx, res, layout, access, pipeline); @@ -2583,6 +2613,10 @@ unbind_fb_surface(struct zink_context *ctx, struct pipe_surface *surf, unsigned struct zink_resource *res = zink_resource(surf->texture); if (changed) { if (zink_fb_clear_enabled(ctx, idx)) { + if (res->obj->dt) { + zink_kopper_acquire(ctx, res, UINT64_MAX); + zink_surface_swapchain_update(ctx, zink_csurface(surf)); + } zink_fb_clears_apply(ctx, surf->texture); } if (zink_batch_usage_exists(zink_csurface(surf)->batch_uses)) { @@ -2629,6 +2663,8 @@ zink_set_framebuffer_state(struct pipe_context *pctx, if (i < state->nr_cbufs) ctx->rp_changed |= !!zink_transient_surface(surf) != !!zink_transient_surface(state->cbufs[i]); unbind_fb_surface(ctx, surf, i, i >= state->nr_cbufs || surf != state->cbufs[i]); + if (surf && ctx->needs_present == zink_resource(surf->texture)) + ctx->needs_present = NULL; } if (ctx->fb_state.zsbuf) { struct pipe_surface *surf = ctx->fb_state.zsbuf; @@ -2660,7 +2696,12 @@ zink_set_framebuffer_state(struct pipe_context *pctx, struct zink_surface *transient = zink_transient_surface(surf); if (!samples) samples = MAX3(transient ? transient->base.nr_samples : 1, surf->texture->nr_samples, 1); - zink_resource(surf->texture)->fb_binds++; + struct zink_resource *res = zink_resource(surf->texture); + if (res->modifiers) { + assert(!ctx->needs_present || ctx->needs_present == res); + ctx->needs_present = res; + } + res->fb_binds++; ctx->gfx_pipeline_state.void_alpha_attachments |= util_format_has_alpha1(surf->format) ? BITFIELD_BIT(i) : 0; } } @@ -3130,6 +3171,10 @@ zink_flush(struct pipe_context *pctx, /* start rp to do all the clears */ zink_begin_render_pass(ctx); + if (ctx->needs_present && (flags & PIPE_FLUSH_END_OF_FRAME)) { + zink_resource_image_barrier(ctx, ctx->needs_present, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, 0, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT); + } + if (!batch->has_work) { if (pfence) { /* reuse last fence */ @@ -3434,11 +3479,11 @@ zink_flush_resource(struct pipe_context *pctx, { struct zink_context *ctx = zink_context(pctx); struct zink_resource *res = zink_resource(pres); - /* TODO: this is not futureproof and should be updated once proper - * WSI support is added - */ - if (res->scanout_obj && (pres->bind & (PIPE_BIND_SHARED | PIPE_BIND_SCANOUT))) - pipe_resource_reference(&ctx->batch.state->flush_res, pres); + if (pres->bind & PIPE_BIND_DISPLAY_TARGET && res->obj->acquire) { + zink_resource_image_barrier(ctx, res, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, 0, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT); + zink_batch_reference_resource_rw(&ctx->batch, res, true); + ctx->batch.swapchain = res; + } } void @@ -3473,9 +3518,13 @@ zink_copy_image_buffer(struct zink_context *ctx, struct zink_resource *dst, stru bool buf2img = buf == src; if (buf2img) { + if (img->obj->dt) + zink_kopper_acquire(ctx, img, UINT64_MAX); zink_resource_image_barrier(ctx, img, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, 0); zink_resource_buffer_barrier(ctx, buf, VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); } else { + if (img->obj->dt) + zink_kopper_acquire_readback(ctx, img); zink_resource_image_barrier(ctx, img, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 0, 0); zink_resource_buffer_barrier(ctx, buf, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); util_range_add(&dst->base.b, &dst->valid_buffer_range, dstx, dstx + src_box->width); @@ -3554,6 +3603,8 @@ zink_copy_image_buffer(struct zink_context *ctx, struct zink_resource *dst, stru else VKCTX(CmdCopyImageToBuffer)(batch->state->cmdbuf, img->obj->image, img->layout, buf->obj->buffer, 1, ®ion); } + if (!buf2img && img->obj->dt) + zink_kopper_present_readback(ctx, img); } static void diff --git a/src/gallium/drivers/zink/zink_context.h b/src/gallium/drivers/zink/zink_context.h index d621d894ad7..90c0bc38431 100644 --- a/src/gallium/drivers/zink/zink_context.h +++ b/src/gallium/drivers/zink/zink_context.h @@ -252,6 +252,7 @@ struct zink_context { struct set render_pass_state_cache; struct hash_table *render_pass_cache; bool new_swapchain; + VkExtent2D swapchain_size; bool fb_changed; bool rp_changed; @@ -260,6 +261,7 @@ struct zink_context { uint16_t clears_enabled; uint16_t rp_clears_enabled; uint16_t fbfetch_outputs; + struct zink_resource *needs_present; struct pipe_vertex_buffer vertex_buffers[PIPE_MAX_ATTRIBS]; bool vertex_buffers_dirty; diff --git a/src/gallium/drivers/zink/zink_framebuffer.c b/src/gallium/drivers/zink/zink_framebuffer.c index cf3ea72831e..c3eda61c94d 100644 --- a/src/gallium/drivers/zink/zink_framebuffer.c +++ b/src/gallium/drivers/zink/zink_framebuffer.c @@ -112,8 +112,8 @@ populate_attachment_info(VkFramebufferAttachmentImageInfo *att, struct zink_surf att->sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO; att->pNext = NULL; memcpy(&att->flags, &info->flags, offsetof(struct zink_surface_info, format)); - att->viewFormatCount = 1; - att->pViewFormats = &info->format; + att->viewFormatCount = 1 + !!info->format[1]; + att->pViewFormats = info->format; } static struct zink_framebuffer * diff --git a/src/gallium/drivers/zink/zink_instance.py b/src/gallium/drivers/zink/zink_instance.py index f871b5ff862..20002c4727b 100644 --- a/src/gallium/drivers/zink/zink_instance.py +++ b/src/gallium/drivers/zink/zink_instance.py @@ -107,6 +107,10 @@ void zink_stub_${cmd.lstrip("vk")}(void); %endif %endfor +struct pipe_screen; +struct pipe_resource; +bool zink_kopper_update(struct pipe_screen *pscreen, struct pipe_resource *pres, int *w, int *h); + #endif """ diff --git a/src/gallium/drivers/zink/zink_public.h b/src/gallium/drivers/zink/zink_public.h index a5a4f6bca42..cb3bf6e7daf 100644 --- a/src/gallium/drivers/zink/zink_public.h +++ b/src/gallium/drivers/zink/zink_public.h @@ -29,7 +29,7 @@ struct sw_winsys; struct pipe_screen_config; struct pipe_screen * -zink_create_screen(struct sw_winsys *winsys); +zink_create_screen(struct sw_winsys *winsys, const struct pipe_screen_config *config); struct pipe_screen * zink_drm_create_screen(int fd, const struct pipe_screen_config *config); diff --git a/src/gallium/drivers/zink/zink_resource.c b/src/gallium/drivers/zink/zink_resource.c index 932bace91b8..f5ed409b1b4 100644 --- a/src/gallium/drivers/zink/zink_resource.c +++ b/src/gallium/drivers/zink/zink_resource.c @@ -28,6 +28,7 @@ #include "zink_fence.h" #include "zink_program.h" #include "zink_screen.h" +#include "zink_kopper.h" #ifdef VK_USE_PLATFORM_METAL_EXT #include "QuartzCore/CAMetalLayer.h" @@ -95,12 +96,18 @@ zink_destroy_resource_object(struct zink_screen *screen, struct zink_resource_ob if (obj->is_buffer) { VKSCR(DestroyBuffer)(screen->dev, obj->buffer, NULL); VKSCR(DestroyBuffer)(screen->dev, obj->storage_buffer, NULL); + } else if (obj->dt) { + zink_kopper_displaytarget_destroy(screen, obj->dt); } else { VKSCR(DestroyImage)(screen->dev, obj->image, NULL); } zink_descriptor_set_refs_clear(&obj->desc_set_refs, obj); - zink_bo_unref(screen, obj->bo); + if (obj->dt) { + util_queue_fence_destroy(&obj->present_fence); + FREE(obj->bo); //this is a dummy struct + } else + zink_bo_unref(screen, obj->bo); FREE(obj); } @@ -124,7 +131,6 @@ zink_resource_destroy(struct pipe_screen *pscreen, /* no need to do anything for the caches, these objects own the resource lifetimes */ zink_resource_object_reference(screen, &res->obj, NULL); - zink_resource_object_reference(screen, &res->scanout_obj, NULL); threaded_resource_deinit(pres); FREE_CL(res); } @@ -471,11 +477,12 @@ create_ici(struct zink_screen *screen, VkImageCreateInfo *ici, const struct pipe static struct zink_resource_object * resource_object_create(struct zink_screen *screen, const struct pipe_resource *templ, struct winsys_handle *whandle, bool *optimal_tiling, - const uint64_t *modifiers, int modifiers_count) + const uint64_t *modifiers, int modifiers_count, const void *loader_private) { struct zink_resource_object *obj = CALLOC_STRUCT(zink_resource_object); if (!obj) return NULL; + obj->last_dt_idx = obj->dt_idx = UINT32_MAX; //TODO: unionize VkMemoryRequirements reqs = {0}; VkMemoryPropertyFlags flags; @@ -509,12 +516,14 @@ resource_object_create(struct zink_screen *screen, const struct pipe_resource *t if (shared && screen->info.have_EXT_external_memory_dma_buf) export_types |= VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; - /* TODO: remove linear for wsi */ - bool scanout = templ->bind & PIPE_BIND_SCANOUT; - pipe_reference_init(&obj->reference, 1); util_dynarray_init(&obj->desc_set_refs.refs, NULL); - if (templ->target == PIPE_BUFFER) { + if (loader_private) { + obj->bo = CALLOC_STRUCT(zink_bo); + obj->transfer_dst = true; + util_queue_fence_init(&obj->present_fence); + return obj; + } else if (templ->target == PIPE_BUFFER) { VkBufferCreateInfo bci = create_bci(screen, templ, templ->bind); if (VKSCR(CreateBuffer)(screen->dev, &bci, NULL, &obj->buffer) != VK_SUCCESS) { @@ -588,10 +597,8 @@ resource_object_create(struct zink_screen *screen, const struct pipe_resource *t idfmlci.pDrmFormatModifiers = modifiers; ici.pNext = &idfmlci; } else if (ici.tiling == VK_IMAGE_TILING_OPTIMAL) { - // TODO: remove for wsi if (!external) ici.pNext = NULL; - scanout = false; shared = false; } } @@ -602,16 +609,6 @@ resource_object_create(struct zink_screen *screen, const struct pipe_resource *t if (ici.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT) obj->transfer_dst = true; - struct wsi_image_create_info image_wsi_info = { - VK_STRUCTURE_TYPE_WSI_IMAGE_CREATE_INFO_MESA, - NULL, - .scanout = scanout && ici.tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT, - }; - - if ((screen->needs_mesa_wsi || screen->needs_mesa_flush_wsi) && scanout) { - image_wsi_info.pNext = ici.pNext; - ici.pNext = &image_wsi_info; - } if (util_format_is_yuv(templ->format)) { VkFormatFeatureFlags feats = VK_FORMAT_FEATURE_FLAG_BITS_MAX_ENUM; switch (ici.tiling) { @@ -808,18 +805,6 @@ resource_object_create(struct zink_screen *screen, const struct pipe_resource *t } #endif - struct wsi_memory_allocate_info memory_wsi_info = { - VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA, - NULL, - }; - - if (screen->needs_mesa_wsi && scanout) { - memory_wsi_info.implicit_sync = true; - - memory_wsi_info.pNext = mai.pNext; - mai.pNext = &memory_wsi_info; - } - unsigned alignment = MAX2(reqs.alignment, 256); if (templ->usage == PIPE_USAGE_STAGING && obj->is_buffer) alignment = MAX2(alignment, screen->info.props.limits.minMemoryMapAlignment); @@ -899,7 +884,8 @@ resource_create(struct pipe_screen *pscreen, const struct pipe_resource *templ, struct winsys_handle *whandle, unsigned external_usage, - const uint64_t *modifiers, int modifiers_count) + const uint64_t *modifiers, int modifiers_count, + const void *loader_private) { struct zink_screen *screen = zink_screen(pscreen); struct zink_resource *res = CALLOC_STRUCT_CL(zink_resource); @@ -928,12 +914,7 @@ resource_create(struct pipe_screen *pscreen, templ2.flags &= ~PIPE_RESOURCE_FLAG_SPARSE; res->base.b.flags &= ~PIPE_RESOURCE_FLAG_SPARSE; } - unsigned scanout_flags = templ->bind & (PIPE_BIND_SCANOUT | PIPE_BIND_SHARED); - if (whandle && whandle->type == ZINK_EXTERNAL_MEMORY_HANDLE) - scanout_flags = 0; - else if (!(templ->bind & PIPE_BIND_LINEAR)) - templ2.bind &= ~scanout_flags; - res->obj = resource_object_create(screen, &templ2, whandle, &optimal_tiling, NULL, 0); + res->obj = resource_object_create(screen, &templ2, whandle, &optimal_tiling, modifiers, modifiers_count, loader_private); if (!res->obj) { free(res->modifiers); FREE_CL(res); @@ -969,24 +950,34 @@ resource_create(struct pipe_screen *pscreen, res->layout = res->dmabuf_acquire ? VK_IMAGE_LAYOUT_PREINITIALIZED : VK_IMAGE_LAYOUT_UNDEFINED; res->optimal_tiling = optimal_tiling; res->aspect = aspect_from_format(templ->format); - if (scanout_flags && optimal_tiling) { - // TODO: remove for wsi - templ2 = res->base.b; - templ2.bind = scanout_flags | PIPE_BIND_LINEAR; - res->scanout_obj = resource_object_create(screen, &templ2, whandle, &optimal_tiling, res->modifiers, res->modifiers_count); - assert(!optimal_tiling); - } } - if (screen->winsys && (templ->bind & PIPE_BIND_DISPLAY_TARGET)) { - struct sw_winsys *winsys = screen->winsys; - res->dt = winsys->displaytarget_create(screen->winsys, - res->base.b.bind, - res->base.b.format, - templ->width0, - templ->height0, - 64, NULL, - &res->dt_stride); + if (loader_private) { + if (templ->bind & PIPE_BIND_DISPLAY_TARGET) { + /* backbuffer */ + res->obj->dt = zink_kopper_displaytarget_create(screen, + res->base.b.bind, + res->base.b.format, + templ->width0, + templ->height0, + 64, loader_private, + &res->dt_stride); + assert(res->obj->dt); + } else { + /* frontbuffer */ + struct zink_resource *back = (void*)loader_private; + struct kopper_displaytarget *cdt = back->obj->dt; + cdt->refcount++; + assert(back->obj->dt); + res->obj->dt = back->obj->dt; + } + struct kopper_displaytarget *cdt = res->obj->dt; + if (zink_kopper_has_srgb(cdt)) + res->obj->vkflags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; + if (cdt->swapchain->scci.flags == VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR) + res->obj->vkflags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT_KHR; + res->obj->vkusage = cdt->swapchain->scci.imageUsage; + res->base.b.bind |= PIPE_BIND_DISPLAY_TARGET; } if (res->obj->is_buffer) { res->base.buffer_id_unique = util_idalloc_mt_alloc(&screen->buffer_ids); @@ -1003,14 +994,22 @@ static struct pipe_resource * zink_resource_create(struct pipe_screen *pscreen, const struct pipe_resource *templ) { - return resource_create(pscreen, templ, NULL, 0, NULL, 0); + return resource_create(pscreen, templ, NULL, 0, NULL, 0, NULL); } static struct pipe_resource * zink_resource_create_with_modifiers(struct pipe_screen *pscreen, const struct pipe_resource *templ, const uint64_t *modifiers, int modifiers_count) { - return resource_create(pscreen, templ, NULL, 0, modifiers, modifiers_count); + return resource_create(pscreen, templ, NULL, 0, modifiers, modifiers_count, NULL); +} + +static struct pipe_resource * +zink_resource_create_drawable(struct pipe_screen *pscreen, + const struct pipe_resource *templ, + const void *loader_private) +{ + return resource_create(pscreen, templ, NULL, 0, NULL, 0, loader_private); } static bool @@ -1025,8 +1024,7 @@ zink_resource_get_param(struct pipe_screen *pscreen, struct pipe_context *pctx, { struct zink_screen *screen = zink_screen(pscreen); struct zink_resource *res = zink_resource(pres); - //TODO: remove for wsi - struct zink_resource_object *obj = res->scanout_obj ? res->scanout_obj : res->obj; + struct zink_resource_object *obj = res->obj; struct winsys_handle whandle; VkImageAspectFlags aspect; if (res->modifiers) { @@ -1140,13 +1138,12 @@ zink_resource_get_handle(struct pipe_screen *pscreen, #ifdef ZINK_USE_DMABUF struct zink_resource *res = zink_resource(tex); struct zink_screen *screen = zink_screen(pscreen); - //TODO: remove for wsi - struct zink_resource_object *obj = res->scanout_obj ? res->scanout_obj : res->obj; + struct zink_resource_object *obj = res->obj; + assert(screen->drm_fd >= 0); VkMemoryGetFdInfoKHR fd_info = {0}; int fd; fd_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR; - //TODO: remove for wsi fd_info.memory = zink_bo_get_mem(obj->bo); if (whandle->type == WINSYS_HANDLE_TYPE_FD) fd_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; @@ -1203,7 +1200,7 @@ zink_resource_from_handle(struct pipe_screen *pscreen, modifier = whandle->modifier; modifier_count = 1; } - return resource_create(pscreen, &templ2, whandle, usage, &modifier, modifier_count); + return resource_create(pscreen, &templ2, whandle, usage, &modifier, modifier_count, NULL); #else return NULL; #endif @@ -1246,7 +1243,7 @@ zink_resource_from_memobj(struct pipe_screen *pscreen, { struct zink_memory_object *memobj = (struct zink_memory_object *)pmemobj; - return resource_create(pscreen, templ, &memobj->whandle, 0, NULL, 0); + return resource_create(pscreen, templ, &memobj->whandle, 0, NULL, 0, NULL); } static bool @@ -1272,7 +1269,7 @@ invalidate_buffer(struct zink_context *ctx, struct zink_resource *res) return false; struct zink_resource_object *old_obj = res->obj; - struct zink_resource_object *new_obj = resource_object_create(screen, &res->base.b, NULL, NULL, NULL, 0); + struct zink_resource_object *new_obj = resource_object_create(screen, &res->base.b, NULL, NULL, NULL, 0, NULL); if (!new_obj) { debug_printf("new backing resource alloc failed!"); return false; @@ -1820,11 +1817,12 @@ zink_resource_object_init_storage(struct zink_context *ctx, struct zink_resource if (res->obj->is_buffer) { unreachable("zink: all buffers should have this bit"); } else { + assert(!res->obj->dt); zink_fb_clears_apply_region(ctx, &res->base.b, (struct u_rect){0, res->base.b.width0, 0, res->base.b.height0}); zink_resource_image_barrier(ctx, res, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 0, 0); res->base.b.bind |= PIPE_BIND_SHADER_IMAGE; struct zink_resource_object *old_obj = res->obj; - struct zink_resource_object *new_obj = resource_object_create(screen, &res->base.b, NULL, &res->optimal_tiling, res->modifiers, res->modifiers_count); + struct zink_resource_object *new_obj = resource_object_create(screen, &res->base.b, NULL, &res->optimal_tiling, res->modifiers, res->modifiers_count, NULL); if (!new_obj) { debug_printf("new backing resource alloc failed!"); res->base.b.bind &= ~PIPE_BIND_SHADER_IMAGE; @@ -1948,6 +1946,7 @@ zink_screen_resource_init(struct pipe_screen *pscreen) struct zink_screen *screen = zink_screen(pscreen); pscreen->resource_create = zink_resource_create; pscreen->resource_create_with_modifiers = zink_resource_create_with_modifiers; + pscreen->resource_create_drawable = zink_resource_create_drawable; pscreen->resource_destroy = zink_resource_destroy; pscreen->transfer_helper = u_transfer_helper_create(&transfer_vtbl, true, true, false, false, !screen->have_D24_UNORM_S8_UINT); diff --git a/src/gallium/drivers/zink/zink_resource.h b/src/gallium/drivers/zink/zink_resource.h index 25a67c32bad..0321b4a1fb7 100644 --- a/src/gallium/drivers/zink/zink_resource.h +++ b/src/gallium/drivers/zink/zink_resource.h @@ -79,7 +79,22 @@ struct zink_resource_object { bool render_target; bool is_buffer; + /* TODO: this should be a union */ struct zink_bo *bo; + // struct { + void *dt; + uint32_t dt_idx; + uint32_t last_dt_idx; + VkSemaphore acquire; + VkSemaphore present; + bool acquired; + bool new_dt; + bool dt_has_data; + bool indefinite_acquire; + struct util_queue_fence present_fence; + // } + + VkDeviceSize offset, size, alignment; VkImageCreateFlags vkflags; VkImageUsageFlags vkusage; @@ -98,8 +113,6 @@ struct zink_resource { enum pipe_format internal_format:16; struct zink_resource_object *obj; - struct zink_resource_object *scanout_obj; //TODO: remove for wsi - bool scanout_obj_init; union { struct { struct util_range valid_buffer_range; @@ -141,7 +154,6 @@ struct zink_resource { }; bool dmabuf_acquire; - struct sw_displaytarget *dt; unsigned dt_stride; uint8_t modifiers_count; diff --git a/src/gallium/drivers/zink/zink_screen.c b/src/gallium/drivers/zink/zink_screen.c index b75e61bc675..1336ba3aecb 100644 --- a/src/gallium/drivers/zink/zink_screen.c +++ b/src/gallium/drivers/zink/zink_screen.c @@ -23,6 +23,7 @@ #include "zink_screen.h" +#include "zink_kopper.h" #include "zink_compiler.h" #include "zink_context.h" #include "zink_device_info.h" @@ -50,6 +51,8 @@ #include "util/u_cpu_detect.h" +#include "driver_trace/tr_context.h" + #include "frontend/sw_winsys.h" #if DETECT_OS_WINDOWS @@ -1204,6 +1207,10 @@ zink_destroy_screen(struct pipe_screen *pscreen) { struct zink_screen *screen = zink_screen(pscreen); + hash_table_foreach(&screen->dts, entry) + zink_kopper_deinit_displaytarget(screen, entry->data); + simple_mtx_destroy(&screen->dt_lock); + if (VK_NULL_HANDLE != screen->debugUtilsCallbackHandle) { VKSCR(DestroyDebugUtilsMessengerEXT)(screen->instance, screen->debugUtilsCallbackHandle, NULL); } @@ -1341,36 +1348,43 @@ init_queue(struct zink_screen *screen) static void zink_flush_frontbuffer(struct pipe_screen *pscreen, - struct pipe_context *pcontext, + struct pipe_context *pctx, struct pipe_resource *pres, unsigned level, unsigned layer, void *winsys_drawable_handle, struct pipe_box *sub_box) { struct zink_screen *screen = zink_screen(pscreen); - struct sw_winsys *winsys = screen->winsys; struct zink_resource *res = zink_resource(pres); + struct zink_context *ctx = zink_context(pctx); - if (!winsys) - return; - void *map = winsys->displaytarget_map(winsys, res->dt, 0); + /* if the surface has never been acquired, there's nothing to present, + * so this is a no-op */ + if (!res->obj->acquired && res->obj->last_dt_idx == UINT32_MAX) + return; - if (map) { - struct pipe_transfer *transfer = NULL; - void *res_map = pipe_texture_map(pcontext, pres, level, layer, PIPE_MAP_READ, 0, 0, - u_minify(pres->width0, level), - u_minify(pres->height0, level), - &transfer); - if (res_map) { - util_copy_rect((ubyte*)map, pres->format, res->dt_stride, 0, 0, - transfer->box.width, transfer->box.height, - (const ubyte*)res_map, transfer->stride, 0, 0); - pipe_texture_unmap(pcontext, transfer); + /* need to get the actual zink_context, not the threaded context */ + if (screen->threaded) + pctx = threaded_context_unwrap_sync(pctx); + pctx = trace_get_possibly_threaded_context(pctx); + ctx = zink_context(pctx); + if (ctx->batch.swapchain) { + pctx->flush(pctx, NULL, 0); + if (ctx->last_fence && screen->threaded) { + struct zink_batch_state *bs = zink_batch_state(ctx->last_fence); + util_queue_fence_wait(&bs->flush_completed); } - winsys->displaytarget_unmap(winsys, res->dt); } - winsys->displaytarget_display(winsys, res->dt, winsys_drawable_handle, sub_box); + if (res->obj->acquired) + zink_kopper_present_queue(screen, res); + else { + assert(res->obj->last_dt_idx != UINT32_MAX); + if (!zink_kopper_last_present_eq(res->obj->dt, res->obj->last_dt_idx)) { + zink_kopper_acquire_readback(ctx, res); + zink_kopper_present_readback(ctx, res); + } + } } bool @@ -1619,23 +1633,6 @@ zink_internal_setup_moltenvk(struct zink_screen *screen) return true; } -static void -check_device_needs_mesa_wsi(struct zink_screen *screen) -{ - if ( - /* Raspberry Pi 4 V3DV driver */ - (screen->info.props.vendorID == 0x14E4 && - screen->info.props.deviceID == 42) || - /* RADV */ - screen->info.driver_props.driverID == VK_DRIVER_ID_MESA_RADV_KHR - ) { - screen->needs_mesa_wsi = true; - } else if (screen->info.driver_props.driverID == VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA_KHR || - screen->info.driver_props.driverID == VK_DRIVER_ID_MESA_VENUS) - screen->needs_mesa_flush_wsi = true; - -} - static void populate_format_props(struct zink_screen *screen) { @@ -2150,11 +2147,6 @@ zink_internal_create_screen(const struct pipe_screen_config *config) if (screen->threaded) util_queue_init(&screen->flush_queue, "zfq", 8, 1, UTIL_QUEUE_INIT_RESIZE_IF_FULL, screen); - /* Some Vulkan implementations have special requirements for WSI - * allocations. - */ - check_device_needs_mesa_wsi(screen); - zink_internal_setup_moltenvk(screen); screen->dev = zink_create_logical_device(screen); @@ -2293,6 +2285,8 @@ zink_internal_create_screen(const struct pipe_screen_config *config) _mesa_hash_table_init(&screen->framebuffer_cache, screen, hash_framebuffer_state, equals_framebuffer_state); } + simple_mtx_init(&screen->dt_lock, mtx_plain); + zink_screen_init_descriptor_funcs(screen, false); util_idalloc_mt_init_tc(&screen->buffer_ids); @@ -2312,12 +2306,12 @@ fail: } struct pipe_screen * -zink_create_screen(struct sw_winsys *winsys) +zink_create_screen(struct sw_winsys *winsys, const struct pipe_screen_config *config) { - struct zink_screen *ret = zink_internal_create_screen(NULL); + struct zink_screen *ret = zink_internal_create_screen(config); if (ret) { - ret->winsys = winsys; ret->drm_fd = -1; + ret->sw_winsys = winsys; } return &ret->base; diff --git a/src/gallium/drivers/zink/zink_screen.h b/src/gallium/drivers/zink/zink_screen.h index 40fb5b93f72..8833f47d542 100644 --- a/src/gallium/drivers/zink/zink_screen.h +++ b/src/gallium/drivers/zink/zink_screen.h @@ -40,6 +40,9 @@ #include "util/u_vertex_state_cache.h" #include "pipebuffer/pb_cache.h" #include "pipebuffer/pb_slab.h" +#include "frontend/sw_winsys.h" +#include "kopper_interface.h" + #include extern uint32_t zink_debug; @@ -87,9 +90,14 @@ struct zink_screen { unsigned buffer_rebind_counter; + struct hash_table dts; + simple_mtx_t dt_lock; + bool device_lost; - struct sw_winsys *winsys; int drm_fd; + struct sw_winsys winsys; + struct sw_winsys *sw_winsys; // wrapped + __DRIkopperLoaderExtension *loader; struct hash_table framebuffer_cache; simple_mtx_t framebuffer_mtx; @@ -145,9 +153,6 @@ struct zink_screen { uint32_t cur_custom_border_color_samplers; - bool needs_mesa_wsi; - bool needs_mesa_flush_wsi; - struct vk_dispatch_table vk; bool (*descriptor_program_init)(struct zink_context *ctx, struct zink_program *pg); @@ -184,7 +189,6 @@ struct zink_screen { } driver_workarounds; }; - /* update last_finished to account for batch_id wrapping */ static inline void zink_screen_update_last_finished(struct zink_screen *screen, uint32_t batch_id) diff --git a/src/gallium/drivers/zink/zink_surface.c b/src/gallium/drivers/zink/zink_surface.c index fdcd2f8fb61..08c5b38aeab 100644 --- a/src/gallium/drivers/zink/zink_surface.c +++ b/src/gallium/drivers/zink/zink_surface.c @@ -26,6 +26,7 @@ #include "zink_resource.h" #include "zink_screen.h" #include "zink_surface.h" +#include "zink_kopper.h" #include "util/format/u_format.h" #include "util/u_inlines.h" @@ -114,7 +115,12 @@ init_surface_info(struct zink_surface *surface, struct zink_resource *res, VkIma surface->info.width = surface->base.width; surface->info.height = surface->base.height; surface->info.layerCount = ivci->subresourceRange.layerCount; - surface->info.format = ivci->format; + surface->info.format[0] = ivci->format; + if (res->obj->dt) { + struct kopper_displaytarget *cdt = res->obj->dt; + if (zink_kopper_has_srgb(cdt)) + surface->info.format[1] = ivci->format == cdt->formats[0] ? cdt->formats[1] : cdt->formats[0]; + } surface->info_hash = _mesa_hash_data(&surface->info, sizeof(surface->info)); } @@ -249,7 +255,16 @@ zink_create_surface(struct pipe_context *pctx, VkImageViewCreateInfo ivci = create_ivci(zink_screen(pctx->screen), res, templ, pres->target == PIPE_TEXTURE_3D ? target_2d[is_array] : pres->target); - struct pipe_surface *psurf = zink_get_surface(zink_context(pctx), pres, templ, &ivci); + struct pipe_surface *psurf = NULL; + if (res->obj->dt) { + /* don't cache swapchain surfaces. that's weird. */ + struct zink_surface *surface = do_create_surface(pctx, pres, templ, &ivci, 0, false); + if (surface) { + surface->is_swapchain = true; + psurf = &surface->base; + } + } else + psurf = zink_get_surface(zink_context(pctx), pres, templ, &ivci); if (!psurf) return NULL; @@ -308,7 +323,7 @@ zink_destroy_surface(struct zink_screen *screen, struct pipe_surface *psurface) { struct zink_surface *surface = zink_surface(psurface); struct zink_resource *res = zink_resource(psurface->texture); - if (!psurface->nr_samples) { + if (!psurface->nr_samples && !surface->is_swapchain) { simple_mtx_lock(&res->surface_mtx); if (psurface->reference.count) { /* got a cache hit during deletion */ @@ -325,10 +340,17 @@ zink_destroy_surface(struct zink_screen *screen, struct pipe_surface *psurface) surface_clear_fb_refs(screen, psurface); zink_descriptor_set_refs_clear(&surface->desc_set_refs, surface); util_dynarray_fini(&surface->framebuffer_refs); - pipe_resource_reference(&psurface->texture, NULL); if (surface->simage_view) VKSCR(DestroyImageView)(screen->dev, surface->simage_view, NULL); - VKSCR(DestroyImageView)(screen->dev, surface->image_view, NULL); + if (surface->is_swapchain) { + for (unsigned i = 0; i < surface->old_swapchain_size; i++) + VKSCR(DestroyImageView)(screen->dev, surface->old_swapchain[i], NULL); + for (unsigned i = 0; i < surface->swapchain_size; i++) + VKSCR(DestroyImageView)(screen->dev, surface->swapchain[i], NULL); + free(surface->swapchain); + } else + VKSCR(DestroyImageView)(screen->dev, surface->image_view, NULL); + pipe_resource_reference(&psurface->texture, NULL); FREE(surface); } @@ -350,6 +372,7 @@ zink_rebind_surface(struct zink_context *ctx, struct pipe_surface **psurface) struct zink_screen *screen = zink_screen(ctx->base.screen); if (surface->simage_view) return false; + assert(!res->obj->dt); VkImageViewCreateInfo ivci = create_ivci(screen, zink_resource((*psurface)->texture), (*psurface), surface->base.texture->target); uint32_t hash = hash_ivci(&ivci); @@ -425,3 +448,29 @@ zink_context_surface_init(struct pipe_context *context) context->create_surface = zink_create_surface; context->surface_destroy = zink_surface_destroy; } + +void +zink_surface_swapchain_update(struct zink_context *ctx, struct zink_surface *surface) +{ + struct zink_screen *screen = zink_screen(ctx->base.screen); + struct zink_resource *res = zink_resource(surface->base.texture); + struct kopper_displaytarget *cdt = res->obj->dt; + if (res->obj->dt != surface->dt) { + /* new swapchain: clear out previous old_swapchain and move current swapchain there */ + for (unsigned i = 0; i < surface->old_swapchain_size; i++) + util_dynarray_append(&ctx->batch.state->dead_swapchains, VkImageView, surface->old_swapchain[i]); + free(surface->old_swapchain); + surface->old_swapchain = surface->swapchain; + surface->old_swapchain_size = surface->swapchain_size; + surface->swapchain_size = cdt->swapchain->num_images; + surface->swapchain = calloc(surface->swapchain_size, sizeof(VkImageView)); + init_surface_info(surface, res, &surface->ivci); + } + if (!surface->swapchain[res->obj->dt_idx]) { + assert(res->obj->image && cdt->swapchain->images[res->obj->dt_idx] == res->obj->image); + surface->ivci.image = res->obj->image; + assert(surface->ivci.image); + VKSCR(CreateImageView)(screen->dev, &surface->ivci, NULL, &surface->swapchain[res->obj->dt_idx]); + } + surface->image_view = surface->swapchain[res->obj->dt_idx]; +} diff --git a/src/gallium/drivers/zink/zink_surface.h b/src/gallium/drivers/zink/zink_surface.h index 0c78008f7e6..b7146a1816a 100644 --- a/src/gallium/drivers/zink/zink_surface.h +++ b/src/gallium/drivers/zink/zink_surface.h @@ -36,7 +36,7 @@ struct zink_surface_info { uint32_t width; uint32_t height; uint32_t layerCount; - VkFormat format; + VkFormat format[2]; }; struct zink_surface { @@ -44,7 +44,13 @@ struct zink_surface { VkImageViewCreateInfo ivci; struct zink_surface_info info; //TODO: union with fb refs uint32_t info_hash; + bool is_swapchain; VkImageView image_view; + void *dt; + VkImageView *swapchain; + unsigned swapchain_size; + VkImageView *old_swapchain; + unsigned old_swapchain_size; VkImageView simage_view;//old iview after storage replacement/rebind void *obj; //backing resource object uint32_t hash; @@ -141,4 +147,7 @@ zink_rebind_ctx_surface(struct zink_context *ctx, struct pipe_surface **psurface struct pipe_surface * zink_surface_create_null(struct zink_context *ctx, enum pipe_texture_target target, unsigned width, unsigned height, unsigned samples); + +void +zink_surface_swapchain_update(struct zink_context *ctx, struct zink_surface *surface); #endif diff --git a/src/gallium/frontends/dri/kopper.c b/src/gallium/frontends/dri/kopper.c index 121e6f1c75a..e4d4e0661ea 100644 --- a/src/gallium/frontends/dri/kopper.c +++ b/src/gallium/frontends/dri/kopper.c @@ -346,11 +346,9 @@ kopper_update_drawable_info(struct dri_drawable *drawable) drawable->textures[ST_ATTACHMENT_BACK_LEFT] : drawable->textures[ST_ATTACHMENT_FRONT_LEFT]; -#if 0 if (is_window && ptex && kscreen->base.fd == -1) zink_kopper_update(screen, ptex, &dPriv->w, &dPriv->h); else -#endif get_drawable_info(dPriv, &x, &y, &dPriv->w, &dPriv->h); } diff --git a/src/gallium/targets/wgl/wgl.c b/src/gallium/targets/wgl/wgl.c index 6d976c36654..d2e0448a161 100644 --- a/src/gallium/targets/wgl/wgl.c +++ b/src/gallium/targets/wgl/wgl.c @@ -97,7 +97,7 @@ wgl_screen_create_by_name(HDC hDC, const char* driver, struct sw_winsys *winsys) #endif #ifdef GALLIUM_ZINK if (strcmp(driver, "zink") == 0) { - screen = zink_create_screen(winsys); + screen = zink_create_screen(winsys, NULL); if (screen) use_zink = TRUE; }