diff --git a/core/rhi/buffer_vk.cpp b/core/rhi/buffer_vk.cpp index be6608d..bd0c1e9 100644 --- a/core/rhi/buffer_vk.cpp +++ b/core/rhi/buffer_vk.cpp @@ -10,6 +10,7 @@ buffer_vk::buffer_vk() { void buffer_vk::create(uint32_t size, vk::BufferUsageFlagBits in_usage, vk::DescriptorType in_descriptor_type) { destroy(); + buffer_size = size; descriptor_type = in_descriptor_type; const renderer* render_vk = application::get()->get_renderer(); const vk::Device& device = render_vk->device; @@ -43,7 +44,7 @@ void buffer_vk::create_staging(uint32_t size) { create(size, vk::BufferUsageFlagBits::eTransferSrc, vk::DescriptorType::eUniformBuffer); } -void buffer_vk::destroy() const { +void buffer_vk::destroy() { if (!buffer) { return; } @@ -52,6 +53,9 @@ void buffer_vk::destroy() const { device.destroyBuffer(buffer); device.freeMemory(memory); + + buffer = nullptr; + memory = nullptr; } void buffer_vk::update(const void* data, uint32_t size) { diff --git a/core/rhi/buffer_vk.h b/core/rhi/buffer_vk.h index 657a242..d880251 100644 --- a/core/rhi/buffer_vk.h +++ b/core/rhi/buffer_vk.h @@ -13,13 +13,13 @@ public: void create_storage(uint32_t size); void create_uniform(uint32_t size); void create_staging(uint32_t size); - void destroy() const; + void destroy(); template T* map() { const auto& device = application::get()->get_renderer()->device; void* mapped; - const auto err = device.mapMemory(memory, 0, VK_WHOLE_SIZE, vk::MemoryMapFlags(), &mapped); + const auto err = device.mapMemory(memory, 0, buffer_size, vk::MemoryMapFlags(), &mapped); check_vk_result(err); return static_cast(mapped); } @@ -38,15 +38,16 @@ public: update(data.data(), data.size() * sizeof(T)); } - operator vk::DescriptorBufferInfo() const { + [[nodiscard]] vk::DescriptorBufferInfo get_descriptor_info() const { vk::DescriptorBufferInfo descriptor_buffer_info; descriptor_buffer_info.setBuffer(buffer); descriptor_buffer_info.setOffset(0); - descriptor_buffer_info.setRange(VK_WHOLE_SIZE); + descriptor_buffer_info.setRange(buffer_size); return descriptor_buffer_info; } vk::Buffer buffer; vk::DeviceMemory memory; vk::DescriptorType descriptor_type; + uint32_t buffer_size; }; diff --git a/core/rhi/compute_pipeline.cpp b/core/rhi/compute_pipeline.cpp index 7cd5475..8c84a2e 100644 --- a/core/rhi/compute_pipeline.cpp +++ b/core/rhi/compute_pipeline.cpp @@ -4,8 +4,15 @@ #include +compute_pipeline::~compute_pipeline() { + const renderer* render_vk = application::get()->get_renderer(); + const vk::Device& device = render_vk->device; + + device.destroyShaderModule(shader_module_); +} + void compute_pipeline::add_binding(uint32_t binding, vk::DescriptorType descriptor_type, uint32_t descriptor_count, - const vk::Sampler* immutable_samplers) { + vk::Sampler immutable_samplers) { const vk::ShaderStageFlags flag = vk::ShaderStageFlagBits::eCompute; vk::DescriptorSetLayoutBinding descriptor_set_layout_binding; @@ -13,7 +20,8 @@ void compute_pipeline::add_binding(uint32_t binding, vk::DescriptorType descript descriptor_set_layout_binding.setDescriptorType(descriptor_type); descriptor_set_layout_binding.setDescriptorCount(descriptor_count); descriptor_set_layout_binding.setStageFlags(flag); - descriptor_set_layout_binding.setPImmutableSamplers(immutable_samplers); + if (immutable_samplers) + descriptor_set_layout_binding.setImmutableSamplers(immutable_samplers); descriptor_set_layout_bindings_.push_back(descriptor_set_layout_binding); } @@ -21,13 +29,8 @@ void compute_pipeline::create() { const renderer* render_vk = application::get()->get_renderer(); const vk::Device& device = render_vk->device; - vk::PipelineCacheCreateInfo pipeline_cache_create_info; - pipeline_cache_create_info.setInitialDataSize(0); - pipeline_cache_ = device.createPipelineCache(pipeline_cache_create_info); - create_pipeline_layout(); - vk::PipelineShaderStageCreateInfo pipeline_shader_stage_create_info; pipeline_shader_stage_create_info.setStage(vk::ShaderStageFlagBits::eCompute); pipeline_shader_stage_create_info.setModule(shader_module_); @@ -36,55 +39,27 @@ void compute_pipeline::create() { vk::ComputePipelineCreateInfo pipeline_create_info; pipeline_create_info.setLayout(pipeline_layout_); pipeline_create_info.setStage(pipeline_shader_stage_create_info); - const auto pipeline_result = device.createComputePipeline(pipeline_cache_, pipeline_create_info); + const auto pipeline_result = device.createComputePipeline(VK_NULL_HANDLE, pipeline_create_info); check_vk_result(pipeline_result.result); pipeline_ = pipeline_result.value; } -void compute_pipeline::destroy() { - const renderer* render_vk = application::get()->get_renderer(); - const vk::Device& device = render_vk->device; - - device.destroyPipeline(pipeline_); - device.destroyPipelineCache(pipeline_cache_); - device.destroyPipelineLayout(pipeline_layout_); -} - void compute_pipeline::dispatch(uint32_t group_count_x, uint32_t group_count_y, uint32_t group_count_z) const { #ifdef _DEBUG if (pipeline_ == vk::Pipeline()) { throw std::runtime_error("Pipeline not created"); } #endif - const renderer* render_vk = application::get()->get_renderer(); - const vk::Device& device = render_vk->device; - const vk::CommandPool& command_pool = render_vk->get_command_pool(); + renderer* render_vk = application::get()->get_renderer(); - vk::CommandBufferAllocateInfo command_buffer_allocate_info; - command_buffer_allocate_info.setCommandPool(command_pool); - command_buffer_allocate_info.setLevel(vk::CommandBufferLevel::ePrimary); - command_buffer_allocate_info.setCommandBufferCount(1); - const vk::CommandBuffer command_buffer = device.allocateCommandBuffers(command_buffer_allocate_info)[0]; - - vk::CommandBufferBeginInfo command_buffer_begin_info; - command_buffer_begin_info.setFlags(vk::CommandBufferUsageFlagBits::eOneTimeSubmit); - command_buffer.begin(command_buffer_begin_info); + const vk::CommandBuffer command_buffer = render_vk->create_command_buffer(vk::CommandBufferLevel::ePrimary, true); command_buffer.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline_); command_buffer.bindDescriptorSets(vk::PipelineBindPoint::eCompute, pipeline_layout_, 0, descriptor_set_, nullptr); command_buffer.dispatch(group_count_x, group_count_y, group_count_z); - command_buffer.end(); - - vk::SubmitInfo submit_info; - submit_info.setCommandBufferCount(1); - submit_info.setPCommandBuffers(&command_buffer); - render_vk->queue.submit(submit_info, nullptr); - render_vk->queue.waitIdle(); - - device.freeCommandBuffers(command_pool, command_buffer); - device.destroyCommandPool(command_pool); + render_vk->end_command_buffer(command_buffer, true); } void compute_pipeline::set_shader(const uint8_t* shader_code, size_t shader_code_size) { diff --git a/core/rhi/compute_pipeline.h b/core/rhi/compute_pipeline.h index afd8657..67d7573 100644 --- a/core/rhi/compute_pipeline.h +++ b/core/rhi/compute_pipeline.h @@ -3,9 +3,9 @@ class CORE_API compute_pipeline : public pipeline { public: - void add_binding(uint32_t binding, vk::DescriptorType descriptor_type, uint32_t descriptor_count, const vk::Sampler* immutable_samplers) override; + ~compute_pipeline() override; + void add_binding(uint32_t binding, vk::DescriptorType descriptor_type, uint32_t descriptor_count, vk::Sampler immutable_samplers) override; void create() override; - void destroy() override; void dispatch(uint32_t group_count_x, uint32_t group_count_y, uint32_t group_count_z) const; diff --git a/core/rhi/pipeline.cpp b/core/rhi/pipeline.cpp index c98a555..dbec013 100644 --- a/core/rhi/pipeline.cpp +++ b/core/rhi/pipeline.cpp @@ -3,6 +3,49 @@ #include "renderer.h" #include "texture.h" +pipeline::~pipeline() { + const renderer* render_vk = application::get()->get_renderer(); + const vk::Device& device = render_vk->device; + + device.destroyDescriptorPool(descriptor_pool_); + device.destroyDescriptorSetLayout(descriptor_set_layout_); + device.destroyPipelineLayout(pipeline_layout_); + device.destroyPipeline(pipeline_); +} + +void pipeline::add_uniform_buffer(uint32_t binding, std::shared_ptr buf) { + add_binding(binding, vk::DescriptorType::eUniformBuffer, 1, nullptr); + buffers_[binding] = buf; +} + +void pipeline::add_storage_buffer(uint32_t binding, std::shared_ptr buf) { + add_binding(binding, vk::DescriptorType::eStorageBuffer, 1, nullptr); + buffers_[binding] = buf; +} + +void pipeline::add_sampled_image(uint32_t binding, std::shared_ptr in_texture) { + add_binding(binding, vk::DescriptorType::eSampledImage, 1, in_texture->sampler); + textures_[binding] = in_texture; +} + +void pipeline::add_storage_image(uint32_t binding, std::shared_ptr in_texture) { + add_binding(binding, vk::DescriptorType::eStorageImage, 1, in_texture->sampler); + textures_[binding] = in_texture; +} + +void pipeline::add_input_attachment(uint32_t binding) { + add_binding(binding, vk::DescriptorType::eInputAttachment, 1, nullptr); +} + +void pipeline::add_sampler(uint32_t binding, vk::Sampler immutable_samplers) { + add_binding(binding, vk::DescriptorType::eSampler, 1, immutable_samplers); +} + +void pipeline::add_combined_image(uint32_t binding, std::shared_ptr in_texture) { + add_binding(binding, vk::DescriptorType::eCombinedImageSampler, 1, in_texture->sampler); + textures_[binding] = in_texture; +} + void pipeline::create_pipeline_layout() { const renderer* render_vk = application::get()->get_renderer(); const vk::Device& device = render_vk->device; @@ -11,16 +54,32 @@ void pipeline::create_pipeline_layout() { descriptor_set_layout_create_info.setBindings(descriptor_set_layout_bindings_); descriptor_set_layout_ = device.createDescriptorSetLayout(descriptor_set_layout_create_info); - vk::PipelineLayoutCreateInfo pipeline_layout_create_info; - pipeline_layout_create_info.setSetLayouts(descriptor_set_layout_); - pipeline_layout_ = device.createPipelineLayout(pipeline_layout_create_info); + std::vector pool_sizes; + { + std::map temp_pool_sizes; + for (const auto& binding: descriptor_set_layout_bindings_) { + temp_pool_sizes[binding.descriptorType]++; + } + for (const auto& pair: temp_pool_sizes) { + pool_sizes.emplace_back(pair.first, pair.second); + } + } + + vk::DescriptorPoolCreateInfo descriptor_pool_create_info; + descriptor_pool_create_info.setMaxSets(1); + descriptor_pool_create_info.setPoolSizes(pool_sizes); + descriptor_pool_ = device.createDescriptorPool(descriptor_pool_create_info); vk::DescriptorSetAllocateInfo descriptor_set_allocate_info; - descriptor_set_allocate_info.setDescriptorPool(render_vk->descriptor_pool); + descriptor_set_allocate_info.setDescriptorPool(descriptor_pool_); + descriptor_set_allocate_info.setDescriptorSetCount(1); descriptor_set_allocate_info.setSetLayouts(descriptor_set_layout_); - descriptor_set_ = device.allocateDescriptorSets(descriptor_set_allocate_info).front(); + const std::vector& sets = device.allocateDescriptorSets(descriptor_set_allocate_info); + descriptor_set_ = sets.front(); std::vector write_descriptor_sets; + std::vector> temp_buffer_infos; + std::vector> temp_image_infoses; for (const auto& binding_info: descriptor_set_layout_bindings_) { vk::WriteDescriptorSet write_descriptor_set; @@ -33,14 +92,17 @@ void pipeline::create_pipeline_layout() { case vk::DescriptorType::eSampledImage: case vk::DescriptorType::eStorageImage: { const auto& t = textures_[binding_info.binding]; - vk::DescriptorImageInfo image_info = *t.get(); - write_descriptor_set.setImageInfo(image_info); + vk::DescriptorImageInfo image_info = t->get_descriptor_info(); + temp_image_infoses.push_back({image_info}); + write_descriptor_set.setImageInfo(temp_image_infoses.back()); } break; case vk::DescriptorType::eUniformBuffer: case vk::DescriptorType::eStorageBuffer: { - vk::DescriptorBufferInfo buffer_info = buffers_[binding_info.binding]; - write_descriptor_set.setBufferInfo(buffer_info); + const auto& b = buffers_[binding_info.binding]; + vk::DescriptorBufferInfo buffer_info = b->get_descriptor_info(); + temp_buffer_infos.push_back( {buffer_info} ); + write_descriptor_set.setBufferInfo(temp_buffer_infos.back()); } break; default: @@ -50,4 +112,8 @@ void pipeline::create_pipeline_layout() { } device.updateDescriptorSets(write_descriptor_sets, nullptr); + + vk::PipelineLayoutCreateInfo pipeline_layout_create_info; + pipeline_layout_create_info.setSetLayouts(descriptor_set_layout_); + pipeline_layout_ = device.createPipelineLayout(pipeline_layout_create_info); } diff --git a/core/rhi/pipeline.h b/core/rhi/pipeline.h index b9744fb..efc168b 100644 --- a/core/rhi/pipeline.h +++ b/core/rhi/pipeline.h @@ -4,55 +4,44 @@ #include "buffer_vk.h" +class render_resource; class texture; /// 1. add_binding /// 2. create(); /// 3. dispatch(); -class pipeline { +class CORE_API pipeline { public: - virtual ~pipeline() = default; + virtual ~pipeline(); - virtual void add_binding(uint32_t binding, vk::DescriptorType descriptor_type, uint32_t descriptor_count, const vk::Sampler* immutable_samplers) = 0; + virtual void add_binding(uint32_t binding, vk::DescriptorType descriptor_type, uint32_t descriptor_count, vk::Sampler immutable_samplers) = 0; - void add_uniform_buffer(uint32_t binding, const buffer_vk& buf, uint32_t descriptor_count = 1) { - add_binding(binding, vk::DescriptorType::eUniformBuffer, descriptor_count, nullptr); - buffers_[binding] = buf; - } - void add_storage_buffer(uint32_t binding, const buffer_vk& buf, uint32_t descriptor_count = 1) { - add_binding(binding, vk::DescriptorType::eStorageBuffer, descriptor_count, nullptr); - buffers_[binding] = buf; - } - void add_sampled_image(uint32_t binding, uint32_t descriptor_count = 1, const vk::Sampler* immutable_samplers = nullptr) { - add_binding(binding, vk::DescriptorType::eSampledImage, descriptor_count, immutable_samplers); - } - void add_storage_image(uint32_t binding, std::shared_ptr in_texture, uint32_t descriptor_count = 1) { - add_binding(binding, vk::DescriptorType::eStorageImage, descriptor_count, nullptr); - textures_[binding] = in_texture; - } - void add_input_attachment(uint32_t binding, uint32_t descriptor_count = 1) { - add_binding(binding, vk::DescriptorType::eInputAttachment, descriptor_count, nullptr); - } - void add_sampler(uint32_t binding, uint32_t descriptor_count = 1, const vk::Sampler* immutable_samplers = nullptr) { - add_binding(binding, vk::DescriptorType::eSampler, descriptor_count, immutable_samplers); - } - void add_uniform_image(uint32_t binding, std::shared_ptr in_texture, uint32_t descriptor_count = 1, const vk::Sampler* immutable_samplers = nullptr) { - add_binding(binding, vk::DescriptorType::eCombinedImageSampler, descriptor_count, immutable_samplers); - textures_[binding] = in_texture; - } + void add_uniform_buffer(uint32_t binding, std::shared_ptr buf); + + void add_storage_buffer(uint32_t binding, std::shared_ptr buf); + + void add_sampled_image(uint32_t binding, std::shared_ptr in_texture); + + void add_storage_image(uint32_t binding, std::shared_ptr in_texture); + + void add_input_attachment(uint32_t binding); + + void add_sampler(uint32_t binding, vk::Sampler immutable_samplers = nullptr); + + void add_combined_image(uint32_t binding, std::shared_ptr in_texture); virtual void create() = 0; - virtual void destroy() = 0; - +protected: vk::Pipeline pipeline_; - vk::PipelineCache pipeline_cache_; vk::PipelineLayout pipeline_layout_; vk::DescriptorSetLayout descriptor_set_layout_; vk::DescriptorSet descriptor_set_; + + vk::DescriptorPool descriptor_pool_; std::vector descriptor_set_layout_bindings_; - std::map buffers_; - std::map> textures_; + std::map> buffers_; + std::map> textures_; protected: void create_pipeline_layout(); }; diff --git a/core/rhi/render_resource.h b/core/rhi/render_resource.h index 83c9bf8..d7c7f36 100644 --- a/core/rhi/render_resource.h +++ b/core/rhi/render_resource.h @@ -1,17 +1,67 @@ #pragma once #include "imgui.h" +#include "renderer.h" +#include "application/application.h" class render_resource : public std::enable_shared_from_this { public: - virtual ~render_resource() = default; + render_resource() { + format = vk::Format::eUndefined; + width_ = 0; + height_ = 0; + image = nullptr; + image_view = nullptr; + sampler = nullptr; + memory = nullptr; + descriptor_set = nullptr; + } + virtual ~render_resource() { + render_resource::destroy(); + } - virtual int get_width() const = 0; + [[nodiscard]] int get_width() const { return width_; } + [[nodiscard]] int get_height() const { return height_; } + [[nodiscard]] ImTextureID get_texture_id() const { return descriptor_set; } + [[nodiscard]] vk::DescriptorImageInfo get_descriptor_info() const { + vk::DescriptorImageInfo info; + info.setImageLayout(vk::ImageLayout::eShaderReadOnlyOptimal); + info.setImageView(image_view); + info.setSampler(sampler); + return info; + } - virtual int get_height() const = 0; - - virtual ImTextureID get_texture_id() = 0; - - void draw() { + void init(uint32_t width, uint32_t height, vk::Format in_format) { + width_ = width; + height_ = height; + format = in_format; + on_init(); + } + void draw() const { ImGui::Image(get_texture_id(), ImVec2(static_cast(get_width()), static_cast(get_height()))); } + virtual void destroy() { + const auto r = application::get()->get_renderer(); + const auto& device = r->device; + device.destroySampler(sampler); + device.destroyImageView(image_view); + device.destroyImage(image); + device.freeMemory(memory); + ImGui_ImplVulkan_RemoveTexture(descriptor_set); + sampler = nullptr; + image_view = nullptr; + image = nullptr; + memory = nullptr; + descriptor_set = nullptr; + } + + vk::Image image; + vk::ImageView image_view; + vk::Sampler sampler; + vk::DescriptorSet descriptor_set; + vk::DeviceMemory memory; + vk::Format format; +protected: + virtual void on_init() = 0; + uint32_t width_; + uint32_t height_; }; diff --git a/core/rhi/render_target.cpp b/core/rhi/render_target.cpp index de90976..1feefb4 100644 --- a/core/rhi/render_target.cpp +++ b/core/rhi/render_target.cpp @@ -4,14 +4,6 @@ #include "application/application.h" #include "utils/utils.hpp" -void render_target::init(const int width, const int height, const vk::Format in_format) { - width_ = width; - height_ = height; - format = in_format; - - create(width, height); -} - void* render_target::lock(lock_state state) const { const auto r = application::get()->get_renderer(); const auto& device = r->device; @@ -37,7 +29,14 @@ void render_target::unlock() { device.unmapMemory(memory); } -void render_target::create(int width, int height) { +void render_target::destroy() { + render_resource::destroy(); + const auto r = application::get()->get_renderer(); + const auto& device = r->device; + device.destroyFramebuffer(framebuffer); +} + +void render_target::create(uint32_t width, uint32_t height) { auto r = application::get()->get_renderer(); const auto& device = r->device; const auto& physical_device = r->physical_device; @@ -50,7 +49,7 @@ void render_target::create(int width, int height) { image_create_info.setArrayLayers(1); image_create_info.setSamples(vk::SampleCountFlagBits::e1); image_create_info.setTiling(vk::ImageTiling::eOptimal); - image_create_info.setUsage(vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eColorAttachment); + image_create_info.setUsage(vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eStorage); image_create_info.setSharingMode(vk::SharingMode::eExclusive); image_create_info.setInitialLayout(vk::ImageLayout::eUndefined); image = device.createImage(image_create_info); @@ -80,16 +79,27 @@ void render_target::create(int width, int height) { framebuffer_create_info.setHeight(height); framebuffer_create_info.setLayers(1); framebuffer = device.createFramebuffer(framebuffer_create_info); + + vk::SamplerCreateInfo sampler_info; + sampler_info.setMagFilter(vk::Filter::eLinear); + sampler_info.setMinFilter(vk::Filter::eLinear); + sampler_info.setMipmapMode(vk::SamplerMipmapMode::eLinear); + sampler_info.setAddressModeU(vk::SamplerAddressMode::eRepeat); + sampler_info.setAddressModeV(vk::SamplerAddressMode::eRepeat); + sampler_info.setAddressModeW(vk::SamplerAddressMode::eRepeat); + sampler_info.setMinLod(-1000); + sampler_info.setMaxLod(1000); + sampler_info.setMaxAnisotropy(1); + sampler = device.createSampler(sampler_info); + + descriptor_set = ImGui_ImplVulkan_AddTexture(sampler, image_view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); } -void render_target::on_resize(int width, int height) { - const auto r = application::get()->get_renderer(); - const auto& device = r->device; - - device.destroyFramebuffer(framebuffer); - device.destroyImageView(image_view); - device.destroyImage(image); - device.freeMemory(memory); +void render_target::on_init() { + create(width_, height_); +} +void render_target::on_resize(uint32_t width, uint32_t height) { + destroy(); create(width, height); } diff --git a/core/rhi/render_target.h b/core/rhi/render_target.h index 73f28eb..90bc0b7 100644 --- a/core/rhi/render_target.h +++ b/core/rhi/render_target.h @@ -12,13 +12,8 @@ enum class lock_state { class render_target : public render_resource { public: - [[nodiscard]] int get_height() const override { return height_; } - [[nodiscard]] int get_width() const override { return width_; } - [[nodiscard]] ImTextureID get_texture_id() override { return descriptor_set; } - void init(const int width, const int height, const vk::Format in_format); - - void resize(const int width, const int height) { + void resize(const uint32_t width, const uint32_t height) { if (width_ == width && height_ == height) return; @@ -32,17 +27,12 @@ public: void* lock(lock_state state) const; void unlock(); - std::function)> on_resize_callback; - vk::Image image; - vk::ImageView image_view; - vk::DeviceMemory memory; - vk::Framebuffer framebuffer; - vk::Format format; - vk::DescriptorSet descriptor_set; -protected: - void create(int width, int height); - void on_resize(int width, int height); + void destroy() override; - int width_ = 0; - int height_ = 0; + std::function)> on_resize_callback; + vk::Framebuffer framebuffer; +protected: + void create(uint32_t width, uint32_t height); + void on_init() override; + void on_resize(uint32_t width, uint32_t height); }; diff --git a/core/rhi/renderer.cpp b/core/rhi/renderer.cpp index 2de07ef..5569fb5 100644 --- a/core/rhi/renderer.cpp +++ b/core/rhi/renderer.cpp @@ -6,6 +6,17 @@ #include "application/application.h" #include "texture.h" + + +#ifdef APP_USE_VULKAN_DEBUG_REPORT +static VKAPI_ATTR VkBool32 VKAPI_CALL on_debug_report(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage, void* pUserData) +{ + (void)flags; (void)object; (void)location; (void)messageCode; (void)pUserData; (void)pLayerPrefix; // Unused arguments + fprintf(stderr, "[vulkan] Debug report from ObjectType: %i\nMessage: %s\n\n", objectType, pMessage); + return VK_FALSE; +} +#endif // APP_USE_VULKAN_DEBUG_REPORT + static bool is_extension_available(const std::vector& properties, const char* extension) { return std::ranges::any_of(properties, [extension](const vk::ExtensionProperties& p) { return strcmp(p.extensionName, extension) == 0; @@ -36,12 +47,27 @@ vk::CommandBuffer renderer::create_command_buffer(vk::CommandBufferLevel level, return command_buffer; } -void renderer::end_command_buffer(vk::CommandBuffer command_buffer) { +void renderer::end_command_buffer(vk::CommandBuffer command_buffer, bool use_fence) const { command_buffer.end(); - vk::SubmitInfo submit_info; - submit_info.setCommandBuffers(command_buffer); - queue.submit(submit_info, nullptr); + if (use_fence) { + vk::FenceCreateInfo fence_create_info = {}; + vk::Fence fence = device.createFence(fence_create_info); + + vk::SubmitInfo submit_info; + submit_info.setCommandBuffers(command_buffer); + queue.submit(submit_info, fence); + + const auto err = device.waitForFences(1, &fence, VK_TRUE, 100000000000); + check_vk_result(err); + + device.destroyFence(fence); + } + else { + vk::SubmitInfo submit_info; + submit_info.setCommandBuffers(command_buffer); + queue.submit(submit_info, nullptr); + } } void renderer::init_vulkan(GLFWwindow* window_handle) { @@ -70,7 +96,7 @@ void renderer::init_vulkan(GLFWwindow* window_handle) { init_info.Device = device; init_info.QueueFamily = queue_family; init_info.Queue = queue; - init_info.PipelineCache = pipeline_cache; + init_info.PipelineCache = VK_NULL_HANDLE; init_info.DescriptorPool = descriptor_pool; init_info.RenderPass = main_window_data.RenderPass; init_info.Subpass = 0; @@ -120,10 +146,30 @@ void renderer::setup_vulkan(std::vector instance_extensions) { create_info.flags |= vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR; } #endif + // Enabling validation layers +#ifdef APP_USE_VULKAN_DEBUG_REPORT + const char* layers[] = { "VK_LAYER_KHRONOS_validation" }; + create_info.enabledLayerCount = 1; + create_info.ppEnabledLayerNames = layers; + instance_extensions.push_back("VK_EXT_debug_report"); +#endif // Create Vulkan Instance create_info.setPEnabledExtensionNames(instance_extensions); instance = vk::createInstance(create_info, allocator); + + // Setup the debug report callback +#ifdef APP_USE_VULKAN_DEBUG_REPORT + auto vkCreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT"); + IM_ASSERT(vkCreateDebugReportCallbackEXT != nullptr); + VkDebugReportCallbackCreateInfoEXT debug_report_ci = {}; + debug_report_ci.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT; + debug_report_ci.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; + debug_report_ci.pfnCallback = on_debug_report; + debug_report_ci.pUserData = nullptr; + auto err = vkCreateDebugReportCallbackEXT(instance, &debug_report_ci, (VkAllocationCallbacks*)allocator, &debug_report); + check_vk_result(err); +#endif } // Select Physical Device (GPU) @@ -228,8 +274,8 @@ void renderer::cleanup_vulkan() const { device.destroyDescriptorPool(descriptor_pool); #ifdef APP_USE_VULKAN_DEBUG_REPORT // Remove the debug report callback - auto vkDestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(g_Instance, "vkDestroyDebugReportCallbackEXT"); - vkDestroyDebugReportCallbackEXT(g_Instance, g_DebugReport, g_Allocator); + auto vkDestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT"); + vkDestroyDebugReportCallbackEXT(instance, debug_report, (VkAllocationCallbacks*)allocator); #endif // APP_USE_VULKAN_DEBUG_REPORT device.destroy(); @@ -413,7 +459,9 @@ void renderer::end_frame(GLFWwindow* window_handle) { std::shared_ptr renderer::create_texture(const uint8_t* data, int width, int height, vk::Format format) { auto out = std::make_shared(); - out->init_data(data, width, height, format); + out->init(width, height, format); + if (data) + out->upload(data, width * height * 4); return out; } diff --git a/core/rhi/renderer.h b/core/rhi/renderer.h index 01c4e67..042be76 100644 --- a/core/rhi/renderer.h +++ b/core/rhi/renderer.h @@ -7,6 +7,10 @@ #include +#ifdef _DEBUG +#define APP_USE_VULKAN_DEBUG_REPORT +#endif + class pixel_shader_drawer; class render_target; class texture; @@ -58,10 +62,12 @@ public: uint32_t queue_family = (uint32_t) -1; vk::Queue queue = VK_NULL_HANDLE; vk::DescriptorPool descriptor_pool = VK_NULL_HANDLE; - vk::PipelineCache pipeline_cache = VK_NULL_HANDLE; +#ifdef APP_USE_VULKAN_DEBUG_REPORT + VkDebugReportCallbackEXT debug_report = VK_NULL_HANDLE; +#endif [[nodiscard]] vk::CommandPool get_command_pool() const; [[nodiscard]] vk::CommandBuffer create_command_buffer(vk::CommandBufferLevel level, bool begin) const; - void end_command_buffer(vk::CommandBuffer command_buffer); + void end_command_buffer(vk::CommandBuffer command_buffer, bool use_fence = false) const; ImGui_ImplVulkanH_Window main_window_data; int min_image_count = 2; diff --git a/core/rhi/texture.cpp b/core/rhi/texture.cpp index 162f677..406e20d 100644 --- a/core/rhi/texture.cpp +++ b/core/rhi/texture.cpp @@ -8,12 +8,6 @@ texture::texture() { - format = vk::Format::eUndefined; - width_ = 0; - height_ = 0; - image = nullptr; - image_view = nullptr; - sampler = nullptr; memory = nullptr; } @@ -28,67 +22,6 @@ texture::~texture() { } } -bool texture::init_data(const uint8_t* data, int width, int height, vk::Format in_format) { - width_ = width; - height_ = height; - format = in_format; - - const renderer* r = application::get()->get_renderer(); - const vk::Device& device = r->device; - const vk::PhysicalDevice& physical_device = r->physical_device; - - vk::ImageCreateInfo image_info; - image_info.setImageType(vk::ImageType::e2D); - image_info.setFormat(format); - image_info.setExtent({static_cast(width), static_cast(height), 1}); - image_info.setMipLevels(1); - image_info.setArrayLayers(1); - image_info.setSamples(vk::SampleCountFlagBits::e1); - image_info.setTiling(vk::ImageTiling::eOptimal); - image_info.setUsage(vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst); - image_info.setSharingMode(vk::SharingMode::eExclusive); - image_info.setInitialLayout(vk::ImageLayout::eUndefined); - image = device.createImage(image_info); - - const vk::PhysicalDeviceMemoryProperties memory_properties = physical_device.getMemoryProperties(); - const vk::MemoryRequirements memory_requirements = device.getImageMemoryRequirements(image); - const uint32_t memory_type = vk::su::findMemoryType(memory_properties, memory_requirements.memoryTypeBits, - vk::MemoryPropertyFlagBits::eDeviceLocal); - - vk::MemoryAllocateInfo memory_allocate_info; - memory_allocate_info.setAllocationSize(memory_requirements.size); - memory_allocate_info.setMemoryTypeIndex(memory_type); - memory = device.allocateMemory(memory_allocate_info); - device.bindImageMemory(image, memory, 0); - - vk::ImageViewCreateInfo view_info; - view_info.setImage(image); - view_info.setViewType(vk::ImageViewType::e2D); - view_info.setFormat(format); - view_info.setSubresourceRange({vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}); - image_view = device.createImageView(view_info); - - vk::SamplerCreateInfo sampler_info; - sampler_info.setMagFilter(vk::Filter::eLinear); - sampler_info.setMinFilter(vk::Filter::eLinear); - sampler_info.setMipmapMode(vk::SamplerMipmapMode::eLinear); - sampler_info.setAddressModeU(vk::SamplerAddressMode::eRepeat); - sampler_info.setAddressModeV(vk::SamplerAddressMode::eRepeat); - sampler_info.setAddressModeW(vk::SamplerAddressMode::eRepeat); - sampler_info.setMinLod(-1000); - sampler_info.setMaxLod(1000); - sampler_info.setMaxAnisotropy(1); - sampler = device.createSampler(sampler_info); - - descriptor_set = ImGui_ImplVulkan_AddTexture(sampler, image_view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - uint32_t image_size = width * height * 4; - - if (data) { - upload(data, image_size); - } - return true; -} - void texture::upload(const void* data, size_t size) { renderer* r = application::get()->get_renderer(); const vk::Device& device = r->device; @@ -155,3 +88,54 @@ void texture::upload(const void* data, size_t size) { // device.freeCommandBuffers(command_pool, command_buffer); } + +void texture::on_init() { + const renderer* r = application::get()->get_renderer(); + const vk::Device& device = r->device; + const vk::PhysicalDevice& physical_device = r->physical_device; + + vk::ImageCreateInfo image_info; + image_info.setImageType(vk::ImageType::e2D); + image_info.setFormat(format); + image_info.setExtent({ width_, height_, 1 }); + image_info.setMipLevels(1); + image_info.setArrayLayers(1); + image_info.setSamples(vk::SampleCountFlagBits::e1); + image_info.setTiling(vk::ImageTiling::eOptimal); + image_info.setUsage(vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eStorage); + image_info.setSharingMode(vk::SharingMode::eExclusive); + image_info.setInitialLayout(vk::ImageLayout::eUndefined); + image = device.createImage(image_info); + + const vk::PhysicalDeviceMemoryProperties memory_properties = physical_device.getMemoryProperties(); + const vk::MemoryRequirements memory_requirements = device.getImageMemoryRequirements(image); + const uint32_t memory_type = vk::su::findMemoryType(memory_properties, memory_requirements.memoryTypeBits, + vk::MemoryPropertyFlagBits::eDeviceLocal); + + vk::MemoryAllocateInfo memory_allocate_info; + memory_allocate_info.setAllocationSize(memory_requirements.size); + memory_allocate_info.setMemoryTypeIndex(memory_type); + memory = device.allocateMemory(memory_allocate_info); + device.bindImageMemory(image, memory, 0); + + vk::ImageViewCreateInfo view_info; + view_info.setImage(image); + view_info.setViewType(vk::ImageViewType::e2D); + view_info.setFormat(format); + view_info.setSubresourceRange({vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}); + image_view = device.createImageView(view_info); + + vk::SamplerCreateInfo sampler_info; + sampler_info.setMagFilter(vk::Filter::eLinear); + sampler_info.setMinFilter(vk::Filter::eLinear); + sampler_info.setMipmapMode(vk::SamplerMipmapMode::eLinear); + sampler_info.setAddressModeU(vk::SamplerAddressMode::eRepeat); + sampler_info.setAddressModeV(vk::SamplerAddressMode::eRepeat); + sampler_info.setAddressModeW(vk::SamplerAddressMode::eRepeat); + sampler_info.setMinLod(-1000); + sampler_info.setMaxLod(1000); + sampler_info.setMaxAnisotropy(1); + sampler = device.createSampler(sampler_info); + + descriptor_set = ImGui_ImplVulkan_AddTexture(sampler, image_view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); +} diff --git a/core/rhi/texture.h b/core/rhi/texture.h index f5a4ff4..831a29a 100644 --- a/core/rhi/texture.h +++ b/core/rhi/texture.h @@ -11,30 +11,9 @@ public: ~texture() override; - [[nodiscard]] int get_width() const override { return width_; } - [[nodiscard]] int get_height() const override { return height_; } - [[nodiscard]] ImTextureID get_texture_id() override { return descriptor_set; } - - bool init_data(const uint8_t* data, int width, int height, vk::Format in_format); bool is_valid() const { return image_view; } - operator vk::DescriptorImageInfo() const { - vk::DescriptorImageInfo info; - info.setImageLayout(vk::ImageLayout::eShaderReadOnlyOptimal); - info.setImageView(image_view); - info.setSampler(sampler); - return info; - } void upload(const void* data, size_t size); - - vk::Image image; - vk::ImageView image_view; - vk::Sampler sampler; - vk::DeviceMemory memory; - vk::DescriptorSet descriptor_set; - - vk::Format format; protected: - int width_; - int height_; + void on_init() override; };