This commit is contained in:
Kbz-8
2025-06-16 15:18:27 +02:00
parent 15510fa8a7
commit cd7e5ad26f
165 changed files with 78107 additions and 0 deletions

112
Runtime/Includes/Renderer/Buffer.h git.filemode.normal_file
View File

@@ -0,0 +1,112 @@
#ifndef __SCOP_GPU_BUFFER__
#define __SCOP_GPU_BUFFER__
#include <kvf.h>
#include <Renderer/Enums.h>
#include <Core/Logs.h>
#include <Renderer/RenderCore.h>
#include <Utils/Buffer.h>
#include <Renderer/Memory/Block.h>
namespace Scop
{
class GPUBuffer
{
public:
GPUBuffer() = default;
void Init(BufferType type, VkDeviceSize size, VkBufferUsageFlags usage, CPUBuffer data, std::string_view name = {}, bool dedicated_alloc = false);
void Destroy() noexcept;
bool CopyFrom(const GPUBuffer& buffer, std::size_t src_offset = 0, std::size_t dst_offset = 0) noexcept;
void Swap(GPUBuffer& buffer) noexcept;
[[nodiscard]] inline void* GetMap() const noexcept { return m_memory.map; }
[[nodiscard]] inline VkBuffer operator()() const noexcept { return m_buffer; }
[[nodiscard]] inline VkBuffer Get() const noexcept { return m_buffer; }
[[nodiscard]] inline VkDeviceMemory GetMemory() const noexcept { return m_memory.memory; }
[[nodiscard]] inline VkDeviceSize GetSize() const noexcept { return m_size; }
[[nodiscard]] inline VkDeviceSize GetOffset() const noexcept { return 0; }
[[nodiscard]] inline static std::size_t GetBufferCount() noexcept { return s_buffer_count; }
[[nodiscard]] inline bool IsInit() const noexcept { return m_buffer != VK_NULL_HANDLE; }
~GPUBuffer() = default;
protected:
void PushToGPU() noexcept;
protected:
VkBuffer m_buffer = VK_NULL_HANDLE;
MemoryBlock m_memory = NULL_MEMORY_BLOCK;
VkDeviceSize m_size = 0;
private:
void CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, std::string_view name, bool dedicated_alloc);
private:
inline static std::size_t s_buffer_count = 0;
std::string m_name;
VkBufferUsageFlags m_usage = 0;
VkMemoryPropertyFlags m_flags = 0;
bool m_is_dedicated_alloc = false;
};
class VertexBuffer : public GPUBuffer
{
public:
inline void Init(std::uint32_t size, VkBufferUsageFlags additional_flags = 0, std::string_view name = {}) { GPUBuffer::Init(BufferType::LowDynamic, size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | additional_flags, {}, std::move(name)); }
void SetData(CPUBuffer data);
inline void Bind(VkCommandBuffer cmd) const noexcept { VkDeviceSize offset = 0; RenderCore::Get().vkCmdBindVertexBuffers(cmd, 0, 1, &m_buffer, &offset); }
};
class IndexBuffer : public GPUBuffer
{
public:
inline void Init(std::uint32_t size, VkBufferUsageFlags additional_flags = 0, std::string_view name = {}) { GPUBuffer::Init(BufferType::LowDynamic, size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | additional_flags, {}, std::move(name)); }
void SetData(CPUBuffer data);
inline void Bind(VkCommandBuffer cmd) const noexcept { RenderCore::Get().vkCmdBindIndexBuffer(cmd, m_buffer, 0, VK_INDEX_TYPE_UINT32); }
};
class MeshBuffer : public GPUBuffer
{
public:
inline void Init(std::uint32_t vertex_size, std::uint32_t index_size, VkBufferUsageFlags additional_flags = 0, CPUBuffer data = {}, std::string_view name = {})
{
m_vertex_offset = 0;
m_index_offset = vertex_size;
GPUBuffer::Init(BufferType::LowDynamic, vertex_size + index_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | additional_flags, std::move(data), std::move(name), false);
}
void SetVertexData(CPUBuffer data);
void SetIndexData(CPUBuffer data);
inline void BindVertex(VkCommandBuffer cmd) const noexcept { RenderCore::Get().vkCmdBindVertexBuffers(cmd, 0, 1, &m_buffer, &m_vertex_offset); }
inline void BindIndex(VkCommandBuffer cmd) const noexcept { RenderCore::Get().vkCmdBindIndexBuffer(cmd, m_buffer, m_index_offset, VK_INDEX_TYPE_UINT32); }
private:
VkDeviceSize m_vertex_offset;
VkDeviceSize m_index_offset;
};
class UniformBuffer
{
public:
void Init(std::uint32_t size, std::string_view name = {});
void SetData(CPUBuffer data, std::size_t frame_index);
void Destroy() noexcept;
inline VkDeviceSize GetSize(int i) const noexcept { return m_buffers[i].GetSize(); }
inline VkDeviceSize GetOffset(int i) const noexcept { return m_buffers[i].GetOffset(); }
inline VkBuffer GetVk(int i) const noexcept { return m_buffers[i].Get(); }
inline GPUBuffer& Get(int i) noexcept { return m_buffers[i]; }
private:
std::array<GPUBuffer, MAX_FRAMES_IN_FLIGHT> m_buffers;
std::array<void*, MAX_FRAMES_IN_FLIGHT> m_maps;
};
}
#endif

93
Runtime/Includes/Renderer/Descriptor.h git.filemode.normal_file
View File

