vulkan图片加载

This commit is contained in:
Nanako 2024-02-20 08:44:56 +08:00 committed by daiqingshuang
parent fbb01724a4
commit 45bd309e8d
28 changed files with 1076 additions and 843 deletions

View File

@ -7,7 +7,7 @@
#include "imgui_internal.h"
#include "filesystem/stb_image.h"
#include "rhi/texture.h"
#include "rhi/vulkan/renderer_vk.h"
#include "rhi/renderer.h"
#include "spdlog/async.h"
#include "spdlog/spdlog.h"
#include "spdlog/sinks/basic_file_sink.h"
@ -31,7 +31,7 @@ void application::init(const window_params& in_window_params, int argc, char** a
init_glfw();
init_imgui();
renderer_ = new renderer_vk();
renderer_ = new renderer();
renderer_->pre_init();
@ -44,7 +44,6 @@ void application::init(const window_params& in_window_params, int argc, char** a
}
renderer_->init(window_);
renderer_->resize(in_window_params.width, in_window_params.height);
g_is_running = true;
}
@ -67,7 +66,6 @@ int application::run() {
void application::shutdown() {
renderer_->shutdown();
destroy_imgui();
renderer_->post_shutdown();
delete renderer_;
renderer_ = nullptr;
@ -77,31 +75,31 @@ void application::shutdown() {
g_is_running = false;
}
std::shared_ptr<texture> application::load_texture(const std::string& path) const {
std::shared_ptr<texture> application::load_texture(const std::string& path, vk::Format format) const {
int width = 0;
int height = 0;
unsigned char* image_data = stbi_load(path.c_str(), &width, &height, nullptr, 4);
uint8_t* image_data = stbi_load(path.c_str(), &width, &height, nullptr, 4);
if (!image_data) {
spdlog::error("Failed to load texture: {}", path.c_str());
return nullptr;
}
const auto texture = renderer_->create_texture(image_data, width, height);
const auto texture = renderer::create_texture(image_data, width, height, format);
stbi_image_free(image_data);
return texture;
}
std::shared_ptr<texture>
application::create_texture(const unsigned char* data, const int width, const int height) const {
return renderer_->create_texture(data, width, height);
application::create_texture(const unsigned char* data, const int width, const int height, vk::Format format) const {
return renderer::create_texture(data, width, height, format);
}
std::shared_ptr<render_target> application::create_render_target(const int width, const int height,
texture_format format) const {
return renderer_->create_render_target(width, height, format);
vk::Format format) const {
return renderer::create_render_target(width, height, format);
}
std::shared_ptr<pixel_shader_drawer> application::create_pixel_shader_drawer() const {
return renderer_->create_pixel_shader_drawer();
return nullptr;
}
void application::init_glfw() {

View File

@ -2,8 +2,9 @@
#include <string>
#include "imgui.h"
#include "GLFW/glfw3.h"
#include <vulkan/vulkan.hpp>
class renderer_vk;
class renderer;
class pixel_shader_drawer;
class render_target;
class texture;
@ -54,12 +55,12 @@ public:
virtual void init_imgui(ImGuiContext* in_context) = 0;
[[nodiscard]] std::shared_ptr<texture> load_texture(const std::string& path) const;
[[nodiscard]] std::shared_ptr<texture> load_texture(const std::string& path, vk::Format format = vk::Format::eR8G8B8A8Unorm) const;
std::shared_ptr<texture> create_texture(const unsigned char* data, int width, int height) const;
std::shared_ptr<texture> create_texture(const unsigned char* data, int width, int height, vk::Format format) const;
[[nodiscard]] std::shared_ptr<render_target> create_render_target(int width, int height,
texture_format format) const;
vk::Format format) const;
[[nodiscard]] std::shared_ptr<pixel_shader_drawer> create_pixel_shader_drawer() const;
@ -67,11 +68,11 @@ public:
[[nodiscard]] virtual const char* get_draw_ps_vertex_shader_entry() const = 0; // Vertex Shader used for drawing ps
[[nodiscard]] renderer_vk* get_renderer() const { return renderer_; }
[[nodiscard]] renderer* get_renderer() const { return renderer_; }
[[nodiscard]] GLFWwindow* get_window() const { return window_; }
protected:
renderer_vk* renderer_ = nullptr;
renderer* renderer_ = nullptr;
GLFWwindow* window_ = nullptr;
std::shared_ptr<spdlog::logger> async_spdlog_;

View File

@ -1,6 +1,5 @@
#pragma once
#include "spdlog/spdlog.h"
#include "rhi/rhi_defintion.h"
#ifdef core_EXPORTS
#define CORE_API __declspec(dllexport)

61
core/rhi/buffer_vk.cpp Normal file
View File

@ -0,0 +1,61 @@
#include "buffer_vk.h"
#include "utils/utils.hpp"
buffer_vk::buffer_vk() {
buffer = nullptr;
memory = nullptr;
descriptor_type = vk::DescriptorType::eUniformBuffer;
}
void buffer_vk::create(uint32_t size, vk::BufferUsageFlagBits in_usage, vk::DescriptorType in_descriptor_type) {
destroy();
descriptor_type = in_descriptor_type;
const renderer* render_vk = application::get()->get_renderer();
const vk::Device& device = render_vk->device;
vk::BufferCreateInfo buffer_create_info;
buffer_create_info.setSize(size);
buffer_create_info.setUsage(in_usage);
buffer_create_info.setSharingMode(vk::SharingMode::eExclusive);
buffer = device.createBuffer(buffer_create_info);
const vk::PhysicalDeviceMemoryProperties memory_properties = render_vk->physical_device.getMemoryProperties();
const vk::MemoryRequirements memory_requirements = device.getBufferMemoryRequirements(buffer);
const auto memory_type = vk::su::findMemoryType(memory_properties, memory_requirements.memoryTypeBits, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);
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.bindBufferMemory(buffer, memory, 0);
}
void buffer_vk::create_storage(uint32_t size) {
create(size, vk::BufferUsageFlagBits::eStorageBuffer, vk::DescriptorType::eStorageBuffer);
}
void buffer_vk::create_uniform(uint32_t size) {
create(size, vk::BufferUsageFlagBits::eUniformBuffer, vk::DescriptorType::eUniformBuffer);
}
void buffer_vk::create_staging(uint32_t size) {
create(size, vk::BufferUsageFlagBits::eTransferSrc, vk::DescriptorType::eUniformBuffer);
}
void buffer_vk::destroy() const {
if (!buffer) {
return;
}
const renderer* render_vk = application::get()->get_renderer();
const vk::Device& device = render_vk->device;
device.destroyBuffer(buffer);
device.freeMemory(memory);
}
void buffer_vk::update(const void* data, uint32_t size) {
const auto p = map<void>();
memcpy(p, data, size);
unmap();
}

52
core/rhi/buffer_vk.h Normal file
View File

@ -0,0 +1,52 @@
#pragma once
#include <application/application.h>
#include <vulkan/vulkan.hpp>
#include "renderer.h"
class CORE_API buffer_vk {
public:
buffer_vk();
~buffer_vk() { destroy(); }
void create(uint32_t size, vk::BufferUsageFlagBits in_usage, vk::DescriptorType in_descriptor_type);
void create_storage(uint32_t size);
void create_uniform(uint32_t size);
void create_staging(uint32_t size);
void destroy() const;
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);
check_vk_result(err);
return static_cast<T*>(mapped);
}
void unmap() const {
const auto& device = application::get()->get_renderer()->device;
device.unmapMemory(memory);
}
void update(const void* data, uint32_t size);
template <typename T>
void update(const T& data) {
update(&data, sizeof(T));
}
template <typename T>
void update(const std::vector<T>& data) {
update(data.data(), data.size() * sizeof(T));
}
operator vk::DescriptorBufferInfo() const {
vk::DescriptorBufferInfo descriptor_buffer_info;
descriptor_buffer_info.setBuffer(buffer);
descriptor_buffer_info.setOffset(0);
descriptor_buffer_info.setRange(VK_WHOLE_SIZE);
return descriptor_buffer_info;
}
vk::Buffer buffer;
vk::DeviceMemory memory;
vk::DescriptorType descriptor_type;
};

View File

@ -0,0 +1,98 @@
#include "compute_pipeline.h"
#include "renderer.h"
#include <vulkan/vulkan.hpp>
void compute_pipeline::add_binding(uint32_t binding, vk::DescriptorType descriptor_type, uint32_t descriptor_count,
const vk::Sampler* immutable_samplers) {
const vk::ShaderStageFlags flag = vk::ShaderStageFlagBits::eCompute;
vk::DescriptorSetLayoutBinding descriptor_set_layout_binding;
descriptor_set_layout_binding.setBinding(binding);
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);
descriptor_set_layout_bindings_.push_back(descriptor_set_layout_binding);
}
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_);
pipeline_shader_stage_create_info.setPName("main");
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);
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();
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);
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);
}
void compute_pipeline::set_shader(const uint8_t* shader_code, size_t shader_code_size) {
const renderer* render_vk = application::get()->get_renderer();
const vk::Device& device = render_vk->device;
vk::ShaderModuleCreateInfo shader_module_create_info;
shader_module_create_info.setCodeSize(shader_code_size);
shader_module_create_info.setPCode(reinterpret_cast<const uint32_t*>(shader_code));
shader_module_ = device.createShaderModule(shader_module_create_info);
}

