diff --git a/src/gallium/drivers/zink/zink_context.c b/src/gallium/drivers/zink/zink_context.c index 3f0cea6a3f1..8e5a943ea55 100644 --- a/src/gallium/drivers/zink/zink_context.c +++ b/src/gallium/drivers/zink/zink_context.c @@ -709,7 +709,6 @@ create_framebuffer(struct zink_context *ctx) struct pipe_surface *attachments[PIPE_MAX_COLOR_BUFS + 1] = {}; struct zink_framebuffer_state state = {}; - state.rp = get_render_pass(ctx); for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) { struct pipe_surface *psurf = ctx->fb_state.cbufs[i]; state.attachments[i] = psurf ? zink_surface(psurf)->image_view : VK_NULL_HANDLE; @@ -728,7 +727,9 @@ create_framebuffer(struct zink_context *ctx) state.layers = MAX2(util_framebuffer_get_num_layers(&ctx->fb_state), 1); state.samples = ctx->fb_state.samples; - return zink_create_framebuffer(ctx, screen, &state, attachments); + struct zink_framebuffer *fb = zink_create_framebuffer(ctx, &state, attachments); + zink_init_framebuffer(screen, fb, get_render_pass(ctx)); + return fb; } static void @@ -814,7 +815,7 @@ zink_batch_rp(struct zink_context *ctx) struct zink_batch *batch = zink_curr_batch(ctx); if (!batch->in_rp) { zink_begin_render_pass(ctx, batch); - assert(batch->fb && batch->fb->state.rp); + assert(batch->fb && batch->fb->rp); } return batch; } @@ -847,7 +848,7 @@ zink_set_framebuffer_state(struct pipe_context *pctx, zink_framebuffer_reference(screen, &fb, NULL); fb = create_framebuffer(ctx); zink_framebuffer_reference(screen, &ctx->framebuffer, fb); - ctx->gfx_pipeline_state.render_pass = fb->state.rp; + ctx->gfx_pipeline_state.render_pass = fb->rp; uint8_t rast_samples = util_framebuffer_get_num_samples(state); /* in vulkan, gl_SampleMask needs to be explicitly ignored for sampleCount == 1 */ diff --git a/src/gallium/drivers/zink/zink_framebuffer.c b/src/gallium/drivers/zink/zink_framebuffer.c index 3baf8aca4e2..cbd0a5bb0ff 100644 --- a/src/gallium/drivers/zink/zink_framebuffer.c +++ b/src/gallium/drivers/zink/zink_framebuffer.c @@ -63,7 +63,14 @@ void zink_destroy_framebuffer(struct zink_screen *screen, struct zink_framebuffer *fb) { - vkDestroyFramebuffer(screen->dev, fb->fb, NULL); + hash_table_foreach(&fb->objects, he) { +#if defined(_WIN64) || defined(__x86_64__) + vkDestroyFramebuffer(screen->dev, he->data, NULL); +#else + VkFramebuffer *ptr = he->data; + vkDestroyFramebuffer(screen->dev, *ptr, NULL); +#endif + } for (int i = 0; i < ARRAY_SIZE(fb->surfaces); ++i) pipe_surface_reference(fb->surfaces + i, NULL); @@ -72,11 +79,60 @@ zink_destroy_framebuffer(struct zink_screen *screen, ralloc_free(fb); } +void +zink_init_framebuffer(struct zink_screen *screen, struct zink_framebuffer *fb, struct zink_render_pass *rp) +{ + VkFramebuffer ret; + + if (fb->rp == rp) + return; + + uint32_t hash = _mesa_hash_pointer(rp); + + struct hash_entry *he = _mesa_hash_table_search_pre_hashed(&fb->objects, hash, rp); + if (he) { +#if defined(_WIN64) || defined(__x86_64__) + ret = (VkFramebuffer)he->data; +#else + VkFramebuffer *ptr = he->data; + ret = *ptr; +#endif + goto out; + } + + VkFramebufferCreateInfo fci = {}; + fci.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + fci.renderPass = rp->render_pass; + fci.attachmentCount = fb->state.num_attachments; + fci.pAttachments = fb->state.attachments; + fci.width = fb->state.width; + fci.height = fb->state.height; + fci.layers = fb->state.layers; + + if (vkCreateFramebuffer(screen->dev, &fci, NULL, &ret) != VK_SUCCESS) + return; +#if defined(_WIN64) || defined(__x86_64__) + _mesa_hash_table_insert_pre_hashed(&fb->objects, hash, rp, ret); +#else + VkFramebuffer *ptr = ralloc(fb, VkFramebuffer); + if (!ptr) { + vkDestroyFramebuffer(screen->dev, ret, NULL); + return; + } + *ptr = ret; + _mesa_hash_table_insert_pre_hashed(&fb->objects, hash, rp, ptr); +#endif +out: + fb->rp = rp; + fb->fb = ret; +} + struct zink_framebuffer * -zink_create_framebuffer(struct zink_context *ctx, struct zink_screen *screen, +zink_create_framebuffer(struct zink_context *ctx, struct zink_framebuffer_state *state, struct pipe_surface **attachments) { + struct zink_screen *screen = zink_screen(ctx->base.screen); struct zink_framebuffer *fb = rzalloc(NULL, struct zink_framebuffer); if (!fb) return NULL; @@ -93,22 +149,14 @@ zink_create_framebuffer(struct zink_context *ctx, struct zink_screen *screen, } } - VkFramebufferCreateInfo fci = {}; - fci.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - fci.renderPass = state->rp->render_pass; - fci.attachmentCount = state->num_attachments; - fci.pAttachments = state->attachments; - fci.width = state->width; - fci.height = state->height; - fci.layers = state->layers; - - if (vkCreateFramebuffer(screen->dev, &fci, NULL, &fb->fb) != VK_SUCCESS) { - zink_destroy_framebuffer(screen, fb); - return NULL; - } + if (!_mesa_hash_table_init(&fb->objects, fb, _mesa_hash_pointer, _mesa_key_pointer_equal)) + goto fail; memcpy(&fb->state, state, sizeof(struct zink_framebuffer_state)); return fb; +fail: + zink_destroy_framebuffer(screen, fb); + return NULL; } void diff --git a/src/gallium/drivers/zink/zink_framebuffer.h b/src/gallium/drivers/zink/zink_framebuffer.h index 1950ea23b0b..58d590e74fc 100644 --- a/src/gallium/drivers/zink/zink_framebuffer.h +++ b/src/gallium/drivers/zink/zink_framebuffer.h @@ -27,6 +27,7 @@ #include "pipe/p_state.h" #include +#include "util/hash_table.h" #include "util/u_inlines.h" struct zink_context; @@ -34,7 +35,6 @@ struct zink_screen; struct zink_render_pass; struct zink_framebuffer_state { - struct zink_render_pass *rp; uint32_t width; uint16_t height, layers; uint8_t samples; @@ -44,18 +44,25 @@ struct zink_framebuffer_state { struct zink_framebuffer { struct pipe_reference reference; + + /* current objects */ VkFramebuffer fb; + struct zink_render_pass *rp; struct pipe_surface *surfaces[PIPE_MAX_COLOR_BUFS + 1]; struct pipe_surface *null_surface; /* for use with unbound attachments */ struct zink_framebuffer_state state; + struct hash_table objects; }; struct zink_framebuffer * -zink_create_framebuffer(struct zink_context *ctx, struct zink_screen *screen, +zink_create_framebuffer(struct zink_context *ctx, struct zink_framebuffer_state *fb, struct pipe_surface **attachments); +void +zink_init_framebuffer(struct zink_screen *screen, struct zink_framebuffer *fb, struct zink_render_pass *rp); + void zink_destroy_framebuffer(struct zink_screen *screen, struct zink_framebuffer *fbuf);