@@ -0,0 +1,93 @@
#ifndef __SCOP_DESCRIPTOR_SET__
#define __SCOP_DESCRIPTOR_SET__
#include <vector>
#include <cstdint>
#include <kvf.h>
#include <Utils/NonOwningPtr.h>
#include <Renderer/RenderCore.h>
#include <Renderer/Pipelines/Shader.h>
namespace Scop
{
struct Descriptor
{
NonOwningPtr<class GPUBuffer> storage_buffer_ptr;
NonOwningPtr<class GPUBuffer> uniform_buffer_ptr;
NonOwningPtr<class Image> image_ptr;
VkDescriptorType type;
std::uint32_t binding;
};
class DescriptorPool
{
public:
DescriptorPool() = default;
void Init() noexcept;
void Destroy() noexcept;
std::shared_ptr<class DescriptorSet> RequestDescriptorSet(const ShaderSetLayout& layout, ShaderType shader_type);
void ReturnDescriptorSet(std::shared_ptr<class DescriptorSet> set);
[[nodiscard]] inline VkDescriptorPool Get() const noexcept { return m_pool; }
[[nodiscard]] inline std::size_t GetNumberOfSetsAllocated() const noexcept { return m_allocation_count; }
~DescriptorPool() = default;
private:
std::vector<std::shared_ptr<class DescriptorSet>> m_free_sets;
std::vector<std::shared_ptr<class DescriptorSet>> m_used_sets;
VkDescriptorPool m_pool;
std::size_t m_allocation_count = 0;
};
class DescriptorPoolManager
{
public:
DescriptorPoolManager() = default;
DescriptorPool& GetAvailablePool();
void Destroy();
~DescriptorPoolManager() = default;
private:
std::vector<DescriptorPool> m_pools;
};
class DescriptorSet : public std::enable_shared_from_this<DescriptorSet>
{
friend DescriptorPool;
public:
void SetImage(std::size_t i, std::uint32_t binding, class Image& image);
void SetStorageBuffer(std::size_t i, std::uint32_t binding, class GPUBuffer& buffer);
void SetUniformBuffer(std::size_t i, std::uint32_t binding, class GPUBuffer& buffer);
void Update(std::size_t i, VkCommandBuffer cmd = VK_NULL_HANDLE) noexcept;
void ReturnDescriptorSetToPool();
[[nodiscard]] inline VkDescriptorSet GetSet(std::size_t i) const noexcept { return m_sets[i]; }
[[nodiscard]] inline bool IsInit() const noexcept { return m_sets[0] != VK_NULL_HANDLE; }
[[nodiscard]] inline VkDescriptorSetLayout GetVulkanLayout() const noexcept { return m_set_layout; }
[[nodiscard]] inline const ShaderSetLayout& GetShaderLayout() const { return m_shader_layout; }
[[nodiscard]] inline ShaderType GetShaderType() const noexcept { return m_shader_type; }
~DescriptorSet() = default;
private:
DescriptorSet(DescriptorPool& pool, VkDescriptorSetLayout vulkan_layout, const ShaderSetLayout& layout, std::array<VkDescriptorSet, MAX_FRAMES_IN_FLIGHT> vulkan_sets, ShaderType shader_type);
private:
ShaderSetLayout m_shader_layout;
std::vector<Descriptor> m_descriptors;
std::array<VkDescriptorSet, MAX_FRAMES_IN_FLIGHT> m_sets;
VkDescriptorSetLayout m_set_layout;
ShaderType m_shader_type;
DescriptorPool& m_pool;
};
}
#endif

31
Runtime/Includes/Renderer/Enums.h git.filemode.normal_file
View File

@@ -0,0 +1,31 @@
#ifndef __SCOP_RENDERER_ENUMS__
#define __SCOP_RENDERER_ENUMS__
#include <cstddef>
namespace Scop
{
enum class BufferType
{
Constant = 0,
Staging,
HighDynamic, // typically stored in RAM
LowDynamic, // typically stored in VRAM
EndEnum
};
constexpr std::size_t BufferTypeCount = static_cast<std::size_t>(BufferType::EndEnum);
enum class ImageType
{
Color = 0,
Cube,
Depth,
// Maybe add depth array
EndEnum
};
constexpr std::size_t ImageTypeCount = static_cast<std::size_t>(ImageType::EndEnum);
}
#endif

146
Runtime/Includes/Renderer/Image.h git.filemode.normal_file
View File

