diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2018-03-21 14:28:43 -0400 |
|---|---|---|
| committer | Tim Foley <tfoleyNV@users.noreply.github.com> | 2018-03-21 11:28:43 -0700 |
| commit | d421988f91d0d6fda78b9aea4cba763f9c662ffe (patch) | |
| tree | 4207ebec4a744f67df540388133033753cffa359 /tools/render-test/render-vk.cpp | |
| parent | 98b8e0c809ceab84cee25389e54f3f37d220d95e (diff) | |
First pass impls on ComPtr and reorganise Renderer (#450)
* Fixed some small typos in api-users-guide.md
* Fix some small typos in slang-test/main.cpp, render-test/render-d3d11.cpp
* Remove exit() calls from test code. Added Slang::Result, which works in the same way as COM HRESULT.
* FIx bug introduced when moving to Slang::Result - handling E_INVALIDARG on Dx11.
* Fix the testing of feature levels on Dx11 renderer.
* First attempt at README.md for slang-test.
* Tidied up the slang-test README.md file.
* Fix some small typos in tools/slang-test/main.cpp
* Fix spaces -> tabs problems.
Fix some small types.
* Refactor Renderer implementations such that:
* Class definition does not contain long implementation/s
* Removed unused globals
* Ordered implementation after class definition
* Made renderer specific classes child classes, and use Impl postfix to differentiate
* Converted tabs into spaces
* First pass at Slang::ComPtr. Added slang-defines.h which sets up some fairly commonly used defines such as SLANG_FORCE_INLINE, compiler detection, os detection, and some other cross platform features.
Diffstat (limited to 'tools/render-test/render-vk.cpp')
| -rw-r--r-- | tools/render-test/render-vk.cpp | 1398 |
1 files changed, 693 insertions, 705 deletions
diff --git a/tools/render-test/render-vk.cpp b/tools/render-test/render-vk.cpp index 1f8e11aa6..2c74c8883 100644 --- a/tools/render-test/render-vk.cpp +++ b/tools/render-test/render-vk.cpp @@ -81,6 +81,92 @@ namespace renderer_test { class VKRenderer : public Renderer, public ShaderCompiler { public: + // Renderer implementation + virtual SlangResult initialize(void* inWindowHandle) override; + virtual void setClearColor(float const* color) override; + virtual void clearFrame() override; + virtual void presentFrame() override; + virtual SlangResult captureScreenShot(char const* outputPath) override; + virtual void serializeOutput(BindingState* state, const char * fileName) override; + virtual Buffer* createBuffer(BufferDesc const& desc) override; + virtual InputLayout* createInputLayout(InputElementDesc const* inputElements, UInt inputElementCount) override; + virtual BindingState * createBindingState(const ShaderInputLayout & layout) override; + virtual ShaderCompiler* getShaderCompiler() override; + virtual void* map(Buffer* buffer, MapFlavor flavor) override; + virtual void unmap(Buffer* buffer) override; + virtual void setInputLayout(InputLayout* inputLayout) override; + virtual void setPrimitiveTopology(PrimitiveTopology topology) override; + virtual void setBindingState(BindingState * state); + virtual void setVertexBuffers(UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* strides, UInt const* offsets) override; + virtual void setShaderProgram(ShaderProgram* inProgram) override; + virtual void setConstantBuffers(UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* offsets) override; + virtual void draw(UInt vertexCount, UInt startVertex) override; + virtual void dispatchCompute(int x, int y, int z) override; + + // ShaderCompiler implementation + virtual ShaderProgram* compileProgram(ShaderCompileRequest const& request) override; + + protected: + + struct BufferImpl + { + VkBuffer buffer; + VkDeviceMemory memory; + }; + + struct ShaderProgramImpl + { + VkPipelineShaderStageCreateInfo compute; + VkPipelineShaderStageCreateInfo vertex; + VkPipelineShaderStageCreateInfo fragment; + }; + + struct BindingImpl + { + ShaderInputType type; + InputBufferType bufferType; // Only valid if `type` is `Buffer` + + VkImageView srv; + VkBufferView uav; + VkBuffer buffer; + VkSampler samplerState; + + int binding = 0; + bool isOutput = false; + int bufferLength = 0; + }; + + struct BindingStateImpl + { + Slang::List<BindingImpl> bindings; + int numRenderTargets; + }; + + struct InputLayoutImpl + { + }; + + VkBool32 handleDebugMessage(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject, + size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg); + BufferImpl createBufferImpl(size_t bufferSize, VkBufferUsageFlags usage, VkMemoryPropertyFlags reqMemoryProperties, void const* initData = nullptr); + + VkCommandBuffer getCommandBuffer(); + VkCommandBuffer beginCommandBuffer(); + void flushCommandBuffer(VkCommandBuffer commandBuffer); + + uint32_t getMemoryTypeIndex(uint32_t inTypeBits, VkMemoryPropertyFlags properties); + + VkPipelineShaderStageCreateInfo compileEntryPoint(const ShaderCompileRequest::EntryPoint& entryPointRequest, VkShaderStageFlagBits stage); + + void createInputTexture(const InputTextureDesc& inputDesc, VkImageView& viewOut); + void createInputSampler(const InputSamplerDesc& inputDesc, VkSampler& stateOut); + void createInputBuffer(const ShaderInputLayoutEntry& entry, const InputBufferDesc& bufferDesc, const Slang::List<unsigned int>& bufferData, + VkBuffer& bufferOut, VkBufferView& uavOut, VkImageView& srvOut); + + 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 instance; VkPhysicalDevice physicalDevice; @@ -94,6 +180,10 @@ public: VkSubmitInfo submitInfo; VkDebugReportCallbackEXT debugReportCallback; + BindingStateImpl* currentBindingState = nullptr; + ShaderProgramImpl* currentProgram = nullptr; + + float clearColor[4]; #define DECLARE_PROC(NAME) PFN_##NAME NAME; DECLARE_PROC(vkGetInstanceProcAddr); @@ -101,605 +191,555 @@ public: FOREACH_INSTANCE_PROC(DECLARE_PROC) FOREACH_DEVICE_PROC(DECLARE_PROC) #undef DECLARE_PROC + +}; - // Renderer interface - - static SlangResult toSlangResult(VkResult res) - { - return (res == VK_SUCCESS) ? SLANG_OK : SLANG_FAIL; - } - void checkResult(VkResult result) - { - assert(result == VK_SUCCESS); - } - - VkBool32 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; - } +Renderer* createVKRenderer() +{ + return new VKRenderer(); +} - 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) - { - return ((VKRenderer*) pUserData)->handleDebugMessage( - flags, objType, srcObject, location, msgCode, pLayerPrefix, pMsg); - } +/* static */SlangResult VKRenderer::toSlangResult(VkResult res) +{ + return (res == VK_SUCCESS) ? SLANG_OK : SLANG_FAIL; +} - virtual SlangResult initialize(void* inWindowHandle) override - { - char const* dynamicLibraryName = "vulkan-1.dll"; - HMODULE vulkan = LoadLibraryA(dynamicLibraryName); - if(!vulkan) - { - fprintf(stderr, "error: failed load '%s'\n", dynamicLibraryName); - return SLANG_FAIL; - } +void VKRenderer::checkResult(VkResult result) +{ + assert(result == VK_SUCCESS); +} - vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr) GetProcAddress(vulkan, "vkGetInstanceProcAddr"); - if(!vkGetInstanceProcAddr) - { - fprintf(stderr, "error: failed load symbol 'vkGetInstanceProcAddr'\n"); - return SLANG_FAIL; - } +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; +} - VkApplicationInfo applicationInfo = { VK_STRUCTURE_TYPE_APPLICATION_INFO }; - applicationInfo.pApplicationName = "slang-render-test"; - applicationInfo.pEngineName = "slang-render-test"; - applicationInfo.apiVersion = VK_API_VERSION_1_0; +/* 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); +} - char const* instanceExtensions[] = { - VK_KHR_SURFACE_EXTENSION_NAME, -#ifdef _WIN32 - VK_KHR_WIN32_SURFACE_EXTENSION_NAME, -#else -#endif +VkCommandBuffer VKRenderer::getCommandBuffer() +{ + VkCommandBufferAllocateInfo info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO }; + info.commandPool = commandPool; + info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + info.commandBufferCount = 1; -#if ENABLE_VALIDATION_LAYER - VK_EXT_DEBUG_REPORT_EXTENSION_NAME, -#endif - }; + VkCommandBuffer commandBuffer; + checkResult(vkAllocateCommandBuffers( + device, &info, &commandBuffer)); - VkInstanceCreateInfo instanceCreateInfo = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO }; - instanceCreateInfo.pApplicationInfo = &applicationInfo; + return commandBuffer; +} - instanceCreateInfo.enabledExtensionCount = sizeof(instanceExtensions) / sizeof(instanceExtensions[0]); - instanceCreateInfo.ppEnabledExtensionNames = &instanceExtensions[0]; +VkCommandBuffer VKRenderer::beginCommandBuffer() +{ + VkCommandBuffer commandBuffer = getCommandBuffer(); -#if ENABLE_VALIDATION_LAYER + VkCommandBufferBeginInfo beginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; + checkResult(vkBeginCommandBuffer(commandBuffer, &beginInfo)); - uint32_t layerCount = 1; - const char *layerNames[] = { - "VK_LAYER_LUNARG_standard_validation" - }; + return commandBuffer; +} - instanceCreateInfo.enabledLayerCount = layerCount; - instanceCreateInfo.ppEnabledLayerNames = layerNames; -#endif +void VKRenderer::flushCommandBuffer(VkCommandBuffer commandBuffer) +{ + checkResult(vkEndCommandBuffer(commandBuffer)); - instance = 0; + VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &commandBuffer; -#define LOAD_INSTANCE_PROC(NAME) NAME = (PFN_##NAME) vkGetInstanceProcAddr(instance, #NAME); + checkResult(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); + checkResult(vkQueueWaitIdle(queue)); - FOREACH_GLOBAL_PROC(LOAD_INSTANCE_PROC); + vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer); +} - RETURN_ON_VK_FAIL(vkCreateInstance(&instanceCreateInfo, nullptr, &instance)); +VKRenderer::BufferImpl VKRenderer::createBufferImpl(size_t bufferSize, VkBufferUsageFlags usage, VkMemoryPropertyFlags reqMemoryProperties, void const* initData) +{ + if (initData) + { + // TODO: what if we are allocating it as CPU-writable anyway? + usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; + } - FOREACH_INSTANCE_PROC(LOAD_INSTANCE_PROC); + VkBufferCreateInfo bufferCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; + bufferCreateInfo.size = bufferSize; + bufferCreateInfo.usage = usage; -#undef LOAD_INSTANCE_PROC + VkBuffer buffer; + checkResult(vkCreateBuffer( + device, &bufferCreateInfo, nullptr, &buffer)); + VkMemoryRequirements memoryReqs = {}; + vkGetBufferMemoryRequirements(device, buffer, &memoryReqs); -#if ENABLE_VALIDATION_LAYER - VkDebugReportFlagsEXT debugFlags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT; + uint32_t memoryTypeIndex = getMemoryTypeIndex( + memoryReqs.memoryTypeBits, reqMemoryProperties); - VkDebugReportCallbackCreateInfoEXT debugCreateInfo = { VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT }; - debugCreateInfo.pfnCallback = &debugMessageCallback; - debugCreateInfo.pUserData = this; - debugCreateInfo.flags = debugFlags; + VkMemoryPropertyFlags actualMemoryProperites = deviceMemoryProperties.memoryTypes[memoryTypeIndex].propertyFlags; - RETURN_ON_VK_FAIL(vkCreateDebugReportCallbackEXT(instance, &debugCreateInfo, nullptr, &debugReportCallback)); + VkMemoryAllocateInfo allocateInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; + allocateInfo.allocationSize = memoryReqs.size; + allocateInfo.memoryTypeIndex = memoryTypeIndex; -#endif + VkDeviceMemory memory; + checkResult(vkAllocateMemory( + device, &allocateInfo, nullptr, &memory)); - uint32_t physicalDeviceCount = 0; - RETURN_ON_VK_FAIL(vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, nullptr)); + checkResult(vkBindBufferMemory( + device, buffer, memory, 0)); - VkPhysicalDevice* physicalDevices = (VkPhysicalDevice*)alloca( - physicalDeviceCount * sizeof(VkPhysicalDevice)); - RETURN_ON_VK_FAIL(vkEnumeratePhysicalDevices( - instance, &physicalDeviceCount, physicalDevices)); + if (initData) + { + // TODO: only create staging buffer if the memory type + // used for the buffer doesn't let us fill things in + // directly. - uint32_t selectedDeviceIndex = 0; - // TODO: allow override of selected device - physicalDevice = physicalDevices[selectedDeviceIndex]; + BufferImpl staging = createBufferImpl(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties); - vkGetPhysicalDeviceFeatures(physicalDevice, &deviceFeatures); - vkGetPhysicalDeviceMemoryProperties(physicalDevice, &deviceMemoryProperties); + // Copy into staging buffer + void* mappedData = nullptr; + checkResult(vkMapMemory(device, staging.memory, 0, bufferSize, 0, &mappedData)); + memcpy(mappedData, initData, bufferSize); + vkUnmapMemory(device, staging.memory); - uint32_t queueFamilyCount = 0; - vkGetPhysicalDeviceQueueFamilyProperties( - physicalDevice, &queueFamilyCount, nullptr); + // Copy from staging buffer to real buffer + VkCommandBuffer commandBuffer = beginCommandBuffer(); - VkQueueFamilyProperties* queueFamilies = (VkQueueFamilyProperties*)alloca( - queueFamilyCount * sizeof(VkQueueFamilyProperties)); - vkGetPhysicalDeviceQueueFamilyProperties( - physicalDevice, &queueFamilyCount, queueFamilies); + VkBufferCopy copyInfo = {}; + copyInfo.size = bufferSize; + vkCmdCopyBuffer(commandBuffer, staging.buffer, buffer, 1, ©Info); - // Find a queue that can service our needs - VkQueueFlags reqQueueFlags = - VK_QUEUE_GRAPHICS_BIT - | VK_QUEUE_COMPUTE_BIT; + flushCommandBuffer(commandBuffer); - 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); + // Now destroy the staging buffer + vkDestroyBuffer(device, staging.buffer, nullptr); + vkFreeMemory(device, staging.memory, nullptr); + } - float queuePriority = 0.0f; - VkDeviceQueueCreateInfo queueCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO }; - queueCreateInfo.queueFamilyIndex = queueFamilyIndex; - queueCreateInfo.queueCount = 1; - queueCreateInfo.pQueuePriorities = &queuePriority; + BufferImpl impl; + impl.buffer = buffer; + impl.memory = memory; + return impl; +} - char const* const deviceExtensions[] = +uint32_t VKRenderer::getMemoryTypeIndex(uint32_t inTypeBits, VkMemoryPropertyFlags properties) +{ + uint32_t typeBits = inTypeBits; + uint32_t typeIndex = 0; + while (typeBits) + { + if ((deviceMemoryProperties.memoryTypes[typeIndex].propertyFlags & properties) == properties) { - VK_KHR_SWAPCHAIN_EXTENSION_NAME, - }; + return typeIndex; + } + typeIndex++; + typeBits >>= 1; + } - VkDeviceCreateInfo deviceCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO }; - deviceCreateInfo.queueCreateInfoCount = 1; - deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo; - deviceCreateInfo.pEnabledFeatures = &enabledFeatures; + assert(!"failed to find a usable memory type"); + return uint32_t(-1); +} - deviceCreateInfo.enabledExtensionCount = sizeof(deviceExtensions) / sizeof(deviceExtensions[0]); - deviceCreateInfo.ppEnabledExtensionNames = &deviceExtensions[0]; +void VKRenderer::createInputTexture(const InputTextureDesc& inputDesc, VkImageView& viewOut) +{ + TextureData texData; + generateTextureData(texData, inputDesc); + assert(!"unimplemented"); +} - RETURN_ON_VK_FAIL(vkCreateDevice( - physicalDevice, &deviceCreateInfo, nullptr, &device)); +void VKRenderer::createInputSampler(const InputSamplerDesc& inputDesc, VkSampler& stateOut) +{ + assert(!"unimplemented"); +} -#define LOAD_DEVICE_PROC(NAME) NAME = (PFN_##NAME) vkGetDeviceProcAddr(device, #NAME); - FOREACH_DEVICE_PROC(LOAD_DEVICE_PROC) -#undef LOAD_DEVICE_PROC +void VKRenderer::createInputBuffer(const ShaderInputLayoutEntry& entry, const InputBufferDesc& bufferDesc, const Slang::List<unsigned int>& bufferData, + VkBuffer& bufferOut, VkBufferView& uavOut, VkImageView& srvOut) +{ + size_t bufferSize = bufferData.Count() * sizeof(unsigned int); + void const* initData = bufferData.Buffer(); - // Create a command pool + VkBufferUsageFlags usage = 0; + VkMemoryPropertyFlags reqMemoryProperties = 0; - VkCommandPoolCreateInfo commandPoolCreateInfo = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO }; - commandPoolCreateInfo.queueFamilyIndex = queueFamilyIndex; - commandPoolCreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + switch (bufferDesc.type) + { + case InputBufferType::ConstantBuffer: + usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + reqMemoryProperties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + break; - RETURN_ON_VK_FAIL(vkCreateCommandPool( - device, &commandPoolCreateInfo, nullptr, &commandPool)); + case InputBufferType::StorageBuffer: + usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; + reqMemoryProperties = 0; + break; + } - vkGetDeviceQueue( - device, - queueFamilyIndex, - 0, - &queue); + // If we are going to read back from the buffer, be sure to request + // the required access. + if (entry.isOutput) + { + usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + } - // set up swap chain + BufferImpl bufferImpl = createBufferImpl(bufferSize, usage, reqMemoryProperties, initData); + // TODO: need to hang onto the `memory` field so + // that we can release it when we are done. + bufferOut = bufferImpl.buffer; - // create command buffers + // Fill in any views needed + switch (bufferDesc.type) + { + case InputBufferType::ConstantBuffer: + break; - // depth/stencil? + case InputBufferType::StorageBuffer: + { + } + break; + } +} - // render pass? +VkPipelineShaderStageCreateInfo VKRenderer::compileEntryPoint(const ShaderCompileRequest::EntryPoint& entryPointRequest, VkShaderStageFlagBits stage) +{ + char const* dataBegin = entryPointRequest.source.dataBegin; + char const* dataEnd = entryPointRequest.source.dataEnd; - // pipeline cache + // We need to make a copy of the code, since the Slang compiler + // will free the memory after a compile request is closed. + size_t codeSize = dataEnd - dataBegin; + char* codeBegin = (char*)malloc(codeSize); + memcpy(codeBegin, dataBegin, codeSize); - // frame buffer + VkShaderModuleCreateInfo moduleCreateInfo = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO }; + moduleCreateInfo.pCode = (uint32_t*)codeBegin; + moduleCreateInfo.codeSize = codeSize; + VkShaderModule module; + checkResult(vkCreateShaderModule(device, &moduleCreateInfo, nullptr, &module)); + //::free(codeBegin); - // create semaphores for sync + VkPipelineShaderStageCreateInfo shaderStageCreateInfo = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO }; + shaderStageCreateInfo.stage = stage; - return SLANG_OK; - } + shaderStageCreateInfo.module = module; + shaderStageCreateInfo.pName = "main"; + return shaderStageCreateInfo; +} - float clearColor[4]; - virtual void setClearColor(float const* color) override - { - for(int ii = 0; ii < 4; ++ii) - clearColor[ii] = color[ii]; - } +// !!!!!!!!!!!!!!!!!!!!!!!!!!!! Renderer interface !!!!!!!!!!!!!!!!!!!!!!!!!! - virtual void clearFrame() override +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; } - virtual void presentFrame() override + vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)GetProcAddress(vulkan, "vkGetInstanceProcAddr"); + if (!vkGetInstanceProcAddr) { + fprintf(stderr, "error: failed load symbol 'vkGetInstanceProcAddr'\n"); + return SLANG_FAIL; } - virtual SlangResult captureScreenShot(char const* outputPath) override - { - return SLANG_FAIL; - } + VkApplicationInfo applicationInfo = { VK_STRUCTURE_TYPE_APPLICATION_INFO }; + applicationInfo.pApplicationName = "slang-render-test"; + applicationInfo.pEngineName = "slang-render-test"; + applicationInfo.apiVersion = VK_API_VERSION_1_0; - virtual ShaderCompiler* getShaderCompiler() override - { - return this; - } + char const* instanceExtensions[] = { + VK_KHR_SURFACE_EXTENSION_NAME, +#ifdef _WIN32 + VK_KHR_WIN32_SURFACE_EXTENSION_NAME, +#else +#endif - VkCommandBuffer getCommandBuffer() - { - VkCommandBufferAllocateInfo info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO }; - info.commandPool = commandPool; - info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - info.commandBufferCount = 1; +#if ENABLE_VALIDATION_LAYER + VK_EXT_DEBUG_REPORT_EXTENSION_NAME, +#endif + }; - VkCommandBuffer commandBuffer; - checkResult(vkAllocateCommandBuffers( - device, &info, &commandBuffer)); + VkInstanceCreateInfo instanceCreateInfo = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO }; + instanceCreateInfo.pApplicationInfo = &applicationInfo; - return commandBuffer; - } + instanceCreateInfo.enabledExtensionCount = sizeof(instanceExtensions) / sizeof(instanceExtensions[0]); + instanceCreateInfo.ppEnabledExtensionNames = &instanceExtensions[0]; - VkCommandBuffer beginCommandBuffer() - { - VkCommandBuffer commandBuffer = getCommandBuffer(); +#if ENABLE_VALIDATION_LAYER - VkCommandBufferBeginInfo beginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; - checkResult(vkBeginCommandBuffer(commandBuffer, &beginInfo)); + uint32_t layerCount = 1; + const char *layerNames[] = { + "VK_LAYER_LUNARG_standard_validation" + }; - return commandBuffer; - } + instanceCreateInfo.enabledLayerCount = layerCount; + instanceCreateInfo.ppEnabledLayerNames = layerNames; +#endif - void flushCommandBuffer(VkCommandBuffer commandBuffer) - { - checkResult(vkEndCommandBuffer(commandBuffer)); + instance = 0; - VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &commandBuffer; +#define LOAD_INSTANCE_PROC(NAME) NAME = (PFN_##NAME) vkGetInstanceProcAddr(instance, #NAME); - checkResult(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); - checkResult(vkQueueWaitIdle(queue)); + FOREACH_GLOBAL_PROC(LOAD_INSTANCE_PROC); - vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer); - } + RETURN_ON_VK_FAIL(vkCreateInstance(&instanceCreateInfo, nullptr, &instance)); - struct BufferImpl - { - VkBuffer buffer; - VkDeviceMemory memory; - }; + FOREACH_INSTANCE_PROC(LOAD_INSTANCE_PROC); - BufferImpl createBufferImpl( - size_t bufferSize, - VkBufferUsageFlags usage, - VkMemoryPropertyFlags reqMemoryProperties, - void const* initData = nullptr) - { - if( initData ) - { - // TODO: what if we are allocating it as CPU-writable anyway? - usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; - } +#undef LOAD_INSTANCE_PROC - VkBufferCreateInfo bufferCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; - bufferCreateInfo.size = bufferSize; - bufferCreateInfo.usage = usage; - VkBuffer buffer; - checkResult(vkCreateBuffer( - device, &bufferCreateInfo, nullptr, &buffer)); +#if ENABLE_VALIDATION_LAYER + VkDebugReportFlagsEXT debugFlags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT; - VkMemoryRequirements memoryReqs = {}; - vkGetBufferMemoryRequirements(device, buffer, &memoryReqs); + VkDebugReportCallbackCreateInfoEXT debugCreateInfo = { VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT }; + debugCreateInfo.pfnCallback = &debugMessageCallback; + debugCreateInfo.pUserData = this; + debugCreateInfo.flags = debugFlags; - uint32_t memoryTypeIndex = getMemoryTypeIndex( - memoryReqs.memoryTypeBits, reqMemoryProperties); + RETURN_ON_VK_FAIL(vkCreateDebugReportCallbackEXT(instance, &debugCreateInfo, nullptr, &debugReportCallback)); - VkMemoryPropertyFlags actualMemoryProperites = deviceMemoryProperties.memoryTypes[memoryTypeIndex].propertyFlags; +#endif - VkMemoryAllocateInfo allocateInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; - allocateInfo.allocationSize = memoryReqs.size; - allocateInfo.memoryTypeIndex = memoryTypeIndex; + uint32_t physicalDeviceCount = 0; + RETURN_ON_VK_FAIL(vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, nullptr)); - VkDeviceMemory memory; - checkResult(vkAllocateMemory( - device, &allocateInfo, nullptr, &memory)); + VkPhysicalDevice* physicalDevices = (VkPhysicalDevice*)alloca( + physicalDeviceCount * sizeof(VkPhysicalDevice)); + RETURN_ON_VK_FAIL(vkEnumeratePhysicalDevices( + instance, &physicalDeviceCount, physicalDevices)); - checkResult(vkBindBufferMemory( - device, buffer, memory, 0)); + uint32_t selectedDeviceIndex = 0; + // TODO: allow override of selected device + physicalDevice = physicalDevices[selectedDeviceIndex]; - if( initData ) - { - // TODO: only create staging buffer if the memory type - // used for the buffer doesn't let us fill things in - // directly. - - BufferImpl staging = createBufferImpl( - bufferSize, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - - // Copy into staging buffer - void* mappedData = nullptr; - checkResult(vkMapMemory(device, staging.memory, 0, bufferSize, 0, &mappedData)); - memcpy(mappedData, initData, bufferSize); - vkUnmapMemory(device, staging.memory); - - // Copy from staging buffer to real buffer - VkCommandBuffer commandBuffer = beginCommandBuffer(); - - VkBufferCopy copyInfo = {}; - copyInfo.size = bufferSize; - vkCmdCopyBuffer( - commandBuffer, - staging.buffer, - buffer, - 1, - ©Info); - - flushCommandBuffer(commandBuffer); - - // Now destroy the staging buffer - vkDestroyBuffer(device, staging.buffer, nullptr); - vkFreeMemory(device, staging.memory, nullptr); - } + vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties); + vkGetPhysicalDeviceFeatures(physicalDevice, &deviceFeatures); + vkGetPhysicalDeviceMemoryProperties(physicalDevice, &deviceMemoryProperties); - BufferImpl impl; - impl.buffer = buffer; - impl.memory = memory; - return impl; - } + uint32_t queueFamilyCount = 0; + vkGetPhysicalDeviceQueueFamilyProperties( + physicalDevice, &queueFamilyCount, nullptr); - virtual Buffer* createBuffer(BufferDesc const& desc) override - { - size_t bufferSize = desc.size; + VkQueueFamilyProperties* queueFamilies = (VkQueueFamilyProperties*)alloca( + queueFamilyCount * sizeof(VkQueueFamilyProperties)); + vkGetPhysicalDeviceQueueFamilyProperties( + physicalDevice, &queueFamilyCount, queueFamilies); - VkBufferUsageFlags usage = 0; - VkMemoryPropertyFlags reqMemoryProperties = 0; + // Find a queue that can service our needs + VkQueueFlags reqQueueFlags = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT; - switch( desc.flavor ) + uint32_t queueFamilyIndex = uint32_t(-1); + for (uint32_t qq = 0; qq < queueFamilyCount; ++qq) + { + if ((queueFamilies[qq].queueFlags & reqQueueFlags) == reqQueueFlags) { - case BufferFlavor::Constant: - usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; - reqMemoryProperties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - break; - - case BufferFlavor::Vertex: - usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; - reqMemoryProperties = 0; + queueFamilyIndex = qq; break; } - - BufferImpl bufferImpl = createBufferImpl( - bufferSize, - usage, - reqMemoryProperties, - desc.initData); - - BufferImpl* bufferPtr = new BufferImpl(); - *bufferPtr = bufferImpl; - return (Buffer*) bufferPtr; } + assert(queueFamilyIndex < queueFamilyCount); - struct InputLayoutImpl + float queuePriority = 0.0f; + VkDeviceQueueCreateInfo queueCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO }; + queueCreateInfo.queueFamilyIndex = queueFamilyIndex; + queueCreateInfo.queueCount = 1; + queueCreateInfo.pQueuePriorities = &queuePriority; + + char const* const deviceExtensions[] = { + VK_KHR_SWAPCHAIN_EXTENSION_NAME, }; - virtual InputLayout* createInputLayout(InputElementDesc const* inputElements, UInt inputElementCount) override - { - InputLayoutImpl* impl = new InputLayoutImpl(); + VkDeviceCreateInfo deviceCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO }; + deviceCreateInfo.queueCreateInfoCount = 1; + deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo; + deviceCreateInfo.pEnabledFeatures = &enabledFeatures; - // TODO: actually initialize things + deviceCreateInfo.enabledExtensionCount = sizeof(deviceExtensions) / sizeof(deviceExtensions[0]); + deviceCreateInfo.ppEnabledExtensionNames = &deviceExtensions[0]; - return (InputLayout*) impl; - } + RETURN_ON_VK_FAIL(vkCreateDevice( + physicalDevice, &deviceCreateInfo, nullptr, &device)); - virtual void* map(Buffer* buffer, MapFlavor flavor) override - { - return nullptr; - } +#define LOAD_DEVICE_PROC(NAME) NAME = (PFN_##NAME) vkGetDeviceProcAddr(device, #NAME); + FOREACH_DEVICE_PROC(LOAD_DEVICE_PROC) +#undef LOAD_DEVICE_PROC - virtual void unmap(Buffer* buffer) override - { - } + // Create a command pool - virtual void setInputLayout(InputLayout* inputLayout) override - { - } + VkCommandPoolCreateInfo commandPoolCreateInfo = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO }; + commandPoolCreateInfo.queueFamilyIndex = queueFamilyIndex; + commandPoolCreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - virtual void setPrimitiveTopology(PrimitiveTopology topology) override - { - } + RETURN_ON_VK_FAIL(vkCreateCommandPool( + device, &commandPoolCreateInfo, nullptr, &commandPool)); - virtual void setVertexBuffers(UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* strides, UInt const* offsets) override - { - } + vkGetDeviceQueue(device, queueFamilyIndex, 0, &queue); - struct ShaderProgramImpl - { - VkPipelineShaderStageCreateInfo compute; - VkPipelineShaderStageCreateInfo vertex; - VkPipelineShaderStageCreateInfo fragment; - }; + // set up swap chain - ShaderProgramImpl* currentProgram = nullptr; - virtual void setShaderProgram(ShaderProgram* program) override - { - currentProgram = (ShaderProgramImpl*) program; - } - virtual void setConstantBuffers(UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* offsets) override - { - } - virtual void draw(UInt vertexCount, UInt startVertex = 0) override - { - } + // create command buffers - struct BindingImpl - { - ShaderInputType type; - InputBufferType bufferType; // Only valid if `type` is `Buffer` + // depth/stencil? - VkImageView srv; - VkBufferView uav; - VkBuffer buffer; - VkSampler samplerState; + // render pass? - int binding = 0; - bool isOutput = false; - int bufferLength = 0; - }; + // pipeline cache - struct BindingStateImpl - { - Slang::List<BindingImpl> bindings; - int numRenderTargets; - }; + // frame buffer - uint32_t getMemoryTypeIndex( - uint32_t inTypeBits, - VkMemoryPropertyFlags properties) - { - uint32_t typeBits = inTypeBits; - uint32_t typeIndex = 0; - while( typeBits ) - { - if((deviceMemoryProperties.memoryTypes[typeIndex].propertyFlags & properties) == properties) - { - return typeIndex; - } - typeIndex++; - typeBits >>= 1; - } - assert(!"failed to find a usable memory type"); - return uint32_t(-1); - } - void createInputBuffer( - ShaderInputLayoutEntry const& entry, - InputBufferDesc const& bufferDesc, - Slang::List<unsigned int> const& bufferData, - VkBuffer &bufferOut, - VkBufferView &uavOut, - VkImageView &srvOut) - { - size_t bufferSize = bufferData.Count() * sizeof(unsigned int); - void const* initData = bufferData.Buffer(); + // create semaphores for sync + + return SLANG_OK; +} - VkBufferUsageFlags usage = 0; - VkMemoryPropertyFlags reqMemoryProperties = 0; +void VKRenderer::setClearColor(float const* color) +{ + for (int ii = 0; ii < 4; ++ii) + clearColor[ii] = color[ii]; +} - switch( bufferDesc.type ) - { - case InputBufferType::ConstantBuffer: +void VKRenderer::clearFrame() +{ +} + +void VKRenderer::presentFrame() +{ +} + +SlangResult VKRenderer::captureScreenShot(char const* outputPath) +{ + return SLANG_FAIL; +} + +ShaderCompiler* VKRenderer::getShaderCompiler() +{ + return this; +} + +Buffer* VKRenderer::createBuffer(BufferDesc const& desc) +{ + size_t bufferSize = desc.size; + + VkBufferUsageFlags usage = 0; + VkMemoryPropertyFlags reqMemoryProperties = 0; + + switch (desc.flavor) + { + case BufferFlavor::Constant: usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; reqMemoryProperties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; break; - case InputBufferType::StorageBuffer: - usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; + case BufferFlavor::Vertex: + usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; reqMemoryProperties = 0; break; - } + } - // If we are going to read back from the buffer, be sure to request - // the required access. - if(entry.isOutput) - { - usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - } + BufferImpl bufferImpl = createBufferImpl( + bufferSize, + usage, + reqMemoryProperties, + desc.initData); - BufferImpl bufferImpl = createBufferImpl( - bufferSize, - usage, - reqMemoryProperties, - initData); + BufferImpl* bufferPtr = new BufferImpl(); + *bufferPtr = bufferImpl; + return (Buffer*)bufferPtr; +} - // TODO: need to hang onto the `memory` field so - // that we can release it when we are done. +InputLayout* VKRenderer::createInputLayout(InputElementDesc const* inputElements, UInt inputElementCount) +{ + InputLayoutImpl* impl = new InputLayoutImpl; - bufferOut = bufferImpl.buffer; + // TODO: actually initialize things - // Fill in any views needed - switch( bufferDesc.type ) - { - case InputBufferType::ConstantBuffer: - break; + return (InputLayout*)impl; +} - case InputBufferType::StorageBuffer: - { - } - break; - } - } +void* VKRenderer::map(Buffer* buffer, MapFlavor flavor) +{ + return nullptr; +} - void createInputTexture( - InputTextureDesc const& inputDesc, - VkImageView& viewOut) - { - TextureData texData; - generateTextureData(texData, inputDesc); - assert(!"unimplemented"); - } +void VKRenderer::unmap(Buffer* buffer) +{ +} - void createInputSampler( - InputSamplerDesc const& inputDesc, - VkSampler& stateOut) - { - assert(!"unimplemented"); - } +void VKRenderer::setInputLayout(InputLayout* inputLayout) +{ +} + +void VKRenderer::setPrimitiveTopology(PrimitiveTopology topology) +{ +} - virtual BindingState* createBindingState(const ShaderInputLayout & layout) +void VKRenderer::setVertexBuffers(UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* strides, UInt const* offsets) +{ +} + +void VKRenderer::setShaderProgram(ShaderProgram* program) +{ + currentProgram = (ShaderProgramImpl*)program; +} + +void VKRenderer::setConstantBuffers(UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* offsets) +{ +} + +void VKRenderer::draw(UInt vertexCount, UInt startVertex = 0) +{ +} + +BindingState* VKRenderer::createBindingState(const ShaderInputLayout& layout) +{ + BindingStateImpl* bindingState = new BindingStateImpl; + bindingState->numRenderTargets = layout.numRenderTargets; + for (auto & entry : layout.entries) { - BindingStateImpl* bindingState = new BindingStateImpl(); - bindingState->numRenderTargets = layout.numRenderTargets; - for (auto & entry : layout.entries) + BindingImpl binding; + binding.type = entry.type; + binding.binding = entry.hlslBinding; + binding.isOutput = entry.isOutput; + switch (entry.type) { - BindingImpl binding; - binding.type = entry.type; - binding.binding = entry.hlslBinding; - binding.isOutput = entry.isOutput; - switch (entry.type) - { case ShaderInputType::Buffer: { createInputBuffer(entry, entry.bufferDesc, entry.bufferData, binding.buffer, binding.uav, binding.srv); @@ -710,328 +750,276 @@ public: case ShaderInputType::Texture: { createInputTexture(entry.textureDesc, binding.srv); + break; } - break; case ShaderInputType::Sampler: { createInputSampler(entry.samplerDesc, binding.samplerState); + break; } - break; case ShaderInputType::CombinedTextureSampler: { throw "not implemented"; + break; } - break; - } - bindingState->bindings.Add(binding); } - - return (BindingState*) bindingState; + bindingState->bindings.Add(binding); } - BindingStateImpl* currentBindingState = nullptr; - virtual void setBindingState(BindingState * state) - { - currentBindingState = (BindingStateImpl*) state; - } + return (BindingState*)bindingState; +} - virtual void serializeOutput(BindingState* s, const char * fileName) - { - auto state = (BindingStateImpl*) s; +void VKRenderer::setBindingState(BindingState * state) +{ + currentBindingState = (BindingStateImpl*)state; +} + +void VKRenderer::serializeOutput(BindingState* s, const char * fileName) +{ + auto state = (BindingStateImpl*)s; - FILE * f = fopen(fileName, "wb"); - int id = 0; - for (auto& bb: state->bindings) + FILE * f = fopen(fileName, "wb"); + int id = 0; + for (auto& bb : state->bindings) + { + if (bb.isOutput) { - if (bb.isOutput) + if (bb.buffer) { - if (bb.buffer) - { - // create staging buffer - size_t bufferSize = bb.bufferLength; - BufferImpl staging = createBufferImpl( - 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(); - - VkBufferCopy copyInfo = {}; - copyInfo.size = bufferSize; - vkCmdCopyBuffer( - commandBuffer, - bb.buffer, - staging.buffer, - 1, - ©Info); - - flushCommandBuffer(commandBuffer); - - // Write out the data from the buffer - void* mappedData = nullptr; - checkResult(vkMapMemory(device, staging.memory, 0, bufferSize, 0, &mappedData)); - - auto ptr = (unsigned int *) mappedData; - for (auto i = 0u; i < bufferSize / sizeof(unsigned int); i++) - fprintf(f, "%X\n", ptr[i]); - - vkUnmapMemory(device, staging.memory); - - // Now destroy the staging buffer - vkDestroyBuffer(device, staging.buffer, nullptr); - vkFreeMemory(device, staging.memory, nullptr); - } - else - { - printf("invalid output type at %d.\n", id); - } + // create staging buffer + size_t bufferSize = bb.bufferLength; + BufferImpl staging = createBufferImpl( + 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(); + + VkBufferCopy copyInfo = {}; + copyInfo.size = bufferSize; + vkCmdCopyBuffer( + commandBuffer, + bb.buffer, + staging.buffer, + 1, + ©Info); + + flushCommandBuffer(commandBuffer); + + // Write out the data from the buffer + void* mappedData = nullptr; + checkResult(vkMapMemory(device, staging.memory, 0, bufferSize, 0, &mappedData)); + + auto ptr = (unsigned int *)mappedData; + for (auto i = 0u; i < bufferSize / sizeof(unsigned int); i++) + fprintf(f, "%X\n", ptr[i]); + + vkUnmapMemory(device, staging.memory); + + // Now destroy the staging buffer + vkDestroyBuffer(device, staging.buffer, nullptr); + vkFreeMemory(device, staging.memory, nullptr); + } + else + { + printf("invalid output type at %d.\n", id); } - id++; } - fclose(f); - - + id++; } + fclose(f); +} - virtual void dispatchCompute(int x, int y, int z) override - { - - - // HACK: create a new pipeline for every call +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 + // First create a pipeline layout based on what is bound - Slang::List<VkDescriptorSetLayoutBinding> bindings; + Slang::List<VkDescriptorSetLayoutBinding> bindings; - for( auto bb : currentBindingState->bindings ) + for (auto bb : currentBindingState->bindings) + { + switch (bb.type) { - switch( bb.type ) - { case ShaderInputType::Buffer: + { + switch (bb.bufferType) { - switch(bb.bufferType) - { case InputBufferType::StorageBuffer: - { - VkDescriptorSetLayoutBinding binding = {}; - binding.binding = bb.binding; - binding.descriptorCount = 1; - binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - binding.stageFlags = VK_SHADER_STAGE_ALL; - - bindings.Add(binding); - } - break; + { + VkDescriptorSetLayoutBinding binding = {}; + binding.binding = bb.binding; + binding.descriptorCount = 1; + binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + binding.stageFlags = VK_SHADER_STAGE_ALL; + + bindings.Add(binding); + } + break; default: // handle other cases break; - } } - break; + } + break; default: // TODO: handle the other cases break; - } } + } - VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO }; - descriptorSetLayoutInfo.bindingCount = uint32_t(bindings.Count()); - descriptorSetLayoutInfo.pBindings = bindings.Buffer(); + VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO }; + descriptorSetLayoutInfo.bindingCount = uint32_t(bindings.Count()); + descriptorSetLayoutInfo.pBindings = bindings.Buffer(); - VkDescriptorSetLayout descriptorSetLayout = 0; - checkResult(vkCreateDescriptorSetLayout( - device, &descriptorSetLayoutInfo, nullptr, &descriptorSetLayout)); + VkDescriptorSetLayout descriptorSetLayout = 0; + checkResult(vkCreateDescriptorSetLayout( + device, &descriptorSetLayoutInfo, nullptr, &descriptorSetLayout)); - // Create a descriptor pool for allocating sets + // 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 }, - }; + 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; + 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( - device, &descriptorPoolInfo, nullptr, &descriptorPool)); + VkDescriptorPool descriptorPool; + checkResult(vkCreateDescriptorPool( + device, &descriptorPoolInfo, nullptr, &descriptorPool)); - // Create a descriptor set based on our layout + // 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; + VkDescriptorSetAllocateInfo descriptorSetAllocInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO }; + descriptorSetAllocInfo.descriptorPool = descriptorPool; + descriptorSetAllocInfo.descriptorSetCount = 1; + descriptorSetAllocInfo.pSetLayouts = &descriptorSetLayout; - VkDescriptorSet descriptorSet; - checkResult(vkAllocateDescriptorSets( - device, &descriptorSetAllocInfo, &descriptorSet)); + VkDescriptorSet descriptorSet; + checkResult(vkAllocateDescriptorSets( + device, &descriptorSetAllocInfo, &descriptorSet)); - // Fill in the descritpor set, using our binding information - for( auto bb : currentBindingState->bindings ) + // Fill in the descritpor set, using our binding information + for (auto bb : currentBindingState->bindings) + { + switch (bb.type) { - switch( bb.type ) - { case ShaderInputType::Buffer: + { + switch (bb.bufferType) { - switch(bb.bufferType) - { case InputBufferType::StorageBuffer: - { - VkDescriptorBufferInfo bufferInfo; - bufferInfo.buffer = bb.buffer; - bufferInfo.offset = 0; - bufferInfo.range = bb.bufferLength; - - VkWriteDescriptorSet writeInfo = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; - writeInfo.descriptorCount = 1; - writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - writeInfo.dstSet = descriptorSet; - writeInfo.dstBinding = bb.binding; - writeInfo.dstArrayElement = 0; - writeInfo.pBufferInfo = &bufferInfo; - - vkUpdateDescriptorSets( - device, - 1, - &writeInfo, - 0, - nullptr); - } - break; + { + VkDescriptorBufferInfo bufferInfo; + bufferInfo.buffer = bb.buffer; + bufferInfo.offset = 0; + bufferInfo.range = bb.bufferLength; + + VkWriteDescriptorSet writeInfo = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; + writeInfo.descriptorCount = 1; + writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + writeInfo.dstSet = descriptorSet; + writeInfo.dstBinding = bb.binding; + writeInfo.dstArrayElement = 0; + writeInfo.pBufferInfo = &bufferInfo; + + vkUpdateDescriptorSets( + device, + 1, + &writeInfo, + 0, + nullptr); + } + break; default: // handle other cases break; - } } - break; + } + break; default: // TODO: handle the other cases break; - } } + } - // Create a pipeline layout based on our descriptor set layout(s) + // 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; + VkPipelineLayoutCreateInfo pipelineLayoutInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; + pipelineLayoutInfo.setLayoutCount = 1; + pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout; - VkPipelineLayout pipelineLayout = 0; - checkResult(vkCreatePipelineLayout( - device, &pipelineLayoutInfo, nullptr, &pipelineLayout)); + VkPipelineLayout pipelineLayout = 0; + checkResult(vkCreatePipelineLayout( + device, &pipelineLayoutInfo, nullptr, &pipelineLayout)); - // Then create a pipeline to use that layout + // Then create a pipeline to use that layout - VkComputePipelineCreateInfo computePipelineInfo = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO }; - computePipelineInfo.stage = currentProgram->compute; - computePipelineInfo.layout = pipelineLayout; + VkComputePipelineCreateInfo computePipelineInfo = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO }; + computePipelineInfo.stage = currentProgram->compute; + computePipelineInfo.layout = pipelineLayout; - VkPipelineCache pipelineCache = 0; + VkPipelineCache pipelineCache = 0; - VkPipeline pipeline; - checkResult(vkCreateComputePipelines( - device, pipelineCache, 1, &computePipelineInfo, nullptr, &pipeline)); + VkPipeline pipeline; + checkResult(vkCreateComputePipelines( + device, pipelineCache, 1, &computePipelineInfo, nullptr, &pipeline)); - // Also create descriptor sets based on the given pipeline layout + // Also create descriptor sets based on the given pipeline layout - VkCommandBuffer commandBuffer = beginCommandBuffer(); + VkCommandBuffer commandBuffer = beginCommandBuffer(); - vkCmdBindPipeline( - commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline); + vkCmdBindPipeline( + commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline); - vkCmdBindDescriptorSets( - commandBuffer, - VK_PIPELINE_BIND_POINT_COMPUTE, - pipelineLayout, - 0, 1, - &descriptorSet, - 0, - nullptr); + vkCmdBindDescriptorSets( + commandBuffer, + VK_PIPELINE_BIND_POINT_COMPUTE, + pipelineLayout, + 0, 1, + &descriptorSet, + 0, + nullptr); - vkCmdDispatch(commandBuffer, x, y, z); + vkCmdDispatch(commandBuffer, x, y, z); - flushCommandBuffer(commandBuffer); + flushCommandBuffer(commandBuffer); - vkDestroyPipeline(device, pipeline, nullptr); + vkDestroyPipeline(device, pipeline, nullptr); - // TODO: need to free up the other resources too... - } + // TODO: need to free up the other resources too... +} - // ShaderCompiler interface - VkPipelineShaderStageCreateInfo compileEntryPoint( - ShaderCompileRequest::EntryPoint const& entryPointRequest, - VkShaderStageFlagBits stage) + +// ShaderCompiler interface +ShaderProgram* VKRenderer::compileProgram(const ShaderCompileRequest & request) +{ + ShaderProgramImpl* impl = new ShaderProgramImpl; + if (request.computeShader.name) { - char const* dataBegin = entryPointRequest.source.dataBegin; - char const* dataEnd = entryPointRequest.source.dataEnd; - - // We need to make a copy of the code, since the Slang compiler - // will free the memory after a compile request is closed. - size_t codeSize = dataEnd - dataBegin; - char* codeBegin = (char*) malloc(codeSize); - memcpy(codeBegin, dataBegin, codeSize); - - VkShaderModuleCreateInfo moduleCreateInfo = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO }; - moduleCreateInfo.pCode = (uint32_t*) codeBegin; - moduleCreateInfo.codeSize = codeSize; - - VkShaderModule module; - checkResult(vkCreateShaderModule( - 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; + impl->compute = compileEntryPoint(request.computeShader, VK_SHADER_STAGE_COMPUTE_BIT); } - - virtual ShaderProgram* compileProgram(ShaderCompileRequest const& request) override + else { - ShaderProgramImpl* impl = new ShaderProgramImpl(); - - if( request.computeShader.name ) - { - impl->compute = compileEntryPoint( - request.computeShader, - VK_SHADER_STAGE_COMPUTE_BIT); - } - else - { - impl->vertex = compileEntryPoint( - request.vertexShader, - VK_SHADER_STAGE_VERTEX_BIT); - - impl->fragment = compileEntryPoint( - request.fragmentShader, - VK_SHADER_STAGE_FRAGMENT_BIT); - } - - return (ShaderProgram*) impl; + impl->vertex = compileEntryPoint(request.vertexShader, VK_SHADER_STAGE_VERTEX_BIT); + impl->fragment = compileEntryPoint(request.fragmentShader, VK_SHADER_STAGE_FRAGMENT_BIT); } -}; - - - -Renderer* createVKRenderer() -{ - return new VKRenderer(); + return (ShaderProgram*)impl; } + } // renderer_test |
