#include #include #include #include "vulkan.hpp" namespace vk { template 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 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 enumerate_extensions() const override{ return extension_props.into_iter_ptr(); } rs::iterator enumerate_queue_families() const override { return queue_family_props.into_iter_ptr(); } private: VkPhysicalDevice physical_device; VkPhysicalDeviceProperties props; VkPhysicalDeviceMemoryProperties mem_props; rs::vector extension_props; rs::vector 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 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 enumerate_physical_device() const override { return physical_devices.into_iter_ptr().map([](const PhysicalDeviceImpl* p) { return static_cast(p); }); } VkInstance handle() const override { return instance; } private: VkInstance instance; rs::vector 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 enumerate_formats() const override { return supported_formats.into_iter_ptr().map([](const VkSurfaceFormatKHR* p) { return static_cast(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 supported_formats; }; class DeviceImpl : public Device { public: DeviceImpl(VkDevice handle, rs::vector 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 enumerate_queues() const override { return queues.into_iter_ptr(); } rs::vector queue_family_in_use() const override { return queues.into_iter_ptr().map([](const Queue* q) -> uint32_t { return q->queue_family_index; }).collect>().into_iter().collect>(); } private: VkDevice device; rs::vector 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) : 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; }; class ImageImpl : public Image, public std::enable_shared_from_this { 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 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(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 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 get_swapchain_images() override { return swapchain_imageviews.into_iter_mptr().map([](ImageViewImpl* iv) { return static_cast(iv); }).collect>(); } private: VkDevice inner_device; VkSwapchainKHR swapchain; VkFormat format; rs::vector 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 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 pool; rs::vector write_buffer_info; rs::vector write_image_info; rs::vector 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 { 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> alloc_descriptor_set(const DescriptorSetLayout& layout, uint32_t count) override { std::vector 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 sets(count); if(vkAllocateDescriptorSets(inner_device, &alloc_info, sets.data()) != VK_SUCCESS) return {}; rs::vector> descriptor_sets; std::weak_ptr 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 mem_barriors; rs::vector buffer_barriors; rs::vector 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 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 regions; }; class CommandBufferImpl : public CommandBuffer { public: CommandBufferImpl(VkDevice device, VkCommandBuffer buffer, std::weak_ptr 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 weak_pool; }; class CommandPoolImpl : public CommandPool, public std::enable_shared_from_this { 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> alloc_command_buffer(VkCommandBufferLevel level, uint32_t count) override { rs::vector> results; alloc_command_buffer(results, level, count); return results; } CommandPool& alloc_command_buffer(rs::vector>& vec, VkCommandBufferLevel level, uint32_t count) override { rs::vector 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 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::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::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>& command_buffers) override { rs::vector 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 image_semaphore; std::vector signal_semaphore; std::vector submit_fence; uint32_t img_count = 1; uint32_t current_frame = 0; uint32_t current_index = 0; bool outofdate = false; }; rs::vector list_layer_properties() { uint32_t layer_count = 0; vkEnumerateInstanceLayerProperties(&layer_count, nullptr); rs::vector 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& layers) { layer_names = layers; return *this; } InstanceBuilder& set_extensions(const rs::vector& extensions) { extension_names = extensions; return *this; } std::shared_ptr 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(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 layer_names; rs::vector extension_names; }; class DeviceBuilderImpl : public DeviceBuilder { public: DeviceBuilderImpl(const PhysicalDevice& handle) : physical_device(&handle) {} DeviceBuilder& set_extensions(const rs::vector& 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 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> 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* p) { return p->size() > 0; }).map([](size_t idx, const rs::vector* 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>(); 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>(); return std::shared_ptr(new DeviceImpl(device, std::move(queues))); } return nullptr; } private: const PhysicalDevice* physical_device; rs::vector extension_names; rs::vector> 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 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(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 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(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 end() { auto d = defer([this](){delete this;}); VkSampler sampler; if(vkCreateSampler(device, &sampler_info, nullptr, &sampler) != VK_SUCCESS) return nullptr; return std::make_shared(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& 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 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(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 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(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 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(new DescriptorSetLayoutImpl(device, descriptor_set_layout)); } private: VkDevice device; rs::vector 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 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(new DescriptorPoolImpl(device, descriptor_pool, flags)); } private: VkDevice device; rs::vector 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 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(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 input_attributes; rs::vector 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 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(new FramebufferImpl(device, framebuffer, {width, height})); } private: VkDevice device; VkRenderPass render_pass; std::vector 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 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(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::from_raw_surface(VkSurfaceKHR surface, const Instance& inst, const PhysicalDevice& physical_device) { return std::shared_ptr(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::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 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(buffer.data()); VkShaderModule shaderModule; if(vkCreateShaderModule(device.handle(), &shader_module_create_info, nullptr, &shaderModule) != VK_SUCCESS) return nullptr; return std::shared_ptr(new ShaderModuleImpl(device.handle(), shaderModule)); } std::shared_ptr 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(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::create_renderer(const vk::Device& device, uint32_t img_count) { return std::shared_ptr(new RendererImpl(device.handle(), img_count)); } }