@@ -0,0 +1,146 @@
#ifndef __SCOP_IMAGE__
#define __SCOP_IMAGE__
#include <cstdint>
#include <vector>
#include <kvf.h>
#include <Maths/Vec4.h>
#include <Renderer/RenderCore.h>
#include <Renderer/Buffer.h>
#include <Utils/Buffer.h>
#include <Renderer/Enums.h>
#include <Renderer/Memory/Block.h>
namespace Scop
{
class Image
{
public:
Image() = default;
inline void Init(VkImage image, VkFormat format, std::uint32_t width, std::uint32_t height, VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED, std::string_view name = {}) noexcept
{
m_image = image;
m_format = format;
m_width = width;
m_height = height;
m_layout = layout;
#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
}
void Init(ImageType type, std::uint32_t width, std::uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, bool is_multisampled = false, std::string_view name = {}, bool dedicated_alloc = false);
void CreateImageView(VkImageViewType type, VkImageAspectFlags aspectFlags, int layer_count = 1) noexcept;
void CreateSampler() noexcept;
void TransitionLayout(VkImageLayout new_layout, VkCommandBuffer cmd = VK_NULL_HANDLE);
void Clear(VkCommandBuffer cmd, Vec4f color);
void DestroySampler() noexcept;
void DestroyImageView() noexcept;
virtual void Destroy() noexcept;
[[nodiscard]] inline VkImage Get() const noexcept { return m_image; }
[[nodiscard]] inline VkImage operator()() const noexcept { return m_image; }
[[nodiscard]] inline VkDeviceMemory GetDeviceMemory() const noexcept { return m_memory.memory; }
[[nodiscard]] inline VkImageView GetImageView() const noexcept { return m_image_view; }
[[nodiscard]] inline VkFormat GetFormat() const noexcept { return m_format; }
[[nodiscard]] inline VkImageTiling GetTiling() const noexcept { return m_tiling; }
[[nodiscard]] inline VkImageLayout GetLayout() const noexcept { return m_layout; }
[[nodiscard]] inline VkSampler GetSampler() const noexcept { return m_sampler; }
[[nodiscard]] inline std::uint32_t GetWidth() const noexcept { return m_width; }
[[nodiscard]] inline std::uint32_t GetHeight() const noexcept { return m_height; }
[[nodiscard]] inline bool IsInit() const noexcept { return m_image != VK_NULL_HANDLE; }
[[nodiscard]] inline ImageType GetType() const noexcept { return m_type; }
[[nodiscard]] inline static std::size_t GetImageCount() noexcept { return s_image_count; }
virtual ~Image() = default;
private:
inline static std::size_t s_image_count = 0;
MemoryBlock m_memory = NULL_MEMORY_BLOCK;
VkImage m_image = VK_NULL_HANDLE;
VkImageView m_image_view = VK_NULL_HANDLE;
VkSampler m_sampler = VK_NULL_HANDLE;
VkFormat m_format;
VkImageTiling m_tiling;
VkImageLayout m_layout = VK_IMAGE_LAYOUT_UNDEFINED;
ImageType m_type;
std::uint32_t m_width = 0;
std::uint32_t m_height = 0;
bool m_is_multisampled = false;
};
class DepthImage : public Image
{
public:
DepthImage() = default;
inline void Init(std::uint32_t width, std::uint32_t height, bool is_multisampled = false, std::string_view name = {})
{
std::vector<VkFormat> candidates = { VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT };
VkFormat format = kvfFindSupportFormatInCandidates(RenderCore::Get().GetDevice(), candidates.data(), candidates.size(), VK_IMAGE_TILING_OPTIMAL, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);
Image::Init(ImageType::Depth, width, height, format, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, is_multisampled, std::move(name));
Image::TransitionLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
Image::CreateImageView(VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_DEPTH_BIT);
}
~DepthImage() = default;
};
class Texture : public Image
{
public:
Texture() = default;
Texture(CPUBuffer pixels, std::uint32_t width, std::uint32_t height, VkFormat format = VK_FORMAT_R8G8B8A8_SRGB, bool is_multisampled = false, std::string_view name = {}, bool dedicated_alloc = false)
{
Init(std::move(pixels), width, height, format, is_multisampled, std::move(name), dedicated_alloc);
}
inline void Init(CPUBuffer pixels, std::uint32_t width, std::uint32_t height, VkFormat format = VK_FORMAT_R8G8B8A8_SRGB, bool is_multisampled = false, std::string_view name = {}, bool dedicated_alloc = false)
{
Image::Init(ImageType::Color, width, height, format, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, is_multisampled, std::move(name), dedicated_alloc);
Image::CreateImageView(VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT);
Image::CreateSampler();
if(pixels)
{
TransitionLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
GPUBuffer staging_buffer;
std::size_t size = width * height * kvfFormatSize(format);
staging_buffer.Init(BufferType::Staging, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, pixels);
VkCommandBuffer cmd = kvfCreateCommandBuffer(RenderCore::Get().GetDevice());
kvfBeginCommandBuffer(cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
kvfCopyBufferToImage(cmd, Image::Get(), staging_buffer.Get(), staging_buffer.GetOffset(), VK_IMAGE_ASPECT_COLOR_BIT, { width, height, 1 });
RenderCore::Get().vkEndCommandBuffer(cmd);
VkFence fence = kvfCreateFence(RenderCore::Get().GetDevice());
kvfSubmitSingleTimeCommandBuffer(RenderCore::Get().GetDevice(), cmd, KVF_GRAPHICS_QUEUE, fence);
kvfDestroyFence(RenderCore::Get().GetDevice(), fence);
staging_buffer.Destroy();
}
if(!pixels)
TransitionLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
else
TransitionLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}
~Texture() override { Destroy(); }
};
class CubeTexture : public Image
{
public:
CubeTexture() = default;
CubeTexture(CPUBuffer pixels, std::uint32_t width, std::uint32_t height, VkFormat format = VK_FORMAT_R8G8B8A8_SRGB, std::string_view name = {})
{
Init(std::move(pixels), width, height, format, std::move(name));
}
void Init(CPUBuffer pixels, std::uint32_t width, std::uint32_t height, VkFormat format = VK_FORMAT_R8G8B8A8_SRGB, std::string_view name = {});
~CubeTexture() override { Destroy(); }
};
}
#endif

49
Runtime/Includes/Renderer/Memory/Block.h git.filemode.normal_file
View File

@@ -0,0 +1,49 @@
#ifndef __SCOP_VULKAN_MEMORY_BLOCK__
#define __SCOP_VULKAN_MEMORY_BLOCK__
#include <kvf.h>
#include <algorithm>
namespace Scop
{
class MemoryBlock
{
friend class MemoryChunk;
public:
MemoryBlock() = default;
[[nodiscard]] inline bool operator==(const MemoryBlock& rhs) const noexcept
{
return memory == rhs.memory &&
offset == rhs.offset &&
size == rhs.size &&
free == rhs.free &&
map == rhs.map;
}
inline void Swap(MemoryBlock& rhs) noexcept
{
std::swap(memory, rhs.memory);
std::swap(offset, rhs.offset);
std::swap(size, rhs.size);
std::swap(map, rhs.map);
std::swap(free, rhs.free);
}
~MemoryBlock() = default;
public:
VkDeviceMemory memory = VK_NULL_HANDLE;
VkDeviceSize offset = 0;
VkDeviceSize size = 0;
void* map = nullptr; // useless if it's a GPU allocation
private:
bool free = false;
};
constexpr MemoryBlock NULL_MEMORY_BLOCK{};
}
#endif

39
Runtime/Includes/Renderer/Memory/Chunk.h git.filemode.normal_file
View File

@@ -0,0 +1,39 @@
#ifndef __SCOP_VULKAN_MEMORY_CHUNK__
#define __SCOP_VULKAN_MEMORY_CHUNK__
#include <vector>
#include <cstdint>
#include <optional>
#include <Renderer/Memory/Block.h>
namespace Scop
{
class MemoryChunk
{
public:
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);
[[nodiscard]] std::optional<MemoryBlock> Allocate(VkDeviceSize size, VkDeviceSize alignment);
void Deallocate(const MemoryBlock& block);
[[nodiscard]] inline bool Has(const MemoryBlock& block) const noexcept { return block.memory == m_memory; }
[[nodiscard]] inline std::int32_t GetMemoryTypeIndex() const noexcept { return m_memory_type_index; }
[[nodiscard]] inline bool IsDedicated() const noexcept { return m_is_dedicated; }
[[nodiscard]] inline void* GetMap() const noexcept { return p_map; }
[[nodiscard]] inline VkDeviceSize GetSize() const noexcept { return m_size; }
~MemoryChunk();
protected:
std::vector<MemoryBlock> m_blocks;
VkDevice m_device = VK_NULL_HANDLE;
VkPhysicalDevice m_physical = VK_NULL_HANDLE;
VkDeviceMemory m_memory = VK_NULL_HANDLE;
void* p_map = nullptr;
VkDeviceSize m_size = 0;
std::int32_t m_memory_type_index;
bool m_is_dedicated;
};
}
#endif

View File

@@ -0,0 +1,52 @@
#ifndef __SCOP_VULKAN_MEMORY_DEVICE_ALLOCATOR__
#define __SCOP_VULKAN_MEMORY_DEVICE_ALLOCATOR__
#include <mutex>
#include <vector>
#include <memory>
#include <cstdint>
#include <Renderer/Memory/Block.h>
#include <Renderer/Memory/Chunk.h>
namespace Scop
{
constexpr std::size_t SMALL_HEAP_MAX_SIZE = (1024ULL * 1024 * 1024); // 1GB
constexpr std::size_t DEFAULT_LARGE_HEAP_BLOCK_SIZE = (256ULL * 1024 * 1024); // 256MiB
constexpr std::uint32_t NEW_BLOCK_SIZE_SHIFT_MAX = 3;
class DeviceAllocator
{
public:
DeviceAllocator() = default;
void AttachToDevice(VkDevice device, VkPhysicalDevice physical) noexcept;
inline void DetachFromDevice() noexcept { m_chunks.clear(); m_device = VK_NULL_HANDLE; m_physical = VK_NULL_HANDLE; }
[[nodiscard]] inline std::size_t GetAllocationsCount() const noexcept { return m_allocations_count; }
[[nodiscard]] MemoryBlock Allocate(VkDeviceSize size, VkDeviceSize alignment, std::int32_t memory_type_index, bool dedicated_chunk = false);
void Deallocate(const MemoryBlock& block);
[[nodiscard]] inline std::uint32_t GetVramUsage() const noexcept { return m_vram_usage; }
[[nodiscard]] inline std::uint32_t GetVramHostVisibleUsage() const noexcept { return m_vram_host_visible_usage; }
~DeviceAllocator() = default;
private:
VkDeviceSize CalcPreferredChunkSize(std::uint32_t mem_type_index);
private:
std::vector<std::unique_ptr<MemoryChunk>> m_chunks;
VkPhysicalDeviceMemoryProperties m_mem_props;
VkDevice m_device = VK_NULL_HANDLE;
VkPhysicalDevice m_physical = VK_NULL_HANDLE;
std::size_t m_allocations_count = 0;
std::mutex m_alloc_mutex;
std::mutex m_dealloc_mutex;
std::uint32_t m_vram_usage = 0;
std::uint32_t m_vram_host_visible_usage = 0;
bool m_last_chunk_creation_failed = false;
};
}
#endif

