vulkan图片加载
This commit is contained in:
parent
fbb01724a4
commit
45bd309e8d
@ -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() {
|
||||
|
@ -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_;
|
||||
|
||||
|
@ -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
61
core/rhi/buffer_vk.cpp
Normal 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
52
core/rhi/buffer_vk.h
Normal 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;
|
||||
};
|
98
core/rhi/compute_pipeline.cpp
Normal file
98
core/rhi/compute_pipeline.cpp
Normal 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);
|
||||
}
|
15
core/rhi/compute_pipeline.h
Normal file
15
core/rhi/compute_pipeline.h
Normal 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
53
core/rhi/pipeline.cpp
Normal 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);
|
||||
}
|
@ -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();
|
||||
};
|
95
core/rhi/render_target.cpp
Normal file
95
core/rhi/render_target.cpp
Normal 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);
|
||||
}
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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,
|
||||
};
|
@ -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
157
core/rhi/texture.cpp
Normal 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);
|
||||
}
|
@ -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_;
|
||||
|
@ -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_);
|
||||
}
|
@ -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) {
|
||||
|
||||
}
|
||||
};
|
@ -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);
|
||||
}
|
@ -1 +0,0 @@
|
||||
#include "render_target_vk.h"
|
@ -1,8 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "rhi/render_target.h"
|
||||
|
||||
|
||||
class render_target_vk : public render_target {
|
||||
|
||||
};
|
@ -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);
|
||||
}
|
@ -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;
|
||||
};
|
@ -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;
|
||||
}
|
@ -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_;
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user