View File

@ -0,0 +1,15 @@
#pragma once
#include "pipeline.h"
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;
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 set_shader(const uint8_t *shader_code, size_t shader_code_size);
private:
vk::ShaderModule shader_module_;
};

53
core/rhi/pipeline.cpp Normal file
View File

@ -0,0 +1,53 @@
#include "pipeline.h"
#include "renderer.h"
#include "texture.h"
void pipeline::create_pipeline_layout() {
const renderer* render_vk = application::get()->get_renderer();
const vk::Device& device = render_vk->device;
vk::DescriptorSetLayoutCreateInfo descriptor_set_layout_create_info;
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);
vk::DescriptorSetAllocateInfo descriptor_set_allocate_info;
descriptor_set_allocate_info.setDescriptorPool(render_vk->descriptor_pool);
descriptor_set_allocate_info.setSetLayouts(descriptor_set_layout_);
descriptor_set_ = device.allocateDescriptorSets(descriptor_set_allocate_info).front();
std::vector<vk::WriteDescriptorSet> write_descriptor_sets;
for (const auto& binding_info: descriptor_set_layout_bindings_) {
vk::WriteDescriptorSet write_descriptor_set;
write_descriptor_set.setDstSet(descriptor_set_);
write_descriptor_set.setDstBinding(binding_info.binding);
write_descriptor_set.setDescriptorType(binding_info.descriptorType);
switch (binding_info.descriptorType) {
case vk::DescriptorType::eCombinedImageSampler:
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);
}
break;
case vk::DescriptorType::eUniformBuffer:
case vk::DescriptorType::eStorageBuffer: {
vk::DescriptorBufferInfo buffer_info = buffers_[binding_info.binding];
write_descriptor_set.setBufferInfo(buffer_info);
}
break;
default:
continue;
}
write_descriptor_sets.push_back(write_descriptor_set);
}
device.updateDescriptorSets(write_descriptor_sets, nullptr);
}

View File

@ -1,26 +1,34 @@
#pragma once
#include <vulkan/vulkan.hpp>
#include <map>
#include "buffer_vk.h"
class texture;
/// 1. add_binding
/// 2. create();
/// 3. execute_pipeline();
/// 3. dispatch();
class pipeline {
public:
virtual ~pipeline() = default;
virtual void add_binding(uint32_t binding, vk::DescriptorType descriptor_type, uint32_t descriptor_count, const vk::Sampler* immutable_samplers) = 0;
void add_uniform_buffer(uint32_t binding, uint32_t descriptor_count = 1) {
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, uint32_t descriptor_count = 1) {
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, uint32_t descriptor_count = 1) {
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);
@ -28,19 +36,23 @@ public:
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_combined_image_sampler(uint32_t binding, uint32_t descriptor_count = 1, const vk::Sampler* immutable_samplers = nullptr) {
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 create_pipeline_layout();
virtual void create() = 0;
virtual void destroy() = 0;
virtual void bind(vk::CommandBuffer command_buffer) const = 0;
void execute_pipeline() const;
vk::Pipeline pipeline_;
vk::PipelineCache pipeline_cache_;
vk::PipelineLayout pipeline_layout_;
vk::DescriptorSetLayout descriptor_set_layout_;
vk::DescriptorSet descriptor_set_;
std::vector<vk::DescriptorSetLayoutBinding> descriptor_set_layout_bindings_;
std::map<uint32_t, buffer_vk> buffers_;
std::map<uint32_t, std::shared_ptr<texture>> textures_;
protected:
void create_pipeline_layout();
};

View File

@ -0,0 +1,95 @@
#include "render_target.h"
#include "renderer.h"
#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;
vk::ImageSubresource subresource;
subresource.setAspectMask(vk::ImageAspectFlagBits::eColor);
subresource.setMipLevel(0);
subresource.setArrayLayer(0);
const vk::SubresourceLayout subresource_layout = device.getImageSubresourceLayout(image, subresource);
void* data;
const vk::Result result = device.mapMemory(memory, 0, VK_WHOLE_SIZE, vk::MemoryMapFlags(), &data);
check_vk_result(result);
return static_cast<uint8_t*>(data) + subresource_layout.offset;
}
void render_target::unlock() {
const auto r = application::get()->get_renderer();
const auto& device = r->device;
device.unmapMemory(memory);
}
void render_target::create(int width, int height) {
auto r = application::get()->get_renderer();
const auto& device = r->device;
const auto& physical_device = r->physical_device;
vk::ImageCreateInfo image_create_info;
image_create_info.setImageType(vk::ImageType::e2D);
image_create_info.setFormat(format);
image_create_info.setExtent({static_cast<uint32_t>(width), static_cast<uint32_t>(height), 1});
image_create_info.setMipLevels(1);
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.setSharingMode(vk::SharingMode::eExclusive);
image_create_info.setInitialLayout(vk::ImageLayout::eUndefined);
image = device.createImage(image_create_info);
vk::PhysicalDeviceMemoryProperties memory_properties = physical_device.getMemoryProperties();
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 image_view_create_info;
image_view_create_info.setImage(image);
image_view_create_info.setViewType(vk::ImageViewType::e2D);
image_view_create_info.setFormat(format);
image_view_create_info.setSubresourceRange({vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1});
image_view = device.createImageView(image_view_create_info);
vk::FramebufferCreateInfo framebuffer_create_info;
framebuffer_create_info.setRenderPass(r->main_window_data.RenderPass);
framebuffer_create_info.setAttachmentCount(1);
framebuffer_create_info.setAttachments(image_view);
framebuffer_create_info.setWidth(width);
framebuffer_create_info.setHeight(height);
framebuffer_create_info.setLayers(1);
framebuffer = device.createFramebuffer(framebuffer_create_info);
}
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);
create(width, height);
}

View File