View File

@@ -0,0 +1,82 @@
#ifndef __SCOP_GRAPHICS_PIPELINE__
#define __SCOP_GRAPHICS_PIPELINE__
#include <memory>
#include <vector>
#include <kvf.h>
#include <Graphics/Enums.h>
#include <Renderer/Image.h>
#include <Utils/NonOwningPtr.h>
#include <Renderer/Pipelines/Shader.h>
#include <Renderer/Pipelines/Pipeline.h>
namespace Scop
{
struct GraphicPipelineDescriptor
{
std::shared_ptr<Shader> vertex_shader;
std::shared_ptr<Shader> fragment_shader;
std::vector<NonOwningPtr<Texture>> color_attachments;
NonOwningPtr<DepthImage> depth = nullptr;
NonOwningPtr<class Renderer> renderer = nullptr;
std::string name = {};
CullMode culling = CullMode::Front;
bool no_vertex_inputs = false;
bool depth_test_equal = false;
bool clear_color_attachments = true;
bool wireframe = false;
};
class GraphicPipeline : public Pipeline
{
friend class Render2DPass;
friend class FinalPass;
friend class ForwardPass;
friend class PostProcessPass;
friend class SkyboxPass;
public:
GraphicPipeline() = default;
inline void Setup(GraphicPipelineDescriptor descriptor)
{
if(!descriptor.vertex_shader || !descriptor.fragment_shader)
FatalError("Vulkan: invalid shaders");
m_description = std::move(descriptor);
}
bool BindPipeline(VkCommandBuffer command_buffer, std::size_t framebuffer_index, std::array<float, 4> clear) noexcept;
void EndPipeline(VkCommandBuffer command_buffer) noexcept override;
void Destroy() noexcept;
[[nodiscard]] inline VkPipeline GetPipeline() const override { return m_pipeline; }
[[nodiscard]] inline VkPipelineLayout GetPipelineLayout() const override { return m_pipeline_layout; }
[[nodiscard]] inline VkPipelineBindPoint GetPipelineBindPoint() const override { return VK_PIPELINE_BIND_POINT_GRAPHICS; }
[[nodiscard]] inline bool IsPipelineBound() const noexcept { return s_bound_pipeline == this; }
[[nodiscard]] inline GraphicPipelineDescriptor& GetDescription() noexcept { return m_description; }
inline ~GraphicPipeline() noexcept { Destroy(); }
private:
void Init(GraphicPipelineDescriptor descriptor);
void CreateFramebuffers(const std::vector<NonOwningPtr<Texture>>& render_targets, bool clear_attachments);
void TransitionAttachments(VkCommandBuffer cmd = VK_NULL_HANDLE);
// Private override to remove access
bool BindPipeline(VkCommandBuffer) noexcept override { return false; };
private:
static inline GraphicPipeline* s_bound_pipeline = nullptr;
GraphicPipelineDescriptor m_description;
std::vector<VkFramebuffer> m_framebuffers;
std::vector<VkClearValue> m_clears;
VkRenderPass m_renderpass = VK_NULL_HANDLE;
VkPipeline m_pipeline = VK_NULL_HANDLE;
VkPipelineLayout m_pipeline_layout = VK_NULL_HANDLE;
};
}
#endif

View File

@@ -0,0 +1,25 @@
#ifndef __SCOP_PIPELINE__
#define __SCOP_PIPELINE__
#include <kvf.h>
#include <Renderer/RenderCore.h>
namespace Scop
{
class Pipeline
{
public:
Pipeline() = default;
inline virtual bool BindPipeline(VkCommandBuffer command_buffer) noexcept { RenderCore::Get().vkCmdBindPipeline(command_buffer, GetPipelineBindPoint(), GetPipeline()); return true; }
inline virtual void EndPipeline([[maybe_unused]] VkCommandBuffer command_buffer) noexcept {}
virtual VkPipeline GetPipeline() const = 0;
virtual VkPipelineLayout GetPipelineLayout() const = 0;
virtual VkPipelineBindPoint GetPipelineBindPoint() const = 0;
virtual ~Pipeline() = default;
};
}
#endif

123
Runtime/Includes/Renderer/Pipelines/Shader.h git.filemode.normal_file
View File

@@ -0,0 +1,123 @@
#ifndef __SCOP_SHADER__
#define __SCOP_SHADER__
#include <vector>
#include <cstdint>
#include <filesystem>
#include <unordered_map>
#include <kvf.h>
#include <Maths/Mat4.h>
#include <Utils/NonOwningPtr.h>
namespace Scop
{
struct ShaderSetLayout
{
std::unordered_map<int, VkDescriptorType> binds;
ShaderSetLayout(std::unordered_map<int, VkDescriptorType> b) : binds(std::move(b)) {}
inline bool operator==(const ShaderSetLayout& rhs) const { return binds == rhs.binds; }
};
struct ShaderPushConstantLayout
{
std::size_t offset;
std::size_t size;
ShaderPushConstantLayout(std::size_t o, std::size_t s) : offset(o), size(s) {}
};
struct ShaderLayout
{
std::unordered_map<int, ShaderSetLayout> set_layouts;
std::vector<ShaderPushConstantLayout> push_constants;
ShaderLayout(std::unordered_map<int, ShaderSetLayout> s, std::vector<ShaderPushConstantLayout> pc) : set_layouts(std::move(s)), push_constants(std::move(pc)) {}
};
enum class ShaderType
{
Vertex,
Fragment,
Compute
};
struct ShaderPipelineLayoutPart
{
std::vector<VkPushConstantRange> push_constants;
std::vector<VkDescriptorSetLayout> set_layouts;
};
class Shader
{
public:
Shader(const std::vector<std::uint32_t>& bytecode, ShaderType type, ShaderLayout layout, std::string shader_name = {});
[[nodiscard]] inline const ShaderLayout& GetShaderLayout() const { return m_layout; }
[[nodiscard]] inline const std::vector<std::uint32_t>& GetByteCode() const noexcept { return m_bytecode; }
[[nodiscard]] inline const ShaderPipelineLayoutPart& GetPipelineLayout() const noexcept { return m_pipeline_layout_part; }
[[nodiscard]] inline VkShaderModule GetShaderModule() const noexcept { return m_module; }
[[nodiscard]] inline VkShaderStageFlagBits GetShaderStage() const noexcept { return m_stage; }
[[nodiscard]] inline NonOwningPtr<class GraphicPipeline> GetGraphicPipelineInUse() const noexcept { return p_pipeline_in_use; }
inline void SetPipelineInUse(NonOwningPtr<class GraphicPipeline> pipeline) noexcept { p_pipeline_in_use = pipeline; }
void Destroy();
~Shader();
private:
void GeneratePipelineLayout(ShaderLayout layout);
private:
std::string m_name;
ShaderLayout m_layout;
ShaderPipelineLayoutPart m_pipeline_layout_part;
std::vector<std::uint32_t> m_bytecode;
std::vector<VkDescriptorSetLayout> m_set_layouts;
VkShaderStageFlagBits m_stage;
VkShaderModule m_module = VK_NULL_HANDLE;
NonOwningPtr<class GraphicPipeline> p_pipeline_in_use = nullptr;
};
std::shared_ptr<Shader> LoadShaderFromFile(const std::filesystem::path& filepath, ShaderType type, ShaderLayout layout);
static const ShaderLayout DefaultForwardVertexShaderLayout(
{
{ 0,
ShaderSetLayout({
{ 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER },
{ 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER },
})
}
}, { ShaderPushConstantLayout({ 0, sizeof(Mat4f) * 2 }) }
);
static const Scop::ShaderLayout DefaultShaderLayout(
{
{ 1,
Scop::ShaderSetLayout({
{ 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER },
{ 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER }
})
}
}, {}
);
static const Scop::ShaderLayout PostProcessShaderLayout(
{
{ 0,
Scop::ShaderSetLayout({
{ 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER },
{ 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER },
{ 2, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER }
})
}
}, {}
);
}
#endif

