/* Copyright (c) 2019-2025, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 the "License"; * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "resource_replay.h" #include "common/vk_common.h" #include "core/util/logging.hpp" #include "rendering/pipeline_state.h" #include "resource_cache.h" namespace vkb { namespace { inline void read_subpass_info(std::istringstream &is, std::vector &value) { std::size_t size; read(is, size); value.resize(size); for (SubpassInfo &subpass : value) { read(is, subpass.input_attachments); read(is, subpass.output_attachments); } } } // namespace ResourceReplay::ResourceReplay() { stream_resources[ResourceType::ShaderModule] = std::bind(&ResourceReplay::create_shader_module, this, std::placeholders::_1, std::placeholders::_2); stream_resources[ResourceType::PipelineLayout] = std::bind(&ResourceReplay::create_pipeline_layout, this, std::placeholders::_1, std::placeholders::_2); stream_resources[ResourceType::RenderPass] = std::bind(&ResourceReplay::create_render_pass, this, std::placeholders::_1, std::placeholders::_2); stream_resources[ResourceType::GraphicsPipeline] = std::bind(&ResourceReplay::create_graphics_pipeline, this, std::placeholders::_1, std::placeholders::_2); } void ResourceReplay::play(ResourceCache &resource_cache, ResourceRecord &recorder) { std::istringstream stream{recorder.get_stream().str()}; while (true) { // Read command id ResourceType resource_type; read(stream, resource_type); if (stream.eof()) { break; } // Find command function for the given command id auto cmd_it = stream_resources.find(resource_type); // Check if command replayer supports the given command if (cmd_it != stream_resources.end()) { // Run command function cmd_it->second(resource_cache, stream); } else { LOGE("Replay command not supported."); } } } void ResourceReplay::create_shader_module(ResourceCache &resource_cache, std::istringstream &stream) { VkShaderStageFlagBits stage{}; std::string glsl_source; std::string entry_point; read(stream, stage, glsl_source, entry_point); ShaderSource shader_source{}; shader_source.set_source(std::move(glsl_source)); ShaderVariant shader_variant; auto &shader_module = resource_cache.request_shader_module(stage, shader_source, shader_variant); shader_modules.push_back(&shader_module); } void ResourceReplay::create_pipeline_layout(ResourceCache &resource_cache, std::istringstream &stream) { std::vector shader_indices; read(stream, shader_indices); std::vector shader_stages(shader_indices.size()); std::transform(shader_indices.begin(), shader_indices.end(), shader_stages.begin(), [&](size_t shader_index) { assert(shader_index < shader_modules.size()); return shader_modules[shader_index]; }); auto &pipeline_layout = resource_cache.request_pipeline_layout(shader_stages); pipeline_layouts.push_back(&pipeline_layout); } void ResourceReplay::create_render_pass(ResourceCache &resource_cache, std::istringstream &stream) { std::vector attachments; std::vector load_store_infos; std::vector subpasses; read(stream, attachments, load_store_infos); read_subpass_info(stream, subpasses); auto &render_pass = resource_cache.request_render_pass(attachments, load_store_infos, subpasses); render_passes.push_back(&render_pass); } void ResourceReplay::create_graphics_pipeline(ResourceCache &resource_cache, std::istringstream &stream) { size_t pipeline_layout_index{}; size_t render_pass_index{}; uint32_t subpass_index{}; read(stream, pipeline_layout_index, render_pass_index, subpass_index); std::map> specialization_constant_state{}; read(stream, specialization_constant_state); VertexInputState vertex_input_state{}; read(stream, vertex_input_state.attributes, vertex_input_state.bindings); InputAssemblyState input_assembly_state{}; RasterizationState rasterization_state{}; ViewportState viewport_state{}; MultisampleState multisample_state{}; DepthStencilState depth_stencil_state{}; read(stream, input_assembly_state, rasterization_state, viewport_state, multisample_state, depth_stencil_state); ColorBlendState color_blend_state{}; read(stream, color_blend_state.logic_op, color_blend_state.logic_op_enable, color_blend_state.attachments); PipelineState pipeline_state{}; assert(pipeline_layout_index < pipeline_layouts.size()); pipeline_state.set_pipeline_layout(*pipeline_layouts[pipeline_layout_index]); assert(render_pass_index < render_passes.size()); pipeline_state.set_render_pass(*render_passes[render_pass_index]); for (auto &item : specialization_constant_state) { pipeline_state.set_specialization_constant(item.first, item.second); } pipeline_state.set_subpass_index(subpass_index); pipeline_state.set_vertex_input_state(vertex_input_state); pipeline_state.set_input_assembly_state(input_assembly_state); pipeline_state.set_rasterization_state(rasterization_state); pipeline_state.set_viewport_state(viewport_state); pipeline_state.set_multisample_state(multisample_state); pipeline_state.set_depth_stencil_state(depth_stencil_state); pipeline_state.set_color_blend_state(color_blend_state); auto &graphics_pipeline = resource_cache.request_graphics_pipeline(pipeline_state); graphics_pipelines.push_back(&graphics_pipeline); } } // namespace vkb