yes
This commit is contained in:
246
Runtime/Sources/Renderer/Buffer.cpp
git.filemode.normal_file
246
Runtime/Sources/Renderer/Buffer.cpp
git.filemode.normal_file
@@ -0,0 +1,246 @@
|
||||
#include <Renderer/RenderCore.h>
|
||||
#include <Core/Logs.h>
|
||||
#include <Renderer/Buffer.h>
|
||||
|
||||
namespace Scop
|
||||
{
|
||||
void GPUBuffer::Init(BufferType type, VkDeviceSize size, VkBufferUsageFlags usage, CPUBuffer data, std::string_view name, bool dedicated_alloc)
|
||||
{
|
||||
if(type == BufferType::Constant)
|
||||
{
|
||||
if(data.Empty())
|
||||
{
|
||||
Warning("Vulkan: trying to create constant buffer without data (constant buffers cannot be modified after creation)");
|
||||
return;
|
||||
}
|
||||
m_usage = usage | VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
||||
m_flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||
}
|
||||
else if(type == BufferType::HighDynamic)
|
||||
{
|
||||
m_usage = usage;
|
||||
m_flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||
}
|
||||
else // LowDynamic or Staging
|
||||
{
|
||||
m_usage = usage | VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
||||
m_flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||
}
|
||||
|
||||
if(type == BufferType::Staging && data.Empty())
|
||||
Warning("Vulkan: trying to create staging buffer without data (wtf?)");
|
||||
|
||||
CreateBuffer(size, m_usage, m_flags, std::move(name), dedicated_alloc);
|
||||
|
||||
if(!data.Empty())
|
||||
{
|
||||
if(m_memory.map != nullptr)
|
||||
std::memcpy(m_memory.map, data.GetData(), data.GetSize());
|
||||
}
|
||||
if(type == BufferType::Constant || type == BufferType::LowDynamic)
|
||||
PushToGPU();
|
||||
}
|
||||
|
||||
void GPUBuffer::CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, std::string_view name, bool dedicated_alloc)
|
||||
{
|
||||
auto device = RenderCore::Get().GetDevice();
|
||||
m_buffer = kvfCreateBuffer(device, usage, size);
|
||||
|
||||
VkMemoryRequirements mem_requirements;
|
||||
RenderCore::Get().vkGetBufferMemoryRequirements(device, m_buffer, &mem_requirements);
|
||||
|
||||
//m_memory = RenderCore::Get().GetAllocator().Allocate(size, mem_requirements.alignment, *FindMemoryType(mem_requirements.memoryTypeBits, properties), dedicated_alloc);
|
||||
m_memory = RenderCore::Get().GetAllocator().Allocate(mem_requirements.size, mem_requirements.alignment, *FindMemoryType(mem_requirements.memoryTypeBits, properties), dedicated_alloc);
|
||||
RenderCore::Get().vkBindBufferMemory(device, m_buffer, m_memory.memory, m_memory.offset);
|
||||
|
||||
#ifdef SCOP_HAS_DEBUG_UTILS_FUNCTIONS
|
||||
std::string alloc_name{ name };
|
||||
if(usage & VK_BUFFER_USAGE_INDEX_BUFFER_BIT)
|
||||
alloc_name.append("_index_buffer");
|
||||
else if(usage & VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)
|
||||
alloc_name.append("_vertex_buffer");
|
||||
else if(usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT)
|
||||
alloc_name.append("_uniform_buffer");
|
||||
else
|
||||
alloc_name.append("_buffer");
|
||||
if(m_flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
|
||||
alloc_name.append("_gpu");
|
||||
m_name = name;
|
||||
|
||||
VkDebugUtilsObjectNameInfoEXT name_info{};
|
||||
name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
|
||||
name_info.objectType = VK_OBJECT_TYPE_BUFFER;
|
||||
name_info.objectHandle = reinterpret_cast<std::uint64_t>(m_buffer);
|
||||
name_info.pObjectName = m_name.c_str();
|
||||
RenderCore::Get().vkSetDebugUtilsObjectNameEXT(RenderCore::Get().GetDevice(), &name_info);
|
||||
#endif
|
||||
|
||||
m_size = size;
|
||||
|
||||
m_is_dedicated_alloc = dedicated_alloc;
|
||||
|
||||
s_buffer_count++;
|
||||
}
|
||||
|
||||
bool GPUBuffer::CopyFrom(const GPUBuffer& buffer, std::size_t src_offset, std::size_t dst_offset) noexcept
|
||||
{
|
||||
if(!(m_usage & VK_BUFFER_USAGE_TRANSFER_DST_BIT))
|
||||
{
|
||||
Error("Vulkan: buffer cannot be the destination of a copy because it does not have the correct usage flag");
|
||||
return false;
|
||||
}
|
||||
if(!(buffer.m_usage & VK_BUFFER_USAGE_TRANSFER_SRC_BIT))
|
||||
{
|
||||
Error("Vulkan: buffer cannot be the source of a copy because it does not have the correct usage flag");
|
||||
return false;
|
||||
}
|
||||
|
||||
VkCommandBuffer cmd = kvfCreateCommandBuffer(RenderCore::Get().GetDevice());
|
||||
kvfBeginCommandBuffer(cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
|
||||
kvfCopyBufferToBuffer(cmd, m_buffer, buffer.Get(), buffer.GetSize(), src_offset, dst_offset);
|
||||
kvfEndCommandBuffer(cmd);
|
||||
if(!RenderCore::Get().StackSubmits())
|
||||
{
|
||||
VkFence fence = kvfCreateFence(RenderCore::Get().GetDevice());
|
||||
kvfSubmitSingleTimeCommandBuffer(RenderCore::Get().GetDevice(), cmd, KVF_GRAPHICS_QUEUE, fence);
|
||||
kvfWaitForFence(RenderCore::Get().GetDevice(), fence);
|
||||
kvfDestroyFence(RenderCore::Get().GetDevice(), fence);
|
||||
kvfDestroyCommandBuffer(RenderCore::Get().GetDevice(), cmd);
|
||||
}
|
||||
else
|
||||
kvfSubmitSingleTimeCommandBuffer(RenderCore::Get().GetDevice(), cmd, KVF_GRAPHICS_QUEUE, VK_NULL_HANDLE);
|
||||
return true;
|
||||
}
|
||||
|
||||
void GPUBuffer::PushToGPU() noexcept
|
||||
{
|
||||
GPUBuffer new_buffer;
|
||||
new_buffer.m_usage = (this->m_usage & 0xFFFFFFFC) | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
||||
new_buffer.m_flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
new_buffer.CreateBuffer(m_memory.size, new_buffer.m_usage, new_buffer.m_flags, m_name, m_is_dedicated_alloc);
|
||||
|
||||
if(new_buffer.CopyFrom(*this))
|
||||
Swap(new_buffer);
|
||||
new_buffer.Destroy();
|
||||
}
|
||||
|
||||
void GPUBuffer::Destroy() noexcept
|
||||
{
|
||||
if(m_buffer == VK_NULL_HANDLE)
|
||||
return;
|
||||
RenderCore::Get().WaitDeviceIdle();
|
||||
RenderCore::Get().vkDestroyBuffer(RenderCore::Get().GetDevice(), m_buffer, nullptr);
|
||||
RenderCore::Get().GetAllocator().Deallocate(m_memory);
|
||||
m_buffer = VK_NULL_HANDLE;
|
||||
m_memory = NULL_MEMORY_BLOCK;
|
||||
s_buffer_count--;
|
||||
}
|
||||
|
||||
void GPUBuffer::Swap(GPUBuffer& buffer) noexcept
|
||||
{
|
||||
std::swap(m_buffer, buffer.m_buffer);
|
||||
m_memory.Swap(buffer.m_memory);
|
||||
std::swap(m_usage, buffer.m_usage);
|
||||
std::swap(m_flags, buffer.m_flags);
|
||||
}
|
||||
|
||||
void VertexBuffer::SetData(CPUBuffer data)
|
||||
{
|
||||
if(data.GetSize() > m_memory.size)
|
||||
{
|
||||
Error("Vulkan: trying to store too much data in a vertex buffer (% bytes in % bytes)", data.GetSize(), m_memory.size);
|
||||
return;
|
||||
}
|
||||
if(data.Empty())
|
||||
{
|
||||
Warning("Vulkan: cannot set empty data in a vertex buffer");
|
||||
return;
|
||||
}
|
||||
GPUBuffer staging;
|
||||
staging.Init(BufferType::Staging, data.GetSize(), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, data);
|
||||
CopyFrom(staging);
|
||||
staging.Destroy();
|
||||
}
|
||||
|
||||
void IndexBuffer::SetData(CPUBuffer data)
|
||||
{
|
||||
if(data.GetSize() > m_memory.size)
|
||||
{
|
||||
Error("Vulkan: trying to store too much data in an index buffer (% bytes in % bytes)", data.GetSize(), m_memory.size);
|
||||
return;
|
||||
}
|
||||
if(data.Empty())
|
||||
{
|
||||
Warning("Vulkan: cannot set empty data in an index buffer");
|
||||
return;
|
||||
}
|
||||
GPUBuffer staging;
|
||||
staging.Init(BufferType::Staging, data.GetSize(), VK_BUFFER_USAGE_INDEX_BUFFER_BIT, data);
|
||||
CopyFrom(staging);
|
||||
staging.Destroy();
|
||||
}
|
||||
|
||||
void MeshBuffer::SetVertexData(CPUBuffer data)
|
||||
{
|
||||
if(data.GetSize() > m_index_offset)
|
||||
{
|
||||
Error("Vulkan: trying to store too much data in a vertex buffer (% bytes in % bytes)", data.GetSize(), m_index_offset);
|
||||
return;
|
||||
}
|
||||
if(data.Empty())
|
||||
{
|
||||
Warning("Vulkan: cannot set empty data in a vertex buffer");
|
||||
return;
|
||||
}
|
||||
GPUBuffer staging;
|
||||
staging.Init(BufferType::Staging, data.GetSize(), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, data);
|
||||
CopyFrom(staging, 0, 0);
|
||||
staging.Destroy();
|
||||
}
|
||||
|
||||
void MeshBuffer::SetIndexData(CPUBuffer data)
|
||||
{
|
||||
if(data.GetSize() > m_memory.size - m_index_offset)
|
||||
{
|
||||
Error("Vulkan: trying to store too much data in an index buffer (% bytes in % bytes)", data.GetSize(), m_memory.size - m_index_offset);
|
||||
return;
|
||||
}
|
||||
if(data.Empty())
|
||||
{
|
||||
Warning("Vulkan: cannot set empty data in an index buffer");
|
||||
return;
|
||||
}
|
||||
GPUBuffer staging;
|
||||
staging.Init(BufferType::Staging, data.GetSize(), VK_BUFFER_USAGE_INDEX_BUFFER_BIT, data);
|
||||
CopyFrom(staging, 0, m_index_offset);
|
||||
staging.Destroy();
|
||||
}
|
||||
|
||||
void UniformBuffer::Init(std::uint32_t size, std::string_view name)
|
||||
{
|
||||
for(int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
|
||||
{
|
||||
m_buffers[i].Init(BufferType::HighDynamic, size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, {}, name);
|
||||
m_maps[i] = m_buffers[i].GetMap();
|
||||
if(m_maps[i] == nullptr)
|
||||
FatalError("Vulkan: unable to map a uniform buffer");
|
||||
}
|
||||
}
|
||||
|
||||
void UniformBuffer::SetData(CPUBuffer data, std::size_t frame_index)
|
||||
{
|
||||
if(data.GetSize() > m_buffers[frame_index].GetSize())
|
||||
{
|
||||
Error("Vulkan: invalid data size to update to a uniform buffer, % != %", data.GetSize(), m_buffers[frame_index].GetSize());
|
||||
return;
|
||||
}
|
||||
if(m_maps[frame_index] != nullptr)
|
||||
std::memcpy(m_maps[frame_index], data.GetData(), data.GetSize());
|
||||
}
|
||||
|
||||
void UniformBuffer::Destroy() noexcept
|
||||
{
|
||||
for(int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
|
||||
m_buffers[i].Destroy();
|
||||
}
|
||||
}
|
||||
293
Runtime/Sources/Renderer/Descriptor.cpp
git.filemode.normal_file
293
Runtime/Sources/Renderer/Descriptor.cpp
git.filemode.normal_file
@@ -0,0 +1,293 @@
|
||||
#include <kvf.h>
|
||||
#include <algorithm>
|
||||
|
||||
#include <Core/Logs.h>
|
||||
#include <Renderer/Image.h>
|
||||
#include <Renderer/Enums.h>
|
||||
#include <Renderer/Buffer.h>
|
||||
#include <Renderer/RenderCore.h>
|
||||
#include <Renderer/Descriptor.h>
|
||||
#include <Renderer/RenderCore.h>
|
||||
|
||||
namespace Scop
|
||||
{
|
||||
constexpr std::size_t MAX_SETS_PER_POOL = MAX_FRAMES_IN_FLIGHT * 1024;
|
||||
|
||||
void TransitionImageToCorrectLayout(Image& image, VkCommandBuffer cmd)
|
||||
{
|
||||
if(!image.IsInit())
|
||||
return;
|
||||
if(image.GetType() == ImageType::Color || image.GetType() == ImageType::Cube)
|
||||
image.TransitionLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, cmd);
|
||||
else if(image.GetType() == ImageType::Depth)
|
||||
image.TransitionLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, cmd);
|
||||
else
|
||||
Error("Vulkan: cannot transition descriptor image layout, unkown image type");
|
||||
}
|
||||
|
||||
void DescriptorPool::Init() noexcept
|
||||
{
|
||||
VkDescriptorPoolSize pool_sizes[] = {
|
||||
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, MAX_SETS_PER_POOL },
|
||||
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, MAX_SETS_PER_POOL },
|
||||
{ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, MAX_SETS_PER_POOL }
|
||||
};
|
||||
|
||||
VkDescriptorPoolCreateInfo pool_info{};
|
||||
pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||
pool_info.poolSizeCount = sizeof(pool_sizes) / sizeof(pool_sizes[0]);
|
||||
pool_info.pPoolSizes = pool_sizes;
|
||||
pool_info.maxSets = MAX_SETS_PER_POOL;
|
||||
pool_info.flags = 0;
|
||||
kvfCheckVk(RenderCore::Get().vkCreateDescriptorPool(RenderCore::Get().GetDevice(), &pool_info, nullptr, &m_pool));
|
||||
m_allocation_count = 0;
|
||||
}
|
||||
|
||||
void DescriptorPool::Destroy() noexcept
|
||||
{
|
||||
if(m_pool == VK_NULL_HANDLE)
|
||||
return;
|
||||
for(auto& set : m_free_sets)
|
||||
kvfDestroyDescriptorSetLayout(RenderCore::Get().GetDevice(), set->m_set_layout);
|
||||
for(auto& set : m_used_sets)
|
||||
kvfDestroyDescriptorSetLayout(RenderCore::Get().GetDevice(), set->m_set_layout);
|
||||
RenderCore::Get().vkDestroyDescriptorPool(RenderCore::Get().GetDevice(), m_pool, nullptr);
|
||||
m_pool = VK_NULL_HANDLE;
|
||||
m_allocation_count = 0;
|
||||
m_free_sets.clear();
|
||||
m_used_sets.clear();
|
||||
}
|
||||
|
||||
std::shared_ptr<DescriptorSet> DescriptorPool::RequestDescriptorSet(const ShaderSetLayout& layout, ShaderType shader_type)
|
||||
{
|
||||
auto it = std::find_if(m_free_sets.begin(), m_free_sets.end(), [&](std::shared_ptr<DescriptorSet> set)
|
||||
{
|
||||
return shader_type == set->GetShaderType() && layout == set->GetShaderLayout();
|
||||
});
|
||||
if(it != m_free_sets.end())
|
||||
{
|
||||
std::shared_ptr<DescriptorSet> set = *it;
|
||||
m_free_sets.erase(it);
|
||||
m_used_sets.push_back(set);
|
||||
return set;
|
||||
}
|
||||
|
||||
std::array<VkDescriptorSet, MAX_FRAMES_IN_FLIGHT> vulkan_sets;
|
||||
|
||||
VkShaderStageFlagBits vulkan_shader_stage;
|
||||
switch(shader_type)
|
||||
{
|
||||
case ShaderType::Vertex: vulkan_shader_stage = VK_SHADER_STAGE_VERTEX_BIT; break;
|
||||
case ShaderType::Fragment: vulkan_shader_stage = VK_SHADER_STAGE_FRAGMENT_BIT; break;
|
||||
|
||||
default: FatalError("wtf"); vulkan_shader_stage = VK_SHADER_STAGE_VERTEX_BIT; /* Just to shut up warnings */ break;
|
||||
}
|
||||
|
||||
std::vector<VkDescriptorSetLayoutBinding> bindings(layout.binds.size());
|
||||
{
|
||||
std::size_t i = 0;
|
||||
for(auto& [bind, type] : layout.binds)
|
||||
{
|
||||
bindings[i].binding = bind;
|
||||
bindings[i].descriptorCount = 1;
|
||||
bindings[i].descriptorType = type;
|
||||
bindings[i].pImmutableSamplers = nullptr;
|
||||
bindings[i].stageFlags = vulkan_shader_stage;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
VkDescriptorSetLayout vulkan_layout = kvfCreateDescriptorSetLayout(RenderCore::Get().GetDevice(), bindings.data(), bindings.size());
|
||||
|
||||
for(int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
|
||||
{
|
||||
VkDescriptorSetAllocateInfo alloc_info = {};
|
||||
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||
alloc_info.descriptorPool = m_pool;
|
||||
alloc_info.descriptorSetCount = 1;
|
||||
alloc_info.pSetLayouts = &vulkan_layout;
|
||||
VkDescriptorSet vulkan_set;
|
||||
kvfCheckVk(RenderCore::Get().vkAllocateDescriptorSets(RenderCore::Get().GetDevice(), &alloc_info, &vulkan_set));
|
||||
m_allocation_count++;
|
||||
vulkan_sets[i] = vulkan_set;
|
||||
}
|
||||
|
||||
std::shared_ptr<DescriptorSet> set(new DescriptorSet(*this, vulkan_layout, layout, std::move(vulkan_sets), shader_type));
|
||||
m_used_sets.push_back(set);
|
||||
return set;
|
||||
}
|
||||
|
||||
void DescriptorPool::ReturnDescriptorSet(std::shared_ptr<DescriptorSet> set)
|
||||
{
|
||||
//std::size_t i = 0;
|
||||
auto it = std::find_if(m_used_sets.begin(), m_used_sets.end(), [&](const std::shared_ptr<DescriptorSet>& rhs_set)
|
||||
{
|
||||
//i++;
|
||||
//std::cout << m_used_sets.size() << " " << i << std::endl;
|
||||
return set == rhs_set;
|
||||
});
|
||||
if(it == m_used_sets.end())
|
||||
return;
|
||||
m_used_sets.erase(it);
|
||||
m_free_sets.push_back(set);
|
||||
}
|
||||
|
||||
DescriptorPool& DescriptorPoolManager::GetAvailablePool()
|
||||
{
|
||||
for(auto& pool : m_pools)
|
||||
{
|
||||
if(pool.GetNumberOfSetsAllocated() < MAX_SETS_PER_POOL)
|
||||
return pool;
|
||||
}
|
||||
m_pools.emplace_back().Init();
|
||||
return m_pools.back();
|
||||
}
|
||||
|
||||
void DescriptorPoolManager::Destroy()
|
||||
{
|
||||
for(auto& pool : m_pools)
|
||||
pool.Destroy();
|
||||
m_pools.clear();
|
||||
}
|
||||
|
||||
DescriptorSet::DescriptorSet(DescriptorPool& pool, VkDescriptorSetLayout vulkan_layout, const ShaderSetLayout& layout, std::array<VkDescriptorSet, MAX_FRAMES_IN_FLIGHT> vulkan_sets, ShaderType shader_type) :
|
||||
m_shader_layout(layout),
|
||||
m_sets(std::move(vulkan_sets)),
|
||||
m_set_layout(vulkan_layout),
|
||||
m_shader_type(shader_type),
|
||||
m_pool(pool)
|
||||
{
|
||||
for(auto& [binding, type] : layout.binds)
|
||||
{
|
||||
m_descriptors.emplace_back();
|
||||
m_descriptors.back().type = type;
|
||||
m_descriptors.back().binding = binding;
|
||||
}
|
||||
}
|
||||
|
||||
void DescriptorSet::SetImage(std::size_t i, std::uint32_t binding, class Image& image)
|
||||
{
|
||||
Verify(m_sets[i] != VK_NULL_HANDLE, "invalid descriptor");
|
||||
auto it = std::find_if(m_descriptors.begin(), m_descriptors.end(), [=](Descriptor descriptor)
|
||||
{
|
||||
return binding == descriptor.binding;
|
||||
});
|
||||
if(it == m_descriptors.end())
|
||||
{
|
||||
Warning("Vulkan: cannot update descriptor set image; invalid binding");
|
||||
return;
|
||||
}
|
||||
if(it->type != VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
|
||||
{
|
||||
Error("Vulkan: trying to bind an image to the wrong descriptor");
|
||||
return;
|
||||
}
|
||||
it->image_ptr = ℑ
|
||||
}
|
||||
|
||||
void DescriptorSet::SetStorageBuffer(std::size_t i, std::uint32_t binding, class GPUBuffer& buffer)
|
||||
{
|
||||
Verify(m_sets[i] != VK_NULL_HANDLE, "invalid descriptor");
|
||||
auto it = std::find_if(m_descriptors.begin(), m_descriptors.end(), [=](Descriptor descriptor)
|
||||
{
|
||||
return binding == descriptor.binding;
|
||||
});
|
||||
if(it == m_descriptors.end())
|
||||
{
|
||||
Warning("Vulkan: cannot update descriptor set buffer; invalid binding");
|
||||
return;
|
||||
}
|
||||
if(it->type != VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
|
||||
{
|
||||
Error("Vulkan: trying to bind a buffer to the wrong descriptor");
|
||||
return;
|
||||
}
|
||||
it->storage_buffer_ptr = &buffer;
|
||||
}
|
||||
|
||||
void DescriptorSet::SetUniformBuffer(std::size_t i, std::uint32_t binding, class GPUBuffer& buffer)
|
||||
{
|
||||
Verify(m_sets[i] != VK_NULL_HANDLE, "invalid descriptor");
|
||||
auto it = std::find_if(m_descriptors.begin(), m_descriptors.end(), [=](Descriptor descriptor)
|
||||
{
|
||||
return binding == descriptor.binding;
|
||||
});
|
||||
if(it == m_descriptors.end())
|
||||
{
|
||||
Warning("Vulkan: cannot update descriptor set buffer; invalid binding");
|
||||
return;
|
||||
}
|
||||
if(it->type != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER)
|
||||
{
|
||||
Error("Vulkan: trying to bind a buffer to the wrong descriptor");
|
||||
return;
|
||||
}
|
||||
it->uniform_buffer_ptr = &buffer;
|
||||
}
|
||||
|
||||
void DescriptorSet::Update(std::size_t i, VkCommandBuffer cmd) noexcept
|
||||
{
|
||||
Verify(m_sets[i] != VK_NULL_HANDLE, "invalid descriptor");
|
||||
|
||||
std::size_t image_count = 0;
|
||||
std::size_t buffer_count = 0;
|
||||
|
||||
for(auto& descriptor : m_descriptors)
|
||||
{
|
||||
if(descriptor.image_ptr)
|
||||
image_count++;
|
||||
else if(descriptor.uniform_buffer_ptr || descriptor.storage_buffer_ptr)
|
||||
buffer_count++;
|
||||
else
|
||||
FatalError("unknown descriptor data");
|
||||
}
|
||||
|
||||
std::vector<VkWriteDescriptorSet> writes(m_descriptors.size());
|
||||
std::vector<VkDescriptorBufferInfo> buffer_infos(buffer_count);
|
||||
std::vector<VkDescriptorImageInfo> image_infos(image_count);
|
||||
std::size_t buffer_index = 0;
|
||||
std::size_t image_index = 0;
|
||||
std::size_t write_index = 0;
|
||||
|
||||
for(auto& descriptor : m_descriptors)
|
||||
{
|
||||
if(descriptor.image_ptr)
|
||||
{
|
||||
TransitionImageToCorrectLayout(*descriptor.image_ptr, cmd);
|
||||
VkDescriptorImageInfo info{};
|
||||
info.sampler = descriptor.image_ptr->GetSampler();
|
||||
info.imageLayout = descriptor.image_ptr->GetLayout();
|
||||
info.imageView = descriptor.image_ptr->GetImageView();
|
||||
image_infos[image_index] = std::move(info);
|
||||
writes[write_index] = kvfWriteImageToDescriptorSet(RenderCore::Get().GetDevice(), m_sets[i], &image_infos[image_index], descriptor.binding);
|
||||
image_index++;
|
||||
}
|
||||
else if(descriptor.uniform_buffer_ptr)
|
||||
{
|
||||
VkDescriptorBufferInfo info{};
|
||||
info.buffer = descriptor.uniform_buffer_ptr->Get();
|
||||
info.offset = descriptor.uniform_buffer_ptr->GetOffset();
|
||||
info.range = VK_WHOLE_SIZE;
|
||||
buffer_infos[buffer_index] = std::move(info);
|
||||
writes[write_index] = kvfWriteUniformBufferToDescriptorSet(RenderCore::Get().GetDevice(), m_sets[i], &buffer_infos[buffer_index], descriptor.binding);
|
||||
buffer_index++;
|
||||
}
|
||||
else if(descriptor.storage_buffer_ptr)
|
||||
{
|
||||
VkDescriptorBufferInfo info{};
|
||||
info.buffer = descriptor.storage_buffer_ptr->Get();
|
||||
info.offset = descriptor.storage_buffer_ptr->GetOffset();
|
||||
info.range = VK_WHOLE_SIZE;
|
||||
buffer_infos[buffer_index] = std::move(info);
|
||||
writes[write_index] = kvfWriteStorageBufferToDescriptorSet(RenderCore::Get().GetDevice(), m_sets[i], &buffer_infos[buffer_index], descriptor.binding);
|
||||
buffer_index++;
|
||||
}
|
||||
write_index++;
|
||||
}
|
||||
RenderCore::Get().vkUpdateDescriptorSets(RenderCore::Get().GetDevice(), writes.size(), writes.data(), 0, nullptr);
|
||||
}
|
||||
|
||||
void DescriptorSet::ReturnDescriptorSetToPool()
|
||||
{
|
||||
m_pool.ReturnDescriptorSet(shared_from_this());
|
||||
}
|
||||
}
|
||||
265
Runtime/Sources/Renderer/Image.cpp
git.filemode.normal_file
265
Runtime/Sources/Renderer/Image.cpp
git.filemode.normal_file
@@ -0,0 +1,265 @@
|
||||
#include <Renderer/Image.h>
|
||||
#include <Renderer/RenderCore.h>
|
||||
#include <Core/Logs.h>
|
||||
|
||||
namespace Scop
|
||||
{
|
||||
void Image::Init(ImageType type, std::uint32_t width, std::uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, bool is_multisampled, std::string_view name, bool dedicated_alloc)
|
||||
{
|
||||
m_type = type;
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
m_format = format;
|
||||
m_tiling = tiling;
|
||||
m_is_multisampled = is_multisampled;
|
||||
|
||||
KvfImageType kvf_type = KVF_IMAGE_OTHER;
|
||||
switch(m_type)
|
||||
{
|
||||
case ImageType::Color: kvf_type = KVF_IMAGE_COLOR; break;
|
||||
case ImageType::Depth: kvf_type = KVF_IMAGE_DEPTH; break;
|
||||
case ImageType::Cube: kvf_type = KVF_IMAGE_CUBE; break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
if(m_is_multisampled)
|
||||
{
|
||||
VkImageCreateInfo image_info{};
|
||||
image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
image_info.imageType = VK_IMAGE_TYPE_2D;
|
||||
image_info.extent.width = width;
|
||||
image_info.extent.height = height;
|
||||
image_info.extent.depth = 1;
|
||||
image_info.mipLevels = 1;
|
||||
image_info.arrayLayers = (m_type == ImageType::Cube ? 6 : 1);
|
||||
image_info.format = format;
|
||||
image_info.tiling = tiling;
|
||||
image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
image_info.usage = usage;
|
||||
image_info.samples = VK_SAMPLE_COUNT_4_BIT;
|
||||
image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
kvfCheckVk(RenderCore::Get().vkCreateImage(RenderCore::Get().GetDevice(), &image_info, nullptr, &m_image));
|
||||
}
|
||||
else
|
||||
m_image = kvfCreateImage(RenderCore::Get().GetDevice(), width, height, format, tiling, usage, kvf_type);
|
||||
|
||||
VkMemoryRequirements mem_requirements;
|
||||
RenderCore::Get().vkGetImageMemoryRequirements(RenderCore::Get().GetDevice(), m_image, &mem_requirements);
|
||||
|
||||
m_memory = RenderCore::Get().GetAllocator().Allocate(mem_requirements.size, mem_requirements.alignment, *FindMemoryType(mem_requirements.memoryTypeBits, properties), dedicated_alloc);
|
||||
RenderCore::Get().vkBindImageMemory(RenderCore::Get().GetDevice(), m_image, m_memory.memory, m_memory.offset);
|
||||
|
||||
#ifdef SCOP_HAS_DEBUG_UTILS_FUNCTIONS
|
||||
VkDebugUtilsObjectNameInfoEXT name_info{};
|
||||
name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
|
||||
name_info.objectType = VK_OBJECT_TYPE_IMAGE;
|
||||
name_info.objectHandle = reinterpret_cast<std::uint64_t>(m_image);
|
||||
name_info.pObjectName = name.data();
|
||||
RenderCore::Get().vkSetDebugUtilsObjectNameEXT(RenderCore::Get().GetDevice(), &name_info);
|
||||
#endif
|
||||
|
||||
s_image_count++;
|
||||
}
|
||||
|
||||
void Image::CreateImageView(VkImageViewType type, VkImageAspectFlags aspect_flags, int layer_count) noexcept
|
||||
{
|
||||
m_image_view = kvfCreateImageView(RenderCore::Get().GetDevice(), m_image, m_format, type, aspect_flags, layer_count);
|
||||
}
|
||||
|
||||
void Image::CreateSampler() noexcept
|
||||
{
|
||||
m_sampler = kvfCreateSampler(RenderCore::Get().GetDevice(), VK_FILTER_NEAREST, VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_MIPMAP_MODE_NEAREST);
|
||||
}
|
||||
|
||||
void Image::TransitionLayout(VkImageLayout new_layout, VkCommandBuffer cmd)
|
||||
{
|
||||
if(new_layout == m_layout)
|
||||
return;
|
||||
bool is_single_time_cmd_buffer = (cmd == VK_NULL_HANDLE);
|
||||
KvfImageType kvf_type = KVF_IMAGE_OTHER;
|
||||
switch(m_type)
|
||||
{
|
||||
case ImageType::Color: kvf_type = KVF_IMAGE_COLOR; break;
|
||||
case ImageType::Depth: kvf_type = KVF_IMAGE_DEPTH; break;
|
||||
case ImageType::Cube: kvf_type = KVF_IMAGE_CUBE; break;
|
||||
default: break;
|
||||
}
|
||||
if(is_single_time_cmd_buffer)
|
||||
cmd = kvfCreateCommandBuffer(RenderCore::Get().GetDevice());
|
||||
kvfTransitionImageLayout(RenderCore::Get().GetDevice(), m_image, kvf_type, cmd, m_format, m_layout, new_layout, is_single_time_cmd_buffer);
|
||||
if(is_single_time_cmd_buffer)
|
||||
kvfDestroyCommandBuffer(RenderCore::Get().GetDevice(), cmd);
|
||||
m_layout = new_layout;
|
||||
}
|
||||
|
||||
void Image::Clear(VkCommandBuffer cmd, Vec4f color)
|
||||
{
|
||||
VkImageSubresourceRange subresource_range{};
|
||||
subresource_range.baseMipLevel = 0;
|
||||
subresource_range.layerCount = (m_type == ImageType::Cube ? 6 : 1);
|
||||
subresource_range.levelCount = 1;
|
||||
subresource_range.baseArrayLayer = 0;
|
||||
|
||||
if(m_type == ImageType::Color || m_type == ImageType::Cube)
|
||||
{
|
||||
VkImageLayout old_layout = m_layout;
|
||||
subresource_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
TransitionLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, cmd);
|
||||
VkClearColorValue clear_color = VkClearColorValue({ { color.x, color.y, color.z, color.w } });
|
||||
RenderCore::Get().vkCmdClearColorImage(cmd, m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_color, 1, &subresource_range);
|
||||
TransitionLayout(old_layout, cmd);
|
||||
}
|
||||
else if(m_type == ImageType::Depth)
|
||||
{
|
||||
VkClearDepthStencilValue clear_depth_stencil = { 1.0f, 1 };
|
||||
subresource_range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
TransitionLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, cmd);
|
||||
RenderCore::Get().vkCmdClearDepthStencilImage(cmd, m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_depth_stencil, 1, &subresource_range);
|
||||
TransitionLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, cmd);
|
||||
}
|
||||
}
|
||||
|
||||
void Image::DestroySampler() noexcept
|
||||
{
|
||||
if(m_sampler != VK_NULL_HANDLE)
|
||||
kvfDestroySampler(RenderCore::Get().GetDevice(), m_sampler);
|
||||
m_sampler = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
void Image::DestroyImageView() noexcept
|
||||
{
|
||||
if(m_image_view != VK_NULL_HANDLE)
|
||||
kvfDestroyImageView(RenderCore::Get().GetDevice(), m_image_view);
|
||||
m_image_view = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
void Image::Destroy() noexcept
|
||||
{
|
||||
if(m_image == VK_NULL_HANDLE && m_image_view == VK_NULL_HANDLE && m_sampler == VK_NULL_HANDLE)
|
||||
return;
|
||||
RenderCore::Get().WaitDeviceIdle();
|
||||
DestroySampler();
|
||||
DestroyImageView();
|
||||
|
||||
if(m_image != VK_NULL_HANDLE)
|
||||
{
|
||||
RenderCore::Get().GetAllocator().Deallocate(m_memory);
|
||||
m_memory = NULL_MEMORY_BLOCK;
|
||||
kvfDestroyImage(RenderCore::Get().GetDevice(), m_image);
|
||||
}
|
||||
m_image = VK_NULL_HANDLE;
|
||||
m_memory = NULL_MEMORY_BLOCK;
|
||||
m_image = VK_NULL_HANDLE;
|
||||
m_image_view = VK_NULL_HANDLE;
|
||||
m_sampler = VK_NULL_HANDLE;
|
||||
m_layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
m_width = 0;
|
||||
m_height = 0;
|
||||
m_is_multisampled = false;
|
||||
s_image_count--;
|
||||
}
|
||||
|
||||
void CubeTexture::Init(CPUBuffer pixels, std::uint32_t width, std::uint32_t height, VkFormat format, std::string_view name)
|
||||
{
|
||||
if(!pixels)
|
||||
FatalError("Vulkan: a cubemap cannot be created without pixels data");
|
||||
|
||||
std::array<std::vector<std::uint8_t>, 6> texture_data;
|
||||
std::uint32_t face_width = width / 4;
|
||||
std::uint32_t face_height = height / 3;
|
||||
|
||||
std::size_t size = 0;
|
||||
|
||||
for(std::uint32_t cy = 0, face = 0; cy < 3; cy++)
|
||||
{
|
||||
for(std::uint32_t cx = 0; cx < 4; cx++)
|
||||
{
|
||||
if(cx == 0 || cx == 2 || cx == 3)
|
||||
{
|
||||
if(cy != 1)
|
||||
continue;
|
||||
}
|
||||
|
||||
texture_data[face] = std::vector<std::uint8_t>(face_width * face_height * sizeof(std::uint32_t));
|
||||
|
||||
size += sizeof(std::uint32_t) * width * height;
|
||||
|
||||
for(std::uint32_t y = 0; y < face_height; y++)
|
||||
{
|
||||
std::uint32_t offset = y;
|
||||
std::uint32_t yp = cy * face_height + offset;
|
||||
for(std::uint32_t x = 0; x < face_width; x++)
|
||||
{
|
||||
offset = x;
|
||||
std::uint32_t xp = cx * face_width + offset;
|
||||
texture_data[face][(x + y * face_width) * sizeof(std::uint32_t) + 0] = pixels.GetData()[(xp + yp * width) * sizeof(std::uint32_t) + 0];
|
||||
texture_data[face][(x + y * face_width) * sizeof(std::uint32_t) + 1] = pixels.GetData()[(xp + yp * width) * sizeof(std::uint32_t) + 1];
|
||||
texture_data[face][(x + y * face_width) * sizeof(std::uint32_t) + 2] = pixels.GetData()[(xp + yp * width) * sizeof(std::uint32_t) + 2];
|
||||
texture_data[face][(x + y * face_width) * sizeof(std::uint32_t) + 3] = pixels.GetData()[(xp + yp * width) * sizeof(std::uint32_t) + 3];
|
||||
}
|
||||
}
|
||||
face++;
|
||||
}
|
||||
}
|
||||
|
||||
CPUBuffer complete_data(size);
|
||||
std::uint32_t pointer_offset = 0;
|
||||
|
||||
const std::uint32_t face_order[6] = { 3, 1, 0, 5, 2, 4 };
|
||||
|
||||
for(std::uint32_t face : face_order)
|
||||
{
|
||||
std::size_t current_size = face_width * face_height * sizeof(std::uint32_t);
|
||||
std::memcpy(complete_data.GetData() + pointer_offset, texture_data[face].data(), current_size);
|
||||
pointer_offset += current_size;
|
||||
}
|
||||
|
||||
Image::Init(ImageType::Cube, face_width, face_height, format, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, false, std::move(name));
|
||||
Image::CreateImageView(VK_IMAGE_VIEW_TYPE_CUBE, VK_IMAGE_ASPECT_COLOR_BIT, 6);
|
||||
Image::CreateSampler();
|
||||
|
||||
GPUBuffer staging_buffer;
|
||||
staging_buffer.Init(BufferType::Staging, complete_data.GetSize(), VK_BUFFER_USAGE_TRANSFER_SRC_BIT, complete_data);
|
||||
std::vector<VkBufferImageCopy> buffer_copy_regions;
|
||||
std::uint32_t offset = 0;
|
||||
|
||||
for(std::uint32_t face = 0; face < 6; face++)
|
||||
{
|
||||
VkBufferImageCopy buffer_copy_region{};
|
||||
buffer_copy_region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
buffer_copy_region.imageSubresource.mipLevel = 0;
|
||||
buffer_copy_region.imageSubresource.baseArrayLayer = face;
|
||||
buffer_copy_region.imageSubresource.layerCount = 1;
|
||||
buffer_copy_region.imageExtent.width = face_width;
|
||||
buffer_copy_region.imageExtent.height = face_height;
|
||||
buffer_copy_region.imageExtent.depth = 1;
|
||||
buffer_copy_region.bufferOffset = offset;
|
||||
buffer_copy_regions.push_back(buffer_copy_region);
|
||||
|
||||
offset += face_width * face_height * kvfFormatSize(format);
|
||||
}
|
||||
|
||||
VkImageSubresourceRange subresource_range{};
|
||||
subresource_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
subresource_range.baseMipLevel = 0;
|
||||
subresource_range.levelCount = 1;
|
||||
subresource_range.layerCount = 6;
|
||||
|
||||
auto device = RenderCore::Get().GetDevice();
|
||||
|
||||
VkCommandBuffer cmd = kvfCreateCommandBuffer(device);
|
||||
kvfBeginCommandBuffer(cmd, 0);
|
||||
TransitionLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, cmd);
|
||||
RenderCore::Get().vkCmdCopyBufferToImage(cmd, staging_buffer.Get(), Image::Get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, buffer_copy_regions.size(), buffer_copy_regions.data());
|
||||
TransitionLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, cmd);
|
||||
kvfEndCommandBuffer(cmd);
|
||||
|
||||
VkFence fence = kvfCreateFence(device);
|
||||
kvfSubmitSingleTimeCommandBuffer(device, cmd, KVF_GRAPHICS_QUEUE, fence);
|
||||
kvfWaitForFence(device, fence);
|
||||
kvfDestroyFence(device, fence);
|
||||
|
||||
staging_buffer.Destroy();
|
||||
}
|
||||
}
|
||||
110
Runtime/Sources/Renderer/Memory/Chunk.cpp
git.filemode.normal_file
110
Runtime/Sources/Renderer/Memory/Chunk.cpp
git.filemode.normal_file
@@ -0,0 +1,110 @@
|
||||
#include <Renderer/Memory/Chunk.h>
|
||||
#include <Renderer/RenderCore.h>
|
||||
#include <Core/EventBus.h>
|
||||
#include <Core/Logs.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace Scop
|
||||
{
|
||||
namespace Internal
|
||||
{
|
||||
struct MemoryChunkAllocFailedEvent : public EventBase
|
||||
{
|
||||
Event What() const override { return Event::MemoryChunkAllocationFailed; }
|
||||
};
|
||||
}
|
||||
|
||||
MemoryChunk::MemoryChunk(VkDevice device, VkPhysicalDevice physical, VkDeviceSize size, std::int32_t memory_type_index, bool is_dedicated, std::uint32_t& vram_usage, std::uint32_t& vram_host_visible_usage)
|
||||
: m_device(device), m_physical(physical), m_size(size), m_memory_type_index(memory_type_index), m_is_dedicated(is_dedicated)
|
||||
{
|
||||
Verify(device != VK_NULL_HANDLE, "Memory Chunk : invalid device");
|
||||
VkMemoryAllocateInfo alloc_info{};
|
||||
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
alloc_info.allocationSize = size;
|
||||
alloc_info.memoryTypeIndex = m_memory_type_index;
|
||||
if(RenderCore::Get().vkAllocateMemory(m_device, &alloc_info, nullptr, &m_memory) != VK_SUCCESS)
|
||||
{
|
||||
EventBus::Send("__ScopDeviceAllocator", Internal::MemoryChunkAllocFailedEvent{});
|
||||
return;
|
||||
}
|
||||
|
||||
VkPhysicalDeviceMemoryProperties properties;
|
||||
RenderCore::Get().vkGetPhysicalDeviceMemoryProperties(m_physical, &properties);
|
||||
if((properties.memoryTypes[m_memory_type_index].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
|
||||
{
|
||||
if(RenderCore::Get().vkMapMemory(m_device, m_memory, 0, VK_WHOLE_SIZE, 0, &p_map) != VK_SUCCESS)
|
||||
FatalError("Vulkan: failed to map a host visible chunk");
|
||||
vram_host_visible_usage += size;
|
||||
}
|
||||
else
|
||||
vram_usage += size;
|
||||
|
||||
MemoryBlock& block = m_blocks.emplace_back();
|
||||
block.memory = m_memory;
|
||||
block.offset = 0;
|
||||
block.size = size;
|
||||
block.free = true;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<MemoryBlock> MemoryChunk::Allocate(VkDeviceSize size, VkDeviceSize alignment)
|
||||
{
|
||||
for(std::size_t i = 0; i < m_blocks.size(); i++)
|
||||
{
|
||||
if(!m_blocks[i].free || m_blocks[i].size < size)
|
||||
continue;
|
||||
VkDeviceSize offset_displacement = (m_blocks[i].offset % alignment != 0) ? alignment - m_blocks[i].offset % alignment : 0;
|
||||
VkDeviceSize old_size_available = m_blocks[i].size - offset_displacement;
|
||||
|
||||
if(size + offset_displacement <= m_blocks[i].size)
|
||||
{
|
||||
m_blocks[i].offset += offset_displacement;
|
||||
m_blocks[i].size = size;
|
||||
m_blocks[i].free = false;
|
||||
|
||||
if(p_map != nullptr)
|
||||
m_blocks[i].map = reinterpret_cast<void*>(reinterpret_cast<std::uintptr_t>(p_map) + m_blocks[i].offset);
|
||||
|
||||
MemoryBlock new_block;
|
||||
new_block.memory = m_memory;
|
||||
new_block.offset = m_blocks[i].offset + m_blocks[i].size;
|
||||
new_block.size = old_size_available - size;
|
||||
new_block.free = true;
|
||||
|
||||
if(new_block.size > 0)
|
||||
m_blocks.emplace(m_blocks.begin() + i + 1, new_block);
|
||||
return m_blocks[i];
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void MemoryChunk::Deallocate(const MemoryBlock& block)
|
||||
{
|
||||
auto it = std::find(m_blocks.begin(), m_blocks.end(), block);
|
||||
if(it == m_blocks.end())
|
||||
FatalError("Memory Chunk : cannot deallocate a block that is owned by another chunk");
|
||||
it->free = true;
|
||||
|
||||
bool end = false;
|
||||
while(!end)
|
||||
{
|
||||
end = true;
|
||||
for(auto it = m_blocks.begin(); it != m_blocks.end(); ++it)
|
||||
{
|
||||
if(it->free && it + 1 != m_blocks.end() && (it + 1)->free)
|
||||
{
|
||||
it->size += (it + 1)->size;
|
||||
m_blocks.erase(it + 1);
|
||||
end = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MemoryChunk::~MemoryChunk()
|
||||
{
|
||||
RenderCore::Get().vkFreeMemory(m_device, m_memory, nullptr);
|
||||
}
|
||||
}
|
||||
112
Runtime/Sources/Renderer/Memory/DeviceAllocator.cpp
git.filemode.normal_file
112
Runtime/Sources/Renderer/Memory/DeviceAllocator.cpp
git.filemode.normal_file
@@ -0,0 +1,112 @@
|
||||
#include <Renderer/Memory/DeviceAllocator.h>
|
||||
#include <Renderer/RenderCore.h>
|
||||
#include <Maths/Constants.h>
|
||||
#include <Core/Logs.h>
|
||||
#include <Core/EventBus.h>
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace Scop
|
||||
{
|
||||
#define AlignUp(val, alignment) ((val + alignment - 1) & ~(alignment - 1))
|
||||
|
||||
void DeviceAllocator::AttachToDevice(VkDevice device, VkPhysicalDevice physical) noexcept
|
||||
{
|
||||
m_device = device;
|
||||
m_physical = physical;
|
||||
|
||||
RenderCore::Get().vkGetPhysicalDeviceMemoryProperties(physical, &m_mem_props);
|
||||
|
||||
std::function<void(const EventBase&)> functor = [this](const EventBase& event)
|
||||
{
|
||||
if(event.What() == Event::MemoryChunkAllocationFailed)
|
||||
m_last_chunk_creation_failed = true;
|
||||
};
|
||||
EventBus::RegisterListener({ functor, "__ScopDeviceAllocator" });
|
||||
}
|
||||
|
||||
[[nodiscard]] MemoryBlock DeviceAllocator::Allocate(VkDeviceSize size, VkDeviceSize alignment, std::int32_t memory_type_index, bool dedicated_chunk)
|
||||
{
|
||||
Verify(m_device != VK_NULL_HANDLE, "invalid device");
|
||||
Verify(m_physical != VK_NULL_HANDLE, "invalid physical device");
|
||||
const std::lock_guard<std::mutex> guard(m_alloc_mutex);
|
||||
if(!dedicated_chunk)
|
||||
{
|
||||
for(auto& chunk : m_chunks)
|
||||
{
|
||||
if(chunk->GetMemoryTypeIndex() == memory_type_index)
|
||||
{
|
||||
std::optional<MemoryBlock> block = chunk->Allocate(size, alignment);
|
||||
if(block.has_value())
|
||||
return *block;
|
||||
}
|
||||
}
|
||||
}
|
||||
VkDeviceSize chunk_size = dedicated_chunk ? size + alignment : CalcPreferredChunkSize(memory_type_index);
|
||||
if(chunk_size < size + alignment)
|
||||
chunk_size = size + alignment;
|
||||
m_chunks.emplace_back(std::make_unique<MemoryChunk>(m_device, m_physical, chunk_size, memory_type_index, dedicated_chunk, m_vram_usage, m_vram_host_visible_usage));
|
||||
|
||||
if(m_last_chunk_creation_failed && !dedicated_chunk)
|
||||
{
|
||||
// Allocation of this size failed? Try 1/2, 1/4, 1/8 of preferred chunk size.
|
||||
std::uint32_t new_block_size_shift = 0;
|
||||
while(m_last_chunk_creation_failed && new_block_size_shift < NEW_BLOCK_SIZE_SHIFT_MAX)
|
||||
{
|
||||
m_last_chunk_creation_failed = false;
|
||||
m_chunks.pop_back();
|
||||
chunk_size /= 2;
|
||||
if(chunk_size < size + alignment)
|
||||
{
|
||||
m_last_chunk_creation_failed = true;
|
||||
break;
|
||||
}
|
||||
m_chunks.emplace_back(std::make_unique<MemoryChunk>(m_device, m_physical, chunk_size, memory_type_index, false, m_vram_usage, m_vram_host_visible_usage));
|
||||
}
|
||||
}
|
||||
|
||||
// If we could not recover from allocation failure
|
||||
if(m_last_chunk_creation_failed)
|
||||
FatalError("Device Allocator: could not allocate a memory chunk");
|
||||
|
||||
std::optional<MemoryBlock> block = m_chunks.back()->Allocate(size, alignment);
|
||||
m_allocations_count++;
|
||||
if(block.has_value())
|
||||
return *block;
|
||||
FatalError("Device Allocator: could not allocate a memory block");
|
||||
return {}; // to avoid warnings
|
||||
}
|
||||
|
||||
void DeviceAllocator::Deallocate(const MemoryBlock& block)
|
||||
{
|
||||
Verify(m_device != VK_NULL_HANDLE, "invalid device");
|
||||
Verify(m_physical != VK_NULL_HANDLE, "invalid physical device");
|
||||
const std::lock_guard<std::mutex> guard(m_dealloc_mutex);
|
||||
for(auto it = m_chunks.begin(); it != m_chunks.end(); ++it)
|
||||
{
|
||||
if((*it)->Has(block))
|
||||
{
|
||||
(*it)->Deallocate(block);
|
||||
if((*it)->IsDedicated())
|
||||
{
|
||||
if((*it)->GetMap() != nullptr) // If it is host visible
|
||||
m_vram_host_visible_usage -= (*it)->GetSize();
|
||||
else
|
||||
m_vram_usage -= (*it)->GetSize();
|
||||
m_chunks.erase(it);
|
||||
m_allocations_count--;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
Error("Device Allocator: unable to free a block; could not find it's chunk");
|
||||
}
|
||||
|
||||
VkDeviceSize DeviceAllocator::CalcPreferredChunkSize(std::uint32_t mem_type_index)
|
||||
{
|
||||
std::uint32_t heap_index = m_mem_props.memoryTypes[mem_type_index].heapIndex;
|
||||
VkDeviceSize heap_size = m_mem_props.memoryHeaps[heap_index].size;
|
||||
bool is_small_heap = heap_size <= SMALL_HEAP_MAX_SIZE;
|
||||
return AlignUp((is_small_heap ? (heap_size / 8) : DEFAULT_LARGE_HEAP_BLOCK_SIZE), (VkDeviceSize)32);
|
||||
}
|
||||
}
|
||||
236
Runtime/Sources/Renderer/Pipelines/Graphics.cpp
git.filemode.normal_file
236
Runtime/Sources/Renderer/Pipelines/Graphics.cpp
git.filemode.normal_file
@@ -0,0 +1,236 @@
|
||||
#include <Renderer/Pipelines/Graphics.h>
|
||||
#include <Renderer/RenderCore.h>
|
||||
#include <Renderer/Renderer.h>
|
||||
#include <Renderer/Vertex.h>
|
||||
#include <Graphics/Enums.h>
|
||||
#include <Core/EventBus.h>
|
||||
#include <Core/Logs.h>
|
||||
|
||||
namespace Scop
|
||||
{
|
||||
void GraphicPipeline::Init(GraphicPipelineDescriptor descriptor)
|
||||
{
|
||||
Setup(std::move(descriptor));
|
||||
|
||||
m_description.vertex_shader->SetPipelineInUse(this);
|
||||
m_description.fragment_shader->SetPipelineInUse(this);
|
||||
|
||||
std::vector<VkPushConstantRange> push_constants;
|
||||
std::vector<VkDescriptorSetLayout> set_layouts;
|
||||
push_constants.insert(push_constants.end(), m_description.vertex_shader->GetPipelineLayout().push_constants.begin(), m_description.vertex_shader->GetPipelineLayout().push_constants.end());
|
||||
push_constants.insert(push_constants.end(), m_description.fragment_shader->GetPipelineLayout().push_constants.begin(), m_description.fragment_shader->GetPipelineLayout().push_constants.end());
|
||||
set_layouts.insert(set_layouts.end(), m_description.vertex_shader->GetPipelineLayout().set_layouts.begin(), m_description.vertex_shader->GetPipelineLayout().set_layouts.end());
|
||||
set_layouts.insert(set_layouts.end(), m_description.fragment_shader->GetPipelineLayout().set_layouts.begin(), m_description.fragment_shader->GetPipelineLayout().set_layouts.end());
|
||||
m_pipeline_layout = kvfCreatePipelineLayout(RenderCore::Get().GetDevice(), set_layouts.data(), set_layouts.size(), push_constants.data(), push_constants.size());
|
||||
|
||||
CreateFramebuffers(m_description.color_attachments, m_description.clear_color_attachments);
|
||||
|
||||
VkPhysicalDeviceFeatures features{};
|
||||
RenderCore::Get().vkGetPhysicalDeviceFeatures(RenderCore::Get().GetPhysicalDevice(), &features);
|
||||
|
||||
VkCullModeFlags cullmode;
|
||||
switch(m_description.culling)
|
||||
{
|
||||
case CullMode::None: cullmode = VK_CULL_MODE_NONE; break;
|
||||
case CullMode::Back: cullmode = VK_CULL_MODE_BACK_BIT; break;
|
||||
case CullMode::Front: cullmode = VK_CULL_MODE_FRONT_BIT; break;
|
||||
case CullMode::FrontAndBack: cullmode = VK_CULL_MODE_FRONT_AND_BACK; break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
KvfGraphicsPipelineBuilder* builder = kvfCreateGPipelineBuilder();
|
||||
kvfGPipelineBuilderAddShaderStage(builder, m_description.vertex_shader->GetShaderStage(), m_description.vertex_shader->GetShaderModule(), "main");
|
||||
kvfGPipelineBuilderAddShaderStage(builder, m_description.fragment_shader->GetShaderStage(), m_description.fragment_shader->GetShaderModule(), "main");
|
||||
kvfGPipelineBuilderSetInputTopology(builder, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
|
||||
kvfGPipelineBuilderSetCullMode(builder, cullmode, VK_FRONT_FACE_CLOCKWISE);
|
||||
kvfGPipelineBuilderEnableAlphaBlending(builder);
|
||||
if(m_description.depth)
|
||||
kvfGPipelineBuilderEnableDepthTest(builder, (m_description.depth_test_equal ? VK_COMPARE_OP_EQUAL : VK_COMPARE_OP_LESS), true);
|
||||
else
|
||||
kvfGPipelineBuilderDisableDepthTest(builder);
|
||||
if(m_description.wireframe && features.fillModeNonSolid)
|
||||
kvfGPipelineBuilderSetPolygonMode(builder, VK_POLYGON_MODE_LINE, 1.0f);
|
||||
else
|
||||
kvfGPipelineBuilderSetPolygonMode(builder, VK_POLYGON_MODE_FILL, 1.0f);
|
||||
if(features.sampleRateShading)
|
||||
kvfGPipelineBuilderSetMultisamplingShading(builder, VK_SAMPLE_COUNT_1_BIT, 0.25f);
|
||||
else
|
||||
kvfGPipelineBuilderSetMultisampling(builder, VK_SAMPLE_COUNT_1_BIT);
|
||||
|
||||
if(!m_description.no_vertex_inputs)
|
||||
{
|
||||
VkVertexInputBindingDescription binding_description = Vertex::GetBindingDescription();
|
||||
auto attributes_description = Vertex::GetAttributeDescriptions();
|
||||
kvfGPipelineBuilderSetVertexInputs(builder, binding_description, attributes_description.data(), attributes_description.size());
|
||||
}
|
||||
|
||||
m_pipeline = kvfCreateGraphicsPipeline(RenderCore::Get().GetDevice(), VK_NULL_HANDLE, m_pipeline_layout, builder, m_renderpass);
|
||||
kvfDestroyGPipelineBuilder(builder);
|
||||
|
||||
#ifdef SCOP_HAS_DEBUG_UTILS_FUNCTIONS
|
||||
VkDebugUtilsObjectNameInfoEXT name_info{};
|
||||
name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
|
||||
name_info.objectType = VK_OBJECT_TYPE_PIPELINE;
|
||||
name_info.objectHandle = reinterpret_cast<std::uint64_t>(m_pipeline);
|
||||
name_info.pObjectName = m_description.name.data();
|
||||
RenderCore::Get().vkSetDebugUtilsObjectNameEXT(RenderCore::Get().GetDevice(), &name_info);
|
||||
|
||||
name_info.objectType = VK_OBJECT_TYPE_RENDER_PASS;
|
||||
name_info.objectHandle = reinterpret_cast<std::uint64_t>(m_renderpass);
|
||||
RenderCore::Get().vkSetDebugUtilsObjectNameEXT(RenderCore::Get().GetDevice(), &name_info);
|
||||
|
||||
name_info.objectType = VK_OBJECT_TYPE_SHADER_MODULE;
|
||||
name_info.objectHandle = reinterpret_cast<std::uint64_t>(m_description.vertex_shader->GetShaderModule());
|
||||
RenderCore::Get().vkSetDebugUtilsObjectNameEXT(RenderCore::Get().GetDevice(), &name_info);
|
||||
|
||||
name_info.objectHandle = reinterpret_cast<std::uint64_t>(m_description.fragment_shader->GetShaderModule());
|
||||
RenderCore::Get().vkSetDebugUtilsObjectNameEXT(RenderCore::Get().GetDevice(), &name_info);
|
||||
|
||||
name_info.objectType = VK_OBJECT_TYPE_FRAMEBUFFER;
|
||||
for(VkFramebuffer fb : m_framebuffers)
|
||||
{
|
||||
name_info.objectHandle = reinterpret_cast<std::uint64_t>(fb);
|
||||
RenderCore::Get().vkSetDebugUtilsObjectNameEXT(RenderCore::Get().GetDevice(), &name_info);
|
||||
}
|
||||
Message("Vulkan: % graphics pipeline created", m_description.name);
|
||||
#else
|
||||
Message("Vulkan: graphics pipeline created");
|
||||
#endif
|
||||
}
|
||||
|
||||
bool GraphicPipeline::BindPipeline(VkCommandBuffer command_buffer, std::size_t framebuffer_index, std::array<float, 4> clear) noexcept
|
||||
{
|
||||
if(s_bound_pipeline != nullptr)
|
||||
{
|
||||
Error("Vulkan: cannot bind a graphics pipeline because another one have not been unbound");
|
||||
return false;
|
||||
}
|
||||
|
||||
s_bound_pipeline = this;
|
||||
TransitionAttachments(command_buffer);
|
||||
|
||||
VkFramebuffer fb = m_framebuffers[framebuffer_index];
|
||||
VkExtent2D fb_extent = kvfGetFramebufferSize(fb);
|
||||
|
||||
VkViewport viewport{};
|
||||
viewport.x = 0.0f;
|
||||
viewport.y = 0.0f;
|
||||
viewport.width = fb_extent.width;
|
||||
viewport.height = fb_extent.height;
|
||||
viewport.minDepth = 0.0f;
|
||||
viewport.maxDepth = 1.0f;
|
||||
RenderCore::Get().vkCmdSetViewport(command_buffer, 0, 1, &viewport);
|
||||
|
||||
VkRect2D scissor{};
|
||||
scissor.offset = { 0, 0 };
|
||||
scissor.extent = fb_extent;
|
||||
RenderCore::Get().vkCmdSetScissor(command_buffer, 0, 1, &scissor);
|
||||
|
||||
for(int i = 0; i < m_clears.size(); i++)
|
||||
{
|
||||
m_clears[i].color.float32[0] = clear[0];
|
||||
m_clears[i].color.float32[1] = clear[1];
|
||||
m_clears[i].color.float32[2] = clear[2];
|
||||
m_clears[i].color.float32[3] = clear[3];
|
||||
}
|
||||
|
||||
if(m_description.depth)
|
||||
m_clears.back().depthStencil = VkClearDepthStencilValue{ 1.0f, 0 };
|
||||
|
||||
kvfBeginRenderPass(m_renderpass, command_buffer, fb, fb_extent, m_clears.data(), m_clears.size());
|
||||
RenderCore::Get().vkCmdBindPipeline(command_buffer, GetPipelineBindPoint(), GetPipeline());
|
||||
return true;
|
||||
}
|
||||
|
||||
void GraphicPipeline::EndPipeline(VkCommandBuffer command_buffer) noexcept
|
||||
{
|
||||
if(s_bound_pipeline != this)
|
||||
return;
|
||||
RenderCore::Get().vkCmdEndRenderPass(command_buffer);
|
||||
s_bound_pipeline = nullptr;
|
||||
}
|
||||
|
||||
void GraphicPipeline::Destroy() noexcept
|
||||
{
|
||||
if(m_pipeline == VK_NULL_HANDLE)
|
||||
return;
|
||||
RenderCore::Get().WaitDeviceIdle();
|
||||
|
||||
for(auto& fb : m_framebuffers)
|
||||
{
|
||||
kvfDestroyFramebuffer(RenderCore::Get().GetDevice(), fb);
|
||||
Message("Vulkan: framebuffer destroyed");
|
||||
}
|
||||
|
||||
kvfDestroyPipelineLayout(RenderCore::Get().GetDevice(), m_pipeline_layout);
|
||||
Message("Vulkan: graphics pipeline layout destroyed");
|
||||
kvfDestroyRenderPass(RenderCore::Get().GetDevice(), m_renderpass);
|
||||
Message("Vulkan: renderpass destroyed");
|
||||
kvfDestroyPipeline(RenderCore::Get().GetDevice(), m_pipeline);
|
||||
|
||||
m_description.vertex_shader.reset();
|
||||
m_description.fragment_shader.reset();
|
||||
m_description.color_attachments.clear();
|
||||
m_framebuffers.clear();
|
||||
m_clears.clear();
|
||||
m_renderpass = VK_NULL_HANDLE;
|
||||
m_pipeline = VK_NULL_HANDLE;
|
||||
m_pipeline_layout = VK_NULL_HANDLE;
|
||||
Message("Vulkan: graphics pipeline destroyed");
|
||||
}
|
||||
|
||||
void GraphicPipeline::CreateFramebuffers(const std::vector<NonOwningPtr<Texture>>& render_targets, bool clear_attachments)
|
||||
{
|
||||
TransitionAttachments();
|
||||
|
||||
std::vector<VkAttachmentDescription> attachments;
|
||||
std::vector<VkImageView> attachment_views;
|
||||
if(m_description.renderer)
|
||||
{
|
||||
attachments.push_back(kvfBuildSwapchainAttachmentDescription(m_description.renderer->GetSwapchain().Get(), clear_attachments));
|
||||
attachment_views.push_back(m_description.renderer->GetSwapchain().GetSwapchainImages()[0].GetImageView());
|
||||
}
|
||||
|
||||
for(NonOwningPtr<Texture> image : render_targets)
|
||||
{
|
||||
attachments.push_back(kvfBuildAttachmentDescription(KVF_IMAGE_COLOR, image->GetFormat(), image->GetLayout(), image->GetLayout(), clear_attachments, VK_SAMPLE_COUNT_1_BIT));
|
||||
attachment_views.push_back(image->GetImageView());
|
||||
}
|
||||
|
||||
if(m_description.depth)
|
||||
{
|
||||
attachments.push_back(kvfBuildAttachmentDescription(KVF_IMAGE_DEPTH, m_description.depth->GetFormat(), m_description.depth->GetLayout(), m_description.depth->GetLayout(), clear_attachments, VK_SAMPLE_COUNT_1_BIT));
|
||||
attachment_views.push_back(m_description.depth->GetImageView());
|
||||
}
|
||||
|
||||
m_renderpass = kvfCreateRenderPass(RenderCore::Get().GetDevice(), attachments.data(), attachments.size(), GetPipelineBindPoint());
|
||||
m_clears.clear();
|
||||
m_clears.resize(attachments.size());
|
||||
Message("Vulkan: renderpass created");
|
||||
|
||||
if(m_description.renderer)
|
||||
{
|
||||
for(const Image& image : m_description.renderer->GetSwapchain().GetSwapchainImages())
|
||||
{
|
||||
attachment_views[0] = image.GetImageView();
|
||||
m_framebuffers.push_back(kvfCreateFramebuffer(RenderCore::Get().GetDevice(), m_renderpass, attachment_views.data(), attachment_views.size(), { .width = image.GetWidth(), .height = image.GetHeight() }));
|
||||
Message("Vulkan: framebuffer created");
|
||||
}
|
||||
}
|
||||
for(NonOwningPtr<Texture> image : render_targets)
|
||||
{
|
||||
m_framebuffers.push_back(kvfCreateFramebuffer(RenderCore::Get().GetDevice(), m_renderpass, attachment_views.data(), attachment_views.size(), { .width = image->GetWidth(), .height = image->GetHeight() }));
|
||||
Message("Vulkan: framebuffer created");
|
||||
}
|
||||
}
|
||||
|
||||
void GraphicPipeline::TransitionAttachments(VkCommandBuffer cmd)
|
||||
{
|
||||
if(m_description.depth)
|
||||
m_description.depth->TransitionLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, cmd);
|
||||
|
||||
for(NonOwningPtr<Texture> image : m_description.color_attachments)
|
||||
image->TransitionLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, cmd);
|
||||
}
|
||||
}
|
||||
102
Runtime/Sources/Renderer/Pipelines/Shader.cpp
git.filemode.normal_file
102
Runtime/Sources/Renderer/Pipelines/Shader.cpp
git.filemode.normal_file
@@ -0,0 +1,102 @@
|
||||
#include <Renderer/Pipelines/Shader.h>
|
||||
#include <Renderer/RenderCore.h>
|
||||
#include <Core/Logs.h>
|
||||
#include <fstream>
|
||||
|
||||
namespace Scop
|
||||
{
|
||||
Shader::Shader(const std::vector<std::uint32_t>& bytecode, ShaderType type, ShaderLayout layout, std::string name) : m_name(std::move(name)), m_bytecode(bytecode), m_layout(std::move(layout))
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case ShaderType::Vertex : m_stage = VK_SHADER_STAGE_VERTEX_BIT; break;
|
||||
case ShaderType::Fragment : m_stage = VK_SHADER_STAGE_FRAGMENT_BIT; break;
|
||||
case ShaderType::Compute : m_stage = VK_SHADER_STAGE_COMPUTE_BIT; break;
|
||||
default : FatalError("wtf"); break;
|
||||
}
|
||||
m_module = kvfCreateShaderModule(RenderCore::Get().GetDevice(), m_bytecode.data(), m_bytecode.size());
|
||||
Message("Vulkan: shader module % created", m_name);
|
||||
|
||||
#ifdef SCOP_HAS_DEBUG_UTILS_FUNCTIONS
|
||||
VkDebugUtilsObjectNameInfoEXT name_info{};
|
||||
name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
|
||||
name_info.objectType = VK_OBJECT_TYPE_SHADER_MODULE;
|
||||
name_info.objectHandle = reinterpret_cast<std::uint64_t>(m_module);
|
||||
name_info.pObjectName = m_name.c_str();
|
||||
RenderCore::Get().vkSetDebugUtilsObjectNameEXT(RenderCore::Get().GetDevice(), &name_info);
|
||||
#endif
|
||||
|
||||
GeneratePipelineLayout(m_layout);
|
||||
}
|
||||
|
||||
void Shader::GeneratePipelineLayout(ShaderLayout layout)
|
||||
{
|
||||
for(auto& [_, set] : layout.set_layouts)
|
||||
{
|
||||
std::vector<VkDescriptorSetLayoutBinding> bindings(set.binds.size());
|
||||
std::size_t i = 0;
|
||||
for(auto& [bind, type] : set.binds)
|
||||
{
|
||||
bindings[i].binding = bind;
|
||||
bindings[i].descriptorCount = 1;
|
||||
bindings[i].descriptorType = type;
|
||||
bindings[i].pImmutableSamplers = nullptr;
|
||||
bindings[i].stageFlags = m_stage;
|
||||
i++;
|
||||
}
|
||||
m_set_layouts.emplace_back(kvfCreateDescriptorSetLayout(RenderCore::Get().GetDevice(), bindings.data(), bindings.size()));
|
||||
Message("Vulkan: descriptor set layout created");
|
||||
m_pipeline_layout_part.set_layouts.push_back(m_set_layouts.back());
|
||||
}
|
||||
|
||||
std::size_t i = 0;
|
||||
std::vector<VkPushConstantRange> push_constants(layout.push_constants.size());
|
||||
m_pipeline_layout_part.push_constants.resize(layout.push_constants.size());
|
||||
for(auto& pc : layout.push_constants)
|
||||
{
|
||||
VkPushConstantRange push_constant_range = {};
|
||||
push_constant_range.offset = pc.offset;
|
||||
push_constant_range.size = pc.size;
|
||||
push_constant_range.stageFlags = m_stage;
|
||||
push_constants[i] = push_constant_range;
|
||||
m_pipeline_layout_part.push_constants[i] = push_constant_range;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::Destroy()
|
||||
{
|
||||
if(m_module == VK_NULL_HANDLE)
|
||||
return;
|
||||
kvfDestroyShaderModule(RenderCore::Get().GetDevice(), m_module);
|
||||
m_module = VK_NULL_HANDLE;
|
||||
Message("Vulkan: shader module % destroyed", m_name);
|
||||
for(auto& layout : m_set_layouts)
|
||||
{
|
||||
kvfDestroyDescriptorSetLayout(RenderCore::Get().GetDevice(), layout);
|
||||
Message("Vulkan: descriptor set layout destroyed");
|
||||
}
|
||||
}
|
||||
|
||||
Shader::~Shader()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
std::shared_ptr<Shader> LoadShaderFromFile(const std::filesystem::path& filepath, ShaderType type, ShaderLayout layout)
|
||||
{
|
||||
std::ifstream stream(filepath, std::ios::binary);
|
||||
if(!stream.is_open())
|
||||
FatalError("Renderer : unable to open a spirv shader file, %", filepath);
|
||||
std::vector<std::uint32_t> data;
|
||||
stream.seekg(0);
|
||||
std::uint32_t part = 0;
|
||||
while(stream.read(reinterpret_cast<char*>(&part), sizeof(part)))
|
||||
data.push_back(part);
|
||||
stream.close();
|
||||
|
||||
std::shared_ptr<Shader> shader = std::make_shared<Shader>(data, type, layout, filepath.stem().string());
|
||||
Message("Vulkan: shader loaded %", filepath);
|
||||
return shader;
|
||||
}
|
||||
}
|
||||
277
Runtime/Sources/Renderer/RenderCore.cpp
git.filemode.normal_file
277
Runtime/Sources/Renderer/RenderCore.cpp
git.filemode.normal_file
@@ -0,0 +1,277 @@
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_vulkan.h>
|
||||
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
|
||||
#include <Core/Engine.h>
|
||||
#include <Platform/Window.h>
|
||||
#include <Renderer/Descriptor.h>
|
||||
#include <Renderer/RenderCore.h>
|
||||
#include <Renderer/Pipelines/Shader.h>
|
||||
#include <Renderer/Vulkan/VulkanLoader.h>
|
||||
#include <Maths/Mat4.h>
|
||||
#include <Core/Logs.h>
|
||||
|
||||
#define KVF_IMPLEMENTATION
|
||||
#ifdef DEBUG
|
||||
#define KVF_ENABLE_VALIDATION_LAYERS
|
||||
#endif
|
||||
#define KVF_ASSERT(x) (Scop::Assert(x, "internal kvf assertion " #x))
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
|
||||
#include <kvf.h>
|
||||
#pragma GCC diagnostic pop
|
||||
#elif defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wmissing-field-initializers"
|
||||
#include <kvf.h>
|
||||
#pragma clang diagnostic pop
|
||||
#else
|
||||
#include <kvf.h>
|
||||
#endif
|
||||
|
||||
namespace Scop
|
||||
{
|
||||
static std::unique_ptr<VulkanLoader> loader;
|
||||
|
||||
std::optional<std::uint32_t> FindMemoryType(std::uint32_t type_filter, VkMemoryPropertyFlags properties, bool error)
|
||||
{
|
||||
VkPhysicalDeviceMemoryProperties mem_properties;
|
||||
RenderCore::Get().vkGetPhysicalDeviceMemoryProperties(RenderCore::Get().GetPhysicalDevice(), &mem_properties);
|
||||
|
||||
for(std::uint32_t i = 0; i < mem_properties.memoryTypeCount; i++)
|
||||
{
|
||||
if((type_filter & (1 << i)) && (mem_properties.memoryTypes[i].propertyFlags & properties) == properties)
|
||||
return i;
|
||||
}
|
||||
if(error)
|
||||
FatalError("Vulkan: failed to find suitable memory type");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void ErrorCallback(const char* message) noexcept
|
||||
{
|
||||
Logs::Report(LogType::FatalError, 0, "", "", message);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
void ValidationErrorCallback(const char* message) noexcept
|
||||
{
|
||||
Logs::Report(LogType::Error, 0, "", "", message);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
void WarningCallback(const char* message) noexcept
|
||||
{
|
||||
Logs::Report(LogType::Warning, 0, "", "", message);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
RenderCore* RenderCore::s_instance = nullptr;
|
||||
|
||||
RenderCore::RenderCore()
|
||||
{
|
||||
if(s_instance != nullptr)
|
||||
return;
|
||||
|
||||
s_instance = this;
|
||||
|
||||
Window window("", 1, 1, true);
|
||||
std::vector<const char*> instance_extensions = window.GetRequiredVulkanInstanceExtentions();
|
||||
|
||||
loader = std::make_unique<VulkanLoader>();
|
||||
|
||||
LoadKVFGlobalVulkanFunctionPointers();
|
||||
|
||||
kvfSetErrorCallback(&ErrorCallback);
|
||||
kvfSetWarningCallback(&WarningCallback);
|
||||
kvfSetValidationErrorCallback(&ValidationErrorCallback);
|
||||
kvfSetValidationWarningCallback(&WarningCallback);
|
||||
|
||||
//kvfAddLayer("VK_LAYER_MESA_overlay");
|
||||
|
||||
m_instance = kvfCreateInstance(instance_extensions.data(), instance_extensions.size());
|
||||
Message("Vulkan: instance created");
|
||||
|
||||
loader->LoadInstance(m_instance);
|
||||
LoadKVFInstanceVulkanFunctionPointers();
|
||||
|
||||
VkSurfaceKHR surface = window.CreateVulkanSurface(m_instance);
|
||||
|
||||
m_physical_device = kvfPickGoodDefaultPhysicalDevice(m_instance, surface);
|
||||
|
||||
// just for style
|
||||
VkPhysicalDeviceProperties props;
|
||||
vkGetPhysicalDeviceProperties(m_physical_device, &props);
|
||||
Message("Vulkan: physical device picked '%'", props.deviceName);
|
||||
|
||||
const char* device_extensions[] = { VK_KHR_SWAPCHAIN_EXTENSION_NAME };
|
||||
VkPhysicalDeviceFeatures features{};
|
||||
vkGetPhysicalDeviceFeatures(m_physical_device, &features);
|
||||
m_device = kvfCreateDevice(m_physical_device, device_extensions, sizeof(device_extensions) / sizeof(device_extensions[0]), &features);
|
||||
Message("Vulkan: logical device created");
|
||||
|
||||
loader->LoadDevice(m_device);
|
||||
LoadKVFDeviceVulkanFunctionPointers();
|
||||
|
||||
vkDestroySurfaceKHR(m_instance, surface, nullptr);
|
||||
|
||||
m_allocator.AttachToDevice(m_device, m_physical_device);
|
||||
|
||||
p_descriptor_pool_manager = std::make_unique<DescriptorPoolManager>();
|
||||
|
||||
ShaderLayout vertex_shader_layout(
|
||||
{
|
||||
{ 0,
|
||||
ShaderSetLayout({
|
||||
{ 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER }
|
||||
})
|
||||
}
|
||||
}, { ShaderPushConstantLayout({ 0, sizeof(Mat4f) * 2 }) }
|
||||
);
|
||||
m_internal_shaders[DEFAULT_VERTEX_SHADER_ID] = LoadShaderFromFile(ScopEngine::Get().GetAssetsPath() / "Shaders/Build/ForwardVertex.spv", ShaderType::Vertex, std::move(vertex_shader_layout));
|
||||
|
||||
ShaderLayout default_fragment_shader_layout(
|
||||
{
|
||||
{ 1,
|
||||
ShaderSetLayout({
|
||||
{ 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER },
|
||||
{ 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER }
|
||||
})
|
||||
}
|
||||
}, {}
|
||||
);
|
||||
m_internal_shaders[DEFAULT_FRAGMENT_SHADER_ID] = LoadShaderFromFile(ScopEngine::Get().GetAssetsPath() / "Shaders/Build/ForwardDefaultFragment.spv", ShaderType::Fragment, std::move(default_fragment_shader_layout));
|
||||
|
||||
ShaderLayout basic_fragment_shader_layout(
|
||||
{
|
||||
{ 1,
|
||||
ShaderSetLayout({
|
||||
{ 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER },
|
||||
{ 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER }
|
||||
})
|
||||
}
|
||||
}, {}
|
||||
);
|
||||
m_internal_shaders[BASIC_FRAGMENT_SHADER_ID] = LoadShaderFromFile(ScopEngine::Get().GetAssetsPath() / "Shaders/Build/ForwardBasicFragment.spv", ShaderType::Fragment, std::move(basic_fragment_shader_layout));
|
||||
}
|
||||
|
||||
#undef SCOP_LOAD_FUNCTION
|
||||
#define SCOP_LOAD_FUNCTION(fn) pfns.fn = this->fn
|
||||
|
||||
void RenderCore::LoadKVFGlobalVulkanFunctionPointers() const noexcept
|
||||
{
|
||||
KvfGlobalVulkanFunctions pfns;
|
||||
SCOP_LOAD_FUNCTION(vkCreateInstance);
|
||||
SCOP_LOAD_FUNCTION(vkEnumerateInstanceExtensionProperties);
|
||||
SCOP_LOAD_FUNCTION(vkEnumerateInstanceLayerProperties);
|
||||
SCOP_LOAD_FUNCTION(vkGetInstanceProcAddr);
|
||||
kvfPassGlobalVulkanFunctionPointers(&pfns);
|
||||
}
|
||||
|
||||
void RenderCore::LoadKVFInstanceVulkanFunctionPointers() const noexcept
|
||||
{
|
||||
KvfInstanceVulkanFunctions pfns;
|
||||
SCOP_LOAD_FUNCTION(vkCreateDevice);
|
||||
SCOP_LOAD_FUNCTION(vkDestroyInstance);
|
||||
SCOP_LOAD_FUNCTION(vkEnumerateDeviceExtensionProperties);
|
||||
SCOP_LOAD_FUNCTION(vkEnumeratePhysicalDevices);
|
||||
SCOP_LOAD_FUNCTION(vkGetPhysicalDeviceFeatures);
|
||||
SCOP_LOAD_FUNCTION(vkGetPhysicalDeviceFormatProperties);
|
||||
SCOP_LOAD_FUNCTION(vkGetPhysicalDeviceImageFormatProperties);
|
||||
SCOP_LOAD_FUNCTION(vkGetPhysicalDeviceMemoryProperties);
|
||||
SCOP_LOAD_FUNCTION(vkGetPhysicalDeviceProperties);
|
||||
SCOP_LOAD_FUNCTION(vkGetPhysicalDeviceQueueFamilyProperties);
|
||||
SCOP_LOAD_FUNCTION(vkDestroySurfaceKHR);
|
||||
SCOP_LOAD_FUNCTION(vkGetPhysicalDeviceSurfaceCapabilitiesKHR);
|
||||
SCOP_LOAD_FUNCTION(vkGetPhysicalDeviceSurfaceFormatsKHR);
|
||||
SCOP_LOAD_FUNCTION(vkGetPhysicalDeviceSurfacePresentModesKHR);
|
||||
SCOP_LOAD_FUNCTION(vkGetPhysicalDeviceSurfaceSupportKHR);
|
||||
kvfPassInstanceVulkanFunctionPointers(&pfns);
|
||||
}
|
||||
|
||||
void RenderCore::LoadKVFDeviceVulkanFunctionPointers() const noexcept
|
||||
{
|
||||
KvfDeviceVulkanFunctions pfns;
|
||||
SCOP_LOAD_FUNCTION(vkAllocateCommandBuffers);
|
||||
SCOP_LOAD_FUNCTION(vkAllocateDescriptorSets);
|
||||
SCOP_LOAD_FUNCTION(vkBeginCommandBuffer);
|
||||
SCOP_LOAD_FUNCTION(vkCmdBeginRenderPass);
|
||||
SCOP_LOAD_FUNCTION(vkCmdCopyBuffer);
|
||||
SCOP_LOAD_FUNCTION(vkCmdCopyBufferToImage);
|
||||
SCOP_LOAD_FUNCTION(vkCmdCopyImage);
|
||||
SCOP_LOAD_FUNCTION(vkCmdCopyImageToBuffer);
|
||||
SCOP_LOAD_FUNCTION(vkCmdEndRenderPass);
|
||||
SCOP_LOAD_FUNCTION(vkCmdPipelineBarrier);
|
||||
SCOP_LOAD_FUNCTION(vkCreateBuffer);
|
||||
SCOP_LOAD_FUNCTION(vkCreateCommandPool);
|
||||
SCOP_LOAD_FUNCTION(vkCreateDescriptorPool);
|
||||
SCOP_LOAD_FUNCTION(vkCreateDescriptorSetLayout);
|
||||
SCOP_LOAD_FUNCTION(vkCreateFence);
|
||||
SCOP_LOAD_FUNCTION(vkCreateFramebuffer);
|
||||
SCOP_LOAD_FUNCTION(vkCreateGraphicsPipelines);
|
||||
SCOP_LOAD_FUNCTION(vkCreateImage);
|
||||
SCOP_LOAD_FUNCTION(vkCreateImageView);
|
||||
SCOP_LOAD_FUNCTION(vkCreatePipelineLayout);
|
||||
SCOP_LOAD_FUNCTION(vkCreateRenderPass);
|
||||
SCOP_LOAD_FUNCTION(vkCreateSampler);
|
||||
SCOP_LOAD_FUNCTION(vkCreateSemaphore);
|
||||
SCOP_LOAD_FUNCTION(vkCreateShaderModule);
|
||||
SCOP_LOAD_FUNCTION(vkDestroyBuffer);
|
||||
SCOP_LOAD_FUNCTION(vkDestroyCommandPool);
|
||||
SCOP_LOAD_FUNCTION(vkDestroyDescriptorPool);
|
||||
SCOP_LOAD_FUNCTION(vkDestroyDescriptorSetLayout);
|
||||
SCOP_LOAD_FUNCTION(vkDestroyDevice);
|
||||
SCOP_LOAD_FUNCTION(vkDestroyFence);
|
||||
SCOP_LOAD_FUNCTION(vkDestroyFramebuffer);
|
||||
SCOP_LOAD_FUNCTION(vkDestroyImage);
|
||||
SCOP_LOAD_FUNCTION(vkDestroyImageView);
|
||||
SCOP_LOAD_FUNCTION(vkDestroyPipeline);
|
||||
SCOP_LOAD_FUNCTION(vkDestroyPipelineLayout);
|
||||
SCOP_LOAD_FUNCTION(vkDestroyRenderPass);
|
||||
SCOP_LOAD_FUNCTION(vkDestroySampler);
|
||||
SCOP_LOAD_FUNCTION(vkDestroySemaphore);
|
||||
SCOP_LOAD_FUNCTION(vkDestroyShaderModule);
|
||||
SCOP_LOAD_FUNCTION(vkDeviceWaitIdle);
|
||||
SCOP_LOAD_FUNCTION(vkEndCommandBuffer);
|
||||
SCOP_LOAD_FUNCTION(vkFreeCommandBuffers);
|
||||
SCOP_LOAD_FUNCTION(vkGetDeviceQueue);
|
||||
SCOP_LOAD_FUNCTION(vkGetImageSubresourceLayout);
|
||||
SCOP_LOAD_FUNCTION(vkQueueSubmit);
|
||||
SCOP_LOAD_FUNCTION(vkResetCommandBuffer);
|
||||
SCOP_LOAD_FUNCTION(vkResetDescriptorPool);
|
||||
SCOP_LOAD_FUNCTION(vkResetEvent);
|
||||
SCOP_LOAD_FUNCTION(vkResetFences);
|
||||
SCOP_LOAD_FUNCTION(vkUpdateDescriptorSets);
|
||||
SCOP_LOAD_FUNCTION(vkWaitForFences);
|
||||
SCOP_LOAD_FUNCTION(vkCreateSwapchainKHR);
|
||||
SCOP_LOAD_FUNCTION(vkDestroySwapchainKHR);
|
||||
SCOP_LOAD_FUNCTION(vkGetSwapchainImagesKHR);
|
||||
SCOP_LOAD_FUNCTION(vkQueuePresentKHR);
|
||||
kvfPassDeviceVulkanFunctionPointers(m_physical_device, m_device, &pfns);
|
||||
}
|
||||
|
||||
#undef SCOP_LOAD_FUNCTION
|
||||
|
||||
RenderCore::~RenderCore()
|
||||
{
|
||||
if(s_instance == nullptr)
|
||||
return;
|
||||
WaitDeviceIdle();
|
||||
p_descriptor_pool_manager->Destroy();
|
||||
p_descriptor_pool_manager.reset();
|
||||
m_allocator.DetachFromDevice();
|
||||
for(auto shader: m_internal_shaders)
|
||||
shader->Destroy();
|
||||
kvfDestroyDevice(m_device);
|
||||
Message("Vulkan: logical device destroyed");
|
||||
kvfDestroyInstance(m_instance);
|
||||
Message("Vulkan: instance destroyed");
|
||||
loader.reset();
|
||||
|
||||
s_instance = nullptr;
|
||||
}
|
||||
}
|
||||
141
Runtime/Sources/Renderer/RenderPasses/2DPass.cpp
git.filemode.normal_file
141
Runtime/Sources/Renderer/RenderPasses/2DPass.cpp
git.filemode.normal_file
@@ -0,0 +1,141 @@
|
||||
#include <Renderer/RenderPasses/2DPass.h>
|
||||
#include <Renderer/Pipelines/Graphics.h>
|
||||
#include <Renderer/ViewerData.h>
|
||||
#include <Renderer/Renderer.h>
|
||||
#include <Graphics/Scene.h>
|
||||
#include <Core/Engine.h>
|
||||
#include <Maths/Mat4.h>
|
||||
|
||||
namespace Scop
|
||||
{
|
||||
struct SpriteData
|
||||
{
|
||||
Mat4f model_matrix;
|
||||
Vec4f color;
|
||||
};
|
||||
|
||||
struct ViewerData2D
|
||||
{
|
||||
Mat4f projection;
|
||||
};
|
||||
|
||||
void Render2DPass::Init()
|
||||
{
|
||||
ShaderLayout vertex_shader_layout(
|
||||
{
|
||||
{ 0,
|
||||
ShaderSetLayout({
|
||||
{ 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER }
|
||||
})
|
||||
}
|
||||
}, { ShaderPushConstantLayout({ 0, sizeof(SpriteData) }) }
|
||||
);
|
||||
p_vertex_shader = LoadShaderFromFile(ScopEngine::Get().GetAssetsPath() / "Shaders/Build/2DVertex.spv", ShaderType::Vertex, std::move(vertex_shader_layout));
|
||||
ShaderLayout fragment_shader_layout(
|
||||
{
|
||||
{ 1,
|
||||
ShaderSetLayout({
|
||||
{ 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER }
|
||||
})
|
||||
}
|
||||
}, {}
|
||||
);
|
||||
p_fragment_shader = LoadShaderFromFile(ScopEngine::Get().GetAssetsPath() / "Shaders/Build/2DFragment.spv", ShaderType::Fragment, std::move(fragment_shader_layout));
|
||||
|
||||
std::function<void(const EventBase&)> functor = [this](const EventBase& event)
|
||||
{
|
||||
if(event.What() == Event::ResizeEventCode || event.What() == Event::SceneHasChangedEventCode)
|
||||
m_pipeline.Destroy();
|
||||
};
|
||||
EventBus::RegisterListener({ functor, "__ScopRender2DPass" });
|
||||
|
||||
p_viewer_data_set = RenderCore::Get().GetDescriptorPoolManager().GetAvailablePool().RequestDescriptorSet(p_vertex_shader->GetShaderLayout().set_layouts.at(0), ShaderType::Vertex);
|
||||
p_texture_set = RenderCore::Get().GetDescriptorPoolManager().GetAvailablePool().RequestDescriptorSet(p_fragment_shader->GetShaderLayout().set_layouts.at(1), ShaderType::Fragment);
|
||||
|
||||
p_viewer_data_buffer = std::make_shared<UniformBuffer>();
|
||||
p_viewer_data_buffer->Init(sizeof(ViewerData2D));
|
||||
for(std::size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
|
||||
{
|
||||
p_viewer_data_set->SetUniformBuffer(i, 0, p_viewer_data_buffer->Get(i));
|
||||
p_viewer_data_set->Update(i);
|
||||
}
|
||||
}
|
||||
|
||||
void Render2DPass::Pass(Scene& scene, Renderer& renderer, Texture& render_target)
|
||||
{
|
||||
if(m_pipeline.GetPipeline() == VK_NULL_HANDLE)
|
||||
{
|
||||
GraphicPipelineDescriptor pipeline_descriptor;
|
||||
pipeline_descriptor.vertex_shader = p_vertex_shader;
|
||||
pipeline_descriptor.fragment_shader = p_fragment_shader;
|
||||
pipeline_descriptor.color_attachments = { &render_target };
|
||||
pipeline_descriptor.culling = CullMode::None;
|
||||
pipeline_descriptor.clear_color_attachments = false;
|
||||
pipeline_descriptor.name = "2D_pass_pipeline";
|
||||
m_pipeline.Init(std::move(pipeline_descriptor));
|
||||
}
|
||||
|
||||
std::uint32_t frame_index = renderer.GetCurrentFrameIndex();
|
||||
|
||||
ViewerData2D viewer_data;
|
||||
viewer_data.projection = Mat4f::Ortho(0.0f, render_target.GetWidth(), render_target.GetHeight(), 0.0f);
|
||||
static CPUBuffer buffer(sizeof(ViewerData2D));
|
||||
std::memcpy(buffer.GetData(), &viewer_data, buffer.GetSize());
|
||||
p_viewer_data_buffer->SetData(buffer, frame_index);
|
||||
|
||||
VkCommandBuffer cmd = renderer.GetActiveCommandBuffer();
|
||||
m_pipeline.BindPipeline(cmd, 0, {});
|
||||
for(const auto& [_, sprite] : scene.GetSprites())
|
||||
{
|
||||
SpriteData sprite_data;
|
||||
sprite_data.color = sprite.GetColor();
|
||||
|
||||
Mat4f translation_matrix = Mat4f::Identity().ApplyTranslation(Vec3f{ Vec2f(sprite.GetPosition()), 0.0f });
|
||||
Mat4f scale_matrix = Mat4f::Identity().ApplyScale(Vec3f{ sprite.GetScale(), 1.0f });
|
||||
|
||||
sprite_data.model_matrix = Mat4f::Identity();
|
||||
sprite_data.model_matrix.ConcatenateTransform(scale_matrix);
|
||||
sprite_data.model_matrix.ConcatenateTransform(translation_matrix);
|
||||
|
||||
if(!sprite.IsSetInit())
|
||||
const_cast<Sprite&>(sprite).UpdateDescriptorSet(p_texture_set);
|
||||
const_cast<Sprite&>(sprite).Bind(frame_index, cmd);
|
||||
std::array<VkDescriptorSet, 2> sets = { p_viewer_data_set->GetSet(frame_index), sprite.GetSet(frame_index) };
|
||||
RenderCore::Get().vkCmdBindDescriptorSets(cmd, m_pipeline.GetPipelineBindPoint(), m_pipeline.GetPipelineLayout(), 0, sets.size(), sets.data(), 0, nullptr);
|
||||
RenderCore::Get().vkCmdPushConstants(cmd, m_pipeline.GetPipelineLayout(), VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(SpriteData), &sprite_data);
|
||||
sprite.GetMesh()->Draw(cmd, renderer.GetDrawCallsCounterRef(), renderer.GetPolygonDrawnCounterRef());
|
||||
}
|
||||
for(const auto& [_, text] : scene.GetTexts())
|
||||
{
|
||||
SpriteData sprite_data;
|
||||
sprite_data.color = text.GetColor();
|
||||
|
||||
Mat4f translation_matrix = Mat4f::Identity().ApplyTranslation(Vec3f{ Vec2f(text.GetPosition()), 0.0f });
|
||||
Mat4f scale_matrix = Mat4f::Identity().ApplyScale(Vec3f{ text.GetScale(), 1.0f });
|
||||
|
||||
sprite_data.model_matrix = Mat4f::Identity();
|
||||
sprite_data.model_matrix.ConcatenateTransform(scale_matrix);
|
||||
sprite_data.model_matrix.ConcatenateTransform(translation_matrix);
|
||||
|
||||
if(!text.IsSetInit())
|
||||
const_cast<Text&>(text).UpdateDescriptorSet(p_texture_set);
|
||||
const_cast<Text&>(text).Bind(frame_index, cmd);
|
||||
std::array<VkDescriptorSet, 2> sets = { p_viewer_data_set->GetSet(frame_index), text.GetSet(frame_index) };
|
||||
RenderCore::Get().vkCmdBindDescriptorSets(cmd, m_pipeline.GetPipelineBindPoint(), m_pipeline.GetPipelineLayout(), 0, sets.size(), sets.data(), 0, nullptr);
|
||||
RenderCore::Get().vkCmdPushConstants(cmd, m_pipeline.GetPipelineLayout(), VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(SpriteData), &sprite_data);
|
||||
text.GetMesh()->Draw(cmd, renderer.GetDrawCallsCounterRef(), renderer.GetPolygonDrawnCounterRef());
|
||||
}
|
||||
m_pipeline.EndPipeline(cmd);
|
||||
}
|
||||
|
||||
void Render2DPass::Destroy()
|
||||
{
|
||||
RenderCore::Get().WaitDeviceIdle();
|
||||
m_pipeline.Destroy();
|
||||
p_vertex_shader.reset();
|
||||
p_fragment_shader.reset();
|
||||
p_viewer_data_set.reset();
|
||||
p_viewer_data_buffer->Destroy();
|
||||
p_texture_set.reset();
|
||||
}
|
||||
}
|
||||
73
Runtime/Sources/Renderer/RenderPasses/FinalPass.cpp
git.filemode.normal_file
73
Runtime/Sources/Renderer/RenderPasses/FinalPass.cpp
git.filemode.normal_file
@@ -0,0 +1,73 @@
|
||||
#include <Renderer/RenderPasses/FinalPass.h>
|
||||
#include <Renderer/Pipelines/Graphics.h>
|
||||
#include <Renderer/Renderer.h>
|
||||
#include <Graphics/Scene.h>
|
||||
#include <Core/EventBus.h>
|
||||
#include <Core/Engine.h>
|
||||
|
||||
namespace Scop
|
||||
{
|
||||
void FinalPass::Init()
|
||||
{
|
||||
ShaderLayout vertex_shader_layout(
|
||||
{}, {}
|
||||
);
|
||||
p_vertex_shader = LoadShaderFromFile(ScopEngine::Get().GetAssetsPath() / "Shaders/Build/ScreenVertex.spv", ShaderType::Vertex, std::move(vertex_shader_layout));
|
||||
ShaderLayout fragment_shader_layout(
|
||||
{
|
||||
{ 0,
|
||||
ShaderSetLayout({
|
||||
{ 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER }
|
||||
})
|
||||
}
|
||||
}, {}
|
||||
);
|
||||
p_fragment_shader = LoadShaderFromFile(ScopEngine::Get().GetAssetsPath() / "Shaders/Build/ScreenFragment.spv", ShaderType::Fragment, std::move(fragment_shader_layout));
|
||||
|
||||
std::function<void(const EventBase&)> functor = [this](const EventBase& event)
|
||||
{
|
||||
if(event.What() == Event::ResizeEventCode)
|
||||
m_pipeline.Destroy();
|
||||
};
|
||||
EventBus::RegisterListener({ functor, "__ScopFinalPass" });
|
||||
|
||||
p_set = RenderCore::Get().GetDescriptorPoolManager().GetAvailablePool().RequestDescriptorSet(p_fragment_shader->GetShaderLayout().set_layouts.at(0), ShaderType::Fragment);
|
||||
}
|
||||
|
||||
void FinalPass::Pass(Scene& scene, Renderer& renderer, Texture& render_target)
|
||||
{
|
||||
if(m_pipeline.GetPipeline() == VK_NULL_HANDLE)
|
||||
{
|
||||
GraphicPipelineDescriptor pipeline_descriptor;
|
||||
pipeline_descriptor.vertex_shader = p_vertex_shader;
|
||||
pipeline_descriptor.fragment_shader = p_fragment_shader;
|
||||
pipeline_descriptor.renderer = &renderer;
|
||||
pipeline_descriptor.culling = CullMode::None;
|
||||
pipeline_descriptor.no_vertex_inputs = true;
|
||||
pipeline_descriptor.name = "final_pass_pipeline";
|
||||
m_pipeline.Init(std::move(pipeline_descriptor));
|
||||
}
|
||||
|
||||
VkCommandBuffer cmd = renderer.GetActiveCommandBuffer();
|
||||
|
||||
p_set->SetImage(renderer.GetCurrentFrameIndex(), 0, render_target);
|
||||
p_set->Update(renderer.GetCurrentFrameIndex(), cmd);
|
||||
|
||||
m_pipeline.BindPipeline(cmd, renderer.GetSwapchain().GetImageIndex(), { 0.0f, 0.0f, 0.0f, 1.0f });
|
||||
VkDescriptorSet set = p_set->GetSet(renderer.GetCurrentFrameIndex());
|
||||
RenderCore::Get().vkCmdBindDescriptorSets(cmd, m_pipeline.GetPipelineBindPoint(), m_pipeline.GetPipelineLayout(), 0, 1, &set, 0, nullptr);
|
||||
RenderCore::Get().vkCmdDraw(cmd, 3, 1, 0, 0);
|
||||
renderer.GetDrawCallsCounterRef()++;
|
||||
renderer.GetPolygonDrawnCounterRef()++;
|
||||
m_pipeline.EndPipeline(cmd);
|
||||
}
|
||||
|
||||
void FinalPass::Destroy()
|
||||
{
|
||||
RenderCore::Get().WaitDeviceIdle();
|
||||
m_pipeline.Destroy();
|
||||
p_vertex_shader.reset();
|
||||
p_fragment_shader.reset();
|
||||
p_set.reset();
|
||||
}
|
||||
}
|
||||
118
Runtime/Sources/Renderer/RenderPasses/ForwardPass.cpp
git.filemode.normal_file
118
Runtime/Sources/Renderer/RenderPasses/ForwardPass.cpp
git.filemode.normal_file
@@ -0,0 +1,118 @@
|
||||
#include <Renderer/RenderPasses/ForwardPass.h>
|
||||
#include <Renderer/Pipelines/Graphics.h>
|
||||
#include <Renderer/ViewerData.h>
|
||||
#include <Renderer/Renderer.h>
|
||||
#include <Graphics/Scene.h>
|
||||
#include <Maths/Mat4.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace Scop
|
||||
{
|
||||
struct ModelData
|
||||
{
|
||||
Mat4f model_mat;
|
||||
Mat4f normal_mat;
|
||||
};
|
||||
|
||||
void ForwardPass::Pass(Scene& scene, Renderer& renderer, class Texture& render_target)
|
||||
{
|
||||
NonOwningPtr<GraphicPipeline> pipeline = &scene.GetPipeline();
|
||||
if(scene.GetPipeline().GetPipeline() == VK_NULL_HANDLE)
|
||||
{
|
||||
GraphicPipelineDescriptor pipeline_descriptor;
|
||||
pipeline_descriptor.vertex_shader = RenderCore::Get().GetDefaultVertexShader();
|
||||
pipeline_descriptor.fragment_shader = scene.GetFragmentShader();
|
||||
pipeline_descriptor.color_attachments = { &render_target };
|
||||
pipeline_descriptor.depth = &scene.GetDepth();
|
||||
pipeline_descriptor.clear_color_attachments = false;
|
||||
pipeline_descriptor.name = "forward_pass_pipeline";
|
||||
scene.GetPipeline().Init(std::move(pipeline_descriptor));
|
||||
}
|
||||
|
||||
auto render_actor = [&render_target, &renderer, &scene, &pipeline](Actor& actor)
|
||||
{
|
||||
Scene::ForwardData& data = scene.GetForwardData();
|
||||
VkCommandBuffer cmd = renderer.GetActiveCommandBuffer();
|
||||
std::shared_ptr<GraphicPipeline> custom_pipeline = (actor.GetCustomPipeline().has_value() ? actor.GetCustomPipeline()->pipeline : nullptr);
|
||||
|
||||
if(custom_pipeline && !custom_pipeline->IsPipelineBound())
|
||||
{
|
||||
pipeline->EndPipeline(cmd);
|
||||
pipeline = actor.GetCustomPipeline()->pipeline.get();
|
||||
if(pipeline->GetDescription().depth != NonOwningPtr<DepthImage>{ &scene.GetDepth() })
|
||||
{
|
||||
GraphicPipelineDescriptor descriptor = pipeline->GetDescription();
|
||||
descriptor.color_attachments = { &render_target };
|
||||
descriptor.depth = &scene.GetDepth();
|
||||
descriptor.renderer = nullptr;
|
||||
descriptor.clear_color_attachments = false;
|
||||
pipeline->Init(std::move(descriptor));
|
||||
}
|
||||
pipeline->BindPipeline(cmd, 0, {});
|
||||
}
|
||||
else if(!custom_pipeline && !scene.GetPipeline().IsPipelineBound())
|
||||
{
|
||||
pipeline->EndPipeline(cmd);
|
||||
pipeline = &scene.GetPipeline();
|
||||
pipeline->BindPipeline(cmd, 0, {});
|
||||
}
|
||||
|
||||
ModelData model_data;
|
||||
model_data.model_mat = Mat4f::Identity();
|
||||
model_data.model_mat.SetTranslation(actor.GetPosition() - actor.GetModel().GetCenter());
|
||||
model_data.model_mat.SetScale(actor.GetScale());
|
||||
model_data.model_mat = Mat4f::Translate(-actor.GetModel().GetCenter()) * Mat4f::Rotate(actor.GetOrientation()) * model_data.model_mat;
|
||||
model_data.normal_mat = model_data.model_mat;
|
||||
model_data.normal_mat.Inverse().Transpose();
|
||||
|
||||
RenderCore::Get().vkCmdPushConstants(cmd, pipeline->GetPipelineLayout(), VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(ModelData), &model_data);
|
||||
|
||||
if(custom_pipeline)
|
||||
{
|
||||
if(!actor.GetCustomPipeline()->data_uniform_buffer)
|
||||
{
|
||||
actor.GetCustomPipeline()->data_uniform_buffer = std::make_shared<UniformBuffer>();
|
||||
actor.GetCustomPipeline()->data_uniform_buffer->Init(actor.GetCustomPipeline()->data.GetSize(), "custom_data_buffer");
|
||||
}
|
||||
else
|
||||
actor.GetCustomPipeline()->data_uniform_buffer->SetData(actor.GetCustomPipeline()->data, renderer.GetCurrentFrameIndex());
|
||||
if(!actor.GetCustomPipeline()->set)
|
||||
{
|
||||
actor.GetCustomPipeline()->set = RenderCore::Get().GetDescriptorPoolManager().GetAvailablePool().RequestDescriptorSet(custom_pipeline->GetDescription().vertex_shader->GetShaderLayout().set_layouts.at(0), ShaderType::Vertex);
|
||||
for(std::size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
|
||||
{
|
||||
actor.GetCustomPipeline()->set->SetUniformBuffer(i, 0, data.matrices_buffer->Get(i));
|
||||
actor.GetCustomPipeline()->set->SetUniformBuffer(i, 1, actor.GetCustomPipeline()->data_uniform_buffer->Get(i));
|
||||
actor.GetCustomPipeline()->set->Update(i);
|
||||
}
|
||||
}
|
||||
actor.GetModel().Draw(cmd, actor.GetCustomPipeline()->set, *pipeline, data.albedo_set, renderer.GetDrawCallsCounterRef(), renderer.GetPolygonDrawnCounterRef(), renderer.GetCurrentFrameIndex());
|
||||
}
|
||||
else
|
||||
actor.GetModel().Draw(cmd, data.matrices_set, *pipeline, data.albedo_set, renderer.GetDrawCallsCounterRef(), renderer.GetPolygonDrawnCounterRef(), renderer.GetCurrentFrameIndex());
|
||||
};
|
||||
|
||||
std::multimap<float, Actor&> sorted_actors;
|
||||
for(auto& [_, actor] : scene.GetActors())
|
||||
{
|
||||
if(!actor.IsVisible())
|
||||
continue;
|
||||
if(!actor.IsOpaque())
|
||||
{
|
||||
float distance = Vec3f::Distance(actor.GetPosition(), scene.GetCamera()->GetPosition());
|
||||
sorted_actors.emplace(distance, const_cast<Actor&>(actor));
|
||||
}
|
||||
else
|
||||
render_actor(const_cast<Actor&>(actor));
|
||||
}
|
||||
for(auto it = sorted_actors.rbegin(); it != sorted_actors.rend(); ++it)
|
||||
{
|
||||
if(!it->second.IsVisible())
|
||||
continue;
|
||||
render_actor(it->second);
|
||||
}
|
||||
if(pipeline)
|
||||
pipeline->EndPipeline(renderer.GetActiveCommandBuffer());
|
||||
}
|
||||
}
|
||||
62
Runtime/Sources/Renderer/RenderPasses/Passes.cpp
git.filemode.normal_file
62
Runtime/Sources/Renderer/RenderPasses/Passes.cpp
git.filemode.normal_file
@@ -0,0 +1,62 @@
|
||||
#include <Renderer/RenderPasses/Passes.h>
|
||||
#include <Renderer/Renderer.h>
|
||||
#include <Graphics/Scene.h>
|
||||
|
||||
namespace Scop
|
||||
{
|
||||
void RenderPasses::Init()
|
||||
{
|
||||
m_skybox.Init();
|
||||
m_2Dpass.Init();
|
||||
m_post_process.Init();
|
||||
m_final.Init();
|
||||
|
||||
std::function<void(const EventBase&)> functor = [this](const EventBase& event)
|
||||
{
|
||||
if(event.What() == Event::ResizeEventCode)
|
||||
m_main_render_texture.Destroy();
|
||||
};
|
||||
EventBus::RegisterListener({ functor, "__ScopRenderPasses" });
|
||||
}
|
||||
|
||||
void RenderPasses::Pass(Scene& scene, Renderer& renderer)
|
||||
{
|
||||
if(!m_main_render_texture.IsInit())
|
||||
{
|
||||
auto extent = kvfGetSwapchainImagesSize(renderer.GetSwapchain().Get());
|
||||
m_main_render_texture.Init({}, extent.width, extent.height, VK_FORMAT_R8G8B8A8_UNORM, false, "scop_main_render_texture", false);
|
||||
}
|
||||
|
||||
scene.GetDepth().Clear(renderer.GetActiveCommandBuffer(), {});
|
||||
m_main_render_texture.Clear(renderer.GetActiveCommandBuffer(), Vec4f{ 0.0f, 0.0f, 0.0f, 1.0f });
|
||||
m_main_render_texture.TransitionLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, renderer.GetActiveCommandBuffer());
|
||||
|
||||
if(scene.GetDescription().render_3D_enabled)
|
||||
m_forward.Pass(scene, renderer, m_main_render_texture);
|
||||
if(scene.GetDescription().render_skybox_enabled)
|
||||
m_skybox.Pass(scene, renderer, m_main_render_texture);
|
||||
if(scene.GetDescription().render_post_process_enabled && scene.GetDescription().post_process_shader)
|
||||
{
|
||||
m_post_process.Pass(scene, renderer, m_main_render_texture);
|
||||
if(scene.GetDescription().render_2D_enabled)
|
||||
m_2Dpass.Pass(scene, renderer, m_post_process.GetProcessTexture());
|
||||
m_final.Pass(scene, renderer, m_post_process.GetProcessTexture());
|
||||
}
|
||||
else
|
||||
{
|
||||
if(scene.GetDescription().render_2D_enabled)
|
||||
m_2Dpass.Pass(scene, renderer, m_main_render_texture);
|
||||
m_final.Pass(scene, renderer, m_main_render_texture);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderPasses::Destroy()
|
||||
{
|
||||
RenderCore::Get().WaitDeviceIdle();
|
||||
m_skybox.Destroy();
|
||||
m_2Dpass.Destroy();
|
||||
m_post_process.Destroy();
|
||||
m_final.Destroy();
|
||||
m_main_render_texture.Destroy();
|
||||
}
|
||||
}
|
||||
74
Runtime/Sources/Renderer/RenderPasses/PostProcessPass.cpp
git.filemode.normal_file
74
Runtime/Sources/Renderer/RenderPasses/PostProcessPass.cpp
git.filemode.normal_file
@@ -0,0 +1,74 @@
|
||||
#include <Renderer/RenderPasses/PostProcessPass.h>
|
||||
#include <Renderer/Pipelines/Graphics.h>
|
||||
#include <Renderer/Renderer.h>
|
||||
#include <Graphics/Scene.h>
|
||||
#include <Core/EventBus.h>
|
||||
#include <Core/Engine.h>
|
||||
|
||||
namespace Scop
|
||||
{
|
||||
void PostProcessPass::Init()
|
||||
{
|
||||
ShaderLayout vertex_shader_layout(
|
||||
{}, {}
|
||||
);
|
||||
p_vertex_shader = LoadShaderFromFile(ScopEngine::Get().GetAssetsPath() / "Shaders/Build/ScreenVertex.spv", ShaderType::Vertex, std::move(vertex_shader_layout));
|
||||
|
||||
std::function<void(const EventBase&)> functor = [this](const EventBase& event)
|
||||
{
|
||||
if(event.What() == Event::ResizeEventCode)
|
||||
{
|
||||
m_render_texture.Destroy();
|
||||
m_pipeline.Destroy();
|
||||
}
|
||||
};
|
||||
EventBus::RegisterListener({ functor, "__ScopPostProcessPass" });
|
||||
}
|
||||
|
||||
void PostProcessPass::Pass(Scene& scene, Renderer& renderer, Texture& render_target)
|
||||
{
|
||||
Scene::PostProcessData& data = scene.GetPostProcessData();
|
||||
|
||||
if(!m_render_texture.IsInit())
|
||||
{
|
||||
auto extent = kvfGetSwapchainImagesSize(renderer.GetSwapchain().Get());
|
||||
m_render_texture.Init({}, extent.width, extent.height, VK_FORMAT_R8G8B8A8_UNORM, false, "scop_post_process_render_texture", false);
|
||||
}
|
||||
|
||||
if(m_pipeline.GetPipeline() == VK_NULL_HANDLE)
|
||||
{
|
||||
GraphicPipelineDescriptor pipeline_descriptor;
|
||||
pipeline_descriptor.vertex_shader = p_vertex_shader;
|
||||
pipeline_descriptor.fragment_shader = scene.GetDescription().post_process_shader;
|
||||
pipeline_descriptor.color_attachments = { &m_render_texture };
|
||||
pipeline_descriptor.culling = CullMode::None;
|
||||
pipeline_descriptor.clear_color_attachments = false;
|
||||
pipeline_descriptor.no_vertex_inputs = true;
|
||||
pipeline_descriptor.name = "post_process_pass_pipeline";
|
||||
m_pipeline.Init(std::move(pipeline_descriptor));
|
||||
}
|
||||
|
||||
VkCommandBuffer cmd = renderer.GetActiveCommandBuffer();
|
||||
|
||||
data.set->SetImage(renderer.GetCurrentFrameIndex(), 0, render_target);
|
||||
data.set->SetImage(renderer.GetCurrentFrameIndex(), 1, scene.GetDepth());
|
||||
data.set->SetUniformBuffer(renderer.GetCurrentFrameIndex(), 2, data.data_buffer->Get(renderer.GetCurrentFrameIndex()));
|
||||
data.set->Update(renderer.GetCurrentFrameIndex(), cmd);
|
||||
|
||||
m_pipeline.BindPipeline(cmd, 0, {});
|
||||
VkDescriptorSet set = data.set->GetSet(renderer.GetCurrentFrameIndex());
|
||||
RenderCore::Get().vkCmdBindDescriptorSets(cmd, m_pipeline.GetPipelineBindPoint(), m_pipeline.GetPipelineLayout(), 0, 1, &set, 0, nullptr);
|
||||
RenderCore::Get().vkCmdDraw(cmd, 3, 1, 0, 0);
|
||||
renderer.GetDrawCallsCounterRef()++;
|
||||
renderer.GetPolygonDrawnCounterRef()++;
|
||||
m_pipeline.EndPipeline(cmd);
|
||||
}
|
||||
|
||||
void PostProcessPass::Destroy()
|
||||
{
|
||||
RenderCore::Get().WaitDeviceIdle();
|
||||
m_render_texture.Destroy();
|
||||
m_pipeline.Destroy();
|
||||
p_vertex_shader.reset();
|
||||
}
|
||||
}
|
||||
86
Runtime/Sources/Renderer/RenderPasses/SkyboxPass.cpp
git.filemode.normal_file
86
Runtime/Sources/Renderer/RenderPasses/SkyboxPass.cpp
git.filemode.normal_file
@@ -0,0 +1,86 @@
|
||||
#include <Renderer/RenderPasses/SkyboxPass.h>
|
||||
#include <Renderer/Pipelines/Graphics.h>
|
||||
#include <Graphics/MeshFactory.h>
|
||||
#include <Renderer/ViewerData.h>
|
||||
#include <Renderer/Renderer.h>
|
||||
#include <Graphics/Scene.h>
|
||||
#include <Core/EventBus.h>
|
||||
#include <Core/Engine.h>
|
||||
|
||||
namespace Scop
|
||||
{
|
||||
void SkyboxPass::Init()
|
||||
{
|
||||
ShaderLayout vertex_shader_layout(
|
||||
{
|
||||
{ 0,
|
||||
ShaderSetLayout({
|
||||
{ 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER }
|
||||
})
|
||||
}
|
||||
}, {}
|
||||
);
|
||||
p_vertex_shader = LoadShaderFromFile(ScopEngine::Get().GetAssetsPath() / "Shaders/Build/SkyboxVertex.spv", ShaderType::Vertex, std::move(vertex_shader_layout));
|
||||
ShaderLayout fragment_shader_layout(
|
||||
{
|
||||
{ 1,
|
||||
ShaderSetLayout({
|
||||
{ 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER }
|
||||
})
|
||||
}
|
||||
}, {}
|
||||
);
|
||||
p_fragment_shader = LoadShaderFromFile(ScopEngine::Get().GetAssetsPath() / "Shaders/Build/SkyboxFragment.spv", ShaderType::Fragment, std::move(fragment_shader_layout));
|
||||
|
||||
std::function<void(const EventBase&)> functor = [this](const EventBase& event)
|
||||
{
|
||||
if(event.What() == Event::ResizeEventCode || event.What() == Event::SceneHasChangedEventCode)
|
||||
m_pipeline.Destroy();
|
||||
};
|
||||
EventBus::RegisterListener({ functor, "__ScopSkyboxPass" });
|
||||
|
||||
m_cube = CreateCube();
|
||||
p_set = RenderCore::Get().GetDescriptorPoolManager().GetAvailablePool().RequestDescriptorSet(p_fragment_shader->GetShaderLayout().set_layouts.at(1), ShaderType::Fragment);
|
||||
}
|
||||
|
||||
void SkyboxPass::Pass(Scene& scene, Renderer& renderer, class Texture& render_target)
|
||||
{
|
||||
if(!scene.GetSkybox())
|
||||
return;
|
||||
|
||||
if(m_pipeline.GetPipeline() == VK_NULL_HANDLE)
|
||||
{
|
||||
GraphicPipelineDescriptor pipeline_descriptor;
|
||||
pipeline_descriptor.vertex_shader = p_vertex_shader;
|
||||
pipeline_descriptor.fragment_shader = p_fragment_shader;
|
||||
pipeline_descriptor.color_attachments = { &render_target };
|
||||
pipeline_descriptor.depth = &scene.GetDepth();
|
||||
pipeline_descriptor.culling = CullMode::None;
|
||||
pipeline_descriptor.depth_test_equal = true;
|
||||
pipeline_descriptor.clear_color_attachments = false;
|
||||
pipeline_descriptor.name = "skybox_pass_pipeline";
|
||||
m_pipeline.Init(std::move(pipeline_descriptor));
|
||||
}
|
||||
|
||||
VkCommandBuffer cmd = renderer.GetActiveCommandBuffer();
|
||||
|
||||
p_set->SetImage(renderer.GetCurrentFrameIndex(), 0, *scene.GetSkybox());
|
||||
p_set->Update(renderer.GetCurrentFrameIndex(), cmd);
|
||||
|
||||
m_pipeline.BindPipeline(cmd, 0, {});
|
||||
std::array<VkDescriptorSet, 2> sets = { scene.GetForwardData().matrices_set->GetSet(renderer.GetCurrentFrameIndex()), p_set->GetSet(renderer.GetCurrentFrameIndex()) };
|
||||
RenderCore::Get().vkCmdBindDescriptorSets(cmd, m_pipeline.GetPipelineBindPoint(), m_pipeline.GetPipelineLayout(), 0, sets.size(), sets.data(), 0, nullptr);
|
||||
m_cube->Draw(cmd, renderer.GetDrawCallsCounterRef(), renderer.GetPolygonDrawnCounterRef());
|
||||
m_pipeline.EndPipeline(cmd);
|
||||
}
|
||||
|
||||
void SkyboxPass::Destroy()
|
||||
{
|
||||
RenderCore::Get().WaitDeviceIdle();
|
||||
m_pipeline.Destroy();
|
||||
p_vertex_shader.reset();
|
||||
p_fragment_shader.reset();
|
||||
m_cube.reset();
|
||||
p_set.reset();
|
||||
}
|
||||
}
|
||||
96
Runtime/Sources/Renderer/Renderer.cpp
git.filemode.normal_file
96
Runtime/Sources/Renderer/Renderer.cpp
git.filemode.normal_file
@@ -0,0 +1,96 @@
|
||||
#include <Renderer/Renderer.h>
|
||||
#include <Core/Logs.h>
|
||||
#include <Core/Enums.h>
|
||||
#include <Core/Engine.h>
|
||||
#include <Core/EventBus.h>
|
||||
|
||||
namespace Scop
|
||||
{
|
||||
namespace Internal
|
||||
{
|
||||
struct FrameBeginEventBroadcast : public EventBase
|
||||
{
|
||||
Event What() const override { return Event::FrameBeginEventCode; }
|
||||
};
|
||||
}
|
||||
|
||||
void Renderer::Init(NonOwningPtr<Window> window)
|
||||
{
|
||||
std::function<void(const EventBase&)> functor = [this](const EventBase& event)
|
||||
{
|
||||
if(event.What() == Event::ResizeEventCode)
|
||||
{
|
||||
for(std::size_t i = 0; i < m_render_finished_semaphores.size(); i++)
|
||||
{
|
||||
kvfDestroySemaphore(RenderCore::Get().GetDevice(), m_render_finished_semaphores[i]);
|
||||
Message("Vulkan: render finished semaphore destroyed");
|
||||
}
|
||||
m_render_finished_semaphores.clear();
|
||||
for(std::size_t i = 0; i < m_swapchain.GetImagesCount(); i++)
|
||||
{
|
||||
m_render_finished_semaphores.push_back(kvfCreateSemaphore(RenderCore::Get().GetDevice()));
|
||||
Message("Vulkan: render finished semaphore created");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
EventBus::RegisterListener({ functor, "__ScopRenderer" });
|
||||
p_window = window;
|
||||
m_swapchain.Init(p_window);
|
||||
for(std::size_t i = 0; i < m_swapchain.GetImagesCount(); i++)
|
||||
{
|
||||
m_render_finished_semaphores.push_back(kvfCreateSemaphore(RenderCore::Get().GetDevice()));
|
||||
Message("Vulkan: render finished semaphore created");
|
||||
}
|
||||
for(std::size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
|
||||
{
|
||||
m_cmd_buffers[i] = kvfCreateCommandBuffer(RenderCore::Get().GetDevice());
|
||||
Message("Vulkan: command buffer created");
|
||||
m_cmd_fences[i] = kvfCreateFence(RenderCore::Get().GetDevice());
|
||||
Message("Vulkan: fence created");
|
||||
m_image_available_semaphores[i] = kvfCreateSemaphore(RenderCore::Get().GetDevice());
|
||||
Message("Vulkan: image available semaphore created");
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::BeginFrame()
|
||||
{
|
||||
kvfWaitForFence(RenderCore::Get().GetDevice(), m_cmd_fences[m_current_frame_index]);
|
||||
m_swapchain.AquireFrame(m_image_available_semaphores[m_current_frame_index]);
|
||||
RenderCore::Get().vkResetCommandBuffer(m_cmd_buffers[m_current_frame_index], 0);
|
||||
kvfBeginCommandBuffer(m_cmd_buffers[m_current_frame_index], 0);
|
||||
m_drawcalls = 0;
|
||||
m_polygons_drawn = 0;
|
||||
EventBus::SendBroadcast(Internal::FrameBeginEventBroadcast{});
|
||||
}
|
||||
|
||||
void Renderer::EndFrame()
|
||||
{
|
||||
VkPipelineStageFlags wait_stages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
|
||||
kvfEndCommandBuffer(m_cmd_buffers[m_current_frame_index]);
|
||||
kvfSubmitCommandBuffer(RenderCore::Get().GetDevice(), m_cmd_buffers[m_current_frame_index], KVF_GRAPHICS_QUEUE, m_render_finished_semaphores[m_swapchain.GetImageIndex()], m_image_available_semaphores[m_current_frame_index], m_cmd_fences[m_current_frame_index], wait_stages);
|
||||
m_swapchain.Present(m_render_finished_semaphores[m_swapchain.GetImageIndex()]);
|
||||
m_current_frame_index = (m_current_frame_index + 1) % MAX_FRAMES_IN_FLIGHT;
|
||||
}
|
||||
|
||||
void Renderer::Destroy() noexcept
|
||||
{
|
||||
RenderCore::Get().WaitDeviceIdle();
|
||||
for(std::size_t i = 0; i < m_render_finished_semaphores.size(); i++)
|
||||
{
|
||||
kvfDestroySemaphore(RenderCore::Get().GetDevice(), m_render_finished_semaphores[i]);
|
||||
Message("Vulkan: render finished semaphore destroyed");
|
||||
}
|
||||
m_render_finished_semaphores.clear();
|
||||
for(std::size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
|
||||
{
|
||||
kvfDestroySemaphore(RenderCore::Get().GetDevice(), m_image_available_semaphores[i]);
|
||||
Message("Vulkan: image available semaphore destroyed");
|
||||
kvfDestroyCommandBuffer(RenderCore::Get().GetDevice(), m_cmd_buffers[i]);
|
||||
Message("Vulkan: command buffer destroyed");
|
||||
kvfDestroyFence(RenderCore::Get().GetDevice(), m_cmd_fences[i]);
|
||||
Message("Vulkan: fence destroyed");
|
||||
}
|
||||
m_swapchain.Destroy();
|
||||
}
|
||||
}
|
||||
43
Runtime/Sources/Renderer/SceneRenderer.cpp
git.filemode.normal_file
43
Runtime/Sources/Renderer/SceneRenderer.cpp
git.filemode.normal_file
@@ -0,0 +1,43 @@
|
||||
#include <Renderer/ScenesRenderer.h>
|
||||
#include <Renderer/Renderer.h>
|
||||
#include <Graphics/Scene.h>
|
||||
#include <Renderer/ViewerData.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace Scop
|
||||
{
|
||||
void SceneRenderer::Init()
|
||||
{
|
||||
m_passes.Init();
|
||||
}
|
||||
|
||||
void SceneRenderer::Render(Scene& scene, Renderer& renderer)
|
||||
{
|
||||
if(scene.GetCamera())
|
||||
{
|
||||
ViewerData data;
|
||||
data.projection_matrix = scene.GetCamera()->GetProj();
|
||||
data.projection_matrix.GetInverse(&data.inv_projection_matrix);
|
||||
data.view_matrix = scene.GetCamera()->GetView();
|
||||
data.view_matrix.GetInverse(&data.inv_view_matrix);
|
||||
data.view_proj_matrix = data.view_matrix * data.projection_matrix;
|
||||
data.view_proj_matrix.GetInverse(&data.inv_view_proj_matrix);
|
||||
data.camera_position = scene.GetCamera()->GetPosition();
|
||||
|
||||
static CPUBuffer buffer(sizeof(ViewerData));
|
||||
std::memcpy(buffer.GetData(), &data, buffer.GetSize());
|
||||
scene.GetForwardData().matrices_buffer->SetData(buffer, renderer.GetCurrentFrameIndex());
|
||||
}
|
||||
if(scene.GetDescription().render_post_process_enabled && scene.GetDescription().post_process_shader)
|
||||
scene.GetPostProcessData().data_buffer->SetData(scene.GetPostProcessData().data, renderer.GetCurrentFrameIndex());
|
||||
|
||||
m_passes.Pass(scene, renderer);
|
||||
}
|
||||
|
||||
void SceneRenderer::Destroy()
|
||||
{
|
||||
RenderCore::Get().WaitDeviceIdle();
|
||||
m_passes.Destroy();
|
||||
}
|
||||
}
|
||||
254
Runtime/Sources/Renderer/Swapchain.cpp
git.filemode.normal_file
254
Runtime/Sources/Renderer/Swapchain.cpp
git.filemode.normal_file
@@ -0,0 +1,254 @@
|
||||
#include <Platform/Window.h>
|
||||
#include <Renderer/Swapchain.h>
|
||||
#include <Renderer/RenderCore.h>
|
||||
#include <Core/Logs.h>
|
||||
#include <Core/EventBus.h>
|
||||
#include <Maths/Vec2.h>
|
||||
|
||||
namespace Scop
|
||||
{
|
||||
namespace Internal
|
||||
{
|
||||
struct ResizeEventBroadcast : public EventBase
|
||||
{
|
||||
Event What() const override { return Event::ResizeEventCode; }
|
||||
};
|
||||
}
|
||||
|
||||
std::string VulkanFormatName(VkFormat format)
|
||||
{
|
||||
#define STRINGIFY(x) case x: return #x
|
||||
|
||||
switch(format)
|
||||
{
|
||||
STRINGIFY(VK_FORMAT_UNDEFINED);
|
||||
STRINGIFY(VK_FORMAT_R4G4_UNORM_PACK8);
|
||||
STRINGIFY(VK_FORMAT_R4G4B4A4_UNORM_PACK16);
|
||||
STRINGIFY(VK_FORMAT_B4G4R4A4_UNORM_PACK16);
|
||||
STRINGIFY(VK_FORMAT_R5G6B5_UNORM_PACK16);
|
||||
STRINGIFY(VK_FORMAT_B5G6R5_UNORM_PACK16);
|
||||
STRINGIFY(VK_FORMAT_R5G5B5A1_UNORM_PACK16);
|
||||
STRINGIFY(VK_FORMAT_B5G5R5A1_UNORM_PACK16);
|
||||
STRINGIFY(VK_FORMAT_A1R5G5B5_UNORM_PACK16);
|
||||
STRINGIFY(VK_FORMAT_R8_UNORM);
|
||||
STRINGIFY(VK_FORMAT_R8_SNORM);
|
||||
STRINGIFY(VK_FORMAT_R8_USCALED);
|
||||
STRINGIFY(VK_FORMAT_R8_SSCALED);
|
||||
STRINGIFY(VK_FORMAT_R8_UINT);
|
||||
STRINGIFY(VK_FORMAT_R8_SINT);
|
||||
STRINGIFY(VK_FORMAT_R8_SRGB);
|
||||
STRINGIFY(VK_FORMAT_R8G8_UNORM);
|
||||
STRINGIFY(VK_FORMAT_R8G8_SNORM);
|
||||
STRINGIFY(VK_FORMAT_R8G8_USCALED);
|
||||
STRINGIFY(VK_FORMAT_R8G8_SSCALED);
|
||||
STRINGIFY(VK_FORMAT_R8G8_UINT);
|
||||
STRINGIFY(VK_FORMAT_R8G8_SINT);
|
||||
STRINGIFY(VK_FORMAT_R8G8_SRGB);
|
||||
STRINGIFY(VK_FORMAT_R8G8B8_UNORM);
|
||||
STRINGIFY(VK_FORMAT_R8G8B8_SNORM);
|
||||
STRINGIFY(VK_FORMAT_R8G8B8_USCALED);
|
||||
STRINGIFY(VK_FORMAT_R8G8B8_SSCALED);
|
||||
STRINGIFY(VK_FORMAT_R8G8B8_UINT);
|
||||
STRINGIFY(VK_FORMAT_R8G8B8_SINT);
|
||||
STRINGIFY(VK_FORMAT_R8G8B8_SRGB);
|
||||
STRINGIFY(VK_FORMAT_B8G8R8_UNORM);
|
||||
STRINGIFY(VK_FORMAT_B8G8R8_SNORM);
|
||||
STRINGIFY(VK_FORMAT_B8G8R8_USCALED);
|
||||
STRINGIFY(VK_FORMAT_B8G8R8_SSCALED);
|
||||
STRINGIFY(VK_FORMAT_B8G8R8_UINT);
|
||||
STRINGIFY(VK_FORMAT_B8G8R8_SINT);
|
||||
STRINGIFY(VK_FORMAT_B8G8R8_SRGB);
|
||||
STRINGIFY(VK_FORMAT_R8G8B8A8_UNORM);
|
||||
STRINGIFY(VK_FORMAT_R8G8B8A8_SNORM);
|
||||
STRINGIFY(VK_FORMAT_R8G8B8A8_USCALED);
|
||||
STRINGIFY(VK_FORMAT_R8G8B8A8_SSCALED);
|
||||
STRINGIFY(VK_FORMAT_R8G8B8A8_UINT);
|
||||
STRINGIFY(VK_FORMAT_R8G8B8A8_SINT);
|
||||
STRINGIFY(VK_FORMAT_R8G8B8A8_SRGB);
|
||||
STRINGIFY(VK_FORMAT_B8G8R8A8_UNORM);
|
||||
STRINGIFY(VK_FORMAT_B8G8R8A8_SNORM);
|
||||
STRINGIFY(VK_FORMAT_B8G8R8A8_USCALED);
|
||||
STRINGIFY(VK_FORMAT_B8G8R8A8_SSCALED);
|
||||
STRINGIFY(VK_FORMAT_B8G8R8A8_UINT);
|
||||
STRINGIFY(VK_FORMAT_B8G8R8A8_SINT);
|
||||
STRINGIFY(VK_FORMAT_B8G8R8A8_SRGB);
|
||||
STRINGIFY(VK_FORMAT_A8B8G8R8_UNORM_PACK32);
|
||||
STRINGIFY(VK_FORMAT_A8B8G8R8_SNORM_PACK32);
|
||||
STRINGIFY(VK_FORMAT_A8B8G8R8_USCALED_PACK32);
|
||||
STRINGIFY(VK_FORMAT_A8B8G8R8_SSCALED_PACK32);
|
||||
STRINGIFY(VK_FORMAT_A8B8G8R8_UINT_PACK32);
|
||||
STRINGIFY(VK_FORMAT_A8B8G8R8_SINT_PACK32);
|
||||
STRINGIFY(VK_FORMAT_A8B8G8R8_SRGB_PACK32);
|
||||
STRINGIFY(VK_FORMAT_A2R10G10B10_UNORM_PACK32);
|
||||
STRINGIFY(VK_FORMAT_A2R10G10B10_SNORM_PACK32);
|
||||
STRINGIFY(VK_FORMAT_A2R10G10B10_USCALED_PACK32);
|
||||
STRINGIFY(VK_FORMAT_A2R10G10B10_SSCALED_PACK32);
|
||||
STRINGIFY(VK_FORMAT_A2R10G10B10_UINT_PACK32);
|
||||
STRINGIFY(VK_FORMAT_A2R10G10B10_SINT_PACK32);
|
||||
STRINGIFY(VK_FORMAT_A2B10G10R10_UNORM_PACK32);
|
||||
STRINGIFY(VK_FORMAT_A2B10G10R10_SNORM_PACK32);
|
||||
STRINGIFY(VK_FORMAT_A2B10G10R10_USCALED_PACK32);
|
||||
STRINGIFY(VK_FORMAT_A2B10G10R10_SSCALED_PACK32);
|
||||
STRINGIFY(VK_FORMAT_A2B10G10R10_UINT_PACK32);
|
||||
STRINGIFY(VK_FORMAT_A2B10G10R10_SINT_PACK32);
|
||||
STRINGIFY(VK_FORMAT_R16_UNORM);
|
||||
STRINGIFY(VK_FORMAT_R16_SNORM);
|
||||
STRINGIFY(VK_FORMAT_R16_USCALED);
|
||||
STRINGIFY(VK_FORMAT_R16_SSCALED);
|
||||
STRINGIFY(VK_FORMAT_R16_UINT);
|
||||
STRINGIFY(VK_FORMAT_R16_SINT);
|
||||
STRINGIFY(VK_FORMAT_R16_SFLOAT);
|
||||
STRINGIFY(VK_FORMAT_R16G16_UNORM);
|
||||
STRINGIFY(VK_FORMAT_R16G16_SNORM);
|
||||
STRINGIFY(VK_FORMAT_R16G16_USCALED);
|
||||
STRINGIFY(VK_FORMAT_R16G16_SSCALED);
|
||||
STRINGIFY(VK_FORMAT_R16G16_UINT);
|
||||
STRINGIFY(VK_FORMAT_R16G16_SINT);
|
||||
STRINGIFY(VK_FORMAT_R16G16_SFLOAT);
|
||||
STRINGIFY(VK_FORMAT_R16G16B16_UNORM);
|
||||
STRINGIFY(VK_FORMAT_R16G16B16_SNORM);
|
||||
STRINGIFY(VK_FORMAT_R16G16B16_USCALED);
|
||||
STRINGIFY(VK_FORMAT_R16G16B16_SSCALED);
|
||||
STRINGIFY(VK_FORMAT_R16G16B16_UINT);
|
||||
STRINGIFY(VK_FORMAT_R16G16B16_SINT);
|
||||
STRINGIFY(VK_FORMAT_R16G16B16_SFLOAT);
|
||||
STRINGIFY(VK_FORMAT_R16G16B16A16_UNORM);
|
||||
STRINGIFY(VK_FORMAT_R16G16B16A16_SNORM);
|
||||
STRINGIFY(VK_FORMAT_R16G16B16A16_USCALED);
|
||||
STRINGIFY(VK_FORMAT_R16G16B16A16_SSCALED);
|
||||
STRINGIFY(VK_FORMAT_R16G16B16A16_UINT);
|
||||
STRINGIFY(VK_FORMAT_R16G16B16A16_SINT);
|
||||
STRINGIFY(VK_FORMAT_R16G16B16A16_SFLOAT);
|
||||
STRINGIFY(VK_FORMAT_R32_UINT);
|
||||
STRINGIFY(VK_FORMAT_R32_SINT);
|
||||
STRINGIFY(VK_FORMAT_R32_SFLOAT);
|
||||
STRINGIFY(VK_FORMAT_R32G32_UINT);
|
||||
STRINGIFY(VK_FORMAT_R32G32_SINT);
|
||||
STRINGIFY(VK_FORMAT_R32G32_SFLOAT);
|
||||
STRINGIFY(VK_FORMAT_R32G32B32_UINT);
|
||||
STRINGIFY(VK_FORMAT_R32G32B32_SINT);
|
||||
STRINGIFY(VK_FORMAT_R32G32B32_SFLOAT);
|
||||
STRINGIFY(VK_FORMAT_R32G32B32A32_UINT);
|
||||
STRINGIFY(VK_FORMAT_R32G32B32A32_SINT);
|
||||
STRINGIFY(VK_FORMAT_R32G32B32A32_SFLOAT);
|
||||
STRINGIFY(VK_FORMAT_R64_UINT);
|
||||
STRINGIFY(VK_FORMAT_R64_SINT);
|
||||
STRINGIFY(VK_FORMAT_R64_SFLOAT);
|
||||
STRINGIFY(VK_FORMAT_R64G64_UINT);
|
||||
STRINGIFY(VK_FORMAT_R64G64_SINT);
|
||||
STRINGIFY(VK_FORMAT_R64G64_SFLOAT);
|
||||
STRINGIFY(VK_FORMAT_R64G64B64_UINT);
|
||||
STRINGIFY(VK_FORMAT_R64G64B64_SINT);
|
||||
STRINGIFY(VK_FORMAT_R64G64B64_SFLOAT);
|
||||
STRINGIFY(VK_FORMAT_R64G64B64A64_UINT);
|
||||
STRINGIFY(VK_FORMAT_R64G64B64A64_SINT);
|
||||
STRINGIFY(VK_FORMAT_R64G64B64A64_SFLOAT);
|
||||
STRINGIFY(VK_FORMAT_B10G11R11_UFLOAT_PACK32);
|
||||
STRINGIFY(VK_FORMAT_E5B9G9R9_UFLOAT_PACK32);
|
||||
|
||||
default: return "Unknown format";
|
||||
}
|
||||
|
||||
#undef STRINGIFY
|
||||
|
||||
return "Unknown format"; // To avoid warnings
|
||||
}
|
||||
|
||||
void Swapchain::Init(NonOwningPtr<Window> window)
|
||||
{
|
||||
p_window = window;
|
||||
|
||||
std::function<void(const EventBase&)> functor = [this](const EventBase& event)
|
||||
{
|
||||
if(event.What() == Event::ResizeEventCode && !m_resize)
|
||||
m_resize = true;
|
||||
};
|
||||
EventBus::RegisterListener({ functor, "__ScopSwapchain" });
|
||||
|
||||
CreateSwapchain();
|
||||
m_resize = false;
|
||||
}
|
||||
|
||||
void Swapchain::AquireFrame(VkSemaphore signal)
|
||||
{
|
||||
if(m_resize)
|
||||
{
|
||||
RenderCore::Get().WaitDeviceIdle();
|
||||
Destroy();
|
||||
CreateSwapchain();
|
||||
EventBus::SendBroadcast(Internal::ResizeEventBroadcast{});
|
||||
m_resize = false;
|
||||
}
|
||||
|
||||
VkResult result = RenderCore::Get().vkAcquireNextImageKHR(RenderCore::Get().GetDevice(), m_swapchain, UINT64_MAX, signal, VK_NULL_HANDLE, &m_current_image_index);
|
||||
if(result == VK_SUBOPTIMAL_KHR)
|
||||
m_resize = true; // Recreate Swapchain next time
|
||||
else if(result == VK_ERROR_OUT_OF_DATE_KHR)
|
||||
{
|
||||
m_resize = true;
|
||||
AquireFrame(signal);
|
||||
}
|
||||
else if(result != VK_SUCCESS)
|
||||
FatalError("Vulkan: failed to acquire swapchain image, %", kvfVerbaliseVkResult(result));
|
||||
}
|
||||
|
||||
void Swapchain::Present(VkSemaphore wait) noexcept
|
||||
{
|
||||
if(!kvfQueuePresentKHR(RenderCore::Get().GetDevice(), wait, m_swapchain, m_current_image_index))
|
||||
m_resize = true;
|
||||
}
|
||||
|
||||
void Swapchain::Destroy()
|
||||
{
|
||||
if(m_swapchain == VK_NULL_HANDLE)
|
||||
return;
|
||||
RenderCore::Get().WaitDeviceIdle();
|
||||
|
||||
for(Image& img : m_swapchain_images)
|
||||
img.DestroyImageView();
|
||||
m_swapchain_images.clear();
|
||||
kvfDestroySwapchainKHR(RenderCore::Get().GetDevice(), m_swapchain);
|
||||
m_swapchain = VK_NULL_HANDLE;
|
||||
Message("Vulkan: swapchain destroyed");
|
||||
|
||||
RenderCore::Get().vkDestroySurfaceKHR(RenderCore::Get().GetInstance(), m_surface, nullptr);
|
||||
m_surface = VK_NULL_HANDLE;
|
||||
Message("Vulkan: surface destroyed");
|
||||
}
|
||||
|
||||
void Swapchain::CreateSwapchain()
|
||||
{
|
||||
VkExtent2D extent;
|
||||
do
|
||||
{
|
||||
Vec2ui size = p_window->GetVulkanDrawableSize();
|
||||
extent = { size.x, size.y };
|
||||
} while(extent.width == 0 || extent.height == 0);
|
||||
|
||||
m_surface = p_window->CreateVulkanSurface(RenderCore::Get().GetInstance());
|
||||
Message("Vulkan: surface created");
|
||||
m_swapchain = kvfCreateSwapchainKHR(RenderCore::Get().GetDevice(), RenderCore::Get().GetPhysicalDevice(), m_surface, extent, VK_NULL_HANDLE, false, true);
|
||||
|
||||
m_images_count = kvfGetSwapchainImagesCount(m_swapchain);
|
||||
m_min_images_count = kvfGetSwapchainMinImagesCount(m_swapchain);
|
||||
std::vector<VkImage> tmp(m_images_count);
|
||||
m_swapchain_images.resize(m_images_count);
|
||||
RenderCore::Get().vkGetSwapchainImagesKHR(RenderCore::Get().GetDevice(), m_swapchain, &m_images_count, tmp.data());
|
||||
VkCommandBuffer cmd = kvfCreateCommandBuffer(RenderCore::Get().GetDevice());
|
||||
kvfBeginCommandBuffer(cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
|
||||
extent = kvfGetSwapchainImagesSize(m_swapchain); // fix the extent
|
||||
VkFormat format = kvfGetSwapchainImagesFormat(m_swapchain);
|
||||
for(std::size_t i = 0; i < m_images_count; i++)
|
||||
{
|
||||
m_swapchain_images[i].Init(tmp[i], format, extent.width, extent.height, VK_IMAGE_LAYOUT_UNDEFINED, std::string{ "swapchain_" + std::to_string(i) });
|
||||
m_swapchain_images[i].TransitionLayout(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, cmd);
|
||||
m_swapchain_images[i].CreateImageView(VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
}
|
||||
kvfEndCommandBuffer(cmd);
|
||||
VkFence fence = kvfCreateFence(RenderCore::Get().GetDevice());
|
||||
kvfSubmitSingleTimeCommandBuffer(RenderCore::Get().GetDevice(), cmd, KVF_GRAPHICS_QUEUE, fence);
|
||||
kvfDestroyFence(RenderCore::Get().GetDevice(), fence);
|
||||
kvfDestroyCommandBuffer(RenderCore::Get().GetDevice(), cmd);
|
||||
Message("Vulkan: swapchain created with format %", VulkanFormatName(format));
|
||||
}
|
||||
}
|
||||
119
Runtime/Sources/Renderer/Vulkan/VulkanLoader.cpp
git.filemode.normal_file
119
Runtime/Sources/Renderer/Vulkan/VulkanLoader.cpp
git.filemode.normal_file
@@ -0,0 +1,119 @@
|
||||
#include <Renderer/Vulkan/VulkanLoader.h>
|
||||
#include <Renderer/RenderCore.h>
|
||||
#include <Core/Logs.h>
|
||||
|
||||
#include <array>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define DISABLE_GCC_PEDANTIC_WARNINGS \
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wpedantic\"")
|
||||
#define RESTORE_GCC_PEDANTIC_WARNINGS \
|
||||
_Pragma("GCC diagnostic pop")
|
||||
#else
|
||||
#define DISABLE_GCC_PEDANTIC_WARNINGS
|
||||
#define RESTORE_GCC_PEDANTIC_WARNINGS
|
||||
#endif
|
||||
|
||||
namespace Scop
|
||||
{
|
||||
namespace Internal
|
||||
{
|
||||
static inline PFN_vkVoidFunction vkGetInstanceProcAddrStub(void* context, const char* name)
|
||||
{
|
||||
PFN_vkVoidFunction function = RenderCore::Get().vkGetInstanceProcAddr(static_cast<VkInstance>(context), name);
|
||||
if(!function)
|
||||
FatalError("Vulkan Loader: could not load '%'", name);
|
||||
//Message("Vulkan Loader: loaded %", name);
|
||||
return function;
|
||||
}
|
||||
|
||||
static inline PFN_vkVoidFunction vkGetDeviceProcAddrStub(void* context, const char* name)
|
||||
{
|
||||
PFN_vkVoidFunction function = RenderCore::Get().vkGetDeviceProcAddr(static_cast<VkDevice>(context), name);
|
||||
if(!function)
|
||||
FatalError("Vulkan Loader: could not load '%'", name);
|
||||
//Message("Vulkan Loader: loaded %", name);
|
||||
return function;
|
||||
}
|
||||
|
||||
static inline void* LoadLib(const char* libname)
|
||||
{
|
||||
return dlopen(libname, RTLD_NOW | RTLD_LOCAL);
|
||||
}
|
||||
|
||||
static inline void* GetSymbol(void* module, const char* name)
|
||||
{
|
||||
return dlsym(module, name);
|
||||
}
|
||||
}
|
||||
|
||||
VulkanLoader::VulkanLoader()
|
||||
{
|
||||
std::array libnames{
|
||||
"libvulkan.so.1",
|
||||
"libvulkan.so"
|
||||
};
|
||||
|
||||
for(auto libname : libnames)
|
||||
{
|
||||
p_module = Internal::LoadLib(libname);
|
||||
if(p_module != nullptr)
|
||||
{
|
||||
DISABLE_GCC_PEDANTIC_WARNINGS;
|
||||
RenderCore::Get().vkGetInstanceProcAddr = reinterpret_cast<PFN_vkGetInstanceProcAddr>(Internal::GetSymbol(p_module, "vkGetInstanceProcAddr"));
|
||||
RESTORE_GCC_PEDANTIC_WARNINGS;
|
||||
if(RenderCore::Get().vkGetInstanceProcAddr)
|
||||
{
|
||||
Message("Vulkan Loader: libvulkan loaded using '%'", libname);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!p_module || !RenderCore::Get().vkGetInstanceProcAddr)
|
||||
FatalError("Vulkan Loader: failed to load libvulkan");
|
||||
LoadGlobalFunctions(nullptr, Internal::vkGetInstanceProcAddrStub);
|
||||
}
|
||||
|
||||
void VulkanLoader::LoadInstance(VkInstance instance)
|
||||
{
|
||||
LoadInstanceFunctions(instance, Internal::vkGetInstanceProcAddrStub);
|
||||
}
|
||||
|
||||
void VulkanLoader::LoadDevice(VkDevice device)
|
||||
{
|
||||
LoadDeviceFunctions(device, Internal::vkGetDeviceProcAddrStub);
|
||||
}
|
||||
|
||||
void VulkanLoader::LoadGlobalFunctions(void* context, PFN_vkVoidFunction (*load)(void*, const char*)) noexcept
|
||||
{
|
||||
#define SCOP_VULKAN_GLOBAL_FUNCTION(fn) RenderCore::Get().fn = reinterpret_cast<PFN_##fn>(load(context, #fn));
|
||||
#include <Renderer/Vulkan/VulkanDefs.h>
|
||||
#undef SCOP_VULKAN_GLOBAL_FUNCTION
|
||||
Message("Vulkan Loader: global functions loaded");
|
||||
}
|
||||
|
||||
void VulkanLoader::LoadInstanceFunctions(void* context, PFN_vkVoidFunction (*load)(void*, const char*)) noexcept
|
||||
{
|
||||
#define SCOP_VULKAN_INSTANCE_FUNCTION(fn) RenderCore::Get().fn = reinterpret_cast<PFN_##fn>(load(context, #fn));
|
||||
#include <Renderer/Vulkan/VulkanDefs.h>
|
||||
#undef SCOP_VULKAN_INSTANCE_FUNCTION
|
||||
Message("Vulkan Loader: instance functions loaded");
|
||||
}
|
||||
|
||||
void VulkanLoader::LoadDeviceFunctions(void* context, PFN_vkVoidFunction (*load)(void*, const char*)) noexcept
|
||||
{
|
||||
#define SCOP_VULKAN_DEVICE_FUNCTION(fn) RenderCore::Get().fn = reinterpret_cast<PFN_##fn>(load(context, #fn));
|
||||
#include <Renderer/Vulkan/VulkanDefs.h>
|
||||
#undef SCOP_VULKAN_DEVICE_FUNCTION
|
||||
Message("Vulkan Loader: device functions loaded");
|
||||
}
|
||||
|
||||
VulkanLoader::~VulkanLoader()
|
||||
{
|
||||
dlclose(p_module);
|
||||
p_module = nullptr;
|
||||
Message("Vulkan Loader: libvulkan unloaded");
|
||||
}
|
||||
}
|
||||
26
Runtime/Sources/Renderer/Vulkan/VulkanLoader.h
git.filemode.normal_file
26
Runtime/Sources/Renderer/Vulkan/VulkanLoader.h
git.filemode.normal_file
@@ -0,0 +1,26 @@
|
||||
#ifndef __SCOP_VULKAN_LOADER__
|
||||
#define __SCOP_VULKAN_LOADER__
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
namespace Scop
|
||||
{
|
||||
class VulkanLoader
|
||||
{
|
||||
public:
|
||||
VulkanLoader();
|
||||
void LoadInstance(VkInstance instance);
|
||||
void LoadDevice(VkDevice device);
|
||||
~VulkanLoader();
|
||||
|
||||
private:
|
||||
void LoadGlobalFunctions(void* context, PFN_vkVoidFunction (*load)(void*, const char*)) noexcept;
|
||||
void LoadInstanceFunctions(void* context, PFN_vkVoidFunction (*load)(void*, const char*)) noexcept;
|
||||
void LoadDeviceFunctions(void* context, PFN_vkVoidFunction (*load)(void*, const char*)) noexcept;
|
||||
|
||||
private:
|
||||
void* p_module = nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user