80
Runtime/Includes/Renderer/RenderCore.h git.filemode.normal_file
View File

@@ -0,0 +1,80 @@
#ifndef __SCOP_RENDER_CORE__
#define __SCOP_RENDER_CORE__
#include <array>
#include <memory>
#include <cstdint>
#include <optional>
#include <kvf.h>
#include <Renderer/Memory/DeviceAllocator.h>
namespace Scop
{
constexpr const int MAX_FRAMES_IN_FLIGHT = 3;
constexpr const int DEFAULT_VERTEX_SHADER_ID = 0;
constexpr const int DEFAULT_FRAGMENT_SHADER_ID = 1;
constexpr const int BASIC_FRAGMENT_SHADER_ID = 2;
std::optional<std::uint32_t> FindMemoryType(std::uint32_t type_filter, VkMemoryPropertyFlags properties, bool error = true);
#if defined(DEBUG) && defined(VK_EXT_debug_utils)
#define SCOP_HAS_DEBUG_UTILS_FUNCTIONS
#endif
class RenderCore
{
public:
RenderCore();
[[nodiscard]] inline VkInstance GetInstance() const noexcept { return m_instance; }
[[nodiscard]] inline VkInstance& GetInstanceRef() noexcept { return m_instance; }
[[nodiscard]] inline VkDevice GetDevice() const noexcept { return m_device; }
[[nodiscard]] inline VkPhysicalDevice GetPhysicalDevice() const noexcept { return m_physical_device; }
[[nodiscard]] inline DeviceAllocator& GetAllocator() noexcept { return m_allocator; }
[[nodiscard]] inline bool StackSubmits() const noexcept { return m_stack_submits; }
[[nodiscard]] inline class DescriptorPoolManager& GetDescriptorPoolManager() noexcept { return *p_descriptor_pool_manager; }
[[nodiscard]] inline std::shared_ptr<class Shader> GetDefaultVertexShader() const { return m_internal_shaders[DEFAULT_VERTEX_SHADER_ID]; }
[[nodiscard]] inline std::shared_ptr<class Shader> GetBasicFragmentShader() const { return m_internal_shaders[BASIC_FRAGMENT_SHADER_ID]; }
[[nodiscard]] inline std::shared_ptr<class Shader> GetDefaultFragmentShader() const { return m_internal_shaders[DEFAULT_FRAGMENT_SHADER_ID]; }
inline void WaitDeviceIdle() const noexcept { vkDeviceWaitIdle(m_device); }
inline void WaitQueueIdle(KvfQueueType queue) const noexcept { vkQueueWaitIdle(kvfGetDeviceQueue(m_device, queue)); }
inline static bool IsInit() noexcept { return s_instance != nullptr; }
inline static RenderCore& Get() noexcept { return *s_instance; }
inline void ShouldStackSubmits(bool should) noexcept { m_stack_submits = should; }
#define SCOP_VULKAN_GLOBAL_FUNCTION(fn) PFN_##fn fn = nullptr;
#define SCOP_VULKAN_INSTANCE_FUNCTION(fn) PFN_##fn fn = nullptr;
#define SCOP_VULKAN_DEVICE_FUNCTION(fn) PFN_##fn fn = nullptr;
#include <Renderer/Vulkan/VulkanDefs.h>
#undef SCOP_VULKAN_GLOBAL_FUNCTION
#undef SCOP_VULKAN_INSTANCE_FUNCTION
#undef SCOP_VULKAN_DEVICE_FUNCTION
~RenderCore();
private:
void LoadKVFGlobalVulkanFunctionPointers() const noexcept;
void LoadKVFInstanceVulkanFunctionPointers() const noexcept;
void LoadKVFDeviceVulkanFunctionPointers() const noexcept;
private:
static RenderCore* s_instance;
std::array<std::shared_ptr<class Shader>, 3> m_internal_shaders;
DeviceAllocator m_allocator;
VkInstance m_instance = VK_NULL_HANDLE;
VkDevice m_device = VK_NULL_HANDLE;
VkPhysicalDevice m_physical_device = VK_NULL_HANDLE;
std::unique_ptr<class DescriptorPoolManager> p_descriptor_pool_manager;
bool m_stack_submits = false;
};
}
#endif

View File

@@ -0,0 +1,31 @@
#ifndef __SCOP_2D_PASS__
#define __SCOP_2D_PASS__
#include <memory>
#include <Renderer/Descriptor.h>
#include <Renderer/Pipelines/Shader.h>
#include <Renderer/Pipelines/Graphics.h>
namespace Scop
{
class Render2DPass
{
public:
Render2DPass() = default;
void Init();
void Pass(class Scene& scene, class Renderer& renderer, class Texture& render_target);
void Destroy();
~Render2DPass() = default;
private:
GraphicPipeline m_pipeline;
std::shared_ptr<DescriptorSet> p_viewer_data_set;
std::shared_ptr<UniformBuffer> p_viewer_data_buffer;
std::shared_ptr<DescriptorSet> p_texture_set;
std::shared_ptr<Shader> p_vertex_shader;
std::shared_ptr<Shader> p_fragment_shader;
};
}
#endif

View File

@@ -0,0 +1,29 @@
#ifndef __SCOP_FINAL_PASS__
#define __SCOP_FINAL_PASS__
#include <memory>
#include <Renderer/Descriptor.h>
#include <Renderer/Pipelines/Shader.h>
#include <Renderer/Pipelines/Graphics.h>
namespace Scop
{
class FinalPass
{
public:
FinalPass() = default;
void Init();
void Pass(class Scene& scene, class Renderer& renderer, class Texture& render_target);
void Destroy();
~FinalPass() = default;
private:
GraphicPipeline m_pipeline;
std::shared_ptr<DescriptorSet> p_set;
std::shared_ptr<Shader> p_vertex_shader;
std::shared_ptr<Shader> p_fragment_shader;
};
}
#endif

View File