@ -1,6 +1,7 @@
#pragma once
#include <vulkan/vulkan.hpp>
#include "render_resource.h"
#include "rhi_defintion.h"
enum class lock_state {
NONE,
@ -13,14 +14,11 @@ 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 texture_format format) {
width_ = width;
height_ = height;
on_init(width, height, format);
}
void init(const int width, const int height, const vk::Format in_format);
virtual void resize(const int width, const int height) {
void resize(const int width, const int height) {
if (width_ == width && height_ == height)
return;
@ -31,15 +29,19 @@ public:
on_resize_callback(shared_from_this());
}
virtual void* lock(lock_state state) = 0;
virtual void unlock() = 0;
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:
virtual void on_init(int width, int height, texture_format format) = 0;
virtual void on_resize(int width, int height) = 0;
void create(int width, int height);
void on_resize(int width, int height);
int width_ = 0;
int height_ = 0;

View File

@ -1,13 +1,423 @@
#include "renderer.h"
#include "imgui_impl_glfw.h"
#include "render_target.h"
#include "application/application.h"
#include "texture.h"
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;
});
}
vk::CommandPool renderer::get_command_pool() const {
return main_window_data.Frames[main_window_data.FrameIndex].CommandPool;
}
vk::CommandBuffer renderer::create_command_buffer(vk::CommandBufferLevel level, bool begin) const {
vk::CommandBufferAllocateInfo alloc_info;
alloc_info.setCommandPool(get_command_pool());
alloc_info.setLevel(level);
alloc_info.setCommandBufferCount(1);
vk::CommandBuffer command_buffer;
auto err = device.allocateCommandBuffers(&alloc_info, &command_buffer);
check_vk_result(err);
// If requested, also start the new command buffer
if (begin) {
vk::CommandBufferBeginInfo begin_info;
begin_info.setFlags(vk::CommandBufferUsageFlagBits::eOneTimeSubmit);
command_buffer.begin(begin_info);
}
return command_buffer;
}
void renderer::end_command_buffer(vk::CommandBuffer command_buffer) {
command_buffer.end();
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;
uint32_t extensions_count = 0;
const char** glfw_extensions = glfwGetRequiredInstanceExtensions(&extensions_count);
for (uint32_t i = 0; i < extensions_count; i++)
extensions.push_back(glfw_extensions[i]);
setup_vulkan(extensions);
// Create Window Surface
VkSurfaceKHR surface;
VkResult err = glfwCreateWindowSurface(instance, window_handle, reinterpret_cast<VkAllocationCallbacks*>(allocator), &surface);
check_vk_result(err);
// Create Framebuffers
int w, h;
glfwGetFramebufferSize(window_handle, &w, &h);
setup_vulkan_window(surface, w, h);
ImGui_ImplGlfw_InitForVulkan(window_handle, true);
ImGui_ImplVulkan_InitInfo init_info = {};
init_info.Instance = instance;
init_info.PhysicalDevice = physical_device;
init_info.Device = device;
init_info.QueueFamily = queue_family;
init_info.Queue = queue;
init_info.PipelineCache = pipeline_cache;
init_info.DescriptorPool = descriptor_pool;
init_info.RenderPass = main_window_data.RenderPass;
init_info.Subpass = 0;
init_info.MinImageCount = min_image_count;
init_info.ImageCount = main_window_data.ImageCount;
init_info.MSAASamples = VK_SAMPLE_COUNT_1_BIT;
init_info.Allocator = reinterpret_cast<VkAllocationCallbacks*>(allocator);
init_info.CheckVkResultFn = check_vk_result;
ImGui_ImplVulkan_Init(&init_info);
}
vk::PhysicalDevice renderer::setup_vulkan_select_physical_device() const {
const std::vector<vk::PhysicalDevice> gpus = instance.enumeratePhysicalDevices();
IM_ASSERT(!gpus.empty());
// If a number >1 of GPUs got reported, find discrete GPU if present, or use first one available. This covers
// most common cases (multi-gpu/integrated+dedicated graphics). Handling more complicated setups (multiple
// dedicated GPUs) is out of scope of this sample.
for (auto& device: gpus) {
if (const auto properties = device.getProperties(); properties.deviceType == vk::PhysicalDeviceType::eDiscreteGpu)
return device;
}
// Use first GPU (Integrated) is a Discrete one is not available.
if (!gpus.empty())
return gpus[0];
return VK_NULL_HANDLE;
}
void renderer::setup_vulkan(std::vector<const char*> instance_extensions) {
// Create Vulkan Instance
{
vk::InstanceCreateInfo create_info;
// VkInstanceCreateInfo create_info = {};
// create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
// Enumerate available extensions
auto properties = vk::enumerateInstanceExtensionProperties();
// Enable required extensions
if (is_extension_available(properties, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME))
instance_extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
#ifdef VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME
if (is_extension_available(properties, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME)) {
instance_extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
create_info.flags |= vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR;
}
#endif
// Create Vulkan Instance
create_info.setPEnabledExtensionNames(instance_extensions);
instance = vk::createInstance(create_info, allocator);
}
// Select Physical Device (GPU)
physical_device = setup_vulkan_select_physical_device();
// Select graphics queue family
{
const auto queues = physical_device.getQueueFamilyProperties();
for (uint32_t i = 0; i < queues.size(); i++) {
if (queues[i].queueFlags & vk::QueueFlagBits::eGraphics) {
queue_family = i;
break;
}
}
IM_ASSERT(queue_family != static_cast<uint32_t>(-1));
}
// Create Logical Device (with 1 queue)
{
std::vector<const char*> device_extensions;
device_extensions.emplace_back("VK_KHR_swapchain");
// Enumerate physical device extension
auto properties = physical_device.enumerateDeviceExtensionProperties();
#ifdef VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME
if (is_extension_available(properties, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME))
device_extensions.push_back(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME);
#endif
std::vector<float> queue_priority = {1.0f};
vk::DeviceQueueCreateInfo queue_info;
queue_info.setQueueFamilyIndex(queue_family);
queue_info.setQueuePriorities(queue_priority);
vk::DeviceCreateInfo create_info;
create_info.setQueueCreateInfos(queue_info);
create_info.setPEnabledExtensionNames(device_extensions);
device = physical_device.createDevice(create_info, allocator);
queue = device.getQueue(queue_family, 0);
}
// Create Descriptor Pool
// The example only requires a single combined image sampler descriptor for the font image and only uses one descriptor set (for that)
// If you wish to load e.g. additional textures you may need to alter pools sizes.
{
std::vector<vk::DescriptorPoolSize> pool_sizes;
pool_sizes.emplace_back(vk::DescriptorType::eCombinedImageSampler, 1);
vk::DescriptorPoolCreateInfo descriptor_pool_create_info;
descriptor_pool_create_info.setMaxSets(2);
descriptor_pool_create_info.setPoolSizes(pool_sizes);
descriptor_pool = device.createDescriptorPool(descriptor_pool_create_info);
}
}
// All the ImGui_ImplVulkanH_XXX structures/functions are optional helpers used by the demo.
// Your real engine/app may not use them.
void renderer::setup_vulkan_window(VkSurfaceKHR surface, int width,
int height) {
main_window_data.Surface = surface;
// Check for WSI support
vk::Bool32 res;
const auto err = physical_device.getSurfaceSupportKHR(queue_family, main_window_data.Surface, &res);
check_vk_result(err);
if (res != VK_TRUE) {
fprintf(stderr, "Error no WSI support on physical device 0\n");
exit(-1);
}
// Select Surface Format
constexpr VkFormat requestSurfaceImageFormat[] = {
VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8_UNORM, VK_FORMAT_R8G8B8_UNORM
};
constexpr VkColorSpaceKHR requestSurfaceColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
main_window_data.SurfaceFormat = ImGui_ImplVulkanH_SelectSurfaceFormat(physical_device, main_window_data.Surface, requestSurfaceImageFormat,
(size_t) IM_ARRAYSIZE(requestSurfaceImageFormat),
requestSurfaceColorSpace);
// Select Present Mode
#ifdef APP_USE_UNLIMITED_FRAME_RATE
VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_FIFO_KHR };
#else
VkPresentModeKHR present_modes[] = {VK_PRESENT_MODE_FIFO_KHR};
#endif
main_window_data.PresentMode = ImGui_ImplVulkanH_SelectPresentMode(physical_device, main_window_data.Surface, &present_modes[0],
IM_ARRAYSIZE(present_modes));
//printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode);
// Create SwapChain, RenderPass, Framebuffer, etc.
IM_ASSERT(min_image_count >= 2);
ImGui_ImplVulkanH_CreateOrResizeWindow(instance, physical_device, device, &main_window_data, queue_family,
reinterpret_cast<VkAllocationCallbacks*>(allocator), width,
height, min_image_count);
}
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);
#endif // APP_USE_VULKAN_DEBUG_REPORT
device.destroy();
instance.destroy();
}
void renderer::cleanup_vulkan_window() {
ImGui_ImplVulkanH_DestroyWindow(instance, device, &main_window_data,
reinterpret_cast<VkAllocationCallbacks*>(allocator));
}
void renderer::frame_render(ImDrawData* draw_data) {
vk::Semaphore image_acquired_semaphore = main_window_data.FrameSemaphores[main_window_data.SemaphoreIndex].ImageAcquiredSemaphore;
vk::Semaphore render_complete_semaphore = main_window_data.FrameSemaphores[main_window_data.SemaphoreIndex].RenderCompleteSemaphore;
vk::Result err = device.acquireNextImageKHR(main_window_data.Swapchain, UINT64_MAX, image_acquired_semaphore, VK_NULL_HANDLE,
&main_window_data.FrameIndex);
if (err == vk::Result::eErrorOutOfDateKHR || err == vk::Result::eSuboptimalKHR) {
swap_chain_rebuild_ = true;
return;
}
check_vk_result(err);
ImGui_ImplVulkanH_Frame* fd = &main_window_data.Frames[main_window_data.FrameIndex];
const vk::CommandBuffer cmd_buf = fd->CommandBuffer;
const vk::Fence fence = fd->Fence; {
err = device.waitForFences(1, &fence, VK_TRUE, UINT64_MAX);
// wait indefinitely instead of periodically checking
check_vk_result(err);
err = device.resetFences(1, &fence);
check_vk_result(err);
} {
const vk::CommandPool command_pool = fd->CommandPool;
device.resetCommandPool(command_pool);
vk::CommandBufferBeginInfo info = {};
info.setFlags(vk::CommandBufferUsageFlagBits::eOneTimeSubmit);
cmd_buf.begin(info);
} {
const vk::Framebuffer framebuffer = fd->Framebuffer;
const vk::RenderPass render_pass = main_window_data.RenderPass;
const auto clear_color = main_window_data.ClearValue.color.float32;
const auto clear_depth = main_window_data.ClearValue.depthStencil.depth;
const auto clear_stencil = main_window_data.ClearValue.depthStencil.stencil;
vk::ClearValue clear_value;
clear_value.color = vk::ClearColorValue(std::array<float, 4>{
clear_color[0], clear_color[1], clear_color[2], clear_color[3]
});
clear_value.depthStencil = vk::ClearDepthStencilValue(clear_depth, clear_stencil);
std::vector<vk::ClearValue> clear_values;
clear_values.emplace_back(clear_value);
vk::RenderPassBeginInfo info;
info.setRenderPass(render_pass);
info.setFramebuffer(framebuffer);
info.renderArea.extent.width = main_window_data.Width;
info.renderArea.extent.height = main_window_data.Height;
info.setClearValues(clear_values);
cmd_buf.beginRenderPass(info, vk::SubpassContents::eInline);
}
// Record dear imgui primitives into command buffer
ImGui_ImplVulkan_RenderDrawData(draw_data, fd->CommandBuffer);
// Submit command buffer
vkCmdEndRenderPass(fd->CommandBuffer); {
vk::PipelineStageFlags wait_stage = vk::PipelineStageFlagBits::eColorAttachmentOutput;
vk::SubmitInfo info;
info.setWaitSemaphores(image_acquired_semaphore);
info.setWaitDstStageMask(wait_stage);
info.setCommandBuffers(cmd_buf);
info.setSignalSemaphores(render_complete_semaphore);
cmd_buf.end();
err = queue.submit(1, &info, fence);
check_vk_result(err);
}
}
void renderer::frame_present() {
if (swap_chain_rebuild_)
return;
vk::Semaphore render_complete_semaphore = main_window_data.FrameSemaphores[main_window_data.SemaphoreIndex].RenderCompleteSemaphore;
vk::SwapchainKHR swapchain = main_window_data.Swapchain;
uint32_t frame_index = main_window_data.FrameIndex;
vk::PresentInfoKHR info;
info.setWaitSemaphores(render_complete_semaphore);
info.setSwapchains(swapchain);
info.setImageIndices(frame_index);
try {
(void)queue.presentKHR(info);
} catch (const vk::OutOfDateKHRError& e) {
swap_chain_rebuild_ = true;
return;
}
main_window_data.SemaphoreIndex = (main_window_data.SemaphoreIndex + 1) % main_window_data.SemaphoreCount; // Now we can use the next set of semaphores
}
void renderer::pre_init() {
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
}
bool renderer::init(GLFWwindow* window_handle) {
if (has_initialized_)
return true;
if (!glfwVulkanSupported()) {
throw std::runtime_error("Vulkan not supported");
}
init_vulkan(window_handle);
has_initialized_ = true;
return true;
}
void renderer::shutdown() {
default_vs_ = nullptr;
ImGui_ImplGlfw_Shutdown();
ImGui_ImplVulkan_Shutdown();
cleanup_vulkan_window();
cleanup_vulkan();
}
std::shared_ptr<shader> renderer::get_pixel_shader_render_default_vs() {
if (!default_vs_)
default_vs_ = load_shader(application::get()->get_draw_ps_vertex_shader_entry());
return default_vs_;
void renderer::new_frame(GLFWwindow* window_handle) {
// Resize swap chain?
if (swap_chain_rebuild_)
{
int width, height;
glfwGetFramebufferSize(window_handle, &width, &height);
if (width > 0 && height > 0)
{
ImGui_ImplVulkan_SetMinImageCount(min_image_count);
ImGui_ImplVulkanH_CreateOrResizeWindow(instance, physical_device, device, &main_window_data, queue_family, reinterpret_cast<VkAllocationCallbacks*>(allocator), width, height, min_image_count);
main_window_data.FrameIndex = 0;
swap_chain_rebuild_ = false;
}
}
// Start the Dear ImGui frame
ImGui_ImplVulkan_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
}
void renderer::end_frame(GLFWwindow* window_handle) {
ImGuiIO& io = ImGui::GetIO();
// Rendering
ImGui::Render();
ImDrawData* main_draw_data = ImGui::GetDrawData();
const bool main_is_minimized = (main_draw_data->DisplaySize.x <= 0.0f || main_draw_data->DisplaySize.y <= 0.0f);
main_window_data.ClearValue.color.float32[0] = clear_color.x * clear_color.w;
main_window_data.ClearValue.color.float32[1] = clear_color.y * clear_color.w;
main_window_data.ClearValue.color.float32[2] = clear_color.z * clear_color.w;
main_window_data.ClearValue.color.float32[3] = clear_color.w;
if (!main_is_minimized)
frame_render(main_draw_data);
// Update and Render additional Platform Windows
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault();
}
// Present Main Platform Window
if (!main_is_minimized)
frame_present();
}
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);
return out;
}
std::shared_ptr<render_target> renderer::create_render_target(int width, int height, vk::Format format) {
auto out = std::make_shared<render_target>();
out->init(width, height, format);
return out;
}

