vulkan图片加载
This commit is contained in:
parent
fbb01724a4
commit
45bd309e8d
@ -7,7 +7,7 @@
|
|||||||
#include "imgui_internal.h"
|
#include "imgui_internal.h"
|
||||||
#include "filesystem/stb_image.h"
|
#include "filesystem/stb_image.h"
|
||||||
#include "rhi/texture.h"
|
#include "rhi/texture.h"
|
||||||
#include "rhi/vulkan/renderer_vk.h"
|
#include "rhi/renderer.h"
|
||||||
#include "spdlog/async.h"
|
#include "spdlog/async.h"
|
||||||
#include "spdlog/spdlog.h"
|
#include "spdlog/spdlog.h"
|
||||||
#include "spdlog/sinks/basic_file_sink.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_glfw();
|
||||||
init_imgui();
|
init_imgui();
|
||||||
|
|
||||||
renderer_ = new renderer_vk();
|
renderer_ = new renderer();
|
||||||
|
|
||||||
renderer_->pre_init();
|
renderer_->pre_init();
|
||||||
|
|
||||||
@ -44,7 +44,6 @@ void application::init(const window_params& in_window_params, int argc, char** a
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderer_->init(window_);
|
renderer_->init(window_);
|
||||||
renderer_->resize(in_window_params.width, in_window_params.height);
|
|
||||||
g_is_running = true;
|
g_is_running = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +66,6 @@ int application::run() {
|
|||||||
void application::shutdown() {
|
void application::shutdown() {
|
||||||
renderer_->shutdown();
|
renderer_->shutdown();
|
||||||
destroy_imgui();
|
destroy_imgui();
|
||||||
renderer_->post_shutdown();
|
|
||||||
|
|
||||||
delete renderer_;
|
delete renderer_;
|
||||||
renderer_ = nullptr;
|
renderer_ = nullptr;
|
||||||
@ -77,31 +75,31 @@ void application::shutdown() {
|
|||||||
g_is_running = false;
|
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 width = 0;
|
||||||
int height = 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) {
|
if (!image_data) {
|
||||||
spdlog::error("Failed to load texture: {}", path.c_str());
|
spdlog::error("Failed to load texture: {}", path.c_str());
|
||||||
return nullptr;
|
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);
|
stbi_image_free(image_data);
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<texture>
|
std::shared_ptr<texture>
|
||||||
application::create_texture(const unsigned char* data, const int width, const int height) const {
|
application::create_texture(const unsigned char* data, const int width, const int height, vk::Format format) const {
|
||||||
return renderer_->create_texture(data, width, height);
|
return renderer::create_texture(data, width, height, format);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<render_target> application::create_render_target(const int width, const int height,
|
std::shared_ptr<render_target> application::create_render_target(const int width, const int height,
|
||||||
texture_format format) const {
|
vk::Format format) const {
|
||||||
return renderer_->create_render_target(width, height, format);
|
return renderer::create_render_target(width, height, format);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<pixel_shader_drawer> application::create_pixel_shader_drawer() const {
|
std::shared_ptr<pixel_shader_drawer> application::create_pixel_shader_drawer() const {
|
||||||
return renderer_->create_pixel_shader_drawer();
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void application::init_glfw() {
|
void application::init_glfw() {
|
||||||
|
@ -2,8 +2,9 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
#include "GLFW/glfw3.h"
|
#include "GLFW/glfw3.h"
|
||||||
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
class renderer_vk;
|
class renderer;
|
||||||
class pixel_shader_drawer;
|
class pixel_shader_drawer;
|
||||||
class render_target;
|
class render_target;
|
||||||
class texture;
|
class texture;
|
||||||
@ -54,12 +55,12 @@ public:
|
|||||||
|
|
||||||
virtual void init_imgui(ImGuiContext* in_context) = 0;
|
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,
|
[[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;
|
[[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]] 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_; }
|
[[nodiscard]] GLFWwindow* get_window() const { return window_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
renderer_vk* renderer_ = nullptr;
|
renderer* renderer_ = nullptr;
|
||||||
GLFWwindow* window_ = nullptr;
|
GLFWwindow* window_ = nullptr;
|
||||||
std::shared_ptr<spdlog::logger> async_spdlog_;
|
std::shared_ptr<spdlog::logger> async_spdlog_;
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "spdlog/spdlog.h"
|
#include "spdlog/spdlog.h"
|
||||||
#include "rhi/rhi_defintion.h"
|
|
||||||
|
|
||||||
#ifdef core_EXPORTS
|
#ifdef core_EXPORTS
|
||||||
#define CORE_API __declspec(dllexport)
|
#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
|
#pragma once
|
||||||
#include <vulkan/vulkan.hpp>
|
#include <vulkan/vulkan.hpp>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "buffer_vk.h"
|
||||||
|
|
||||||
|
class texture;
|
||||||
|
|
||||||
/// 1. add_binding
|
/// 1. add_binding
|
||||||
/// 2. create();
|
/// 2. create();
|
||||||
/// 3. execute_pipeline();
|
/// 3. dispatch();
|
||||||
class pipeline {
|
class pipeline {
|
||||||
public:
|
public:
|
||||||
virtual ~pipeline() = default;
|
virtual ~pipeline() = default;
|
||||||
|
|
||||||
virtual void add_binding(uint32_t binding, vk::DescriptorType descriptor_type, uint32_t descriptor_count, const vk::Sampler* immutable_samplers) = 0;
|
virtual void add_binding(uint32_t binding, vk::DescriptorType descriptor_type, uint32_t descriptor_count, 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);
|
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);
|
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) {
|
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);
|
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);
|
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) {
|
void add_input_attachment(uint32_t binding, uint32_t descriptor_count = 1) {
|
||||||
add_binding(binding, vk::DescriptorType::eInputAttachment, descriptor_count, nullptr);
|
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) {
|
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);
|
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);
|
add_binding(binding, vk::DescriptorType::eCombinedImageSampler, descriptor_count, immutable_samplers);
|
||||||
|
textures_[binding] = in_texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
void create_pipeline_layout();
|
|
||||||
|
|
||||||
virtual void create() = 0;
|
virtual void create() = 0;
|
||||||
virtual void destroy() = 0;
|
virtual void destroy() = 0;
|
||||||
virtual void bind(vk::CommandBuffer command_buffer) const = 0;
|
|
||||||
void execute_pipeline() const;
|
|
||||||
|
|
||||||
vk::Pipeline pipeline_;
|
vk::Pipeline pipeline_;
|
||||||
vk::PipelineCache pipeline_cache_;
|
vk::PipelineCache pipeline_cache_;
|
||||||
vk::PipelineLayout pipeline_layout_;
|
vk::PipelineLayout pipeline_layout_;
|
||||||
|
vk::DescriptorSetLayout descriptor_set_layout_;
|
||||||
|
vk::DescriptorSet descriptor_set_;
|
||||||
std::vector<vk::DescriptorSetLayoutBinding> descriptor_set_layout_bindings_;
|
std::vector<vk::DescriptorSetLayoutBinding> descriptor_set_layout_bindings_;
|
||||||
|
|
||||||
|
std::map<uint32_t, buffer_vk> buffers_;
|
||||||
|
std::map<uint32_t, std::shared_ptr<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
|
#pragma once
|
||||||
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
#include "render_resource.h"
|
#include "render_resource.h"
|
||||||
#include "rhi_defintion.h"
|
|
||||||
|
|
||||||
enum class lock_state {
|
enum class lock_state {
|
||||||
NONE,
|
NONE,
|
||||||
@ -13,14 +14,11 @@ class render_target : public render_resource {
|
|||||||
public:
|
public:
|
||||||
[[nodiscard]] int get_height() const override { return height_; }
|
[[nodiscard]] int get_height() const override { return height_; }
|
||||||
[[nodiscard]] int get_width() const override { return width_; }
|
[[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) {
|
void init(const int width, const int height, const vk::Format in_format);
|
||||||
width_ = width;
|
|
||||||
height_ = height;
|
|
||||||
on_init(width, height, format);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void resize(const int width, const int height) {
|
void resize(const int width, const int height) {
|
||||||
if (width_ == width && height_ == height)
|
if (width_ == width && height_ == height)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -31,15 +29,19 @@ public:
|
|||||||
on_resize_callback(shared_from_this());
|
on_resize_callback(shared_from_this());
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void* lock(lock_state state) = 0;
|
void* lock(lock_state state) const;
|
||||||
|
void unlock();
|
||||||
virtual void unlock() = 0;
|
|
||||||
|
|
||||||
std::function<void(std::shared_ptr<render_resource>)> on_resize_callback;
|
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:
|
protected:
|
||||||
virtual void on_init(int width, int height, texture_format format) = 0;
|
void create(int width, int height);
|
||||||
virtual void on_resize(int width, int height) = 0;
|
void on_resize(int width, int height);
|
||||||
|
|
||||||
int width_ = 0;
|
int width_ = 0;
|
||||||
int height_ = 0;
|
int height_ = 0;
|
||||||
|
@ -1,13 +1,423 @@
|
|||||||
#include "renderer.h"
|
#include "renderer.h"
|
||||||
|
|
||||||
|
#include "imgui_impl_glfw.h"
|
||||||
|
#include "render_target.h"
|
||||||
|
|
||||||
#include "application/application.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() {
|
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() {
|
void renderer::new_frame(GLFWwindow* window_handle) {
|
||||||
if (!default_vs_)
|
// Resize swap chain?
|
||||||
default_vs_ = load_shader(application::get()->get_draw_ps_vertex_shader_entry());
|
if (swap_chain_rebuild_)
|
||||||
return default_vs_;
|
{
|
||||||
|
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
|
#pragma once
|
||||||
|
|
||||||
|
#include "imgui_impl_vulkan.h"
|
||||||
|
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
#include "GLFW/glfw3.h"
|
#include "GLFW/glfw3.h"
|
||||||
|
|
||||||
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
class pixel_shader_drawer;
|
class pixel_shader_drawer;
|
||||||
class shader;
|
|
||||||
class render_target;
|
class render_target;
|
||||||
class texture;
|
class texture;
|
||||||
constexpr ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
|
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
|
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 {
|
class renderer {
|
||||||
public:
|
public:
|
||||||
virtual ~renderer() = default;
|
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 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();
|
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);
|
||||||
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;
|
|
||||||
|
|
||||||
void set_vsync(const bool vsync) { vsync_ = vsync; }
|
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:
|
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;
|
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
|
#pragma once
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
#include <string>
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
|
#include "buffer_vk.h"
|
||||||
#include "render_resource.h"
|
#include "render_resource.h"
|
||||||
|
|
||||||
class texture : public render_resource {
|
class texture : public render_resource {
|
||||||
public:
|
public:
|
||||||
texture(): width_(0), height_(0) {
|
texture();
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool init_data(const unsigned char* data, int width, int height) = 0;
|
~texture() override;
|
||||||
|
|
||||||
[[nodiscard]] virtual bool is_valid() const = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] int get_width() const override { return width_; }
|
[[nodiscard]] int get_width() const override { return width_; }
|
||||||
[[nodiscard]] int get_height() const override { return height_; }
|
[[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:
|
protected:
|
||||||
int width_;
|
int width_;
|
||||||
int height_;
|
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