@@ -0,0 +1,15 @@
#ifndef __SCOP_FORWARD_PASS__
#define __SCOP_FORWARD_PASS__
namespace Scop
{
class ForwardPass
{
public:
ForwardPass() = default;
void Pass(class Scene& scene, class Renderer& renderer, class Texture& render_target);
~ForwardPass() = default;
};
}
#endif

View File

@@ -0,0 +1,32 @@
#ifndef __SCOP_PASSES__
#define __SCOP_PASSES__
#include <Renderer/Image.h>
#include <Renderer/RenderPasses/SkyboxPass.h>
#include <Renderer/RenderPasses/ForwardPass.h>
#include <Renderer/RenderPasses/FinalPass.h>
#include <Renderer/RenderPasses/PostProcessPass.h>
#include <Renderer/RenderPasses/2DPass.h>
namespace Scop
{
class RenderPasses
{
public:
RenderPasses() = default;
void Init();
void Pass(class Scene& scene, class Renderer& renderer);
void Destroy();
~RenderPasses() = default;
private:
SkyboxPass m_skybox;
Render2DPass m_2Dpass;
PostProcessPass m_post_process;
FinalPass m_final;
Texture m_main_render_texture;
ForwardPass m_forward;
};
}
#endif

View File

@@ -0,0 +1,28 @@
#ifndef __SCOP_POST_PROCESS_PASS__
#define __SCOP_POST_PROCESS_PASS__
#include <Renderer/Descriptor.h>
#include <Renderer/Pipelines/Shader.h>
#include <Renderer/Pipelines/Graphics.h>
namespace Scop
{
class PostProcessPass
{
public:
PostProcessPass() = default;
void Init();
void Pass(class Scene& scene, class Renderer& renderer, class Texture& render_target);
void Destroy();
[[nodiscard]] inline Texture& GetProcessTexture() noexcept { return m_render_texture; }
~PostProcessPass() = default;
private:
GraphicPipeline m_pipeline;
Texture m_render_texture;
std::shared_ptr<Shader> p_vertex_shader;
};
}
#endif

View File

@@ -0,0 +1,30 @@
#ifndef __SCOP_SKYBOX_PASS__
#define __SCOP_SKYBOX_PASS__
#include <memory>
#include <Renderer/Descriptor.h>
#include <Renderer/Pipelines/Shader.h>
#include <Renderer/Pipelines/Graphics.h>
namespace Scop
{
class SkyboxPass
{
public:
SkyboxPass() = default;
void Init();
void Pass(class Scene& scene, class Renderer& renderer, class Texture& render_target);
void Destroy();
~SkyboxPass() = default;
private:
GraphicPipeline m_pipeline;
std::shared_ptr<DescriptorSet> p_set;
std::shared_ptr<Shader> p_vertex_shader;
std::shared_ptr<Shader> p_fragment_shader;
std::shared_ptr<class Mesh> m_cube;
};
}
#endif

55
Runtime/Includes/Renderer/Renderer.h git.filemode.normal_file
View File

@@ -0,0 +1,55 @@
#ifndef __SCOP_RENDERER__
#define __SCOP_RENDERER__
#include <Platform/Window.h>
#include <Utils/NonOwningPtr.h>
#include <Renderer/Swapchain.h>
#include <Renderer/RenderCore.h>
#include <Renderer/Image.h>
#include <kvf.h>
#include <array>
#include <Core/EventBus.h>
namespace Scop
{
class Renderer
{
public:
Renderer() = default;
void Init(NonOwningPtr<Window> window);
void BeginFrame();
void EndFrame();
[[nodiscard]] inline VkSemaphore GetImageAvailableSemaphore(int index) const noexcept { return m_image_available_semaphores[index]; }
[[nodiscard]] inline VkSemaphore GetRenderFinishedSemaphore(int index) const noexcept { return m_render_finished_semaphores[index]; }
[[nodiscard]] inline VkCommandBuffer GetCommandBuffer(int index) const noexcept { return m_cmd_buffers[index]; }
[[nodiscard]] inline VkCommandBuffer GetActiveCommandBuffer() const noexcept { return m_cmd_buffers[m_current_frame_index]; }
[[nodiscard]] inline std::size_t& GetDrawCallsCounterRef() noexcept { return m_drawcalls; }
[[nodiscard]] inline std::size_t& GetPolygonDrawnCounterRef() noexcept { return m_polygons_drawn; }
[[nodiscard]] inline std::size_t GetCurrentFrameIndex() const noexcept { return m_current_frame_index; }
[[nodiscard]] inline NonOwningPtr<Window> GetWindow() const noexcept { return p_window; }
[[nodiscard]] inline const Swapchain& GetSwapchain() const noexcept { return m_swapchain; }
void Destroy() noexcept;
~Renderer() = default;
private:
Swapchain m_swapchain;
std::vector<VkSemaphore> m_render_finished_semaphores;
std::array<VkSemaphore, MAX_FRAMES_IN_FLIGHT> m_image_available_semaphores;
std::array<VkCommandBuffer, MAX_FRAMES_IN_FLIGHT> m_cmd_buffers;
std::array<VkFence, MAX_FRAMES_IN_FLIGHT> m_cmd_fences;
NonOwningPtr<Window> p_window;
std::uint32_t m_current_frame_index = 0;
std::size_t m_polygons_drawn = 0;
std::size_t m_drawcalls = 0;
};
}
#endif

22
Runtime/Includes/Renderer/ScenesRenderer.h git.filemode.normal_file
View File

@@ -0,0 +1,22 @@
#ifndef __SCOP_SCENES_RENDERER__
#define __SCOP_SCENES_RENDERER__
#include <Renderer/RenderPasses/Passes.h>
namespace Scop
{
class SceneRenderer
{
public:
SceneRenderer() = default;
void Init();
void Render(class Scene& scene, class Renderer& renderer); // TODO : add RTT support
void Destroy();
~SceneRenderer() = default;
private:
RenderPasses m_passes;
};
}
#endif

43
Runtime/Includes/Renderer/Swapchain.h git.filemode.normal_file
View File

@@ -0,0 +1,43 @@
#ifndef __SCOP_SWAPCHAIN__
#define __SCOP_SWAPCHAIN__
#include <Utils/NonOwningPtr.h>
#include <Renderer/Image.h>
namespace Scop
{
class Swapchain
{
public:
Swapchain() = default;
void Init(NonOwningPtr<class Window> window);
void AquireFrame(VkSemaphore signal);
void Present(VkSemaphore wait) noexcept;
void Destroy();
[[nodiscard]] inline VkSwapchainKHR Get() const noexcept { return m_swapchain; }
[[nodiscard]] inline VkSurfaceKHR GetSurface() const noexcept { return m_surface; }
[[nodiscard]] inline std::uint32_t GetImagesCount() const noexcept { return m_images_count; }
[[nodiscard]] inline std::uint32_t GetMinImagesCount() const noexcept { return m_min_images_count; }
[[nodiscard]] inline std::uint32_t GetImageIndex() const noexcept { return m_current_image_index; }
[[nodiscard]] inline const std::vector<Image>& GetSwapchainImages() const { return m_swapchain_images; }
~Swapchain() = default;
private:
void CreateSwapchain();
private:
std::vector<Image> m_swapchain_images;
VkSwapchainKHR m_swapchain = VK_NULL_HANDLE;
VkSurfaceKHR m_surface = VK_NULL_HANDLE;
NonOwningPtr<class Window> p_window;
std::uint32_t m_images_count = 0;
std::uint32_t m_min_images_count = 0;
std::uint32_t m_current_image_index = 0;
bool m_resize = false;
};
}
#endif