View File

@ -1,10 +1,13 @@
#pragma once
#include "imgui_impl_vulkan.h"
#include "imgui.h"
#include "GLFW/glfw3.h"
#include <vulkan/vulkan.hpp>
class pixel_shader_drawer;
class shader;
class render_target;
class texture;
constexpr ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
@ -12,39 +15,68 @@ constexpr float clear_color_with_alpha[4] = {
clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w
};
static void check_vk_result(vk::Result err) {
if (err == vk::Result::eSuccess)
return;
spdlog::error("[vulkan] Error: VkResult = {}", vk::to_string(err));
abort();
}
static void check_vk_result(VkResult err) {
if (err == VK_SUCCESS)
return;
if (err < 0) {
spdlog::error("[vulkan] Error: VkResult = {}", err);
abort();
}
}
class renderer {
public:
virtual ~renderer() = default;
virtual void pre_init() {
}
void pre_init();
virtual bool init(GLFWwindow* window_handle) = 0;
bool init(GLFWwindow* window_handle);
virtual void shutdown();
virtual void post_shutdown() {
}
void new_frame(GLFWwindow* window_handle);
virtual std::shared_ptr<shader> load_shader(const std::string& entry_name) = 0;
void end_frame(GLFWwindow* window_handle);
virtual std::shared_ptr<shader> get_pixel_shader_render_default_vs();
virtual std::shared_ptr<pixel_shader_drawer> create_pixel_shader_drawer() = 0;
virtual void new_frame(GLFWwindow* window_handle) = 0;
virtual void end_frame(GLFWwindow* window_handle) = 0;
virtual void resize(int width, int height) = 0;
virtual std::shared_ptr<texture> create_texture(const unsigned char* data, int width, int height) = 0;
virtual std::shared_ptr<render_target> create_render_target(int width, int height, texture_format format) = 0;
static CORE_API std::shared_ptr<texture> create_texture(const uint8_t* data, int width, int height, vk::Format format);
static CORE_API std::shared_ptr<render_target> create_render_target(int width, int height, vk::Format format);
void set_vsync(const bool vsync) { vsync_ = vsync; }
vk::AllocationCallbacks* allocator = nullptr;
vk::Instance instance = VK_NULL_HANDLE;
vk::PhysicalDevice physical_device = VK_NULL_HANDLE;
vk::Device device = VK_NULL_HANDLE;
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;
[[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);
ImGui_ImplVulkanH_Window main_window_data;
int min_image_count = 2;
protected:
std::shared_ptr<shader> default_vs_;
void init_vulkan(GLFWwindow* window_handle);
[[nodiscard]] vk::PhysicalDevice setup_vulkan_select_physical_device() const;
void setup_vulkan(std::vector<const char*> instance_extensions);
void setup_vulkan_window(VkSurfaceKHR surface, int width, int height);
void cleanup_vulkan() const;
void cleanup_vulkan_window();
void frame_render(ImDrawData* draw_data);
void frame_present();
bool has_initialized_ = false;
bool swap_chain_rebuild_ = false;
bool vsync_ = true;
};

View File

@ -1,34 +0,0 @@
#pragma once
enum class texture_format {
RGBA8,
RGBA16_FLOAT,
RGBA32_FLOAT,
R32_FLOAT,
RG32_FLOAT,
R11F_G11F_B10F,
R16_FLOAT,
RGBA16,
RGB10_A2,
RG16,
RG8,
R16,
R8,
RG16_SNORM,
RG8_SNORM,
R16_SNORM,
R8_SNORM,
R32I,
R32UI,
R8I,
R16I,
R32F,
R8UI,
R16UI,
RG32I,
RG32UI,
RG8I,
RG16I,
RGB10_A2UI,
RG16UI,
};

View File

@ -1,58 +0,0 @@
#pragma once
class render_target;
class texture;
struct shader_draw_data {
int width;
int height;
};
class shader : public std::enable_shared_from_this<shader> {
public:
virtual ~shader() = default;
virtual bool init() { return false; }
[[nodiscard]] virtual bool is_initialized() const = 0;
virtual void bind() = 0;
virtual void unbind() = 0;
virtual void compute(int x, int y, int z) {
}
// param setters
virtual void set_cbuffer(const char* name, void* buffer, int size) = 0;
virtual void set_uav_buffer(const char* name, void* buffer, int count, int element_size) {
}
virtual void set_texture(const char* name, std::shared_ptr<texture> in_texture) = 0;
virtual void set_render_target(const char* name, std::shared_ptr<render_target> in_render_target) = 0;
template<typename T>
void set_cbuffer(const char* name, const T& buffer) {
set_cbuffer(name, (void*) &buffer, sizeof(T));
}
template<typename T>
void set_cbuffer(const char* name, const std::vector<T>& buffer) {
set_cbuffer(name, (void*) buffer.data(), sizeof(T) * buffer.size());
}
template<typename T>
void set_uav_buffer(const char* name, const T& buffer) {
set_uav_buffer(name, (void*) &buffer, sizeof(buffer), sizeof(T));
}
template<typename T>
void set_uav_buffer(const char* name, const std::vector<T>& buffer) {
set_uav_buffer(name, (void*) buffer.data(), buffer.size(), sizeof(T));
}
void begin_draw(const shader_draw_data& in_data) { if (on_begin_draw) on_begin_draw(in_data, *this); }
std::function<void(const shader_draw_data&, shader&)> on_begin_draw;
};

157
core/rhi/texture.cpp Normal file
View File

@ -0,0 +1,157 @@
#include "texture.h"
#include "buffer_vk.h"
#include "application/application.h"
#include "renderer.h"
#include "utils/utils.hpp"
texture::texture() {
format = vk::Format::eUndefined;
width_ = 0;
height_ = 0;
image = nullptr;
image_view = nullptr;
sampler = nullptr;
memory = nullptr;
}
texture::~texture() {
if (image) {
const renderer* render_vk = application::get()->get_renderer();
const vk::Device& device = render_vk->device;
device.destroyImage(image);
device.destroyImageView(image_view);
device.destroySampler(sampler);
device.freeMemory(memory);
}
}
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;
// Create Upload Buffer
vk::BufferCreateInfo buffer_info;
buffer_info.setSize(size);
buffer_info.setUsage(vk::BufferUsageFlagBits::eTransferSrc);
buffer_info.setSharingMode(vk::SharingMode::eExclusive);
vk::Buffer upload_buffer = device.createBuffer(buffer_info);
vk::MemoryRequirements req = device.getBufferMemoryRequirements(upload_buffer);
uint32_t upload_memory_type = vk::su::findMemoryType(r->physical_device.getMemoryProperties(), req.memoryTypeBits,
vk::MemoryPropertyFlagBits::eHostVisible);
vk::MemoryAllocateInfo alloc_info;
alloc_info.setAllocationSize(req.size);
alloc_info.setMemoryTypeIndex(upload_memory_type);
vk::DeviceMemory upload_memory = device.allocateMemory(alloc_info);
device.bindBufferMemory(upload_buffer, upload_memory, 0);
void* p = device.mapMemory(upload_memory, 0, size);
memcpy(p, data, size);
vk::MappedMemoryRange memory_range;
memory_range.setMemory(upload_memory);
memory_range.setSize(size);
device.flushMappedMemoryRanges(memory_range);
device.unmapMemory(upload_memory);
const vk::CommandBuffer command_buffer = r->create_command_buffer(vk::CommandBufferLevel::ePrimary, true);
vk::ImageMemoryBarrier copy_barrier;
copy_barrier.setDstAccessMask(vk::AccessFlagBits::eTransferWrite);
copy_barrier.setOldLayout(vk::ImageLayout::eUndefined);
copy_barrier.setNewLayout(vk::ImageLayout::eTransferDstOptimal);
copy_barrier.setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED);
copy_barrier.setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED);
copy_barrier.setImage(image);
copy_barrier.setSubresourceRange({vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1});
command_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eHost, vk::PipelineStageFlagBits::eTransfer, {}, {}, {},
copy_barrier);
vk::BufferImageCopy region;
region.setImageSubresource({vk::ImageAspectFlagBits::eColor, 0, 0, 1});
region.setImageExtent({static_cast<uint32_t>(width_), static_cast<uint32_t>(height_), 1});
command_buffer.copyBufferToImage(upload_buffer, image, vk::ImageLayout::eTransferDstOptimal, region);
vk::ImageMemoryBarrier use_barrier;
use_barrier.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite);
use_barrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead);
use_barrier.setOldLayout(vk::ImageLayout::eTransferDstOptimal);
use_barrier.setNewLayout(vk::ImageLayout::eShaderReadOnlyOptimal);
use_barrier.setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED);
use_barrier.setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED);
use_barrier.setImage(image);
use_barrier.setSubresourceRange({vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1});
command_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {},
{}, {}, use_barrier);
r->end_command_buffer(command_buffer);
device.waitIdle();
device.destroyBuffer(upload_buffer);
device.freeMemory(upload_memory);
// device.freeCommandBuffers(command_pool, command_buffer);
}

