diff --git a/src/gallium/auxiliary/util/u_threaded_context.c b/src/gallium/auxiliary/util/u_threaded_context.c index e32bfc98c56..782c65bc17e 100644 --- a/src/gallium/auxiliary/util/u_threaded_context.c +++ b/src/gallium/auxiliary/util/u_threaded_context.c @@ -232,17 +232,21 @@ tc_batch_increment_renderpass_info(struct threaded_context *tc, unsigned batch_i /* copy the previous data in its entirety: this is still the same renderpass */ if (tc->renderpass_info_recording) { tc_info[batch->renderpass_info_idx].info.data = tc->renderpass_info_recording->data; + tc_info[batch->renderpass_info_idx].info.resolve = tc->renderpass_info_recording->resolve; + tc->renderpass_info_recording->resolve = NULL; tc_batch_rp_info(tc->renderpass_info_recording)->next = &tc_info[batch->renderpass_info_idx]; tc_info[batch->renderpass_info_idx].prev = tc_batch_rp_info(tc->renderpass_info_recording); /* guard against deadlock scenario */ assert(&tc_batch_rp_info(tc->renderpass_info_recording)->next->info != tc->renderpass_info_recording); } else { tc_info[batch->renderpass_info_idx].info.data = 0; + pipe_resource_reference(&tc_info[batch->renderpass_info_idx].info.resolve, NULL); tc_info[batch->renderpass_info_idx].prev = NULL; } } else { /* selectively copy: only the CSO metadata is copied, and a new framebuffer state will be added later */ tc_info[batch->renderpass_info_idx].info.data = 0; + pipe_resource_reference(&tc_info[batch->renderpass_info_idx].info.resolve, NULL); if (tc->renderpass_info_recording) { tc_info[batch->renderpass_info_idx].info.data16[2] = tc->renderpass_info_recording->data16[2]; tc_batch_rp_info(tc->renderpass_info_recording)->next = NULL; @@ -1477,6 +1481,9 @@ tc_set_framebuffer_state(struct pipe_context *_pipe, tc_set_resource_batch_usage_persistent(tc, tc->fb_resources[i], true); } tc->nr_cbufs = nr_cbufs; + tc->fb_layers = util_framebuffer_get_num_layers(fb); + tc->fb_width = fb->width; + tc->fb_height = fb->height; if (tc->options.parse_renderpass_info) { /* store existing zsbuf data for possible persistence */ uint8_t zsbuf = tc->renderpass_info_recording->has_draw ? @@ -1500,7 +1507,9 @@ tc_set_framebuffer_state(struct pipe_context *_pipe, * just increment the index and keep using the existing info for recording */ tc->batch_slots[tc->next].renderpass_info_idx = 0; + tc->renderpass_info_recording->has_resolve = false; } + assert(!tc->renderpass_info_recording->resolve); tc->seen_fb_state = true; } /* ref for cmd */ @@ -4498,7 +4507,13 @@ tc_call_blit(struct pipe_context *pipe, void *call) return call_size(tc_blit_call); } -static void +static uint16_t ALWAYS_INLINE +tc_call_resolve(struct pipe_context *pipe, void *call) +{ + return tc_call_blit(pipe, call); +} + +static struct tc_blit_call * tc_blit_enqueue(struct threaded_context *tc, const struct pipe_blit_info *info) { struct tc_blit_call *blit = tc_add_call(tc, TC_CALL_blit, tc_blit_call); @@ -4508,6 +4523,7 @@ tc_blit_enqueue(struct threaded_context *tc, const struct pipe_blit_info *info) tc_set_resource_batch_usage(tc, info->src.resource); tc_set_resource_reference(&blit->info.src.resource, info->src.resource); memcpy(&blit->info, info, sizeof(*info)); + return blit; } static void @@ -4518,29 +4534,62 @@ tc_blit(struct pipe_context *_pipe, const struct pipe_blit_info *info) /* filter out untracked non-resolves */ if (!tc->options.parse_renderpass_info || info->src.resource->nr_samples <= 1 || - info->dst.resource->nr_samples > 1) { + info->dst.resource->nr_samples > 1 || + info->scissor_enable || + info->swizzle_enable || + info->alpha_blend || + info->src.resource->format != info->src.format || + info->dst.resource->format != info->dst.format || + info->src.format != info->dst.format || + info->src.box.width < 0 || + info->src.box.height < 0 || + info->src.box.depth < 0 || + info->dst.box.width < 0 || + info->dst.box.height < 0 || + info->dst.box.depth < 0 || + info->src.box.x != info->dst.box.x || + info->src.box.y != info->dst.box.y || + info->src.box.z != info->dst.box.z || + info->src.box.width != info->dst.box.width || + info->src.box.height != info->dst.box.height || + info->src.box.depth != info->dst.box.depth || + info->src.box.width != tc->fb_width || + info->src.box.height != tc->fb_height || + tc->renderpass_info_recording->ended || + (info->dst.resource->array_size && info->dst.resource->array_size != tc->fb_layers) || + (!tc->renderpass_info_recording->has_draw && !tc->renderpass_info_recording->cbuf_clear && !tc->renderpass_info_recording->zsbuf_clear)) { if (tc->options.parse_renderpass_info && tc->in_renderpass) tc_check_fb_access(tc, info->src.resource, info->dst.resource); tc_blit_enqueue(tc, info); return; } + struct pipe_resource *src = tc->nr_cbufs ? tc->fb_resources[0] : tc->fb_resources[PIPE_MAX_COLOR_BUFS]; if (tc->fb_resolve == info->dst.resource) { +#if TC_DEBUG >= 3 + tc_printf("WSI RESOLVE MERGE"); +#endif /* optimize out this blit entirely */ tc->renderpass_info_recording->has_resolve = true; tc->renderpass_info_recording->ended = true; tc_signal_renderpass_info_ready(tc); - return; - } - for (unsigned i = 0; i < PIPE_MAX_COLOR_BUFS; i++) { - if (tc->fb_resources[i] == info->src.resource) { - tc->renderpass_info_recording->has_resolve = true; - break; - } - } - if (tc->options.parse_renderpass_info && tc->in_renderpass) + } else if (src == info->src.resource && + (!tc->renderpass_info_recording->has_resolve || + tc->renderpass_info_recording->resolve == info->dst.resource)) { +#if TC_DEBUG >= 3 + tc_printf("RESOLVE MERGE"); +#endif + /* can only optimize out the first resolve */ + tc->renderpass_info_recording->has_resolve = true; + pipe_resource_reference(&tc->renderpass_info_recording->resolve, info->dst.resource); + tc_set_resource_batch_usage(tc, info->dst.resource); + tc->renderpass_info_recording->ended = true; + tc_signal_renderpass_info_ready(tc); + } else if (tc->in_renderpass) { tc_check_fb_access(tc, info->src.resource, info->dst.resource); - tc_blit_enqueue(tc, info); + } + struct tc_blit_call *blit = tc_blit_enqueue(tc, info); + blit->base.call_id = TC_CALL_resolve; } struct tc_generate_mipmap { diff --git a/src/gallium/auxiliary/util/u_threaded_context.h b/src/gallium/auxiliary/util/u_threaded_context.h index fae4ba30bb3..a5fe19b93f9 100644 --- a/src/gallium/auxiliary/util/u_threaded_context.h +++ b/src/gallium/auxiliary/util/u_threaded_context.h @@ -440,7 +440,7 @@ struct tc_renderpass_info { bool zsbuf_invalidate : 1; /* whether a draw occurs */ bool has_draw : 1; - /* whether a framebuffer resolve occurs on cbuf[0] */ + /* whether a framebuffer resolve occurs on cbuf[0] or zsbuf */ bool has_resolve : 1; /* whether queries are ended during this renderpass */ bool has_query_ends : 1; @@ -468,6 +468,8 @@ struct tc_renderpass_info { /* zsbuf fb info is in data8[3] & BITFIELD_MASK(4) */ uint8_t data8[8]; }; + /* only valid if has_resolve is true and the resolve member of pipe_framebuffer_state is NULL */ + struct pipe_resource *resolve; }; static inline bool @@ -640,6 +642,9 @@ struct threaded_context { unsigned max_images; unsigned max_samplers; unsigned nr_cbufs; + unsigned fb_layers; + uint16_t fb_width; + uint16_t fb_height; unsigned last, next, next_buf_list; diff --git a/src/gallium/auxiliary/util/u_threaded_context_calls.h b/src/gallium/auxiliary/util/u_threaded_context_calls.h index e606b403dd1..317f16c85d0 100644 --- a/src/gallium/auxiliary/util/u_threaded_context_calls.h +++ b/src/gallium/auxiliary/util/u_threaded_context_calls.h @@ -75,6 +75,7 @@ CALL(draw_vstate_single) CALL(draw_vstate_multi) CALL(launch_grid) CALL(blit) +CALL(resolve) CALL(generate_mipmap) CALL(invalidate_resource) CALL(clear_render_target) diff --git a/src/gallium/drivers/zink/zink_blit.c b/src/gallium/drivers/zink/zink_blit.c index 9b49a5c9bce..e00ea311a74 100644 --- a/src/gallium/drivers/zink/zink_blit.c +++ b/src/gallium/drivers/zink/zink_blit.c @@ -330,6 +330,18 @@ zink_blit(struct pipe_context *pctx, struct zink_resource *use_src = src; struct zink_resource *dst = zink_resource(info->dst.resource); bool needs_present_readback = false; + + if (ctx->awaiting_resolve && ctx->in_rp && ctx->dynamic_fb.tc_info.has_resolve) { + struct pipe_resource *resolve = ctx->fb_state.resolve; + if (!resolve) + resolve = ctx->dynamic_fb.tc_info.resolve; + if (resolve == info->dst.resource) { + zink_batch_no_rp_safe(ctx); + ctx->awaiting_resolve = false; + return; + } + } + if (zink_is_swapchain(dst)) { if (!zink_kopper_acquire(ctx, dst, UINT64_MAX)) return; diff --git a/src/gallium/drivers/zink/zink_context.c b/src/gallium/drivers/zink/zink_context.c index 611c362a72f..ffdf5109792 100644 --- a/src/gallium/drivers/zink/zink_context.c +++ b/src/gallium/drivers/zink/zink_context.c @@ -72,6 +72,8 @@ update_tc_info(struct zink_context *ctx) const struct tc_renderpass_info *info = threaded_context_get_renderpass_info(ctx->tc); ctx->rp_changed |= ctx->dynamic_fb.tc_info.data != info->data; ctx->dynamic_fb.tc_info.data = info->data; + ctx->dynamic_fb.tc_info.resolve = info->resolve; + ctx->awaiting_resolve = ctx->dynamic_fb.tc_info.has_resolve; } else { struct tc_renderpass_info info = ctx->dynamic_fb.tc_info; bool zsbuf_used = !ctx->zsbuf_unused; @@ -3204,22 +3206,37 @@ begin_rendering(struct zink_context *ctx, bool check_msaa_expand) ctx->dynamic_fb.attachments[PIPE_MAX_COLOR_BUFS + 1].resolveMode = 0; } } - if (ctx->fb_state.resolve && use_tc_info && ctx->dynamic_fb.tc_info.has_resolve) { + if (use_tc_info && ctx->dynamic_fb.tc_info.has_resolve) { struct zink_resource *res = zink_resource(ctx->fb_state.resolve); - zink_surface_resolve_init(screen, res, ctx->fb_state.resolve->format); + if (!res) + res = zink_resource(ctx->dynamic_fb.tc_info.resolve); + assert(res); + zink_batch_resource_usage_set(ctx->bs, res, true, false); + bool is_depth = util_format_is_depth_or_stencil(res->base.b.format); + enum pipe_format format = res->base.b.format; + if (!ctx->fb_state.resolve) + format = is_depth ? ctx->fb_state.zsbuf.format : ctx->fb_state.cbufs[0].format; + zink_surface_resolve_init(screen, res, format); struct zink_surface *surf = zink_surface(res->surface); if (zink_is_swapchain(res)) { if (!zink_kopper_acquire(ctx, res, UINT64_MAX)) return 0; zink_surface_swapchain_update(ctx, surf); } - zink_batch_resource_usage_set(ctx->bs, res, true, false); - VkImageLayout layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + VkImageLayout layout = is_depth ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + if (screen->driver_workarounds.general_layout) + layout = VK_IMAGE_LAYOUT_GENERAL; + unsigned idx = util_format_is_depth_or_stencil(res->base.b.format) ? PIPE_MAX_COLOR_BUFS : 0; screen->image_barrier(ctx, res, layout, 0, 0); res->obj->unordered_read = res->obj->unordered_write = false; - ctx->dynamic_fb.attachments[0].resolveMode = VK_RESOLVE_MODE_AVERAGE_BIT; - ctx->dynamic_fb.attachments[0].resolveImageLayout = zink_resource(surf->base.texture)->layout; - ctx->dynamic_fb.attachments[0].resolveImageView = surf->image_view; + ctx->dynamic_fb.attachments[idx].resolveMode = VK_RESOLVE_MODE_AVERAGE_BIT; + ctx->dynamic_fb.attachments[idx].resolveImageLayout = zink_resource(surf->base.texture)->layout; + ctx->dynamic_fb.attachments[idx].resolveImageView = surf->image_view; + if (idx == PIPE_MAX_COLOR_BUFS) { + ctx->dynamic_fb.attachments[idx + 1].resolveMode = VK_RESOLVE_MODE_AVERAGE_BIT; + ctx->dynamic_fb.attachments[idx + 1].resolveImageLayout = zink_resource(surf->base.texture)->layout; + ctx->dynamic_fb.attachments[idx + 1].resolveImageView = surf->image_view; + } } ctx->zsbuf_unused = !zsbuf_used; assert(ctx->fb_state.width >= ctx->dynamic_fb.info.renderArea.extent.width); diff --git a/src/gallium/drivers/zink/zink_types.h b/src/gallium/drivers/zink/zink_types.h index c8defb20dc2..60b8c2b49d9 100644 --- a/src/gallium/drivers/zink/zink_types.h +++ b/src/gallium/drivers/zink/zink_types.h @@ -1768,6 +1768,7 @@ struct zink_context { struct set rendering_state_cache[6]; //[util_logbase2_ceil(msrtss samplecount)] struct zink_resource *swapchain; VkExtent2D swapchain_size; + bool awaiting_resolve; //from tc info bool in_rp; //renderpass is currently active bool rp_changed; //force renderpass restart bool rp_layout_changed; //renderpass changed, maybe restart