/* Copyright (c) 2023-2025, NVIDIA CORPORATION. All rights reserved. * * 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. */ #pragma once #include "common/hpp_vk_common.h" #include "core/hpp_descriptor_set.h" #include "core/hpp_image_view.h" #include "core/hpp_render_pass.h" #include "core/hpp_shader_module.h" #include "hpp_resource_record.h" #include "rendering/hpp_render_target.h" #include "resource_caching.h" #include namespace std { template struct hash> { size_t operator()(std::map const &bindings) const { size_t result = 0; vkb::hash_combine(result, bindings.size()); for (auto const &binding : bindings) { vkb::hash_combine(result, binding.first); vkb::hash_combine(result, binding.second); } return result; } }; template struct hash> { size_t operator()(std::vector const &values) const { size_t result = 0; vkb::hash_combine(result, values.size()); for (auto const &value : values) { vkb::hash_combine(result, value); } return result; } }; template <> struct hash { size_t operator()(vkb::common::HPPLoadStoreInfo const &lsi) const { size_t result = 0; vkb::hash_combine(result, lsi.load_op); vkb::hash_combine(result, lsi.store_op); return result; } }; template struct hash> { size_t operator()(const vkb::core::VulkanResource &vulkan_resource) const { return std::hash()(vulkan_resource.get_handle()); } }; template <> struct hash { size_t operator()(const vkb::core::HPPDescriptorPool &descriptor_pool) const { return std::hash()(reinterpret_cast(descriptor_pool)); } }; template <> struct hash { size_t operator()(vkb::core::HPPDescriptorSet &descriptor_set) const { size_t result = 0; vkb::hash_combine(result, descriptor_set.get_layout()); // descriptor_pool ? vkb::hash_combine(result, descriptor_set.get_buffer_infos()); vkb::hash_combine(result, descriptor_set.get_image_infos()); vkb::hash_combine(result, descriptor_set.get_handle()); // write_descriptor_sets ? return result; } }; template <> struct hash { size_t operator()(const vkb::core::HPPDescriptorSetLayout &descriptor_set_layout) const { return std::hash()(reinterpret_cast(descriptor_set_layout)); } }; template <> struct hash { size_t operator()(const vkb::core::HPPImage &image) const { size_t result = 0; vkb::hash_combine(result, image.get_memory()); vkb::hash_combine(result, image.get_type()); vkb::hash_combine(result, image.get_extent()); vkb::hash_combine(result, image.get_format()); vkb::hash_combine(result, image.get_usage()); vkb::hash_combine(result, image.get_sample_count()); vkb::hash_combine(result, image.get_tiling()); vkb::hash_combine(result, image.get_subresource()); vkb::hash_combine(result, image.get_array_layer_count()); return result; } }; template <> struct hash { size_t operator()(const vkb::core::HPPImageView &image_view) const { size_t result = std::hash>()(image_view); vkb::hash_combine(result, image_view.get_image()); vkb::hash_combine(result, image_view.get_format()); vkb::hash_combine(result, image_view.get_subresource_range()); return result; } }; template <> struct hash { size_t operator()(const vkb::core::HPPRenderPass &render_pass) const { return std::hash()(reinterpret_cast(render_pass)); } }; template <> struct hash { size_t operator()(const vkb::core::HPPShaderModule &shader_module) const { return std::hash()(reinterpret_cast(shader_module)); } }; template <> struct hash { size_t operator()(vkb::core::HPPShaderResource const &shader_resource) const { size_t result = 0; vkb::hash_combine(result, shader_resource.stages); vkb::hash_combine(result, shader_resource.type); vkb::hash_combine(result, shader_resource.mode); vkb::hash_combine(result, shader_resource.set); vkb::hash_combine(result, shader_resource.binding); vkb::hash_combine(result, shader_resource.location); vkb::hash_combine(result, shader_resource.input_attachment_index); vkb::hash_combine(result, shader_resource.vec_size); vkb::hash_combine(result, shader_resource.columns); vkb::hash_combine(result, shader_resource.array_size); vkb::hash_combine(result, shader_resource.offset); vkb::hash_combine(result, shader_resource.size); vkb::hash_combine(result, shader_resource.constant_id); vkb::hash_combine(result, shader_resource.qualifiers); vkb::hash_combine(result, shader_resource.name); return result; } }; template <> struct hash { size_t operator()(const vkb::core::HPPShaderSource &shader_source) const { return std::hash()(reinterpret_cast(shader_source)); } }; template <> struct hash { size_t operator()(const vkb::core::HPPShaderVariant &shader_variant) const { return std::hash()(reinterpret_cast(shader_variant)); } }; template <> struct hash { size_t operator()(vkb::core::HPPSubpassInfo const &subpass_info) const { size_t result = 0; vkb::hash_combine(result, subpass_info.input_attachments); vkb::hash_combine(result, subpass_info.output_attachments); vkb::hash_combine(result, subpass_info.color_resolve_attachments); vkb::hash_combine(result, subpass_info.disable_depth_stencil_attachment); vkb::hash_combine(result, subpass_info.depth_stencil_resolve_attachment); vkb::hash_combine(result, subpass_info.depth_stencil_resolve_mode); vkb::hash_combine(result, subpass_info.debug_name); return result; } }; template <> struct hash { size_t operator()(const vkb::rendering::HPPAttachment &attachment) const { size_t result = 0; vkb::hash_combine(result, attachment.format); vkb::hash_combine(result, attachment.samples); vkb::hash_combine(result, attachment.usage); vkb::hash_combine(result, attachment.initial_layout); return result; } }; template <> struct hash { size_t operator()(const vkb::rendering::HPPPipelineState &pipeline_state) const { return std::hash()(reinterpret_cast(pipeline_state)); } }; template <> struct hash { size_t operator()(const vkb::rendering::HPPRenderTarget &render_target) const { size_t result = 0; vkb::hash_combine(result, render_target.get_extent()); for (auto const &view : render_target.get_views()) { vkb::hash_combine(result, view); } for (auto const &attachment : render_target.get_attachments()) { vkb::hash_combine(result, attachment); } for (auto const &input : render_target.get_input_attachments()) { vkb::hash_combine(result, input); } for (auto const &output : render_target.get_output_attachments()) { vkb::hash_combine(result, output); } return result; } }; } // namespace std namespace vkb { namespace common { /** * @brief facade helper functions and structs around the functions and structs in common/resource_caching, providing a vulkan.hpp-based interface */ namespace { template struct HPPRecordHelper { size_t record(HPPResourceRecord & /*recorder*/, A &.../*args*/) { return 0; } void index(HPPResourceRecord & /*recorder*/, size_t /*index*/, T & /*resource*/) {} }; template struct HPPRecordHelper { size_t record(HPPResourceRecord &recorder, A &...args) { return recorder.register_shader_module(args...); } void index(HPPResourceRecord &recorder, size_t index, vkb::core::HPPShaderModule &shader_module) { recorder.set_shader_module(index, shader_module); } }; template struct HPPRecordHelper { size_t record(HPPResourceRecord &recorder, A &...args) { return recorder.register_pipeline_layout(args...); } void index(HPPResourceRecord &recorder, size_t index, vkb::core::HPPPipelineLayout &pipeline_layout) { recorder.set_pipeline_layout(index, pipeline_layout); } }; template struct HPPRecordHelper { size_t record(HPPResourceRecord &recorder, A &...args) { return recorder.register_render_pass(args...); } void index(HPPResourceRecord &recorder, size_t index, vkb::core::HPPRenderPass &render_pass) { recorder.set_render_pass(index, render_pass); } }; template struct HPPRecordHelper { size_t record(HPPResourceRecord &recorder, A &...args) { return recorder.register_graphics_pipeline(args...); } void index(HPPResourceRecord &recorder, size_t index, vkb::core::HPPGraphicsPipeline &graphics_pipeline) { recorder.set_graphics_pipeline(index, graphics_pipeline); } }; } // namespace template T &request_resource(vkb::core::DeviceCpp &device, vkb::HPPResourceRecord *recorder, std::unordered_map &resources, A &...args) { HPPRecordHelper record_helper; size_t hash{0U}; hash_param(hash, args...); auto res_it = resources.find(hash); if (res_it != resources.end()) { return res_it->second; } // If we do not have it already, create and cache it const char *res_type = typeid(T).name(); size_t res_id = resources.size(); LOGD("Building #{} cache object ({})", res_id, res_type); // Only error handle in release #ifndef DEBUG try { #endif T resource(device, args...); auto res_ins_it = resources.emplace(hash, std::move(resource)); if (!res_ins_it.second) { throw std::runtime_error{std::string{"Insertion error for #"} + std::to_string(res_id) + "cache object (" + res_type + ")"}; } res_it = res_ins_it.first; if (recorder) { size_t index = record_helper.record(*recorder, args...); record_helper.index(*recorder, index, res_it->second); } #ifndef DEBUG } catch (const std::exception &e) { LOGE("Creation error for #{} cache object ({})", res_id, res_type); throw e; } #endif return res_it->second; } } // namespace common } // namespace vkb