View File

@ -1,21 +1,39 @@
#pragma once
#include "imgui.h"
#include <string>
#include <vulkan/vulkan.hpp>
#include "buffer_vk.h"
#include "render_resource.h"
class texture : public render_resource {
public:
texture(): width_(0), height_(0) {
}
texture();
virtual bool init_data(const unsigned char* data, int width, int height) = 0;
[[nodiscard]] virtual bool is_valid() const = 0;
~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_;

View File

@ -1,48 +0,0 @@
#include "compute_pipeline.h"
#include "application/application.h"
#include <vulkan/vulkan.hpp>
#include "renderer_vk.h"
void compute_pipeline::add_binding(uint32_t binding, vk::DescriptorType descriptor_type, uint32_t descriptor_count, const vk::Sampler* immutable_samplers) {
const vk::ShaderStageFlags flag = vk::ShaderStageFlagBits::eCompute;
vk::DescriptorSetLayoutBinding descriptor_set_layout_binding;
descriptor_set_layout_binding.setBinding(binding);
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);
descriptor_set_layout_bindings_.push_back(descriptor_set_layout_binding);
}
void compute_pipeline::create() {
const auto renderer_vk = application::get()->get_renderer();
auto device = renderer_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::ComputePipelineCreateInfo compute_pipeline_create_info;
compute_pipeline_create_info.setLayout(pipeline_layout_);
const auto pipeline_result = device.createComputePipeline(pipeline_cache_, compute_pipeline_create_info);
check_vk_result(pipeline_result.result);
pipeline_ = pipeline_result.value;
}
void compute_pipeline::destroy() {
const auto renderer_vk = application::get()->get_renderer();
auto device = renderer_vk->device;
device.destroyPipeline(pipeline_);
device.destroyPipelineCache(pipeline_cache_);
device.destroyPipelineLayout(pipeline_layout_);
}
void compute_pipeline::bind(vk::CommandBuffer command_buffer) const {
command_buffer.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline_);
}

