diff --git a/src/gallium/drivers/zink/zink_clear.c b/src/gallium/drivers/zink/zink_clear.c index 5ae59cd2dfa..01813a7081f 100644 --- a/src/gallium/drivers/zink/zink_clear.c +++ b/src/gallium/drivers/zink/zink_clear.c @@ -784,3 +784,27 @@ zink_fb_clears_apply_region(struct zink_context *ctx, struct pipe_resource *pres } } } + +void +zink_fb_clear_rewrite(struct zink_context *ctx, unsigned idx, enum pipe_format before, enum pipe_format after) +{ + /* if the values for the clear color are incompatible, they must be rewritten; + * this occurs if: + * - the formats' srgb-ness does not match + * - the formats' signedness does not match + */ + const struct util_format_description *bdesc = util_format_description(before); + const struct util_format_description *adesc = util_format_description(after); + bool bsigned = bdesc->channel[util_format_get_first_non_void_channel(before)].type == UTIL_FORMAT_TYPE_SIGNED; + bool asigned = adesc->channel[util_format_get_first_non_void_channel(after)].type == UTIL_FORMAT_TYPE_SIGNED; + if (util_format_is_srgb(before) == util_format_is_srgb(after) && + bsigned == asigned) + return; + struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[idx]; + for (int j = 0; j < zink_fb_clear_count(fb_clear); j++) { + struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(fb_clear, j); + uint32_t data[4]; + util_format_pack_rgba(before, data, clear->color.ui, 1); + util_format_unpack_rgba(after, clear->color.ui, data, 1); + } +} diff --git a/src/gallium/drivers/zink/zink_clear.h b/src/gallium/drivers/zink/zink_clear.h index 05fb115b84a..b1f4b18ff01 100644 --- a/src/gallium/drivers/zink/zink_clear.h +++ b/src/gallium/drivers/zink/zink_clear.h @@ -110,3 +110,6 @@ zink_fb_clears_apply_or_discard(struct zink_context *ctx, struct pipe_resource * void zink_fb_clears_apply_region(struct zink_context *ctx, struct pipe_resource *pres, struct u_rect region); + +void +zink_fb_clear_rewrite(struct zink_context *ctx, unsigned idx, enum pipe_format before, enum pipe_format after); diff --git a/src/gallium/drivers/zink/zink_context.c b/src/gallium/drivers/zink/zink_context.c index 7240cdbcc72..87fba7643b4 100644 --- a/src/gallium/drivers/zink/zink_context.c +++ b/src/gallium/drivers/zink/zink_context.c @@ -2853,9 +2853,22 @@ zink_set_framebuffer_state(struct pipe_context *pctx, bool flush_clears = ctx->clears_enabled && (ctx->dynamic_fb.info.layerCount != layers || state->width != w || state->height != h); - for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) { - if (i >= state->nr_cbufs || ctx->fb_state.cbufs[i] != state->cbufs[i]) - flush_clears |= zink_fb_clear_enabled(ctx, i); + if (ctx->clears_enabled && !flush_clears) { + for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) { + if (i >= state->nr_cbufs || !ctx->fb_state.cbufs[i] || !state->cbufs[i]) + flush_clears |= zink_fb_clear_enabled(ctx, i); + else if (zink_fb_clear_enabled(ctx, i) && ctx->fb_state.cbufs[i] != state->cbufs[i]) { + struct zink_surface *a = zink_csurface(ctx->fb_state.cbufs[i]); + struct zink_surface *b = zink_csurface(state->cbufs[i]); + if (a == b) + continue; + if (memcmp(&a->base.u.tex, &b->base.u.tex, sizeof(b->base.u.tex)) || + a->base.texture != b->base.texture) + flush_clears = true; + else if (a->base.format != b->base.format) + zink_fb_clear_rewrite(ctx, i, a->base.format, b->base.format); + } + } } if (ctx->fb_state.zsbuf != state->zsbuf) flush_clears |= zink_fb_clear_enabled(ctx, PIPE_MAX_COLOR_BUFS);