From c552d99b09f068504b44423e1ed807d7289afc49 Mon Sep 17 00:00:00 2001 From: Mike Blumenkrantz Date: Wed, 30 Jun 2021 11:51:31 -0400 Subject: [PATCH] zink: use imageless framebuffers this feature lets zink avoid the screen-based framebuffer cache with locks in favor of a context-based one that doesn't need any complicated wizardry to work since it doesn't need to track refcounts for attachments or work across contexts since the surface info gets passed in when the renderpass is begun also expand the dummy surface to an array for use with multisampling and simplify surface refs there for non-imageless case Reviewed-by: Dave Airlie Part-of: --- src/gallium/drivers/zink/zink_context.c | 128 +++++++++++++++------- src/gallium/drivers/zink/zink_context.h | 5 +- src/gallium/drivers/zink/zink_device_info.py | 4 + src/gallium/drivers/zink/zink_framebuffer.c | 156 ++++++++++++++++++++++++--- src/gallium/drivers/zink/zink_framebuffer.h | 28 +++-- src/gallium/drivers/zink/zink_screen.c | 16 +-- src/gallium/drivers/zink/zink_surface.c | 8 +- 7 files changed, 265 insertions(+), 80 deletions(-) diff --git a/src/gallium/drivers/zink/zink_context.c b/src/gallium/drivers/zink/zink_context.c index f5311a3..d258e7e 100644 --- a/src/gallium/drivers/zink/zink_context.c +++ b/src/gallium/drivers/zink/zink_context.c @@ -94,7 +94,8 @@ zink_context_destroy(struct pipe_context *pctx) pipe_resource_reference(&ctx->dummy_vertex_buffer, NULL); pipe_resource_reference(&ctx->dummy_xfb_buffer, NULL); - zink_surface_reference(screen, (struct zink_surface**)&ctx->dummy_surface, NULL); + for (unsigned i = 0; i < ARRAY_SIZE(ctx->dummy_surface); i++) + zink_surface_reference(screen, (struct zink_surface**)&ctx->dummy_surface[i], NULL); zink_buffer_view_reference(screen, &ctx->dummy_bufferview, NULL); simple_mtx_destroy(&ctx->batch_mtx); @@ -110,7 +111,10 @@ zink_context_destroy(struct pipe_context *pctx) zink_batch_state_destroy(screen, *bs); } - if (ctx->framebuffer) { + if (screen->info.have_KHR_imageless_framebuffer) { + hash_table_foreach(&ctx->framebuffer_cache, he) + zink_destroy_framebuffer(screen, he->data); + } else if (ctx->framebuffer) { simple_mtx_lock(&screen->framebuffer_mtx); struct hash_entry *entry = _mesa_hash_table_search(&screen->framebuffer_cache, &ctx->framebuffer->state); if (zink_framebuffer_reference(screen, &ctx->framebuffer, NULL)) @@ -502,7 +506,7 @@ update_descriptor_state_sampler(struct zink_context *ctx, enum pipe_shader_type ctx->di.textures[shader][slot].imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; ctx->di.tbos[shader][slot] = VK_NULL_HANDLE; } else { - struct zink_surface *null_surface = zink_surface(ctx->dummy_surface); + struct zink_surface *null_surface = zink_surface(ctx->dummy_surface[0]); struct zink_buffer_view *null_bufferview = ctx->dummy_bufferview; ctx->di.textures[shader][slot].imageView = null_surface->image_view; ctx->di.textures[shader][slot].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; @@ -538,7 +542,7 @@ update_descriptor_state_image(struct zink_context *ctx, enum pipe_shader_type sh memset(&ctx->di.images[shader][slot], 0, sizeof(ctx->di.images[shader][slot])); ctx->di.texel_images[shader][slot] = VK_NULL_HANDLE; } else { - struct zink_surface *null_surface = zink_surface(ctx->dummy_surface); + struct zink_surface *null_surface = zink_surface(ctx->dummy_surface[0]); struct zink_buffer_view *null_bufferview = ctx->dummy_bufferview; ctx->di.images[shader][slot].imageView = null_surface->image_view; ctx->di.images[shader][slot].imageLayout = VK_IMAGE_LAYOUT_GENERAL; @@ -1479,7 +1483,7 @@ zink_update_fbfetch(struct zink_context *ctx) ctx->di.fbfetch.imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; ctx->di.fbfetch.imageView = zink_screen(ctx->base.screen)->info.rb2_feats.nullDescriptor ? VK_NULL_HANDLE : - zink_surface(ctx->dummy_surface)->image_view; + zink_surface(ctx->dummy_surface[0])->image_view; zink_screen(ctx->base.screen)->context_invalidate_descriptor_state(ctx, PIPE_SHADER_FRAGMENT, ZINK_DESCRIPTOR_TYPE_UBO, 0, 1); return; } @@ -1554,7 +1558,7 @@ get_render_pass(struct zink_context *ctx) state.rts[i].swapchain = surf->texture->bind & PIPE_BIND_SCANOUT; } else { state.rts[i].format = VK_FORMAT_R8_UINT; - state.rts[i].samples = MAX2(fb->samples, 1); + state.rts[i].samples = fb->samples; } state.num_rts++; } @@ -1612,6 +1616,20 @@ get_render_pass(struct zink_context *ctx) return rp; } +static uint32_t +hash_framebuffer_imageless(const void *key) +{ + struct zink_framebuffer_state* s = (struct zink_framebuffer_state*)key; + return _mesa_hash_data(key, offsetof(struct zink_framebuffer_state, infos) + sizeof(s->infos[0]) * s->num_attachments); +} + +static bool +equals_framebuffer_imageless(const void *a, const void *b) +{ + struct zink_framebuffer_state *s = (struct zink_framebuffer_state*)a; + return memcmp(a, b, offsetof(struct zink_framebuffer_state, infos) + sizeof(s->infos[0]) * s->num_attachments) == 0; +} + static void setup_framebuffer(struct zink_context *ctx) { @@ -1652,11 +1670,30 @@ setup_framebuffer(struct zink_context *ctx) if (!ctx->fb_changed) return; - zink_init_framebuffer(screen, ctx->framebuffer, rp); + ctx->init_framebuffer(screen, ctx->framebuffer, rp); ctx->fb_changed = false; ctx->gfx_pipeline_state.render_pass = rp; } +static VkImageView +prep_fb_attachment(struct zink_context *ctx, struct pipe_surface *psurf, unsigned i) +{ + if (!psurf) + return zink_surface(ctx->dummy_surface[util_logbase2_ceil(ctx->fb_state.samples)])->image_view; + + struct zink_surface *surf = zink_surface(psurf); + zink_batch_resource_usage_set(&ctx->batch, zink_resource(surf->base.texture), true); + zink_batch_usage_set(&surf->batch_uses, ctx->batch.state); + + struct zink_resource *res = zink_resource(surf->base.texture); + VkAccessFlags access; + VkPipelineStageFlags pipeline; + VkImageLayout layout = zink_render_pass_attachment_get_barrier_info(ctx->gfx_pipeline_state.render_pass, + i, &pipeline, &access); + zink_resource_image_barrier(ctx, NULL, res, layout, access, pipeline); + return surf->image_view; +} + static unsigned begin_render_pass(struct zink_context *ctx) { @@ -1715,20 +1752,17 @@ begin_render_pass(struct zink_context *ctx) assert(ctx->gfx_pipeline_state.render_pass && ctx->framebuffer); - for (int i = 0; i < ctx->framebuffer->state.num_attachments; i++) { - if (ctx->framebuffer->surfaces[i]) { - struct zink_surface *surf = zink_surface(ctx->framebuffer->surfaces[i]); - zink_batch_resource_usage_set(batch, zink_resource(surf->base.texture), true); - zink_batch_usage_set(&surf->batch_uses, batch->state); - - struct zink_resource *res = zink_resource(surf->base.texture); - VkAccessFlags access; - VkPipelineStageFlags pipeline; - VkImageLayout layout = zink_render_pass_attachment_get_barrier_info(ctx->gfx_pipeline_state.render_pass, - i, &pipeline, &access); - zink_resource_image_barrier(ctx, NULL, res, layout, access, pipeline); - } - } + VkRenderPassAttachmentBeginInfo infos; + VkImageView att[PIPE_MAX_COLOR_BUFS + 1]; + infos.sType = VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO; + infos.pNext = NULL; + infos.attachmentCount = ctx->framebuffer->state.num_attachments; + infos.pAttachments = att; + for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) + att[i] = prep_fb_attachment(ctx, ctx->fb_state.cbufs[i], i); + att[ctx->fb_state.nr_cbufs] = prep_fb_attachment(ctx, ctx->fb_state.zsbuf, ctx->fb_state.nr_cbufs); + if (zink_screen(ctx->base.screen)->info.have_KHR_imageless_framebuffer) + rpbi.pNext = &infos; vkCmdBeginRenderPass(batch->state->cmdbuf, &rpbi, VK_SUBPASS_CONTENTS_INLINE); batch->in_rp = true; @@ -2021,13 +2055,15 @@ zink_set_framebuffer_state(struct pipe_context *pctx, if (ctx->fb_state.width != w || ctx->fb_state.height != h) ctx->scissor_changed = true; rebind_fb_state(ctx, NULL, true); - /* zink_get_framebuffer adds a ref if the fb is reused or created; + ctx->fb_state.samples = util_framebuffer_get_num_samples(state); + uint8_t rast_samples = ctx->fb_state.samples - 1; + /* get_framebuffer adds a ref if the fb is reused or created; * always do get_framebuffer first to avoid deleting the same fb * we're about to use */ - struct zink_framebuffer *fb = zink_get_framebuffer(ctx); - if (ctx->framebuffer) { - struct zink_screen *screen = zink_screen(pctx->screen); + struct zink_framebuffer *fb = ctx->get_framebuffer(ctx); + struct zink_screen *screen = zink_screen(ctx->base.screen); + if (ctx->framebuffer && !screen->info.have_KHR_imageless_framebuffer) { simple_mtx_lock(&screen->framebuffer_mtx); struct hash_entry *he = _mesa_hash_table_search(&screen->framebuffer_cache, &ctx->framebuffer->state); if (ctx->framebuffer && !ctx->framebuffer->state.num_attachments) { @@ -2040,7 +2076,7 @@ zink_set_framebuffer_state(struct pipe_context *pctx, } /* a framebuffer loses 1 ref every time we unset it; * we do NOT add refs here, as the ref has already been added in - * zink_get_framebuffer() + * get_framebuffer() */ if (zink_framebuffer_reference(screen, &ctx->framebuffer, NULL) && he) _mesa_hash_table_remove(&screen->framebuffer_cache, he); @@ -2049,7 +2085,6 @@ zink_set_framebuffer_state(struct pipe_context *pctx, ctx->fb_changed |= ctx->framebuffer != fb; ctx->framebuffer = fb; - uint8_t rast_samples = util_framebuffer_get_num_samples(state) - 1; /* in vulkan, gl_SampleMask needs to be explicitly ignored for sampleCount == 1 */ if ((ctx->gfx_pipeline_state.rast_samples > 0) != (rast_samples > 0)) ctx->dirty_shader_stages |= 1 << PIPE_SHADER_FRAGMENT; @@ -2685,10 +2720,8 @@ zink_texture_barrier(struct pipe_context *pctx, unsigned flags) bmb.pNext = NULL; bmb.srcAccessMask = 0; bmb.dstAccessMask = 0; - struct zink_surface *surf = zink_surface(ctx->framebuffer->surfaces[ctx->framebuffer->state.num_attachments - 1]); - struct zink_resource *res = zink_resource(surf->base.texture); zink_batch_no_rp(ctx); - if (res->aspect != VK_IMAGE_ASPECT_COLOR_BIT) { + if (ctx->fb_state.zsbuf) { VkMemoryBarrier dmb; dmb.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; dmb.pNext = NULL; @@ -2707,7 +2740,7 @@ zink_texture_barrier(struct pipe_context *pctx, unsigned flags) bmb.srcAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; bmb.dstAccessMask |= VK_ACCESS_SHADER_READ_BIT; } - if (ctx->framebuffer->state.num_attachments > 1) { + if (ctx->fb_state.nr_cbufs > 0) { bmb.srcAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; bmb.dstAccessMask |= VK_ACCESS_SHADER_READ_BIT; } @@ -3134,11 +3167,15 @@ zink_rebind_framebuffer(struct zink_context *ctx, struct zink_resource *res) { if (!ctx->framebuffer) return; - for (unsigned i = 0; i < ctx->framebuffer->state.num_attachments; i++) { - if (!ctx->framebuffer->surfaces[i] || - zink_resource(ctx->framebuffer->surfaces[i]->texture) != res) + for (unsigned i = 0; i < ctx->fb_state.nr_cbufs; i++) { + if (!ctx->fb_state.cbufs[i] || + zink_resource(ctx->fb_state.cbufs[i]->texture) != res) continue; - zink_rebind_surface(ctx, &ctx->framebuffer->surfaces[i]); + zink_rebind_surface(ctx, &ctx->fb_state.cbufs[i]); + zink_batch_no_rp(ctx); + } + if (ctx->fb_state.zsbuf && zink_resource(ctx->fb_state.zsbuf->texture) != res) { + zink_rebind_surface(ctx, &ctx->fb_state.zsbuf); zink_batch_no_rp(ctx); } if (rebind_fb_state(ctx, res, false)) @@ -3488,6 +3525,14 @@ zink_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags) ctx->base.screen = pscreen; ctx->base.priv = priv; + if (screen->info.have_KHR_imageless_framebuffer) { + ctx->get_framebuffer = zink_get_framebuffer_imageless; + ctx->init_framebuffer = zink_init_framebuffer_imageless; + } else { + ctx->get_framebuffer = zink_get_framebuffer; + ctx->init_framebuffer = zink_init_framebuffer; + } + ctx->base.destroy = zink_context_destroy; ctx->base.get_device_reset_status = zink_get_device_reset_status; ctx->base.set_device_reset_callback = zink_set_device_reset_callback; @@ -3576,6 +3621,7 @@ zink_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags) goto fail; _mesa_hash_table_init(&ctx->compute_program_cache, ctx, _mesa_hash_pointer, _mesa_key_pointer_equal); + _mesa_hash_table_init(&ctx->framebuffer_cache, ctx, hash_framebuffer_imageless, equals_framebuffer_imageless); _mesa_set_init(&ctx->render_pass_state_cache, ctx, hash_rp_state, equals_rp_state); ctx->render_pass_cache = _mesa_hash_table_create(NULL, hash_render_pass_state, @@ -3592,9 +3638,13 @@ zink_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags) PIPE_BIND_STREAM_OUTPUT, PIPE_USAGE_DEFAULT, sizeof(data)); if (!ctx->dummy_xfb_buffer) goto fail; - ctx->dummy_surface = zink_surface_create_null(ctx, PIPE_TEXTURE_2D, 1, 1, 1); - if (!ctx->dummy_surface) - goto fail; + for (unsigned i = 0; i < ARRAY_SIZE(ctx->dummy_surface); i++) { + if (!(screen->info.props.limits.framebufferDepthSampleCounts & BITFIELD_BIT(i))) + continue; + ctx->dummy_surface[i] = zink_surface_create_null(ctx, PIPE_TEXTURE_2D, 1024, 1024, BITFIELD_BIT(i)); + if (!ctx->dummy_surface[i]) + goto fail; + } ctx->dummy_bufferview = get_buffer_view(ctx, zink_resource(ctx->dummy_vertex_buffer), PIPE_FORMAT_R8_UNORM, 0, sizeof(data)); if (!ctx->dummy_bufferview) goto fail; @@ -3627,7 +3677,7 @@ zink_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags) } } if (!screen->info.rb2_feats.nullDescriptor) - ctx->di.fbfetch.imageView = zink_surface(ctx->dummy_surface)->image_view; + ctx->di.fbfetch.imageView = zink_surface(ctx->dummy_surface[0])->image_view; p_atomic_inc(&screen->base.num_contexts); zink_select_draw_vbo(ctx); diff --git a/src/gallium/drivers/zink/zink_context.h b/src/gallium/drivers/zink/zink_context.h index 6e1d9ff..bdf8cd5 100644 --- a/src/gallium/drivers/zink/zink_context.h +++ b/src/gallium/drivers/zink/zink_context.h @@ -200,6 +200,9 @@ struct zink_context { struct zink_image_view image_views[PIPE_SHADER_TYPES][PIPE_MAX_SHADER_IMAGES]; struct pipe_framebuffer_state fb_state; + struct zink_framebuffer *(*get_framebuffer)(struct zink_context*); + void (*init_framebuffer)(struct zink_screen *screen, struct zink_framebuffer *fb, struct zink_render_pass *rp); + struct hash_table framebuffer_cache; struct zink_vertex_elements_state *element_state; struct zink_rasterizer_state *rast_state; @@ -284,7 +287,7 @@ struct zink_context { struct pipe_resource *dummy_vertex_buffer; struct pipe_resource *dummy_xfb_buffer; - struct pipe_surface *dummy_surface; + struct pipe_surface *dummy_surface[7]; struct zink_buffer_view *dummy_bufferview; unsigned buffer_rebind_counter; diff --git a/src/gallium/drivers/zink/zink_device_info.py b/src/gallium/drivers/zink/zink_device_info.py index 5494b9e..97838b5 100644 --- a/src/gallium/drivers/zink/zink_device_info.py +++ b/src/gallium/drivers/zink/zink_device_info.py @@ -104,6 +104,10 @@ EXTENSIONS = [ alias="index_uint8", features=True, conditions=["$feats.indexTypeUint8"]), + Extension("VK_KHR_imageless_framebuffer", + alias="imgless", + features=True, + conditions=["$feats.imagelessFramebuffer"]), Extension("VK_EXT_robustness2", alias="rb2", properties=True, diff --git a/src/gallium/drivers/zink/zink_framebuffer.c b/src/gallium/drivers/zink/zink_framebuffer.c index a96c2e3..6147581 100644 --- a/src/gallium/drivers/zink/zink_framebuffer.c +++ b/src/gallium/drivers/zink/zink_framebuffer.c @@ -45,14 +45,135 @@ zink_destroy_framebuffer(struct zink_screen *screen, #endif } - if (fb->null_surface) - pipe_resource_reference(&fb->null_surface->texture, NULL); - zink_surface_reference(screen, (struct zink_surface**)&fb->null_surface, NULL); - ralloc_free(fb); } void +zink_init_framebuffer_imageless(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.flags = VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT; + fci.renderPass = rp->render_pass; + fci.attachmentCount = fb->state.num_attachments; + fci.pAttachments = NULL; + fci.width = fb->state.width; + fci.height = fb->state.height; + fci.layers = fb->state.layers + 1; + + VkFramebufferAttachmentsCreateInfo attachments; + attachments.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO; + attachments.pNext = NULL; + attachments.attachmentImageInfoCount = fb->state.num_attachments; + attachments.pAttachmentImageInfos = fb->infos; + fci.pNext = &attachments; + + 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; +} + +static void +populate_attachment_info(VkFramebufferAttachmentImageInfo *att, struct zink_surface_info *info) +{ + att->sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO; + att->pNext = NULL; + memcpy(&att->flags, &info->flags, offsetof(struct zink_surface_info, format)); + att->viewFormatCount = 1; + att->pViewFormats = &info->format; +} + +static struct zink_framebuffer * +create_framebuffer_imageless(struct zink_context *ctx, struct zink_framebuffer_state *state) +{ + struct zink_screen *screen = zink_screen(ctx->base.screen); + struct zink_framebuffer *fb = rzalloc(ctx, struct zink_framebuffer); + if (!fb) + return NULL; + pipe_reference_init(&fb->reference, 1); + + 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)); + for (int i = 0; i < state->num_attachments; i++) + populate_attachment_info(&fb->infos[i], &fb->state.infos[i]); + + return fb; +fail: + zink_destroy_framebuffer(screen, fb); + return NULL; +} + +struct zink_framebuffer * +zink_get_framebuffer_imageless(struct zink_context *ctx) +{ + assert(zink_screen(ctx->base.screen)->info.have_KHR_imageless_framebuffer); + + struct zink_framebuffer_state state; + for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) { + struct pipe_surface *psurf = ctx->fb_state.cbufs[i]; + if (!psurf) + psurf = ctx->dummy_surface[util_logbase2_ceil(ctx->gfx_pipeline_state.rast_samples+1)]; + struct zink_surface *surface = zink_surface(psurf); + memcpy(&state.infos[i], &surface->info, sizeof(surface->info)); + } + + state.num_attachments = ctx->fb_state.nr_cbufs; + if (ctx->fb_state.zsbuf) { + struct pipe_surface *psurf = ctx->fb_state.zsbuf; + struct zink_surface *surface = zink_surface(psurf); + memcpy(&state.infos[state.num_attachments], &surface->info, sizeof(surface->info)); + state.num_attachments++; + } + + state.width = MAX2(ctx->fb_state.width, 1); + state.height = MAX2(ctx->fb_state.height, 1); + state.layers = MAX2(util_framebuffer_get_num_layers(&ctx->fb_state), 1) - 1; + state.samples = ctx->gfx_pipeline_state.rast_samples; + + struct zink_framebuffer *fb; + struct hash_entry *entry = _mesa_hash_table_search(&ctx->framebuffer_cache, &state); + if (entry) + return entry->data; + + fb = create_framebuffer_imageless(ctx, &state); + _mesa_hash_table_insert(&ctx->framebuffer_cache, &fb->state, fb); + + return fb; +} + +void zink_init_framebuffer(struct zink_screen *screen, struct zink_framebuffer *fb, struct zink_render_pass *rp) { VkFramebuffer ret; @@ -80,7 +201,7 @@ zink_init_framebuffer(struct zink_screen *screen, struct zink_framebuffer *fb, s fci.pAttachments = fb->state.attachments; fci.width = fb->state.width; fci.height = fb->state.height; - fci.layers = fb->state.layers; + fci.layers = fb->state.layers + 1; if (vkCreateFramebuffer(screen->dev, &fci, NULL, &ret) != VK_SUCCESS) return; @@ -100,10 +221,10 @@ out: fb->fb = ret; } -struct zink_framebuffer * -zink_create_framebuffer(struct zink_context *ctx, - struct zink_framebuffer_state *state, - struct pipe_surface **attachments) +static struct zink_framebuffer * +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); @@ -118,13 +239,11 @@ zink_create_framebuffer(struct zink_context *ctx, /* no ref! */ fb->surfaces[i] = attachments[i]; num_attachments++; + util_dynarray_append(&surf->framebuffer_refs, struct zink_framebuffer*, fb); } else { - if (!fb->null_surface) - fb->null_surface = zink_surface_create_null(ctx, PIPE_TEXTURE_2D, state->width, state->height, state->samples); - surf = zink_surface(fb->null_surface); - state->attachments[i] = zink_surface(fb->null_surface)->image_view; + surf = zink_surface(ctx->dummy_surface[util_logbase2_ceil(state->samples+1)]); + state->attachments[i] = surf->image_view; } - util_dynarray_append(&surf->framebuffer_refs, struct zink_framebuffer*, fb); } pipe_reference_init(&fb->reference, 1 + num_attachments); @@ -148,6 +267,9 @@ struct zink_framebuffer * zink_get_framebuffer(struct zink_context *ctx) { struct zink_screen *screen = zink_screen(ctx->base.screen); + + assert(!screen->info.have_KHR_imageless_framebuffer); + struct pipe_surface *attachments[PIPE_MAX_COLOR_BUFS + 1] = {0}; struct zink_framebuffer_state state = {0}; @@ -166,8 +288,8 @@ zink_get_framebuffer(struct zink_context *ctx) state.width = MAX2(ctx->fb_state.width, 1); state.height = MAX2(ctx->fb_state.height, 1); - state.layers = MAX2(util_framebuffer_get_num_layers(&ctx->fb_state), 1); - state.samples = ctx->fb_state.samples; + state.layers = MAX2(util_framebuffer_get_num_layers(&ctx->fb_state), 1) - 1; + state.samples = ctx->gfx_pipeline_state.rast_samples; struct zink_framebuffer *fb; simple_mtx_lock(&screen->framebuffer_mtx); @@ -182,7 +304,7 @@ zink_get_framebuffer(struct zink_context *ctx) * going to be bound; necessary to handle framebuffers which have no "real" attachments * and are only using null surfaces since the only ref they get is the extra one here */ - fb = zink_create_framebuffer(ctx, &state, attachments); + fb = create_framebuffer(ctx, &state, attachments); _mesa_hash_table_insert(&screen->framebuffer_cache, &fb->state, fb); } simple_mtx_unlock(&screen->framebuffer_mtx); diff --git a/src/gallium/drivers/zink/zink_framebuffer.h b/src/gallium/drivers/zink/zink_framebuffer.h index f2a23e4..4fb8bf6 100644 --- a/src/gallium/drivers/zink/zink_framebuffer.h +++ b/src/gallium/drivers/zink/zink_framebuffer.h @@ -36,10 +36,14 @@ struct zink_render_pass; struct zink_framebuffer_state { uint32_t width; - uint16_t height, layers; - uint8_t samples; - uint8_t num_attachments; - VkImageView attachments[PIPE_MAX_COLOR_BUFS + 1]; + uint16_t height; + uint32_t layers:6; + uint32_t samples:6; + uint32_t num_attachments:4; + union { + VkImageView attachments[PIPE_MAX_COLOR_BUFS + 1]; + struct zink_surface_info infos[PIPE_MAX_COLOR_BUFS + 1]; + }; }; struct zink_framebuffer { @@ -49,19 +53,18 @@ struct zink_framebuffer { 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; + union { + struct pipe_surface *surfaces[PIPE_MAX_COLOR_BUFS + 1]; + VkFramebufferAttachmentImageInfo infos[PIPE_MAX_COLOR_BUFS + 1]; + }; struct hash_table objects; }; -struct zink_framebuffer * -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_init_framebuffer_imageless(struct zink_screen *screen, struct zink_framebuffer *fb, struct zink_render_pass *rp); void zink_destroy_framebuffer(struct zink_screen *screen, @@ -88,5 +91,8 @@ zink_framebuffer_reference(struct zink_screen *screen, } struct zink_framebuffer * +zink_get_framebuffer_imageless(struct zink_context *ctx); + +struct zink_framebuffer * zink_get_framebuffer(struct zink_context *ctx); #endif diff --git a/src/gallium/drivers/zink/zink_screen.c b/src/gallium/drivers/zink/zink_screen.c index c99fd83..92a40de 100644 --- a/src/gallium/drivers/zink/zink_screen.c +++ b/src/gallium/drivers/zink/zink_screen.c @@ -1059,14 +1059,16 @@ zink_destroy_screen(struct pipe_screen *pscreen) zink_buffer_view_reference(screen, &bv, NULL); } - hash_table_foreach(&screen->framebuffer_cache, entry) { - struct zink_framebuffer* fb = (struct zink_framebuffer*)entry->data; - zink_destroy_framebuffer(screen, fb); + if (!screen->info.have_KHR_imageless_framebuffer) { + hash_table_foreach(&screen->framebuffer_cache, entry) { + struct zink_framebuffer* fb = (struct zink_framebuffer*)entry->data; + zink_destroy_framebuffer(screen, fb); + } + simple_mtx_destroy(&screen->framebuffer_mtx); } simple_mtx_destroy(&screen->surface_mtx); simple_mtx_destroy(&screen->bufferview_mtx); - simple_mtx_destroy(&screen->framebuffer_mtx); u_transfer_helper_destroy(pscreen->transfer_helper); #ifdef ENABLE_SHADER_CACHE @@ -1919,9 +1921,11 @@ zink_internal_create_screen(const struct pipe_screen_config *config) simple_mtx_init(&screen->surface_mtx, mtx_plain); simple_mtx_init(&screen->bufferview_mtx, mtx_plain); - simple_mtx_init(&screen->framebuffer_mtx, mtx_plain); - _mesa_hash_table_init(&screen->framebuffer_cache, screen, hash_framebuffer_state, equals_framebuffer_state); + if (!screen->info.have_KHR_imageless_framebuffer) { + simple_mtx_init(&screen->framebuffer_mtx, mtx_plain); + _mesa_hash_table_init(&screen->framebuffer_cache, screen, hash_framebuffer_state, equals_framebuffer_state); + } _mesa_hash_table_init(&screen->surface_cache, screen, NULL, equals_ivci); _mesa_hash_table_init(&screen->bufferview_cache, screen, NULL, equals_bvci); diff --git a/src/gallium/drivers/zink/zink_surface.c b/src/gallium/drivers/zink/zink_surface.c index 75b4103..233ec4c 100644 --- a/src/gallium/drivers/zink/zink_surface.c +++ b/src/gallium/drivers/zink/zink_surface.c @@ -222,11 +222,6 @@ surface_clear_fb_refs(struct zink_screen *screen, struct pipe_surface *psurface) simple_mtx_unlock(&screen->framebuffer_mtx); break; } - /* null surface doesn't get a ref but it will double-free - * if the pointer isn't unset - */ - if (fb->null_surface == psurface) - fb->null_surface = NULL; } } util_dynarray_fini(&surface->framebuffer_refs); @@ -242,7 +237,8 @@ zink_destroy_surface(struct zink_screen *screen, struct pipe_surface *psurface) assert(he->data == surface); _mesa_hash_table_remove(&screen->surface_cache, he); simple_mtx_unlock(&screen->surface_mtx); - surface_clear_fb_refs(screen, psurface); + if (!screen->info.have_KHR_imageless_framebuffer) + surface_clear_fb_refs(screen, psurface); zink_descriptor_set_refs_clear(&surface->desc_set_refs, surface); util_dynarray_fini(&surface->framebuffer_refs); pipe_resource_reference(&psurface->texture, NULL); -- 2.7.4