diff --git a/src/gallium/drivers/zink/zink_context.c b/src/gallium/drivers/zink/zink_context.c index 1ebf5605ead..bf5ac2f9332 100644 --- a/src/gallium/drivers/zink/zink_context.c +++ b/src/gallium/drivers/zink/zink_context.c @@ -3139,6 +3139,22 @@ zink_set_color_write_enables(struct zink_context *ctx) } } +static void +check_framebuffer_surface_mutable(struct pipe_context *pctx, struct pipe_surface *psurf) +{ + struct zink_context *ctx = zink_context(pctx); + struct zink_ctx_surface *csurf = (struct zink_ctx_surface *)psurf; + if (!csurf->needs_mutable) + return; + zink_resource_object_init_mutable(ctx, zink_resource(psurf->texture)); + struct pipe_surface *psurf2 = pctx->create_surface(pctx, psurf->texture, psurf); + pipe_resource_reference(&psurf2->texture, NULL); + struct zink_ctx_surface *csurf2 = (struct zink_ctx_surface *)psurf2; + zink_surface_reference(zink_screen(pctx->screen), &csurf->surf, csurf2->surf); + pctx->surface_destroy(pctx, psurf2); + csurf->needs_mutable = false; +} + static void zink_set_framebuffer_state(struct pipe_context *pctx, const struct pipe_framebuffer_state *state) @@ -3225,6 +3241,7 @@ zink_set_framebuffer_state(struct pipe_context *pctx, if (!samples) samples = MAX3(transient ? transient->base.nr_samples : 1, psurf->texture->nr_samples, psurf->nr_samples ? psurf->nr_samples : 1); struct zink_resource *res = zink_resource(psurf->texture); + check_framebuffer_surface_mutable(pctx, psurf); if (zink_csurface(psurf)->info.layerCount > layers) ctx->fb_layer_mismatch |= BITFIELD_BIT(i); if (res->modifiers) { @@ -3254,6 +3271,7 @@ zink_set_framebuffer_state(struct pipe_context *pctx, if (ctx->fb_state.zsbuf) { struct pipe_surface *psurf = ctx->fb_state.zsbuf; struct zink_surface *transient = zink_transient_surface(psurf); + check_framebuffer_surface_mutable(pctx, psurf); if (transient || psurf->nr_samples) ctx->transient_attachments |= BITFIELD_BIT(PIPE_MAX_COLOR_BUFS); if (!samples) diff --git a/src/gallium/drivers/zink/zink_surface.c b/src/gallium/drivers/zink/zink_surface.c index 6b8fd3530bc..5a08c17badd 100644 --- a/src/gallium/drivers/zink/zink_surface.c +++ b/src/gallium/drivers/zink/zink_surface.c @@ -272,10 +272,18 @@ zink_create_surface(struct pipe_context *pctx, { struct zink_resource *res = zink_resource(pres); bool is_array = templ->u.tex.last_layer != templ->u.tex.first_layer; + bool needs_mutable = false; enum pipe_texture_target target_2d[] = {PIPE_TEXTURE_2D, PIPE_TEXTURE_2D_ARRAY}; - if (!res->obj->dt && pres->format != templ->format) + if (!res->obj->dt && pres->format != templ->format) { /* mutable not set by default */ + needs_mutable = !(res->base.b.bind & ZINK_BIND_MUTABLE); + } + + if (!zink_screen(pctx->screen)->threaded && needs_mutable) { + /* this is fine without tc */ + needs_mutable = false; zink_resource_object_init_mutable(zink_context(pctx), res); + } if (!zink_get_format(zink_screen(pctx->screen), templ->format)) return NULL; @@ -291,12 +299,19 @@ zink_create_surface(struct pipe_context *pctx, surface->is_swapchain = true; psurf = &surface->base; } - } else + } else if (!needs_mutable) { psurf = zink_get_surface(zink_context(pctx), pres, templ, &ivci); - if (!psurf) + } + if (!psurf && !needs_mutable) return NULL; - struct zink_ctx_surface *csurf = (struct zink_ctx_surface*)wrap_surface(pctx, psurf); + struct zink_ctx_surface *csurf = (struct zink_ctx_surface*)wrap_surface(pctx, needs_mutable ? templ : psurf); + csurf->needs_mutable = needs_mutable; + if (needs_mutable) { + csurf->surf = NULL; + pipe_resource_reference(&csurf->base.texture, pres); + init_pipe_surface_info(pctx, &csurf->base, templ, pres); + } if (templ->nr_samples && !zink_screen(pctx->screen)->info.have_EXT_multisampled_render_to_single_sampled) { /* transient fb attachment: not cached */ @@ -357,6 +372,9 @@ zink_surface_destroy(struct pipe_context *pctx, struct pipe_surface *psurface) { struct zink_ctx_surface *csurf = (struct zink_ctx_surface *)psurface; + if (csurf->needs_mutable) + /* this has an extra resource ref */ + pipe_resource_reference(&csurf->base.texture, NULL); zink_surface_reference(zink_screen(pctx->screen), &csurf->surf, NULL); pipe_surface_release(pctx, (struct pipe_surface**)&csurf->transient); FREE(csurf); diff --git a/src/gallium/drivers/zink/zink_types.h b/src/gallium/drivers/zink/zink_types.h index 972bef014d1..f68cea07499 100644 --- a/src/gallium/drivers/zink/zink_types.h +++ b/src/gallium/drivers/zink/zink_types.h @@ -1447,6 +1447,7 @@ struct zink_ctx_surface { struct zink_surface *surf; //the actual surface struct zink_ctx_surface *transient; //for use with EXT_multisample_render_to_texture bool transient_init; //whether the transient surface has data + bool needs_mutable; }; /* use this cast for framebuffer surfaces */