View File

@ -1,14 +0,0 @@
#pragma once
#include "pipeline.h"
class compute_pipeline : pipeline {
public:
void add_binding(uint32_t binding, vk::DescriptorType descriptor_type, uint32_t descriptor_count, const vk::Sampler* immutable_samplers) override;
void create() override;
void destroy() override;
void bind(vk::CommandBuffer command_buffer) const override;
void set_shader(const std::string& file_path) {
}
};

View File

@ -1,51 +0,0 @@
#include "pipeline.h"
#include "renderer_vk.h"
#include "application/application.h"
void pipeline::create_pipeline_layout() {
const auto renderer = application::get()->get_renderer();
const auto device = renderer->device;
vk::DescriptorSetLayoutCreateInfo descriptor_set_layout_create_info;
descriptor_set_layout_create_info.setBindings(descriptor_set_layout_bindings_);
vk::DescriptorSetLayout 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);
}
void pipeline::execute_pipeline() const {
#ifdef _DEBUG
if (pipeline_ == vk::Pipeline()) {
throw std::runtime_error("Pipeline not created");
}
#endif
const auto renderer = application::get()->get_renderer();
const auto device = renderer->device;
const auto command_pool = renderer->command_pool;
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);
bind(command_buffer);
command_buffer.end();
vk::SubmitInfo submit_info;
submit_info.setCommandBufferCount(1);
submit_info.setPCommandBuffers(&command_buffer);
renderer->queue.submit(submit_info, nullptr);
renderer->queue.waitIdle();
device.freeCommandBuffers(command_pool, command_buffer);
device.destroyCommandPool(command_pool);
}

View File

@ -1 +0,0 @@
#include "render_target_vk.h"

View File

@ -1,8 +0,0 @@
#pragma once
#include "rhi/render_target.h"
class render_target_vk : public render_target {
};

View File