29
Runtime/Includes/Renderer/Vertex.h git.filemode.normal_file
View File

@@ -0,0 +1,29 @@
#ifndef __SCOP_VERTEX__
#define __SCOP_VERTEX__
#include <kvf.h>
#include <array>
#include <Maths/Vec4.h>
#include <Maths/Vec2.h>
namespace Scop
{
struct Vertex
{
alignas(16) Vec4f position = Vec4f{ 0.0f, 0.0f, 0.0f, 1.0f };
alignas(16) Vec4f color = Vec4f{ 1.0f, 1.0f, 1.0f, 1.0f };
alignas(16) Vec4f normal = Vec4f{ 0.0f, 0.0f, 0.0f, 1.0f };
alignas(16) Vec2f uv = Vec2f{ 0.0f, 0.0f };
Vertex() = default;
Vertex(Vec4f p, Vec4f c, Vec4f n, Vec2f u) : position(std::move(p)), color(std::move(c)), normal(std::move(n)), uv(std::move(u)) {}
Vertex(Vec4f p, Vec4f n, Vec2f u) : position(std::move(p)), normal(std::move(n)), uv(std::move(u)) {}
[[nodiscard]] inline static VkVertexInputBindingDescription GetBindingDescription();
[[nodiscard]] inline static std::array<VkVertexInputAttributeDescription, 4> GetAttributeDescriptions();
};
}
#include <Renderer/Vertex.inl>
#endif

41
Runtime/Includes/Renderer/Vertex.inl git.filemode.normal_file
View File

@@ -0,0 +1,41 @@
#pragma once
#include <Renderer/Vertex.h>
namespace Scop
{
VkVertexInputBindingDescription Vertex::GetBindingDescription()
{
VkVertexInputBindingDescription binding_description{};
binding_description.binding = 0;
binding_description.stride = sizeof(Vertex);
binding_description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
return binding_description;
}
std::array<VkVertexInputAttributeDescription, 4> Vertex::GetAttributeDescriptions()
{
std::array<VkVertexInputAttributeDescription, 4> attribute_descriptions;
attribute_descriptions[0].binding = 0;
attribute_descriptions[0].location = 0;
attribute_descriptions[0].format = VK_FORMAT_R32G32B32A32_SFLOAT;
attribute_descriptions[0].offset = offsetof(Vertex, position);
attribute_descriptions[1].binding = 0;
attribute_descriptions[1].location = 1;
attribute_descriptions[1].format = VK_FORMAT_R32G32B32A32_SFLOAT;
attribute_descriptions[1].offset = offsetof(Vertex, color);
attribute_descriptions[2].binding = 0;
attribute_descriptions[2].location = 2;
attribute_descriptions[2].format = VK_FORMAT_R32G32B32A32_SFLOAT;
attribute_descriptions[2].offset = offsetof(Vertex, normal);
attribute_descriptions[3].binding = 0;
attribute_descriptions[3].location = 3;
attribute_descriptions[3].format = VK_FORMAT_R32G32_SFLOAT;
attribute_descriptions[3].offset = offsetof(Vertex, uv);
return attribute_descriptions;
}
}

21
Runtime/Includes/Renderer/ViewerData.h git.filemode.normal_file
View File

@@ -0,0 +1,21 @@
#ifndef __SCOP_VIEWER_DATA__
#define __SCOP_VIEWER_DATA__
#include <Maths/Mat4.h>
#include <Maths/Vec3.h>
namespace Scop
{
struct ViewerData
{
Mat4f projection_matrix;
Mat4f inv_projection_matrix;
Mat4f view_matrix;
Mat4f inv_view_matrix;
Mat4f view_proj_matrix;
Mat4f inv_view_proj_matrix;
alignas(16) Vec3f camera_position;
};
}
#endif

127
Runtime/Includes/Renderer/Vulkan/VulkanDefs.h git.filemode.normal_file
View File

