diff --git a/src/gallium/drivers/zink/zink_context.c b/src/gallium/drivers/zink/zink_context.c index 260a6da7ac6..e1e7c9ccb98 100644 --- a/src/gallium/drivers/zink/zink_context.c +++ b/src/gallium/drivers/zink/zink_context.c @@ -1996,13 +1996,155 @@ zink_update_vk_sample_locations(struct zink_context *ctx) } } +static unsigned +find_rp_state(struct zink_context *ctx) +{ + bool found = false; + struct set_entry *he = _mesa_set_search_or_add(&ctx->rendering_state_cache, &ctx->gfx_pipeline_state.rendering_info, &found); + struct zink_rendering_info *info; + if (found) { + info = (void*)he->key; + return info->id; + } + info = ralloc(ctx, struct zink_rendering_info); + memcpy(info, &ctx->gfx_pipeline_state.rendering_info, sizeof(VkPipelineRenderingCreateInfo)); + info->id = ctx->rendering_state_cache.entries; + he->key = info; + return info->id; +} + +static unsigned +begin_rendering(struct zink_context *ctx) +{ + unsigned clear_buffers = 0; + ctx->gfx_pipeline_state.render_pass = NULL; + zink_update_vk_sample_locations(ctx); + zink_render_update_swapchain(ctx); + bool has_depth = false; + bool has_stencil = false; + if (ctx->rp_changed) { + /* init imageviews, base loadOp, formats */ + for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) { + struct zink_surface *surf = zink_csurface(ctx->fb_state.cbufs[i]); + VkImageView iv = zink_prep_fb_attachment(ctx, surf, i); + if (!iv) + /* dead swapchain */ + return 0; + ctx->dynamic_fb.attachments[i].imageView = iv; + ctx->dynamic_fb.attachments[i].loadOp = !surf || (surf->is_swapchain && ctx->new_swapchain) ? + VK_ATTACHMENT_LOAD_OP_DONT_CARE : + VK_ATTACHMENT_LOAD_OP_LOAD; + ctx->gfx_pipeline_state.rendering_formats[i] = surf ? surf->info.format[0] : VK_FORMAT_R8G8B8A8_UNORM; + } + + /* unset depth and stencil info: reset below */ + ctx->dynamic_fb.info.pDepthAttachment = NULL; + ctx->gfx_pipeline_state.rendering_info.depthAttachmentFormat = VK_FORMAT_UNDEFINED; + ctx->dynamic_fb.info.pStencilAttachment = NULL; + ctx->gfx_pipeline_state.rendering_info.stencilAttachmentFormat = VK_FORMAT_UNDEFINED; + + if (ctx->fb_state.zsbuf) { + struct zink_surface *surf = zink_csurface(ctx->fb_state.zsbuf); + has_depth = util_format_has_depth(util_format_description(ctx->fb_state.zsbuf->format)); + has_stencil = util_format_has_stencil(util_format_description(ctx->fb_state.zsbuf->format)); + VkImageView iv = zink_prep_fb_attachment(ctx, surf, ctx->fb_state.nr_cbufs); + + /* depth may or may not be used but init it anyway */ + ctx->dynamic_fb.attachments[PIPE_MAX_COLOR_BUFS].imageView = iv; + ctx->dynamic_fb.attachments[PIPE_MAX_COLOR_BUFS].imageLayout = zink_resource(surf->base.texture)->layout; + ctx->dynamic_fb.attachments[PIPE_MAX_COLOR_BUFS].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + + /* stencil may or may not be used but init it anyway */ + ctx->dynamic_fb.attachments[PIPE_MAX_COLOR_BUFS+1].imageView = iv; + ctx->dynamic_fb.attachments[PIPE_MAX_COLOR_BUFS+1].imageLayout = zink_resource(surf->base.texture)->layout; + ctx->dynamic_fb.attachments[PIPE_MAX_COLOR_BUFS+1].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + + if (has_depth) { + ctx->dynamic_fb.info.pDepthAttachment = &ctx->dynamic_fb.attachments[PIPE_MAX_COLOR_BUFS]; + ctx->gfx_pipeline_state.rendering_info.depthAttachmentFormat = surf->info.format[0]; + /* stencil info only set for clears below */ + } + if (has_stencil) { + /* must be stencil-only */ + ctx->dynamic_fb.info.pStencilAttachment = &ctx->dynamic_fb.attachments[PIPE_MAX_COLOR_BUFS + 1]; + ctx->gfx_pipeline_state.rendering_info.stencilAttachmentFormat = surf->info.format[0]; + } + } else { + ctx->dynamic_fb.info.pDepthAttachment = NULL; + ctx->gfx_pipeline_state.rendering_info.depthAttachmentFormat = VK_FORMAT_UNDEFINED; + } + } + + /* similar to begin_render_pass(), but just filling in VkRenderingInfo */ + for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) { + /* these are no-ops */ + if (!ctx->fb_state.cbufs[i] || !zink_fb_clear_enabled(ctx, i)) + continue; + /* these need actual clear calls inside the rp */ + struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(&ctx->fb_clears[i], 0); + if (zink_fb_clear_needs_explicit(&ctx->fb_clears[i])) { + clear_buffers |= (PIPE_CLEAR_COLOR0 << i); + if (zink_fb_clear_count(&ctx->fb_clears[i]) < 2 || + zink_fb_clear_element_needs_explicit(clear)) + continue; + } + /* we now know there's one clear that can be done here */ + zink_fb_clear_util_unpack_clear_color(clear, ctx->fb_state.cbufs[i]->format, (void*)&ctx->dynamic_fb.attachments[i].clearValue); + ctx->dynamic_fb.attachments[i].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + } + if (ctx->fb_state.zsbuf && zink_fb_clear_enabled(ctx, PIPE_MAX_COLOR_BUFS)) { + struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[PIPE_MAX_COLOR_BUFS]; + struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(fb_clear, 0); + if (!zink_fb_clear_element_needs_explicit(clear)) { + /* base zs clear info */ + ctx->dynamic_fb.attachments[PIPE_MAX_COLOR_BUFS].clearValue.depthStencil.depth = clear->zs.depth; + ctx->dynamic_fb.attachments[PIPE_MAX_COLOR_BUFS].clearValue.depthStencil.stencil = clear->zs.stencil; + /* always init separate stencil attachment */ + ctx->dynamic_fb.attachments[PIPE_MAX_COLOR_BUFS+1].clearValue.depthStencil.stencil = clear->zs.stencil; + if ((zink_fb_clear_element(fb_clear, 0)->zs.bits & PIPE_CLEAR_DEPTH)) + /* initiate a depth clear */ + ctx->dynamic_fb.attachments[PIPE_MAX_COLOR_BUFS].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + if ((zink_fb_clear_element(fb_clear, 0)->zs.bits & PIPE_CLEAR_STENCIL)) { + /* use a stencil clear, also set stencil attachment */ + ctx->dynamic_fb.attachments[PIPE_MAX_COLOR_BUFS+1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + } + } + if (zink_fb_clear_needs_explicit(fb_clear)) { + for (int j = !zink_fb_clear_element_needs_explicit(clear); + (clear_buffers & PIPE_CLEAR_DEPTHSTENCIL) != PIPE_CLEAR_DEPTHSTENCIL && j < zink_fb_clear_count(fb_clear); + j++) + clear_buffers |= zink_fb_clear_element(fb_clear, j)->zs.bits; + } + } + /* validate zs VUs: attachment must be null or format must be valid */ + assert(!ctx->dynamic_fb.info.pDepthAttachment || ctx->gfx_pipeline_state.rendering_info.depthAttachmentFormat); + assert(!ctx->dynamic_fb.info.pStencilAttachment || ctx->gfx_pipeline_state.rendering_info.stencilAttachmentFormat); + + /* update pipeline info id for compatibility VUs */ + unsigned rp_state = find_rp_state(ctx); + ctx->gfx_pipeline_state.dirty |= ctx->gfx_pipeline_state.rp_state != rp_state; + ctx->gfx_pipeline_state.rp_state = rp_state; + + VKCTX(CmdBeginRendering)(ctx->batch.state->cmdbuf, &ctx->dynamic_fb.info); + ctx->batch.in_rp = true; + ctx->new_swapchain = false; + return clear_buffers; +} + void zink_batch_rp(struct zink_context *ctx) { if (ctx->batch.in_rp) return; unsigned clear_buffers; - clear_buffers = zink_begin_render_pass(ctx); + /* use renderpass for multisample-to-singlesample or fbfetch: + * - msrtss is TODO + * - dynamic rendering doesn't have input attachments + */ + if (!zink_screen(ctx->base.screen)->info.have_KHR_dynamic_rendering || ctx->transient_attachments || ctx->fbfetch_outputs) + clear_buffers = zink_begin_render_pass(ctx); + else + clear_buffers = begin_rendering(ctx); if (!ctx->batch.in_rp) return; //dead swapchain if (ctx->render_condition.query) @@ -2019,6 +2161,10 @@ zink_batch_no_rp(struct zink_context *ctx) zink_stop_conditional_render(ctx); if (ctx->gfx_pipeline_state.render_pass) zink_end_render_pass(ctx); + else { + VKCTX(CmdEndRendering)(ctx->batch.state->cmdbuf); + ctx->batch.in_rp = false; + } assert(!ctx->batch.in_rp); } @@ -2044,8 +2190,18 @@ zink_prep_fb_attachment(struct zink_context *ctx, struct zink_surface *surf, uns if (!i) zink_update_fbfetch(ctx); } - VkImageLayout layout = zink_render_pass_attachment_get_barrier_info(&ctx->gfx_pipeline_state.render_pass->state.rts[i], - i < ctx->fb_state.nr_cbufs, &pipeline, &access); + VkImageLayout layout; + if (ctx->gfx_pipeline_state.render_pass) { + layout = zink_render_pass_attachment_get_barrier_info(&ctx->gfx_pipeline_state.render_pass->state.rts[i], + i < ctx->fb_state.nr_cbufs, &pipeline, &access); + } else { + struct zink_rt_attrib rt; + if (i < ctx->fb_state.nr_cbufs) + zink_init_color_attachment(ctx, i, &rt); + else + zink_init_zs_attachment(ctx, &rt); + layout = zink_render_pass_attachment_get_barrier_info(&rt, i < ctx->fb_state.nr_cbufs, &pipeline, &access); + } zink_resource_image_barrier(ctx, res, layout, access, pipeline); if (i == ctx->fb_state.nr_cbufs && res->bind_count[0] && res->bind_count[0] != res->image_bind_count[0]) { unsigned find = res->bind_count[0] - res->image_bind_count[0]; @@ -2060,6 +2216,35 @@ zink_prep_fb_attachment(struct zink_context *ctx, struct zink_surface *surf, uns return surf->image_view; } +static uint32_t +hash_rendering_state(const void *key) +{ + const VkPipelineRenderingCreateInfo *info = key; + uint32_t hash = 0; + /* + uint32_t colorAttachmentCount; + const VkFormat* pColorAttachmentFormats; + VkFormat depthAttachmentFormat; + VkFormat stencilAttachmentFormat; + * this data is not optimally arranged, so it must be manually hashed + */ + hash = XXH32(&info->colorAttachmentCount, sizeof(uint32_t), hash); + hash = XXH32(&info->depthAttachmentFormat, sizeof(uint32_t), hash); + hash = XXH32(&info->stencilAttachmentFormat, sizeof(VkFormat), hash); + return XXH32(info->pColorAttachmentFormats, sizeof(VkFormat) * info->colorAttachmentCount, hash); +} + +static bool +equals_rendering_state(const void *a, const void *b) +{ + const VkPipelineRenderingCreateInfo *ai = a; + const VkPipelineRenderingCreateInfo *bi = b; + return ai->colorAttachmentCount == bi->colorAttachmentCount && + ai->depthAttachmentFormat == bi->depthAttachmentFormat && + ai->stencilAttachmentFormat == bi->stencilAttachmentFormat && + !memcmp(ai->pColorAttachmentFormats, bi->pColorAttachmentFormats, sizeof(VkFormat) * ai->colorAttachmentCount); +} + static uint32_t hash_framebuffer_imageless(const void *key) { @@ -2310,6 +2495,7 @@ rebind_fb_state(struct zink_context *ctx, struct zink_resource *match_res, bool static void unbind_fb_surface(struct zink_context *ctx, struct pipe_surface *surf, unsigned idx, bool changed) { + ctx->dynamic_fb.attachments[idx].imageView = VK_NULL_HANDLE; if (!surf) return; struct zink_surface *transient = zink_transient_surface(surf); @@ -2398,6 +2584,16 @@ zink_set_framebuffer_state(struct pipe_context *pctx, ctx->gfx_pipeline_state.void_alpha_attachments = 0; ctx->transient_attachments = 0; + ctx->dynamic_fb.info.renderArea.offset.x = 0; + ctx->dynamic_fb.info.renderArea.offset.y = 0; + ctx->dynamic_fb.info.renderArea.extent.width = state->width; + ctx->dynamic_fb.info.renderArea.extent.height = state->height; + ctx->dynamic_fb.info.colorAttachmentCount = ctx->fb_state.nr_cbufs; + unsigned layers = util_framebuffer_get_num_layers(state); + ctx->rp_changed |= ctx->dynamic_fb.info.layerCount != layers; + ctx->dynamic_fb.info.layerCount = layers; + ctx->gfx_pipeline_state.rendering_info.colorAttachmentCount = ctx->fb_state.nr_cbufs; + for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) { struct pipe_surface *psurf = ctx->fb_state.cbufs[i]; if (psurf) { @@ -4011,6 +4207,17 @@ zink_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags) _mesa_hash_table_init(&ctx->framebuffer_cache, ctx, hash_framebuffer_imageless, equals_framebuffer_imageless); if (!zink_init_render_pass(ctx)) goto fail; + _mesa_set_init(&ctx->rendering_state_cache, ctx, hash_rendering_state, equals_rendering_state); + ctx->dynamic_fb.info.pColorAttachments = ctx->dynamic_fb.attachments; + ctx->dynamic_fb.info.sType = VK_STRUCTURE_TYPE_RENDERING_INFO; + for (unsigned i = 0; i < ARRAY_SIZE(ctx->dynamic_fb.attachments); i++) { + VkRenderingAttachmentInfo *att = &ctx->dynamic_fb.attachments[i]; + att->sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO; + att->imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + att->storeOp = VK_ATTACHMENT_STORE_OP_STORE; + } + ctx->gfx_pipeline_state.rendering_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO; + ctx->gfx_pipeline_state.rendering_info.pColorAttachmentFormats = ctx->gfx_pipeline_state.rendering_formats; const uint32_t data[] = {0}; if (!is_copy_only) { diff --git a/src/gallium/drivers/zink/zink_context.h b/src/gallium/drivers/zink/zink_context.h index 895687098df..4960282c90b 100644 --- a/src/gallium/drivers/zink/zink_context.h +++ b/src/gallium/drivers/zink/zink_context.h @@ -152,6 +152,11 @@ struct zink_bindless_descriptor { uint32_t access; //PIPE_ACCESS_... }; +struct zink_rendering_info { + VkPipelineRenderingCreateInfo info; + unsigned id; +}; + static inline struct zink_resource * zink_descriptor_surface_resource(struct zink_descriptor_surface *ds) { @@ -249,6 +254,11 @@ struct zink_context { unsigned dirty_shader_stages : 6; /* mask of changed shader stages */ bool last_vertex_stage_dirty; + struct { + VkRenderingAttachmentInfo attachments[PIPE_MAX_COLOR_BUFS + 2]; //+depth, +stencil + VkRenderingInfo info; + } dynamic_fb; + struct set rendering_state_cache; struct set render_pass_state_cache; struct hash_table *render_pass_cache; bool new_swapchain; diff --git a/src/gallium/drivers/zink/zink_device_info.py b/src/gallium/drivers/zink/zink_device_info.py index 8e96979f8ff..db80f70baeb 100644 --- a/src/gallium/drivers/zink/zink_device_info.py +++ b/src/gallium/drivers/zink/zink_device_info.py @@ -150,6 +150,9 @@ EXTENSIONS = [ Extension("VK_NV_linear_color_attachment", alias="linear_color", features=True), + Extension("VK_KHR_dynamic_rendering", + alias="dynamic_render", + features=True), Extension("VK_KHR_shader_clock", alias="shader_clock", features=True, diff --git a/src/gallium/drivers/zink/zink_pipeline.c b/src/gallium/drivers/zink/zink_pipeline.c index b00b47ad0fd..e34ecac0c5d 100644 --- a/src/gallium/drivers/zink/zink_pipeline.c +++ b/src/gallium/drivers/zink/zink_pipeline.c @@ -108,8 +108,10 @@ zink_create_gfx_pipeline(struct zink_screen *screen, VkPipelineColorBlendStateCreateInfo blend_state = {0}; blend_state.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; if (state->blend_state) { - unsigned num_attachments = state->render_pass->state.num_rts; - if (state->render_pass->state.have_zsbuf) + unsigned num_attachments = state->render_pass ? + state->render_pass->state.num_rts : + state->rendering_info.colorAttachmentCount; + if (state->render_pass && state->render_pass->state.have_zsbuf) num_attachments--; if (state->void_alpha_attachments) { for (unsigned i = 0; i < num_attachments; i++) { @@ -315,7 +317,10 @@ zink_create_gfx_pipeline(struct zink_screen *screen, VkGraphicsPipelineCreateInfo pci = {0}; pci.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; pci.layout = prog->base.layout; - pci.renderPass = state->render_pass->render_pass; + if (state->render_pass) + pci.renderPass = state->render_pass->render_pass; + else + pci.pNext = &state->rendering_info; if (!screen->info.have_EXT_vertex_input_dynamic_state || !state->element_state->num_attribs) pci.pVertexInputState = &vertex_input_state; pci.pInputAssemblyState = &primitive_state; diff --git a/src/gallium/drivers/zink/zink_pipeline.h b/src/gallium/drivers/zink/zink_pipeline.h index 72807d943a4..4964464cf77 100644 --- a/src/gallium/drivers/zink/zink_pipeline.h +++ b/src/gallium/drivers/zink/zink_pipeline.h @@ -86,6 +86,8 @@ struct zink_gfx_pipeline_state { } shader_keys; struct zink_blend_state *blend_state; struct zink_render_pass *render_pass; + VkFormat rendering_formats[PIPE_MAX_COLOR_BUFS]; + VkPipelineRenderingCreateInfo rendering_info; VkPipeline pipeline; unsigned idx : 8; enum pipe_prim_type gfx_prim_mode; //pending mode diff --git a/src/gallium/drivers/zink/zink_program.c b/src/gallium/drivers/zink/zink_program.c index 38e1f5c775f..1c56255e546 100644 --- a/src/gallium/drivers/zink/zink_program.c +++ b/src/gallium/drivers/zink/zink_program.c @@ -242,6 +242,9 @@ equals_gfx_pipeline_state(const void *a, const void *b) const struct zink_gfx_pipeline_state *sb = b; if (sa->uses_dynamic_stride != sb->uses_dynamic_stride) return false; + /* dynamic vs rp */ + if (!!sa->render_pass != !!sb->render_pass) + return false; if (!sa->have_EXT_extended_dynamic_state || !sa->uses_dynamic_stride) { if (sa->vertex_buffers_enabled_mask != sb->vertex_buffers_enabled_mask) return false;