@ -1,404 +0,0 @@
#include "renderer_vk.h"
#include "imgui_impl_glfw.h"
#include "utils/utils.hpp"
#include "GLFW/glfw3.h"
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;
});
}
vk::PhysicalDevice renderer_vk::setup_vulkan_select_physical_device() const {
const std::vector<vk::PhysicalDevice> gpus = instance.enumeratePhysicalDevices();
IM_ASSERT(!gpus.empty());
// If a number >1 of GPUs got reported, find discrete GPU if present, or use first one available. This covers
// most common cases (multi-gpu/integrated+dedicated graphics). Handling more complicated setups (multiple
// dedicated GPUs) is out of scope of this sample.
for (auto& device: gpus) {
if (const auto properties = device.getProperties(); properties.deviceType == vk::PhysicalDeviceType::eDiscreteGpu)
return device;
}
// Use first GPU (Integrated) is a Discrete one is not available.
if (!gpus.empty())
return gpus[0];
return VK_NULL_HANDLE;
}
void renderer_vk::setup_vulkan(std::vector<const char*> instance_extensions) {
// Create Vulkan Instance
{
vk::InstanceCreateInfo create_info;
// VkInstanceCreateInfo create_info = {};
// create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
// Enumerate available extensions
auto properties = vk::enumerateInstanceExtensionProperties();
// Enable required extensions
if (is_extension_available(properties, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME))
instance_extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
#ifdef VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME
if (is_extension_available(properties, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME)) {
instance_extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
create_info.flags |= vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR;
}
#endif
// Create Vulkan Instance
create_info.setPEnabledExtensionNames(instance_extensions);
instance = vk::createInstance(create_info, allocator);
}
// Select Physical Device (GPU)
physical_device = setup_vulkan_select_physical_device();
// Select graphics queue family
{
const auto queues = physical_device.getQueueFamilyProperties();
for (uint32_t i = 0; i < queues.size(); i++) {
if (queues[i].queueFlags & vk::QueueFlagBits::eGraphics) {
queue_family = i;
break;
}
}
IM_ASSERT(queue_family != static_cast<uint32_t>(-1));
}
// Create Logical Device (with 1 queue)
{
std::vector<const char*> device_extensions;
device_extensions.emplace_back("VK_KHR_swapchain");
// Enumerate physical device extension
auto properties = physical_device.enumerateDeviceExtensionProperties();
#ifdef VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME
if (is_extension_available(properties, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME))
device_extensions.push_back(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME);
#endif
std::vector<float> queue_priority = {1.0f};
vk::DeviceQueueCreateInfo queue_info;
queue_info.setQueueFamilyIndex(queue_family);
queue_info.setQueuePriorities(queue_priority);
vk::DeviceCreateInfo create_info;
create_info.setQueueCreateInfos(queue_info);
create_info.setPEnabledExtensionNames(device_extensions);
device = physical_device.createDevice(create_info, allocator);
queue = device.getQueue(queue_family, 0);
}
// Create Descriptor Pool
// The example only requires a single combined image sampler descriptor for the font image and only uses one descriptor set (for that)
// If you wish to load e.g. additional textures you may need to alter pools sizes.
{
std::vector<vk::DescriptorPoolSize> pool_sizes;
pool_sizes.emplace_back(vk::DescriptorType::eCombinedImageSampler, 1);
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);
}
// Create Command Pool
{
vk::CommandPoolCreateInfo cmd_pool_info;
cmd_pool_info.setQueueFamilyIndex(queue_family);
cmd_pool_info.setFlags(vk::CommandPoolCreateFlagBits::eResetCommandBuffer);
command_pool = device.createCommandPool(cmd_pool_info);
}
}
// All the ImGui_ImplVulkanH_XXX structures/functions are optional helpers used by the demo.
// Your real engine/app may not use them.
void renderer_vk::setup_vulkan_window(VkSurfaceKHR surface, int width,
int height) {
main_window_data.Surface = surface;
// Check for WSI support
vk::Bool32 res;
const auto err = physical_device.getSurfaceSupportKHR(queue_family, main_window_data.Surface, &res);
check_vk_result(err);
if (res != VK_TRUE) {
fprintf(stderr, "Error no WSI support on physical device 0\n");
exit(-1);
}
// Select Surface Format
constexpr VkFormat requestSurfaceImageFormat[] = {
VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8_UNORM, VK_FORMAT_R8G8B8_UNORM
};
constexpr VkColorSpaceKHR requestSurfaceColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
main_window_data.SurfaceFormat = ImGui_ImplVulkanH_SelectSurfaceFormat(physical_device, main_window_data.Surface, requestSurfaceImageFormat,
(size_t) IM_ARRAYSIZE(requestSurfaceImageFormat),
requestSurfaceColorSpace);
// Select Present Mode
#ifdef APP_USE_UNLIMITED_FRAME_RATE
VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_FIFO_KHR };
#else
VkPresentModeKHR present_modes[] = {VK_PRESENT_MODE_FIFO_KHR};
#endif
main_window_data.PresentMode = ImGui_ImplVulkanH_SelectPresentMode(physical_device, main_window_data.Surface, &present_modes[0],
IM_ARRAYSIZE(present_modes));
//printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode);
// Create SwapChain, RenderPass, Framebuffer, etc.
IM_ASSERT(min_image_count >= 2);
ImGui_ImplVulkanH_CreateOrResizeWindow(instance, physical_device, device, &main_window_data, queue_family,
reinterpret_cast<VkAllocationCallbacks*>(allocator), width,
height, min_image_count);
}
void renderer_vk::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);
#endif // APP_USE_VULKAN_DEBUG_REPORT
device.destroy();
instance.destroy();
}
void renderer_vk::cleanup_vulkan_window() {
ImGui_ImplVulkanH_DestroyWindow(instance, device, &main_window_data,
reinterpret_cast<VkAllocationCallbacks*>(allocator));
}
void renderer_vk::frame_render(ImDrawData* draw_data) {
vk::Semaphore image_acquired_semaphore = main_window_data.FrameSemaphores[main_window_data.SemaphoreIndex].ImageAcquiredSemaphore;
vk::Semaphore render_complete_semaphore = main_window_data.FrameSemaphores[main_window_data.SemaphoreIndex].RenderCompleteSemaphore;
vk::Result err = device.acquireNextImageKHR(main_window_data.Swapchain, UINT64_MAX, image_acquired_semaphore, VK_NULL_HANDLE,
&main_window_data.FrameIndex);
if (err == vk::Result::eErrorOutOfDateKHR || err == vk::Result::eSuboptimalKHR) {
swap_chain_rebuild_ = true;
return;
}
check_vk_result(err);
ImGui_ImplVulkanH_Frame* fd = &main_window_data.Frames[main_window_data.FrameIndex];
const vk::CommandBuffer cmd_buf = fd->CommandBuffer;
const vk::Fence fence = fd->Fence; {
err = device.waitForFences(1, &fence, VK_TRUE, UINT64_MAX);
// wait indefinitely instead of periodically checking
check_vk_result(err);
err = device.resetFences(1, &fence);
check_vk_result(err);
} {
const vk::CommandPool command_pool = fd->CommandPool;
device.resetCommandPool(command_pool);
vk::CommandBufferBeginInfo info = {};
info.setFlags(vk::CommandBufferUsageFlagBits::eOneTimeSubmit);
cmd_buf.begin(info);
} {
const vk::Framebuffer framebuffer = fd->Framebuffer;
const vk::RenderPass render_pass = main_window_data.RenderPass;
const auto clear_color = main_window_data.ClearValue.color.float32;
const auto clear_depth = main_window_data.ClearValue.depthStencil.depth;
const auto clear_stencil = main_window_data.ClearValue.depthStencil.stencil;
vk::ClearValue clear_value;
clear_value.color = vk::ClearColorValue(std::array<float, 4>{
clear_color[0], clear_color[1], clear_color[2], clear_color[3]
});
clear_value.depthStencil = vk::ClearDepthStencilValue(clear_depth, clear_stencil);
std::vector<vk::ClearValue> clear_values;
clear_values.emplace_back(clear_value);
vk::RenderPassBeginInfo info;
info.setRenderPass(render_pass);
info.setFramebuffer(framebuffer);
info.renderArea.extent.width = main_window_data.Width;
info.renderArea.extent.height = main_window_data.Height;
info.setClearValues(clear_values);
cmd_buf.beginRenderPass(info, vk::SubpassContents::eInline);
}
// Record dear imgui primitives into command buffer
ImGui_ImplVulkan_RenderDrawData(draw_data, fd->CommandBuffer);
// Submit command buffer
vkCmdEndRenderPass(fd->CommandBuffer); {
vk::PipelineStageFlags wait_stage = vk::PipelineStageFlagBits::eColorAttachmentOutput;
vk::SubmitInfo info;
info.setWaitSemaphores(image_acquired_semaphore);
info.setWaitDstStageMask(wait_stage);
info.setCommandBuffers(cmd_buf);
info.setSignalSemaphores(render_complete_semaphore);
cmd_buf.end();
err = queue.submit(1, &info, fence);
check_vk_result(err);
}
}
void renderer_vk::frame_present() {
if (swap_chain_rebuild_)
return;
vk::Semaphore render_complete_semaphore = main_window_data.FrameSemaphores[main_window_data.SemaphoreIndex].RenderCompleteSemaphore;
vk::SwapchainKHR swapchain = main_window_data.Swapchain;
uint32_t frame_index = main_window_data.FrameIndex;
vk::PresentInfoKHR info;
info.setWaitSemaphores(render_complete_semaphore);
info.setSwapchains(swapchain);
info.setImageIndices(frame_index);
try {
(void)queue.presentKHR(info);
} catch (const vk::OutOfDateKHRError& e) {
swap_chain_rebuild_ = true;
return;
}
main_window_data.SemaphoreIndex = (main_window_data.SemaphoreIndex + 1) % main_window_data.SemaphoreCount; // Now we can use the next set of semaphores
}
void renderer_vk::pre_init() {
renderer::pre_init();
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
}
bool renderer_vk::init(GLFWwindow* window_handle) {
if (has_initialized_)
return true;
if (!glfwVulkanSupported()) {
throw std::runtime_error("Vulkan not supported");
}
init_vulkan(window_handle);
has_initialized_ = true;
return true;
}
void renderer_vk::shutdown() {
renderer::shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui_ImplVulkan_Shutdown();
}
std::shared_ptr<shader> renderer_vk::load_shader(const std::string& entry_name) {
return nullptr;
}
std::shared_ptr<pixel_shader_drawer> renderer_vk::create_pixel_shader_drawer() {
return nullptr;
}
void renderer_vk::new_frame(GLFWwindow* window_handle) {
// Resize swap chain?
if (swap_chain_rebuild_)
{
int width, height;
glfwGetFramebufferSize(window_handle, &width, &height);
if (width > 0 && height > 0)
{
ImGui_ImplVulkan_SetMinImageCount(min_image_count);
ImGui_ImplVulkanH_CreateOrResizeWindow(instance, physical_device, device, &main_window_data, queue_family, reinterpret_cast<VkAllocationCallbacks*>(allocator), width, height, min_image_count);
main_window_data.FrameIndex = 0;
swap_chain_rebuild_ = false;
}
}
// Start the Dear ImGui frame
ImGui_ImplVulkan_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
}
void renderer_vk::end_frame(GLFWwindow* window_handle) {
ImGuiIO& io = ImGui::GetIO();
// Rendering
ImGui::Render();
ImDrawData* main_draw_data = ImGui::GetDrawData();
const bool main_is_minimized = (main_draw_data->DisplaySize.x <= 0.0f || main_draw_data->DisplaySize.y <= 0.0f);
main_window_data.ClearValue.color.float32[0] = clear_color.x * clear_color.w;
main_window_data.ClearValue.color.float32[1] = clear_color.y * clear_color.w;
main_window_data.ClearValue.color.float32[2] = clear_color.z * clear_color.w;
main_window_data.ClearValue.color.float32[3] = clear_color.w;
if (!main_is_minimized)
frame_render(main_draw_data);
// Update and Render additional Platform Windows
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault();
}
// Present Main Platform Window
if (!main_is_minimized)
frame_present();
}
void renderer_vk::resize(int width, int height) {
}
std::shared_ptr<texture> renderer_vk::create_texture(const unsigned char* data, int width, int height) {
return nullptr;
}
std::shared_ptr<render_target> renderer_vk::create_render_target(int width, int height, texture_format format) {
return nullptr;
}
void renderer_vk::init_vulkan(GLFWwindow* window_handle) {
std::vector<const char*> extensions;
uint32_t extensions_count = 0;
const char** glfw_extensions = glfwGetRequiredInstanceExtensions(&extensions_count);
for (uint32_t i = 0; i < extensions_count; i++)
extensions.push_back(glfw_extensions[i]);
setup_vulkan(extensions);
// Create Window Surface
VkSurfaceKHR surface;
VkResult err = glfwCreateWindowSurface(instance, window_handle, reinterpret_cast<VkAllocationCallbacks*>(allocator), &surface);
check_vk_result(err);
// Create Framebuffers
int w, h;
glfwGetFramebufferSize(window_handle, &w, &h);
setup_vulkan_window(surface, w, h);
ImGui_ImplGlfw_InitForVulkan(window_handle, true);
ImGui_ImplVulkan_InitInfo init_info = {};
init_info.Instance = instance;
init_info.PhysicalDevice = physical_device;
init_info.Device = device;
init_info.QueueFamily = queue_family;
init_info.Queue = queue;
init_info.PipelineCache = pipeline_cache;
init_info.DescriptorPool = descriptor_pool;
init_info.RenderPass = main_window_data.RenderPass;
init_info.Subpass = 0;
init_info.MinImageCount = min_image_count;
init_info.ImageCount = main_window_data.ImageCount;
init_info.MSAASamples = VK_SAMPLE_COUNT_1_BIT;
init_info.Allocator = reinterpret_cast<VkAllocationCallbacks*>(allocator);
init_info.CheckVkResultFn = check_vk_result;
ImGui_ImplVulkan_Init(&init_info);
}

