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) {
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) {

View File

@ -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 <typename T>
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<T*>(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;
};

View File

@ -4,8 +4,15 @@
#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,
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) {

View File

@ -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;

View File

@ -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<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() {
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<vk::DescriptorPoolSize> pool_sizes;
{
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;
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<vk::DescriptorSet>& sets = device.allocateDescriptorSets(descriptor_set_allocate_info);
descriptor_set_ = sets.front();
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_) {
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);
}

View File

@ -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<texture> 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<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;
}
void add_uniform_buffer(uint32_t binding, std::shared_ptr<buffer_vk> buf);
void add_storage_buffer(uint32_t binding, std::shared_ptr<buffer_vk> buf);
void add_sampled_image(uint32_t binding, std::shared_ptr<render_resource> in_texture);
void add_storage_image(uint32_t binding, std::shared_ptr<render_resource> 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<render_resource> 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<vk::DescriptorSetLayoutBinding> descriptor_set_layout_bindings_;
std::map<uint32_t, buffer_vk> buffers_;
std::map<uint32_t, std::shared_ptr<texture>> textures_;
std::map<uint32_t, std::shared_ptr<buffer_vk>> buffers_;
std::map<uint32_t, std::shared_ptr<render_resource>> textures_;
protected:
void create_pipeline_layout();
};

View File

@ -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<render_resource> {
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<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 "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);
}

View File

@ -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<void(std::shared_ptr<render_resource>)> 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<void(std::shared_ptr<render_resource>)> 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);
};

View File

@ -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<vk::ExtensionProperties>& properties, const char* extension) {
return std::ranges::any_of(properties, [extension](const vk::ExtensionProperties& p) {
return strcmp(p.extensionName, extension) == 0;
@ -36,13 +47,28 @@ 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();
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) {
std::vector<const char*> extensions;
@ -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<const char*> 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<texture> renderer::create_texture(const uint8_t* data, int width, int height, vk::Format format) {
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;
}

View File

@ -7,6 +7,10 @@
#include <vulkan/vulkan.hpp>
#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;

View File

@ -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<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) {
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);
}

View File

@ -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;
};