Files
korenkonder_ReDIVA/src/CRE/Vulkan/manager.cpp
T

761 lines
32 KiB
C++

/*
by korenkonder
GitHub/GitLab: korenkonder
*/
#pragma once
#include "manager.hpp"
#include "../../KKdLib/prj/algorithm.hpp"
#include "../../KKdLib/prj/shared_ptr.hpp"
#include "../../KKdLib/hash.hpp"
#include "../static_var.hpp"
#include "DescriptorPipeline.hpp"
#include "DynamicBuffer.hpp"
#include "Pipeline.hpp"
#include "RenderPass.hpp"
#include "Sampler.hpp"
#include "StagingBuffer.hpp"
#include <unordered_map>
#include <vector>
struct descriptor_pipeline_data {
uint32_t sampler_count;
uint32_t uniform_count;
uint32_t storage_count;
uint8_t pad[4];
uint64_t bindings_hash;
uint64_t push_constant_ranges_hash;
inline descriptor_pipeline_data() : sampler_count(), uniform_count(),
storage_count(), pad(), bindings_hash(), push_constant_ranges_hash() {
}
inline descriptor_pipeline_data(uint32_t sampler_count, uint32_t uniform_count,
uint32_t storage_count, uint64_t bindings_hash, uint64_t push_constant_ranges_hash) : pad() {
this->sampler_count = sampler_count;
this->uniform_count = uniform_count;
this->storage_count = storage_count;
this->bindings_hash = bindings_hash;
this->push_constant_ranges_hash = push_constant_ranges_hash;
}
};
template <>
class std::hash<descriptor_pipeline_data> {
public:
size_t operator()(const descriptor_pipeline_data& format) const {
return (size_t)hash_xxh3_64bits(&format, sizeof(format));
}
};
constexpr bool operator==(const descriptor_pipeline_data& left, const descriptor_pipeline_data& right) {
return left.sampler_count == right.sampler_count && left.uniform_count == right.uniform_count
&& left.storage_count == right.storage_count && left.bindings_hash == right.bindings_hash
&& left.push_constant_ranges_hash == right.push_constant_ranges_hash;
}
struct pipeline_data {
uint64_t stages_hash;
uint64_t vertex_input_info_binding_hash;
uint64_t vertex_input_info_attribute_hash;
uint64_t input_assembly_state_hash;
uint64_t rasterization_state_hash;
uint64_t depth_stencil_state_hash;
uint64_t color_blend_attachmen_hash;
bool line_width;
bool stencil;
uint8_t pad[6];
VkPipelineLayout layout;
VkRenderPass render_pass;
inline pipeline_data() : stages_hash(), vertex_input_info_binding_hash(),
vertex_input_info_attribute_hash(), input_assembly_state_hash(),
rasterization_state_hash(), depth_stencil_state_hash(), color_blend_attachmen_hash(),
line_width(), stencil(), pad(), layout(), render_pass() {
}
inline pipeline_data(uint64_t stages_hash,
uint64_t vertex_input_info_binding_hash, uint64_t vertex_input_info_attribute_hash,
uint64_t input_assembly_state_hash, uint64_t rasterization_state_hash,
uint64_t depth_stencil_state_hash, uint64_t color_blend_attachmen_hash,
bool line_width, bool stencil, VkPipelineLayout layout, VkRenderPass render_pass) : pad() {
this->stages_hash = stages_hash;
this->vertex_input_info_binding_hash = vertex_input_info_binding_hash;
this->vertex_input_info_attribute_hash = vertex_input_info_attribute_hash;
this->input_assembly_state_hash = input_assembly_state_hash;
this->rasterization_state_hash = rasterization_state_hash;
this->depth_stencil_state_hash = depth_stencil_state_hash;
this->color_blend_attachmen_hash = color_blend_attachmen_hash;
this->line_width = line_width;
this->stencil = stencil;
this->layout = layout;
this->render_pass = render_pass;
}
};
template <>
class std::hash<pipeline_data> {
public:
size_t operator()(const pipeline_data& format) const {
return (size_t)hash_xxh3_64bits(&format, sizeof(format));
}
};
constexpr bool operator==(const pipeline_data& left, const pipeline_data& right) {
return left.stages_hash == right.stages_hash
&& left.vertex_input_info_binding_hash == right.vertex_input_info_binding_hash
&& left.vertex_input_info_attribute_hash == right.vertex_input_info_attribute_hash
&& left.input_assembly_state_hash == right.input_assembly_state_hash
&& left.rasterization_state_hash == right.rasterization_state_hash
&& left.depth_stencil_state_hash == right.depth_stencil_state_hash
&& left.color_blend_attachmen_hash == right.color_blend_attachmen_hash
&& left.layout == right.layout && left.render_pass == right.render_pass;
}
struct render_pass_data {
uint64_t color_formats_hash;
GLenum depth_format;
bool depth_read_only;
uint8_t pad[3];
inline render_pass_data() : color_formats_hash(), depth_format(), depth_read_only(), pad() {
}
inline render_pass_data(uint64_t color_formats_hash, GLenum depth_format, bool depth_read_only) : pad() {
this->color_formats_hash = color_formats_hash;
this->depth_format = depth_format;
this->depth_read_only = depth_read_only;
}
};
template <>
class std::hash<render_pass_data> {
public:
size_t operator()(const render_pass_data& format) const {
return (size_t)hash_xxh3_64bits(&format, sizeof(format));
}
};
constexpr bool operator==(const render_pass_data& left, const render_pass_data& right) {
return left.color_formats_hash == right.color_formats_hash
&& left.depth_format == right.depth_format;
}
namespace Vulkan {
struct manager {
struct free_framebuffer_data {
VkDevice device;
VkFramebuffer framebuffer;
const VkAllocationCallbacks* allocator;
inline free_framebuffer_data() : device(), framebuffer(), allocator() {
}
inline free_framebuffer_data(VkDevice device,
VkFramebuffer framebuffer, const VkAllocationCallbacks* allocator) {
this->device = device;
this->framebuffer = framebuffer;
this->allocator = allocator;
}
};
struct free_image_view_data {
VkDevice device;
VkImageView image_view;
const VkAllocationCallbacks* allocator;
inline free_image_view_data() : device(), image_view(), allocator() {
}
inline free_image_view_data(VkDevice device,
VkImageView image_view, const VkAllocationCallbacks* allocator) {
this->device = device;
this->image_view = image_view;
this->allocator = allocator;
}
};
struct frame_data {
std::vector<free_framebuffer_data> free_framebuffers;
std::vector<free_image_view_data> free_image_views;
std::vector<Vulkan::DynamicBuffer> dynamic_buffers;
std::vector<Vulkan::StagingBuffer> staging_buffers;
frame_data();
~frame_data();
void ctrl();
};
std::vector<frame_data> frames_data;
uint32_t frame;
std::unordered_map<descriptor_pipeline_data,
prj::shared_ptr<Vulkan::DescriptorPipeline>> descriptor_pipelines;
std::unordered_map<pipeline_data, prj::shared_ptr<Vulkan::Pipeline>> pipelines;
std::unordered_map<render_pass_data, prj::shared_ptr<Vulkan::RenderPass>> render_passes;
std::unordered_map<uint64_t, prj::shared_ptr<Vulkan::Sampler>> samplers;
manager(uint32_t max_frames);
~manager();
void free_framebuffer(VkDevice device,
VkFramebuffer framebuffer, const VkAllocationCallbacks* allocator);
void free_image_view(VkDevice device,
VkImageView image_view, const VkAllocationCallbacks* allocator);
prj::shared_ptr<Vulkan::DescriptorPipeline> get_descriptor_pipeline(
uint32_t sampler_count, uint32_t uniform_count, uint32_t storage_count,
const VkDescriptorSetLayoutBinding* bindings,
uint32_t push_constant_range_count, VkPushConstantRange* push_constant_ranges);
frame_data& get_frame_data();
prj::shared_ptr<Vulkan::Pipeline> get_pipeline(uint32_t stage_count,
const VkPipelineShaderStageCreateInfo* stages,
uint32_t vertex_input_binding_description_count,
const VkVertexInputBindingDescription* vertex_input_binding_descriptions,
uint32_t vertex_input_attribute_description_count,
const VkVertexInputAttributeDescription* vertex_input_attribute_descriptions,
const VkPipelineInputAssemblyStateCreateInfo* input_assembly_state,
const VkPipelineRasterizationStateCreateInfo* rasterization_state,
const VkPipelineDepthStencilStateCreateInfo* depth_stencil_state,
uint32_t color_blend_attachment_count,
const VkPipelineColorBlendAttachmentState* color_blend_attachments,
bool line_width, bool stencil, VkPipelineLayout layout, VkRenderPass render_pass);
prj::shared_ptr<Vulkan::RenderPass> get_render_pass(GLenum* color_formats,
uint32_t color_format_count, GLenum depth_format, bool depth_read_only);
prj::shared_ptr<Vulkan::Sampler> get_sampler(const gl_sampler& sampler_data);
Vulkan::Buffer get_dynamic_buffer(VkDeviceSize size, VkDeviceSize alignment);
Vulkan::Buffer get_staging_buffer(VkDeviceSize size, VkDeviceSize alignment);
void next_frame(uint32_t frame);
void reset_descriptor_pipelines_descriptor_set_collections();
};
manager* manager_ptr;
void manager_init(uint32_t max_frames) {
manager_ptr = new manager(max_frames);
}
void manager_free_descriptor_pipelines() {
manager_ptr->descriptor_pipelines.clear();
}
void manager_free_framebuffer(VkDevice device,
VkFramebuffer framebuffer, const VkAllocationCallbacks* allocator) {
manager_ptr->free_framebuffer(device, framebuffer, allocator);
}
void manager_free_image_view(VkDevice device,
VkImageView image_view, const VkAllocationCallbacks* allocator) {
manager_ptr->free_image_view(device, image_view, allocator);
}
void manager_free_pipelines() {
manager_ptr->pipelines.clear();
}
void manager_free_render_passes() {
manager_ptr->render_passes.clear();
}
void manager_free_samplers() {
manager_ptr->samplers.clear();
}
prj::shared_ptr<Vulkan::DescriptorPipeline> manager_get_descriptor_pipeline(
uint32_t sampler_count, uint32_t uniform_count, uint32_t storage_count,
const VkDescriptorSetLayoutBinding* bindings,
uint32_t push_constant_range_count, VkPushConstantRange* push_constant_ranges) {
return manager_ptr->get_descriptor_pipeline(
sampler_count, uniform_count, storage_count, bindings,
push_constant_range_count, push_constant_ranges);
}
uint32_t manager_get_frame() {
return manager_ptr->frame;
}
prj::shared_ptr<Vulkan::Pipeline> manager_get_pipeline(uint32_t stage_count,
const VkPipelineShaderStageCreateInfo* stages,
uint32_t vertex_input_binding_description_count,
const VkVertexInputBindingDescription* vertex_input_binding_descriptions,
uint32_t vertex_input_attribute_description_count,
const VkVertexInputAttributeDescription* vertex_input_attribute_descriptions,
const VkPipelineInputAssemblyStateCreateInfo* input_assembly_state,
const VkPipelineRasterizationStateCreateInfo* rasterization_state,
const VkPipelineDepthStencilStateCreateInfo* depth_stencil_state,
uint32_t color_blend_attachment_count,
const VkPipelineColorBlendAttachmentState* color_blend_attachments,
bool line_width, bool stencil, VkPipelineLayout layout, VkRenderPass render_pass) {
return manager_ptr->get_pipeline(stage_count, stages,
vertex_input_binding_description_count, vertex_input_binding_descriptions,
vertex_input_attribute_description_count, vertex_input_attribute_descriptions,
input_assembly_state, rasterization_state, depth_stencil_state,
color_blend_attachment_count, color_blend_attachments,
line_width, stencil, layout, render_pass);
}
prj::shared_ptr<Vulkan::RenderPass> manager_get_render_pass(
GLenum* color_formats, uint32_t color_format_count,
GLenum depth_format, bool depth_read_only) {
return manager_ptr->get_render_pass(color_formats,
color_format_count, depth_format, depth_read_only);
}
prj::shared_ptr<Vulkan::Sampler> manager_get_sampler(const gl_sampler& sampler_data) {
return manager_ptr->get_sampler(sampler_data);
}
Vulkan::Buffer manager_get_dynamic_buffer(VkDeviceSize size, VkDeviceSize alignment) {
return manager_ptr->get_dynamic_buffer(size, alignment);
}
Vulkan::Buffer manager_get_staging_buffer(VkDeviceSize size, VkDeviceSize alignment) {
return manager_ptr->get_staging_buffer(size, alignment);
}
void manager_next_frame(uint32_t frame) {
manager_ptr->next_frame(frame);
}
void manager_reset_descriptor_pipelines_descriptor_set_collections() {
manager_ptr->reset_descriptor_pipelines_descriptor_set_collections();
}
void manager_free() {
delete manager_ptr;
}
manager::frame_data::frame_data() {
}
manager::frame_data::~frame_data() {
ctrl();
for (Vulkan::StagingBuffer& i : staging_buffers)
i.Destroy();
for (Vulkan::DynamicBuffer& i : dynamic_buffers)
i.Destroy();
}
void manager::frame_data::ctrl() {
for (free_framebuffer_data& i : free_framebuffers)
vkDestroyFramebuffer(i.device, i.framebuffer, i.allocator);
free_framebuffers.clear();
for (free_image_view_data& i : free_image_views)
vkDestroyImageView(i.device, i.image_view, i.allocator);
free_image_views.clear();
for (Vulkan::DynamicBuffer& i : dynamic_buffers) {
if (!i.curr_size)
i.empty_frame_count++;
}
auto i_dyn_begin = dynamic_buffers.begin();
auto i_dyn_end = dynamic_buffers.end();
for (auto i = i_dyn_end; i != i_dyn_begin; ) {
i--;
if (!i->curr_size) {
i->empty_frame_count++;
if (i->empty_frame_count >= 60) {
i->Destroy();
i = dynamic_buffers.erase(i);
i_dyn_begin = dynamic_buffers.begin();
continue;
}
}
else
i->empty_frame_count = 0;
i->curr_size = 0;
}
auto i_stg_begin = staging_buffers.begin();
auto i_stg_end = staging_buffers.end();
for (auto i = i_stg_end; i != i_stg_begin; ) {
i--;
if (!i->curr_size) {
i->empty_frame_count++;
if (i->empty_frame_count >= 60) {
i->Destroy();
i = staging_buffers.erase(i);
i_stg_begin = staging_buffers.begin();
continue;
}
}
else
i->empty_frame_count = 0;
i->curr_size = 0;
}
}
manager::manager(uint32_t max_frames) : frame() {
frames_data.resize(max_frames);
}
manager::~manager() {
}
void manager::free_framebuffer(VkDevice device,
VkFramebuffer framebuffer, const VkAllocationCallbacks* allocator) {
if (framebuffer) {
frame_data& frame_data = get_frame_data();
frame_data.free_framebuffers.push_back({ device, framebuffer, allocator });
}
}
void manager::free_image_view(VkDevice device,
VkImageView image_view, const VkAllocationCallbacks* allocator) {
if (image_view) {
frame_data& frame_data = get_frame_data();
frame_data.free_image_views.push_back({ device, image_view, allocator });
}
}
prj::shared_ptr<Vulkan::DescriptorPipeline> manager::get_descriptor_pipeline(
uint32_t sampler_count, uint32_t uniform_count, uint32_t storage_count,
const VkDescriptorSetLayoutBinding* bindings,
uint32_t push_constant_range_count, VkPushConstantRange* push_constant_ranges) {
uint64_t bindings_hash = hash_xxh3_64bits(bindings,
sizeof(VkDescriptorSetLayoutBinding) * ((size_t)sampler_count + uniform_count + storage_count ));
uint64_t push_constant_ranges_hash = hash_xxh3_64bits(push_constant_ranges,
sizeof(VkPushConstantRange) * push_constant_range_count);
auto elem = descriptor_pipelines.find({ sampler_count, uniform_count,
storage_count, bindings_hash, push_constant_ranges_hash });
if (elem != descriptor_pipelines.end())
return elem->second;
prj::shared_ptr<Vulkan::DescriptorPipeline> descriptor_pipeline(
new Vulkan::DescriptorPipeline(Vulkan::current_device, Vulkan::current_descriptor_pool,
sampler_count, uniform_count, storage_count,
bindings, push_constant_range_count, push_constant_ranges));
descriptor_pipelines.insert({ { sampler_count, uniform_count, storage_count,
bindings_hash, push_constant_ranges_hash }, descriptor_pipeline });
return descriptor_pipeline;
}
manager::frame_data& manager::get_frame_data() {
return frames_data.data()[frame];
}
prj::shared_ptr<Vulkan::Pipeline> manager::get_pipeline(uint32_t stage_count,
const VkPipelineShaderStageCreateInfo* stages,
uint32_t vertex_input_binding_description_count,
const VkVertexInputBindingDescription* vertex_input_binding_descriptions,
uint32_t vertex_input_attribute_description_count,
const VkVertexInputAttributeDescription* vertex_input_attribute_descriptions,
const VkPipelineInputAssemblyStateCreateInfo* input_assembly_state,
const VkPipelineRasterizationStateCreateInfo* rasterization_state,
const VkPipelineDepthStencilStateCreateInfo* depth_stencil_state,
uint32_t color_blend_attachment_count,
const VkPipelineColorBlendAttachmentState* color_blend_attachments,
bool line_width, bool stencil, VkPipelineLayout layout, VkRenderPass render_pass) {
uint64_t stages_hash = hash_xxh3_64bits(stages,
sizeof(VkPipelineShaderStageCreateInfo) * stage_count);
uint64_t vertex_input_info_binding_hash = hash_xxh3_64bits(vertex_input_binding_descriptions,
sizeof(VkVertexInputBindingDescription) * vertex_input_binding_description_count);
uint64_t vertex_input_info_attribute_hash = hash_xxh3_64bits(vertex_input_attribute_descriptions,
sizeof(VkVertexInputAttributeDescription) * vertex_input_attribute_description_count);
uint64_t input_assembly_state_hash = hash_xxh3_64bits(input_assembly_state,
sizeof(VkPipelineInputAssemblyStateCreateInfo));
uint64_t rasterization_state_hash = hash_xxh3_64bits(rasterization_state,
sizeof(VkPipelineRasterizationStateCreateInfo));
uint64_t depth_stencil_state_hash = hash_xxh3_64bits(depth_stencil_state,
sizeof(VkPipelineDepthStencilStateCreateInfo));
uint64_t color_blend_attachmen_hash = hash_xxh3_64bits(color_blend_attachments,
sizeof(VkPipelineColorBlendAttachmentState) * color_blend_attachment_count);
auto elem = pipelines.find({ stages_hash, vertex_input_info_binding_hash, vertex_input_info_attribute_hash,
input_assembly_state_hash, rasterization_state_hash,
depth_stencil_state_hash, color_blend_attachmen_hash,
line_width, stencil, layout, render_pass });
if (elem != pipelines.end())
return elem->second;
VkPipelineViewportStateCreateInfo viewport_state = {};
viewport_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewport_state.viewportCount = 1;
viewport_state.scissorCount = 1;
prj::shared_ptr<Vulkan::Pipeline> pipeline(new Vulkan::Pipeline(Vulkan::current_device, 0,
stage_count, stages, vertex_input_binding_description_count, vertex_input_binding_descriptions,
vertex_input_attribute_description_count, vertex_input_attribute_descriptions,
input_assembly_state, &viewport_state, rasterization_state, depth_stencil_state,
color_blend_attachment_count, color_blend_attachments, line_width, stencil, layout, render_pass));
pipelines.insert({ { stages_hash, vertex_input_info_binding_hash, vertex_input_info_attribute_hash,
input_assembly_state_hash, rasterization_state_hash,
depth_stencil_state_hash, color_blend_attachmen_hash,
line_width, stencil, layout, render_pass }, pipeline });
return pipeline;
}
prj::shared_ptr<Vulkan::RenderPass> manager::get_render_pass(GLenum* color_formats,
uint32_t color_format_count, GLenum depth_format, bool depth_read_only) {
uint64_t color_formats_hash = hash_xxh3_64bits(color_formats,
sizeof(GLenum) * color_format_count);
auto elem = render_passes.find({ color_formats_hash, depth_format, depth_read_only });
if (elem != render_passes.end())
return elem->second;
VkAttachmentReference* color_attachment_reference = force_malloc<VkAttachmentReference>(color_format_count);
VkAttachmentReference depth_attachment_reference = {};
VkSubpassDescription subpass_description = {};
subpass_description.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
if (color_format_count) {
for (uint32_t i = 0; i < color_format_count; i++) {
color_attachment_reference[i].attachment = i;
color_attachment_reference[i].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
}
subpass_description.colorAttachmentCount = color_format_count;
subpass_description.pColorAttachments = color_attachment_reference;
}
else
subpass_description.colorAttachmentCount = 0;
if (depth_format) {
depth_attachment_reference.attachment = 1;
depth_attachment_reference.layout = depth_read_only
? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
: VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
subpass_description.pDepthStencilAttachment = &depth_attachment_reference;
}
VkSubpassDependency subpass_dependency = {};
subpass_dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
subpass_dependency.dstSubpass = 0;
subpass_dependency.srcStageMask = 0;
subpass_dependency.srcAccessMask = 0;
subpass_dependency.dstStageMask = 0;
subpass_dependency.dstAccessMask = 0;
if (color_format_count) {
subpass_dependency.srcStageMask |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
subpass_dependency.dstStageMask |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
subpass_dependency.dstAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
}
if (depth_format) {
subpass_dependency.srcStageMask |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
subpass_dependency.dstStageMask |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
if (!depth_read_only)
subpass_dependency.dstAccessMask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
}
int32_t attachment_count = 0;
VkAttachmentDescription* attachments
= force_malloc<VkAttachmentDescription>((size_t)color_format_count + 1);
if (color_format_count)
for (uint32_t i = 0; i < color_format_count; i++) {
VkAttachmentDescription& color_attachment = attachments[attachment_count];
color_attachment.flags = 0;
color_attachment.format = Vulkan::get_format(color_formats[i]);
color_attachment.samples = VK_SAMPLE_COUNT_1_BIT;
color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
color_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
color_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
color_attachment.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
color_attachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachment_count++;
}
if (depth_format) {
const bool stencil = depth_format == GL_DEPTH24_STENCIL8;
VkAttachmentDescription& depth_attachment = attachments[attachment_count];
depth_attachment.flags = 0;
depth_attachment.format = Vulkan::get_format(depth_format);
depth_attachment.samples = VK_SAMPLE_COUNT_1_BIT;
depth_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
depth_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
depth_attachment.stencilLoadOp = stencil
? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE;
depth_attachment.stencilStoreOp = stencil
? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE;
depth_attachment.initialLayout = depth_read_only
? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
: VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
depth_attachment.finalLayout = depth_read_only
? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
: VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
attachment_count++;
}
prj::shared_ptr<Vulkan::RenderPass> render_pass(new Vulkan::RenderPass(Vulkan::current_device, 0,
attachment_count, attachments, 1, &subpass_description, 1, &subpass_dependency));
render_passes.insert({ { color_formats_hash, depth_format, depth_read_only }, render_pass });
free_def(attachments);
free_def(color_attachment_reference);
return render_pass;
}
static VkSamplerAddressMode get_sampler_address_mode(GLenum wrap) {
switch (wrap) {
case GL_REPEAT:
default:
return VK_SAMPLER_ADDRESS_MODE_REPEAT;
case GL_CLAMP_TO_BORDER:
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
case GL_CLAMP_TO_EDGE:
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
case GL_MIRRORED_REPEAT:
return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
case GL_MIRROR_CLAMP_TO_EDGE:
return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE;
}
}
prj::shared_ptr<Vulkan::Sampler> manager::get_sampler(const gl_sampler& sampler_data) {
uint64_t sampler_hash = hash_xxh3_64bits(&sampler_data, sizeof(gl_sampler));
auto elem = samplers.find(sampler_hash);
if (elem != samplers.end())
return elem->second;
VkFilter vk_mag_filter = sampler_data.mag_filter != GL_NEAREST ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
bool no_mipmap = false;
VkFilter vk_min_filter;
VkSamplerMipmapMode vk_mipmap_mode;
switch (sampler_data.min_filter) {
case GL_NEAREST:
no_mipmap = true;
vk_min_filter = VK_FILTER_NEAREST;
vk_mipmap_mode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
break;
case GL_NEAREST_MIPMAP_NEAREST:
vk_min_filter = VK_FILTER_NEAREST;
vk_mipmap_mode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
break;
case GL_LINEAR:
default:
no_mipmap = true;
vk_min_filter = VK_FILTER_LINEAR;
vk_mipmap_mode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
break;
case GL_LINEAR_MIPMAP_NEAREST:
vk_min_filter = VK_FILTER_LINEAR;
vk_mipmap_mode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
break;
case GL_NEAREST_MIPMAP_LINEAR:
vk_min_filter = VK_FILTER_NEAREST;
vk_mipmap_mode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
break;
case GL_LINEAR_MIPMAP_LINEAR:
vk_min_filter = VK_FILTER_LINEAR;
vk_mipmap_mode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
break;
}
float_t min_lod = max_def(sampler_data.min_lod, 0.0f);
float_t max_lod = max_def(sampler_data.max_lod, min_lod);
VkBorderColor vk_border_color;
if (sampler_data.border_color == 0.0f)
vk_border_color = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
else if (sampler_data.border_color == vec4(0.0f, 0.0f, 0.0f, 1.0f))
vk_border_color = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;
else if (sampler_data.border_color == 1.0f)
vk_border_color = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
else
vk_border_color = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
prj::shared_ptr<Vulkan::Sampler> sampler(new Vulkan::Sampler(Vulkan::current_device, 0,
vk_mag_filter, vk_min_filter, vk_mipmap_mode, sampler_data.lod_bias,
get_sampler_address_mode(sampler_data.wrap_s),
get_sampler_address_mode(sampler_data.wrap_t),
get_sampler_address_mode(sampler_data.wrap_r),
no_mipmap, min_lod, max_lod,
sampler_data.max_anisotropy, vk_border_color));
samplers.insert({ sampler_hash, sampler });
return sampler;
}
Vulkan::Buffer manager::get_dynamic_buffer(VkDeviceSize size, VkDeviceSize alignment) {
frame_data& frame_data = get_frame_data();
for (Vulkan::DynamicBuffer& i : frame_data.dynamic_buffers)
if (align_val(i.curr_size, alignment) + align_val(size, alignment) <= i.GetSize()) {
i.curr_size = align_val(i.curr_size, alignment);
Vulkan::Buffer buffer = (Vulkan::Buffer)i;
buffer.SetOffset(i.curr_size);
buffer.SetSize(size);
i.curr_size += align_val(size, alignment);
return buffer;
}
VkDeviceSize buffer_size = 0x1000000;
while (buffer_size <= size)
buffer_size *= 2;
frame_data.dynamic_buffers.push_back({});
Vulkan::DynamicBuffer& dynamic_buffer = frame_data.dynamic_buffers.back();
dynamic_buffer.Create(Vulkan::current_allocator, buffer_size);
Vulkan::Buffer buffer = (Vulkan::Buffer)dynamic_buffer;
buffer.SetOffset(0);
buffer.SetSize(size);
dynamic_buffer.curr_size = align_val(size, alignment);
return buffer;
}
Vulkan::Buffer manager::get_staging_buffer(VkDeviceSize size, VkDeviceSize alignment) {
frame_data& frame_data = get_frame_data();
for (Vulkan::StagingBuffer& i : frame_data.staging_buffers)
if (align_val(i.curr_size, alignment) + align_val(size, alignment) <= i.GetSize()) {
i.curr_size = align_val(i.curr_size, alignment);
Vulkan::Buffer buffer = (Vulkan::Buffer)i;
buffer.SetOffset(i.curr_size);
buffer.SetSize(size);
i.curr_size += align_val(size, alignment);
return buffer;
}
VkDeviceSize buffer_size = 0x1000000;
while (buffer_size <= size)
buffer_size *= 2;
frame_data.staging_buffers.push_back({});
Vulkan::StagingBuffer& staging_buffer = frame_data.staging_buffers.back();
staging_buffer.Create(Vulkan::current_allocator, buffer_size);
Vulkan::Buffer buffer = (Vulkan::Buffer)staging_buffer;
buffer.SetOffset(0);
buffer.SetSize(size);
staging_buffer.curr_size = align_val(size, alignment);
return buffer;
}
void manager::next_frame(uint32_t frame) {
this->frame = frame;
get_frame_data().ctrl();
}
void manager::reset_descriptor_pipelines_descriptor_set_collections() {
for (auto& i : descriptor_pipelines)
i.second.get()->ResetSetCollectionsState();
}
}