Reuse prepared shader bindings across draws and dispatches

This commit is contained in:
nmzik
2026-09-24 04:42:23 +04:00
parent 0382d0ca58
commit 3bd5de646d
5 changed files with 115 additions and 30 deletions
@@ -750,18 +750,27 @@ void RenderExecutor::ResetBindings() {
m_bound_images.clear();
}
PreparedBindings RenderExecutor::PrepareBindings(const ShaderStageRuntime& runtime) {
void RenderExecutor::PrepareBindings(const ShaderStageRuntime& runtime,
PreparedBindings& prepared) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(!runtime);
const auto& program = *runtime.program;
const auto& snapshot = *runtime.resources;
PreparedBindings prepared;
prepared.runtime = &runtime;
prepared.images.reserve(program.info.images.size());
prepared.gds = {nullptr, 0, VK_WHOLE_SIZE};
prepared.flattened_srt = {};
prepared.shader_data_buffer = {};
prepared.buffer_sources.clear();
prepared.buffers.clear();
prepared.images.resize(program.info.images.size());
prepared.samplers.clear();
prepared.shader_data.clear();
for (uint32_t i = 0; i < program.info.images.size(); i++) {
auto binding = ResolveTexture(program.info.images[i], snapshot.images[i]);
BindImage(binding.image_id, binding.desc.type == TextureCache::BindingType::Storage);
prepared.images.push_back(std::move(binding));
binding.mip_views.swap(prepared.images[i].mip_views);
binding.mip_views.clear();
prepared.images[i] = std::move(binding);
}
prepared.samplers.reserve(program.info.samplers.size());
for (uint32_t i = 0; i < program.info.samplers.size(); i++) {
@@ -776,7 +785,6 @@ PreparedBindings RenderExecutor::PrepareBindings(const ShaderStageRuntime& runti
program.bindings, ShaderRecompiler::IR::DescriptorBindingKind::Gds) != nullptr) {
prepared.gds.buffer = m_context.GetBufferCache().GetGdsBuffer()->Handle();
}
return prepared;
}
void RenderExecutor::FindBuffers(PreparedBindings& prepared) {
+3 -1
View File
@@ -160,7 +160,7 @@ public:
void DispatchIndirect(uint64_t submit_id, CommandBuffer& buffer, uint64_t args_addr,
uint32_t mode);
[[nodiscard]] PreparedBindings PrepareBindings(const ShaderStageRuntime& runtime);
void PrepareBindings(const ShaderStageRuntime& runtime, PreparedBindings& prepared);
void FindBuffers(PreparedBindings& bindings);
void RebindBuffers(PreparedBindings& bindings);
void RebindImages(PreparedBindings& bindings);
@@ -210,6 +210,8 @@ private:
uint32_t group_y, uint32_t group_z, uint32_t mode);
RenderContext& m_context;
GraphicsBindings m_graphics_bindings;
PreparedBindings m_compute_bindings;
std::vector<ImageId> m_bound_images;
std::vector<vk::DescriptorBufferInfo> m_descriptor_buffers;
std::vector<vk::DescriptorImageInfo> m_descriptor_images;
@@ -362,7 +362,8 @@ void RenderExecutor::DispatchDirect(uint64_t submit_id, CommandBuffer& buffer,
buffer.EndRendering();
auto& pipeline =
m_context.GetPipelineCache().GetComputePipeline(input_info, compute_program);
auto bindings = PrepareBindings(input_info.stage);
auto& bindings = m_compute_bindings;
PrepareBindings(input_info.stage, bindings);
FindBuffers(bindings);
if (program.info.uses_dma) {
m_context.PrepareBda();
@@ -414,7 +415,8 @@ void RenderExecutor::DispatchIndirect(uint64_t submit_id, CommandBuffer& buffer,
cs_regs, buffer.GetRegisters().GetShaderRegisters(), input_info);
buffer.EndRendering();
auto& pipeline = m_context.GetPipelineCache().GetComputePipeline(input_info, compute_program);
auto bindings = PrepareBindings(input_info.stage);
auto& bindings = m_compute_bindings;
PrepareBindings(input_info.stage, bindings);
FindBuffers(bindings);
const auto& program = *input_info.stage.program;
if (program.info.uses_dma) {
@@ -1076,15 +1076,16 @@ void RenderExecutor::ExecutePreparedDraw(uint64_t submit_id, CommandBuffer& buff
index_source.guest_element_size);
}
LogDrawPhase(draw.Name(), "PrepareBindings");
GraphicsBindings bindings;
auto& bindings = m_graphics_bindings;
std::array<PreparedBindings*, 4> descriptor_stages {};
uint32_t stage_count = 0;
for (uint32_t i = 0; i < vertex_stages.size(); i++) {
bindings.vertex[i] = PrepareBindings(state.vertex_info[i].stage);
PrepareBindings(state.vertex_info[i].stage, bindings.vertex[i]);
descriptor_stages[stage_count++] = &bindings.vertex[i];
}
if (state.ps_active) {
bindings.pixel.emplace(PrepareBindings(state.ps_input_info.stage));
if (!bindings.pixel) bindings.pixel.emplace();
PrepareBindings(state.ps_input_info.stage, *bindings.pixel);
descriptor_stages[stage_count++] = &*bindings.pixel;
}
const auto stages = std::span {descriptor_stages.data(), stage_count};
@@ -1116,7 +1117,7 @@ void RenderExecutor::ExecutePreparedDraw(uint64_t submit_id, CommandBuffer& buff
if (!mesh_active) {
CommitVertexBuffers(vk_buffer, vertex_bindings);
}
if (bindings.pixel && !draw.IsIndexed()) {
if (state.ps_active && !draw.IsIndexed()) {
SetDrawDebugPhase(buffer, submit_id, draw, 0x300u);
}
CommitBindings(buffer, vk::PipelineBindPoint::eGraphics, pipeline, stages);