summaryrefslogtreecommitdiffstats
path: root/tools/render-test/render-vk.cpp
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2018-05-03 14:25:13 -0400
committerGitHub <noreply@github.com>2018-05-03 14:25:13 -0400
commit367f3a78a40731da45ee12b9a18c94707f1d1429 (patch)
tree5993ef627e1a094ea1d401c31e6b00e3c63c308a /tools/render-test/render-vk.cpp
parent78935493587ec65a199d844327613021667acc1b (diff)
Feature/vulkan first render (#545)
* First pass at InputLayout for Vulkan Add support for RGBA_Float32 * Use VulkanModule and VulkanApi to handle accessing Vulkan types. * First pass at Vulkan swap chain/Device queue. * Added VulkanUtil for generic function functions. * Move more functionality to VulkanApi and VulkanUtil. Make Buffer able to initialize itself. * More tidy up around VulkanDeviceQueue * First pass use of VulkanDeviceQueue in VkRenderer * First pass use of VulkanSwapChain on VkRenderer * Added depth formats. Binding for constant and vertex buffers for Vulkan. * Setting up VkImageView on backbuffers. * First pass support for setting up vkRenderPass. * Fixes to work around Vulkan swap chain/verification issues. * Added support for Pipeline and a pipeline cache. * Working without waiting - because use of pipeline cache. * Added support for VkFramebuffer in Vulkan. * First pass at creating Vulkan graphics pipeline. * More efforts to get Vulkan to render. * Small improvement for checking of Binding flags. * Removed setConstantBuffers from the Renderer interface - so that all resource binding takes place through the BindingState. To make this work required a 'hack' in render-test main.cpp - so that the constant buffer binding that is needed in some tests is only added when it doesn't clash. * RendererID -> unified into RendererType. Added getRendererType to Renderer interface. Added ProjectionStyle, and function to get from RendererType. Added getIdentityProjection to RendererUtil - to get projection that is the 'identity' - but hits the same pixels for all projection styles. * Fix build problem on Win32 on Vulkan where should use VK_NULL_HANDLE. * Improve naming, comments. Remove dead code. * Remove unwanted comment.
Diffstat (limited to 'tools/render-test/render-vk.cpp')
-rw-r--r--tools/render-test/render-vk.cpp1310
1 files changed, 835 insertions, 475 deletions
diff --git a/tools/render-test/render-vk.cpp b/tools/render-test/render-vk.cpp
index ef05d23b6..9999d1e82 100644
--- a/tools/render-test/render-vk.cpp
+++ b/tools/render-test/render-vk.cpp
@@ -6,84 +6,32 @@
#include "../../source/core/smart-pointer.h"
-#ifdef _WIN32
-#define VK_USE_PLATFORM_WIN32_KHR 1
-#endif
+#include "vk-api.h"
+#include "vk-util.h"
+#include "vk-device-queue.h"
+#include "vk-swap-chain.h"
-#define VK_NO_PROTOTYPES
-#include <vulkan/vulkan.h>
+// Vulkan has a different coordinate system to ogl
+// http://anki3d.org/vulkan-coordinate-system/
#define ENABLE_VALIDATION_LAYER 1
-
#ifdef _MSC_VER
-
-#include <stddef.h>
-
-#pragma warning(disable: 4996)
-
-#if (_MSC_VER < 1900)
-#define snprintf sprintf_s
+# include <stddef.h>
+# pragma warning(disable: 4996)
+# if (_MSC_VER < 1900)
+# define snprintf sprintf_s
+# endif
#endif
-#endif
-
-#define FOREACH_GLOBAL_PROC(M) \
- M(vkCreateInstance) \
- /* */
-
-#define FOREACH_INSTANCE_PROC(M) \
- M(vkCreateDevice) \
- M(vkCreateDebugReportCallbackEXT) \
- M(vkDestroyDebugReportCallbackEXT) \
- M(vkDebugReportMessageEXT) \
- M(vkEnumeratePhysicalDevices) \
- M(vkGetPhysicalDeviceProperties) \
- M(vkGetPhysicalDeviceFeatures) \
- M(vkGetPhysicalDeviceMemoryProperties) \
- M(vkGetPhysicalDeviceQueueFamilyProperties) \
- M(vkGetDeviceProcAddr) \
- /* */
-
-#define FOREACH_DEVICE_PROC(M) \
- M(vkCreateDescriptorPool) \
- M(vkCreateCommandPool) \
- M(vkGetDeviceQueue) \
- M(vkAllocateCommandBuffers) \
- M(vkBeginCommandBuffer) \
- M(vkEndCommandBuffer) \
- M(vkQueueSubmit) \
- M(vkQueueWaitIdle) \
- M(vkFreeCommandBuffers) \
- M(vkCreateBuffer) \
- M(vkGetBufferMemoryRequirements) \
- M(vkAllocateMemory) \
- M(vkBindBufferMemory) \
- M(vkMapMemory) \
- M(vkUnmapMemory) \
- M(vkCmdCopyBuffer) \
- M(vkDestroyBuffer) \
- M(vkFreeMemory) \
- M(vkCreateDescriptorSetLayout) \
- M(vkAllocateDescriptorSets) \
- M(vkUpdateDescriptorSets) \
- M(vkCreatePipelineLayout) \
- M(vkCreateComputePipelines) \
- M(vkCmdBindPipeline) \
- M(vkCmdBindDescriptorSets) \
- M(vkCmdDispatch) \
- M(vkDestroyPipeline) \
- M(vkCreateShaderModule) \
- /* */
-
namespace renderer_test {
using namespace Slang;
-#define RETURN_ON_VK_FAIL(x) { VkResult _vkRes = x; if (_vkRes != VK_SUCCESS) { SLANG_RETURN_ON_FAIL(toSlangResult(_vkRes)); }}
-
class VKRenderer : public Renderer, public ShaderCompiler
{
public:
+ enum { kMaxRenderTargets = 8, kMaxAttachments = kMaxRenderTargets + 1 };
+
// Renderer implementation
virtual SlangResult initialize(void* inWindowHandle) override;
virtual void setClearColor(const float color[4]) override;
@@ -102,44 +50,56 @@ public:
virtual void setBindingState(BindingState* state);
virtual void setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* strides, const UInt* offsets) override;
virtual void setShaderProgram(ShaderProgram* inProgram) override;
- virtual void setConstantBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* offsets) override;
virtual void draw(UInt vertexCount, UInt startVertex) override;
virtual void dispatchCompute(int x, int y, int z) override;
- virtual void submitGpuWork() override {}
- virtual void waitForGpu() override {}
+ virtual void submitGpuWork() override;
+ virtual void waitForGpu() override;
+ virtual RendererType getRendererType() const override { return RendererType::Vulkan; }
// ShaderCompiler implementation
virtual ShaderProgram* compileProgram(const ShaderCompileRequest& request) override;
+ /// Dtor
+ ~VKRenderer();
+
protected:
class Buffer
{
public:
-
+ /// Initialize a buffer with specified size, and memory props
+ Result init(const VulkanApi& api, size_t bufferSize, VkBufferUsageFlags usage, VkMemoryPropertyFlags reqMemoryProperties);
+
/// Returns true if has been initialized
- bool isInitialized() const { return m_renderer != nullptr; }
+ bool isInitialized() const { return m_api != nullptr; }
// Default Ctor
Buffer():
- m_renderer(nullptr)
+ m_api(nullptr)
{}
/// Dtor
~Buffer()
{
- if (m_renderer)
+ if (m_api)
{
- m_renderer->vkDestroyBuffer(m_renderer->m_device, m_buffer, nullptr);
- m_renderer->vkFreeMemory(m_renderer->m_device, m_memory, nullptr);
+ m_api->vkDestroyBuffer(m_api->m_device, m_buffer, nullptr);
+ m_api->vkFreeMemory(m_api->m_device, m_memory, nullptr);
}
}
VkBuffer m_buffer;
VkDeviceMemory m_memory;
- VKRenderer* m_renderer;
+ const VulkanApi* m_api;
};
+ class InputLayoutImpl : public InputLayout
+ {
+ public:
+ List<VkVertexInputAttributeDescription> m_vertexDescs;
+ int m_vertexSize;
+ };
+
class BufferResourceImpl: public BufferResource
{
public:
@@ -166,6 +126,12 @@ public:
{
public:
+ ShaderProgramImpl(PipelineType pipelineType):
+ m_pipelineType(pipelineType)
+ {}
+
+ PipelineType m_pipelineType;
+
VkPipelineShaderStageCreateInfo m_compute;
VkPipelineShaderStageCreateInfo m_vertex;
VkPipelineShaderStageCreateInfo m_fragment;
@@ -195,185 +161,586 @@ public:
VKRenderer* m_renderer;
List<BindingDetail> m_bindingDetails;
};
-
- class InputLayoutImpl: public InputLayout
+
+ struct BoundVertexBuffer
{
- public:
+ RefPtr<BufferResourceImpl> m_buffer;
+ int m_stride;
+ int m_offset;
+ };
+
+ class Pipeline : public RefObject
+ {
+ public:
+ Pipeline(const VulkanApi& api):
+ m_api(&api)
+ {
+ }
+ ~Pipeline()
+ {
+ if (m_pipeline != VK_NULL_HANDLE)
+ {
+ m_api->vkDestroyPipeline(m_api->m_device, m_pipeline, nullptr);
+ }
+ if (m_descriptorPool != VK_NULL_HANDLE)
+ {
+ m_api->vkDestroyDescriptorPool(m_api->m_device, m_descriptorPool, nullptr);
+ }
+ if (m_pipelineLayout != VK_NULL_HANDLE)
+ {
+ m_api->vkDestroyPipelineLayout(m_api->m_device, m_pipelineLayout, nullptr);
+ }
+ if(m_descriptorSetLayout != VK_NULL_HANDLE)
+ {
+ m_api->vkDestroyDescriptorSetLayout(m_api->m_device, m_descriptorSetLayout, nullptr);
+ }
+ }
+
+ const VulkanApi* m_api;
+
+ VkPrimitiveTopology m_primitiveTopology;
+ RefPtr<BindingStateImpl> m_bindingState;
+ RefPtr<InputLayoutImpl> m_inputLayout;
+ RefPtr<ShaderProgramImpl> m_shaderProgram;
+
+ VkDescriptorSetLayout m_descriptorSetLayout = VK_NULL_HANDLE;
+ VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE;
+ VkDescriptorPool m_descriptorPool = VK_NULL_HANDLE;
+ VkDescriptorSet m_descriptorSet = VK_NULL_HANDLE;
+ VkPipeline m_pipeline = VK_NULL_HANDLE;
};
VkBool32 handleDebugMessage(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject,
size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg);
- VkCommandBuffer getCommandBuffer();
- VkCommandBuffer beginCommandBuffer();
- void flushCommandBuffer(VkCommandBuffer commandBuffer);
-
- uint32_t getMemoryTypeIndex(uint32_t inTypeBits, VkMemoryPropertyFlags properties);
-
VkPipelineShaderStageCreateInfo compileEntryPoint(const ShaderCompileRequest::EntryPoint& entryPointRequest, VkShaderStageFlagBits stage, List<char>& bufferOut);
- SlangResult _initBuffer(size_t bufferSize, VkBufferUsageFlags usage, VkMemoryPropertyFlags reqMemoryProperties, Buffer& bufferOut);
-
- static SlangResult toSlangResult(VkResult res);
- static void checkResult(VkResult result);
static VKAPI_ATTR VkBool32 VKAPI_CALL debugMessageCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject,
size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg, void* pUserData);
- VkInstance m_instance;
- VkPhysicalDevice m_physicalDevice;
- VkPhysicalDeviceProperties m_deviceProperties;
- VkPhysicalDeviceFeatures m_deviceFeatures;
- VkPhysicalDeviceMemoryProperties m_deviceMemoryProperties;
- VkDevice m_device;
- VkQueue m_queue;
- VkCommandPool m_commandPool;
- VkSubmitInfo m_submitInfo;
- VkDebugReportCallbackEXT m_debugReportCallback;
+ /// Returns true if m_currentPipeline matches the current configuration
+ Pipeline* _getPipeline();
+ bool _isEqual(const Pipeline& pipeline) const;
+ Slang::Result _createPipeline(RefPtr<Pipeline>& pipelineOut);
+ void _beginRender();
+ void _endRender();
+ Slang::Result _beginPass();
+ void _endPass();
+
+ VkDebugReportCallbackEXT m_debugReportCallback;
+
+ RefPtr<InputLayoutImpl> m_currentInputLayout;
RefPtr<BindingStateImpl> m_currentBindingState;
RefPtr<ShaderProgramImpl> m_currentProgram;
- float m_clearColor[4] = { 0, 0, 0, 0 };;
+ List<RefPtr<Pipeline> > m_pipelineCache;
+ Pipeline* m_currentPipeline = nullptr;
-#define DECLARE_PROC(NAME) PFN_##NAME NAME;
- DECLARE_PROC(vkGetInstanceProcAddr);
- FOREACH_GLOBAL_PROC(DECLARE_PROC)
- FOREACH_INSTANCE_PROC(DECLARE_PROC)
- FOREACH_DEVICE_PROC(DECLARE_PROC)
-#undef DECLARE_PROC
+ List<BoundVertexBuffer> m_boundVertexBuffers;
+ VkPrimitiveTopology m_primitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+
+ VkDevice m_device = VK_NULL_HANDLE;
+
+ VulkanModule m_module;
+ VulkanApi m_api;
+
+ VulkanDeviceQueue m_deviceQueue;
+ VulkanSwapChain m_swapChain;
+
+ VkRenderPass m_renderPass = VK_NULL_HANDLE;
+
+ int m_swapChainImageIndex = -1;
+
+ float m_clearColor[4] = { 0, 0, 0, 0 };
};
-Renderer* createVKRenderer()
+/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! VkRenderer::Buffer !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+
+Result VKRenderer::Buffer::init(const VulkanApi& api, size_t bufferSize, VkBufferUsageFlags usage, VkMemoryPropertyFlags reqMemoryProperties)
{
- return new VKRenderer;
+ assert(!isInitialized());
+
+ m_api = &api;
+ m_memory = VK_NULL_HANDLE;
+ m_buffer = VK_NULL_HANDLE;
+
+ VkBufferCreateInfo bufferCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
+ bufferCreateInfo.size = bufferSize;
+ bufferCreateInfo.usage = usage;
+
+ SLANG_VK_CHECK(api.vkCreateBuffer(api.m_device, &bufferCreateInfo, nullptr, &m_buffer));
+
+ VkMemoryRequirements memoryReqs = {};
+ api.vkGetBufferMemoryRequirements(api.m_device, m_buffer, &memoryReqs);
+
+ int memoryTypeIndex = api.findMemoryTypeIndex(memoryReqs.memoryTypeBits, reqMemoryProperties);
+ assert(memoryTypeIndex >= 0);
+
+ VkMemoryPropertyFlags actualMemoryProperites = api.m_deviceMemoryProperties.memoryTypes[memoryTypeIndex].propertyFlags;
+
+ VkMemoryAllocateInfo allocateInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
+ allocateInfo.allocationSize = memoryReqs.size;
+ allocateInfo.memoryTypeIndex = memoryTypeIndex;
+
+ SLANG_VK_CHECK(api.vkAllocateMemory(api.m_device, &allocateInfo, nullptr, &m_memory));
+ SLANG_VK_CHECK(api.vkBindBufferMemory(api.m_device, m_buffer, m_memory, 0));
+
+ return SLANG_OK;
}
-/* static */SlangResult VKRenderer::toSlangResult(VkResult res)
+/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! VkRenderer !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+
+bool VKRenderer::_isEqual(const Pipeline& pipeline) const
{
- return (res == VK_SUCCESS) ? SLANG_OK : SLANG_FAIL;
+ return
+ pipeline.m_bindingState == m_currentBindingState &&
+ pipeline.m_primitiveTopology == m_primitiveTopology &&
+ pipeline.m_inputLayout == m_currentInputLayout &&
+ pipeline.m_shaderProgram == m_currentProgram;
}
-void VKRenderer::checkResult(VkResult result)
+VKRenderer::Pipeline* VKRenderer::_getPipeline()
{
- assert(result == VK_SUCCESS);
+ if (m_currentPipeline && _isEqual(*m_currentPipeline))
+ {
+ return m_currentPipeline;
+ }
+
+ // Look for a match in the cache
+ for (int i = 0; i < int(m_pipelineCache.Count()); ++i)
+ {
+ Pipeline* pipeline = m_pipelineCache[i];
+ if (_isEqual(*pipeline))
+ {
+ m_currentPipeline = pipeline;
+ return pipeline;
+ }
+ }
+
+ RefPtr<Pipeline> pipeline;
+ SLANG_RETURN_NULL_ON_FAIL(_createPipeline(pipeline));
+ m_pipelineCache.Add(pipeline);
+ m_currentPipeline = pipeline;
+ return pipeline;
}
-VkBool32 VKRenderer::handleDebugMessage(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject,
- size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg)
+Slang::Result VKRenderer::_createPipeline(RefPtr<Pipeline>& pipelineOut)
{
- char const* severity = "message";
- if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT)
- severity = "warning";
- if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT)
- severity = "error";
+ RefPtr<Pipeline> pipeline(new Pipeline(m_api));
- char buffer[1024];
- sprintf_s(buffer,
- "%s: %s %d: %s\n",
- pLayerPrefix,
- severity,
- msgCode,
- pMsg);
+ // Initialize the state
+ pipeline->m_primitiveTopology = m_primitiveTopology;
+ pipeline->m_bindingState = m_currentBindingState;
+ pipeline->m_shaderProgram = m_currentProgram;
+ pipeline->m_inputLayout = m_currentInputLayout;
- fprintf(stderr, "%s", buffer);
- fflush(stderr);
+ // Must be equal at this point if all the items are correctly set in pipeline
+ assert(_isEqual(*pipeline));
- OutputDebugStringA(buffer);
+ // First create a pipeline layout based on what is bound
- return VK_FALSE;
-}
+ const auto& srcDetails = m_currentBindingState->m_bindingDetails;
+ const auto& srcBindings = m_currentBindingState->getDesc().m_bindings;
-/* static */VKAPI_ATTR VkBool32 VKAPI_CALL VKRenderer::debugMessageCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject,
- size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg, void* pUserData)
-{
- return ((VKRenderer*)pUserData)->handleDebugMessage(flags, objType, srcObject, location, msgCode, pLayerPrefix, pMsg);
-}
+ const int numBindings = int(srcBindings.Count());
-VkCommandBuffer VKRenderer::getCommandBuffer()
-{
- VkCommandBufferAllocateInfo info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
- info.commandPool = m_commandPool;
- info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
- info.commandBufferCount = 1;
+ Slang::List<VkDescriptorSetLayoutBinding> dstBindings;
+ for (int i = 0; i < numBindings; ++i)
+ {
+ const auto& srcDetail = srcDetails[i];
+ const auto& srcBinding = srcBindings[i];
- VkCommandBuffer commandBuffer;
- checkResult(vkAllocateCommandBuffers(m_device, &info, &commandBuffer));
+ switch (srcBinding.bindingType)
+ {
+ case BindingType::Buffer:
+ {
+ BufferResourceImpl* bufferResource = static_cast<BufferResourceImpl*>(srcBinding.resource.Ptr());
+ const BufferResource::Desc& bufferResourceDesc = bufferResource->getDesc();
- return commandBuffer;
-}
+ if (bufferResourceDesc.bindFlags & Resource::BindFlag::UnorderedAccess)
+ {
+ VkDescriptorSetLayoutBinding dstBinding = {};
+ dstBinding.binding = srcDetail.m_binding;
+ dstBinding.descriptorCount = 1;
+ dstBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+ dstBinding.stageFlags = VK_SHADER_STAGE_ALL;
-VkCommandBuffer VKRenderer::beginCommandBuffer()
-{
- VkCommandBuffer commandBuffer = getCommandBuffer();
+ dstBindings.Add(dstBinding);
+ }
+ else if (bufferResourceDesc.bindFlags & Resource::BindFlag::ConstantBuffer)
+ {
+ VkDescriptorSetLayoutBinding dstBinding = {};
+ dstBinding.binding = srcDetail.m_binding;
+ dstBinding.descriptorCount = 1;
+ dstBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ dstBinding.stageFlags = VK_SHADER_STAGE_ALL;
- VkCommandBufferBeginInfo beginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
- checkResult(vkBeginCommandBuffer(commandBuffer, &beginInfo));
+ dstBindings.Add(dstBinding);
+ }
- return commandBuffer;
-}
+ break;
+ }
+ default:
+ // TODO: handle the other cases
+ break;
+ }
+ }
-void VKRenderer::flushCommandBuffer(VkCommandBuffer commandBuffer)
-{
- checkResult(vkEndCommandBuffer(commandBuffer));
+ VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
+ descriptorSetLayoutInfo.bindingCount = uint32_t(dstBindings.Count());
+ descriptorSetLayoutInfo.pBindings = dstBindings.Buffer();
- VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
- submitInfo.commandBufferCount = 1;
- submitInfo.pCommandBuffers = &commandBuffer;
+ SLANG_VK_CHECK(m_api.vkCreateDescriptorSetLayout(m_device, &descriptorSetLayoutInfo, nullptr, &pipeline->m_descriptorSetLayout));
- checkResult(vkQueueSubmit(m_queue, 1, &submitInfo, VK_NULL_HANDLE));
- checkResult(vkQueueWaitIdle(m_queue));
+ // Create a descriptor pool for allocating sets
+ VkDescriptorPoolSize poolSizes[] =
+ {
+ { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 128 },
+ { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 128 },
+ { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 128 },
+ };
- vkFreeCommandBuffers(m_device, m_commandPool, 1, &commandBuffer);
-}
+ VkDescriptorPoolCreateInfo descriptorPoolInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
+ descriptorPoolInfo.maxSets = 128; // TODO: actually pick a size
+ descriptorPoolInfo.poolSizeCount = SLANG_COUNT_OF(poolSizes);
+ descriptorPoolInfo.pPoolSizes = poolSizes;
-SlangResult VKRenderer::_initBuffer(size_t bufferSize, VkBufferUsageFlags usage, VkMemoryPropertyFlags reqMemoryProperties, Buffer& bufferOut)
-{
- assert(!bufferOut.isInitialized());
+ SLANG_VK_CHECK(m_api.vkCreateDescriptorPool(m_device, &descriptorPoolInfo, nullptr, &pipeline->m_descriptorPool));
- bufferOut.m_renderer = this;
- bufferOut.m_memory = 0;
- bufferOut.m_buffer = 0;
-
- VkBufferCreateInfo bufferCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
- bufferCreateInfo.size = bufferSize;
- bufferCreateInfo.usage = usage;
+ // Create a descriptor set based on our layout
- checkResult(vkCreateBuffer(m_device, &bufferCreateInfo, nullptr, &bufferOut.m_buffer));
+ VkDescriptorSetAllocateInfo descriptorSetAllocInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
+ descriptorSetAllocInfo.descriptorPool = pipeline->m_descriptorPool;
+ descriptorSetAllocInfo.descriptorSetCount = 1;
+ descriptorSetAllocInfo.pSetLayouts = &pipeline->m_descriptorSetLayout;
- VkMemoryRequirements memoryReqs = {};
- vkGetBufferMemoryRequirements(m_device, bufferOut.m_buffer, &memoryReqs);
+ SLANG_VK_CHECK(m_api.vkAllocateDescriptorSets(m_device, &descriptorSetAllocInfo, &pipeline->m_descriptorSet));
- uint32_t memoryTypeIndex = getMemoryTypeIndex(memoryReqs.memoryTypeBits, reqMemoryProperties);
+ // Fill in the descriptor set, using our binding information
- VkMemoryPropertyFlags actualMemoryProperites = m_deviceMemoryProperties.memoryTypes[memoryTypeIndex].propertyFlags;
+ int elementIndex = 0;
- VkMemoryAllocateInfo allocateInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
- allocateInfo.allocationSize = memoryReqs.size;
- allocateInfo.memoryTypeIndex = memoryTypeIndex;
+ for (int i = 0; i < numBindings; ++i)
+ {
+ const auto& srcDetail = srcDetails[i];
+ const auto& srcBinding = srcBindings[i];
+
+ switch (srcBinding.bindingType)
+ {
+ case BindingType::Buffer:
+ {
+ BufferResourceImpl* bufferResource = static_cast<BufferResourceImpl*>(srcBinding.resource.Ptr());
+ const BufferResource::Desc& bufferResourceDesc = bufferResource->getDesc();
+
+ VkDescriptorBufferInfo bufferInfo;
+ bufferInfo.buffer = bufferResource->m_buffer.m_buffer;
+ bufferInfo.offset = 0;
+ bufferInfo.range = bufferResourceDesc.sizeInBytes;
+
+ VkWriteDescriptorSet writeInfo = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
+ writeInfo.descriptorCount = 1;
+
+ writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+ if (bufferResource->m_initialUsage == Resource::Usage::UnorderedAccess)
+ {
+ writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+ }
+ else if (bufferResource->m_initialUsage == Resource::Usage::ConstantBuffer)
+ {
+ writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ }
- checkResult(vkAllocateMemory(m_device, &allocateInfo, nullptr, &bufferOut.m_memory));
- checkResult(vkBindBufferMemory(m_device, bufferOut.m_buffer, bufferOut.m_memory, 0));
+ writeInfo.dstSet = pipeline->m_descriptorSet;
+ writeInfo.dstBinding = srcDetail.m_binding;
+ writeInfo.dstArrayElement = 0;
+ writeInfo.pBufferInfo = &bufferInfo;
+
+ m_api.vkUpdateDescriptorSets(m_device, 1, &writeInfo, 0, nullptr);
+
+ break;
+ }
+ default:
+ {
+ // handle other cases
+ break;
+ }
+ }
+ }
+
+ // Create a pipeline layout based on our descriptor set layout(s)
+ VkPipelineLayoutCreateInfo pipelineLayoutInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
+ pipelineLayoutInfo.setLayoutCount = 1;
+ pipelineLayoutInfo.pSetLayouts = &pipeline->m_descriptorSetLayout;
+
+ SLANG_VK_CHECK(m_api.vkCreatePipelineLayout(m_device, &pipelineLayoutInfo, nullptr, &pipeline->m_pipelineLayout));
+
+ VkPipelineCache pipelineCache = VK_NULL_HANDLE;
+
+ if (m_currentProgram->m_pipelineType == PipelineType::Compute)
+ {
+ // Then create a pipeline to use that layout
+
+ VkComputePipelineCreateInfo computePipelineInfo = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO };
+ computePipelineInfo.stage = m_currentProgram->m_compute;
+ computePipelineInfo.layout = pipeline->m_pipelineLayout;
+
+ SLANG_VK_CHECK(m_api.vkCreateComputePipelines(m_device, pipelineCache, 1, &computePipelineInfo, nullptr, &pipeline->m_pipeline));
+ }
+ else if (m_currentProgram->m_pipelineType == PipelineType::Graphics)
+ {
+ // Create the graphics pipeline
+
+ const int width = m_swapChain.getWidth();
+ const int height = m_swapChain.getHeight();
+
+ VkPipelineShaderStageCreateInfo shaderStages[] = { m_currentProgram->m_vertex, m_currentProgram->m_fragment };
+
+ // VertexBuffer/s
+ // Currently only handles one
+
+ VkPipelineVertexInputStateCreateInfo vertexInputInfo = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO };
+ vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
+ vertexInputInfo.vertexBindingDescriptionCount = 0;
+ vertexInputInfo.vertexAttributeDescriptionCount = 0;
+
+ VkVertexInputBindingDescription vertexInputBindingDescription;
+
+ if (m_currentInputLayout)
+ {
+ vertexInputBindingDescription.binding = 0;
+ vertexInputBindingDescription.stride = m_currentInputLayout->m_vertexSize;
+ vertexInputBindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
+
+ const auto& srcAttributeDescs = m_currentInputLayout->m_vertexDescs;
+
+ vertexInputInfo.vertexBindingDescriptionCount = 1;
+ vertexInputInfo.pVertexBindingDescriptions = &vertexInputBindingDescription;
+
+ vertexInputInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(srcAttributeDescs.Count());
+ vertexInputInfo.pVertexAttributeDescriptions = srcAttributeDescs.Buffer();
+ }
+
+ //
+
+ VkPipelineInputAssemblyStateCreateInfo inputAssembly = {};
+ inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
+ inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+ inputAssembly.primitiveRestartEnable = VK_FALSE;
+
+ VkViewport viewport = {};
+ viewport.x = 0.0f;
+ viewport.y = 0.0f;
+ viewport.width = (float)width;
+ viewport.height = (float)height;
+ viewport.minDepth = 0.0f;
+ viewport.maxDepth = 1.0f;
+
+ VkRect2D scissor = {};
+ scissor.offset = { 0, 0 };
+ scissor.extent = { uint32_t(width), uint32_t(height) };
+
+ VkPipelineViewportStateCreateInfo viewportState = {};
+ viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
+ viewportState.viewportCount = 1;
+ viewportState.pViewports = &viewport;
+ viewportState.scissorCount = 1;
+ viewportState.pScissors = &scissor;
+
+ VkPipelineRasterizationStateCreateInfo rasterizer = {};
+ rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
+ rasterizer.depthClampEnable = VK_FALSE;
+ rasterizer.rasterizerDiscardEnable = VK_FALSE;
+ rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
+ rasterizer.lineWidth = 1.0f;
+ rasterizer.cullMode = VK_CULL_MODE_NONE;
+ rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
+ rasterizer.depthBiasEnable = VK_FALSE;
+
+ VkPipelineMultisampleStateCreateInfo multisampling = {};
+ multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
+ multisampling.sampleShadingEnable = VK_FALSE;
+ multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
+
+ VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
+ colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
+ colorBlendAttachment.blendEnable = VK_FALSE;
+
+ VkPipelineColorBlendStateCreateInfo colorBlending = {};
+ colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
+ 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;
+
+ VkGraphicsPipelineCreateInfo pipelineInfo = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO };
+
+ pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
+ pipelineInfo.stageCount = 2;
+ pipelineInfo.pStages = shaderStages;
+ pipelineInfo.pVertexInputState = &vertexInputInfo;
+ pipelineInfo.pInputAssemblyState = &inputAssembly;
+ pipelineInfo.pViewportState = &viewportState;
+ pipelineInfo.pRasterizationState = &rasterizer;
+ pipelineInfo.pMultisampleState = &multisampling;
+ pipelineInfo.pColorBlendState = &colorBlending;
+ pipelineInfo.layout = pipeline->m_pipelineLayout;
+ pipelineInfo.renderPass = m_renderPass;
+ pipelineInfo.subpass = 0;
+ pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
+
+ SLANG_VK_CHECK(m_api.vkCreateGraphicsPipelines(m_device, pipelineCache, 1, &pipelineInfo, nullptr, &pipeline->m_pipeline));
+ }
+ else
+ {
+ assert(!"Unhandled program type");
+ return SLANG_FAIL;
+ }
+
+ pipelineOut = pipeline;
return SLANG_OK;
}
-uint32_t VKRenderer::getMemoryTypeIndex(uint32_t inTypeBits, VkMemoryPropertyFlags properties)
+Result VKRenderer::_beginPass()
{
- uint32_t typeBits = inTypeBits;
- uint32_t typeIndex = 0;
- while (typeBits)
+ if (m_swapChainImageIndex < 0)
{
- if ((m_deviceMemoryProperties.memoryTypes[typeIndex].propertyFlags & properties) == properties)
+ return SLANG_FAIL;
+ }
+
+ const int numRenderTargets = 1;
+
+ const VulkanSwapChain::Image& image = m_swapChain.getImages()[m_swapChainImageIndex];
+
+ int numAttachments = 0;
+
+ // Start render pass
+ VkClearValue clearValues[kMaxAttachments];
+ clearValues[numAttachments++] = VkClearValue{ m_clearColor[0], m_clearColor[1], m_clearColor[2], m_clearColor[3] };
+
+ bool hasDepthBuffer = false;
+ if (hasDepthBuffer)
+ {
+ VkClearValue& clearValue = clearValues[numAttachments++];
+
+ clearValue.depthStencil.depth = 1.0f;
+ clearValue.depthStencil.stencil = 0;
+ }
+
+ const int width = m_swapChain.getWidth();
+ const int height = m_swapChain.getHeight();
+
+ VkCommandBuffer cmdBuffer = m_deviceQueue.getCommandBuffer();
+
+ VkRenderPassBeginInfo renderPassBegin = {};
+ renderPassBegin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+ renderPassBegin.renderPass = m_renderPass;
+ renderPassBegin.framebuffer = image.m_frameBuffer;
+ renderPassBegin.renderArea.offset.x = 0;
+ renderPassBegin.renderArea.offset.y = 0;
+ renderPassBegin.renderArea.extent.width = width;
+ renderPassBegin.renderArea.extent.height = height;
+ renderPassBegin.clearValueCount = numAttachments;
+ renderPassBegin.pClearValues = clearValues;
+
+ m_api.vkCmdBeginRenderPass(cmdBuffer, &renderPassBegin, VK_SUBPASS_CONTENTS_INLINE);
+
+ // Set up scissor and viewport
+ {
+ VkRect2D rects[kMaxRenderTargets] = {};
+ VkViewport viewports[kMaxRenderTargets] = {};
+ for (int i = 0; i < numRenderTargets; ++i)
{
- return typeIndex;
+ rects[i] = VkRect2D{ 0, 0, uint32_t(width), uint32_t(height) };
+
+ VkViewport& dstViewport = viewports[i];
+
+ dstViewport.x = 0.0f;
+ dstViewport.y = 0.0f;
+ dstViewport.width = float(width);
+ dstViewport.height = float(height);
+ dstViewport.minDepth = 0.0f;
+ dstViewport.maxDepth = 1.0f;
}
- typeIndex++;
- typeBits >>= 1;
+
+ m_api.vkCmdSetScissor(cmdBuffer, 0, numRenderTargets, rects);
+ m_api.vkCmdSetViewport(cmdBuffer, 0, numRenderTargets, viewports);
+ }
+
+ return SLANG_OK;
+}
+
+void VKRenderer::_endPass()
+{
+ VkCommandBuffer cmdBuffer = m_deviceQueue.getCommandBuffer();
+ m_api.vkCmdEndRenderPass(cmdBuffer);
+}
+
+void VKRenderer::_beginRender()
+{
+ m_swapChainImageIndex = m_swapChain.nextFrontImageIndex();
+
+ if (m_swapChainImageIndex < 0)
+ {
+ return;
}
+}
- assert(!"failed to find a usable memory type");
- return uint32_t(-1);
+void VKRenderer::_endRender()
+{
+ m_deviceQueue.flush();
+}
+
+Renderer* createVKRenderer()
+{
+ return new VKRenderer;
+}
+
+VKRenderer::~VKRenderer()
+{
+ if (m_renderPass != VK_NULL_HANDLE)
+ {
+ m_api.vkDestroyRenderPass(m_device, m_renderPass, nullptr);
+ m_renderPass = VK_NULL_HANDLE;
+ }
+}
+
+
+VkBool32 VKRenderer::handleDebugMessage(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject,
+ size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg)
+{
+ char const* severity = "message";
+ if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT)
+ severity = "warning";
+ if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT)
+ severity = "error";
+
+ char buffer[1024];
+ sprintf_s(buffer,
+ "%s: %s %d: %s\n",
+ pLayerPrefix,
+ severity,
+ msgCode,
+ pMsg);
+
+ fprintf(stderr, "%s", buffer);
+ fflush(stderr);
+
+ OutputDebugStringA(buffer);
+
+ return VK_FALSE;
+}
+
+/* static */VKAPI_ATTR VkBool32 VKAPI_CALL VKRenderer::debugMessageCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject,
+ size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg, void* pUserData)
+{
+ return ((VKRenderer*)pUserData)->handleDebugMessage(flags, objType, srcObject, location, msgCode, pLayerPrefix, pMsg);
}
VkPipelineShaderStageCreateInfo VKRenderer::compileEntryPoint(const ShaderCompileRequest::EntryPoint& entryPointRequest, VkShaderStageFlagBits stage, List<char>& bufferOut)
@@ -394,15 +761,14 @@ VkPipelineShaderStageCreateInfo VKRenderer::compileEntryPoint(const ShaderCompil
moduleCreateInfo.codeSize = codeSize;
VkShaderModule module;
- checkResult(vkCreateShaderModule(m_device, &moduleCreateInfo, nullptr, &module));
-
- //::free(codeBegin);
+ SLANG_VK_CHECK(m_api.vkCreateShaderModule(m_device, &moduleCreateInfo, nullptr, &module));
VkPipelineShaderStageCreateInfo shaderStageCreateInfo = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO };
shaderStageCreateInfo.stage = stage;
shaderStageCreateInfo.module = module;
shaderStageCreateInfo.pName = "main";
+
return shaderStageCreateInfo;
}
@@ -410,31 +776,22 @@ VkPipelineShaderStageCreateInfo VKRenderer::compileEntryPoint(const ShaderCompil
SlangResult VKRenderer::initialize(void* inWindowHandle)
{
- char const* dynamicLibraryName = "vulkan-1.dll";
- HMODULE vulkan = LoadLibraryA(dynamicLibraryName);
- if (!vulkan)
- {
- fprintf(stderr, "error: failed load '%s'\n", dynamicLibraryName);
- return SLANG_FAIL;
- }
-
- vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)GetProcAddress(vulkan, "vkGetInstanceProcAddr");
- if (!vkGetInstanceProcAddr)
- {
- fprintf(stderr, "error: failed load symbol 'vkGetInstanceProcAddr'\n");
- return SLANG_FAIL;
- }
+ SLANG_RETURN_ON_FAIL(m_module.init());
+ SLANG_RETURN_ON_FAIL(m_api.initGlobalProcs(m_module));
VkApplicationInfo applicationInfo = { VK_STRUCTURE_TYPE_APPLICATION_INFO };
applicationInfo.pApplicationName = "slang-render-test";
applicationInfo.pEngineName = "slang-render-test";
applicationInfo.apiVersion = VK_API_VERSION_1_0;
- char const* instanceExtensions[] = {
+ char const* instanceExtensions[] =
+ {
VK_KHR_SURFACE_EXTENSION_NAME,
-#ifdef _WIN32
+
+#if SLANG_WINDOWS_FAMILY
VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
#else
+ VK_KHR_XLIB_SURFACE_EXTENSION_NAME
#endif
#if ENABLE_VALIDATION_LAYER
@@ -442,35 +799,22 @@ SlangResult VKRenderer::initialize(void* inWindowHandle)
#endif
};
+ VkInstance instance = VK_NULL_HANDLE;
+
VkInstanceCreateInfo instanceCreateInfo = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };
instanceCreateInfo.pApplicationInfo = &applicationInfo;
- instanceCreateInfo.enabledExtensionCount = sizeof(instanceExtensions) / sizeof(instanceExtensions[0]);
+ instanceCreateInfo.enabledExtensionCount = SLANG_COUNT_OF(instanceExtensions);
instanceCreateInfo.ppEnabledExtensionNames = &instanceExtensions[0];
#if ENABLE_VALIDATION_LAYER
-
- uint32_t layerCount = 1;
- const char *layerNames[] = {
- "VK_LAYER_LUNARG_standard_validation"
- };
-
- instanceCreateInfo.enabledLayerCount = layerCount;
+ const char* layerNames[] = { "VK_LAYER_LUNARG_standard_validation" };
+ instanceCreateInfo.enabledLayerCount = SLANG_COUNT_OF(layerNames);
instanceCreateInfo.ppEnabledLayerNames = layerNames;
#endif
- m_instance = 0;
-
-#define LOAD_INSTANCE_PROC(NAME) NAME = (PFN_##NAME) vkGetInstanceProcAddr(m_instance, #NAME);
-
- FOREACH_GLOBAL_PROC(LOAD_INSTANCE_PROC);
-
- RETURN_ON_VK_FAIL(vkCreateInstance(&instanceCreateInfo, nullptr, &m_instance));
-
- FOREACH_INSTANCE_PROC(LOAD_INSTANCE_PROC);
-
-#undef LOAD_INSTANCE_PROC
-
+ SLANG_VK_RETURN_ON_FAIL(m_api.vkCreateInstance(&instanceCreateInfo, nullptr, &instance));
+ SLANG_RETURN_ON_FAIL(m_api.initInstanceProcs(instance));
#if ENABLE_VALIDATION_LAYER
VkDebugReportFlagsEXT debugFlags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
@@ -480,43 +824,23 @@ SlangResult VKRenderer::initialize(void* inWindowHandle)
debugCreateInfo.pUserData = this;
debugCreateInfo.flags = debugFlags;
- RETURN_ON_VK_FAIL(vkCreateDebugReportCallbackEXT(m_instance, &debugCreateInfo, nullptr, &m_debugReportCallback));
-
+ SLANG_VK_RETURN_ON_FAIL(m_api.vkCreateDebugReportCallbackEXT(instance, &debugCreateInfo, nullptr, &m_debugReportCallback));
#endif
- uint32_t physicalDeviceCount = 0;
- RETURN_ON_VK_FAIL(vkEnumeratePhysicalDevices(m_instance, &physicalDeviceCount, nullptr));
+ uint32_t numPhysicalDevices = 0;
+ SLANG_VK_RETURN_ON_FAIL(m_api.vkEnumeratePhysicalDevices(instance, &numPhysicalDevices, nullptr));
- VkPhysicalDevice* physicalDevices = (VkPhysicalDevice*)alloca(physicalDeviceCount * sizeof(VkPhysicalDevice));
- RETURN_ON_VK_FAIL(vkEnumeratePhysicalDevices(m_instance, &physicalDeviceCount, physicalDevices));
+ List<VkPhysicalDevice> physicalDevices;
+ physicalDevices.SetSize(numPhysicalDevices);
+ SLANG_VK_RETURN_ON_FAIL(m_api.vkEnumeratePhysicalDevices(instance, &numPhysicalDevices, physicalDevices.Buffer()));
- uint32_t selectedDeviceIndex = 0;
// TODO: allow override of selected device
- m_physicalDevice = physicalDevices[selectedDeviceIndex];
-
- vkGetPhysicalDeviceProperties(m_physicalDevice, &m_deviceProperties);
- vkGetPhysicalDeviceFeatures(m_physicalDevice, &m_deviceFeatures);
- vkGetPhysicalDeviceMemoryProperties(m_physicalDevice, &m_deviceMemoryProperties);
-
- uint32_t queueFamilyCount = 0;
- vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice, &queueFamilyCount, nullptr);
-
- VkQueueFamilyProperties* queueFamilies = (VkQueueFamilyProperties*)alloca(queueFamilyCount * sizeof(VkQueueFamilyProperties));
- vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice, &queueFamilyCount, queueFamilies);
-
- // Find a queue that can service our needs
- VkQueueFlags reqQueueFlags = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT;
-
- uint32_t queueFamilyIndex = uint32_t(-1);
- for (uint32_t qq = 0; qq < queueFamilyCount; ++qq)
- {
- if ((queueFamilies[qq].queueFlags & reqQueueFlags) == reqQueueFlags)
- {
- queueFamilyIndex = qq;
- break;
- }
- }
- assert(queueFamilyIndex < queueFamilyCount);
+ uint32_t selectedDeviceIndex = 0;
+
+ SLANG_RETURN_ON_FAIL(m_api.initPhysicalDevice(physicalDevices[selectedDeviceIndex]));
+
+ int queueFamilyIndex = m_api.findQueue(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT);
+ assert(queueFamilyIndex >= 0);
float queuePriority = 0.0f;
VkDeviceQueueCreateInfo queueCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO };
@@ -532,48 +856,136 @@ SlangResult VKRenderer::initialize(void* inWindowHandle)
VkDeviceCreateInfo deviceCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
deviceCreateInfo.queueCreateInfoCount = 1;
deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo;
- deviceCreateInfo.pEnabledFeatures = &m_deviceFeatures;
-
- deviceCreateInfo.enabledExtensionCount = sizeof(deviceExtensions) / sizeof(deviceExtensions[0]);
- deviceCreateInfo.ppEnabledExtensionNames = &deviceExtensions[0];
+ deviceCreateInfo.pEnabledFeatures = &m_api.m_deviceFeatures;
- RETURN_ON_VK_FAIL(vkCreateDevice(m_physicalDevice, &deviceCreateInfo, nullptr, &m_device));
+ deviceCreateInfo.enabledExtensionCount = SLANG_COUNT_OF(deviceExtensions);
+ deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions;
-#define LOAD_DEVICE_PROC(NAME) NAME = (PFN_##NAME) vkGetDeviceProcAddr(m_device, #NAME);
- FOREACH_DEVICE_PROC(LOAD_DEVICE_PROC)
-#undef LOAD_DEVICE_PROC
+ SLANG_VK_RETURN_ON_FAIL(m_api.vkCreateDevice(m_api.m_physicalDevice, &deviceCreateInfo, nullptr, &m_device));
+ SLANG_RETURN_ON_FAIL(m_api.initDeviceProcs(m_device));
- // Create a command pool
-
- VkCommandPoolCreateInfo commandPoolCreateInfo = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
- commandPoolCreateInfo.queueFamilyIndex = queueFamilyIndex;
- commandPoolCreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
-
- RETURN_ON_VK_FAIL(vkCreateCommandPool(m_device, &commandPoolCreateInfo, nullptr, &m_commandPool));
-
- vkGetDeviceQueue(m_device, queueFamilyIndex, 0, &m_queue);
+ {
+ VkQueue queue;
+ m_api.vkGetDeviceQueue(m_device, queueFamilyIndex, 0, &queue);
+ SLANG_RETURN_ON_FAIL(m_deviceQueue.init(m_api, queue, queueFamilyIndex));
+ }
// set up swap chain
+ {
+ VulkanSwapChain::Desc desc;
+ VulkanSwapChain::PlatformDesc* platformDesc = nullptr;
+
+ desc.init();
+ desc.m_format = Format::RGBA_Unorm_UInt8;
+#if SLANG_WINDOWS_FAMILY
+ VulkanSwapChain::WinPlatformDesc winPlatformDesc;
+ winPlatformDesc.m_hinstance = ::GetModuleHandle(nullptr);
+ winPlatformDesc.m_hwnd = (HWND)inWindowHandle;
+ platformDesc = &winPlatformDesc;
+#endif
- // create command buffers
+ SLANG_RETURN_ON_FAIL(m_swapChain.init(&m_deviceQueue, desc, platformDesc));
+ }
// depth/stencil?
// render pass?
- // pipeline cache
+ {
+ const int numRenderTargets = 1;
+ bool shouldClear = true;
+ bool shouldClearDepth = false;
+ bool shouldClearStencil = false;
+ bool hasDepthBuffer = false;
+
+ Format depthFormat = Format::Unknown;
+ VkFormat colorFormat = m_swapChain.getVkFormat();
+
+ int numAttachments = 0;
+ // We need extra space if we have depth buffer
+ VkAttachmentDescription attachmentDesc[kMaxRenderTargets + 1] = {};
+ for (int i = 0; i < numRenderTargets; ++i)
+ {
+ VkAttachmentDescription& dst = attachmentDesc[numAttachments ++];
+
+ dst.flags = 0;
+ dst.format = colorFormat;
+ dst.samples = VK_SAMPLE_COUNT_1_BIT;
+ dst.loadOp = shouldClear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD;
+ dst.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+ dst.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ dst.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ dst.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+ dst.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+ }
+ if (hasDepthBuffer)
+ {
+ VkAttachmentDescription& dst = attachmentDesc[numAttachments++];
+
+ dst.flags = 0;
+ dst.format = VulkanUtil::getVkFormat(depthFormat);
+ dst.samples = VK_SAMPLE_COUNT_1_BIT;
+ dst.loadOp = shouldClearDepth ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD;
+ dst.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+ dst.stencilLoadOp = shouldClearStencil ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD;
+ dst.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
+ dst.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+ dst.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+ }
- // frame buffer
+ VkAttachmentReference colorAttachments[kMaxRenderTargets] = {};
+ for (int i = 0; i < numRenderTargets; ++i)
+ {
+ VkAttachmentReference& dst = colorAttachments[i];
+ dst.attachment = i;
+ dst.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+ }
+ VkAttachmentReference depthAttachment = {};
+ depthAttachment.attachment = numRenderTargets;
+ depthAttachment.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+
+ VkSubpassDescription subpassDesc = {};
+ subpassDesc.flags = 0;
+ subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+ subpassDesc.inputAttachmentCount = 0u;
+ subpassDesc.pInputAttachments = nullptr;
+ subpassDesc.colorAttachmentCount = numRenderTargets;
+ subpassDesc.pColorAttachments = colorAttachments;
+ subpassDesc.pResolveAttachments = nullptr;
+ subpassDesc.pDepthStencilAttachment = hasDepthBuffer ? &depthAttachment : nullptr;
+ subpassDesc.preserveAttachmentCount = 0u;
+ subpassDesc.pPreserveAttachments = nullptr;
+
+ VkRenderPassCreateInfo renderPassCreateInfo = {};
+ renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
+ renderPassCreateInfo.attachmentCount = numAttachments;
+ renderPassCreateInfo.pAttachments = attachmentDesc;
+ renderPassCreateInfo.subpassCount = 1;
+ renderPassCreateInfo.pSubpasses = &subpassDesc;
+ SLANG_VK_RETURN_ON_FAIL(m_api.vkCreateRenderPass(m_device, &renderPassCreateInfo, nullptr, &m_renderPass));
+ }
+ // frame buffer
+ SLANG_RETURN_ON_FAIL(m_swapChain.createFrameBuffers(m_renderPass));
- // create semaphores for sync
+ _beginRender();
return SLANG_OK;
}
+void VKRenderer::submitGpuWork()
+{
+ m_deviceQueue.flush();
+}
+
+void VKRenderer::waitForGpu()
+{
+ m_deviceQueue.flushAndWait();
+}
+
void VKRenderer::setClearColor(const float color[4])
{
for (int ii = 0; ii < 4; ++ii)
@@ -585,7 +997,13 @@ void VKRenderer::clearFrame()
}
void VKRenderer::presentFrame()
-{
+{
+ _endRender();
+
+ const bool vsync = true;
+ m_swapChain.present(vsync);
+
+ _beginRender();
}
SlangResult VKRenderer::captureScreenShot(char const* outputPath)
@@ -672,11 +1090,11 @@ BufferResource* VKRenderer::createBufferResource(Resource::Usage initialUsage, c
}
RefPtr<BufferResourceImpl> buffer(new BufferResourceImpl(initialUsage, desc, this));
- SLANG_RETURN_NULL_ON_FAIL(_initBuffer(desc.sizeInBytes, usage, reqMemoryProperties, buffer->m_buffer));
+ SLANG_RETURN_NULL_ON_FAIL(buffer->m_buffer.init(m_api, desc.sizeInBytes, usage, reqMemoryProperties));
if ((desc.cpuAccessFlags & Resource::AccessFlag::Write) || initData)
{
- SLANG_RETURN_NULL_ON_FAIL(_initBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, buffer->m_uploadBuffer));
+ SLANG_RETURN_NULL_ON_FAIL(buffer->m_uploadBuffer.init(m_api, bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT));
}
if (initData)
@@ -686,30 +1104,57 @@ BufferResource* VKRenderer::createBufferResource(Resource::Usage initialUsage, c
// directly.
// Copy into staging buffer
void* mappedData = nullptr;
- checkResult(vkMapMemory(m_device, buffer->m_uploadBuffer.m_memory, 0, bufferSize, 0, &mappedData));
- memcpy(mappedData, initData, bufferSize);
- vkUnmapMemory(m_device, buffer->m_uploadBuffer.m_memory);
+ SLANG_VK_CHECK(m_api.vkMapMemory(m_device, buffer->m_uploadBuffer.m_memory, 0, bufferSize, 0, &mappedData));
+ ::memcpy(mappedData, initData, bufferSize);
+ m_api.vkUnmapMemory(m_device, buffer->m_uploadBuffer.m_memory);
// Copy from staging buffer to real buffer
- VkCommandBuffer commandBuffer = beginCommandBuffer();
-
+ VkCommandBuffer commandBuffer = m_deviceQueue.getCommandBuffer();
+
VkBufferCopy copyInfo = {};
copyInfo.size = bufferSize;
- vkCmdCopyBuffer(commandBuffer, buffer->m_uploadBuffer.m_buffer, buffer->m_buffer.m_buffer, 1, &copyInfo);
+ m_api.vkCmdCopyBuffer(commandBuffer, buffer->m_uploadBuffer.m_buffer, buffer->m_buffer.m_buffer, 1, &copyInfo);
- flushCommandBuffer(commandBuffer);
+ //flushCommandBuffer(commandBuffer);
}
return buffer.detach();
}
-InputLayout* VKRenderer::createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount)
+InputLayout* VKRenderer::createInputLayout(const InputElementDesc* elements, UInt numElements)
{
- InputLayoutImpl* impl = new InputLayoutImpl;
+ RefPtr<InputLayoutImpl> layout(new InputLayoutImpl);
+
+ List<VkVertexInputAttributeDescription>& dstVertexDescs = layout->m_vertexDescs;
- // TODO: actually initialize things
+ size_t vertexSize = 0;
+ dstVertexDescs.SetSize(numElements);
+
+ for (UInt i = 0; i < numElements; ++i)
+ {
+ const InputElementDesc& srcDesc = elements[i];
+ VkVertexInputAttributeDescription& dstDesc = dstVertexDescs[i];
+
+ dstDesc.location = uint32_t(i);
+ dstDesc.binding = 0;
+ dstDesc.format = VulkanUtil::getVkFormat(srcDesc.format);
+ if (dstDesc.format == VK_FORMAT_UNDEFINED)
+ {
+ return nullptr;
+ }
+
+ dstDesc.offset = uint32_t(srcDesc.offset);
+
+ const size_t elementSize = RendererUtil::getFormatSize(srcDesc.format);
+ assert(elementSize > 0);
+ const size_t endElement = srcDesc.offset + elementSize;
+
+ vertexSize = (vertexSize < endElement) ? endElement : vertexSize;
+ }
- return (InputLayout*)impl;
+ // Work out the overall size
+ layout->m_vertexSize = int(vertexSize);
+ return layout.detach();
}
void* VKRenderer::map(BufferResource* bufferIn, MapFlavor flavor)
@@ -717,6 +1162,9 @@ void* VKRenderer::map(BufferResource* bufferIn, MapFlavor flavor)
BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(bufferIn);
assert(buffer->m_mapFlavor == MapFlavor::Unknown);
+ // Make sure everything has completed before reading...
+ m_deviceQueue.flushAndWait();
+
const size_t bufferSize = buffer->getDesc().sizeInBytes;
switch (flavor)
@@ -730,7 +1178,7 @@ void* VKRenderer::map(BufferResource* bufferIn, MapFlavor flavor)
}
void* mappedData = nullptr;
- checkResult(vkMapMemory(m_device, buffer->m_uploadBuffer.m_memory, 0, bufferSize, 0, &mappedData));
+ SLANG_VK_CHECK(m_api.vkMapMemory(m_device, buffer->m_uploadBuffer.m_memory, 0, bufferSize, 0, &mappedData));
buffer->m_mapFlavor = flavor;
return mappedData;
}
@@ -742,23 +1190,25 @@ void* VKRenderer::map(BufferResource* bufferIn, MapFlavor flavor)
// create staging buffer
Buffer staging;
- SLANG_RETURN_NULL_ON_FAIL(_initBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, staging));
+ SLANG_RETURN_NULL_ON_FAIL(staging.init(m_api, bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT));
// Copy from real buffer to staging buffer
- VkCommandBuffer commandBuffer = beginCommandBuffer();
+ VkCommandBuffer commandBuffer = m_deviceQueue.getCommandBuffer();
VkBufferCopy copyInfo = {};
copyInfo.size = bufferSize;
- vkCmdCopyBuffer(commandBuffer, buffer->m_buffer.m_buffer, staging.m_buffer, 1, &copyInfo);
+ m_api.vkCmdCopyBuffer(commandBuffer, buffer->m_buffer.m_buffer, staging.m_buffer, 1, &copyInfo);
- flushCommandBuffer(commandBuffer);
+ m_deviceQueue.flushAndWait();
// Write out the data from the buffer
void* mappedData = nullptr;
- checkResult(vkMapMemory(m_device, staging.m_memory, 0, bufferSize, 0, &mappedData));
+ SLANG_VK_CHECK(m_api.vkMapMemory(m_device, staging.m_memory, 0, bufferSize, 0, &mappedData));
::memcpy(buffer->m_readBuffer.Buffer(), mappedData, bufferSize);
- vkUnmapMemory(m_device, staging.m_memory);
+ m_api.vkUnmapMemory(m_device, staging.m_memory);
+
+ buffer->m_mapFlavor = flavor;
return buffer->m_readBuffer.Buffer();
}
@@ -779,16 +1229,17 @@ void VKRenderer::unmap(BufferResource* bufferIn)
case MapFlavor::WriteDiscard:
case MapFlavor::HostWrite:
{
- vkUnmapMemory(m_device, buffer->m_uploadBuffer.m_memory);
+ m_api.vkUnmapMemory(m_device, buffer->m_uploadBuffer.m_memory);
// Copy from staging buffer to real buffer
- VkCommandBuffer commandBuffer = beginCommandBuffer();
+ VkCommandBuffer commandBuffer = m_deviceQueue.getCommandBuffer();
VkBufferCopy copyInfo = {};
copyInfo.size = bufferSize;
- vkCmdCopyBuffer(commandBuffer, buffer->m_uploadBuffer.m_buffer, buffer->m_buffer.m_buffer, 1, &copyInfo);
+ m_api.vkCmdCopyBuffer(commandBuffer, buffer->m_uploadBuffer.m_buffer, buffer->m_buffer.m_buffer, 1, &copyInfo);
- flushCommandBuffer(commandBuffer);
+ // TODO: is this necessary?
+ //m_deviceQueue.flushAndWait();
break;
}
default: break;
@@ -800,14 +1251,37 @@ void VKRenderer::unmap(BufferResource* bufferIn)
void VKRenderer::setInputLayout(InputLayout* inputLayout)
{
+ m_currentInputLayout = static_cast<InputLayoutImpl*>(inputLayout);
}
void VKRenderer::setPrimitiveTopology(PrimitiveTopology topology)
{
+ m_primitiveTopology = VulkanUtil::getVkPrimitiveTopology(topology);
}
void VKRenderer::setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* strides, const UInt* offsets)
{
+ {
+ const UInt num = startSlot + slotCount;
+ if (num > m_boundVertexBuffers.Count())
+ {
+ m_boundVertexBuffers.SetSize(num);
+ }
+ }
+
+ for (UInt i = 0; i < slotCount; i++)
+ {
+ BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(buffers[i]);
+ if (buffer)
+ {
+ assert(buffer->m_initialUsage == Resource::Usage::VertexBuffer);
+ }
+
+ BoundVertexBuffer& boundBuffer = m_boundVertexBuffers[startSlot + i];
+ boundBuffer.m_buffer = buffer;
+ boundBuffer.m_stride = int(strides[i]);
+ boundBuffer.m_offset = int(offsets[i]);
+ }
}
void VKRenderer::setShaderProgram(ShaderProgram* program)
@@ -815,12 +1289,58 @@ void VKRenderer::setShaderProgram(ShaderProgram* program)
m_currentProgram = (ShaderProgramImpl*)program;
}
-void VKRenderer::setConstantBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* offsets)
+void VKRenderer::draw(UInt vertexCount, UInt startVertex = 0)
{
+ Pipeline* pipeline = _getPipeline();
+ if (!pipeline || pipeline->m_shaderProgram->m_pipelineType != PipelineType::Graphics)
+ {
+ assert(!"Invalid render pipeline");
+ return;
+ }
+
+ SLANG_RETURN_VOID_ON_FAIL(_beginPass());
+
+ // Also create descriptor sets based on the given pipeline layout
+ VkCommandBuffer commandBuffer = m_deviceQueue.getCommandBuffer();
+
+ m_api.vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->m_pipeline);
+ m_api.vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->m_pipelineLayout,
+ 0, 1, &pipeline->m_descriptorSet, 0, nullptr);
+
+ // Bind the vertex buffer
+ if (m_boundVertexBuffers.Count() > 0 && m_boundVertexBuffers[0].m_buffer)
+ {
+ const BoundVertexBuffer& boundVertexBuffer = m_boundVertexBuffers[0];
+
+ VkBuffer vertexBuffers[] = { boundVertexBuffer.m_buffer->m_buffer.m_buffer };
+ VkDeviceSize offsets[] = { VkDeviceSize(boundVertexBuffer.m_offset) };
+
+ m_api.vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets);
+ }
+
+ m_api.vkCmdDraw(commandBuffer, static_cast<uint32_t>(vertexCount), 1, 0, 0);
+
+ _endPass();
}
-void VKRenderer::draw(UInt vertexCount, UInt startVertex = 0)
+void VKRenderer::dispatchCompute(int x, int y, int z)
{
+ Pipeline* pipeline = _getPipeline();
+ if (!pipeline || pipeline->m_shaderProgram->m_pipelineType != PipelineType::Compute)
+ {
+ assert(!"Invalid render pipeline");
+ return;
+ }
+
+ // Also create descriptor sets based on the given pipeline layout
+ VkCommandBuffer commandBuffer = m_deviceQueue.getCommandBuffer();
+
+ m_api.vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline->m_pipeline);
+
+ m_api.vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline->m_pipelineLayout,
+ 0, 1, &pipeline->m_descriptorSet, 0, nullptr);
+
+ m_api.vkCmdDispatch(commandBuffer, x, y, z);
}
BindingState* VKRenderer::createBindingState(const BindingState::Desc& bindingStateDesc)
@@ -871,172 +1391,12 @@ void VKRenderer::setBindingState(BindingState* state)
m_currentBindingState = static_cast<BindingStateImpl*>(state);
}
-void VKRenderer::dispatchCompute(int x, int y, int z)
-{
- // HACK: create a new pipeline for every call
-
- // First create a pipeline layout based on what is bound
-
- const auto& srcDetails = m_currentBindingState->m_bindingDetails;
- const auto& srcBindings = m_currentBindingState->getDesc().m_bindings;
-
- const int numBindings = int(srcBindings.Count());
-
- Slang::List<VkDescriptorSetLayoutBinding> dstBindings;
- for (int i = 0; i < numBindings; ++i)
- {
- const auto& srcDetail = srcDetails[i];
- const auto& srcBinding = srcBindings[i];
-
- switch (srcBinding.bindingType)
- {
- case BindingType::Buffer:
- {
- BufferResourceImpl* bufferResource = static_cast<BufferResourceImpl*>(srcBinding.resource.Ptr());
- const BufferResource::Desc& bufferResourceDesc = bufferResource->getDesc();
-
- if (bufferResourceDesc.bindFlags & Resource::BindFlag::UnorderedAccess)
- {
- VkDescriptorSetLayoutBinding dstBinding = {};
- dstBinding.binding = srcDetail.m_binding;
- dstBinding.descriptorCount = 1;
- dstBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
- dstBinding.stageFlags = VK_SHADER_STAGE_ALL;
-
- dstBindings.Add(dstBinding);
- }
-
- break;
- }
- default:
- // TODO: handle the other cases
- break;
- }
- }
-
- VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
- descriptorSetLayoutInfo.bindingCount = uint32_t(dstBindings.Count());
- descriptorSetLayoutInfo.pBindings = dstBindings.Buffer();
-
- VkDescriptorSetLayout descriptorSetLayout = 0;
- checkResult(vkCreateDescriptorSetLayout(m_device, &descriptorSetLayoutInfo, nullptr, &descriptorSetLayout));
-
- // Create a descriptor pool for allocating sets
-
- VkDescriptorPoolSize poolSizes[] =
- {
- { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 128 },
- { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 128 },
- { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 128 },
- };
-
- VkDescriptorPoolCreateInfo descriptorPoolInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
- descriptorPoolInfo.maxSets = 128; // TODO: actually pick a size
- descriptorPoolInfo.poolSizeCount = sizeof(poolSizes) / sizeof(poolSizes[0]);
- descriptorPoolInfo.pPoolSizes = poolSizes;
-
- VkDescriptorPool descriptorPool;
- checkResult(vkCreateDescriptorPool(m_device, &descriptorPoolInfo, nullptr, &descriptorPool));
-
- // Create a descriptor set based on our layout
-
- VkDescriptorSetAllocateInfo descriptorSetAllocInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
- descriptorSetAllocInfo.descriptorPool = descriptorPool;
- descriptorSetAllocInfo.descriptorSetCount = 1;
- descriptorSetAllocInfo.pSetLayouts = &descriptorSetLayout;
-
- VkDescriptorSet descriptorSet;
- checkResult(vkAllocateDescriptorSets(m_device, &descriptorSetAllocInfo, &descriptorSet));
-
- // Fill in the descriptor set, using our binding information
-
- for (int i = 0; i < numBindings; ++i)
- {
- const auto& srcDetail = srcDetails[i];
- const auto& srcBinding = srcBindings[i];
-
- switch (srcBinding.bindingType)
- {
- case BindingType::Buffer:
- {
- BufferResourceImpl* bufferResource = static_cast<BufferResourceImpl*>(srcBinding.resource.Ptr());
- const BufferResource::Desc& bufferResourceDesc = bufferResource->getDesc();
-
- if (bufferResourceDesc.bindFlags & Resource::BindFlag::UnorderedAccess)
- {
- VkDescriptorBufferInfo bufferInfo;
- bufferInfo.buffer = bufferResource->m_buffer.m_buffer;
- bufferInfo.offset = 0;
- bufferInfo.range = bufferResourceDesc.sizeInBytes;
-
- VkWriteDescriptorSet writeInfo = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
- writeInfo.descriptorCount = 1;
- writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
- writeInfo.dstSet = descriptorSet;
- writeInfo.dstBinding = srcDetail.m_binding;
- writeInfo.dstArrayElement = 0;
- writeInfo.pBufferInfo = &bufferInfo;
-
- vkUpdateDescriptorSets(m_device, 1, &writeInfo, 0, nullptr);
- }
- break;
- }
- default:
- {
- // handle other cases
- break;
- }
- }
- }
-
- // Create a pipeline layout based on our descriptor set layout(s)
-
- VkPipelineLayoutCreateInfo pipelineLayoutInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
- pipelineLayoutInfo.setLayoutCount = 1;
- pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout;
-
- VkPipelineLayout pipelineLayout = 0;
- checkResult(vkCreatePipelineLayout(m_device, &pipelineLayoutInfo, nullptr, &pipelineLayout));
-
- // Then create a pipeline to use that layout
-
- VkComputePipelineCreateInfo computePipelineInfo = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO };
- computePipelineInfo.stage = m_currentProgram->m_compute;
- computePipelineInfo.layout = pipelineLayout;
-
- VkPipelineCache pipelineCache = 0;
-
- VkPipeline pipeline;
- checkResult(vkCreateComputePipelines(m_device, pipelineCache, 1, &computePipelineInfo, nullptr, &pipeline));
-
- // Also create descriptor sets based on the given pipeline layout
-
- VkCommandBuffer commandBuffer = beginCommandBuffer();
-
- vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline);
-
- vkCmdBindDescriptorSets(
- commandBuffer,
- VK_PIPELINE_BIND_POINT_COMPUTE,
- pipelineLayout,
- 0, 1,
- &descriptorSet,
- 0,
- nullptr);
-
- vkCmdDispatch(commandBuffer, x, y, z);
-
- flushCommandBuffer(commandBuffer);
-
- vkDestroyPipeline(m_device, pipeline, nullptr);
-
- // TODO: need to free up the other resources too...
-}
-
// ShaderCompiler interface
-ShaderProgram* VKRenderer::compileProgram(const ShaderCompileRequest & request)
+ShaderProgram* VKRenderer::compileProgram(const ShaderCompileRequest& request)
{
- ShaderProgramImpl* impl = new ShaderProgramImpl;
+ const PipelineType pipelineType = request.computeShader.name ? PipelineType::Compute : PipelineType::Graphics;
+
+ ShaderProgramImpl* impl = new ShaderProgramImpl(pipelineType);
if (request.computeShader.name)
{
impl->m_compute = compileEntryPoint(request.computeShader, VK_SHADER_STAGE_COMPUTE_BIT, impl->m_buffers[0]);