tacraft/vulkan.cpp

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));
}
}