@@ -0,0 +1,127 @@
// No header guard
#ifdef VK_VERSION_1_0
#ifdef SCOP_VULKAN_GLOBAL_FUNCTION
SCOP_VULKAN_GLOBAL_FUNCTION(vkCreateInstance)
SCOP_VULKAN_GLOBAL_FUNCTION(vkEnumerateInstanceExtensionProperties)
SCOP_VULKAN_GLOBAL_FUNCTION(vkEnumerateInstanceLayerProperties)
SCOP_VULKAN_GLOBAL_FUNCTION(vkGetInstanceProcAddr)
#endif
#ifdef SCOP_VULKAN_INSTANCE_FUNCTION
SCOP_VULKAN_INSTANCE_FUNCTION(vkCreateDevice)
SCOP_VULKAN_INSTANCE_FUNCTION(vkDestroyInstance)
SCOP_VULKAN_INSTANCE_FUNCTION(vkEnumerateDeviceExtensionProperties)
SCOP_VULKAN_INSTANCE_FUNCTION(vkEnumeratePhysicalDevices)
SCOP_VULKAN_INSTANCE_FUNCTION(vkGetDeviceProcAddr)
SCOP_VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceFeatures)
SCOP_VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceFormatProperties)
SCOP_VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceImageFormatProperties)
SCOP_VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceMemoryProperties)
SCOP_VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceProperties)
SCOP_VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceQueueFamilyProperties)
#ifdef DEBUG
#ifdef VK_EXT_debug_utils
SCOP_VULKAN_INSTANCE_FUNCTION(vkSetDebugUtilsObjectNameEXT)
//SCOP_VULKAN_INSTANCE_FUNCTION(vkSetDebugUtilsObjectTagEXT)
#endif
#endif
#endif
#ifdef SCOP_VULKAN_DEVICE_FUNCTION
SCOP_VULKAN_DEVICE_FUNCTION(vkAllocateCommandBuffers)
SCOP_VULKAN_DEVICE_FUNCTION(vkAllocateDescriptorSets)
SCOP_VULKAN_DEVICE_FUNCTION(vkAllocateMemory)
SCOP_VULKAN_DEVICE_FUNCTION(vkBeginCommandBuffer)
SCOP_VULKAN_DEVICE_FUNCTION(vkBindBufferMemory)
SCOP_VULKAN_DEVICE_FUNCTION(vkBindImageMemory)
SCOP_VULKAN_DEVICE_FUNCTION(vkCmdBeginRenderPass)
SCOP_VULKAN_DEVICE_FUNCTION(vkCmdBindDescriptorSets)
SCOP_VULKAN_DEVICE_FUNCTION(vkCmdBindIndexBuffer)
SCOP_VULKAN_DEVICE_FUNCTION(vkCmdBindPipeline)
SCOP_VULKAN_DEVICE_FUNCTION(vkCmdBindVertexBuffers)
SCOP_VULKAN_DEVICE_FUNCTION(vkCmdClearAttachments)
SCOP_VULKAN_DEVICE_FUNCTION(vkCmdClearColorImage)
SCOP_VULKAN_DEVICE_FUNCTION(vkCmdClearDepthStencilImage)
SCOP_VULKAN_DEVICE_FUNCTION(vkCmdCopyBuffer)
SCOP_VULKAN_DEVICE_FUNCTION(vkCmdCopyBufferToImage)
SCOP_VULKAN_DEVICE_FUNCTION(vkCmdCopyImage)
SCOP_VULKAN_DEVICE_FUNCTION(vkCmdCopyImageToBuffer)
SCOP_VULKAN_DEVICE_FUNCTION(vkCmdDraw)
SCOP_VULKAN_DEVICE_FUNCTION(vkCmdDrawIndexed)
SCOP_VULKAN_DEVICE_FUNCTION(vkCmdEndRenderPass)
SCOP_VULKAN_DEVICE_FUNCTION(vkCmdPipelineBarrier)
SCOP_VULKAN_DEVICE_FUNCTION(vkCmdPushConstants)
SCOP_VULKAN_DEVICE_FUNCTION(vkCmdSetScissor)
SCOP_VULKAN_DEVICE_FUNCTION(vkCmdSetViewport)
SCOP_VULKAN_DEVICE_FUNCTION(vkCreateBuffer)
SCOP_VULKAN_DEVICE_FUNCTION(vkCreateCommandPool)
SCOP_VULKAN_DEVICE_FUNCTION(vkCreateDescriptorPool)
SCOP_VULKAN_DEVICE_FUNCTION(vkCreateDescriptorSetLayout)
SCOP_VULKAN_DEVICE_FUNCTION(vkCreateFence)
SCOP_VULKAN_DEVICE_FUNCTION(vkCreateFramebuffer)
SCOP_VULKAN_DEVICE_FUNCTION(vkCreateGraphicsPipelines)
SCOP_VULKAN_DEVICE_FUNCTION(vkCreateImage)
SCOP_VULKAN_DEVICE_FUNCTION(vkCreateImageView)
SCOP_VULKAN_DEVICE_FUNCTION(vkCreatePipelineLayout)
SCOP_VULKAN_DEVICE_FUNCTION(vkCreateRenderPass)
SCOP_VULKAN_DEVICE_FUNCTION(vkCreateSampler)
SCOP_VULKAN_DEVICE_FUNCTION(vkCreateSemaphore)
SCOP_VULKAN_DEVICE_FUNCTION(vkCreateShaderModule)
SCOP_VULKAN_DEVICE_FUNCTION(vkDestroyBuffer)
SCOP_VULKAN_DEVICE_FUNCTION(vkDestroyCommandPool)
SCOP_VULKAN_DEVICE_FUNCTION(vkDestroyDescriptorPool)
SCOP_VULKAN_DEVICE_FUNCTION(vkDestroyDescriptorSetLayout)
SCOP_VULKAN_DEVICE_FUNCTION(vkDestroyDevice)
SCOP_VULKAN_DEVICE_FUNCTION(vkDestroyFence)
SCOP_VULKAN_DEVICE_FUNCTION(vkDestroyFramebuffer)
SCOP_VULKAN_DEVICE_FUNCTION(vkDestroyImage)
SCOP_VULKAN_DEVICE_FUNCTION(vkDestroyImageView)
SCOP_VULKAN_DEVICE_FUNCTION(vkDestroyPipeline)
SCOP_VULKAN_DEVICE_FUNCTION(vkDestroyPipelineLayout)
SCOP_VULKAN_DEVICE_FUNCTION(vkDestroyRenderPass)
SCOP_VULKAN_DEVICE_FUNCTION(vkDestroySampler)
SCOP_VULKAN_DEVICE_FUNCTION(vkDestroySemaphore)
SCOP_VULKAN_DEVICE_FUNCTION(vkDestroyShaderModule)
SCOP_VULKAN_DEVICE_FUNCTION(vkDeviceWaitIdle)
SCOP_VULKAN_DEVICE_FUNCTION(vkEndCommandBuffer)
SCOP_VULKAN_DEVICE_FUNCTION(vkFlushMappedMemoryRanges)
SCOP_VULKAN_DEVICE_FUNCTION(vkFreeCommandBuffers)
SCOP_VULKAN_DEVICE_FUNCTION(vkFreeMemory)
SCOP_VULKAN_DEVICE_FUNCTION(vkGetBufferMemoryRequirements)
SCOP_VULKAN_DEVICE_FUNCTION(vkGetDeviceMemoryCommitment)
SCOP_VULKAN_DEVICE_FUNCTION(vkGetDeviceQueue)
SCOP_VULKAN_DEVICE_FUNCTION(vkGetFenceStatus)
SCOP_VULKAN_DEVICE_FUNCTION(vkGetImageMemoryRequirements)
SCOP_VULKAN_DEVICE_FUNCTION(vkGetImageSubresourceLayout)
SCOP_VULKAN_DEVICE_FUNCTION(vkInvalidateMappedMemoryRanges)
SCOP_VULKAN_DEVICE_FUNCTION(vkMapMemory)
SCOP_VULKAN_DEVICE_FUNCTION(vkQueueSubmit)
SCOP_VULKAN_DEVICE_FUNCTION(vkQueueWaitIdle)
SCOP_VULKAN_DEVICE_FUNCTION(vkResetCommandBuffer)
SCOP_VULKAN_DEVICE_FUNCTION(vkResetDescriptorPool)
SCOP_VULKAN_DEVICE_FUNCTION(vkResetEvent)
SCOP_VULKAN_DEVICE_FUNCTION(vkResetFences)
SCOP_VULKAN_DEVICE_FUNCTION(vkUnmapMemory)
SCOP_VULKAN_DEVICE_FUNCTION(vkUpdateDescriptorSets)
SCOP_VULKAN_DEVICE_FUNCTION(vkWaitForFences)
#endif
#endif
#ifdef VK_KHR_swapchain
#ifdef SCOP_VULKAN_DEVICE_FUNCTION
SCOP_VULKAN_DEVICE_FUNCTION(vkAcquireNextImageKHR)
SCOP_VULKAN_DEVICE_FUNCTION(vkCreateSwapchainKHR)
SCOP_VULKAN_DEVICE_FUNCTION(vkDestroySwapchainKHR)
SCOP_VULKAN_DEVICE_FUNCTION(vkGetSwapchainImagesKHR)
SCOP_VULKAN_DEVICE_FUNCTION(vkQueuePresentKHR)
#endif
#endif
#ifdef VK_KHR_surface
#ifdef SCOP_VULKAN_INSTANCE_FUNCTION
SCOP_VULKAN_INSTANCE_FUNCTION(vkDestroySurfaceKHR)
SCOP_VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfaceCapabilitiesKHR)
SCOP_VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfaceFormatsKHR)
SCOP_VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfacePresentModesKHR)
SCOP_VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfaceSupportKHR)
#endif
#endif