diff --git a/src/gallium/drivers/zink/zink_blit.c b/src/gallium/drivers/zink/zink_blit.c index bef9765220e..6b1f7234ba5 100644 --- a/src/gallium/drivers/zink/zink_blit.c +++ b/src/gallium/drivers/zink/zink_blit.c @@ -36,6 +36,9 @@ blit_resolve(struct zink_context *ctx, const struct pipe_blit_info *info) if (info->dst.resource->target == PIPE_BUFFER) util_range_add(info->dst.resource, &dst->valid_buffer_range, info->dst.box.x, info->dst.box.x + info->dst.box.width); + + zink_fb_clears_apply(ctx, info->dst.resource); + zink_fb_clears_apply(ctx, info->src.resource); struct zink_batch *batch = zink_batch_no_rp(ctx); zink_batch_reference_resource_rw(batch, src, false); @@ -116,6 +119,8 @@ blit_native(struct zink_context *ctx, const struct pipe_blit_info *info) dst->format != zink_get_format(screen, info->dst.format)) return false; + zink_fb_clears_apply(ctx, info->dst.resource); + zink_fb_clears_apply(ctx, info->src.resource); struct zink_batch *batch = zink_batch_no_rp(ctx); zink_batch_reference_resource_rw(batch, src, false); zink_batch_reference_resource_rw(batch, dst, true); diff --git a/src/gallium/drivers/zink/zink_clear.c b/src/gallium/drivers/zink/zink_clear.c index 597daa9b6d2..0638b569ff8 100644 --- a/src/gallium/drivers/zink/zink_clear.c +++ b/src/gallium/drivers/zink/zink_clear.c @@ -26,6 +26,7 @@ #include "zink_screen.h" #include "util/u_blitter.h" +#include "util/u_dynarray.h" #include "util/format/u_format.h" #include "util/format_srgb.h" #include "util/u_framebuffer.h" @@ -36,6 +37,8 @@ static inline bool check_3d_layers(struct pipe_surface *psurf) { + if (psurf->texture->target != PIPE_TEXTURE_3D) + return true; /* SPEC PROBLEM: * though the vk spec doesn't seem to explicitly address this, currently drivers * are claiming that all 3D images have a single "3D" layer regardless of layercount, @@ -49,6 +52,12 @@ check_3d_layers(struct pipe_surface *psurf) return true; } +static inline bool +scissor_states_equal(const struct pipe_scissor_state *a, const struct pipe_scissor_state *b) +{ + return a->minx == b->minx && a->miny == b->miny && a->maxx == b->maxx && a->maxy == b->maxy; +} + static void clear_in_rp(struct pipe_context *pctx, unsigned buffers, @@ -58,8 +67,6 @@ clear_in_rp(struct pipe_context *pctx, { struct zink_context *ctx = zink_context(pctx); struct pipe_framebuffer_state *fb = &ctx->fb_state; - struct zink_resource *resources[PIPE_MAX_COLOR_BUFS + 1] = {}; - int res_count = 0; VkClearAttachment attachments[1 + PIPE_MAX_COLOR_BUFS]; int num_attachments = 0; @@ -79,9 +86,6 @@ clear_in_rp(struct pipe_context *pctx, attachments[num_attachments].colorAttachment = i; attachments[num_attachments].clearValue.color = color; ++num_attachments; - struct zink_resource *res = (struct zink_resource*)fb->cbufs[i]->texture; - zink_resource_image_barrier(ctx, NULL, res, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 0, 0); - resources[res_count++] = res; } } @@ -96,9 +100,6 @@ clear_in_rp(struct pipe_context *pctx, attachments[num_attachments].clearValue.depthStencil.depth = depth; attachments[num_attachments].clearValue.depthStencil.stencil = stencil; ++num_attachments; - struct zink_resource *res = (struct zink_resource*)fb->zsbuf->texture; - zink_resource_image_barrier(ctx, NULL, res, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 0, 0); - resources[res_count++] = res; } VkClearRect cr = {}; @@ -114,8 +115,6 @@ clear_in_rp(struct pipe_context *pctx, cr.baseArrayLayer = 0; cr.layerCount = util_framebuffer_get_num_layers(fb); struct zink_batch *batch = zink_batch_rp(ctx); - for (int i = 0; i < res_count; i++) - zink_batch_reference_resource_rw(batch, resources[i], true); vkCmdClearAttachments(batch->cmdbuf, num_attachments, attachments, 1, &cr); } @@ -168,11 +167,6 @@ clear_needs_rp(unsigned width, unsigned height, struct u_rect *region) { struct u_rect intersect = {0, width, 0, height}; - /* FIXME: this is very inefficient; if no renderpass has been started yet, - * we should record the clear if it's full-screen, and apply it as we - * start the render-pass. Otherwise we can do a partial out-of-renderpass - * clear. - */ if (!u_rect_test_intersection(region, &intersect)) /* is this even a thing? */ return true; @@ -185,6 +179,25 @@ clear_needs_rp(unsigned width, unsigned height, struct u_rect *region) return false; } +static struct zink_framebuffer_clear_data * +get_clear_data(struct zink_context *ctx, struct zink_framebuffer_clear *fb_clear, const struct pipe_scissor_state *scissor_state) +{ + struct zink_framebuffer_clear_data *clear = NULL; + unsigned num_clears = zink_fb_clear_count(fb_clear); + if (num_clears) { + struct zink_framebuffer_clear_data *last_clear = zink_fb_clear_element(fb_clear, num_clears - 1); + /* if we're completely overwriting the previous clear, merge this into the previous clear */ + if (!scissor_state || (last_clear->has_scissor && scissor_states_equal(&last_clear->scissor, scissor_state))) + clear = last_clear; + } + if (!clear) { + struct zink_framebuffer_clear_data cd = {}; + util_dynarray_append(&fb_clear->clears, struct zink_framebuffer_clear_data, cd); + clear = zink_fb_clear_element(fb_clear, zink_fb_clear_count(fb_clear) - 1); + } + return clear; +} + void zink_clear(struct pipe_context *pctx, unsigned buffers, @@ -203,7 +216,7 @@ zink_clear(struct pipe_context *pctx, } - if (needs_rp || batch->in_rp || ctx->render_condition_active) { + if (batch->in_rp || ctx->render_condition_active) { clear_in_rp(pctx, buffers, scissor_state, pcolor, depth, stencil); return; } @@ -212,45 +225,129 @@ zink_clear(struct pipe_context *pctx, for (unsigned i = 0; i < fb->nr_cbufs; i++) { if ((buffers & (PIPE_CLEAR_COLOR0 << i)) && fb->cbufs[i]) { struct pipe_surface *psurf = fb->cbufs[i]; + struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[i]; + struct zink_framebuffer_clear_data *clear = get_clear_data(ctx, fb_clear, needs_rp ? scissor_state : NULL); - if (psurf->texture->target == PIPE_TEXTURE_3D && !check_3d_layers(psurf)) { - clear_in_rp(pctx, buffers, scissor_state, pcolor, depth, stencil); - return; - } - struct zink_resource *res = zink_resource(psurf->texture); - union pipe_color_union color = *pcolor; - if (psurf->format != res->base.format && - !util_format_is_srgb(psurf->format) && util_format_is_srgb(res->base.format)) { - /* if SRGB mode is disabled for the fb with a backing srgb image then we have to - * convert this to srgb color - */ - color.f[0] = util_format_srgb_to_linear_float(pcolor->f[0]); - color.f[1] = util_format_srgb_to_linear_float(pcolor->f[1]); - color.f[2] = util_format_srgb_to_linear_float(pcolor->f[2]); - } - clear_color_no_rp(ctx, zink_resource(fb->cbufs[i]->texture), &color, - psurf->u.tex.level, psurf->u.tex.first_layer, - psurf->u.tex.last_layer - psurf->u.tex.first_layer + 1); + fb_clear->enabled = true; + clear->has_scissor = needs_rp; + if (scissor_state && needs_rp) + clear->scissor = *scissor_state; + clear->color.color = *pcolor; + clear->color.srgb = psurf->format != psurf->texture->format && + !util_format_is_srgb(psurf->format) && util_format_is_srgb(psurf->texture->format); } } } if (buffers & PIPE_CLEAR_DEPTHSTENCIL && fb->zsbuf) { - if (fb->zsbuf->texture->target == PIPE_TEXTURE_3D && !check_3d_layers(fb->zsbuf)) { - clear_in_rp(pctx, buffers, scissor_state, pcolor, depth, stencil); - return; - } - VkImageAspectFlags aspects = 0; + struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[PIPE_MAX_COLOR_BUFS]; + struct zink_framebuffer_clear_data *clear = get_clear_data(ctx, fb_clear, needs_rp ? scissor_state : NULL); + fb_clear->enabled = true; + clear->has_scissor = needs_rp; + if (scissor_state && needs_rp) + clear->scissor = *scissor_state; if (buffers & PIPE_CLEAR_DEPTH) - aspects |= VK_IMAGE_ASPECT_DEPTH_BIT; + clear->zs.depth = depth; if (buffers & PIPE_CLEAR_STENCIL) - aspects |= VK_IMAGE_ASPECT_STENCIL_BIT; - clear_zs_no_rp(ctx, zink_resource(fb->zsbuf->texture), aspects, - depth, stencil, fb->zsbuf->u.tex.level, fb->zsbuf->u.tex.first_layer, - fb->zsbuf->u.tex.last_layer - fb->zsbuf->u.tex.first_layer + 1); + clear->zs.stencil = stencil; + clear->zs.bits |= (buffers & PIPE_CLEAR_DEPTHSTENCIL); } } +static inline bool +colors_equal(union pipe_color_union *a, union pipe_color_union *b) +{ + return a->ui[0] == b->ui[0] && a->ui[1] == b->ui[1] && a->ui[2] == b->ui[2] && a->ui[3] == b->ui[3]; +} + +void +zink_clear_framebuffer(struct zink_context *ctx, unsigned clear_buffers) +{ + unsigned to_clear = 0; + struct pipe_framebuffer_state *fb_state = &ctx->fb_state; + while (clear_buffers) { + struct zink_framebuffer_clear *color_clear = NULL; + struct zink_framebuffer_clear *zs_clear = NULL; + unsigned num_clears = 0; + for (int i = 0; i < fb_state->nr_cbufs && clear_buffers >= PIPE_CLEAR_COLOR0; i++) { + struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[i]; + /* these need actual clear calls inside the rp */ + if (!(clear_buffers & (PIPE_CLEAR_COLOR0 << i))) + continue; + if (color_clear) { + /* different number of clears -> do another clear */ + //XXX: could potentially merge "some" of the clears into this one for a very, very small optimization + if (num_clears != zink_fb_clear_count(fb_clear)) + goto out; + /* compare all the clears to determine if we can batch these buffers together */ + for (int j = 0; j < num_clears; j++) { + struct zink_framebuffer_clear_data *a = zink_fb_clear_element(color_clear, j); + struct zink_framebuffer_clear_data *b = zink_fb_clear_element(fb_clear, j); + /* scissors don't match, fire this one off */ + if (a->has_scissor != b->has_scissor || (a->has_scissor && !scissor_states_equal(&a->scissor, &b->scissor))) + goto out; + + /* colors don't match, fire this one off */ + if (!colors_equal(&a->color.color, &b->color.color)) + goto out; + } + } else { + color_clear = fb_clear; + num_clears = zink_fb_clear_count(fb_clear); + } + + clear_buffers &= ~(PIPE_CLEAR_COLOR0 << i); + to_clear |= (PIPE_CLEAR_COLOR0 << i); + } + if (clear_buffers & PIPE_CLEAR_DEPTHSTENCIL) { + struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[PIPE_MAX_COLOR_BUFS]; + if (color_clear) { + if (num_clears != zink_fb_clear_count(fb_clear)) + goto out; + /* compare all the clears to determine if we can batch these buffers together */ + for (int j = 0; j < zink_fb_clear_count(color_clear); j++) { + struct zink_framebuffer_clear_data *a = zink_fb_clear_element(color_clear, j); + struct zink_framebuffer_clear_data *b = zink_fb_clear_element(fb_clear, j); + /* scissors don't match, fire this one off */ + if (a->has_scissor != b->has_scissor || (a->has_scissor && !scissor_states_equal(&a->scissor, &b->scissor))) + goto out; + } + } + zs_clear = fb_clear; + to_clear |= (clear_buffers & PIPE_CLEAR_DEPTHSTENCIL); + clear_buffers &= ~PIPE_CLEAR_DEPTHSTENCIL; + } +out: + if (to_clear) { + if (num_clears) { + for (int j = 0; j < num_clears; j++) { + struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(color_clear, j); + struct zink_framebuffer_clear_data *zsclear = NULL; + if (zs_clear) + zsclear = zink_fb_clear_element(zs_clear, j); + zink_clear(&ctx->base, to_clear, + clear->has_scissor ? &clear->scissor : NULL, + &clear->color.color, + zsclear ? zsclear->zs.depth : 0, + zsclear ? zsclear->zs.stencil : 0); + } + } else { + for (int j = 0; j < zink_fb_clear_count(zs_clear); j++) { + struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(zs_clear, j); + zink_clear(&ctx->base, to_clear, + clear->has_scissor ? &clear->scissor : NULL, + NULL, + clear->zs.depth, + clear->zs.stencil); + } + } + } + to_clear = 0; + } + for (int i = 0; i < ARRAY_SIZE(ctx->fb_clears); i++) + zink_fb_clear_reset(&ctx->fb_clears[i]); +} + static struct pipe_surface * create_clear_surface(struct pipe_context *pctx, struct pipe_resource *pres, unsigned level, const struct pipe_box *box) { @@ -318,3 +415,91 @@ zink_clear_texture(struct pipe_context *pctx, } pipe_surface_reference(&surf, NULL); } + +bool +zink_fb_clear_needs_explicit(struct zink_framebuffer_clear *fb_clear) +{ + if (zink_fb_clear_count(fb_clear) != 1) + return true; + struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(fb_clear, 0); + return clear->has_scissor; +} + +void +zink_fb_clears_apply(struct zink_context *ctx, struct pipe_resource *pres) +{ + if (zink_resource(pres)->aspect == VK_IMAGE_ASPECT_COLOR_BIT) { + for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) { + if (ctx->fb_state.cbufs[i] && ctx->fb_state.cbufs[i]->texture == pres) { + struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[i]; + if (fb_clear->enabled) { + assert(!zink_curr_batch(ctx)->in_rp); + if (zink_fb_clear_needs_explicit(fb_clear) || !check_3d_layers(ctx->fb_state.cbufs[i])) + /* this will automatically trigger all the clears */ + zink_batch_rp(ctx); + else { + struct pipe_surface *psurf = ctx->fb_state.cbufs[i]; + struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(fb_clear, 0); + union pipe_color_union color = clear->color.color; + if (clear->color.srgb) { + /* if SRGB mode is disabled for the fb with a backing srgb image then we have to + * convert this to srgb color + */ + color.f[0] = util_format_srgb_to_linear_float(clear->color.color.f[0]); + color.f[1] = util_format_srgb_to_linear_float(clear->color.color.f[1]); + color.f[2] = util_format_srgb_to_linear_float(clear->color.color.f[2]); + } + + clear_color_no_rp(ctx, zink_resource(pres), &color, + psurf->u.tex.level, psurf->u.tex.first_layer, + psurf->u.tex.last_layer - psurf->u.tex.first_layer + 1); + } + zink_fb_clear_reset(&ctx->fb_clears[i]); + } + return; + } + } + } else { + struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[PIPE_MAX_COLOR_BUFS]; + if (fb_clear->enabled && ctx->fb_state.zsbuf && ctx->fb_state.zsbuf->texture == pres) { + assert(!zink_curr_batch(ctx)->in_rp); + if (zink_fb_clear_needs_explicit(fb_clear) || !check_3d_layers(ctx->fb_state.zsbuf)) + /* this will automatically trigger all the clears */ + zink_batch_rp(ctx); + else { + struct pipe_surface *psurf = ctx->fb_state.zsbuf; + struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(fb_clear, 0); + VkImageAspectFlags aspects = 0; + if (clear->zs.bits & PIPE_CLEAR_DEPTH) + aspects |= VK_IMAGE_ASPECT_DEPTH_BIT; + if (clear->zs.bits & PIPE_CLEAR_STENCIL) + aspects |= VK_IMAGE_ASPECT_STENCIL_BIT; + clear_zs_no_rp(ctx, zink_resource(pres), aspects, clear->zs.depth, clear->zs.stencil, + psurf->u.tex.level, psurf->u.tex.first_layer, + psurf->u.tex.last_layer - psurf->u.tex.first_layer + 1); + zink_fb_clear_reset(fb_clear); + } + } + } +} + +void +zink_fb_clears_discard(struct zink_context *ctx, struct pipe_resource *pres) +{ + if (zink_resource(pres)->aspect == VK_IMAGE_ASPECT_COLOR_BIT) { + for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) { + if (ctx->fb_state.cbufs[i] && ctx->fb_state.cbufs[i]->texture == pres) { + if (ctx->fb_clears[i].enabled) { + zink_fb_clear_reset(&ctx->fb_clears[i]); + return; + } + } + } + } else { + if (ctx->fb_clears[PIPE_MAX_COLOR_BUFS].enabled && ctx->fb_state.zsbuf && ctx->fb_state.zsbuf->texture == pres) { + int i = PIPE_MAX_COLOR_BUFS; + zink_fb_clear_reset(&ctx->fb_clears[i]); + } + } +} + diff --git a/src/gallium/drivers/zink/zink_context.c b/src/gallium/drivers/zink/zink_context.c index 8d525f8f7dd..a0df27d7d5f 100644 --- a/src/gallium/drivers/zink/zink_context.c +++ b/src/gallium/drivers/zink/zink_context.c @@ -40,6 +40,7 @@ #include "indices/u_primconvert.h" #include "util/u_blitter.h" #include "util/u_debug.h" +#include "util/format_srgb.h" #include "util/format/u_format.h" #include "util/u_framebuffer.h" #include "util/u_helpers.h" @@ -731,6 +732,7 @@ get_render_pass(struct zink_context *ctx) struct zink_screen *screen = zink_screen(ctx->base.screen); const struct pipe_framebuffer_state *fb = &ctx->fb_state; struct zink_render_pass_state state = { 0 }; + uint32_t clears = 0; for (int i = 0; i < fb->nr_cbufs; i++) { struct pipe_surface *surf = fb->cbufs[i]; @@ -738,6 +740,8 @@ get_render_pass(struct zink_context *ctx) state.rts[i].format = zink_get_format(screen, surf->format); state.rts[i].samples = surf->texture->nr_samples > 0 ? surf->texture->nr_samples : VK_SAMPLE_COUNT_1_BIT; + state.rts[i].clear_color = ctx->fb_clears[i].enabled && !zink_fb_clear_needs_explicit(&ctx->fb_clears[i]); + clears |= !!state.rts[i].clear_color ? BITFIELD_BIT(i) : 0; } else { state.rts[i].format = VK_FORMAT_R8_UINT; state.rts[i].samples = MAX2(fb->samples, 1); @@ -748,11 +752,22 @@ get_render_pass(struct zink_context *ctx) if (fb->zsbuf) { struct zink_resource *zsbuf = zink_resource(fb->zsbuf->texture); + struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[PIPE_MAX_COLOR_BUFS]; state.rts[fb->nr_cbufs].format = zsbuf->format; state.rts[fb->nr_cbufs].samples = zsbuf->base.nr_samples > 0 ? zsbuf->base.nr_samples : VK_SAMPLE_COUNT_1_BIT; + state.rts[fb->nr_cbufs].clear_color = fb_clear->enabled && + !zink_fb_clear_needs_explicit(fb_clear) && + (zink_fb_clear_element(fb_clear, 0)->zs.bits & PIPE_CLEAR_DEPTH); + state.rts[fb->nr_cbufs].clear_stencil = fb_clear->enabled && + !zink_fb_clear_needs_explicit(fb_clear) && + (zink_fb_clear_element(fb_clear, 0)->zs.bits & PIPE_CLEAR_STENCIL); + clears |= state.rts[fb->nr_cbufs].clear_color || state.rts[fb->nr_cbufs].clear_stencil ? BITFIELD_BIT(fb->nr_cbufs) : 0;; state.num_rts++; } state.have_zsbuf = fb->zsbuf != NULL; +#ifndef NDEBUG + state.clears = clears; +#endif uint32_t hash = hash_render_pass_state(&state); struct hash_entry *entry = _mesa_hash_table_search_pre_hashed(ctx->render_pass_cache, hash, @@ -845,8 +860,51 @@ zink_begin_render_pass(struct zink_context *ctx, struct zink_batch *batch) rpbi.renderArea.offset.y = 0; rpbi.renderArea.extent.width = fb_state->width; rpbi.renderArea.extent.height = fb_state->height; - rpbi.clearValueCount = 0; - rpbi.pClearValues = NULL; + + VkClearValue clears[PIPE_MAX_COLOR_BUFS + 1] = {}; + unsigned clear_buffers = 0; + uint32_t clear_validate = 0; + for (int i = 0; i < fb_state->nr_cbufs; i++) { + /* these are no-ops */ + if (!fb_state->cbufs[i] || !ctx->fb_clears[i].enabled) + continue; + /* these need actual clear calls inside the rp */ + if (zink_fb_clear_needs_explicit(&ctx->fb_clears[i])) { + clear_buffers |= (PIPE_CLEAR_COLOR0 << i); + continue; + } + /* we now know there's only one clear */ + struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(&ctx->fb_clears[i], 0); + if (clear->color.srgb) { + clears[i].color.float32[0] = util_format_srgb_to_linear_float(clear->color.color.f[0]); + clears[i].color.float32[1] = util_format_srgb_to_linear_float(clear->color.color.f[1]); + clears[i].color.float32[2] = util_format_srgb_to_linear_float(clear->color.color.f[2]); + } else { + clears[i].color.float32[0] = clear->color.color.f[0]; + clears[i].color.float32[1] = clear->color.color.f[1]; + clears[i].color.float32[2] = clear->color.color.f[2]; + } + clears[i].color.float32[3] = clear->color.color.f[3]; + rpbi.clearValueCount = i + 1; + clear_validate |= BITFIELD_BIT(i); + assert(ctx->framebuffer->rp->state.clears); + } + if (fb_state->zsbuf && ctx->fb_clears[PIPE_MAX_COLOR_BUFS].enabled) { + struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[PIPE_MAX_COLOR_BUFS]; + if (zink_fb_clear_needs_explicit(fb_clear)) { + for (int j = 0; j < zink_fb_clear_count(fb_clear); j++) + clear_buffers |= zink_fb_clear_element(fb_clear, j)->zs.bits; + } else { + struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(fb_clear, 0); + clears[fb_state->nr_cbufs].depthStencil.depth = clear->zs.depth; + clears[fb_state->nr_cbufs].depthStencil.stencil = clear->zs.stencil; + rpbi.clearValueCount = fb_state->nr_cbufs + 1; + clear_validate |= BITFIELD_BIT(fb_state->nr_cbufs); + assert(ctx->framebuffer->rp->state.clears); + } + } + assert(clear_validate == ctx->framebuffer->rp->state.clears); + rpbi.pClearValues = &clears[0]; rpbi.framebuffer = ctx->framebuffer->fb; assert(ctx->gfx_pipeline_state.render_pass && ctx->framebuffer); @@ -859,6 +917,8 @@ zink_begin_render_pass(struct zink_context *ctx, struct zink_batch *batch) vkCmdBeginRenderPass(batch->cmdbuf, &rpbi, VK_SUBPASS_CONTENTS_INLINE); batch->in_rp = true; + + zink_clear_framebuffer(ctx, clear_buffers); } static void @@ -916,6 +976,22 @@ zink_set_framebuffer_state(struct pipe_context *pctx, { struct zink_context *ctx = zink_context(pctx); + for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) { + struct pipe_surface *surf = ctx->fb_state.cbufs[i]; + if (surf && + (!state->cbufs[i] || i >= state->nr_cbufs || + surf->texture != state->cbufs[i]->texture || + surf->format != state->cbufs[i]->format || + memcmp(&surf->u, &state->cbufs[i]->u, sizeof(union pipe_surface_desc)))) + zink_fb_clears_apply(ctx, surf->texture); + } + if (ctx->fb_state.zsbuf) { + struct pipe_surface *surf = ctx->fb_state.zsbuf; + if (!state->zsbuf || surf->texture != state->zsbuf->texture || + memcmp(&surf->u, &state->zsbuf->u, sizeof(union pipe_surface_desc))) + zink_fb_clears_apply(ctx, ctx->fb_state.zsbuf->texture); + } + util_copy_framebuffer_state(&ctx->fb_state, state); uint8_t rast_samples = util_framebuffer_get_num_samples(state); @@ -1515,6 +1591,9 @@ zink_resource_copy_region(struct pipe_context *pctx, } else unreachable("planar formats not yet handled"); + zink_fb_clears_apply(ctx, pdst); + zink_fb_clears_apply(ctx, psrc); + region.srcSubresource.aspectMask = src->aspect; region.srcSubresource.mipLevel = src_level; region.srcSubresource.layerCount = 1; @@ -1767,6 +1846,8 @@ zink_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags) ctx->base.stream_uploader = u_upload_create_default(&ctx->base); ctx->base.const_uploader = ctx->base.stream_uploader; + for (int i = 0; i < ARRAY_SIZE(ctx->fb_clears); i++) + util_dynarray_init(&ctx->fb_clears[i].clears, ctx); int prim_hwsupport = 1 << PIPE_PRIM_POINTS | 1 << PIPE_PRIM_LINES | diff --git a/src/gallium/drivers/zink/zink_context.h b/src/gallium/drivers/zink/zink_context.h index 30e7df16586..b0c5b6df29b 100644 --- a/src/gallium/drivers/zink/zink_context.h +++ b/src/gallium/drivers/zink/zink_context.h @@ -96,6 +96,27 @@ struct zink_viewport_state { uint8_t num_viewports; }; +struct zink_framebuffer_clear_data { + union { + struct { + union pipe_color_union color; + bool srgb; + } color; + struct { + float depth; + unsigned stencil; + uint8_t bits : 2; // PIPE_CLEAR_DEPTH, PIPE_CLEAR_STENCIL + } zs; + }; + struct pipe_scissor_state scissor; + bool has_scissor; +}; + +struct zink_framebuffer_clear { + struct util_dynarray clears; + bool enabled; +}; + #define ZINK_SHADER_COUNT (PIPE_SHADER_TYPES - 1) #define ZINK_NUM_GFX_BATCHES 4 #define ZINK_COMPUTE_BATCH_ID ZINK_NUM_GFX_BATCHES @@ -145,6 +166,7 @@ struct zink_context { struct primconvert_context *primconvert; struct zink_framebuffer *framebuffer; + struct zink_framebuffer_clear fb_clears[PIPE_MAX_COLOR_BUFS + 1]; struct pipe_vertex_buffer buffers[PIPE_MAX_ATTRIBS]; uint32_t buffers_enabled_mask; @@ -270,6 +292,37 @@ zink_clear_texture(struct pipe_context *ctx, const struct pipe_box *box, const void *data); +bool +zink_fb_clear_needs_explicit(struct zink_framebuffer_clear *fb_clear); + +void +zink_clear_framebuffer(struct zink_context *ctx, unsigned clear_buffers); + +static inline struct zink_framebuffer_clear_data * +zink_fb_clear_element(struct zink_framebuffer_clear *fb_clear, int idx) +{ + return util_dynarray_element(&fb_clear->clears, struct zink_framebuffer_clear_data, idx); +} + +static inline unsigned +zink_fb_clear_count(struct zink_framebuffer_clear *fb_clear) +{ + return util_dynarray_num_elements(&fb_clear->clears, struct zink_framebuffer_clear_data); +} + +static inline void +zink_fb_clear_reset(struct zink_framebuffer_clear *fb_clear) +{ + util_dynarray_fini(&fb_clear->clears); + fb_clear->enabled = false; +} + +void +zink_fb_clears_apply(struct zink_context *ctx, struct pipe_resource *pres); + +void +zink_fb_clears_discard(struct zink_context *ctx, struct pipe_resource *pres); + void zink_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *dinfo, diff --git a/src/gallium/drivers/zink/zink_render_pass.c b/src/gallium/drivers/zink/zink_render_pass.c index b1eb9015bd8..80565d43d1e 100644 --- a/src/gallium/drivers/zink/zink_render_pass.c +++ b/src/gallium/drivers/zink/zink_render_pass.c @@ -40,7 +40,7 @@ create_render_pass(VkDevice dev, struct zink_render_pass_state *state) attachments[i].flags = 0; attachments[i].format = rt->format; attachments[i].samples = rt->samples; - attachments[i].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + attachments[i].loadOp = rt->clear_color ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD; attachments[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE; attachments[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; attachments[i].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; @@ -56,9 +56,9 @@ create_render_pass(VkDevice dev, struct zink_render_pass_state *state) attachments[num_attachments].flags = 0; attachments[num_attachments].format = rt->format; attachments[num_attachments].samples = rt->samples; - attachments[num_attachments].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + attachments[num_attachments].loadOp = rt->clear_color ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD; attachments[num_attachments].storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attachments[num_attachments].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + attachments[num_attachments].stencilLoadOp = rt->clear_stencil ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD; attachments[num_attachments].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; attachments[num_attachments].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; attachments[num_attachments].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; diff --git a/src/gallium/drivers/zink/zink_render_pass.h b/src/gallium/drivers/zink/zink_render_pass.h index 577b92c9065..02dc2119439 100644 --- a/src/gallium/drivers/zink/zink_render_pass.h +++ b/src/gallium/drivers/zink/zink_render_pass.h @@ -34,6 +34,8 @@ struct zink_screen; struct zink_rt_attrib { VkFormat format; VkSampleCountFlagBits samples; + bool clear_color; + bool clear_stencil; }; struct zink_render_pass_state { @@ -41,6 +43,9 @@ struct zink_render_pass_state { uint8_t have_zsbuf : 1; struct zink_rt_attrib rts[PIPE_MAX_COLOR_BUFS + 1]; unsigned num_rts; +#ifndef NDEBUG + uint32_t clears; //for extra verification +#endif }; struct zink_render_pass { diff --git a/src/gallium/drivers/zink/zink_resource.c b/src/gallium/drivers/zink/zink_resource.c index 7930a281518..2ec1f84a9b1 100644 --- a/src/gallium/drivers/zink/zink_resource.c +++ b/src/gallium/drivers/zink/zink_resource.c @@ -619,6 +619,7 @@ zink_transfer_map(struct pipe_context *pctx, if (usage & PIPE_MAP_WRITE) util_range_add(&res->base, &res->valid_buffer_range, box->x, box->x + box->width); } else { + zink_fb_clears_apply(ctx, pres); if (res->optimal_tiling || !res->host_visible) { enum pipe_format format = pres->format; if (usage & PIPE_MAP_DEPTH_ONLY)