1708 lines
77 KiB
C++
1708 lines
77 KiB
C++
|
#include <fstream>
|
||
|
#include <shaderc/shaderc.hpp>
|
||
|
#include <iostream>
|
||
|
|
||
|
#include "vulkan.hpp"
|
||
|
|
||
|
namespace vk {
|
||
|
|
||
|
template<typename T>
|
||
|
class defer {
|
||
|
public:
|
||
|
defer(const T& t) : ft(t) {}
|
||
|
~defer() { ft(); }
|
||
|
T ft;
|
||
|
};
|
||
|
|
||
|
class PhysicalDeviceImpl : public PhysicalDevice {
|
||
|
public:
|
||
|
PhysicalDeviceImpl(VkPhysicalDevice handle) : physical_device(handle) {
|
||
|
vkGetPhysicalDeviceProperties(handle, &props);
|
||
|
vkGetPhysicalDeviceMemoryProperties(handle, &mem_props);
|
||
|
uint32_t extension_count = 0;
|
||
|
vkEnumerateDeviceExtensionProperties(handle, nullptr, &extension_count, nullptr);
|
||
|
rs::vector<VkExtensionProperties> extension_props(extension_count);
|
||
|
vkEnumerateDeviceExtensionProperties(handle, nullptr, &extension_count, extension_props.data());
|
||
|
uint32_t queue_family_count = 0;
|
||
|
vkGetPhysicalDeviceQueueFamilyProperties(handle, &queue_family_count, nullptr);
|
||
|
queue_family_props.resize(queue_family_count);
|
||
|
vkGetPhysicalDeviceQueueFamilyProperties(handle, &queue_family_count, queue_family_props.data());
|
||
|
vkGetPhysicalDeviceFeatures(handle, &features);
|
||
|
}
|
||
|
PhysicalDeviceImpl(const PhysicalDeviceImpl&) = delete;
|
||
|
PhysicalDeviceImpl(PhysicalDeviceImpl&& pdev) {
|
||
|
physical_device = pdev.physical_device;
|
||
|
props = pdev.props;
|
||
|
mem_props = pdev.mem_props;
|
||
|
extension_props = std::move(pdev.extension_props);
|
||
|
queue_family_props = std::move(pdev.queue_family_props);
|
||
|
features = pdev.features;
|
||
|
};
|
||
|
~PhysicalDeviceImpl() {}
|
||
|
|
||
|
VkPhysicalDevice handle() const override { return physical_device;}
|
||
|
const VkPhysicalDeviceProperties* properties() const override { return &props; }
|
||
|
const VkPhysicalDeviceMemoryProperties* mem_properties() const override { return &mem_props; }
|
||
|
const VkPhysicalDeviceFeatures* supported_features() const override { return &features; }
|
||
|
rs::iterator<const VkExtensionProperties*> enumerate_extensions() const override{ return extension_props.into_iter_ptr(); }
|
||
|
rs::iterator<const VkQueueFamilyProperties*> enumerate_queue_families() const override { return queue_family_props.into_iter_ptr(); }
|
||
|
|
||
|
private:
|
||
|
VkPhysicalDevice physical_device;
|
||
|
VkPhysicalDeviceProperties props;
|
||
|
VkPhysicalDeviceMemoryProperties mem_props;
|
||
|
rs::vector<VkExtensionProperties> extension_props;
|
||
|
rs::vector<VkQueueFamilyProperties> queue_family_props;
|
||
|
VkPhysicalDeviceFeatures features;
|
||
|
};
|
||
|
|
||
|
class InstanceImpl : public Instance {
|
||
|
public:
|
||
|
InstanceImpl(VkInstance handle) : instance(handle) {
|
||
|
uint32_t device_count = 0;
|
||
|
vkEnumeratePhysicalDevices(instance, &device_count, nullptr);
|
||
|
rs::vector<VkPhysicalDevice> devices(device_count);
|
||
|
vkEnumeratePhysicalDevices(instance, &device_count, devices.data());
|
||
|
physical_devices.reserve(device_count);
|
||
|
for(auto p : devices)
|
||
|
physical_devices.emplace_back(p);
|
||
|
}
|
||
|
InstanceImpl(const InstanceImpl&) = delete;
|
||
|
~InstanceImpl() {
|
||
|
vkDestroyInstance(instance, nullptr);
|
||
|
}
|
||
|
|
||
|
rs::iterator<const PhysicalDevice*> enumerate_physical_device() const override {
|
||
|
return physical_devices.into_iter_ptr().map([](const PhysicalDeviceImpl* p) {
|
||
|
return static_cast<const PhysicalDevice*>(p);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
VkInstance handle() const override { return instance; }
|
||
|
|
||
|
private:
|
||
|
VkInstance instance;
|
||
|
rs::vector<PhysicalDeviceImpl> physical_devices;
|
||
|
};
|
||
|
|
||
|
class SurfaceImpl : public Surface {
|
||
|
public:
|
||
|
SurfaceImpl(VkSurfaceKHR s, const Instance& inst, const PhysicalDevice& dev) : surface(s) {
|
||
|
instance = inst.handle();
|
||
|
physical_device = dev.handle();
|
||
|
refresh();
|
||
|
}
|
||
|
SurfaceImpl(const SurfaceImpl&) = delete;
|
||
|
~SurfaceImpl() {
|
||
|
vkDestroySurfaceKHR(instance, surface, nullptr);
|
||
|
}
|
||
|
|
||
|
VkSurfaceKHR handle() const override { return surface; }
|
||
|
void refresh() override {
|
||
|
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, surface, &surface_capabilities);
|
||
|
uint32_t surface_format_count = 0;
|
||
|
vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &surface_format_count, nullptr);
|
||
|
supported_formats.resize(surface_format_count);
|
||
|
vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &surface_format_count, supported_formats.data());
|
||
|
}
|
||
|
const VkSurfaceCapabilitiesKHR* capabilities() const override { return &surface_capabilities; }
|
||
|
rs::iterator<const VkSurfaceFormatKHR*> enumerate_formats() const override {
|
||
|
return supported_formats.into_iter_ptr().map([](const VkSurfaceFormatKHR* p) {
|
||
|
return static_cast<const VkSurfaceFormatKHR*>(p);
|
||
|
});
|
||
|
}
|
||
|
const VkSurfaceFormatKHR* default_format() const override {
|
||
|
return supported_formats.into_iter_ptr().find([](const VkSurfaceFormatKHR* format) {
|
||
|
return format->format == VK_FORMAT_B8G8R8A8_UNORM;
|
||
|
}).value_or(&supported_formats[0]);
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
VkInstance instance;
|
||
|
VkSurfaceKHR surface;
|
||
|
VkPhysicalDevice physical_device;
|
||
|
VkSurfaceCapabilitiesKHR surface_capabilities;
|
||
|
rs::vector<VkSurfaceFormatKHR> supported_formats;
|
||
|
};
|
||
|
|
||
|
class DeviceImpl : public Device {
|
||
|
public:
|
||
|
DeviceImpl(VkDevice handle, rs::vector<Queue> q) : device(handle), queues(std::move(q)) {}
|
||
|
DeviceImpl(const DeviceImpl&) = delete;
|
||
|
~DeviceImpl() {
|
||
|
vkDeviceWaitIdle(device);
|
||
|
vkDestroyDevice(device, nullptr);
|
||
|
}
|
||
|
|
||
|
VkDevice handle() const override { return device; }
|
||
|
void wait_idle() const override {
|
||
|
vkDeviceWaitIdle(device);
|
||
|
}
|
||
|
|
||
|
rs::iterator<const Queue*> enumerate_queues() const override { return queues.into_iter_ptr(); }
|
||
|
rs::vector<uint32_t> queue_family_in_use() const override {
|
||
|
return queues.into_iter_ptr().map([](const Queue* q) -> uint32_t {
|
||
|
return q->queue_family_index;
|
||
|
}).collect<rs::set<uint32_t>>().into_iter().collect<rs::vector<uint32_t>>();
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
VkDevice device;
|
||
|
rs::vector<Queue> queues;
|
||
|
};
|
||
|
|
||
|
class BufferImpl : public Buffer {
|
||
|
public:
|
||
|
BufferImpl(VkDevice device, VkBuffer buffer, VkDeviceMemory mem, size_t size, bool host_visible)
|
||
|
: inner_device(device), buffer(buffer), device_memory(mem), mem_size(size), host_visible(host_visible) {}
|
||
|
BufferImpl(const BufferImpl&) = delete;
|
||
|
~BufferImpl() {
|
||
|
vkDestroyBuffer(inner_device, buffer, nullptr);
|
||
|
vkFreeMemory(inner_device, device_memory, nullptr);
|
||
|
}
|
||
|
|
||
|
VkBuffer handle() const override { return buffer; }
|
||
|
bool can_map() const override { return host_visible; }
|
||
|
void* map(uint32_t offset, uint32_t size) override {
|
||
|
void* data = nullptr;
|
||
|
if(mapped || vkMapMemory(inner_device, device_memory, offset, size, 0, &data) != VK_SUCCESS)
|
||
|
return nullptr;
|
||
|
mapped = true;
|
||
|
return data;
|
||
|
}
|
||
|
void unmap() override {
|
||
|
mapped = false;
|
||
|
vkUnmapMemory(inner_device, device_memory);
|
||
|
}
|
||
|
|
||
|
void update_buffer(const void* src, uint32_t size) {
|
||
|
void* dst = nullptr;
|
||
|
if(vkMapMemory(inner_device, device_memory, 0, size, 0, &dst) != VK_SUCCESS) {
|
||
|
std::cout << "map error!" << std::endl;
|
||
|
return;
|
||
|
}
|
||
|
memcpy(dst, src, size);
|
||
|
vkUnmapMemory(inner_device, device_memory);
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
VkDevice inner_device;
|
||
|
VkBuffer buffer;
|
||
|
VkDeviceMemory device_memory;
|
||
|
size_t mem_size;
|
||
|
bool mapped = false;
|
||
|
bool host_visible;
|
||
|
};
|
||
|
|
||
|
class ImageViewImpl : public ImageView {
|
||
|
public:
|
||
|
ImageViewImpl(VkDevice device, VkImageView handle, std::shared_ptr<Image> image)
|
||
|
: device(device), imageview(handle), image(image) {}
|
||
|
ImageViewImpl(const ImageViewImpl&) = delete;
|
||
|
ImageViewImpl(ImageViewImpl&& iv) {
|
||
|
device = iv.device;
|
||
|
imageview = iv.imageview;
|
||
|
iv.imageview = nullptr;
|
||
|
};
|
||
|
~ImageViewImpl() {
|
||
|
if(imageview != nullptr)
|
||
|
vkDestroyImageView(device, imageview, nullptr);
|
||
|
}
|
||
|
|
||
|
VkImageView handle() const override {
|
||
|
return imageview;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
VkDevice device;
|
||
|
VkImageView imageview;
|
||
|
std::shared_ptr<Image> image;
|
||
|
};
|
||
|
|
||
|
class ImageImpl : public Image, public std::enable_shared_from_this<ImageImpl> {
|
||
|
public:
|
||
|
ImageImpl(VkDevice device, VkImage handle, VkDeviceMemory memory, VkFormat format, bool host_visible)
|
||
|
: inner_device(device), image(handle), device_memory(memory), format(format), host_visible(host_visible) {}
|
||
|
ImageImpl(const ImageImpl&) = delete;
|
||
|
~ImageImpl() {
|
||
|
vkDestroyImage(inner_device, image, nullptr);
|
||
|
vkFreeMemory(inner_device, device_memory, nullptr);
|
||
|
}
|
||
|
|
||
|
VkImage handle() const override { return image; }
|
||
|
|
||
|
std::shared_ptr<ImageView> create_view(VkFormat view_format, VkImageAspectFlags aspect) override {
|
||
|
VkImageViewCreateInfo view_info;
|
||
|
view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||
|
view_info.pNext = nullptr;
|
||
|
view_info.flags = 0;
|
||
|
view_info.image = image;
|
||
|
view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||
|
view_info.format = view_format;
|
||
|
view_info.subresourceRange = {aspect, 0u, 1u, 0u, 1u};
|
||
|
view_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||
|
view_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||
|
view_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||
|
view_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||
|
VkImageView image_view;
|
||
|
if (vkCreateImageView(inner_device, &view_info, nullptr, &image_view) != VK_SUCCESS)
|
||
|
return nullptr;
|
||
|
return std::make_shared<ImageViewImpl>(inner_device, image_view, shared_from_this());
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
VkDevice inner_device;
|
||
|
VkImage image;
|
||
|
VkDeviceMemory device_memory;
|
||
|
bool mapped = false;
|
||
|
bool host_visible;
|
||
|
VkFormat format;
|
||
|
};
|
||
|
|
||
|
class SamplerImpl : public Sampler {
|
||
|
public:
|
||
|
SamplerImpl(VkDevice device, VkSampler handle) : inner_device(device), sampler(handle) {}
|
||
|
SamplerImpl(const SamplerImpl&) = delete;
|
||
|
~SamplerImpl() {
|
||
|
vkDestroySampler(inner_device, sampler, nullptr);
|
||
|
}
|
||
|
|
||
|
VkSampler handle() const override { return sampler; }
|
||
|
|
||
|
private:
|
||
|
VkDevice inner_device;
|
||
|
VkSampler sampler;
|
||
|
};
|
||
|
|
||
|
class ShaderModuleImpl : public ShaderModule {
|
||
|
public:
|
||
|
ShaderModuleImpl(VkDevice device, VkShaderModule handle) : inner_device(device), shader_module(handle) {}
|
||
|
ShaderModuleImpl(const ShaderModuleImpl&) = delete;
|
||
|
~ShaderModuleImpl() {
|
||
|
vkDestroyShaderModule(inner_device, shader_module, nullptr);
|
||
|
};
|
||
|
|
||
|
VkShaderModule handle() const override { return shader_module; }
|
||
|
|
||
|
private:
|
||
|
VkDevice inner_device;
|
||
|
VkShaderModule shader_module;
|
||
|
};
|
||
|
|
||
|
class SwapchainImpl : public Swapchain {
|
||
|
public:
|
||
|
SwapchainImpl(VkDevice device, VkSwapchainKHR handle, VkFormat fmt) : inner_device(device), swapchain(handle), format(fmt) {
|
||
|
uint32_t swapchain_image_count = 0;
|
||
|
vkGetSwapchainImagesKHR(device, swapchain, &swapchain_image_count, nullptr);
|
||
|
rs::vector<VkImage> swapchain_images(swapchain_image_count);
|
||
|
vkGetSwapchainImagesKHR(device, swapchain, &swapchain_image_count, swapchain_images.data());
|
||
|
for(VkImage img : swapchain_images) {
|
||
|
VkImageViewCreateInfo imageview_create_info;
|
||
|
imageview_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||
|
imageview_create_info.pNext = nullptr;
|
||
|
imageview_create_info.flags = 0;
|
||
|
imageview_create_info.image = img;
|
||
|
imageview_create_info.format = format;
|
||
|
imageview_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||
|
imageview_create_info.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
|
||
|
imageview_create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||
|
imageview_create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||
|
imageview_create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||
|
imageview_create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||
|
VkImageView view;
|
||
|
vkCreateImageView(device, &imageview_create_info, nullptr, &view);
|
||
|
swapchain_imageviews.emplace_back(device, view, nullptr);
|
||
|
}
|
||
|
}
|
||
|
SwapchainImpl(const SwapchainImpl&) = delete;
|
||
|
~SwapchainImpl() {
|
||
|
vkDestroySwapchainKHR(inner_device, swapchain, nullptr);
|
||
|
}
|
||
|
|
||
|
VkSwapchainKHR handle() const override { return swapchain;}
|
||
|
uint32_t image_count() const override { return swapchain_imageviews.size(); }
|
||
|
|
||
|
rs::vector<ImageView*> get_swapchain_images() override {
|
||
|
return swapchain_imageviews.into_iter_mptr().map([](ImageViewImpl* iv) {
|
||
|
return static_cast<ImageView*>(iv);
|
||
|
}).collect<rs::vector<ImageView*>>();
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
VkDevice inner_device;
|
||
|
VkSwapchainKHR swapchain;
|
||
|
VkFormat format;
|
||
|
rs::vector<ImageViewImpl> swapchain_imageviews;
|
||
|
};
|
||
|
|
||
|
class RenderPassImpl : public RenderPass {
|
||
|
public:
|
||
|
RenderPassImpl(VkDevice device, VkRenderPass handle) : inner_device(device), render_pass(handle) {}
|
||
|
RenderPassImpl(const RenderPassImpl&) = delete;
|
||
|
~RenderPassImpl() {
|
||
|
vkDestroyRenderPass(inner_device, render_pass, nullptr);
|
||
|
}
|
||
|
|
||
|
VkRenderPass handle() const override {return render_pass; }
|
||
|
|
||
|
private:
|
||
|
VkDevice inner_device;
|
||
|
VkRenderPass render_pass;
|
||
|
};
|
||
|
|
||
|
class DescriptorSetImpl : public DescriptorSet {
|
||
|
public:
|
||
|
DescriptorSetImpl(VkDevice device, VkDescriptorSet handle, std::weak_ptr<DescriptorPool> pool)
|
||
|
: inner_device(device), descriptor_set(handle), pool(pool) {}
|
||
|
DescriptorSetImpl(const DescriptorSetImpl&) = delete;
|
||
|
~DescriptorSetImpl() {
|
||
|
if(auto pool_ptr = pool.lock(); pool_ptr != nullptr)
|
||
|
vkFreeDescriptorSets(inner_device, pool_ptr->handle(), 1, &descriptor_set);
|
||
|
}
|
||
|
VkDescriptorSet handle() const override { return descriptor_set; }
|
||
|
|
||
|
DescriptorSet& update_write(VkDescriptorType type, uint32_t binding, uint32_t start_index) {
|
||
|
VkWriteDescriptorSet descriptor_write;
|
||
|
descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||
|
descriptor_write.pNext = nullptr;
|
||
|
descriptor_write.dstSet = descriptor_set;
|
||
|
descriptor_write.dstBinding = binding;
|
||
|
descriptor_write.descriptorType = type;
|
||
|
descriptor_write.dstArrayElement = start_index;
|
||
|
descriptor_write.descriptorCount = 0;
|
||
|
descriptor_write.pBufferInfo = nullptr;
|
||
|
descriptor_write.pImageInfo = nullptr;
|
||
|
descriptor_write.pTexelBufferView = nullptr;
|
||
|
write_info.push_back(descriptor_write);
|
||
|
return *this;
|
||
|
}
|
||
|
DescriptorSet& update_write_buffer_info(const Buffer& buffer, uint32_t offset, uint32_t range, uint32_t rep_count) override {
|
||
|
VkDescriptorBufferInfo buffer_info;
|
||
|
buffer_info.buffer = buffer.handle();
|
||
|
buffer_info.offset = offset;
|
||
|
buffer_info.range = range;
|
||
|
for(uint32_t i = 0; i < rep_count; ++i)
|
||
|
write_buffer_info.push_back(buffer_info);
|
||
|
write_info.back().pBufferInfo = write_buffer_info.data();
|
||
|
write_info.back().descriptorCount = write_buffer_info.size();
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
DescriptorSet& update_write_image_info(const ImageView& view, const Sampler& sampler) override {
|
||
|
VkDescriptorImageInfo image_info;
|
||
|
image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||
|
image_info.imageView = view.handle();
|
||
|
image_info.sampler = sampler.handle();
|
||
|
write_image_info.push_back(image_info);
|
||
|
write_info.back().pImageInfo = write_image_info.data();
|
||
|
write_info.back().descriptorCount = write_image_info.size();
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
virtual DescriptorSet& update_end() override {
|
||
|
if(!write_info.empty()) {
|
||
|
vkUpdateDescriptorSets(inner_device, write_info.size(), write_info.data(), 0, nullptr);
|
||
|
write_buffer_info.clear();
|
||
|
write_image_info.clear();
|
||
|
write_info.clear();
|
||
|
}
|
||
|
return *this;
|
||
|
}
|
||
|
private:
|
||
|
VkDevice inner_device;
|
||
|
VkDescriptorSet descriptor_set;
|
||
|
std::weak_ptr<DescriptorPool> pool;
|
||
|
rs::vector<VkDescriptorBufferInfo> write_buffer_info;
|
||
|
rs::vector<VkDescriptorImageInfo> write_image_info;
|
||
|
rs::vector<VkWriteDescriptorSet> write_info;
|
||
|
};
|
||
|
|
||
|
class DescriptorSetLayoutImpl : public DescriptorSetLayout {
|
||
|
public:
|
||
|
DescriptorSetLayoutImpl(VkDevice device, VkDescriptorSetLayout handle) : inner_device(device), layout(handle) {}
|
||
|
DescriptorSetLayoutImpl(const DescriptorSetLayoutImpl&) = delete;
|
||
|
~DescriptorSetLayoutImpl() {
|
||
|
vkDestroyDescriptorSetLayout(inner_device, layout, nullptr);
|
||
|
}
|
||
|
|
||
|
VkDescriptorSetLayout handle() const override { return layout; }
|
||
|
|
||
|
private:
|
||
|
VkDevice inner_device;
|
||
|
VkDescriptorSetLayout layout;
|
||
|
};
|
||
|
|
||
|
class DescriptorPoolImpl : public DescriptorPool, public std::enable_shared_from_this<DescriptorPoolImpl> {
|
||
|
public:
|
||
|
DescriptorPoolImpl(VkDevice device, VkDescriptorPool handle, VkDescriptorPoolCreateFlags flags)
|
||
|
: inner_device(device), pool(handle), flags(flags) {}
|
||
|
DescriptorPoolImpl(const DescriptorPoolImpl&) = delete;
|
||
|
~DescriptorPoolImpl() {
|
||
|
vkDestroyDescriptorPool(inner_device, pool, nullptr);
|
||
|
}
|
||
|
|
||
|
VkDescriptorPool handle() const override { return pool; }
|
||
|
|
||
|
rs::vector<std::shared_ptr<DescriptorSet>> alloc_descriptor_set(const DescriptorSetLayout& layout, uint32_t count) override {
|
||
|
std::vector<VkDescriptorSetLayout> layouts(count, layout.handle());
|
||
|
VkDescriptorSetAllocateInfo alloc_info;
|
||
|
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||
|
alloc_info.pNext = nullptr;
|
||
|
alloc_info.descriptorPool = pool;
|
||
|
alloc_info.descriptorSetCount = count;
|
||
|
alloc_info.pSetLayouts = layouts.data();
|
||
|
std::vector<VkDescriptorSet> sets(count);
|
||
|
if(vkAllocateDescriptorSets(inner_device, &alloc_info, sets.data()) != VK_SUCCESS)
|
||
|
return {};
|
||
|
rs::vector<std::shared_ptr<DescriptorSet>> descriptor_sets;
|
||
|
std::weak_ptr<DescriptorPool> ptr = (flags & VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT) ? shared_from_this() : nullptr;
|
||
|
for(auto& ds : sets)
|
||
|
descriptor_sets.emplace_back(new DescriptorSetImpl(inner_device, ds, ptr));
|
||
|
return descriptor_sets;
|
||
|
}
|
||
|
|
||
|
void reset() override {
|
||
|
vkResetDescriptorPool(inner_device, pool, 0);
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
VkDevice inner_device;
|
||
|
VkDescriptorPool pool;
|
||
|
VkDescriptorPoolCreateFlags flags = 0;
|
||
|
};
|
||
|
|
||
|
class PipelineImpl : public Pipeline {
|
||
|
public:
|
||
|
PipelineImpl(VkDevice device, VkPipeline handle, VkPipelineLayout layout)
|
||
|
: inner_device(device), pipeline(handle), pipeline_layout(layout) {}
|
||
|
PipelineImpl(const RenderPassImpl&) = delete;
|
||
|
~PipelineImpl() {
|
||
|
vkDestroyPipeline(inner_device, pipeline, nullptr);
|
||
|
vkDestroyPipelineLayout(inner_device, pipeline_layout, nullptr);
|
||
|
}
|
||
|
|
||
|
VkPipeline handle() const override { return pipeline; }
|
||
|
VkPipelineLayout layout() const override { return pipeline_layout; }
|
||
|
|
||
|
private:
|
||
|
VkDevice inner_device;
|
||
|
VkPipeline pipeline;
|
||
|
VkPipelineLayout pipeline_layout;
|
||
|
};
|
||
|
|
||
|
class FramebufferImpl : public Framebuffer {
|
||
|
public:
|
||
|
FramebufferImpl(VkDevice device, VkFramebuffer handle, VkExtent2D sz) : inner_device(device), framebuffer(handle), fsize(sz) {}
|
||
|
FramebufferImpl(const FramebufferImpl&) = delete;
|
||
|
~FramebufferImpl() {
|
||
|
vkDestroyFramebuffer(inner_device, framebuffer, nullptr);
|
||
|
}
|
||
|
|
||
|
VkFramebuffer handle() const override { return framebuffer; }
|
||
|
VkExtent2D size() const override { return fsize; }
|
||
|
|
||
|
private:
|
||
|
VkExtent2D fsize;
|
||
|
VkDevice inner_device;
|
||
|
VkFramebuffer framebuffer;
|
||
|
};
|
||
|
|
||
|
class CommandPipelineBarrierBuilderImpl : public CommandPipelineBarrierBuilder {
|
||
|
public:
|
||
|
CommandPipelineBarrierBuilderImpl(CommandBuffer* pcmd, VkPipelineStageFlags src, VkPipelineStageFlags dst)
|
||
|
: cmd_buffer(pcmd), src(src), dst(dst) {}
|
||
|
|
||
|
CommandPipelineBarrierBuilder& add_image_memory_barrior(const Image& img) override {
|
||
|
VkImageMemoryBarrier barrier;
|
||
|
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||
|
barrier.pNext = nullptr;
|
||
|
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||
|
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||
|
barrier.image = img.handle();
|
||
|
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||
|
barrier.subresourceRange.baseMipLevel = 0;
|
||
|
barrier.subresourceRange.levelCount = 1;
|
||
|
barrier.subresourceRange.baseArrayLayer = 0;
|
||
|
barrier.subresourceRange.layerCount = 1;
|
||
|
image_barriors.push_back(barrier);
|
||
|
return *this;
|
||
|
}
|
||
|
CommandPipelineBarrierBuilder& image_set_layout(VkImageLayout old_layout, VkImageLayout new_layout) {
|
||
|
image_barriors.back().oldLayout = old_layout;
|
||
|
image_barriors.back().newLayout = new_layout;
|
||
|
return *this;
|
||
|
}
|
||
|
CommandPipelineBarrierBuilder& image_set_aspect_mask(VkImageAspectFlags aspect_mask) {
|
||
|
image_barriors.back().subresourceRange.aspectMask = aspect_mask;
|
||
|
return *this;
|
||
|
}
|
||
|
CommandPipelineBarrierBuilder& image_set_access_mask(VkAccessFlags src, VkAccessFlags dst) {
|
||
|
image_barriors.back().srcAccessMask = src;
|
||
|
image_barriors.back().dstAccessMask = dst;
|
||
|
return *this;
|
||
|
}
|
||
|
CommandBuffer& end_pipeline_barrior() {
|
||
|
auto d = defer([this](){delete this;});
|
||
|
vkCmdPipelineBarrier(
|
||
|
cmd_buffer->handle(), src, dst, 0,
|
||
|
mem_barriors.size(), (mem_barriors.empty() ? nullptr : mem_barriors.data()),
|
||
|
buffer_barriors.size(), (buffer_barriors.empty() ? nullptr : buffer_barriors.data()),
|
||
|
image_barriors.size(), (image_barriors.empty() ? nullptr : image_barriors.data())
|
||
|
);
|
||
|
return *cmd_buffer;
|
||
|
}
|
||
|
private:
|
||
|
rs::vector<VkMemoryBarrier> mem_barriors;
|
||
|
rs::vector<VkBufferMemoryBarrier> buffer_barriors;
|
||
|
rs::vector<VkImageMemoryBarrier> image_barriors;
|
||
|
CommandBuffer* cmd_buffer;
|
||
|
VkPipelineStageFlags src;
|
||
|
VkPipelineStageFlags dst;
|
||
|
};
|
||
|
|
||
|
class CommandBufferCopyBuilderImpl : public CommandBufferCopyBuilder {
|
||
|
public:
|
||
|
CommandBufferCopyBuilderImpl(CommandBuffer* pcmd, const Buffer& src, const Buffer& dst)
|
||
|
: cmd_buffer(pcmd), src(src.handle()), dst(dst.handle()) {}
|
||
|
CommandBufferCopyBuilder& add_region(uint32_t src_offset, uint32_t dst_offset, uint32_t size) override {
|
||
|
VkBufferCopy region;
|
||
|
region.srcOffset = src_offset;
|
||
|
region.dstOffset = dst_offset;
|
||
|
region.size = size;
|
||
|
regions.push_back(region);
|
||
|
return *this;
|
||
|
}
|
||
|
CommandBuffer& end_buffer_copy() override {
|
||
|
auto d = defer([this](){delete this;});
|
||
|
if(!regions.empty())
|
||
|
vkCmdCopyBuffer(cmd_buffer->handle(), src, dst, regions.size(), regions.data());
|
||
|
return *cmd_buffer;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
CommandBuffer* cmd_buffer;
|
||
|
VkBuffer src;
|
||
|
VkBuffer dst;
|
||
|
rs::vector<VkBufferCopy> regions;
|
||
|
};
|
||
|
|
||
|
class CommandBufferImageCopyBuilderImpl : public CommandBufferImageCopyBuilder {
|
||
|
public:
|
||
|
CommandBufferImageCopyBuilderImpl(CommandBuffer* pcmd, const Buffer& buffer, const Image& img)
|
||
|
: cmd_buffer(pcmd), buffer(buffer.handle()), image(img.handle()) {}
|
||
|
CommandBufferImageCopyBuilder& add_region(uint32_t offset, VkOffset3D img_offset, VkExtent3D img_extent) override {
|
||
|
VkBufferImageCopy region;
|
||
|
region.bufferOffset = offset;
|
||
|
region.bufferRowLength = 0;
|
||
|
region.bufferImageHeight = 0;
|
||
|
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||
|
region.imageSubresource.mipLevel = 0;
|
||
|
region.imageSubresource.baseArrayLayer = 0;
|
||
|
region.imageSubresource.layerCount = 1;
|
||
|
region.imageOffset = img_offset;
|
||
|
region.imageExtent = img_extent;
|
||
|
regions.push_back(region);
|
||
|
return *this;
|
||
|
}
|
||
|
CommandBuffer& end_buffer_image_copy() override {
|
||
|
auto d = defer([this](){delete this;});
|
||
|
if(!regions.empty())
|
||
|
vkCmdCopyBufferToImage(cmd_buffer->handle(), buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, regions.size(), regions.data());
|
||
|
return *cmd_buffer;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
CommandBuffer* cmd_buffer;
|
||
|
VkBuffer buffer;
|
||
|
VkImage image;
|
||
|
rs::vector<VkBufferImageCopy> regions;
|
||
|
};
|
||
|
|
||
|
class CommandBufferImpl : public CommandBuffer {
|
||
|
public:
|
||
|
CommandBufferImpl(VkDevice device, VkCommandBuffer buffer, std::weak_ptr<CommandPool> pool)
|
||
|
: inner_device(device), command_buffer(buffer), weak_pool(pool) {}
|
||
|
CommandBufferImpl(const CommandBufferImpl&) = delete;
|
||
|
~CommandBufferImpl() {
|
||
|
if(auto pool = weak_pool.lock(); pool != nullptr)
|
||
|
vkFreeCommandBuffers(inner_device, pool->handle(), 1, &command_buffer);
|
||
|
}
|
||
|
|
||
|
VkCommandBuffer handle() const override { return command_buffer; }
|
||
|
CommandBuffer& begin_command(VkCommandBufferUsageFlags flag) override {
|
||
|
VkCommandBufferBeginInfo begin_info;
|
||
|
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||
|
begin_info.pNext = nullptr;
|
||
|
begin_info.flags = flag;
|
||
|
begin_info.pInheritanceInfo = nullptr;
|
||
|
vkBeginCommandBuffer(command_buffer, &begin_info);
|
||
|
return *this;
|
||
|
}
|
||
|
void end_command() override {
|
||
|
vkEndCommandBuffer(command_buffer);
|
||
|
}
|
||
|
CommandBuffer& begin_render_pass(const RenderPass& pass, const Framebuffer& buffer, VkClearValue c) override {
|
||
|
VkClearValue cvalues[2] = {c, {1.0f, 0}};
|
||
|
VkRenderPassBeginInfo render_pass_info;
|
||
|
render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||
|
render_pass_info.pNext = nullptr;
|
||
|
render_pass_info.renderPass = pass.handle();
|
||
|
render_pass_info.renderArea = {{0, 0}, buffer.size()};
|
||
|
render_pass_info.framebuffer = buffer.handle();
|
||
|
render_pass_info.clearValueCount = 2;
|
||
|
render_pass_info.pClearValues = cvalues;
|
||
|
vkCmdBeginRenderPass(command_buffer, &render_pass_info, VK_SUBPASS_CONTENTS_INLINE);
|
||
|
return *this;
|
||
|
}
|
||
|
CommandBuffer& end_render_pass() override {
|
||
|
vkCmdEndRenderPass(command_buffer);
|
||
|
return *this;
|
||
|
}
|
||
|
CommandBuffer& bind_pipeline(const Pipeline& pipeline) override {
|
||
|
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.handle());
|
||
|
return *this;
|
||
|
}
|
||
|
CommandBuffer& bind_pipeline_and_descriptor_sets(const Pipeline& pipeline, const DescriptorSet& sets) override {
|
||
|
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.handle());
|
||
|
auto descriptor_set = sets.handle();
|
||
|
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.layout(), 0, 1, &descriptor_set, 0, nullptr);
|
||
|
return *this;
|
||
|
}
|
||
|
CommandBuffer& draw(uint32_t count) override {
|
||
|
vkCmdDraw(command_buffer, count, 1, 0, 0);
|
||
|
return *this;
|
||
|
}
|
||
|
CommandBuffer& draw_vertices(const Buffer& vertex_buffer, uint32_t count) override {
|
||
|
VkBuffer buffers[] = {vertex_buffer.handle()};
|
||
|
VkDeviceSize offsets[] = {0};
|
||
|
vkCmdBindVertexBuffers(command_buffer, 0, 1, buffers, offsets);
|
||
|
vkCmdDraw(command_buffer, count, 1, 0, 0);
|
||
|
return *this;
|
||
|
}
|
||
|
CommandBuffer& draw_indexed(const Buffer& vertex_buffer, const Buffer& index_buffer, uint32_t count) override {
|
||
|
VkBuffer buffers[] = {vertex_buffer.handle()};
|
||
|
VkDeviceSize offsets[] = {0};
|
||
|
vkCmdBindVertexBuffers(command_buffer, 0, 1, buffers, offsets);
|
||
|
vkCmdBindIndexBuffer(command_buffer, index_buffer.handle(), 0, VK_INDEX_TYPE_UINT32);
|
||
|
vkCmdDrawIndexed(command_buffer, count, 1, 0, 0, 0);
|
||
|
return *this;
|
||
|
}
|
||
|
CommandPipelineBarrierBuilder& begin_pipeline_barrior(VkPipelineStageFlags src, VkPipelineStageFlags dst) override {
|
||
|
return *(new CommandPipelineBarrierBuilderImpl(this, src, dst));
|
||
|
}
|
||
|
CommandBufferCopyBuilder& begin_copy_buffer(const Buffer& src, const Buffer& dst) override {
|
||
|
return *(new CommandBufferCopyBuilderImpl(this, src, dst));
|
||
|
}
|
||
|
CommandBufferImageCopyBuilder& begin_copy_buffer_to_image(const Buffer& src, const Image& dst) override {
|
||
|
return *(new CommandBufferImageCopyBuilderImpl(this, src, dst));
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
VkDevice inner_device;
|
||
|
VkCommandBuffer command_buffer;
|
||
|
std::weak_ptr<CommandPool> weak_pool;
|
||
|
};
|
||
|
|
||
|
class CommandPoolImpl : public CommandPool, public std::enable_shared_from_this<CommandPoolImpl> {
|
||
|
public:
|
||
|
CommandPoolImpl(VkDevice device, VkCommandPool pool) : inner_device(device), command_pool(pool) {}
|
||
|
~CommandPoolImpl() {
|
||
|
vkDestroyCommandPool(inner_device, command_pool, nullptr);
|
||
|
}
|
||
|
VkCommandPool handle() const override { return command_pool; }
|
||
|
rs::vector<std::shared_ptr<CommandBuffer>> alloc_command_buffer(VkCommandBufferLevel level, uint32_t count) override {
|
||
|
rs::vector<std::shared_ptr<CommandBuffer>> results;
|
||
|
alloc_command_buffer(results, level, count);
|
||
|
return results;
|
||
|
}
|
||
|
|
||
|
CommandPool& alloc_command_buffer(rs::vector<std::shared_ptr<CommandBuffer>>& vec, VkCommandBufferLevel level, uint32_t count) override {
|
||
|
rs::vector<VkCommandBuffer> command_buffers(count);
|
||
|
VkCommandBufferAllocateInfo alloc_info;
|
||
|
alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||
|
alloc_info.pNext = nullptr;
|
||
|
alloc_info.commandPool = command_pool;
|
||
|
alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||
|
alloc_info.commandBufferCount = (uint32_t) command_buffers.size();
|
||
|
if(vkAllocateCommandBuffers(inner_device, &alloc_info, command_buffers.data()) != VK_SUCCESS)
|
||
|
return *this;
|
||
|
std::weak_ptr<CommandPool> pool = shared_from_this();
|
||
|
for(auto& buf : command_buffers)
|
||
|
vec.emplace_back(new CommandBufferImpl(inner_device, buf, pool));
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
VkDevice inner_device;
|
||
|
VkCommandPool command_pool;
|
||
|
};
|
||
|
|
||
|
class RendererImpl : public Renderer {
|
||
|
public:
|
||
|
RendererImpl(VkDevice device, uint32_t count) : inner_device(device) {
|
||
|
img_count = count;
|
||
|
current_frame = 0;
|
||
|
image_semaphore.resize(img_count);
|
||
|
signal_semaphore.resize(img_count);
|
||
|
submit_fence.resize(img_count);
|
||
|
VkSemaphoreCreateInfo semaphore_info;
|
||
|
semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||
|
semaphore_info.pNext = nullptr;
|
||
|
semaphore_info.flags = 0;
|
||
|
VkFenceCreateInfo fence_info;
|
||
|
fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||
|
fence_info.pNext = nullptr;
|
||
|
fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||
|
|
||
|
for(uint32_t i = 0; i < img_count; ++i) {
|
||
|
vkCreateSemaphore(device, &semaphore_info, nullptr, &image_semaphore[i]);
|
||
|
vkCreateSemaphore(device, &semaphore_info, nullptr, &signal_semaphore[i]);
|
||
|
vkCreateFence(device, &fence_info, nullptr, &submit_fence[i]);
|
||
|
}
|
||
|
}
|
||
|
RendererImpl(const RendererImpl&) = delete;
|
||
|
~RendererImpl() {
|
||
|
for(uint32_t i = 0; i < img_count; ++i) {
|
||
|
vkDestroySemaphore(inner_device, image_semaphore[i], nullptr);
|
||
|
vkDestroySemaphore(inner_device, signal_semaphore[i], nullptr);
|
||
|
vkDestroyFence(inner_device, submit_fence[i], nullptr);
|
||
|
}
|
||
|
}
|
||
|
uint32_t prepare_for_next_frame() override {
|
||
|
current_index = current_frame % img_count;
|
||
|
current_frame++;
|
||
|
vkWaitForFences(inner_device, 1, &submit_fence[current_index], VK_TRUE, std::numeric_limits<uint64_t>::max());
|
||
|
vkResetFences(inner_device, 1, &submit_fence[current_index]);
|
||
|
outofdate = false;
|
||
|
return current_index;
|
||
|
}
|
||
|
uint32_t accquire_next_image(const Swapchain& swapchain) override {
|
||
|
uint32_t image_index = 0;
|
||
|
auto result = vkAcquireNextImageKHR(inner_device, swapchain.handle(), std::numeric_limits<uint64_t>::max(),
|
||
|
image_semaphore[current_index], nullptr, &image_index);
|
||
|
if(result == VK_ERROR_OUT_OF_DATE_KHR)
|
||
|
outofdate = true;
|
||
|
return image_index;
|
||
|
}
|
||
|
Renderer& submit_draw_command(const Queue& queue, const CommandBuffer& command_buffer) override {
|
||
|
VkPipelineStageFlags wait_stages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
|
||
|
VkSubmitInfo submit_info;
|
||
|
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||
|
submit_info.pNext = nullptr;
|
||
|
submit_info.waitSemaphoreCount = 1;
|
||
|
submit_info.pWaitSemaphores = &image_semaphore[current_index];
|
||
|
submit_info.pWaitDstStageMask = wait_stages;
|
||
|
submit_info.commandBufferCount = 1;
|
||
|
auto cmd = command_buffer.handle();
|
||
|
submit_info.pCommandBuffers = &cmd;
|
||
|
submit_info.signalSemaphoreCount = 1;
|
||
|
submit_info.pSignalSemaphores = &signal_semaphore[current_index];
|
||
|
vkQueueSubmit(queue.handle, 1, &submit_info, submit_fence[current_index]);
|
||
|
return *this;
|
||
|
}
|
||
|
Renderer& present(const Queue& queue, const Swapchain& swapchain, uint32_t index) override {
|
||
|
VkSwapchainKHR swapchains[] = {swapchain.handle()};
|
||
|
VkPresentInfoKHR present_info;
|
||
|
present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||
|
present_info.pNext = nullptr;
|
||
|
present_info.waitSemaphoreCount = 1;
|
||
|
present_info.pWaitSemaphores = &signal_semaphore[current_index];
|
||
|
present_info.swapchainCount = 1;
|
||
|
present_info.pSwapchains = swapchains;
|
||
|
present_info.pImageIndices = &index;
|
||
|
present_info.pResults = nullptr;
|
||
|
if(vkQueuePresentKHR(queue.handle, &present_info) == VK_ERROR_OUT_OF_DATE_KHR)
|
||
|
outofdate = true;
|
||
|
return *this;
|
||
|
}
|
||
|
Renderer& wait_idle(const Queue& queue) override {
|
||
|
vkQueueWaitIdle(queue.handle);
|
||
|
return *this;
|
||
|
}
|
||
|
Renderer& submit_onetime_command(const Queue& queue, rs::vector<std::shared_ptr<CommandBuffer>>& command_buffers) override {
|
||
|
rs::vector<VkCommandBuffer> cmds;
|
||
|
for(auto& ptr : command_buffers)
|
||
|
cmds.push_back(ptr->handle());
|
||
|
VkSubmitInfo submitInfo = {};
|
||
|
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||
|
submitInfo.commandBufferCount = cmds.size();
|
||
|
submitInfo.pCommandBuffers = cmds.data();
|
||
|
vkQueueSubmit(queue.handle, 1, &submitInfo, VK_NULL_HANDLE);
|
||
|
return *this;
|
||
|
}
|
||
|
bool out_of_date() const override {
|
||
|
return outofdate;
|
||
|
}
|
||
|
private:
|
||
|
VkDevice inner_device;
|
||
|
std::vector<VkSemaphore> image_semaphore;
|
||
|
std::vector<VkSemaphore> signal_semaphore;
|
||
|
std::vector<VkFence> submit_fence;
|
||
|
uint32_t img_count = 1;
|
||
|
uint32_t current_frame = 0;
|
||
|
uint32_t current_index = 0;
|
||
|
bool outofdate = false;
|
||
|
};
|
||
|
|
||
|
rs::vector<VkLayerProperties> list_layer_properties() {
|
||
|
uint32_t layer_count = 0;
|
||
|
vkEnumerateInstanceLayerProperties(&layer_count, nullptr);
|
||
|
rs::vector<VkLayerProperties> instance_layer_props(layer_count);
|
||
|
vkEnumerateInstanceLayerProperties(&layer_count, instance_layer_props.data());
|
||
|
return instance_layer_props;
|
||
|
}
|
||
|
|
||
|
class InstanceBuilderImpl : public InstanceBuilder {
|
||
|
public:
|
||
|
InstanceBuilder& set_application_name(const char* name) { app_name = name; return *this; }
|
||
|
InstanceBuilder& set_enging_name(const char* name) { engine_name = name; return *this; }
|
||
|
InstanceBuilder& set_application_version(uint32_t ver) { app_version = ver; return *this; }
|
||
|
InstanceBuilder& set_engine_version(uint32_t ver) { engine_version = ver; return *this; }
|
||
|
InstanceBuilder& set_api_version(uint32_t ver) { api_version = ver; return *this; }
|
||
|
InstanceBuilder& set_layers(const rs::vector<const char*>& layers) { layer_names = layers; return *this; }
|
||
|
InstanceBuilder& set_extensions(const rs::vector<const char*>& extensions) { extension_names = extensions; return *this; }
|
||
|
std::shared_ptr<Instance> end() {
|
||
|
auto d = defer([this](){delete this;});
|
||
|
VkApplicationInfo app_info;
|
||
|
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
||
|
app_info.pNext = nullptr;
|
||
|
app_info.pApplicationName = app_name.c_str();
|
||
|
app_info.applicationVersion = app_version;
|
||
|
app_info.pEngineName = engine_name.c_str();
|
||
|
app_info.engineVersion = engine_version;
|
||
|
app_info.apiVersion = api_version;
|
||
|
VkInstanceCreateInfo instance_create_info;
|
||
|
instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||
|
instance_create_info.pNext = nullptr;
|
||
|
instance_create_info.flags = 0;
|
||
|
instance_create_info.pApplicationInfo = &app_info;
|
||
|
instance_create_info.enabledLayerCount = layer_names.size();
|
||
|
instance_create_info.ppEnabledLayerNames = layer_names.empty() ? nullptr : layer_names.data();
|
||
|
instance_create_info.enabledExtensionCount = extension_names.size();
|
||
|
instance_create_info.ppEnabledExtensionNames = extension_names.empty() ? nullptr : extension_names.data();
|
||
|
VkInstance handle;
|
||
|
if(vkCreateInstance(&instance_create_info, nullptr, &handle) != VK_SUCCESS)
|
||
|
return nullptr;
|
||
|
return std::shared_ptr<Instance>(new InstanceImpl(handle));
|
||
|
}
|
||
|
private:
|
||
|
std::string app_name;
|
||
|
std::string engine_name;
|
||
|
uint32_t app_version = 0;
|
||
|
uint32_t engine_version = 0;
|
||
|
uint32_t api_version = 0;
|
||
|
rs::vector<const char*> layer_names;
|
||
|
rs::vector<const char*> extension_names;
|
||
|
};
|
||
|
|
||
|
class DeviceBuilderImpl : public DeviceBuilder {
|
||
|
public:
|
||
|
DeviceBuilderImpl(const PhysicalDevice& handle) : physical_device(&handle) {}
|
||
|
DeviceBuilder& set_extensions(const rs::vector<const char*>& extensions) { extension_names = extensions; return *this; }
|
||
|
DeviceBuilder& add_queue_family(uint32_t index, float priority) { queue_infos.emplace_back(index, priority); return *this; }
|
||
|
DeviceBuilder& enable_features(const VkPhysicalDeviceFeatures& features) { enabled_features = features; return *this; }
|
||
|
std::shared_ptr<Device> end() {
|
||
|
auto d = defer([this](){delete this;});
|
||
|
auto queue_counts = physical_device->enumerate_queue_families().map([](const VkQueueFamilyProperties* q) {
|
||
|
return q->queueCount;
|
||
|
}).collect<rs::vector<uint32_t>>();
|
||
|
rs::vector<rs::vector<float>> priorities(queue_counts.size());
|
||
|
queue_infos.into_iter().for_each([&priorities, &queue_counts](uint32_t idx, float priority) {
|
||
|
if(idx >= priorities.size())
|
||
|
return;
|
||
|
if(priorities[idx].size() < queue_counts[idx])
|
||
|
priorities[idx].push_back(priority);
|
||
|
});
|
||
|
auto queue_create_infos = priorities.into_iter_ptr().enumerate().filter([](size_t idx, const rs::vector<float>* p) {
|
||
|
return p->size() > 0;
|
||
|
}).map([](size_t idx, const rs::vector<float>* p) {
|
||
|
VkDeviceQueueCreateInfo queue_create_info;
|
||
|
queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||
|
queue_create_info.pNext = nullptr;
|
||
|
queue_create_info.flags = 0;
|
||
|
queue_create_info.queueFamilyIndex = (uint32_t)idx;
|
||
|
queue_create_info.queueCount = p->size();
|
||
|
queue_create_info.pQueuePriorities = p->data();
|
||
|
return queue_create_info;
|
||
|
}).collect<rs::vector<VkDeviceQueueCreateInfo>>();
|
||
|
VkDeviceCreateInfo device_create_info;
|
||
|
device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||
|
device_create_info.pNext = nullptr;
|
||
|
device_create_info.flags = 0;
|
||
|
device_create_info.queueCreateInfoCount = (uint32_t)queue_create_infos.size();
|
||
|
device_create_info.pQueueCreateInfos = queue_create_infos.data();
|
||
|
device_create_info.enabledLayerCount = 0;
|
||
|
device_create_info.ppEnabledLayerNames = nullptr;
|
||
|
device_create_info.enabledExtensionCount = extension_names.size();
|
||
|
device_create_info.ppEnabledExtensionNames = extension_names.data();
|
||
|
device_create_info.pEnabledFeatures = &enabled_features;
|
||
|
VkDevice device;
|
||
|
if(vkCreateDevice(physical_device->handle(), &device_create_info, nullptr, &device) == VK_SUCCESS) {
|
||
|
auto queues = queue_create_infos.into_iter_ptr().flat_map([device](const VkDeviceQueueCreateInfo* pinfo) {
|
||
|
return rs::range(0u, pinfo->queueCount).map([device, pinfo](uint32_t idx) {
|
||
|
VkQueue queue;
|
||
|
vkGetDeviceQueue(device, pinfo->queueFamilyIndex, idx, &queue);
|
||
|
return Queue{queue, pinfo->queueFamilyIndex, idx};
|
||
|
});
|
||
|
}).collect<rs::vector<Queue>>();
|
||
|
return std::shared_ptr<Device>(new DeviceImpl(device, std::move(queues)));
|
||
|
}
|
||
|
return nullptr;
|
||
|
}
|
||
|
private:
|
||
|
const PhysicalDevice* physical_device;
|
||
|
rs::vector<const char*> extension_names;
|
||
|
rs::vector<std::pair<uint32_t, float>> queue_infos;
|
||
|
VkPhysicalDeviceFeatures enabled_features;
|
||
|
};
|
||
|
|
||
|
class BufferBuilderImpl : public BufferBuilder {
|
||
|
public:
|
||
|
BufferBuilderImpl(const Device& device, const PhysicalDevice& physical_device) : device(device.handle()) {
|
||
|
mem_props = physical_device.mem_properties();
|
||
|
}
|
||
|
BufferBuilder& alloc_size(size_t size) { this->size = size; return *this; }
|
||
|
BufferBuilder& set_usage(VkBufferUsageFlags usage) { this->usage = usage; return *this; }
|
||
|
BufferBuilder& set_sharing_mode(VkSharingMode mode) { this->mode = mode; return *this; }
|
||
|
BufferBuilder& set_cpu_accessible() {
|
||
|
expected_prop = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||
|
return *this;
|
||
|
}
|
||
|
BufferBuilder& set_device_local() {
|
||
|
expected_prop = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||
|
return *this;
|
||
|
}
|
||
|
std::shared_ptr<Buffer> end() {
|
||
|
auto d = defer([this](){delete this;});
|
||
|
VkBufferCreateInfo buffer_info;
|
||
|
buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||
|
buffer_info.pNext = nullptr;
|
||
|
buffer_info.flags = 0;
|
||
|
buffer_info.size = size;
|
||
|
buffer_info.usage = usage;
|
||
|
buffer_info.sharingMode = mode;
|
||
|
VkBuffer buffer;
|
||
|
if(vkCreateBuffer(device, &buffer_info, nullptr, &buffer) != VK_SUCCESS)
|
||
|
return nullptr;
|
||
|
VkMemoryRequirements mem_requirements;
|
||
|
vkGetBufferMemoryRequirements(device, buffer, &mem_requirements);
|
||
|
auto mem_index = rs::range(0u, mem_props->memoryTypeCount).find([&, this](uint32_t idx) {
|
||
|
return ((mem_requirements.memoryTypeBits & (1 << idx))
|
||
|
&& (mem_props->memoryTypes[idx].propertyFlags & expected_prop) == expected_prop);
|
||
|
}).value();
|
||
|
VkMemoryAllocateInfo alloc_info;
|
||
|
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||
|
alloc_info.pNext = nullptr;
|
||
|
alloc_info.allocationSize = mem_requirements.size;
|
||
|
alloc_info.memoryTypeIndex = mem_index;
|
||
|
VkDeviceMemory device_memory;
|
||
|
if(vkAllocateMemory(device, &alloc_info, nullptr, &device_memory) != VK_SUCCESS) {
|
||
|
vkDestroyBuffer(device, buffer, nullptr);
|
||
|
return nullptr;
|
||
|
}
|
||
|
vkBindBufferMemory(device, buffer, device_memory, 0);
|
||
|
bool host_visible = (expected_prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
|
||
|
return std::shared_ptr<Buffer>(new BufferImpl(device, buffer, device_memory, mem_requirements.size, host_visible));
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
VkDevice device;
|
||
|
const VkPhysicalDeviceMemoryProperties* mem_props;
|
||
|
uint32_t size = 0;
|
||
|
VkBufferUsageFlags usage;
|
||
|
VkSharingMode mode = VK_SHARING_MODE_EXCLUSIVE;
|
||
|
VkMemoryPropertyFlags expected_prop;
|
||
|
};
|
||
|
|
||
|
class ImageBuilderImpl : public ImageBuilder {
|
||
|
public:
|
||
|
ImageBuilderImpl(const Device& device, const PhysicalDevice& physical_device) : device(device.handle()) {
|
||
|
mem_props = physical_device.mem_properties();
|
||
|
info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||
|
info.pNext = nullptr;
|
||
|
info.flags = 0;
|
||
|
info.imageType = VK_IMAGE_TYPE_2D;
|
||
|
info.format = VK_FORMAT_B8G8R8A8_UNORM;
|
||
|
info.extent = {0u, 0u, 1u};
|
||
|
info.mipLevels = 1;
|
||
|
info.arrayLayers = 1;
|
||
|
info.samples = VK_SAMPLE_COUNT_1_BIT;
|
||
|
info.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||
|
info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||
|
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||
|
info.queueFamilyIndexCount = 0;
|
||
|
info.pQueueFamilyIndices = nullptr;
|
||
|
info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||
|
}
|
||
|
ImageBuilder& set_type(VkImageType type) { info.imageType = type; return *this; }
|
||
|
ImageBuilder& set_format(VkFormat format) { info.format = format; return *this; }
|
||
|
ImageBuilder& set_extent(VkExtent3D ext) { info.extent = ext; return *this; }
|
||
|
ImageBuilder& set_mip_level(uint32_t level) { info.mipLevels = level; return *this; }
|
||
|
ImageBuilder& set_array_layers(uint32_t layer) { info.arrayLayers = layer; return *this; }
|
||
|
ImageBuilder& set_samples(VkSampleCountFlagBits samples) { info.samples = samples; return *this; }
|
||
|
ImageBuilder& set_tilling(VkImageTiling tiling) { info.tiling = tiling; return *this; }
|
||
|
ImageBuilder& set_usage(VkImageUsageFlags usage) { info.usage = usage; return *this; }
|
||
|
ImageBuilder& set_sharing_mode(VkSharingMode mode) { info.sharingMode = mode; return *this; }
|
||
|
ImageBuilder& set_init_layout(VkImageLayout layout) { info.initialLayout = layout; return *this; }
|
||
|
ImageBuilder& set_cpu_accessible() {
|
||
|
expected_prop = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||
|
return *this;
|
||
|
}
|
||
|
ImageBuilder& set_device_local() {
|
||
|
expected_prop = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||
|
return *this;
|
||
|
}
|
||
|
std::shared_ptr<Image> end() {
|
||
|
auto d = defer([this](){delete this;});
|
||
|
VkImage image;
|
||
|
if(vkCreateImage(device, &info, nullptr, &image) != VK_SUCCESS)
|
||
|
return nullptr;
|
||
|
VkMemoryRequirements mem_requirements;
|
||
|
vkGetImageMemoryRequirements(device, image, &mem_requirements);
|
||
|
auto mem_index = rs::range(0u, mem_props->memoryTypeCount).find([&, this](uint32_t idx) {
|
||
|
return ((mem_requirements.memoryTypeBits & (1 << idx))
|
||
|
&& (mem_props->memoryTypes[idx].propertyFlags & expected_prop) == expected_prop);
|
||
|
}).value();
|
||
|
VkMemoryAllocateInfo alloc_info;
|
||
|
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||
|
alloc_info.pNext = nullptr;
|
||
|
alloc_info.allocationSize = mem_requirements.size;
|
||
|
alloc_info.memoryTypeIndex = mem_index;
|
||
|
VkDeviceMemory device_memory;
|
||
|
if(vkAllocateMemory(device, &alloc_info, nullptr, &device_memory) != VK_SUCCESS) {
|
||
|
vkDestroyImage(device, image, nullptr);
|
||
|
return nullptr;
|
||
|
}
|
||
|
vkBindImageMemory(device, image, device_memory, 0);
|
||
|
bool host_visible = (expected_prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
|
||
|
return std::make_shared<ImageImpl>(device, image, device_memory, info.format, host_visible);
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
VkDevice device;
|
||
|
const VkPhysicalDeviceMemoryProperties* mem_props;
|
||
|
VkImageCreateInfo info;
|
||
|
VkMemoryPropertyFlags expected_prop;
|
||
|
};
|
||
|
|
||
|
class SamplerBuilderImpl : public SamplerBuilder {
|
||
|
public:
|
||
|
SamplerBuilderImpl(const Device& device) : device(device.handle()) {
|
||
|
sampler_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
||
|
sampler_info.pNext = nullptr;
|
||
|
sampler_info.flags = 0;
|
||
|
sampler_info.magFilter = VK_FILTER_LINEAR;
|
||
|
sampler_info.minFilter = VK_FILTER_LINEAR;
|
||
|
sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||
|
sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||
|
sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||
|
sampler_info.anisotropyEnable = VK_FALSE;
|
||
|
sampler_info.maxAnisotropy = 0;
|
||
|
sampler_info.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
|
||
|
sampler_info.unnormalizedCoordinates = VK_FALSE;
|
||
|
sampler_info.compareEnable = VK_FALSE;
|
||
|
sampler_info.compareOp = VK_COMPARE_OP_ALWAYS;
|
||
|
sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||
|
sampler_info.mipLodBias = 0.0f;
|
||
|
sampler_info.minLod = 0.0f;
|
||
|
sampler_info.maxLod = 0.0f;
|
||
|
}
|
||
|
SamplerBuilder& set_filter(VkFilter filter) {
|
||
|
sampler_info.magFilter = filter;
|
||
|
sampler_info.minFilter = filter;
|
||
|
return *this;
|
||
|
}
|
||
|
SamplerBuilder& set_address_mode(VkSamplerAddressMode mode) {
|
||
|
sampler_info.addressModeU = mode;
|
||
|
sampler_info.addressModeV = mode;
|
||
|
sampler_info.addressModeW = mode;
|
||
|
return *this;
|
||
|
}
|
||
|
SamplerBuilder& set_anisotrophy(float value) {
|
||
|
sampler_info.anisotropyEnable = VK_TRUE;
|
||
|
sampler_info.maxAnisotropy = value;
|
||
|
return *this;
|
||
|
}
|
||
|
std::shared_ptr<Sampler> end() {
|
||
|
auto d = defer([this](){delete this;});
|
||
|
VkSampler sampler;
|
||
|
if(vkCreateSampler(device, &sampler_info, nullptr, &sampler) != VK_SUCCESS)
|
||
|
return nullptr;
|
||
|
return std::make_shared<SamplerImpl>(device, sampler);
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
VkDevice device;
|
||
|
VkSamplerCreateInfo sampler_info;
|
||
|
};
|
||
|
|
||
|
class SwapchainBuilderImpl : public SwapchainBuilder {
|
||
|
public:
|
||
|
SwapchainBuilderImpl(const Device& device) : device(device.handle()) {
|
||
|
swapchain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
||
|
swapchain_create_info.pNext = nullptr;
|
||
|
swapchain_create_info.flags = 0;
|
||
|
swapchain_create_info.surface = nullptr;
|
||
|
swapchain_create_info.minImageCount = 2;
|
||
|
swapchain_create_info.imageFormat = VK_FORMAT_B8G8R8A8_UNORM;
|
||
|
swapchain_create_info.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
|
||
|
swapchain_create_info.imageExtent = {128, 128};
|
||
|
swapchain_create_info.imageArrayLayers = 1;
|
||
|
swapchain_create_info.imageUsage = VK_IMAGE_USAGE_FLAG_BITS_MAX_ENUM;
|
||
|
swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||
|
swapchain_create_info.queueFamilyIndexCount = 0;
|
||
|
swapchain_create_info.pQueueFamilyIndices = nullptr;
|
||
|
swapchain_create_info.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
|
||
|
swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||
|
swapchain_create_info.presentMode = VK_PRESENT_MODE_FIFO_KHR;
|
||
|
swapchain_create_info.clipped = VK_TRUE;
|
||
|
swapchain_create_info.oldSwapchain = nullptr;
|
||
|
}
|
||
|
SwapchainBuilder& set_surface(const Surface& surface) { swapchain_create_info.surface = surface.handle(); return *this; }
|
||
|
SwapchainBuilder& set_min_image_count(uint32_t count) { swapchain_create_info.minImageCount = count; return *this; }
|
||
|
SwapchainBuilder& set_format(VkFormat format) { swapchain_create_info.imageFormat = format; return *this; }
|
||
|
SwapchainBuilder& set_colorspace(VkColorSpaceKHR colorspace) { swapchain_create_info.imageColorSpace = colorspace; return *this; }
|
||
|
SwapchainBuilder& set_extent(VkExtent2D ext) { swapchain_create_info.imageExtent = ext; return *this; }
|
||
|
SwapchainBuilder& set_array_layer(uint32_t array_layer) { swapchain_create_info.imageArrayLayers = array_layer; return *this; }
|
||
|
SwapchainBuilder& set_image_usage(VkImageUsageFlags usage) { swapchain_create_info.imageUsage = usage; return *this; }
|
||
|
SwapchainBuilder& set_queue_family_indices(const rs::vector<uint32_t>& queue_family_indices) {
|
||
|
if(queue_family_indices.size() <= 1) {
|
||
|
swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||
|
swapchain_create_info.queueFamilyIndexCount = 0;
|
||
|
swapchain_create_info.pQueueFamilyIndices = nullptr;
|
||
|
} else {
|
||
|
swapchain_create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
||
|
swapchain_create_info.queueFamilyIndexCount = queue_family_indices.size();
|
||
|
swapchain_create_info.pQueueFamilyIndices = queue_family_indices.data();
|
||
|
}
|
||
|
return *this;
|
||
|
}
|
||
|
SwapchainBuilder& set_transform(VkSurfaceTransformFlagBitsKHR transform) { swapchain_create_info.preTransform = transform; return *this; }
|
||
|
SwapchainBuilder& set_composite_alpha(VkCompositeAlphaFlagBitsKHR alpha) { swapchain_create_info.compositeAlpha = alpha; return *this; }
|
||
|
SwapchainBuilder& set_present_mode(VkPresentModeKHR mode) { swapchain_create_info.presentMode = mode; return *this; }
|
||
|
SwapchainBuilder& set_clipped(VkBool32 clipped) { swapchain_create_info.clipped = clipped; return *this; }
|
||
|
SwapchainBuilder& set_old_swapchain(Swapchain& old) { swapchain_create_info.oldSwapchain = old.handle(); return *this; }
|
||
|
std::shared_ptr<Swapchain> end() {
|
||
|
auto d = defer([this](){delete this;});
|
||
|
VkSwapchainKHR swapchain;
|
||
|
if(vkCreateSwapchainKHR(device, &swapchain_create_info, nullptr, &swapchain) != VK_SUCCESS)
|
||
|
return nullptr;
|
||
|
return std::shared_ptr<Swapchain>(new SwapchainImpl(device, swapchain, swapchain_create_info.imageFormat));
|
||
|
}
|
||
|
private:
|
||
|
VkDevice device;
|
||
|
VkSwapchainCreateInfoKHR swapchain_create_info;
|
||
|
};
|
||
|
|
||
|
class RenderPassBuilderImpl : public RenderPassBuilder {
|
||
|
public:
|
||
|
RenderPassBuilderImpl(const Device& device) : device(device.handle()) {}
|
||
|
|
||
|
RenderPassBuilder& set_format(VkFormat format) { color_format = format; return *this; }
|
||
|
RenderPassBuilder& set_samples(VkSampleCountFlagBits samples) { this->samples = samples; return *this; }
|
||
|
|
||
|
std::shared_ptr<RenderPass> end() {
|
||
|
auto d = defer([this](){delete this;});
|
||
|
VkAttachmentDescription attachments[3];
|
||
|
// 0 - color attackment
|
||
|
attachments[0].flags = 0;
|
||
|
attachments[0].format = color_format;
|
||
|
attachments[0].samples = samples;
|
||
|
attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||
|
attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||
|
attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||
|
attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||
|
attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||
|
if(samples == VK_SAMPLE_COUNT_1_BIT)
|
||
|
attachments[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||
|
else
|
||
|
attachments[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||
|
// 1- depth attackment
|
||
|
attachments[1].flags = 0;
|
||
|
attachments[1].format = VK_FORMAT_D24_UNORM_S8_UINT;
|
||
|
attachments[1].samples = samples;
|
||
|
attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||
|
attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||
|
attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||
|
attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||
|
attachments[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||
|
attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||
|
// 2 - color attachment resolve, for msaa
|
||
|
attachments[2].flags = 0;
|
||
|
attachments[2].format = color_format;
|
||
|
attachments[2].samples = VK_SAMPLE_COUNT_1_BIT;
|
||
|
attachments[2].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||
|
attachments[2].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||
|
attachments[2].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||
|
attachments[2].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||
|
attachments[2].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||
|
attachments[2].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||
|
|
||
|
VkAttachmentReference attachment_ref[3];
|
||
|
attachment_ref[0].attachment = 0;
|
||
|
attachment_ref[0].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||
|
attachment_ref[1].attachment = 1;
|
||
|
attachment_ref[1].layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||
|
attachment_ref[2].attachment = 2;
|
||
|
attachment_ref[2].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||
|
|
||
|
VkSubpassDescription subpass = {};
|
||
|
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||
|
subpass.colorAttachmentCount = 1;
|
||
|
subpass.pColorAttachments = &attachment_ref[0];
|
||
|
subpass.pDepthStencilAttachment = &attachment_ref[1];
|
||
|
if(samples != VK_SAMPLE_COUNT_1_BIT)
|
||
|
subpass.pResolveAttachments = &attachment_ref[2];
|
||
|
|
||
|
VkSubpassDependency dependency;
|
||
|
dependency.dependencyFlags = 0;
|
||
|
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
|
||
|
dependency.dstSubpass = 0;
|
||
|
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||
|
dependency.srcAccessMask = 0;
|
||
|
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||
|
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||
|
|
||
|
VkRenderPassCreateInfo render_pass_info;
|
||
|
render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||
|
render_pass_info.pNext = nullptr;
|
||
|
render_pass_info.flags = 0;
|
||
|
render_pass_info.attachmentCount = (samples == VK_SAMPLE_COUNT_1_BIT) ? 2 : 3;
|
||
|
render_pass_info.pAttachments = attachments;
|
||
|
render_pass_info.subpassCount = 1;
|
||
|
render_pass_info.pSubpasses = &subpass;
|
||
|
render_pass_info.dependencyCount = 1;
|
||
|
render_pass_info.pDependencies = &dependency;
|
||
|
VkRenderPass render_pass;
|
||
|
vkCreateRenderPass(device, &render_pass_info, nullptr, &render_pass);
|
||
|
return std::shared_ptr<RenderPass>(new RenderPassImpl(device, render_pass));
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
VkDevice device;
|
||
|
VkFormat color_format = VK_FORMAT_B8G8R8A8_UNORM;
|
||
|
VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT;
|
||
|
};
|
||
|
|
||
|
class DescriptorSetLayoutBuilderImpl : public DescriptorSetLayoutBuilder {
|
||
|
public:
|
||
|
DescriptorSetLayoutBuilderImpl(const Device& device) : device(device.handle()) {}
|
||
|
DescriptorSetLayoutBuilder& add_binding(VkDescriptorType type) {
|
||
|
VkDescriptorSetLayoutBinding layout_binding;
|
||
|
layout_binding.binding = bindings.size();
|
||
|
layout_binding.descriptorType = type;
|
||
|
layout_binding.descriptorCount = 1;
|
||
|
layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
|
||
|
layout_binding.pImmutableSamplers = nullptr;
|
||
|
bindings.push_back(layout_binding);
|
||
|
return *this;
|
||
|
}
|
||
|
DescriptorSetLayoutBuilder& set_count(uint32_t count) { bindings.back().descriptorCount = count; return *this; }
|
||
|
DescriptorSetLayoutBuilder& set_stage(VkShaderStageFlags stage) { bindings.back().stageFlags = stage; return *this; }
|
||
|
DescriptorSetLayoutBuilder& set_samplers() { return *this; }
|
||
|
std::shared_ptr<DescriptorSetLayout> end() {
|
||
|
auto d = defer([this](){delete this;});
|
||
|
VkDescriptorSetLayoutCreateInfo layout_info;
|
||
|
layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||
|
layout_info.pNext = nullptr;
|
||
|
layout_info.flags = 0;
|
||
|
layout_info.bindingCount = bindings.size();
|
||
|
layout_info.pBindings = bindings.data();
|
||
|
VkDescriptorSetLayout descriptor_set_layout;
|
||
|
if(vkCreateDescriptorSetLayout(device, &layout_info, nullptr, &descriptor_set_layout) != VK_SUCCESS)
|
||
|
return nullptr;
|
||
|
return std::shared_ptr<DescriptorSetLayout>(new DescriptorSetLayoutImpl(device, descriptor_set_layout));
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
VkDevice device;
|
||
|
rs::vector<VkDescriptorSetLayoutBinding> bindings;
|
||
|
};
|
||
|
|
||
|
class DescriptorPoolBuilderImpl : public DescriptorPoolBuilder {
|
||
|
public:
|
||
|
DescriptorPoolBuilderImpl(const Device& device) : device(device.handle()) {}
|
||
|
DescriptorPoolBuilder& add_pool_size(VkDescriptorType type, uint32_t count) { pool_size.push_back({type, count}); return *this; }
|
||
|
DescriptorPoolBuilder& set_max_sets(uint32_t count) { max_sets = count; return *this; }
|
||
|
DescriptorPoolBuilder& set_flags(VkDescriptorPoolCreateFlags flag) { flags = flag; return *this; }
|
||
|
std::shared_ptr<DescriptorPool> end() {
|
||
|
auto d = defer([this](){delete this;});
|
||
|
VkDescriptorPoolCreateInfo pool_info;
|
||
|
pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||
|
pool_info.pNext = nullptr;
|
||
|
pool_info.flags = flags;
|
||
|
pool_info.poolSizeCount = pool_size.size();
|
||
|
pool_info.pPoolSizes = pool_size.data();
|
||
|
pool_info.maxSets = max_sets;;
|
||
|
VkDescriptorPool descriptor_pool;
|
||
|
if(vkCreateDescriptorPool(device, &pool_info, nullptr, &descriptor_pool) != VK_SUCCESS)
|
||
|
return nullptr;
|
||
|
return std::shared_ptr<DescriptorPool>(new DescriptorPoolImpl(device, descriptor_pool, flags));
|
||
|
}
|
||
|
private:
|
||
|
VkDevice device;
|
||
|
rs::vector<VkDescriptorPoolSize> pool_size;
|
||
|
uint32_t max_sets = 0;
|
||
|
VkDescriptorPoolCreateFlags flags = 0;
|
||
|
};
|
||
|
|
||
|
class PipelineBuilderImpl : public PipelineBuilder {
|
||
|
public:
|
||
|
PipelineBuilderImpl(const Device& device) : device(device.handle()) {}
|
||
|
PipelineBuilder& set_render_pass(const RenderPass& pass) { render_pass = pass.handle(); return *this; }
|
||
|
PipelineBuilder& set_vertex_shader(const ShaderModule& vert) { vert_shader = vert.handle(); return *this; }
|
||
|
PipelineBuilder& set_fragment_shader(const ShaderModule& frag) { frag_shader = frag.handle(); return *this; }
|
||
|
PipelineBuilder& normal_viewport(float w, float h) { viewport = {0.0f, 0.0f, w, h, 0.0f, 1.0f}; return *this; }
|
||
|
PipelineBuilder& normal_scissor(uint32_t w, uint32_t h) { scissor = {{0, 0}, {w, h}}; return *this; }
|
||
|
PipelineBuilder& draw_topology(VkPrimitiveTopology topology) { this->topology = topology; return *this; }
|
||
|
PipelineBuilder& set_polygon_mode(VkPolygonMode mode) { polygon_mode = mode; return *this; }
|
||
|
PipelineBuilder& set_cull_mode(VkCullModeFlags mode) { cull_mode = mode; return *this; }
|
||
|
PipelineBuilder& set_front_face(VkFrontFace front) { front_face = front; return *this; }
|
||
|
PipelineBuilder& set_line_width(float width) { line_width = width; return *this; }
|
||
|
PipelineBuilder& set_samples(VkSampleCountFlagBits samples) { this->samples = samples; return *this; }
|
||
|
PipelineBuilder& bind_vertex_size(uint32_t sz) { vertex_size = sz; return *this; }
|
||
|
PipelineBuilder& add_binding_attribute(VkFormat format, uint32_t offset) {
|
||
|
input_attributes.push_back({(uint32_t)input_attributes.size(), 0, format, offset});
|
||
|
return *this;
|
||
|
}
|
||
|
PipelineBuilder& add_descriptor_set_layout(const DescriptorSetLayout& layout) { descriptor_set_layouts.push_back(layout.handle()); return *this; }
|
||
|
|
||
|
std::shared_ptr<Pipeline> end() {
|
||
|
auto d = defer([this](){delete this;});
|
||
|
VkPipelineShaderStageCreateInfo shader_stages[2];
|
||
|
VkPipelineShaderStageCreateInfo& vert_shader_info = shader_stages[0];
|
||
|
vert_shader_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||
|
vert_shader_info.pNext = nullptr;
|
||
|
vert_shader_info.flags = 0;
|
||
|
vert_shader_info.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||
|
vert_shader_info.module = vert_shader;
|
||
|
vert_shader_info.pName = "main";
|
||
|
vert_shader_info.pSpecializationInfo = nullptr;
|
||
|
VkPipelineShaderStageCreateInfo& frag_shader_info = shader_stages[1];
|
||
|
frag_shader_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||
|
frag_shader_info.pNext = nullptr;
|
||
|
frag_shader_info.flags = 0;
|
||
|
frag_shader_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||
|
frag_shader_info.module = frag_shader;
|
||
|
frag_shader_info.pName = "main";
|
||
|
frag_shader_info.pSpecializationInfo = nullptr;
|
||
|
VkPipelineVertexInputStateCreateInfo vertex_input_info;
|
||
|
vertex_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||
|
vertex_input_info.pNext = nullptr;
|
||
|
vertex_input_info.flags = 0;
|
||
|
if(input_attributes.empty()) {
|
||
|
vertex_input_info.vertexBindingDescriptionCount = 0;
|
||
|
vertex_input_info.pVertexBindingDescriptions = nullptr;
|
||
|
vertex_input_info.vertexAttributeDescriptionCount = 0;
|
||
|
vertex_input_info.pVertexAttributeDescriptions = nullptr;
|
||
|
} else {
|
||
|
VkVertexInputBindingDescription binding_description;
|
||
|
binding_description.binding = 0;
|
||
|
binding_description.stride = vertex_size;
|
||
|
binding_description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||
|
vertex_input_info.vertexBindingDescriptionCount = 1;
|
||
|
vertex_input_info.pVertexBindingDescriptions = &binding_description;
|
||
|
vertex_input_info.vertexAttributeDescriptionCount = input_attributes.size();
|
||
|
vertex_input_info.pVertexAttributeDescriptions = input_attributes.data();
|
||
|
}
|
||
|
VkPipelineInputAssemblyStateCreateInfo input_assemply_info;
|
||
|
input_assemply_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
||
|
input_assemply_info.pNext = nullptr;
|
||
|
input_assemply_info.flags = 0;
|
||
|
input_assemply_info.topology = topology;
|
||
|
input_assemply_info.primitiveRestartEnable = VK_FALSE;
|
||
|
VkPipelineViewportStateCreateInfo viewport_state;
|
||
|
viewport_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
||
|
viewport_state.pNext = nullptr;
|
||
|
viewport_state.flags = 0;
|
||
|
viewport_state.viewportCount = 1;
|
||
|
viewport_state.pViewports = &viewport;
|
||
|
viewport_state.scissorCount = 1;
|
||
|
viewport_state.pScissors = &scissor;
|
||
|
VkPipelineRasterizationStateCreateInfo rasterizer;
|
||
|
rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||
|
rasterizer.pNext = nullptr;
|
||
|
rasterizer.flags = 0;
|
||
|
rasterizer.depthClampEnable = VK_FALSE;
|
||
|
rasterizer.rasterizerDiscardEnable = VK_FALSE;
|
||
|
rasterizer.polygonMode = polygon_mode;
|
||
|
rasterizer.cullMode = cull_mode;
|
||
|
rasterizer.frontFace = front_face;
|
||
|
rasterizer.depthBiasEnable = VK_FALSE;
|
||
|
rasterizer.depthBiasConstantFactor = 0.0f;
|
||
|
rasterizer.depthBiasClamp = 0.0f;
|
||
|
rasterizer.depthBiasSlopeFactor = 0.0f;
|
||
|
rasterizer.lineWidth = line_width;
|
||
|
VkPipelineMultisampleStateCreateInfo multisampling;
|
||
|
multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
||
|
multisampling.pNext = nullptr;
|
||
|
multisampling.flags = 0;
|
||
|
multisampling.rasterizationSamples = samples;
|
||
|
multisampling.sampleShadingEnable = VK_FALSE;
|
||
|
multisampling.minSampleShading = 1.0f;
|
||
|
multisampling.pSampleMask = nullptr;
|
||
|
multisampling.alphaToCoverageEnable = VK_FALSE;
|
||
|
multisampling.alphaToOneEnable = VK_FALSE;
|
||
|
VkPipelineColorBlendAttachmentState colorBlendAttachment;
|
||
|
colorBlendAttachment.blendEnable = VK_TRUE;
|
||
|
colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
||
|
colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||
|
colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
|
||
|
colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
||
|
colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||
|
colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
|
||
|
colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT
|
||
|
| VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
||
|
VkPipelineColorBlendStateCreateInfo colorBlending;
|
||
|
colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
||
|
colorBlending.pNext = nullptr;
|
||
|
colorBlending.flags = 0;
|
||
|
colorBlending.logicOpEnable = VK_FALSE;
|
||
|
colorBlending.logicOp = VK_LOGIC_OP_COPY;
|
||
|
colorBlending.attachmentCount = 1;
|
||
|
colorBlending.pAttachments = &colorBlendAttachment;
|
||
|
colorBlending.blendConstants[0] = 0.0f;
|
||
|
colorBlending.blendConstants[1] = 0.0f;
|
||
|
colorBlending.blendConstants[2] = 0.0f;
|
||
|
colorBlending.blendConstants[3] = 0.0f;
|
||
|
VkPipelineLayoutCreateInfo pipeline_layout_info;
|
||
|
pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||
|
pipeline_layout_info.pNext = nullptr;
|
||
|
pipeline_layout_info.flags = 0;
|
||
|
if(descriptor_set_layouts.empty()) {
|
||
|
pipeline_layout_info.setLayoutCount = 0;
|
||
|
pipeline_layout_info.pSetLayouts = nullptr;
|
||
|
} else {
|
||
|
pipeline_layout_info.setLayoutCount = descriptor_set_layouts.size();
|
||
|
pipeline_layout_info.pSetLayouts = descriptor_set_layouts.data();
|
||
|
}
|
||
|
pipeline_layout_info.pushConstantRangeCount = 0;
|
||
|
VkPipelineLayout pipeline_layout;
|
||
|
if(vkCreatePipelineLayout(device, &pipeline_layout_info, nullptr, &pipeline_layout) != VK_SUCCESS)
|
||
|
return nullptr;
|
||
|
|
||
|
VkPipelineDepthStencilStateCreateInfo depthStencil = {};
|
||
|
depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
|
||
|
depthStencil.depthTestEnable = VK_TRUE;
|
||
|
depthStencil.depthWriteEnable = VK_TRUE;
|
||
|
depthStencil.depthCompareOp = VK_COMPARE_OP_LESS;
|
||
|
depthStencil.depthBoundsTestEnable = VK_FALSE;
|
||
|
depthStencil.minDepthBounds = 0.0f;
|
||
|
depthStencil.maxDepthBounds = 1.0f;
|
||
|
depthStencil.stencilTestEnable = VK_FALSE;
|
||
|
depthStencil.front = {};
|
||
|
depthStencil.back = {};
|
||
|
|
||
|
VkGraphicsPipelineCreateInfo pipelineInfo;
|
||
|
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||
|
pipelineInfo.pNext = nullptr;
|
||
|
pipelineInfo.flags = 0;
|
||
|
pipelineInfo.stageCount = 2;
|
||
|
pipelineInfo.pStages = shader_stages;
|
||
|
pipelineInfo.pVertexInputState = &vertex_input_info;
|
||
|
pipelineInfo.pInputAssemblyState = &input_assemply_info;
|
||
|
pipelineInfo.pViewportState = &viewport_state;
|
||
|
pipelineInfo.pRasterizationState = &rasterizer;
|
||
|
pipelineInfo.pMultisampleState = &multisampling;
|
||
|
pipelineInfo.pDepthStencilState = &depthStencil;
|
||
|
pipelineInfo.pColorBlendState = &colorBlending;
|
||
|
pipelineInfo.pDynamicState = nullptr;
|
||
|
pipelineInfo.layout = pipeline_layout;
|
||
|
pipelineInfo.renderPass = render_pass;
|
||
|
pipelineInfo.subpass = 0;
|
||
|
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
|
||
|
pipelineInfo.basePipelineIndex = -1;
|
||
|
VkPipeline graphicsPipeline;
|
||
|
if(vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &graphicsPipeline) != VK_SUCCESS)
|
||
|
return nullptr;
|
||
|
return std::shared_ptr<Pipeline>(new PipelineImpl(device, graphicsPipeline, pipeline_layout));
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
VkDevice device;
|
||
|
VkRenderPass render_pass;
|
||
|
VkShaderModule vert_shader;
|
||
|
VkShaderModule frag_shader;
|
||
|
VkViewport viewport;
|
||
|
VkRect2D scissor;
|
||
|
VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||
|
VkPolygonMode polygon_mode = VK_POLYGON_MODE_FILL;
|
||
|
VkCullModeFlags cull_mode = VK_CULL_MODE_NONE;
|
||
|
VkFrontFace front_face = VK_FRONT_FACE_COUNTER_CLOCKWISE;
|
||
|
float line_width = 1.0;
|
||
|
VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT;
|
||
|
uint32_t vertex_size = 0;
|
||
|
rs::vector<VkVertexInputAttributeDescription> input_attributes;
|
||
|
rs::vector<VkDescriptorSetLayout> descriptor_set_layouts;
|
||
|
};
|
||
|
|
||
|
class FramebufferBuilderImpl : public FramebufferBuilder {
|
||
|
public:
|
||
|
FramebufferBuilderImpl(const Device& dev) : device(dev.handle()) {}
|
||
|
FramebufferBuilder& set_render_pass(const RenderPass& render_pass) { this->render_pass = render_pass.handle(); return *this; }
|
||
|
FramebufferBuilder& set_framebuffer_size(uint32_t w, uint32_t h) { width = w; height = h; return *this; }
|
||
|
FramebufferBuilder& add_image_view(const ImageView& view) { image_views.push_back(view.handle()); return *this; }
|
||
|
FramebufferBuilder& set_flags(VkFramebufferCreateFlags flag) { this->flags = flags; return *this; }
|
||
|
FramebufferBuilder& set_layer(uint32_t layer) { this->layer = layer; return *this; }
|
||
|
std::shared_ptr<Framebuffer> end() {
|
||
|
auto d = defer([this](){delete this;});
|
||
|
VkFramebufferCreateInfo create_info;
|
||
|
create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||
|
create_info.pNext = nullptr;
|
||
|
create_info.flags = flags;
|
||
|
create_info.renderPass = render_pass;
|
||
|
create_info.attachmentCount = image_views.size();
|
||
|
create_info.pAttachments = image_views.data();
|
||
|
create_info.width = width;
|
||
|
create_info.height = height;
|
||
|
create_info.layers = layer;
|
||
|
VkFramebuffer framebuffer;
|
||
|
if(vkCreateFramebuffer(device, &create_info, nullptr, &framebuffer) != VK_SUCCESS)
|
||
|
return nullptr;
|
||
|
return std::shared_ptr<Framebuffer>(new FramebufferImpl(device, framebuffer, {width, height}));
|
||
|
}
|
||
|
private:
|
||
|
VkDevice device;
|
||
|
VkRenderPass render_pass;
|
||
|
std::vector<VkImageView> image_views;
|
||
|
VkFramebufferCreateFlags flags = 0;
|
||
|
uint32_t layer = 1;
|
||
|
uint32_t width = 0;
|
||
|
uint32_t height = 0;
|
||
|
};
|
||
|
|
||
|
class CommandPoolBuilderImpl : public CommandPoolBuilder {
|
||
|
public:
|
||
|
CommandPoolBuilderImpl(const Device& dev) : device(dev.handle()) {}
|
||
|
CommandPoolBuilder& set_queue_family_index(uint32_t idx) { queue_family_index = idx; return *this; }
|
||
|
CommandPoolBuilder& set_pool_flag(VkCommandPoolCreateFlags flags) { pool_flag = flags; return *this; }
|
||
|
std::shared_ptr<CommandPool> end() {
|
||
|
auto d = defer([this](){delete this;});
|
||
|
VkCommandPoolCreateInfo pool_create_info;
|
||
|
pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||
|
pool_create_info.pNext = nullptr;
|
||
|
pool_create_info.flags = pool_flag;
|
||
|
pool_create_info.queueFamilyIndex = queue_family_index;
|
||
|
VkCommandPool command_pool;
|
||
|
if(vkCreateCommandPool(device, &pool_create_info, nullptr, &command_pool) != VK_SUCCESS)
|
||
|
return nullptr;
|
||
|
return std::make_shared<CommandPoolImpl>(device, command_pool);
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
VkDevice device;
|
||
|
uint32_t queue_family_index = 0;
|
||
|
VkCommandPoolCreateFlags pool_flag = 0;
|
||
|
};
|
||
|
|
||
|
// static builders
|
||
|
InstanceBuilder& Instance::begin_build() {
|
||
|
return *(new InstanceBuilderImpl);
|
||
|
}
|
||
|
|
||
|
std::shared_ptr<Surface> Surface::from_raw_surface(VkSurfaceKHR surface, const Instance& inst, const PhysicalDevice& physical_device) {
|
||
|
return std::shared_ptr<Surface>(new SurfaceImpl(surface, inst, physical_device));
|
||
|
}
|
||
|
|
||
|
DeviceBuilder& Device::begin_build(const PhysicalDevice& physical_device) {
|
||
|
return *(new DeviceBuilderImpl(physical_device));
|
||
|
}
|
||
|
|
||
|
BufferBuilder& Buffer::begin_build(const Device& device, const PhysicalDevice& physical_device) {
|
||
|
return *(new BufferBuilderImpl(device, physical_device));
|
||
|
}
|
||
|
|
||
|
ImageBuilder& Image::begin_build(const Device& device, const PhysicalDevice& physical_device) {
|
||
|
return *(new ImageBuilderImpl(device, physical_device));
|
||
|
}
|
||
|
|
||
|
SamplerBuilder& Sampler::begin_build(const Device& device) {
|
||
|
return *(new SamplerBuilderImpl(device));
|
||
|
}
|
||
|
|
||
|
std::shared_ptr<ShaderModule> ShaderModule::load_from_spv(const Device& device, const std::string& filename) {
|
||
|
std::ifstream file(filename, std::ios::ate | std::ios::binary);
|
||
|
if(!file.is_open())
|
||
|
return nullptr;
|
||
|
size_t file_size = (size_t) file.tellg();
|
||
|
std::vector<char> buffer(file_size);
|
||
|
file.seekg(0);
|
||
|
file.read(buffer.data(), file_size);
|
||
|
VkShaderModuleCreateInfo shader_module_create_info;
|
||
|
shader_module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||
|
shader_module_create_info.pNext = nullptr;
|
||
|
shader_module_create_info.flags = 0;
|
||
|
shader_module_create_info.codeSize = file_size;
|
||
|
shader_module_create_info.pCode = reinterpret_cast<uint32_t*>(buffer.data());
|
||
|
VkShaderModule shaderModule;
|
||
|
if(vkCreateShaderModule(device.handle(), &shader_module_create_info, nullptr, &shaderModule) != VK_SUCCESS)
|
||
|
return nullptr;
|
||
|
return std::shared_ptr<ShaderModule>(new ShaderModuleImpl(device.handle(), shaderModule));
|
||
|
}
|
||
|
|
||
|
std::shared_ptr<ShaderModule> ShaderModule::load_from_src(const Device& device, const std::string& filename, uint32_t kind) {
|
||
|
std::ifstream file(filename, std::ios::ate);
|
||
|
if(!file.is_open())
|
||
|
return nullptr;
|
||
|
size_t file_size = (size_t) file.tellg();
|
||
|
std::string text(file_size, ' ');
|
||
|
file.seekg(0);
|
||
|
file.read(text.data(), file_size);
|
||
|
shaderc::Compiler compiler;
|
||
|
shaderc::SpvCompilationResult result = compiler.CompileGlslToSpv(text.c_str(), text.length(), (shaderc_shader_kind)kind, filename.c_str());
|
||
|
if(result.GetNumErrors() != 0) {
|
||
|
std::cout << result.GetErrorMessage() << std::endl;
|
||
|
return nullptr;
|
||
|
}
|
||
|
if(auto status = result.GetCompilationStatus(); status != shaderc_compilation_status_success) {
|
||
|
std::cout << filename << " compile status error ==> " << status << std::endl;
|
||
|
return nullptr;
|
||
|
}
|
||
|
auto bin_begin = result.begin();
|
||
|
size_t code_size = (result.end() - result.begin()) * sizeof(uint32_t);
|
||
|
VkShaderModuleCreateInfo shader_module_create_info;
|
||
|
shader_module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||
|
shader_module_create_info.pNext = nullptr;
|
||
|
shader_module_create_info.flags = 0;
|
||
|
shader_module_create_info.codeSize = code_size;
|
||
|
shader_module_create_info.pCode = bin_begin;
|
||
|
VkShaderModule shaderModule;
|
||
|
if(vkCreateShaderModule(device.handle(), &shader_module_create_info, nullptr, &shaderModule) != VK_SUCCESS)
|
||
|
return nullptr;
|
||
|
return std::shared_ptr<ShaderModule>(new ShaderModuleImpl(device.handle(), shaderModule));
|
||
|
}
|
||
|
|
||
|
SwapchainBuilder& Swapchain::begin_build(const Device& device) {
|
||
|
return *(new SwapchainBuilderImpl(device));
|
||
|
}
|
||
|
|
||
|
RenderPassBuilder& RenderPass::begin_build(const Device& device) {
|
||
|
return *(new RenderPassBuilderImpl(device));
|
||
|
}
|
||
|
|
||
|
DescriptorSetLayoutBuilder& DescriptorSetLayout::begin_build(const Device& device) {
|
||
|
return *(new DescriptorSetLayoutBuilderImpl(device));
|
||
|
}
|
||
|
|
||
|
DescriptorPoolBuilder& DescriptorPool::begin_build(const Device& device) {
|
||
|
return *(new DescriptorPoolBuilderImpl(device));
|
||
|
}
|
||
|
|
||
|
PipelineBuilder& Pipeline::begin_build(const Device& device) {
|
||
|
return *(new PipelineBuilderImpl(device));
|
||
|
}
|
||
|
|
||
|
FramebufferBuilder& Framebuffer::begin_build(const Device& device) {
|
||
|
return *(new FramebufferBuilderImpl(device));
|
||
|
}
|
||
|
|
||
|
CommandPoolBuilder& CommandPool::begin_build(const Device& device) {
|
||
|
return *(new CommandPoolBuilderImpl(device));
|
||
|
}
|
||
|
|
||
|
std::shared_ptr<Renderer> Renderer::create_renderer(const vk::Device& device, uint32_t img_count) {
|
||
|
return std::shared_ptr<Renderer>(new RendererImpl(device.handle(), img_count));
|
||
|
}
|
||
|
|
||
|
}
|