compute pipeline以及buffer绑定

This commit is contained in:
daiqingshuang 2024-02-20 14:09:44 +08:00
parent f055bfbd76
commit b996cf26bb
13 changed files with 332 additions and 230 deletions

View File

@ -10,6 +10,7 @@ buffer_vk::buffer_vk() {
void buffer_vk::create(uint32_t size, vk::BufferUsageFlagBits in_usage, vk::DescriptorType in_descriptor_type) { void buffer_vk::create(uint32_t size, vk::BufferUsageFlagBits in_usage, vk::DescriptorType in_descriptor_type) {
destroy(); destroy();
buffer_size = size;
descriptor_type = in_descriptor_type; descriptor_type = in_descriptor_type;
const renderer* render_vk = application::get()->get_renderer(); const renderer* render_vk = application::get()->get_renderer();
const vk::Device& device = render_vk->device; 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); create(size, vk::BufferUsageFlagBits::eTransferSrc, vk::DescriptorType::eUniformBuffer);
} }
void buffer_vk::destroy() const { void buffer_vk::destroy() {
if (!buffer) { if (!buffer) {
return; return;
} }
@ -52,6 +53,9 @@ void buffer_vk::destroy() const {
device.destroyBuffer(buffer); device.destroyBuffer(buffer);
device.freeMemory(memory); device.freeMemory(memory);
buffer = nullptr;
memory = nullptr;
} }
void buffer_vk::update(const void* data, uint32_t size) { void buffer_vk::update(const void* data, uint32_t size) {

View File

@ -13,13 +13,13 @@ public:
void create_storage(uint32_t size); void create_storage(uint32_t size);
void create_uniform(uint32_t size); void create_uniform(uint32_t size);
void create_staging(uint32_t size); void create_staging(uint32_t size);
void destroy() const; void destroy();
template <typename T> template <typename T>
T* map() { T* map() {
const auto& device = application::get()->get_renderer()->device; const auto& device = application::get()->get_renderer()->device;
void* mapped; 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); check_vk_result(err);
return static_cast<T*>(mapped); return static_cast<T*>(mapped);
} }
@ -38,15 +38,16 @@ public:
update(data.data(), data.size() * sizeof(T)); update(data.data(), data.size() * sizeof(T));
} }
operator vk::DescriptorBufferInfo() const { [[nodiscard]] vk::DescriptorBufferInfo get_descriptor_info() const {
vk::DescriptorBufferInfo descriptor_buffer_info; vk::DescriptorBufferInfo descriptor_buffer_info;
descriptor_buffer_info.setBuffer(buffer); descriptor_buffer_info.setBuffer(buffer);
descriptor_buffer_info.setOffset(0); descriptor_buffer_info.setOffset(0);
descriptor_buffer_info.setRange(VK_WHOLE_SIZE); descriptor_buffer_info.setRange(buffer_size);
return descriptor_buffer_info; return descriptor_buffer_info;
} }
vk::Buffer buffer; vk::Buffer buffer;
vk::DeviceMemory memory; vk::DeviceMemory memory;
vk::DescriptorType descriptor_type; vk::DescriptorType descriptor_type;
uint32_t buffer_size;
}; };

View File

