diff options
Diffstat (limited to 'tools/render-test/render-vk.cpp')
| -rw-r--r-- | tools/render-test/render-vk.cpp | 1033 |
1 files changed, 1033 insertions, 0 deletions
diff --git a/tools/render-test/render-vk.cpp b/tools/render-test/render-vk.cpp new file mode 100644 index 000000000..fd080931d --- /dev/null +++ b/tools/render-test/render-vk.cpp @@ -0,0 +1,1033 @@ +// render-vk.cpp +#include "render-vk.h" + +#include "options.h" +#include "render.h" + +#ifdef _WIN32 +#define VK_USE_PLATFORM_WIN32_KHR 1 +#endif + +#define VK_NO_PROTOTYPES +#include <vulkan/vulkan.h> + +#define ENABLE_VALIDATION_LAYER 1 + + +#ifdef _MSC_VER + +#include <stddef.h> + +#pragma warning(disable: 4996) + +#if (_MSC_VER < 1900) +#define snprintf sprintf_s +#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 { + +class VKRenderer : public Renderer, public ShaderCompiler +{ +public: + + VkInstance instance; + VkPhysicalDevice physicalDevice; + VkPhysicalDeviceProperties deviceProperties; + VkPhysicalDeviceFeatures deviceFeatures; + VkPhysicalDeviceMemoryProperties deviceMemoryProperties; + VkPhysicalDeviceFeatures enabledFeatures; + VkDevice device; + VkQueue queue; + VkCommandPool commandPool; + VkSubmitInfo submitInfo; + VkDebugReportCallbackEXT debugReportCallback; + + +#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 + + // Renderer interface + + 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; + } + + 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); + } + + virtual void initialize(void* inWindowHandle) override + { + char const* dynamicLibraryName = "vulkan-1.dll"; + HMODULE vulkan = LoadLibraryA(dynamicLibraryName); + if(!vulkan) + { + fprintf(stderr, "error: failed load '%s'\n", dynamicLibraryName); + exit(1); + } + + vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr) GetProcAddress(vulkan, "vkGetInstanceProcAddr"); + if(!vkGetInstanceProcAddr) + { + fprintf(stderr, + "error: failed load symbol 'vkGetInstanceProcAddr'\n"); + exit(1); + } + + 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[] = { + VK_KHR_SURFACE_EXTENSION_NAME, +#ifdef _WIN32 + VK_KHR_WIN32_SURFACE_EXTENSION_NAME, +#else +#endif + +#if ENABLE_VALIDATION_LAYER + VK_EXT_DEBUG_REPORT_EXTENSION_NAME, +#endif + }; + + VkInstanceCreateInfo instanceCreateInfo = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO }; + instanceCreateInfo.pApplicationInfo = &applicationInfo; + + instanceCreateInfo.enabledExtensionCount = sizeof(instanceExtensions) / sizeof(instanceExtensions[0]); + instanceCreateInfo.ppEnabledExtensionNames = &instanceExtensions[0]; + +#if ENABLE_VALIDATION_LAYER + + uint32_t layerCount = 1; + const char *layerNames[] = { + "VK_LAYER_LUNARG_standard_validation" + }; + + instanceCreateInfo.enabledLayerCount = layerCount; + instanceCreateInfo.ppEnabledLayerNames = layerNames; +#endif + + instance = 0; + +#define LOAD_INSTANCE_PROC(NAME) NAME = (PFN_##NAME) vkGetInstanceProcAddr(instance, #NAME); + + FOREACH_GLOBAL_PROC(LOAD_INSTANCE_PROC); + + checkResult(vkCreateInstance( + &instanceCreateInfo, + nullptr, + &instance)); + + FOREACH_INSTANCE_PROC(LOAD_INSTANCE_PROC); + +#undef LOAD_INSTANCE_PROC + + +#if ENABLE_VALIDATION_LAYER + VkDebugReportFlagsEXT debugFlags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT; + + VkDebugReportCallbackCreateInfoEXT debugCreateInfo = { VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT }; + debugCreateInfo.pfnCallback = &debugMessageCallback; + debugCreateInfo.pUserData = this; + debugCreateInfo.flags = debugFlags; + + checkResult(vkCreateDebugReportCallbackEXT( + instance, &debugCreateInfo, nullptr, &debugReportCallback)); + +#endif + + uint32_t physicalDeviceCount = 0; + checkResult(vkEnumeratePhysicalDevices( + instance, &physicalDeviceCount, nullptr)); + + VkPhysicalDevice* physicalDevices = (VkPhysicalDevice*)alloca( + physicalDeviceCount * sizeof(VkPhysicalDevice)); + checkResult(vkEnumeratePhysicalDevices( + instance, &physicalDeviceCount, physicalDevices)); + + uint32_t selectedDeviceIndex = 0; + // TODO: allow override of selected device + physicalDevice = physicalDevices[selectedDeviceIndex]; + + vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties); + vkGetPhysicalDeviceFeatures(physicalDevice, &deviceFeatures); + vkGetPhysicalDeviceMemoryProperties(physicalDevice, &deviceMemoryProperties); + + uint32_t queueFamilyCount = 0; + vkGetPhysicalDeviceQueueFamilyProperties( + physicalDevice, &queueFamilyCount, nullptr); + + VkQueueFamilyProperties* queueFamilies = (VkQueueFamilyProperties*)alloca( + queueFamilyCount * sizeof(VkQueueFamilyProperties)); + vkGetPhysicalDeviceQueueFamilyProperties( + 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); + + 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, + }; + + VkDeviceCreateInfo deviceCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO }; + deviceCreateInfo.queueCreateInfoCount = 1; + deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo; + deviceCreateInfo.pEnabledFeatures = &enabledFeatures; + + deviceCreateInfo.enabledExtensionCount = sizeof(deviceExtensions) / sizeof(deviceExtensions[0]); + deviceCreateInfo.ppEnabledExtensionNames = &deviceExtensions[0]; + + checkResult(vkCreateDevice( + physicalDevice, &deviceCreateInfo, nullptr, &device)); + +#define LOAD_DEVICE_PROC(NAME) NAME = (PFN_##NAME) vkGetDeviceProcAddr(device, #NAME); + FOREACH_DEVICE_PROC(LOAD_DEVICE_PROC) +#undef LOAD_DEVICE_PROC + + // 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; + + checkResult(vkCreateCommandPool( + device, &commandPoolCreateInfo, nullptr, &commandPool)); + + vkGetDeviceQueue( + device, + queueFamilyIndex, + 0, + &queue); + + // set up swap chain + + // create command buffers + + // depth/stencil? + + // render pass? + + // pipeline cache + + // frame buffer + + + +// create semaphores for sync + + + } + + float clearColor[4]; + virtual void setClearColor(float const* color) override + { + for(int ii = 0; ii < 4; ++ii) + clearColor[ii] = color[ii]; + } + + virtual void clearFrame() override + { + } + + virtual void presentFrame() override + { + } + + virtual void captureScreenShot(char const* outputPath) override + { + } + + virtual ShaderCompiler* getShaderCompiler() override + { + return this; + } + + VkCommandBuffer getCommandBuffer() + { + VkCommandBufferAllocateInfo info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO }; + info.commandPool = commandPool; + info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + info.commandBufferCount = 1; + + VkCommandBuffer commandBuffer; + checkResult(vkAllocateCommandBuffers( + device, &info, &commandBuffer)); + + return commandBuffer; + } + + VkCommandBuffer beginCommandBuffer() + { + VkCommandBuffer commandBuffer = getCommandBuffer(); + + VkCommandBufferBeginInfo beginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; + checkResult(vkBeginCommandBuffer(commandBuffer, &beginInfo)); + + return commandBuffer; + } + + void flushCommandBuffer(VkCommandBuffer commandBuffer) + { + checkResult(vkEndCommandBuffer(commandBuffer)); + + VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &commandBuffer; + + checkResult(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); + checkResult(vkQueueWaitIdle(queue)); + + vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer); + } + + struct BufferImpl + { + VkBuffer buffer; + VkDeviceMemory memory; + }; + + 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; + } + + VkBufferCreateInfo bufferCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; + bufferCreateInfo.size = bufferSize; + bufferCreateInfo.usage = usage; + + VkBuffer buffer; + checkResult(vkCreateBuffer( + device, &bufferCreateInfo, nullptr, &buffer)); + + VkMemoryRequirements memoryReqs = {}; + vkGetBufferMemoryRequirements(device, buffer, &memoryReqs); + + uint32_t memoryTypeIndex = getMemoryTypeIndex( + memoryReqs.memoryTypeBits, reqMemoryProperties); + + VkMemoryPropertyFlags actualMemoryProperites = deviceMemoryProperties.memoryTypes[memoryTypeIndex].propertyFlags; + + VkMemoryAllocateInfo allocateInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; + allocateInfo.allocationSize = memoryReqs.size; + allocateInfo.memoryTypeIndex = memoryTypeIndex; + + VkDeviceMemory memory; + checkResult(vkAllocateMemory( + device, &allocateInfo, nullptr, &memory)); + + checkResult(vkBindBufferMemory( + device, buffer, memory, 0)); + + 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); + } + + BufferImpl impl; + impl.buffer = buffer; + impl.memory = memory; + return impl; + } + + virtual Buffer* createBuffer(BufferDesc const& desc) override + { + 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 BufferFlavor::Vertex: + usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + reqMemoryProperties = 0; + break; + } + + BufferImpl bufferImpl = createBufferImpl( + bufferSize, + usage, + reqMemoryProperties, + desc.initData); + + BufferImpl* bufferPtr = new BufferImpl(); + *bufferPtr = bufferImpl; + return (Buffer*) bufferPtr; + } + + struct InputLayoutImpl + { + }; + + virtual InputLayout* createInputLayout(InputElementDesc const* inputElements, UInt inputElementCount) override + { + InputLayoutImpl* impl = new InputLayoutImpl(); + + // TODO: actually initialize things + + return (InputLayout*) impl; + } + + virtual void* map(Buffer* buffer, MapFlavor flavor) override + { + return nullptr; + } + + virtual void unmap(Buffer* buffer) override + { + } + + virtual void setInputLayout(InputLayout* inputLayout) override + { + } + + virtual void setPrimitiveTopology(PrimitiveTopology topology) override + { + } + + virtual void setVertexBuffers(UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* strides, UInt const* offsets) override + { + } + + struct ShaderProgramImpl + { + VkPipelineShaderStageCreateInfo compute; + VkPipelineShaderStageCreateInfo vertex; + VkPipelineShaderStageCreateInfo fragment; + }; + + 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 + { + } + + 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; + }; + + 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(); + + VkBufferUsageFlags usage = 0; + VkMemoryPropertyFlags reqMemoryProperties = 0; + + 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; + + case InputBufferType::StorageBuffer: + usage = VK_BUFFER_USAGE_STORAGE_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, + initData); + + // TODO: need to hang onto the `memory` field so + // that we can release it when we are done. + + bufferOut = bufferImpl.buffer; + + // Fill in any views needed + switch( bufferDesc.type ) + { + case InputBufferType::ConstantBuffer: + break; + + case InputBufferType::StorageBuffer: + { + } + break; + } + } + + void createInputTexture( + InputTextureDesc const& inputDesc, + VkImageView& viewOut) + { + TextureData texData; + generateTextureData(texData, inputDesc); + assert(!"unimplemented"); + } + + void createInputSampler( + InputSamplerDesc const& inputDesc, + VkSampler& stateOut) + { + assert(!"unimplemented"); + } + + virtual BindingState* createBindingState(const ShaderInputLayout & layout) + { + 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) + { + case ShaderInputType::Buffer: + { + createInputBuffer(entry, entry.bufferDesc, entry.bufferData, binding.buffer, binding.uav, binding.srv); + binding.bufferLength = (int)(entry.bufferData.Count() * sizeof(unsigned int)); + binding.bufferType = entry.bufferDesc.type; + } + break; + case ShaderInputType::Texture: + { + createInputTexture(entry.textureDesc, binding.srv); + } + break; + case ShaderInputType::Sampler: + { + createInputSampler(entry.samplerDesc, binding.samplerState); + } + break; + case ShaderInputType::CombinedTextureSampler: + { + throw "not implemented"; + } + break; + } + bindingState->bindings.Add(binding); + } + + return (BindingState*) bindingState; + } + + BindingStateImpl* currentBindingState = nullptr; + virtual void setBindingState(BindingState * state) + { + currentBindingState = (BindingStateImpl*) state; + } + + virtual void serializeOutput(BindingState* s, const char * fileName) + { + auto state = (BindingStateImpl*) s; + + FILE * f = fopen(fileName, "wb"); + int id = 0; + for (auto& bb: state->bindings) + { + if (bb.isOutput) + { + 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); + } + } + id++; + } + fclose(f); + + + } + + virtual void dispatchCompute(int x, int y, int z) override + { + + + // HACK: create a new pipeline for every call + + // First create a pipeline layout based on what is bound + + Slang::List<VkDescriptorSetLayoutBinding> bindings; + + for( auto bb : currentBindingState->bindings ) + { + switch( bb.type ) + { + case ShaderInputType::Buffer: + { + 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; + + default: + // handle other cases + 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(); + + VkDescriptorSetLayout descriptorSetLayout = 0; + checkResult(vkCreateDescriptorSetLayout( + 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( + 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( + device, &descriptorSetAllocInfo, &descriptorSet)); + + // Fill in the descritpor set, using our binding information + for( auto bb : currentBindingState->bindings ) + { + switch( bb.type ) + { + case ShaderInputType::Buffer: + { + 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; + + default: + // handle other cases + break; + } + } + break; + + default: + // TODO: handle the 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( + device, &pipelineLayoutInfo, nullptr, &pipelineLayout)); + + // Then create a pipeline to use that layout + + VkComputePipelineCreateInfo computePipelineInfo = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO }; + computePipelineInfo.stage = currentProgram->compute; + computePipelineInfo.layout = pipelineLayout; + + VkPipelineCache pipelineCache = 0; + + VkPipeline pipeline; + checkResult(vkCreateComputePipelines( + 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(device, pipeline, nullptr); + + // TODO: need to free up the other resources too... + } + + // ShaderCompiler interface + + VkPipelineShaderStageCreateInfo compileEntryPoint( + ShaderCompileRequest::EntryPoint const& entryPointRequest, + VkShaderStageFlagBits stage) + { + 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; + } + + virtual ShaderProgram* compileProgram(ShaderCompileRequest const& request) override + { + 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; + } +}; + + + +Renderer* createVKRenderer() +{ + return new VKRenderer(); +} + +} // renderer_test |