View File

@ -1,84 +0,0 @@
//
// Created by 46944 on 2024/2/19.
//
#pragma once
#include <vulkan/vulkan.hpp>
#include "imgui_impl_vulkan.h"
#include "rhi/renderer.h"
static void check_vk_result(vk::Result err) {
if (err == vk::Result::eSuccess)
return;
spdlog::error("[vulkan] Error: VkResult = {}", vk::to_string(err));
abort();
}
static void check_vk_result(VkResult err) {
if (err == VK_SUCCESS)
return;
if (err < 0) {
spdlog::error("[vulkan] Error: VkResult = {}", err);
abort();
}
}
class renderer_vk : public renderer {
public:
void pre_init() override;
bool init(GLFWwindow* window_handle) override;
void shutdown() override;
std::shared_ptr<shader> load_shader(const std::string& entry_name) override;
std::shared_ptr<pixel_shader_drawer> create_pixel_shader_drawer() override;
void new_frame(GLFWwindow* window_handle) override;
void end_frame(GLFWwindow* window_handle) override;
void resize(int width, int height) override;
std::shared_ptr<texture> create_texture(const unsigned char* data, int width, int height) override;
std::shared_ptr<render_target> create_render_target(int width, int height, texture_format format) override;
// Data
vk::AllocationCallbacks* allocator = nullptr;
vk::Instance instance = VK_NULL_HANDLE;
vk::PhysicalDevice physical_device = VK_NULL_HANDLE;
vk::Device device = VK_NULL_HANDLE;
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;
vk::CommandPool command_pool = VK_NULL_HANDLE;
ImGui_ImplVulkanH_Window main_window_data;
int min_image_count = 2;
protected:
[[nodiscard]] vk::PhysicalDevice setup_vulkan_select_physical_device() const;
void setup_vulkan(std::vector<const char*> instance_extensions);
void setup_vulkan_window(VkSurfaceKHR surface, int width, int height);
void cleanup_vulkan() const;
void cleanup_vulkan_window();
void frame_render(ImDrawData* draw_data);
void frame_present();
private:
void init_vulkan(GLFWwindow* window_handle);
bool has_initialized_ = false;
bool swap_chain_rebuild_ = false;
};

View File

@ -1,51 +0,0 @@
#include "texture_vk.h"
#include "renderer_vk.h"
#include "application/application.h"
#include "GLFW/glfw3.h"
bool texture_vk::init_data(const unsigned char* data, int width, int height) {
auto vk_rder = static_cast<renderer_vk*>(application::get()->get_renderer());
auto& device = vk_rder->device;
vk::ImageCreateInfo image_info;
image_info.setFormat(vk::Format::eR8G8B8A8Srgb);
image_info.setImageType(vk::ImageType::e2D);
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_ = device.createImage(image_info);
vk::ImageViewCreateInfo view_info;
view_info.setImage(image_);
view_info.setViewType(vk::ImageViewType::e2D);
view_info.setFormat(vk::Format::eR8G8B8A8Srgb);
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.setAddressModeU(vk::SamplerAddressMode::eClampToEdge);
sampler_info.setAddressModeV(vk::SamplerAddressMode::eClampToEdge);
sampler_info.setAddressModeW(vk::SamplerAddressMode::eClampToEdge);
sampler_info.setAnisotropyEnable(VK_FALSE);
sampler_info.setMaxAnisotropy(1);
sampler_info.setBorderColor(vk::BorderColor::eFloatOpaqueWhite);
sampler_info.setUnnormalizedCoordinates(VK_FALSE);
sampler_info.setCompareEnable(VK_FALSE);
sampler_info.setCompareOp(vk::CompareOp::eAlways);
sampler_info.setMipmapMode(vk::SamplerMipmapMode::eLinear);
sampler_ = device.createSampler(sampler_info);
vk::BufferCreateInfo buffer_info;
buffer_info.setSize(width * height * 4);
buffer_info.setUsage(vk::BufferUsageFlagBits::eTransferSrc);
buffer_info.setSharingMode(vk::SharingMode::eExclusive);
buffer_ = device.createBuffer(buffer_info);
return true;
}

View File

@ -1,17 +0,0 @@
#pragma once
#include <vulkan/vulkan.hpp>
#include "rhi/texture.h"
class texture_vk : public texture {
public:
bool init_data(const unsigned char* data, int width, int height) override;
bool is_valid() const override { return image_view_; }
ImTextureID get_texture_id() override { return static_cast<VkImageView>(image_view_); }
private:
vk::Image image_;
vk::ImageView image_view_;
vk::Sampler sampler_;
vk::Buffer buffer_;
};