@ -4,8 +4,15 @@
#include <vulkan/vulkan.hpp> #include <vulkan/vulkan.hpp>
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, 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; const vk::ShaderStageFlags flag = vk::ShaderStageFlagBits::eCompute;
vk::DescriptorSetLayoutBinding descriptor_set_layout_binding; 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.setDescriptorType(descriptor_type);
descriptor_set_layout_binding.setDescriptorCount(descriptor_count); descriptor_set_layout_binding.setDescriptorCount(descriptor_count);
descriptor_set_layout_binding.setStageFlags(flag); 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); 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 renderer* render_vk = application::get()->get_renderer();
const vk::Device& device = render_vk->device; 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(); create_pipeline_layout();
vk::PipelineShaderStageCreateInfo pipeline_shader_stage_create_info; vk::PipelineShaderStageCreateInfo pipeline_shader_stage_create_info;
pipeline_shader_stage_create_info.setStage(vk::ShaderStageFlagBits::eCompute); pipeline_shader_stage_create_info.setStage(vk::ShaderStageFlagBits::eCompute);
pipeline_shader_stage_create_info.setModule(shader_module_); pipeline_shader_stage_create_info.setModule(shader_module_);
@ -36,55 +39,27 @@ void compute_pipeline::create() {
vk::ComputePipelineCreateInfo pipeline_create_info; vk::ComputePipelineCreateInfo pipeline_create_info;
pipeline_create_info.setLayout(pipeline_layout_); pipeline_create_info.setLayout(pipeline_layout_);
pipeline_create_info.setStage(pipeline_shader_stage_create_info); 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); check_vk_result(pipeline_result.result);
pipeline_ = pipeline_result.value; 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 { void compute_pipeline::dispatch(uint32_t group_count_x, uint32_t group_count_y, uint32_t group_count_z) const {
#ifdef _DEBUG #ifdef _DEBUG
if (pipeline_ == vk::Pipeline()) { if (pipeline_ == vk::Pipeline()) {
throw std::runtime_error("Pipeline not created"); throw std::runtime_error("Pipeline not created");
} }
#endif #endif
const renderer* render_vk = application::get()->get_renderer(); renderer* render_vk = application::get()->get_renderer();
const vk::Device& device = render_vk->device;
const vk::CommandPool& command_pool = render_vk->get_command_pool();
vk::CommandBufferAllocateInfo command_buffer_allocate_info; const vk::CommandBuffer command_buffer = render_vk->create_command_buffer(vk::CommandBufferLevel::ePrimary, true);
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);
command_buffer.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline_); command_buffer.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline_);
command_buffer.bindDescriptorSets(vk::PipelineBindPoint::eCompute, pipeline_layout_, 0, descriptor_set_, nullptr); 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.dispatch(group_count_x, group_count_y, group_count_z);
command_buffer.end(); render_vk->end_command_buffer(command_buffer, true);
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);
} }
void compute_pipeline::set_shader(const uint8_t* shader_code, size_t shader_code_size) { void compute_pipeline::set_shader(const uint8_t* shader_code, size_t shader_code_size) {

View File

@ -3,9 +3,9 @@
class CORE_API compute_pipeline : public pipeline { class CORE_API compute_pipeline : public pipeline {
public: 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 create() override;
void destroy() override;
void dispatch(uint32_t group_count_x, uint32_t group_count_y, uint32_t group_count_z) const; void dispatch(uint32_t group_count_x, uint32_t group_count_y, uint32_t group_count_z) const;

View File

@ -3,6 +3,49 @@
#include "renderer.h" #include "renderer.h"
#include "texture.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<buffer_vk> buf) {
add_binding(binding, vk::DescriptorType::eUniformBuffer, 1, nullptr);
buffers_[binding] = buf;
}
void pipeline::add_storage_buffer(uint32_t binding, std::shared_ptr<buffer_vk> buf) {
add_binding(binding, vk::DescriptorType::eStorageBuffer, 1, nullptr);
buffers_[binding] = buf;
}
void pipeline::add_sampled_image(uint32_t binding, std::shared_ptr<render_resource> 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<render_resource> 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<render_resource> in_texture) {
add_binding(binding, vk::DescriptorType::eCombinedImageSampler, 1, in_texture->sampler);
textures_[binding] = in_texture;
}
void pipeline::create_pipeline_layout() { void pipeline::create_pipeline_layout() {
const renderer* render_vk = application::get()->get_renderer(); const renderer* render_vk = application::get()->get_renderer();
const vk::Device& device = render_vk->device; 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_create_info.setBindings(descriptor_set_layout_bindings_);
descriptor_set_layout_ = device.createDescriptorSetLayout(descriptor_set_layout_create_info); descriptor_set_layout_ = device.createDescriptorSetLayout(descriptor_set_layout_create_info);
vk::PipelineLayoutCreateInfo pipeline_layout_create_info; std::vector<vk::DescriptorPoolSize> pool_sizes;
pipeline_layout_create_info.setSetLayouts(descriptor_set_layout_); {
pipeline_layout_ = device.createPipelineLayout(pipeline_layout_create_info); std::map<vk::DescriptorType, uint32_t> 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; 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_allocate_info.setSetLayouts(descriptor_set_layout_);
descriptor_set_ = device.allocateDescriptorSets(descriptor_set_allocate_info).front(); const std::vector<vk::DescriptorSet>& sets = device.allocateDescriptorSets(descriptor_set_allocate_info);
descriptor_set_ = sets.front();
std::vector<vk::WriteDescriptorSet> write_descriptor_sets; std::vector<vk::WriteDescriptorSet> write_descriptor_sets;
std::vector<std::vector<vk::DescriptorBufferInfo>> temp_buffer_infos;
std::vector<std::vector<vk::DescriptorImageInfo>> temp_image_infoses;
for (const auto& binding_info: descriptor_set_layout_bindings_) { for (const auto& binding_info: descriptor_set_layout_bindings_) {
vk::WriteDescriptorSet write_descriptor_set; vk::WriteDescriptorSet write_descriptor_set;
@ -33,14 +92,17 @@ void pipeline::create_pipeline_layout() {
case vk::DescriptorType::eSampledImage: case vk::DescriptorType::eSampledImage:
case vk::DescriptorType::eStorageImage: { case vk::DescriptorType::eStorageImage: {
const auto& t = textures_[binding_info.binding]; const auto& t = textures_[binding_info.binding];
vk::DescriptorImageInfo image_info = *t.get(); vk::DescriptorImageInfo image_info = t->get_descriptor_info();
write_descriptor_set.setImageInfo(image_info); temp_image_infoses.push_back({image_info});
write_descriptor_set.setImageInfo(temp_image_infoses.back());
} }
break; break;
case vk::DescriptorType::eUniformBuffer: case vk::DescriptorType::eUniformBuffer:
case vk::DescriptorType::eStorageBuffer: { case vk::DescriptorType::eStorageBuffer: {
vk::DescriptorBufferInfo buffer_info = buffers_[binding_info.binding]; const auto& b = buffers_[binding_info.binding];
write_descriptor_set.setBufferInfo(buffer_info); vk::DescriptorBufferInfo buffer_info = b->get_descriptor_info();
temp_buffer_infos.push_back( {buffer_info} );
write_descriptor_set.setBufferInfo(temp_buffer_infos.back());
} }
break; break;
default: default:
@ -50,4 +112,8 @@ void pipeline::create_pipeline_layout() {
} }
device.updateDescriptorSets(write_descriptor_sets, nullptr); 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);
} }

View File

@ -4,55 +4,44 @@
#include "buffer_vk.h" #include "buffer_vk.h"
class render_resource;
class texture; class texture;
/// 1. add_binding /// 1. add_binding
/// 2. create(); /// 2. create();
/// 3. dispatch(); /// 3. dispatch();
class pipeline { class CORE_API pipeline {
public: 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) { void add_uniform_buffer(uint32_t binding, std::shared_ptr<buffer_vk> buf);
add_binding(binding, vk::DescriptorType::eUniformBuffer, descriptor_count, nullptr);
buffers_[binding] = buf; void add_storage_buffer(uint32_t binding, std::shared_ptr<buffer_vk> buf);
}
void add_storage_buffer(uint32_t binding, const buffer_vk& buf, uint32_t descriptor_count = 1) { void add_sampled_image(uint32_t binding, std::shared_ptr<render_resource> in_texture);
add_binding(binding, vk::DescriptorType::eStorageBuffer, descriptor_count, nullptr);
buffers_[binding] = buf; void add_storage_image(uint32_t binding, std::shared_ptr<render_resource> in_texture);
}
void add_sampled_image(uint32_t binding, uint32_t descriptor_count = 1, const vk::Sampler* immutable_samplers = nullptr) { void add_input_attachment(uint32_t binding);
add_binding(binding, vk::DescriptorType::eSampledImage, descriptor_count, immutable_samplers);
} void add_sampler(uint32_t binding, vk::Sampler immutable_samplers = nullptr);
void add_storage_image(uint32_t binding, std::shared_ptr<texture> in_texture, uint32_t descriptor_count = 1) {
add_binding(binding, vk::DescriptorType::eStorageImage, descriptor_count, nullptr); void add_combined_image(uint32_t binding, std::shared_ptr<render_resource> in_texture);
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<texture> 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;
}
virtual void create() = 0; virtual void create() = 0;
virtual void destroy() = 0; protected:
vk::Pipeline pipeline_; vk::Pipeline pipeline_;
vk::PipelineCache pipeline_cache_;
vk::PipelineLayout pipeline_layout_; vk::PipelineLayout pipeline_layout_;
vk::DescriptorSetLayout descriptor_set_layout_; vk::DescriptorSetLayout descriptor_set_layout_;
vk::DescriptorSet descriptor_set_; vk::DescriptorSet descriptor_set_;
vk::DescriptorPool descriptor_pool_;
std::vector<vk::DescriptorSetLayoutBinding> descriptor_set_layout_bindings_; std::vector<vk::DescriptorSetLayoutBinding> descriptor_set_layout_bindings_;
std::map<uint32_t, buffer_vk> buffers_; std::map<uint32_t, std::shared_ptr<buffer_vk>> buffers_;
std::map<uint32_t, std::shared_ptr<texture>> textures_; std::map<uint32_t, std::shared_ptr<render_resource>> textures_;
protected: protected:
void create_pipeline_layout(); void create_pipeline_layout();
}; };

View File

@ -1,17 +1,67 @@
#pragma once #pragma once
#include "imgui.h" #include "imgui.h"
#include "renderer.h"
#include "application/application.h"
class render_resource : public std::enable_shared_from_this<render_resource> { class render_resource : public std::enable_shared_from_this<render_resource> {
public: 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; void init(uint32_t width, uint32_t height, vk::Format in_format) {
width_ = width;
virtual ImTextureID get_texture_id() = 0; height_ = height;
format = in_format;
void draw() { on_init();
}
void draw() const {
ImGui::Image(get_texture_id(), ImVec2(static_cast<float>(get_width()), static_cast<float>(get_height()))); ImGui::Image(get_texture_id(), ImVec2(static_cast<float>(get_width()), static_cast<float>(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_;
}; };

View File

@ -4,14 +4,6 @@
#include "application/application.h" #include "application/application.h"
#include "utils/utils.hpp" #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 { void* render_target::lock(lock_state state) const {
const auto r = application::get()->get_renderer(); const auto r = application::get()->get_renderer();
const auto& device = r->device; const auto& device = r->device;
@ -37,7 +29,14 @@ void render_target::unlock() {
device.unmapMemory(memory); 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(); auto r = application::get()->get_renderer();
const auto& device = r->device; const auto& device = r->device;
const auto& physical_device = r->physical_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.setArrayLayers(1);
image_create_info.setSamples(vk::SampleCountFlagBits::e1); image_create_info.setSamples(vk::SampleCountFlagBits::e1);
image_create_info.setTiling(vk::ImageTiling::eOptimal); 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.setSharingMode(vk::SharingMode::eExclusive);
image_create_info.setInitialLayout(vk::ImageLayout::eUndefined); image_create_info.setInitialLayout(vk::ImageLayout::eUndefined);
image = device.createImage(image_create_info); 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.setHeight(height);
framebuffer_create_info.setLayers(1); framebuffer_create_info.setLayers(1);
framebuffer = device.createFramebuffer(framebuffer_create_info); 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) { void render_target::on_init() {
const auto r = application::get()->get_renderer(); create(width_, height_);
const auto& device = r->device; }
device.destroyFramebuffer(framebuffer);
device.destroyImageView(image_view);
device.destroyImage(image);
device.freeMemory(memory);
void render_target::on_resize(uint32_t width, uint32_t height) {
destroy();
create(width, height); create(width, height);
} }

View File

@ -12,13 +12,8 @@ enum class lock_state {
class render_target : public render_resource { class render_target : public render_resource {
public: 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 uint32_t width, const uint32_t height) {
void resize(const int width, const int height) {
if (width_ == width && height_ == height) if (width_ == width && height_ == height)
return; return;
@ -32,17 +27,12 @@ public:
void* lock(lock_state state) const; void* lock(lock_state state) const;
void unlock(); void unlock();
std::function<void(std::shared_ptr<render_resource>)> on_resize_callback; void destroy() override;
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);
int width_ = 0; std::function<void(std::shared_ptr<render_resource>)> on_resize_callback;
int height_ = 0; 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);
}; };

View File

@ -6,6 +6,17 @@
#include "application/application.h" #include "application/application.h"
#include "texture.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<vk::ExtensionProperties>& properties, const char* extension) { static bool is_extension_available(const std::vector<vk::ExtensionProperties>& properties, const char* extension) {
return std::ranges::any_of(properties, [extension](const vk::ExtensionProperties& p) { return std::ranges::any_of(properties, [extension](const vk::ExtensionProperties& p) {
return strcmp(p.extensionName, extension) == 0; return strcmp(p.extensionName, extension) == 0;
@ -36,12 +47,27 @@ vk::CommandBuffer renderer::create_command_buffer(vk::CommandBufferLevel level,
return command_buffer; 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(); command_buffer.end();
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; vk::SubmitInfo submit_info;
submit_info.setCommandBuffers(command_buffer); submit_info.setCommandBuffers(command_buffer);
queue.submit(submit_info, nullptr); queue.submit(submit_info, nullptr);
}
} }
void renderer::init_vulkan(GLFWwindow* window_handle) { void renderer::init_vulkan(GLFWwindow* window_handle) {
@ -70,7 +96,7 @@ void renderer::init_vulkan(GLFWwindow* window_handle) {
init_info.Device = device; init_info.Device = device;
init_info.QueueFamily = queue_family; init_info.QueueFamily = queue_family;
init_info.Queue = queue; init_info.Queue = queue;
init_info.PipelineCache = pipeline_cache; init_info.PipelineCache = VK_NULL_HANDLE;
init_info.DescriptorPool = descriptor_pool; init_info.DescriptorPool = descriptor_pool;
init_info.RenderPass = main_window_data.RenderPass; init_info.RenderPass = main_window_data.RenderPass;
init_info.Subpass = 0; init_info.Subpass = 0;
@ -120,10 +146,30 @@ void renderer::setup_vulkan(std::vector<const char*> instance_extensions) {
create_info.flags |= vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR; create_info.flags |= vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR;
} }
#endif #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 Vulkan Instance
create_info.setPEnabledExtensionNames(instance_extensions); create_info.setPEnabledExtensionNames(instance_extensions);
instance = vk::createInstance(create_info, allocator); 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) // Select Physical Device (GPU)
@ -228,8 +274,8 @@ void renderer::cleanup_vulkan() const {
device.destroyDescriptorPool(descriptor_pool); device.destroyDescriptorPool(descriptor_pool);
#ifdef APP_USE_VULKAN_DEBUG_REPORT #ifdef APP_USE_VULKAN_DEBUG_REPORT
// Remove the debug report callback // Remove the debug report callback
auto vkDestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(g_Instance, "vkDestroyDebugReportCallbackEXT"); auto vkDestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT");
vkDestroyDebugReportCallbackEXT(g_Instance, g_DebugReport, g_Allocator); vkDestroyDebugReportCallbackEXT(instance, debug_report, (VkAllocationCallbacks*)allocator);
#endif // APP_USE_VULKAN_DEBUG_REPORT #endif // APP_USE_VULKAN_DEBUG_REPORT
device.destroy(); device.destroy();
@ -413,7 +459,9 @@ void renderer::end_frame(GLFWwindow* window_handle) {
std::shared_ptr<texture> renderer::create_texture(const uint8_t* data, int width, int height, vk::Format format) { std::shared_ptr<texture> renderer::create_texture(const uint8_t* data, int width, int height, vk::Format format) {
auto out = std::make_shared<texture>(); auto out = std::make_shared<texture>();
out->init_data(data, width, height, format); out->init(width, height, format);
if (data)
out->upload(data, width * height * 4);
return out; return out;
} }

View File

@ -7,6 +7,10 @@
#include <vulkan/vulkan.hpp> #include <vulkan/vulkan.hpp>
#ifdef _DEBUG
#define APP_USE_VULKAN_DEBUG_REPORT
#endif
class pixel_shader_drawer; class pixel_shader_drawer;
class render_target; class render_target;
class texture; class texture;
@ -58,10 +62,12 @@ public:
uint32_t queue_family = (uint32_t) -1; uint32_t queue_family = (uint32_t) -1;
vk::Queue queue = VK_NULL_HANDLE; vk::Queue queue = VK_NULL_HANDLE;
vk::DescriptorPool descriptor_pool = 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::CommandPool get_command_pool() const;
[[nodiscard]] vk::CommandBuffer create_command_buffer(vk::CommandBufferLevel level, bool begin) 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; ImGui_ImplVulkanH_Window main_window_data;
int min_image_count = 2; int min_image_count = 2;

View File

@ -8,12 +8,6 @@
texture::texture() { texture::texture() {
format = vk::Format::eUndefined;
width_ = 0;
height_ = 0;
image = nullptr;
image_view = nullptr;
sampler = nullptr;
memory = 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<uint32_t>(width), static_cast<uint32_t>(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) { void texture::upload(const void* data, size_t size) {
renderer* r = application::get()->get_renderer(); renderer* r = application::get()->get_renderer();
const vk::Device& device = r->device; 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); // 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);
}

View File

@ -11,30 +11,9 @@ public:
~texture() override; ~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; } 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); 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: protected:
int width_; void on_init() override;
int height_;
}; };