From: jiadozhu <jiadong.zhu@xxxxxxx> This is a standalone test case used for software mcbp on gfx9. Build and open two consoles to run: build/bin/vkpreemption s gfx=draws:1000000,priority:high,delay:0 build/bin/vkpreemption c gfx=draws:1000000,priority:low,delay:0 The result is printed on the console of the server side. Signed-off-by: jiadozhu <jiadong.zhu@xxxxxxx> --- vkpreemption/CMakeLists.txt | 17 + vkpreemption/VulkanInitializers.hpp | 591 ++++++++++++++++++++ vkpreemption/VulkanTools.cpp | 361 ++++++++++++ vkpreemption/VulkanTools.h | 118 ++++ vkpreemption/base.hpp | 269 +++++++++ vkpreemption/build_lnx.sh | 11 + vkpreemption/computework.hpp | 429 ++++++++++++++ vkpreemption/graphicwork.hpp | 777 ++++++++++++++++++++++++++ vkpreemption/headless.comp | 34 ++ vkpreemption/headless.comp.inc | 33 ++ vkpreemption/main.cpp | 385 +++++++++++++ vkpreemption/triangle.frag | 10 + vkpreemption/triangle.frag.glsl | 10 + vkpreemption/triangle.frag.inc | 17 + vkpreemption/triangle.vert | 20 + vkpreemption/triangle.vert.glsl | 20 + vkpreemption/triangle.vert.inc | 34 ++ vkpreemption/vk_amd_dispatch_tunnel.h | 34 ++ vkpreemption/vk_internal_ext_helper.h | 33 ++ 19 files changed, 3203 insertions(+) create mode 100644 vkpreemption/CMakeLists.txt create mode 100644 vkpreemption/VulkanInitializers.hpp create mode 100644 vkpreemption/VulkanTools.cpp create mode 100644 vkpreemption/VulkanTools.h create mode 100644 vkpreemption/base.hpp create mode 100644 vkpreemption/build_lnx.sh create mode 100644 vkpreemption/computework.hpp create mode 100644 vkpreemption/graphicwork.hpp create mode 100644 vkpreemption/headless.comp create mode 100644 vkpreemption/headless.comp.inc create mode 100644 vkpreemption/main.cpp create mode 100644 vkpreemption/triangle.frag create mode 100644 vkpreemption/triangle.frag.glsl create mode 100644 vkpreemption/triangle.frag.inc create mode 100644 vkpreemption/triangle.vert create mode 100644 vkpreemption/triangle.vert.glsl create mode 100644 vkpreemption/triangle.vert.inc create mode 100644 vkpreemption/vk_amd_dispatch_tunnel.h create mode 100644 vkpreemption/vk_internal_ext_helper.h diff --git a/vkpreemption/CMakeLists.txt b/vkpreemption/CMakeLists.txt new file mode 100644 index 00000000..0c54ddab --- /dev/null +++ b/vkpreemption/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 2.8 FATAL_ERROR) +cmake_policy(VERSION 2.8) +project(vkpreemption) + +message("CMAKE_SYSTEM_NAME: ${CMAKE_SYSTEM_NAME}") + +include_directories(glm) + +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/") + +file(GLOB EXAMPLE_SRC "*.cpp" "*.hpp") +add_executable(vkpreemption ${EXAMPLE_SRC}) + +target_link_libraries( + vkpreemption + libvulkan.so +) diff --git a/vkpreemption/VulkanInitializers.hpp b/vkpreemption/VulkanInitializers.hpp new file mode 100644 index 00000000..806ab513 --- /dev/null +++ b/vkpreemption/VulkanInitializers.hpp @@ -0,0 +1,591 @@ +/* +* Initializers for Vulkan structures and objects used by the examples +* Saves lot of VK_STRUCTURE_TYPE assignments +* Some initializers are parameterized for convenience +* +* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de +* +* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) +*/ + +#pragma once + +#include <vector> +#include "vulkan/vulkan.h" + +namespace vks +{ + namespace initializers + { + + inline VkMemoryAllocateInfo memoryAllocateInfo() + { + VkMemoryAllocateInfo memAllocInfo {}; + memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + return memAllocInfo; + } + + inline VkMappedMemoryRange mappedMemoryRange() + { + VkMappedMemoryRange mappedMemoryRange {}; + mappedMemoryRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; + return mappedMemoryRange; + } + + inline VkCommandBufferAllocateInfo commandBufferAllocateInfo( + VkCommandPool commandPool, + VkCommandBufferLevel level, + uint32_t bufferCount) + { + VkCommandBufferAllocateInfo commandBufferAllocateInfo {}; + commandBufferAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + commandBufferAllocateInfo.commandPool = commandPool; + commandBufferAllocateInfo.level = level; + commandBufferAllocateInfo.commandBufferCount = bufferCount; + return commandBufferAllocateInfo; + } + + inline VkCommandPoolCreateInfo commandPoolCreateInfo() + { + VkCommandPoolCreateInfo cmdPoolCreateInfo {}; + cmdPoolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + return cmdPoolCreateInfo; + } + + inline VkCommandBufferBeginInfo commandBufferBeginInfo() + { + VkCommandBufferBeginInfo cmdBufferBeginInfo {}; + cmdBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + return cmdBufferBeginInfo; + } + + inline VkCommandBufferInheritanceInfo commandBufferInheritanceInfo() + { + VkCommandBufferInheritanceInfo cmdBufferInheritanceInfo {}; + cmdBufferInheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; + return cmdBufferInheritanceInfo; + } + + inline VkRenderPassBeginInfo renderPassBeginInfo() + { + VkRenderPassBeginInfo renderPassBeginInfo {}; + renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + return renderPassBeginInfo; + } + + inline VkRenderPassCreateInfo renderPassCreateInfo() + { + VkRenderPassCreateInfo renderPassCreateInfo {}; + renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + return renderPassCreateInfo; + } + + /** @brief Initialize an image memory barrier with no image transfer ownership */ + inline VkImageMemoryBarrier imageMemoryBarrier() + { + VkImageMemoryBarrier imageMemoryBarrier {}; + imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + return imageMemoryBarrier; + } + + /** @brief Initialize a buffer memory barrier with no image transfer ownership */ + inline VkBufferMemoryBarrier bufferMemoryBarrier() + { + VkBufferMemoryBarrier bufferMemoryBarrier {}; + bufferMemoryBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; + bufferMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + bufferMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + return bufferMemoryBarrier; + } + + inline VkMemoryBarrier memoryBarrier() + { + VkMemoryBarrier memoryBarrier {}; + memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; + return memoryBarrier; + } + + inline VkImageCreateInfo imageCreateInfo() + { + VkImageCreateInfo imageCreateInfo {}; + imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + return imageCreateInfo; + } + + inline VkSamplerCreateInfo samplerCreateInfo() + { + VkSamplerCreateInfo samplerCreateInfo {}; + samplerCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + samplerCreateInfo.maxAnisotropy = 1.0f; + return samplerCreateInfo; + } + + inline VkImageViewCreateInfo imageViewCreateInfo() + { + VkImageViewCreateInfo imageViewCreateInfo {}; + imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + return imageViewCreateInfo; + } + + inline VkFramebufferCreateInfo framebufferCreateInfo() + { + VkFramebufferCreateInfo framebufferCreateInfo {}; + framebufferCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + return framebufferCreateInfo; + } + + inline VkSemaphoreCreateInfo semaphoreCreateInfo() + { + VkSemaphoreCreateInfo semaphoreCreateInfo {}; + semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + return semaphoreCreateInfo; + } + + inline VkFenceCreateInfo fenceCreateInfo(VkFenceCreateFlags flags = 0) + { + VkFenceCreateInfo fenceCreateInfo {}; + fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fenceCreateInfo.flags = flags; + return fenceCreateInfo; + } + + inline VkEventCreateInfo eventCreateInfo() + { + VkEventCreateInfo eventCreateInfo {}; + eventCreateInfo.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO; + return eventCreateInfo; + } + + inline VkSubmitInfo submitInfo() + { + VkSubmitInfo submitInfo {}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + return submitInfo; + } + + inline VkViewport viewport( + float width, + float height, + float minDepth, + float maxDepth) + { + VkViewport viewport {}; + viewport.width = width; + viewport.height = height; + viewport.minDepth = minDepth; + viewport.maxDepth = maxDepth; + return viewport; + } + + inline VkRect2D rect2D( + int32_t width, + int32_t height, + int32_t offsetX, + int32_t offsetY) + { + VkRect2D rect2D {}; + rect2D.extent.width = width; + rect2D.extent.height = height; + rect2D.offset.x = offsetX; + rect2D.offset.y = offsetY; + return rect2D; + } + + inline VkBufferCreateInfo bufferCreateInfo() + { + VkBufferCreateInfo bufCreateInfo {}; + bufCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + return bufCreateInfo; + } + + inline VkBufferCreateInfo bufferCreateInfo( + VkBufferUsageFlags usage, + VkDeviceSize size) + { + VkBufferCreateInfo bufCreateInfo {}; + bufCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufCreateInfo.usage = usage; + bufCreateInfo.size = size; + return bufCreateInfo; + } + + inline VkDescriptorPoolCreateInfo descriptorPoolCreateInfo( + uint32_t poolSizeCount, + VkDescriptorPoolSize* pPoolSizes, + uint32_t maxSets) + { + VkDescriptorPoolCreateInfo descriptorPoolInfo {}; + descriptorPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + descriptorPoolInfo.poolSizeCount = poolSizeCount; + descriptorPoolInfo.pPoolSizes = pPoolSizes; + descriptorPoolInfo.maxSets = maxSets; + return descriptorPoolInfo; + } + + inline VkDescriptorPoolCreateInfo descriptorPoolCreateInfo( + const std::vector<VkDescriptorPoolSize>& poolSizes, + uint32_t maxSets) + { + VkDescriptorPoolCreateInfo descriptorPoolInfo{}; + descriptorPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + descriptorPoolInfo.poolSizeCount = static_cast<uint32_t>(poolSizes.size()); + descriptorPoolInfo.pPoolSizes = poolSizes.data(); + descriptorPoolInfo.maxSets = maxSets; + return descriptorPoolInfo; + } + + inline VkDescriptorPoolSize descriptorPoolSize( + VkDescriptorType type, + uint32_t descriptorCount) + { + VkDescriptorPoolSize descriptorPoolSize {}; + descriptorPoolSize.type = type; + descriptorPoolSize.descriptorCount = descriptorCount; + return descriptorPoolSize; + } + + inline VkDescriptorSetLayoutBinding descriptorSetLayoutBinding( + VkDescriptorType type, + VkShaderStageFlags stageFlags, + uint32_t binding, + uint32_t descriptorCount = 1) + { + VkDescriptorSetLayoutBinding setLayoutBinding {}; + setLayoutBinding.descriptorType = type; + setLayoutBinding.stageFlags = stageFlags; + setLayoutBinding.binding = binding; + setLayoutBinding.descriptorCount = descriptorCount; + return setLayoutBinding; + } + + inline VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo( + const VkDescriptorSetLayoutBinding* pBindings, + uint32_t bindingCount) + { + VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo {}; + descriptorSetLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + descriptorSetLayoutCreateInfo.pBindings = pBindings; + descriptorSetLayoutCreateInfo.bindingCount = bindingCount; + return descriptorSetLayoutCreateInfo; + } + + inline VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo( + const std::vector<VkDescriptorSetLayoutBinding>& bindings) + { + VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo{}; + descriptorSetLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + descriptorSetLayoutCreateInfo.pBindings = bindings.data(); + descriptorSetLayoutCreateInfo.bindingCount = static_cast<uint32_t>(bindings.size()); + return descriptorSetLayoutCreateInfo; + } + + inline VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo( + const VkDescriptorSetLayout* pSetLayouts, + uint32_t setLayoutCount = 1) + { + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo {}; + pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutCreateInfo.setLayoutCount = setLayoutCount; + pipelineLayoutCreateInfo.pSetLayouts = pSetLayouts; + return pipelineLayoutCreateInfo; + } + + inline VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo( + uint32_t setLayoutCount = 1) + { + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{}; + pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutCreateInfo.setLayoutCount = setLayoutCount; + return pipelineLayoutCreateInfo; + } + + inline VkDescriptorSetAllocateInfo descriptorSetAllocateInfo( + VkDescriptorPool descriptorPool, + const VkDescriptorSetLayout* pSetLayouts, + uint32_t descriptorSetCount) + { + VkDescriptorSetAllocateInfo descriptorSetAllocateInfo {}; + descriptorSetAllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + descriptorSetAllocateInfo.descriptorPool = descriptorPool; + descriptorSetAllocateInfo.pSetLayouts = pSetLayouts; + descriptorSetAllocateInfo.descriptorSetCount = descriptorSetCount; + return descriptorSetAllocateInfo; + } + + inline VkDescriptorImageInfo descriptorImageInfo(VkSampler sampler, VkImageView imageView, VkImageLayout imageLayout) + { + VkDescriptorImageInfo descriptorImageInfo {}; + descriptorImageInfo.sampler = sampler; + descriptorImageInfo.imageView = imageView; + descriptorImageInfo.imageLayout = imageLayout; + return descriptorImageInfo; + } + + inline VkWriteDescriptorSet writeDescriptorSet( + VkDescriptorSet dstSet, + VkDescriptorType type, + uint32_t binding, + VkDescriptorBufferInfo* bufferInfo, + uint32_t descriptorCount = 1) + { + VkWriteDescriptorSet writeDescriptorSet {}; + writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptorSet.dstSet = dstSet; + writeDescriptorSet.descriptorType = type; + writeDescriptorSet.dstBinding = binding; + writeDescriptorSet.pBufferInfo = bufferInfo; + writeDescriptorSet.descriptorCount = descriptorCount; + return writeDescriptorSet; + } + + inline VkWriteDescriptorSet writeDescriptorSet( + VkDescriptorSet dstSet, + VkDescriptorType type, + uint32_t binding, + VkDescriptorImageInfo *imageInfo, + uint32_t descriptorCount = 1) + { + VkWriteDescriptorSet writeDescriptorSet {}; + writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptorSet.dstSet = dstSet; + writeDescriptorSet.descriptorType = type; + writeDescriptorSet.dstBinding = binding; + writeDescriptorSet.pImageInfo = imageInfo; + writeDescriptorSet.descriptorCount = descriptorCount; + return writeDescriptorSet; + } + + inline VkVertexInputBindingDescription vertexInputBindingDescription( + uint32_t binding, + uint32_t stride, + VkVertexInputRate inputRate) + { + VkVertexInputBindingDescription vInputBindDescription {}; + vInputBindDescription.binding = binding; + vInputBindDescription.stride = stride; + vInputBindDescription.inputRate = inputRate; + return vInputBindDescription; + } + + inline VkVertexInputAttributeDescription vertexInputAttributeDescription( + uint32_t binding, + uint32_t location, + VkFormat format, + uint32_t offset) + { + VkVertexInputAttributeDescription vInputAttribDescription {}; + vInputAttribDescription.location = location; + vInputAttribDescription.binding = binding; + vInputAttribDescription.format = format; + vInputAttribDescription.offset = offset; + return vInputAttribDescription; + } + + inline VkPipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo() + { + VkPipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo {}; + pipelineVertexInputStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + return pipelineVertexInputStateCreateInfo; + } + + inline VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateCreateInfo( + VkPrimitiveTopology topology, + VkPipelineInputAssemblyStateCreateFlags flags, + VkBool32 primitiveRestartEnable) + { + VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateCreateInfo {}; + pipelineInputAssemblyStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + pipelineInputAssemblyStateCreateInfo.topology = topology; + pipelineInputAssemblyStateCreateInfo.flags = flags; + pipelineInputAssemblyStateCreateInfo.primitiveRestartEnable = primitiveRestartEnable; + return pipelineInputAssemblyStateCreateInfo; + } + + inline VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateCreateInfo( + VkPolygonMode polygonMode, + VkCullModeFlags cullMode, + VkFrontFace frontFace, + VkPipelineRasterizationStateCreateFlags flags = 0) + { + VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateCreateInfo {}; + pipelineRasterizationStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + pipelineRasterizationStateCreateInfo.polygonMode = polygonMode; + pipelineRasterizationStateCreateInfo.cullMode = cullMode; + pipelineRasterizationStateCreateInfo.frontFace = frontFace; + pipelineRasterizationStateCreateInfo.flags = flags; + pipelineRasterizationStateCreateInfo.depthClampEnable = VK_FALSE; + pipelineRasterizationStateCreateInfo.lineWidth = 1.0f; + return pipelineRasterizationStateCreateInfo; + } + + inline VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState( + VkColorComponentFlags colorWriteMask, + VkBool32 blendEnable) + { + VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState {}; + pipelineColorBlendAttachmentState.colorWriteMask = colorWriteMask; + pipelineColorBlendAttachmentState.blendEnable = blendEnable; + return pipelineColorBlendAttachmentState; + } + + inline VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateCreateInfo( + uint32_t attachmentCount, + const VkPipelineColorBlendAttachmentState * pAttachments) + { + VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateCreateInfo {}; + pipelineColorBlendStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + pipelineColorBlendStateCreateInfo.attachmentCount = attachmentCount; + pipelineColorBlendStateCreateInfo.pAttachments = pAttachments; + return pipelineColorBlendStateCreateInfo; + } + + inline VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateCreateInfo( + VkBool32 depthTestEnable, + VkBool32 depthWriteEnable, + VkCompareOp depthCompareOp) + { + VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateCreateInfo {}; + pipelineDepthStencilStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + pipelineDepthStencilStateCreateInfo.depthTestEnable = depthTestEnable; + pipelineDepthStencilStateCreateInfo.depthWriteEnable = depthWriteEnable; + pipelineDepthStencilStateCreateInfo.depthCompareOp = depthCompareOp; + pipelineDepthStencilStateCreateInfo.front = pipelineDepthStencilStateCreateInfo.back; + pipelineDepthStencilStateCreateInfo.back.compareOp = VK_COMPARE_OP_ALWAYS; + return pipelineDepthStencilStateCreateInfo; + } + + inline VkPipelineViewportStateCreateInfo pipelineViewportStateCreateInfo( + uint32_t viewportCount, + uint32_t scissorCount, + VkPipelineViewportStateCreateFlags flags = 0) + { + VkPipelineViewportStateCreateInfo pipelineViewportStateCreateInfo {}; + pipelineViewportStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + pipelineViewportStateCreateInfo.viewportCount = viewportCount; + pipelineViewportStateCreateInfo.scissorCount = scissorCount; + pipelineViewportStateCreateInfo.flags = flags; + return pipelineViewportStateCreateInfo; + } + + inline VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo( + VkSampleCountFlagBits rasterizationSamples, + VkPipelineMultisampleStateCreateFlags flags = 0) + { + VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo {}; + pipelineMultisampleStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + pipelineMultisampleStateCreateInfo.rasterizationSamples = rasterizationSamples; + pipelineMultisampleStateCreateInfo.flags = flags; + return pipelineMultisampleStateCreateInfo; + } + + inline VkPipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo( + const VkDynamicState * pDynamicStates, + uint32_t dynamicStateCount, + VkPipelineDynamicStateCreateFlags flags = 0) + { + VkPipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo {}; + pipelineDynamicStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + pipelineDynamicStateCreateInfo.pDynamicStates = pDynamicStates; + pipelineDynamicStateCreateInfo.dynamicStateCount = dynamicStateCount; + pipelineDynamicStateCreateInfo.flags = flags; + return pipelineDynamicStateCreateInfo; + } + + inline VkPipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo( + const std::vector<VkDynamicState>& pDynamicStates, + VkPipelineDynamicStateCreateFlags flags = 0) + { + VkPipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo{}; + pipelineDynamicStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + pipelineDynamicStateCreateInfo.pDynamicStates = pDynamicStates.data(); + pipelineDynamicStateCreateInfo.dynamicStateCount = static_cast<uint32_t>(pDynamicStates.size()); + pipelineDynamicStateCreateInfo.flags = flags; + return pipelineDynamicStateCreateInfo; + } + + inline VkPipelineTessellationStateCreateInfo pipelineTessellationStateCreateInfo(uint32_t patchControlPoints) + { + VkPipelineTessellationStateCreateInfo pipelineTessellationStateCreateInfo {}; + pipelineTessellationStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; + pipelineTessellationStateCreateInfo.patchControlPoints = patchControlPoints; + return pipelineTessellationStateCreateInfo; + } + + inline VkGraphicsPipelineCreateInfo pipelineCreateInfo( + VkPipelineLayout layout, + VkRenderPass renderPass, + VkPipelineCreateFlags flags = 0) + { + VkGraphicsPipelineCreateInfo pipelineCreateInfo {}; + pipelineCreateInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipelineCreateInfo.layout = layout; + pipelineCreateInfo.renderPass = renderPass; + pipelineCreateInfo.flags = flags; + pipelineCreateInfo.basePipelineIndex = -1; + pipelineCreateInfo.basePipelineHandle = VK_NULL_HANDLE; + return pipelineCreateInfo; + } + + inline VkGraphicsPipelineCreateInfo pipelineCreateInfo() + { + VkGraphicsPipelineCreateInfo pipelineCreateInfo{}; + pipelineCreateInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipelineCreateInfo.basePipelineIndex = -1; + pipelineCreateInfo.basePipelineHandle = VK_NULL_HANDLE; + return pipelineCreateInfo; + } + + inline VkComputePipelineCreateInfo computePipelineCreateInfo( + VkPipelineLayout layout, + VkPipelineCreateFlags flags = 0) + { + VkComputePipelineCreateInfo computePipelineCreateInfo {}; + computePipelineCreateInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; + computePipelineCreateInfo.layout = layout; + computePipelineCreateInfo.flags = flags; + return computePipelineCreateInfo; + } + + inline VkPushConstantRange pushConstantRange( + VkShaderStageFlags stageFlags, + uint32_t size, + uint32_t offset) + { + VkPushConstantRange pushConstantRange {}; + pushConstantRange.stageFlags = stageFlags; + pushConstantRange.offset = offset; + pushConstantRange.size = size; + return pushConstantRange; + } + + inline VkBindSparseInfo bindSparseInfo() + { + VkBindSparseInfo bindSparseInfo{}; + bindSparseInfo.sType = VK_STRUCTURE_TYPE_BIND_SPARSE_INFO; + return bindSparseInfo; + } + + /** @brief Initialize a map entry for a shader specialization constant */ + inline VkSpecializationMapEntry specializationMapEntry(uint32_t constantID, uint32_t offset, size_t size) + { + VkSpecializationMapEntry specializationMapEntry{}; + specializationMapEntry.constantID = constantID; + specializationMapEntry.offset = offset; + specializationMapEntry.size = size; + return specializationMapEntry; + } + + /** @brief Initialize a specialization constant info structure to pass to a shader stage */ + inline VkSpecializationInfo specializationInfo(uint32_t mapEntryCount, const VkSpecializationMapEntry* mapEntries, size_t dataSize, const void* data) + { + VkSpecializationInfo specializationInfo{}; + specializationInfo.mapEntryCount = mapEntryCount; + specializationInfo.pMapEntries = mapEntries; + specializationInfo.dataSize = dataSize; + specializationInfo.pData = data; + return specializationInfo; + } + } +} \ No newline at end of file diff --git a/vkpreemption/VulkanTools.cpp b/vkpreemption/VulkanTools.cpp new file mode 100644 index 00000000..e7fcac56 --- /dev/null +++ b/vkpreemption/VulkanTools.cpp @@ -0,0 +1,361 @@ +/* +* Assorted commonly used Vulkan helper functions +* +* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de +* +* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) +*/ + +#include "VulkanTools.h" + +namespace vks +{ + namespace tools + { + bool errorModeSilent = false; + + std::string errorString(VkResult errorCode) + { + switch (errorCode) + { +#define STR(r) case VK_ ##r: return #r + STR(NOT_READY); + STR(TIMEOUT); + STR(EVENT_SET); + STR(EVENT_RESET); + STR(INCOMPLETE); + STR(ERROR_OUT_OF_HOST_MEMORY); + STR(ERROR_OUT_OF_DEVICE_MEMORY); + STR(ERROR_INITIALIZATION_FAILED); + STR(ERROR_DEVICE_LOST); + STR(ERROR_MEMORY_MAP_FAILED); + STR(ERROR_LAYER_NOT_PRESENT); + STR(ERROR_EXTENSION_NOT_PRESENT); + STR(ERROR_FEATURE_NOT_PRESENT); + STR(ERROR_INCOMPATIBLE_DRIVER); + STR(ERROR_TOO_MANY_OBJECTS); + STR(ERROR_FORMAT_NOT_SUPPORTED); + STR(ERROR_SURFACE_LOST_KHR); + STR(ERROR_NATIVE_WINDOW_IN_USE_KHR); + STR(SUBOPTIMAL_KHR); + STR(ERROR_OUT_OF_DATE_KHR); + STR(ERROR_INCOMPATIBLE_DISPLAY_KHR); + STR(ERROR_VALIDATION_FAILED_EXT); + STR(ERROR_INVALID_SHADER_NV); +#undef STR + default: + return "UNKNOWN_ERROR"; + } + } + + std::string physicalDeviceTypeString(VkPhysicalDeviceType type) + { + switch (type) + { +#define STR(r) case VK_PHYSICAL_DEVICE_TYPE_ ##r: return #r + STR(OTHER); + STR(INTEGRATED_GPU); + STR(DISCRETE_GPU); + STR(VIRTUAL_GPU); +#undef STR + default: return "UNKNOWN_DEVICE_TYPE"; + } + } + + VkBool32 getSupportedDepthFormat(VkPhysicalDevice physicalDevice, VkFormat *depthFormat) + { + // Since all depth formats may be optional, we need to find a suitable depth format to use + // Start with the highest precision packed format + std::vector<VkFormat> depthFormats = { + VK_FORMAT_D32_SFLOAT_S8_UINT, + VK_FORMAT_D32_SFLOAT, + VK_FORMAT_D24_UNORM_S8_UINT, + VK_FORMAT_D16_UNORM_S8_UINT, + VK_FORMAT_D16_UNORM + }; + + for (auto& format : depthFormats) + { + VkFormatProperties formatProps; + vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &formatProps); + // Format must support depth stencil attachment for optimal tiling + if (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) + { + *depthFormat = format; + return true; + } + } + + return false; + } + + // Create an image memory barrier for changing the layout of + // an image and put it into an active command buffer + // See chapter 11.4 "Image Layout" for details + + void setImageLayout( + VkCommandBuffer cmdbuffer, + VkImage image, + VkImageLayout oldImageLayout, + VkImageLayout newImageLayout, + VkImageSubresourceRange subresourceRange, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask) + { + // Create an image barrier object + VkImageMemoryBarrier imageMemoryBarrier = vks::initializers::imageMemoryBarrier(); + imageMemoryBarrier.oldLayout = oldImageLayout; + imageMemoryBarrier.newLayout = newImageLayout; + imageMemoryBarrier.image = image; + imageMemoryBarrier.subresourceRange = subresourceRange; + + // Source layouts (old) + // Source access mask controls actions that have to be finished on the old layout + // before it will be transitioned to the new layout + switch (oldImageLayout) + { + case VK_IMAGE_LAYOUT_UNDEFINED: + // Image layout is undefined (or does not matter) + // Only valid as initial layout + // No flags required, listed only for completeness + imageMemoryBarrier.srcAccessMask = 0; + break; + + case VK_IMAGE_LAYOUT_PREINITIALIZED: + // Image is preinitialized + // Only valid as initial layout for linear images, preserves memory contents + // Make sure host writes have been finished + imageMemoryBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT; + break; + + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + // Image is a color attachment + // Make sure any writes to the color buffer have been finished + imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + break; + + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: + // Image is a depth/stencil attachment + // Make sure any writes to the depth/stencil buffer have been finished + imageMemoryBarrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + break; + + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: + // Image is a transfer source + // Make sure any reads from the image have been finished + imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + break; + + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + // Image is a transfer destination + // Make sure any writes to the image have been finished + imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + break; + + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + // Image is read by a shader + // Make sure any shader reads from the image have been finished + imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + break; + default: + // Other source layouts aren't handled (yet) + break; + } + + // Target layouts (new) + // Destination access mask controls the dependency for the new image layout + switch (newImageLayout) + { + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + // Image will be used as a transfer destination + // Make sure any writes to the image have been finished + imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + break; + + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: + // Image will be used as a transfer source + // Make sure any reads from the image have been finished + imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + break; + + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + // Image will be used as a color attachment + // Make sure any writes to the color buffer have been finished + imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + break; + + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: + // Image layout will be used as a depth/stencil attachment + // Make sure any writes to depth/stencil buffer have been finished + imageMemoryBarrier.dstAccessMask = imageMemoryBarrier.dstAccessMask | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + break; + + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + // Image will be read in a shader (sampler, input attachment) + // Make sure any writes to the image have been finished + if (imageMemoryBarrier.srcAccessMask == 0) + { + imageMemoryBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT; + } + imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + break; + default: + // Other source layouts aren't handled (yet) + break; + } + + // Put barrier inside setup command buffer + vkCmdPipelineBarrier( + cmdbuffer, + srcStageMask, + dstStageMask, + 0, + 0, nullptr, + 0, nullptr, + 1, &imageMemoryBarrier); + } + + // Fixed sub resource on first mip level and layer + void setImageLayout( + VkCommandBuffer cmdbuffer, + VkImage image, + VkImageAspectFlags aspectMask, + VkImageLayout oldImageLayout, + VkImageLayout newImageLayout, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask) + { + VkImageSubresourceRange subresourceRange = {}; + subresourceRange.aspectMask = aspectMask; + subresourceRange.baseMipLevel = 0; + subresourceRange.levelCount = 1; + subresourceRange.layerCount = 1; + setImageLayout(cmdbuffer, image, oldImageLayout, newImageLayout, subresourceRange, srcStageMask, dstStageMask); + } + + void insertImageMemoryBarrier( + VkCommandBuffer cmdbuffer, + VkImage image, + VkAccessFlags srcAccessMask, + VkAccessFlags dstAccessMask, + VkImageLayout oldImageLayout, + VkImageLayout newImageLayout, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, + VkImageSubresourceRange subresourceRange) + { + VkImageMemoryBarrier imageMemoryBarrier = vks::initializers::imageMemoryBarrier(); + imageMemoryBarrier.srcAccessMask = srcAccessMask; + imageMemoryBarrier.dstAccessMask = dstAccessMask; + imageMemoryBarrier.oldLayout = oldImageLayout; + imageMemoryBarrier.newLayout = newImageLayout; + imageMemoryBarrier.image = image; + imageMemoryBarrier.subresourceRange = subresourceRange; + + vkCmdPipelineBarrier( + cmdbuffer, + srcStageMask, + dstStageMask, + 0, + 0, nullptr, + 0, nullptr, + 1, &imageMemoryBarrier); + } + + void exitFatal(std::string message, int32_t exitCode) + { +#if defined(_WIN32) + if (!errorModeSilent) { + MessageBox(NULL, message.c_str(), NULL, MB_OK | MB_ICONERROR); + } +#elif defined(__ANDROID__) + LOGE("Fatal error: %s", message.c_str()); + vks::android::showAlert(message.c_str()); +#endif + std::cerr << message << "\n"; +#if !defined(__ANDROID__) + exit(exitCode); +#endif + } + + void exitFatal(std::string message, VkResult resultCode) + { + exitFatal(message, (int32_t)resultCode); + } + + std::string readTextFile(const char *fileName) + { + std::string fileContent; + std::ifstream fileStream(fileName, std::ios::in); + if (!fileStream.is_open()) { + printf("File %s not found\n", fileName); + return ""; + } + std::string line = ""; + while (!fileStream.eof()) { + getline(fileStream, line); + fileContent.append(line + "\n"); + } + fileStream.close(); + return fileContent; + } + +#if 1 + // Android shaders are stored as assets in the apk + // So they need to be loaded via the asset manager + VkShaderModule loadShader(size_t size, const uint32_t* code, VkDevice device) + { + VkShaderModule shaderModule; + VkShaderModuleCreateInfo moduleCreateInfo; + moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + moduleCreateInfo.pNext = NULL; + moduleCreateInfo.codeSize = size; + moduleCreateInfo.pCode = code; + moduleCreateInfo.flags = 0; + + VK_CHECK_RESULT(vkCreateShaderModule(device, &moduleCreateInfo, NULL, &shaderModule)); + + return shaderModule; + } +#else + VkShaderModule loadShader(const char *fileName, VkDevice device) + { + std::ifstream is(fileName, std::ios::binary | std::ios::in | std::ios::ate); + + if (is.is_open()) + { + size_t size = is.tellg(); + is.seekg(0, std::ios::beg); + char* shaderCode = new char[size]; + is.read(shaderCode, size); + is.close(); + + assert(size > 0); + + VkShaderModule shaderModule; + VkShaderModuleCreateInfo moduleCreateInfo{}; + moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + moduleCreateInfo.codeSize = size; + moduleCreateInfo.pCode = (uint32_t*)shaderCode; + + VK_CHECK_RESULT(vkCreateShaderModule(device, &moduleCreateInfo, NULL, &shaderModule)); + + delete[] shaderCode; + + return shaderModule; + } + else + { + std::cerr << "Error: Could not open shader file \"" << fileName << "\"" << std::endl; + return VK_NULL_HANDLE; + } + } +#endif + + bool fileExists(const std::string &filename) + { + std::ifstream f(filename.c_str()); + return !f.fail(); + } + } +} \ No newline at end of file diff --git a/vkpreemption/VulkanTools.h b/vkpreemption/VulkanTools.h new file mode 100644 index 00000000..02b7bbf6 --- /dev/null +++ b/vkpreemption/VulkanTools.h @@ -0,0 +1,118 @@ +/* + * Assorted Vulkan helper functions + * + * Copyright (C) 2016 by Sascha Willems - www.saschawillems.de + * + * This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + */ + +#pragma once + +#include "vulkan/vulkan.h" +#include "VulkanInitializers.hpp" + +#include <math.h> +#include <stdlib.h> +#include <string> +#include <cstring> +#include <fstream> +#include <assert.h> +#include <stdio.h> +#include <vector> +#include <iostream> +#include <stdexcept> +#include <fstream> + +// Custom define for better code readability +#define VK_FLAGS_NONE 0 +// Default fence timeout in nanoseconds +#define DEFAULT_FENCE_TIMEOUT 100000000000 + +// Macro to check and display Vulkan return results +#define VK_CHECK_RESULT(f) \ +{ \ + VkResult res = (f); \ + if (res != VK_SUCCESS) { \ + std::cout << "Fatal : VkResult is \"" << \ + vks::tools::errorString(res) << "\" in " << __FILE__ << \ + " at line " << __LINE__ << std::endl; \ + assert(res == VK_SUCCESS); \ + } \ +} + +#if defined(__ANDROID__) +#define ASSET_PATH "" +#else +#define ASSET_PATH "./../data/" +#endif + +namespace vks +{ + namespace tools + { + /** @brief Disable message boxes on fatal errors */ + extern bool errorModeSilent; + + /** @brief Returns an error code as a string */ + std::string errorString(VkResult errorCode); + + /** @brief Returns the device type as a string */ + std::string physicalDeviceTypeString( + VkPhysicalDeviceType type); + + // Selected a suitable supported depth format starting with 32 + // bit down to 16 bit. Returns false if none of the depth + // formats in the list is supported by the device. + VkBool32 getSupportedDepthFormat( + VkPhysicalDevice physicalDevice, + VkFormat *depthFormat); + + // Put an image memory barrier for setting an image layout on + // the sub resource into the given command buffer + void setImageLayout( + VkCommandBuffer cmdbuffer, + VkImage image, + VkImageLayout oldImageLayout, + VkImageLayout newImageLayout, + VkImageSubresourceRange subresourceRange, + VkPipelineStageFlags srcStageMask = + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + VkPipelineStageFlags dstStageMask = + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); + // Uses a fixed sub resource layout with first mip level and + // layer + void setImageLayout( + VkCommandBuffer cmdbuffer, + VkImage image, + VkImageAspectFlags aspectMask, + VkImageLayout oldImageLayout, + VkImageLayout newImageLayout, + VkPipelineStageFlags srcStageMask = + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + VkPipelineStageFlags dstStageMask = + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); + + // brief Inser an image memory barrier into the command buffer + void insertImageMemoryBarrier( + VkCommandBuffer cmdbuffer, + VkImage image, + VkAccessFlags srcAccessMask, + VkAccessFlags dstAccessMask, + VkImageLayout oldImageLayout, + VkImageLayout newImageLayout, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, + VkImageSubresourceRange subresourceRange); + + // Display error message and exit on fatal error + void exitFatal(std::string message, int32_t exitCode); + void exitFatal(std::string message, VkResult resultCode); + + // Load a SPIR-V shader (binary) + VkShaderModule loadShader(size_t size, const uint32_t *code, + VkDevice device); + + /** @brief Checks if a file exists */ + bool fileExists(const std::string & filename); + } +} diff --git a/vkpreemption/base.hpp b/vkpreemption/base.hpp new file mode 100644 index 00000000..4c3e9edc --- /dev/null +++ b/vkpreemption/base.hpp @@ -0,0 +1,269 @@ +/* + * * + * * Copyright (C) 2020 Samsung Electronics + * * + * */ + +#pragma once + +#include <vulkan/vulkan.h> +#include "VulkanTools.h" + +#include <map> +#include <set> +#include <utility> + +#if defined(VK_USE_PLATFORM_ANDROID_KHR) +#define LOG(...) ((void)__android_log_print(ANDROID_LOG_INFO, "vulkanExample", __VA_ARGS__)) +#else +#define LOG(...) { printf(__VA_ARGS__); fflush(stdout); } +#endif + +struct QueueInfo { + VkQueueFlagBits type; + VkQueueGlobalPriorityEXT priority; + VkQueue queue; + uint32_t familyIndex; + unsigned offset; +}; + +class Workload { +public: + virtual VkFence submit() = 0; + virtual void queryTimestamp(uint64_t time_stamp[], int count) = 0; + virtual void waitIdle() = 0; +}; + +class Base { + VkInstance m_instance; + VkDevice m_device; + VkPhysicalDevice m_physicalDevice; + VkPhysicalDeviceProperties m_deviceProperties; + std::map<VkQueueGlobalPriorityEXT, QueueInfo> m_graphicQueues; + std::map<VkQueueGlobalPriorityEXT, QueueInfo> m_computeQueues; + + std::map<VkQueueGlobalPriorityEXT, QueueInfo>& GetQueueInfos(VkQueueFlagBits type) { + switch(type) { + case VK_QUEUE_COMPUTE_BIT: return m_computeQueues; + case VK_QUEUE_GRAPHICS_BIT: return m_graphicQueues; + default: LOG("Unsupported queue type\n"); + } + + return m_graphicQueues; + } + QueueInfo& CreateQueueInfo(VkQueueFlagBits type, VkQueueGlobalPriorityEXT priority) { + QueueInfo queueInfo = {}; + queueInfo.type = type; + queueInfo.priority = priority; + + return GetQueueInfos(type).insert({priority, queueInfo}).first->second; + } + +public: + VkDevice GetDevice() const { return m_device; } + VkInstance GetInstance() const { return m_instance; } + VkPhysicalDevice GetPhysicalDevice() const { return m_physicalDevice; } + VkPhysicalDeviceProperties GetPhysicalDeviceProperties() const { return m_deviceProperties; } + QueueInfo const& GetQueueInfo(VkQueueFlagBits type, VkQueueGlobalPriorityEXT priority) { + return GetQueueInfos(type).at(priority); + } + + Base(std::vector<VkQueueGlobalPriorityEXT> graphicPriorities, std::vector<VkQueueGlobalPriorityEXT> computePriorities) + { + LOG("Create a device\n"); + +#if defined(VK_USE_PLATFORM_ANDROID_KHR) + LOG("loading vulkan lib"); + vks::android::loadVulkanLibrary(); +#endif + + VkApplicationInfo appInfo = {}; + appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + appInfo.pApplicationName = "Vulkan headless example"; + appInfo.pEngineName = "ComputeWork"; + appInfo.apiVersion = VK_API_VERSION_1_0; + + /* + Vulkan instance creation (without surface extensions) + */ + VkInstanceCreateInfo instanceCreateInfo = {}; + instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + instanceCreateInfo.pApplicationInfo = &appInfo; + + uint32_t layerCount = 0; +#if defined(VK_USE_PLATFORM_ANDROID_KHR) + const char* validationLayers[] = { "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation", "VK_LAYER_LUNARG_object_tracker","VK_LAYER_LUNARG_core_validation", "VK_LAYER_LUNARG_swapchain", "VK_LAYER_GOOGLE_unique_objects" }; + layerCount = 6; +#else + const char* validationLayers[] = { "VK_LAYER_LUNARG_standard_validation" }; + layerCount = 1; +#endif +#if DEBUG + // Check if layers are available + uint32_t instanceLayerCount; + vkEnumerateInstanceLayerProperties(&instanceLayerCount, nullptr); + std::vector<VkLayerProperties> instanceLayers(instanceLayerCount); + vkEnumerateInstanceLayerProperties(&instanceLayerCount, instanceLayers.data()); + + bool layersAvailable = true; + for (auto layerName : validationLayers) { + bool layerAvailable = false; + for (auto instanceLayer : instanceLayers) { + if (strcmp(instanceLayer.layerName, layerName) == 0) { + layerAvailable = true; + break; + } + } + if (!layerAvailable) { + layersAvailable = false; + break; + } + } + + if (layersAvailable) { + instanceCreateInfo.ppEnabledLayerNames = validationLayers; + const char *validationExt = VK_EXT_DEBUG_REPORT_EXTENSION_NAME; + instanceCreateInfo.enabledLayerCount = layerCount; + instanceCreateInfo.enabledExtensionCount = 1; + instanceCreateInfo.ppEnabledExtensionNames = &validationExt; + } +#endif + VK_CHECK_RESULT(vkCreateInstance(&instanceCreateInfo, nullptr, &m_instance)); + +#if defined(VK_USE_PLATFORM_ANDROID_KHR) + vks::android::loadVulkanFunctions(m_instance); +#endif +#if DEBUG + if (layersAvailable) { + VkDebugReportCallbackCreateInfoEXT debugReportCreateInfo = {}; + debugReportCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT; + debugReportCreateInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT; + debugReportCreateInfo.pfnCallback = (PFN_vkDebugReportCallbackEXT)debugMessageCallback; + + // We have to explicitly load this function. + PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT = reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>(vkGetInstanceProcAddr(m_instance, "vkCreateDebugReportCallbackEXT")); + assert(vkCreateDebugReportCallbackEXT); + VK_CHECK_RESULT(vkCreateDebugReportCallbackEXT(instance, &debugReportCreateInfo, nullptr, &debugReportCallback)); + } +#endif + + /* + Vulkan device creation + */ + // Physical device (always use first) + uint32_t deviceCount = 0; + VK_CHECK_RESULT(vkEnumeratePhysicalDevices(m_instance, &deviceCount, nullptr)); + std::vector<VkPhysicalDevice> physicalDevices(deviceCount); + VK_CHECK_RESULT(vkEnumeratePhysicalDevices(m_instance, &deviceCount, physicalDevices.data())); + m_physicalDevice = physicalDevices[0]; + + vkGetPhysicalDeviceProperties(m_physicalDevice, &m_deviceProperties); + LOG("GPU: %s\n", m_deviceProperties.deviceName); + + const float defaultQueuePriority(0.0f); + uint32_t queueFamilyCount; + vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice, &queueFamilyCount, nullptr); + std::vector<VkQueueFamilyProperties> queueFamilyProperties(queueFamilyCount); + vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice, &queueFamilyCount, queueFamilyProperties.data()); + const size_t queueCount = graphicPriorities.size() + computePriorities.size(); + const size_t familyCount = queueFamilyProperties.size(); + std::vector<unsigned> queueFamilyNextOffset(familyCount, 0); + std::vector<VkDeviceQueueCreateInfo> queueCreateInfos(familyCount); + std::vector<VkDeviceQueueGlobalPriorityCreateInfoEXT > queuePriorityCreateInfos(familyCount); + + for (size_t i = 0; i < familyCount; i++) { + VkDeviceQueueGlobalPriorityCreateInfoEXT queuePriorityCreateInfo = {}; + VkDeviceQueueCreateInfo queueCreateInfo = {}; + + queuePriorityCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT; + queuePriorityCreateInfo.pNext = nullptr; + queuePriorityCreateInfo.globalPriority = VK_QUEUE_GLOBAL_PRIORITY_RANGE_SIZE_EXT; + queuePriorityCreateInfos[i] = queuePriorityCreateInfo; + + queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueCreateInfo.queueFamilyIndex = static_cast<uint32_t>(i); + queueCreateInfo.pNext = nullptr; + queueCreateInfo.queueCount = 0; + queueCreateInfo.pQueuePriorities = &defaultQueuePriority; + queueCreateInfos[i] = queueCreateInfo; + } + + auto addQueue = [&](VkQueueFlagBits type, VkQueueGlobalPriorityEXT globalPriority) { + for (uint32_t i = type - 1; i < static_cast<uint32_t>(queueFamilyProperties.size()); i++) { + printf("addQueue queueFamilyNextOffset:%d queueCount:%d queueFlags:%08x queuetype:%d\n", + queueFamilyNextOffset[i], queueFamilyProperties[i].queueCount, + queueFamilyProperties[i].queueFlags, type); + if ((queueFamilyNextOffset[i] < queueFamilyProperties[i].queueCount) + && (queueFamilyProperties[i].queueFlags & type)) + { + auto& queueCreateInfo = queueCreateInfos[i]; + auto& queuePriorityCreateInfo = queuePriorityCreateInfos[i]; + + if (queueCreateInfo.pNext == nullptr || + queuePriorityCreateInfo.globalPriority == globalPriority) + { + queuePriorityCreateInfos[i].globalPriority = globalPriority; + queueCreateInfos[i].pNext = &queuePriorityCreateInfos[i]; + queueCreateInfos[i].queueCount++; + + auto& queueInfo = CreateQueueInfo(type, globalPriority); + queueInfo.offset = queueFamilyNextOffset[i]; + queueInfo.familyIndex = i; + + queueCreateInfos[i].queueCount = queueFamilyProperties[i].queueCount; + if (globalPriority == VkQueueGlobalPriorityEXT::VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT + || globalPriority == VkQueueGlobalPriorityEXT::VK_QUEUE_GLOBAL_PRIORITY_HIGH_EXT) { + queueInfo.offset = queueCreateInfos[i].queueCount - 1; + } + + queueFamilyNextOffset[i]++; + return; + } else { + LOG("Queue family %d already assigned priority %d and trying to assign priority %d\n", + i, queuePriorityCreateInfo.globalPriority, globalPriority); + } + } + } + LOG("Unable to add queue of type %d and priority %d\n", type, globalPriority); + exit(-1); + }; + + // As the Queue with graphics capabilitiies also has compute, reserve it for graphics before its selected for compute + for (auto priority : graphicPriorities) { + addQueue(VK_QUEUE_GRAPHICS_BIT, priority); + } + for (auto priority : computePriorities) { + addQueue(VK_QUEUE_COMPUTE_BIT, priority); + } + + // Create logical device + VkDeviceCreateInfo deviceCreateInfo = {}; + deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + deviceCreateInfo.queueCreateInfoCount = queueCreateInfos.size(); + deviceCreateInfo.pQueueCreateInfos = queueCreateInfos.data(); + VK_CHECK_RESULT(vkCreateDevice(m_physicalDevice, &deviceCreateInfo, nullptr, &m_device)); + + auto getQueue = [&](QueueInfo& queueInfo) { + vkGetDeviceQueue(m_device, queueInfo.familyIndex, queueInfo.offset, &queueInfo.queue); + }; + + LOG("Graphic queues : %zu\n", m_graphicQueues.size()); + for (auto& item: m_graphicQueues) { + auto& queueInfo = item.second; + getQueue(queueInfo); + LOG(" [%p] familyIndex %d, priority %d\n", queueInfo.queue, queueInfo.familyIndex, queueInfo.priority); + } + + LOG("Compute queues : %zu\n", m_computeQueues.size()); + for (auto& item: m_computeQueues) { + auto& queueInfo = item.second; + getQueue(queueInfo); + LOG(" [%p] familyIndex %d, priority %d\n", queueInfo.queue, queueInfo.familyIndex, queueInfo.priority); + } + } + + ~Base() { + vkDestroyDevice(m_device, nullptr); + vkDestroyInstance(m_instance, nullptr); + } +}; diff --git a/vkpreemption/build_lnx.sh b/vkpreemption/build_lnx.sh new file mode 100644 index 00000000..e8f8884b --- /dev/null +++ b/vkpreemption/build_lnx.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +mkdir build + +cd build + +cmake -DCMAKE_BUILD_TYPE=Debug -GNinja .. + +ninja all + +cd .. diff --git a/vkpreemption/computework.hpp b/vkpreemption/computework.hpp new file mode 100644 index 00000000..30d111fb --- /dev/null +++ b/vkpreemption/computework.hpp @@ -0,0 +1,429 @@ +/* +* * +* * Copyright (C) 2020 Samsung Electronics +* * +* */ + + +#pragma once + +#if defined(_WIN32) +#pragma comment(linker, "/subsystem:console") +#elif defined(VK_USE_PLATFORM_ANDROID_KHR) +#include <android/native_activity.h> +#include <android/asset_manager.h> +#include <android_native_app_glue.h> +#include <android/log.h> +#include "VulkanAndroid.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <vector> +#include <iostream> +#include <algorithm> + +#include <vulkan/vulkan.h> +#include "VulkanTools.h" +#include "base.hpp" + +#if defined(VK_USE_PLATFORM_ANDROID_KHR) +android_app* androidapp; +#endif + +#define DEBUG (!NDEBUG) + +#define BUFFER_ELEMENTS 32 + +class ComputeWork : public Workload +{ + const VkDeviceSize bufferSize = BUFFER_ELEMENTS * sizeof(uint32_t); + std::vector<uint32_t> computeInput; + std::vector<uint32_t> computeOutput; + +public: + VkInstance instance; + VkPhysicalDevice physicalDevice; + VkDevice device; + uint32_t queueFamilyIndex; + VkPipelineCache pipelineCache; + VkQueue queue; + VkCommandPool commandPool; + VkCommandBuffer commandBuffer; + VkFence fence; + VkDescriptorPool descriptorPool; + VkDescriptorSetLayout descriptorSetLayout; + VkDescriptorSet descriptorSet; + VkPipelineLayout pipelineLayout; + VkPipeline pipeline; + VkShaderModule shaderModule; + VkQueryPool query_pool; + + VkBuffer deviceBuffer, hostBuffer; + VkDeviceMemory deviceMemory, hostMemory; + + VkDebugReportCallbackEXT debugReportCallback{}; + + VkResult createBuffer(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkBuffer *buffer, VkDeviceMemory *memory, VkDeviceSize size, void *data = nullptr) + { + // Create the buffer handle + VkBufferCreateInfo bufferCreateInfo = vks::initializers::bufferCreateInfo(usageFlags, size); + bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + VK_CHECK_RESULT(vkCreateBuffer(device, &bufferCreateInfo, nullptr, buffer)); + + // Create the memory backing up the buffer handle + VkPhysicalDeviceMemoryProperties deviceMemoryProperties; + vkGetPhysicalDeviceMemoryProperties(physicalDevice, &deviceMemoryProperties); + VkMemoryRequirements memReqs; + VkMemoryAllocateInfo memAlloc = vks::initializers::memoryAllocateInfo(); + vkGetBufferMemoryRequirements(device, *buffer, &memReqs); + memAlloc.allocationSize = memReqs.size; + // Find a memory type index that fits the properties of the buffer + bool memTypeFound = false; + for (uint32_t i = 0; i < deviceMemoryProperties.memoryTypeCount; i++) { + if ((memReqs.memoryTypeBits & 1) == 1) { + if ((deviceMemoryProperties.memoryTypes[i].propertyFlags & memoryPropertyFlags) == memoryPropertyFlags) { + memAlloc.memoryTypeIndex = i; + memTypeFound = true; + } + } + memReqs.memoryTypeBits >>= 1; + } + assert(memTypeFound); + VK_CHECK_RESULT(vkAllocateMemory(device, &memAlloc, nullptr, memory)); + + if (data != nullptr) { + void *mapped; + VK_CHECK_RESULT(vkMapMemory(device, *memory, 0, size, 0, &mapped)); + memcpy(mapped, data, size); + vkUnmapMemory(device, *memory); + } + + VK_CHECK_RESULT(vkBindBufferMemory(device, *buffer, *memory, 0)); + + return VK_SUCCESS; + } + + ComputeWork(Base& base, QueueInfo queueInfo, unsigned commandCount = 1) + : computeInput(BUFFER_ELEMENTS) + , computeOutput(BUFFER_ELEMENTS) + { + device = base.GetDevice(); + instance = base.GetInstance(); + physicalDevice = base.GetPhysicalDevice(); + queueFamilyIndex = queueInfo.familyIndex; + queue = queueInfo.queue; + + // Compute command pool + VkCommandPoolCreateInfo cmdPoolInfo = {}; + cmdPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + cmdPoolInfo.queueFamilyIndex = queueFamilyIndex; + cmdPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + VK_CHECK_RESULT(vkCreateCommandPool(device, &cmdPoolInfo, nullptr, &commandPool)); + + VkQueryPoolCreateInfo query_pool_info; + query_pool_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; + query_pool_info.pNext = NULL; + query_pool_info.queryType = VK_QUERY_TYPE_TIMESTAMP; + query_pool_info.flags = 0; + query_pool_info.queryCount = 2; + query_pool_info.pipelineStatistics = 0; + VK_CHECK_RESULT(vkCreateQueryPool(device, &query_pool_info, NULL, &query_pool)); + + /* + Prepare storage buffers + */ + + // Fill input data + uint32_t n = 0; + std::generate(computeInput.begin(), computeInput.end(), [&n] { return n++; }); + + // Copy input data to VRAM using a staging buffer + { + createBuffer( + VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + &hostBuffer, + &hostMemory, + bufferSize, + computeInput.data()); + + // Flush writes to host visible buffer + void* mapped; + vkMapMemory(device, hostMemory, 0, VK_WHOLE_SIZE, 0, &mapped); + VkMappedMemoryRange mappedRange = vks::initializers::mappedMemoryRange(); + mappedRange.memory = hostMemory; + mappedRange.offset = 0; + mappedRange.size = VK_WHOLE_SIZE; + vkFlushMappedMemoryRanges(device, 1, &mappedRange); + vkUnmapMemory(device, hostMemory); + + createBuffer( + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + &deviceBuffer, + &deviceMemory, + bufferSize); + + // Copy to staging buffer + VkCommandBufferAllocateInfo cmdBufAllocateInfo = vks::initializers::commandBufferAllocateInfo(commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1); + VkCommandBuffer copyCmd; + VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, ©Cmd)); + VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo(); + VK_CHECK_RESULT(vkBeginCommandBuffer(copyCmd, &cmdBufInfo)); + //vkCmdResetQueryPool(copyCmd, query_pool, 0, 2); + VkBufferCopy copyRegion = {}; + copyRegion.size = bufferSize; + //vkCmdWriteTimestamp(copyCmd, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, query_pool, 0); + vkCmdCopyBuffer(copyCmd, hostBuffer, deviceBuffer, 1, ©Region); + //vkCmdWriteTimestamp(copyCmd, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, query_pool, 1); + VK_CHECK_RESULT(vkEndCommandBuffer(copyCmd)); + + VkSubmitInfo submitInfo = vks::initializers::submitInfo(); + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = ©Cmd; + VkFenceCreateInfo fenceInfo = vks::initializers::fenceCreateInfo(VK_FLAGS_NONE); + VkFence fence; + VK_CHECK_RESULT(vkCreateFence(device, &fenceInfo, nullptr, &fence)); + + // Submit to the queue + VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, fence)); + VK_CHECK_RESULT(vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX)); + + vkDestroyFence(device, fence, nullptr); + vkFreeCommandBuffers(device, commandPool, 1, ©Cmd); + } + + /* + Prepare compute pipeline + */ + { + std::vector<VkDescriptorPoolSize> poolSizes = { + vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1), + }; + + VkDescriptorPoolCreateInfo descriptorPoolInfo = + vks::initializers::descriptorPoolCreateInfo(static_cast<uint32_t>(poolSizes.size()), poolSizes.data(), 1); + VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool)); + + std::vector<VkDescriptorSetLayoutBinding> setLayoutBindings = { + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT, 0), + }; + VkDescriptorSetLayoutCreateInfo descriptorLayout = + vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); + VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout)); + + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = + vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayout, 1); + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout)); + + VkDescriptorSetAllocateInfo allocInfo = + vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout, 1); + VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet)); + + VkDescriptorBufferInfo bufferDescriptor = { deviceBuffer, 0, VK_WHOLE_SIZE }; + std::vector<VkWriteDescriptorSet> computeWriteDescriptorSets = { + vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 0, &bufferDescriptor), + }; + vkUpdateDescriptorSets(device, static_cast<uint32_t>(computeWriteDescriptorSets.size()), computeWriteDescriptorSets.data(), 0, NULL); + + VkPipelineCacheCreateInfo pipelineCacheCreateInfo = {}; + pipelineCacheCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; + VK_CHECK_RESULT(vkCreatePipelineCache(device, &pipelineCacheCreateInfo, nullptr, &pipelineCache)); + + // Create pipeline + VkComputePipelineCreateInfo computePipelineCreateInfo = vks::initializers::computePipelineCreateInfo(pipelineLayout, 0); + + // Pass SSBO size via specialization constant + struct SpecializationData { + uint32_t BUFFER_ELEMENT_COUNT = BUFFER_ELEMENTS; + } specializationData; + VkSpecializationMapEntry specializationMapEntry = vks::initializers::specializationMapEntry(0, 0, sizeof(uint32_t)); + VkSpecializationInfo specializationInfo = vks::initializers::specializationInfo(1, &specializationMapEntry, sizeof(SpecializationData), &specializationData); + + VkPipelineShaderStageCreateInfo shaderStage = {}; + shaderStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shaderStage.stage = VK_SHADER_STAGE_COMPUTE_BIT; +#if 1 + const uint32_t headless_comp[] = { + #include "headless.comp.inc" + }; + shaderStage.module = vks::tools::loadShader(sizeof(headless_comp), headless_comp, device); +#else + shaderStage.module = vks::tools::loadShader(ASSET_PATH "shaders/computeheadless/headless.comp.spv", device); +#endif + shaderStage.pName = "main"; + shaderStage.pSpecializationInfo = &specializationInfo; + shaderModule = shaderStage.module; + + assert(shaderStage.module != VK_NULL_HANDLE); + computePipelineCreateInfo.stage = shaderStage; + VK_CHECK_RESULT(vkCreateComputePipelines(device, pipelineCache, 1, &computePipelineCreateInfo, nullptr, &pipeline)); + + // Create a command buffer for compute operations + VkCommandBufferAllocateInfo cmdBufAllocateInfo = + vks::initializers::commandBufferAllocateInfo(commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1); + VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, &commandBuffer)); + + // Fence for compute CB sync + VkFenceCreateInfo fenceCreateInfo = vks::initializers::fenceCreateInfo(VK_FENCE_CREATE_SIGNALED_BIT); + VK_CHECK_RESULT(vkCreateFence(device, &fenceCreateInfo, nullptr, &fence)); + } + + /* + Command buffer creation (for compute work submission) + */ + { + VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo(); + + VK_CHECK_RESULT(vkBeginCommandBuffer(commandBuffer, &cmdBufInfo)); + vkCmdResetQueryPool(commandBuffer, query_pool, 0, 2); + // Barrier to ensure that input buffer transfer is finished before compute shader reads from it + VkBufferMemoryBarrier bufferBarrier = vks::initializers::bufferMemoryBarrier(); + bufferBarrier.buffer = deviceBuffer; + bufferBarrier.size = VK_WHOLE_SIZE; + bufferBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT; + bufferBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + bufferBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + bufferBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + + vkCmdPipelineBarrier( + commandBuffer, + VK_PIPELINE_STAGE_HOST_BIT, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_FLAGS_NONE, + 0, nullptr, + 1, &bufferBarrier, + 0, nullptr); + + vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline); + vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, 0, 1, &descriptorSet, 0, 0); + vkCmdWriteTimestamp(commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, query_pool, 0); + for (int i = 0;i < commandCount; i++) { + vkCmdDispatch(commandBuffer, BUFFER_ELEMENTS, 1, 1); + } + vkCmdWriteTimestamp(commandBuffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, query_pool, 1); + + // Barrier to ensure that shader writes are finished before buffer is read back from GPU + bufferBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + bufferBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + bufferBarrier.buffer = deviceBuffer; + bufferBarrier.size = VK_WHOLE_SIZE; + bufferBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + bufferBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + + vkCmdPipelineBarrier( + commandBuffer, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_FLAGS_NONE, + 0, nullptr, + 1, &bufferBarrier, + 0, nullptr); + + // Read back to host visible buffer + VkBufferCopy copyRegion = {}; + copyRegion.size = bufferSize; + //vkCmdWriteTimestamp(commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, query_pool, 4); + vkCmdCopyBuffer(commandBuffer, deviceBuffer, hostBuffer, 1, ©Region); + //vkCmdWriteTimestamp(commandBuffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, query_pool, 5); + + // Barrier to ensure that buffer copy is finished before host reading from it + bufferBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + bufferBarrier.dstAccessMask = VK_ACCESS_HOST_READ_BIT; + bufferBarrier.buffer = hostBuffer; + bufferBarrier.size = VK_WHOLE_SIZE; + bufferBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + bufferBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + + vkCmdPipelineBarrier( + commandBuffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_HOST_BIT, + VK_FLAGS_NONE, + 0, nullptr, + 1, &bufferBarrier, + 0, nullptr); + + VK_CHECK_RESULT(vkEndCommandBuffer(commandBuffer)); + + } + } + + virtual VkFence submit() override { + // Submit compute work + vkResetFences(device, 1, &fence); + const VkPipelineStageFlags waitStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; + VkSubmitInfo computeSubmitInfo = vks::initializers::submitInfo(); + computeSubmitInfo.pWaitDstStageMask = &waitStageMask; + computeSubmitInfo.commandBufferCount = 1; + computeSubmitInfo.pCommandBuffers = &commandBuffer; + VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &computeSubmitInfo, fence)); + + return fence; + } + + virtual void queryTimestamp(uint64_t time_stamp[], int count) override { + VK_CHECK_RESULT(vkGetQueryPoolResults(device, query_pool, 0, count, + sizeof(uint64_t)*count, time_stamp, sizeof(uint64_t), VK_QUERY_RESULT_64_BIT)); + } + + virtual void waitIdle() override { + VK_CHECK_RESULT(vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX)); + + // Make device writes visible to the host + void *mapped; + vkMapMemory(device, hostMemory, 0, VK_WHOLE_SIZE, 0, &mapped); + VkMappedMemoryRange mappedRange = vks::initializers::mappedMemoryRange(); + mappedRange.memory = hostMemory; + mappedRange.offset = 0; + mappedRange.size = VK_WHOLE_SIZE; + vkInvalidateMappedMemoryRanges(device, 1, &mappedRange); + + // Copy to output + memcpy(computeOutput.data(), mapped, bufferSize); + vkUnmapMemory(device, hostMemory); + + vkQueueWaitIdle(queue); + + // Output buffer contents + LOG("Compute input:\n"); + for (auto v : computeInput) { + LOG("%d \t", v); + } + std::cout << std::endl; + + LOG("Compute output:\n"); + for (auto v : computeOutput) { + LOG("%d \t", v); + } + std::cout << std::endl; + } + + ~ComputeWork() + { + vkDestroyBuffer(device, deviceBuffer, nullptr); + vkFreeMemory(device, deviceMemory, nullptr); + vkDestroyBuffer(device, hostBuffer, nullptr); + vkFreeMemory(device, hostMemory, nullptr); + + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); + vkDestroyDescriptorPool(device, descriptorPool, nullptr); + vkDestroyPipeline(device, pipeline, nullptr); + vkDestroyPipelineCache(device, pipelineCache, nullptr); + vkDestroyFence(device, fence, nullptr); + vkDestroyCommandPool(device, commandPool, nullptr); + vkDestroyShaderModule(device, shaderModule, nullptr); +#if DEBUG + if (debugReportCallback) { + PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallback = reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>(vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT")); + assert(vkDestroyDebugReportCallback); + vkDestroyDebugReportCallback(instance, debugReportCallback, nullptr); + } +#endif + } +}; + diff --git a/vkpreemption/graphicwork.hpp b/vkpreemption/graphicwork.hpp new file mode 100644 index 00000000..eba09481 --- /dev/null +++ b/vkpreemption/graphicwork.hpp @@ -0,0 +1,777 @@ +/* +* * +* * Copyright (C) 2020 Samsung Electronics +* * +* */ + + +#pragma once + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <vector> +#include <array> +#include <iostream> +#include <algorithm> +#include <ctime> + +#define GLM_FORCE_RADIANS +#define GLM_FORCE_DEPTH_ZERO_TO_ONE +#include <glm/glm.hpp> +#include <glm/gtc/matrix_transform.hpp> + +#include <vulkan/vulkan.h> +#include "VulkanTools.h" +#include "base.hpp" + +#if defined(VK_USE_PLATFORM_ANDROID_KHR) +//android_app* androidapp; +#endif + +#define DEBUG (!NDEBUG) + +#define BUFFER_ELEMENTS 32 + +class GraphicsWork : public Workload +{ +public: + VkInstance instance; + VkPhysicalDevice physicalDevice; + VkDevice device; + uint32_t queueFamilyIndex; + VkPipelineCache pipelineCache; + VkQueue queue; + VkFence fence; + VkCommandPool commandPool; + VkCommandBuffer commandBuffer; + VkDescriptorSetLayout descriptorSetLayout; + VkPipelineLayout pipelineLayout; + VkPipeline pipeline; + std::vector<VkShaderModule> shaderModules; + VkBuffer vertexBuffer, indexBuffer; + VkDeviceMemory vertexMemory, indexMemory; + VkQueryPool query_pool; + + struct FrameBufferAttachment { + VkImage image; + VkDeviceMemory memory; + VkImageView view; + }; + int32_t width, height; + VkFramebuffer framebuffer; + FrameBufferAttachment colorAttachment, depthAttachment; + VkRenderPass renderPass; + + VkDebugReportCallbackEXT debugReportCallback{}; + + uint32_t getMemoryTypeIndex(uint32_t typeBits, VkMemoryPropertyFlags properties) { + VkPhysicalDeviceMemoryProperties deviceMemoryProperties; + vkGetPhysicalDeviceMemoryProperties(physicalDevice, &deviceMemoryProperties); + for (uint32_t i = 0; i < deviceMemoryProperties.memoryTypeCount; i++) { + if ((typeBits & 1) == 1) { + if ((deviceMemoryProperties.memoryTypes[i].propertyFlags & properties) == properties) { + return i; + } + } + typeBits >>= 1; + } + return 0; + } + + VkResult createBuffer(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkBuffer *buffer, VkDeviceMemory *memory, VkDeviceSize size, void *data = nullptr) + { + // Create the buffer handle + VkBufferCreateInfo bufferCreateInfo = vks::initializers::bufferCreateInfo(usageFlags, size); + bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + VK_CHECK_RESULT(vkCreateBuffer(device, &bufferCreateInfo, nullptr, buffer)); + + // Create the memory backing up the buffer handle + VkMemoryRequirements memReqs; + VkMemoryAllocateInfo memAlloc = vks::initializers::memoryAllocateInfo(); + vkGetBufferMemoryRequirements(device, *buffer, &memReqs); + memAlloc.allocationSize = memReqs.size; + memAlloc.memoryTypeIndex = getMemoryTypeIndex(memReqs.memoryTypeBits, memoryPropertyFlags); + VK_CHECK_RESULT(vkAllocateMemory(device, &memAlloc, nullptr, memory)); + + if (data != nullptr) { + void *mapped; + VK_CHECK_RESULT(vkMapMemory(device, *memory, 0, size, 0, &mapped)); + memcpy(mapped, data, size); + vkUnmapMemory(device, *memory); + } + + VK_CHECK_RESULT(vkBindBufferMemory(device, *buffer, *memory, 0)); + + return VK_SUCCESS; + } + + /* + Submit command buffer to a queue and wait for fence until queue operations have been finished + */ + void submitWork(VkCommandBuffer cmdBuffer, VkQueue queue) + { + VkSubmitInfo submitInfo = vks::initializers::submitInfo(); + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &cmdBuffer; + VkFenceCreateInfo fenceInfo = vks::initializers::fenceCreateInfo(); + + VK_CHECK_RESULT(vkCreateFence(device, &fenceInfo, nullptr, &fence)); + VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, fence)); + VK_CHECK_RESULT(vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX)); + vkDestroyFence(device, fence, nullptr); + } + + GraphicsWork(Base& base, QueueInfo queueInfo, unsigned commandCount = 10, unsigned triangleCount = 3) + { + device = base.GetDevice(); + instance = base.GetInstance(); + physicalDevice = base.GetPhysicalDevice(); + queueFamilyIndex = queueInfo.familyIndex; + queue = queueInfo.queue; + + // Command pool + VkCommandPoolCreateInfo cmdPoolInfo = {}; + cmdPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + cmdPoolInfo.queueFamilyIndex = queueFamilyIndex; + cmdPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + VK_CHECK_RESULT(vkCreateCommandPool(device, &cmdPoolInfo, nullptr, &commandPool)); + + VkQueryPoolCreateInfo query_pool_info; + query_pool_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; + query_pool_info.pNext = NULL; + query_pool_info.queryType = VK_QUERY_TYPE_TIMESTAMP; + query_pool_info.flags = 0; + query_pool_info.queryCount = 2; + query_pool_info.pipelineStatistics = 0; + VK_CHECK_RESULT(vkCreateQueryPool(device, &query_pool_info, NULL, &query_pool)); + + /* + Prepare vertex and index buffers + */ + struct Vertex { + float position[3]; + float color[3]; + }; + auto randRange = [](float a, float b) -> float { + assert(b > a); + float dist = b - a; + + return ((float)rand() / RAND_MAX * dist) - (dist/2); + }; + + std::srand(std::time(nullptr)); + { + + std::vector<Vertex> vertices = { + { { 1.0f, 1.0f, 0.0f }, { 1.0f, 0.0f, 0.0f } }, + { { -1.0f, 1.0f, 0.0f }, { 0.0f, 1.0f, 0.0f } }, + { { 0.0f, -1.0f, 0.0f }, { 0.0f, 0.0f, 1.0f } } + }; + std::vector<uint32_t> indices = { 0, 1, 2 }; + + const VkDeviceSize vertexBufferSize = vertices.size() * sizeof(Vertex); + const VkDeviceSize indexBufferSize = indices.size() * sizeof(uint32_t); + + VkBuffer stagingBuffer; + VkDeviceMemory stagingMemory; + + // Command buffer for copy commands (reused) + VkCommandBufferAllocateInfo cmdBufAllocateInfo = vks::initializers::commandBufferAllocateInfo(commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1); + VkCommandBuffer copyCmd; + VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, ©Cmd)); + VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo(); + + // Copy input data to VRAM using a staging buffer + { + // Vertices + createBuffer( + VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + &stagingBuffer, + &stagingMemory, + vertexBufferSize, + vertices.data()); + + createBuffer( + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + &vertexBuffer, + &vertexMemory, + vertexBufferSize); + + VK_CHECK_RESULT(vkBeginCommandBuffer(copyCmd, &cmdBufInfo)); + VkBufferCopy copyRegion = {}; + copyRegion.size = vertexBufferSize; + vkCmdCopyBuffer(copyCmd, stagingBuffer, vertexBuffer, 1, ©Region); + VK_CHECK_RESULT(vkEndCommandBuffer(copyCmd)); + + submitWork(copyCmd, queue); + + vkDestroyBuffer(device, stagingBuffer, nullptr); + vkFreeMemory(device, stagingMemory, nullptr); + + // Indices + createBuffer( + VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + &stagingBuffer, + &stagingMemory, + indexBufferSize, + indices.data()); + + createBuffer( + VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + &indexBuffer, + &indexMemory, + indexBufferSize); + + VK_CHECK_RESULT(vkBeginCommandBuffer(copyCmd, &cmdBufInfo)); + copyRegion.size = indexBufferSize; + vkCmdCopyBuffer(copyCmd, stagingBuffer, indexBuffer, 1, ©Region); + VK_CHECK_RESULT(vkEndCommandBuffer(copyCmd)); + + submitWork(copyCmd, queue); + + vkDestroyBuffer(device, stagingBuffer, nullptr); + vkFreeMemory(device, stagingMemory, nullptr); + } + } + + /* + Create framebuffer attachments + */ + width = 1024; + height = 1024; + VkFormat colorFormat = VK_FORMAT_R8G8B8A8_UNORM; + VkFormat depthFormat; + vks::tools::getSupportedDepthFormat(physicalDevice, &depthFormat); + { + // Color attachment + VkImageCreateInfo image = vks::initializers::imageCreateInfo(); + image.imageType = VK_IMAGE_TYPE_2D; + image.format = colorFormat; + image.extent.width = width; + image.extent.height = height; + image.extent.depth = 1; + image.mipLevels = 1; + image.arrayLayers = 1; + image.samples = VK_SAMPLE_COUNT_1_BIT; + image.tiling = VK_IMAGE_TILING_OPTIMAL; + image.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + + VkMemoryAllocateInfo memAlloc = vks::initializers::memoryAllocateInfo(); + VkMemoryRequirements memReqs; + + VK_CHECK_RESULT(vkCreateImage(device, &image, nullptr, &colorAttachment.image)); + vkGetImageMemoryRequirements(device, colorAttachment.image, &memReqs); + memAlloc.allocationSize = memReqs.size; + memAlloc.memoryTypeIndex = getMemoryTypeIndex(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + VK_CHECK_RESULT(vkAllocateMemory(device, &memAlloc, nullptr, &colorAttachment.memory)); + VK_CHECK_RESULT(vkBindImageMemory(device, colorAttachment.image, colorAttachment.memory, 0)); + + VkImageViewCreateInfo colorImageView = vks::initializers::imageViewCreateInfo(); + colorImageView.viewType = VK_IMAGE_VIEW_TYPE_2D; + colorImageView.format = colorFormat; + colorImageView.subresourceRange = {}; + colorImageView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + colorImageView.subresourceRange.baseMipLevel = 0; + colorImageView.subresourceRange.levelCount = 1; + colorImageView.subresourceRange.baseArrayLayer = 0; + colorImageView.subresourceRange.layerCount = 1; + colorImageView.image = colorAttachment.image; + VK_CHECK_RESULT(vkCreateImageView(device, &colorImageView, nullptr, &colorAttachment.view)); + + // Depth stencil attachment + image.format = depthFormat; + image.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + + VK_CHECK_RESULT(vkCreateImage(device, &image, nullptr, &depthAttachment.image)); + vkGetImageMemoryRequirements(device, depthAttachment.image, &memReqs); + memAlloc.allocationSize = memReqs.size; + memAlloc.memoryTypeIndex = getMemoryTypeIndex(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + VK_CHECK_RESULT(vkAllocateMemory(device, &memAlloc, nullptr, &depthAttachment.memory)); + VK_CHECK_RESULT(vkBindImageMemory(device, depthAttachment.image, depthAttachment.memory, 0)); + + VkImageViewCreateInfo depthStencilView = vks::initializers::imageViewCreateInfo(); + depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; + depthStencilView.format = depthFormat; + depthStencilView.flags = 0; + depthStencilView.subresourceRange = {}; + depthStencilView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + depthStencilView.subresourceRange.baseMipLevel = 0; + depthStencilView.subresourceRange.levelCount = 1; + depthStencilView.subresourceRange.baseArrayLayer = 0; + depthStencilView.subresourceRange.layerCount = 1; + depthStencilView.image = depthAttachment.image; + VK_CHECK_RESULT(vkCreateImageView(device, &depthStencilView, nullptr, &depthAttachment.view)); + } + + /* + Create renderpass + */ + { + std::array<VkAttachmentDescription, 2> attchmentDescriptions = {}; + // Color attachment + attchmentDescriptions[0].format = colorFormat; + attchmentDescriptions[0].samples = VK_SAMPLE_COUNT_1_BIT; + attchmentDescriptions[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attchmentDescriptions[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attchmentDescriptions[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attchmentDescriptions[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attchmentDescriptions[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attchmentDescriptions[0].finalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + // Depth attachment + attchmentDescriptions[1].format = depthFormat; + attchmentDescriptions[1].samples = VK_SAMPLE_COUNT_1_BIT; + attchmentDescriptions[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attchmentDescriptions[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attchmentDescriptions[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attchmentDescriptions[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attchmentDescriptions[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attchmentDescriptions[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + VkAttachmentReference colorReference = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; + VkAttachmentReference depthReference = { 1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL }; + + VkSubpassDescription subpassDescription = {}; + subpassDescription.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpassDescription.colorAttachmentCount = 1; + subpassDescription.pColorAttachments = &colorReference; + subpassDescription.pDepthStencilAttachment = &depthReference; + + // Use subpass dependencies for layout transitions + std::array<VkSubpassDependency, 2> dependencies; + + dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL; + dependencies[0].dstSubpass = 0; + dependencies[0].srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependencies[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT; + dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; + + dependencies[1].srcSubpass = 0; + dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL; + dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependencies[1].dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + dependencies[1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; + dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; + + // Create the actual renderpass + VkRenderPassCreateInfo renderPassInfo = {}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + renderPassInfo.attachmentCount = static_cast<uint32_t>(attchmentDescriptions.size()); + renderPassInfo.pAttachments = attchmentDescriptions.data(); + renderPassInfo.subpassCount = 1; + renderPassInfo.pSubpasses = &subpassDescription; + renderPassInfo.dependencyCount = static_cast<uint32_t>(dependencies.size()); + renderPassInfo.pDependencies = dependencies.data(); + VK_CHECK_RESULT(vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass)); + + VkImageView attachments[2]; + attachments[0] = colorAttachment.view; + attachments[1] = depthAttachment.view; + + VkFramebufferCreateInfo framebufferCreateInfo = vks::initializers::framebufferCreateInfo(); + framebufferCreateInfo.renderPass = renderPass; + framebufferCreateInfo.attachmentCount = 2; + framebufferCreateInfo.pAttachments = attachments; + framebufferCreateInfo.width = width; + framebufferCreateInfo.height = height; + framebufferCreateInfo.layers = 1; + VK_CHECK_RESULT(vkCreateFramebuffer(device, &framebufferCreateInfo, nullptr, &framebuffer)); + } + + /* + Prepare graphics pipeline + */ + { + std::vector<VkDescriptorSetLayoutBinding> setLayoutBindings = {}; + VkDescriptorSetLayoutCreateInfo descriptorLayout = + vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); + VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout)); + + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = + vks::initializers::pipelineLayoutCreateInfo(nullptr, 0); + + // MVP via push constant block + VkPushConstantRange pushConstantRange = vks::initializers::pushConstantRange(VK_SHADER_STAGE_VERTEX_BIT, sizeof(glm::mat4), 0); + pipelineLayoutCreateInfo.pushConstantRangeCount = 1; + pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstantRange; + + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout)); + + VkPipelineCacheCreateInfo pipelineCacheCreateInfo = {}; + pipelineCacheCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; + VK_CHECK_RESULT(vkCreatePipelineCache(device, &pipelineCacheCreateInfo, nullptr, &pipelineCache)); + + // Create pipeline + VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = + vks::initializers::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0, VK_FALSE); + + VkPipelineRasterizationStateCreateInfo rasterizationState = + vks::initializers::pipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL, VK_CULL_MODE_BACK_BIT, VK_FRONT_FACE_CLOCKWISE); + + VkPipelineColorBlendAttachmentState blendAttachmentState = + vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE); + + VkPipelineColorBlendStateCreateInfo colorBlendState = + vks::initializers::pipelineColorBlendStateCreateInfo(1, &blendAttachmentState); + + VkPipelineDepthStencilStateCreateInfo depthStencilState = + vks::initializers::pipelineDepthStencilStateCreateInfo(VK_TRUE, VK_TRUE, VK_COMPARE_OP_LESS_OR_EQUAL); + + VkPipelineViewportStateCreateInfo viewportState = + vks::initializers::pipelineViewportStateCreateInfo(1, 1); + + VkPipelineMultisampleStateCreateInfo multisampleState = + vks::initializers::pipelineMultisampleStateCreateInfo(VK_SAMPLE_COUNT_1_BIT); + + std::vector<VkDynamicState> dynamicStateEnables = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR + }; + VkPipelineDynamicStateCreateInfo dynamicState = + vks::initializers::pipelineDynamicStateCreateInfo(dynamicStateEnables); + + VkGraphicsPipelineCreateInfo pipelineCreateInfo = + vks::initializers::pipelineCreateInfo(pipelineLayout, renderPass); + + std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages{}; + + pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState; + pipelineCreateInfo.pRasterizationState = &rasterizationState; + pipelineCreateInfo.pColorBlendState = &colorBlendState; + pipelineCreateInfo.pMultisampleState = &multisampleState; + pipelineCreateInfo.pViewportState = &viewportState; + pipelineCreateInfo.pDepthStencilState = &depthStencilState; + pipelineCreateInfo.pDynamicState = &dynamicState; + pipelineCreateInfo.stageCount = static_cast<uint32_t>(shaderStages.size()); + pipelineCreateInfo.pStages = shaderStages.data(); + + // Vertex bindings an attributes + // Binding description + std::vector<VkVertexInputBindingDescription> vertexInputBindings = { + vks::initializers::vertexInputBindingDescription(0, sizeof(Vertex), VK_VERTEX_INPUT_RATE_VERTEX), + }; + + // Attribute descriptions + std::vector<VkVertexInputAttributeDescription> vertexInputAttributes = { + vks::initializers::vertexInputAttributeDescription(0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0), // Position + vks::initializers::vertexInputAttributeDescription(0, 1, VK_FORMAT_R32G32B32_SFLOAT, sizeof(float) * 3), // Color + }; + + VkPipelineVertexInputStateCreateInfo vertexInputState = vks::initializers::pipelineVertexInputStateCreateInfo(); + vertexInputState.vertexBindingDescriptionCount = static_cast<uint32_t>(vertexInputBindings.size()); + vertexInputState.pVertexBindingDescriptions = vertexInputBindings.data(); + vertexInputState.vertexAttributeDescriptionCount = static_cast<uint32_t>(vertexInputAttributes.size()); + vertexInputState.pVertexAttributeDescriptions = vertexInputAttributes.data(); + + pipelineCreateInfo.pVertexInputState = &vertexInputState; + + shaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shaderStages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; + shaderStages[0].pName = "main"; + shaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; + shaderStages[1].pName = "main"; +#if 1 + const uint32_t triangle_vert[] = { + #include "triangle.vert.inc" + }; + const uint32_t triangle_frag[] = { + #include "triangle.frag.inc" + }; + shaderStages[0].module = vks::tools::loadShader(sizeof(triangle_vert), triangle_vert, device); + shaderStages[1].module = vks::tools::loadShader(sizeof(triangle_frag), triangle_frag, device); +#else + shaderStages[0].module = vks::tools::loadShader(ASSET_PATH "shaders/renderheadless/triangle.vert.spv", device); + shaderStages[1].module = vks::tools::loadShader(ASSET_PATH "shaders/renderheadless/triangle.frag.spv", device); +#endif + shaderModules = { shaderStages[0].module, shaderStages[1].module }; + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipeline)); + } + + /* + Command buffer creation + */ + { + VkCommandBufferAllocateInfo cmdBufAllocateInfo = + vks::initializers::commandBufferAllocateInfo(commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1); + VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, &commandBuffer)); + + VkCommandBufferBeginInfo cmdBufInfo = + vks::initializers::commandBufferBeginInfo(); + + VK_CHECK_RESULT(vkBeginCommandBuffer(commandBuffer, &cmdBufInfo)); + + vkCmdResetQueryPool(commandBuffer, query_pool, 0, 2); + + vkCmdWriteTimestamp(commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, query_pool, 0); + + VkClearValue clearValues[2]; + clearValues[0].color = { { 0.0f, 0.0f, 0.2f, 1.0f } }; + clearValues[1].depthStencil = { 1.0f, 0 }; + + VkRenderPassBeginInfo renderPassBeginInfo = {}; + renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + renderPassBeginInfo.renderArea.extent.width = width; + renderPassBeginInfo.renderArea.extent.height = height; + renderPassBeginInfo.clearValueCount = 2; + renderPassBeginInfo.pClearValues = clearValues; + renderPassBeginInfo.renderPass = renderPass; + renderPassBeginInfo.framebuffer = framebuffer; + + vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + + VkViewport viewport = {}; + viewport.height = (float)height; + viewport.width = (float)width; + viewport.minDepth = (float)0.0f; + viewport.maxDepth = (float)1.0f; + vkCmdSetViewport(commandBuffer, 0, 1, &viewport); + + // Update dynamic scissor state + VkRect2D scissor = {}; + scissor.extent.width = width; + scissor.extent.height = height; + vkCmdSetScissor(commandBuffer, 0, 1, &scissor); + + vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); + + // Render scene + VkDeviceSize offsets[1] = { 0 }; + vkCmdBindVertexBuffers(commandBuffer, 0, 1, &vertexBuffer, offsets); + vkCmdBindIndexBuffer(commandBuffer, indexBuffer, 0, VK_INDEX_TYPE_UINT32); + + std::srand(std::time(nullptr)); + std::vector<glm::vec3> pos(commandCount); + for (auto& v : pos) { + float x = ((float)rand() / RAND_MAX * 3.0) - 1.5f; // [-1.5, 1.5] + float y = ((float)rand() / RAND_MAX ) - 0.5f; // [-0.5, 0.5] + float z = ((float)rand() / RAND_MAX * 1.5) - 4.0f; // [-4.0, -2.5] + + v = glm::vec3(x, y, z); + } + + for (auto v : pos) { + glm::mat4 mvpMatrix = glm::perspective(glm::radians(60.0f), (float)width / (float)height, 0.1f, 256.0f) * glm::translate(glm::mat4(1.0f), v); + vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(mvpMatrix), &mvpMatrix); + + vkCmdDrawIndexed(commandBuffer, 3, 1, 0, 0, 0); + } + + vkCmdEndRenderPass(commandBuffer); + vkCmdWriteTimestamp(commandBuffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, query_pool, 1); + + VK_CHECK_RESULT(vkEndCommandBuffer(commandBuffer)); + } + } + + virtual VkFence submit() override { + VkSubmitInfo submitInfo = vks::initializers::submitInfo(); + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &commandBuffer; + VkFenceCreateInfo fenceInfo = vks::initializers::fenceCreateInfo(); + + VK_CHECK_RESULT(vkCreateFence(device, &fenceInfo, nullptr, &fence)); + VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, fence)); + + return fence; + + } + + virtual void queryTimestamp(uint64_t time_stamp[], int count) override { + VK_CHECK_RESULT(vkGetQueryPoolResults(device, query_pool, 0, count, + sizeof(uint64_t)*count, time_stamp, sizeof(uint64_t), VK_QUERY_RESULT_64_BIT)); + } + + virtual void waitIdle() override { + VK_CHECK_RESULT(vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX)); + vkDestroyFence(device, fence, nullptr); + + vkDeviceWaitIdle(device); + + /* + Copy framebuffer image to host visible image + */ + const char* imagedata; + { + // Create the linear tiled destination image to copy to and to read the memory from + VkImageCreateInfo imgCreateInfo(vks::initializers::imageCreateInfo()); + imgCreateInfo.imageType = VK_IMAGE_TYPE_2D; + imgCreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM; + imgCreateInfo.extent.width = width; + imgCreateInfo.extent.height = height; + imgCreateInfo.extent.depth = 1; + imgCreateInfo.arrayLayers = 1; + imgCreateInfo.mipLevels = 1; + imgCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imgCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; + imgCreateInfo.tiling = VK_IMAGE_TILING_LINEAR; + imgCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT; + // Create the image + VkImage dstImage; + VK_CHECK_RESULT(vkCreateImage(device, &imgCreateInfo, nullptr, &dstImage)); + // Create memory to back up the image + VkMemoryRequirements memRequirements; + VkMemoryAllocateInfo memAllocInfo(vks::initializers::memoryAllocateInfo()); + VkDeviceMemory dstImageMemory; + vkGetImageMemoryRequirements(device, dstImage, &memRequirements); + memAllocInfo.allocationSize = memRequirements.size; + // Memory must be host visible to copy from + memAllocInfo.memoryTypeIndex = getMemoryTypeIndex(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &dstImageMemory)); + VK_CHECK_RESULT(vkBindImageMemory(device, dstImage, dstImageMemory, 0)); + + // Do the actual blit from the offscreen image to our host visible destination image + VkCommandBufferAllocateInfo cmdBufAllocateInfo = vks::initializers::commandBufferAllocateInfo(commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1); + VkCommandBuffer copyCmd; + VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, ©Cmd)); + VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo(); + VK_CHECK_RESULT(vkBeginCommandBuffer(copyCmd, &cmdBufInfo)); + + // Transition destination image to transfer destination layout + vks::tools::insertImageMemoryBarrier( + copyCmd, + dstImage, + 0, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }); + + // colorAttachment.image is already in VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, and does not need to be transitioned + + VkImageCopy imageCopyRegion{}; + imageCopyRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + imageCopyRegion.srcSubresource.layerCount = 1; + imageCopyRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + imageCopyRegion.dstSubresource.layerCount = 1; + imageCopyRegion.extent.width = width; + imageCopyRegion.extent.height = height; + imageCopyRegion.extent.depth = 1; + + vkCmdCopyImage( + copyCmd, + colorAttachment.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + dstImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, + &imageCopyRegion); + + // Transition destination image to general layout, which is the required layout for mapping the image memory later on + vks::tools::insertImageMemoryBarrier( + copyCmd, + dstImage, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_ACCESS_MEMORY_READ_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_GENERAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }); + + VK_CHECK_RESULT(vkEndCommandBuffer(copyCmd)); + + submitWork(copyCmd, queue); + + // Get layout of the image (including row pitch) + VkImageSubresource subResource{}; + subResource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + VkSubresourceLayout subResourceLayout; + + vkGetImageSubresourceLayout(device, dstImage, &subResource, &subResourceLayout); + + // Map image memory so we can start copying from it + vkMapMemory(device, dstImageMemory, 0, VK_WHOLE_SIZE, 0, (void**)&imagedata); + imagedata += subResourceLayout.offset; + + /* + Save host visible framebuffer image to disk (ppm format) + */ + +#if defined (VK_USE_PLATFORM_ANDROID_KHR) + const char* filename = strcat(getenv("EXTERNAL_STORAGE"), "/headless.ppm"); +#else + const char* filename = "headless.ppm"; +#endif + std::ofstream file(filename, std::ios::out | std::ios::binary); + + // ppm header + file << "P6\n" << width << "\n" << height << "\n" << 255 << "\n"; + + // If source is BGR (destination is always RGB) and we can't use blit (which does automatic conversion), we'll have to manually swizzle color components + // Check if source is BGR and needs swizzle + std::vector<VkFormat> formatsBGR = { VK_FORMAT_B8G8R8A8_SRGB, VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_B8G8R8A8_SNORM }; + const bool colorSwizzle = (std::find(formatsBGR.begin(), formatsBGR.end(), VK_FORMAT_R8G8B8A8_UNORM) != formatsBGR.end()); + + // ppm binary pixel data + for (int32_t y = 0; y < height; y++) { + unsigned int *row = (unsigned int*)imagedata; + for (int32_t x = 0; x < width; x++) { + if (colorSwizzle) { + file.write((char*)row + 2, 1); + file.write((char*)row + 1, 1); + file.write((char*)row, 1); + } + else { + file.write((char*)row, 3); + } + row++; + } + imagedata += subResourceLayout.rowPitch; + } + file.close(); + + LOG("Framebuffer image saved to %s\n", filename); + + // Clean up resources + vkUnmapMemory(device, dstImageMemory); + vkFreeMemory(device, dstImageMemory, nullptr); + vkDestroyImage(device, dstImage, nullptr); + } + + vkQueueWaitIdle(queue); + } + + ~GraphicsWork() + { + vkDestroyBuffer(device, vertexBuffer, nullptr); + vkFreeMemory(device, vertexMemory, nullptr); + vkDestroyBuffer(device, indexBuffer, nullptr); + vkFreeMemory(device, indexMemory, nullptr); + vkDestroyImageView(device, colorAttachment.view, nullptr); + vkDestroyImage(device, colorAttachment.image, nullptr); + vkFreeMemory(device, colorAttachment.memory, nullptr); + vkDestroyImageView(device, depthAttachment.view, nullptr); + vkDestroyImage(device, depthAttachment.image, nullptr); + vkFreeMemory(device, depthAttachment.memory, nullptr); + vkDestroyRenderPass(device, renderPass, nullptr); + vkDestroyFramebuffer(device, framebuffer, nullptr); + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); + vkDestroyPipeline(device, pipeline, nullptr); + vkDestroyPipelineCache(device, pipelineCache, nullptr); + vkDestroyCommandPool(device, commandPool, nullptr); + for (auto shadermodule : shaderModules) { + vkDestroyShaderModule(device, shadermodule, nullptr); + } +#if DEBUG + if (debugReportCallback) { + PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallback = reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>(vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT")); + assert(vkDestroyDebugReportCallback); + vkDestroyDebugReportCallback(instance, debugReportCallback, nullptr); + } +#endif +#if defined(VK_USE_PLATFORM_ANDROID_KHR) + vks::android::freeVulkanLibrary(); +#endif + } +}; + diff --git a/vkpreemption/headless.comp b/vkpreemption/headless.comp new file mode 100644 index 00000000..fb72c429 --- /dev/null +++ b/vkpreemption/headless.comp @@ -0,0 +1,34 @@ +#version 450 + +layout(binding = 0) buffer Pos { + uint values[ ]; +}; + +layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in; + +layout (constant_id = 0) const uint BUFFER_ELEMENTS = 32; + +uint fibonacci(uint n) { + if(n <= 1){ + return n; + } + uint curr = 1; + uint prev = 1; + for(uint i = 2; i < n; ++i) { + uint temp = curr; + curr += prev; + prev = temp; + } + return curr; +} + +void main() +{ + uint index = gl_GlobalInvocationID.x; + if (index >= BUFFER_ELEMENTS) + return; + //values[index] = fibonacci(values[index]); + //values[index] = fibonacci(index); + values[index] = values[index]+1; +} + diff --git a/vkpreemption/headless.comp.inc b/vkpreemption/headless.comp.inc new file mode 100644 index 00000000..b41717e9 --- /dev/null +++ b/vkpreemption/headless.comp.inc @@ -0,0 +1,33 @@ + // 8.13.3727 + 0x07230203,0x00010000,0x00080008,0x00000026,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x0006000f,0x00000005,0x00000004,0x6e69616d,0x00000000,0x0000000b,0x00060010,0x00000004, + 0x00000011,0x00000001,0x00000001,0x00000001,0x00030003,0x00000002,0x000001c2,0x00040005, + 0x00000004,0x6e69616d,0x00000000,0x00040005,0x00000008,0x65646e69,0x00000078,0x00080005, + 0x0000000b,0x475f6c67,0x61626f6c,0x766e496c,0x7461636f,0x496e6f69,0x00000044,0x00060005, + 0x00000011,0x46465542,0x455f5245,0x454d454c,0x0053544e,0x00030005,0x00000018,0x00736f50, + 0x00050006,0x00000018,0x00000000,0x756c6176,0x00007365,0x00030005,0x0000001a,0x00000000, + 0x00040047,0x0000000b,0x0000000b,0x0000001c,0x00040047,0x00000011,0x00000001,0x00000000, + 0x00040047,0x00000017,0x00000006,0x00000004,0x00050048,0x00000018,0x00000000,0x00000023, + 0x00000000,0x00030047,0x00000018,0x00000003,0x00040047,0x0000001a,0x00000022,0x00000000, + 0x00040047,0x0000001a,0x00000021,0x00000000,0x00040047,0x00000025,0x0000000b,0x00000019, + 0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00040015,0x00000006,0x00000020, + 0x00000000,0x00040020,0x00000007,0x00000007,0x00000006,0x00040017,0x00000009,0x00000006, + 0x00000003,0x00040020,0x0000000a,0x00000001,0x00000009,0x0004003b,0x0000000a,0x0000000b, + 0x00000001,0x0004002b,0x00000006,0x0000000c,0x00000000,0x00040020,0x0000000d,0x00000001, + 0x00000006,0x00040032,0x00000006,0x00000011,0x00000020,0x00020014,0x00000012,0x0003001d, + 0x00000017,0x00000006,0x0003001e,0x00000018,0x00000017,0x00040020,0x00000019,0x00000002, + 0x00000018,0x0004003b,0x00000019,0x0000001a,0x00000002,0x00040015,0x0000001b,0x00000020, + 0x00000001,0x0004002b,0x0000001b,0x0000001c,0x00000000,0x00040020,0x0000001f,0x00000002, + 0x00000006,0x0004002b,0x00000006,0x00000022,0x00000001,0x0006002c,0x00000009,0x00000025, + 0x00000022,0x00000022,0x00000022,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003, + 0x000200f8,0x00000005,0x0004003b,0x00000007,0x00000008,0x00000007,0x00050041,0x0000000d, + 0x0000000e,0x0000000b,0x0000000c,0x0004003d,0x00000006,0x0000000f,0x0000000e,0x0003003e, + 0x00000008,0x0000000f,0x0004003d,0x00000006,0x00000010,0x00000008,0x000500ae,0x00000012, + 0x00000013,0x00000010,0x00000011,0x000300f7,0x00000015,0x00000000,0x000400fa,0x00000013, + 0x00000014,0x00000015,0x000200f8,0x00000014,0x000100fd,0x000200f8,0x00000015,0x0004003d, + 0x00000006,0x0000001d,0x00000008,0x0004003d,0x00000006,0x0000001e,0x00000008,0x00060041, + 0x0000001f,0x00000020,0x0000001a,0x0000001c,0x0000001e,0x0004003d,0x00000006,0x00000021, + 0x00000020,0x00050080,0x00000006,0x00000023,0x00000021,0x00000022,0x00060041,0x0000001f, + 0x00000024,0x0000001a,0x0000001c,0x0000001d,0x0003003e,0x00000024,0x00000023,0x000100fd, + 0x00010038 diff --git a/vkpreemption/main.cpp b/vkpreemption/main.cpp new file mode 100644 index 00000000..ded4bfa9 --- /dev/null +++ b/vkpreemption/main.cpp @@ -0,0 +1,385 @@ +/* + * * + * * Copyright (C) 2020 Samsung Electronics + * * + * */ + +#include "base.hpp" +#include "computework.hpp" +#include "graphicwork.hpp" + +#include <sys/stat.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/un.h> + +#include <unordered_map> + +#include <regex> +#include <chrono> +#include <numeric> +#include <algorithm> +#include <thread> + +#include<stdio.h> +#include<stdlib.h> +#include<unistd.h> +#include<string.h> +#include<sys/types.h> +#include<sys/msg.h> +#include<sys/ipc.h> +#include<errno.h> + +#define RUN_TIMES 5 +class Request { + + VkQueueGlobalPriorityEXT str2priority(const std::string& str) { + static const std::unordered_map<std::string, VkQueueGlobalPriorityEXT> map = { + {"low", VK_QUEUE_GLOBAL_PRIORITY_LOW_EXT}, + {"medium", VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT}, + {"high", VK_QUEUE_GLOBAL_PRIORITY_HIGH_EXT}, + {"realtime", VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT} + }; + + auto it = map.find(str); + if (it == map.end()) { + LOG("%s is not a valid priority. Use low, medium or high\n", str.c_str()); + return VK_QUEUE_GLOBAL_PRIORITY_MAX_ENUM_EXT; + } else { + return it->second; + } + } + + +public: + enum class Type { + Graphics, + Compute + }; + + unsigned m_commandCount; + VkQueueGlobalPriorityEXT m_priority; + std::chrono::microseconds m_delay = std::chrono::microseconds::zero(); + Type m_type; + Workload* m_workload = nullptr; + + Request(char* str) + { + const std::regex regex_graphic("gfx=draws:([0-9]+),priority:(low|medium|high),delay:([0-9]+)"); + const std::regex regex_compute("compute=dispatch:([0-9]+),priority:(low|medium|high|realtime),delay:([0-9]+)"); + + std::cmatch m; + + if (std::regex_match(str, m, regex_graphic)) { + m_type = Type::Graphics; + m_commandCount = stoi(m[1]); + m_priority = str2priority(m[2]); + m_delay = std::chrono::microseconds(std::stoi(m[3])); + } else if (std::regex_match(str, m, regex_compute)) { + m_type = Type::Compute; + m_commandCount = stoi(m[1]); + m_priority = str2priority(m[2]); + m_delay = std::chrono::microseconds(std::stoi(m[3])); + } else { + LOG("Could not parse \'%s\'", str); + exit(-1); + } + LOG("Request : commands %d, priority %d, delay %lld\n", m_commandCount, m_priority, m_delay.count()); + } + + ~Request() { + if (m_workload != nullptr) { + delete(m_workload); + } + } + + VkQueueFlagBits vkQueueFlag() { + switch(m_type) { + case Type::Graphics: return VK_QUEUE_GRAPHICS_BIT; + case Type::Compute : return VK_QUEUE_COMPUTE_BIT; + } + return VK_QUEUE_FLAG_BITS_MAX_ENUM; + } + + Workload* createWorkload(Base& base, QueueInfo queue, unsigned commandCount) { + switch(m_type) { + case Type::Graphics: return new GraphicsWork(base, queue, commandCount); + case Type::Compute : return new ComputeWork(base, queue, commandCount); + } + return nullptr; + } + + void init(Base& base) { + auto queue = base.GetQueueInfo(vkQueueFlag(), m_priority); + m_workload = createWorkload(base, queue, m_commandCount); + } + + void queryTimestamp(uint64_t time_stamp[], int count) { + m_workload->queryTimestamp(time_stamp, count); + } + + void waitIdle() { + m_workload->waitIdle(); + } + + VkFence submit(Base& base) { + return m_workload->submit(); + } + + static std::vector<Request> rearrangeDelays(std::vector<Request> requests) { + // Sort the vector in ascending order of delays + std::sort(requests.begin(), requests.end(), [](Request a, Request b) { return a.m_delay < b.m_delay; }); + + // The delays do not compound, so subtract the previous one from the current + auto previous = std::chrono::microseconds::zero(); + std::cout << "Delays : " << std::endl; + for (auto& request : requests) { + std::cout << request.m_delay.count(); + request.m_delay -= previous; + std::cout << " -> " << request.m_delay.count() << std::endl; + previous = request.m_delay; + } + + return requests; + } +}; + +#define SOCKET_PATH "/tmp/mysocket" +#define IPC_KEY 0x12345678 +#define TYPE_S 1 +#define TYPE_C 2 + +struct msgbuff{ + long mtype; + char mtext[512]; + uint64_t time_stamp[RUN_TIMES * 2]; +}; + +struct timespec ts; +struct timespec ts1; +struct timespec ts2; +int clifd = -1; + +int server() +{ + int servfd; + int ret; + + servfd = socket(AF_LOCAL,SOCK_STREAM,0); + if(-1 == servfd) + { + perror("Can not create socket"); + return -1; + } + + struct sockaddr_un servaddr; + bzero(&servaddr, sizeof(servaddr)); + strcpy(servaddr.sun_path+1, SOCKET_PATH); + servaddr.sun_family = AF_LOCAL; + socklen_t addrlen = 1 + strlen(SOCKET_PATH) + sizeof(servaddr.sun_family); + + ret = bind(servfd, (struct sockaddr *)&servaddr, addrlen); + if(-1 == ret) + { + perror("bind failed"); + return -1; + } + + ret = listen(servfd, 100); + if(-1 == ret) + { + perror("listen failed"); + return -1; + } + + pthread_t tid; + struct sockaddr_un cliaddr; + + printf("Wait for client connect \n"); + memset(&cliaddr,0,sizeof(cliaddr)); + clifd = accept(servfd,(struct sockaddr *)&cliaddr,&addrlen); + if(clifd == -1) + { + printf("accept connect failed\n"); + return -1; + } + printf("Accept connect success\n"); + + char getData[100]; + bzero(&getData,sizeof(getData)); + ret = read(clifd,&getData,sizeof(getData)); + if(ret > 0) + { + printf("Receive message: %s", getData); + } + + return 0; +} + +int client() +{ + int ret; + + clifd = socket(AF_LOCAL, SOCK_STREAM, 0); + if(-1 == clifd) + { + perror("socket create failed\n"); + return -1; + } + + struct sockaddr_un cileddr; + bzero(&cileddr, sizeof(cileddr)); + strcpy(cileddr.sun_path + 1, SOCKET_PATH); + cileddr.sun_family = AF_LOCAL; + socklen_t addrlen = sizeof(cileddr.sun_family) + strlen(SOCKET_PATH) + 1; + + ret = connect(clifd, (struct sockaddr *)&cileddr, addrlen); + if(ret == -1) { + perror("Connect fail\n"); + return -1; + } + const char *s = std::string("hello\n").c_str(); + send(clifd,s,strlen(s),0); + printf("Client: send hello to server\n"); + return 0; +} + +uint64_t toTime(timespec ts){ + return ts.tv_sec * 1000000000 + ts.tv_nsec; +} + +int gfx(std::vector<Request> &requests, bool isServer) { + std::vector<VkQueueGlobalPriorityEXT> graphic_priorities; + std::vector<VkQueueGlobalPriorityEXT> compute_priorities; + Request& request = requests.back(); + + switch(request.m_type) { + case Request::Type::Graphics: graphic_priorities.push_back(request.m_priority); break; + case Request::Type::Compute : compute_priorities.push_back(request.m_priority); break; + } + + Base base(graphic_priorities, compute_priorities); + + printf("Waiting %lld us ... \n", request.m_delay.count()); + fflush(stdout); + std::this_thread::sleep_for(request.m_delay); + + int msgid = -1; + + int i, j; + + struct msgbuff buf; + memset(&buf, 0x00, sizeof(struct msgbuff)); + + + if (isServer) + { + msgid = server(); + if(msgid < 0) + { + perror("Server: msgget error"); + exit(-1); + } + } + else { + msgid = client(); + if(msgid < 0) + { + perror("Client: error , please start server first\n"); + //exit(-1); + } + } + + clock_gettime(CLOCK_MONOTONIC, &ts); + + if (isServer) + { + printf("Server: start submission time: <%ld.%ld>\n",ts.tv_sec,ts.tv_nsec); + } + else + { + printf("Client: start submission time: <%ld.%ld>\n",ts.tv_sec,ts.tv_nsec); + } + + + uint64_t time_stamp[RUN_TIMES * 2]; + + + std::vector<VkFence> fences; + + for (i = 0; i < RUN_TIMES; i++) { + + fences.clear(); + clock_gettime(CLOCK_MONOTONIC, &ts1); + + printf("pid %d running: %d \n", getpid(), i); + for (j = 0; j < 2; j++) { + request.init(base); + fflush(stdout); + fences.push_back(request.submit(base)); + } + + VK_CHECK_RESULT(vkWaitForFences(base.GetDevice(), fences.size(), fences.data(), VK_TRUE, UINT64_MAX)); + clock_gettime(CLOCK_MONOTONIC, &ts2); + time_stamp[i * 2] = toTime(ts1); + time_stamp[i * 2 + 1] = toTime(ts2); + + } + + + if (isServer) + { + int ret; + memset(&buf, 0x00, sizeof(struct msgbuff)); + ret = read(clifd, &buf, sizeof(buf)); + if(ret > 0) + { + printf("Receive message: client %s\n", buf.mtext); + } + + for (i = 0; i < RUN_TIMES; i++) { + if (request.m_priority >= VK_QUEUE_GLOBAL_PRIORITY_HIGH_EXT + && buf.time_stamp[i * 2] < time_stamp[i * 2] + && buf.time_stamp[i * 2 + 1] > time_stamp[i * 2 + 1]) { + printf("success on(%d) high:%ld low: %ld\n",i, time_stamp[i * 2 + 1] - time_stamp[i * 2], + (buf.time_stamp[i * 2 + 1] - buf.time_stamp[i * 2])); + break; + } + } + if (i == RUN_TIMES) { + printf("****************************FAIL****************************\n"); + } + } + else + { + int ret; + memset(&buf, 0x00, sizeof(struct msgbuff)); + memcpy(buf.time_stamp, time_stamp, sizeof(time_stamp)); + strcpy(buf.mtext, "gpu timestamp"); + send(clifd, &buf, sizeof(buf), 0); + for (i = 0; i < RUN_TIMES; i++) { + printf("Client: gpu timestamp %lu %lu total:%ld\n", buf.time_stamp[i * 2], + buf.time_stamp[i * 2 + 1], (time_stamp[i * 2 + 1] - time_stamp[i * 2])); + } + } + + request.waitIdle(); + + return 0; +} + +int main(int argc, char *argv[]) { + std::vector<Request> requests; + // argv[1] must be used to specify client/server/ace mode + if (strcmp(argv[1], "s") && strcmp(argv[1], "c")) + { + fprintf(stderr, + "The first parameter must be specifying if it's client (c) or server (s) mode?\n"); + exit(-1); + } + + requests.emplace_back(argv[2]); + gfx(requests, !strcmp(argv[1], "s")); + + return 0; +} diff --git a/vkpreemption/triangle.frag b/vkpreemption/triangle.frag new file mode 100644 index 00000000..92e74502 --- /dev/null +++ b/vkpreemption/triangle.frag @@ -0,0 +1,10 @@ +#version 450 + +layout (location = 0) in vec3 inColor; + +layout (location = 0) out vec4 outFragColor; + +void main() +{ + outFragColor = vec4(inColor, 1.0); +} \ No newline at end of file diff --git a/vkpreemption/triangle.frag.glsl b/vkpreemption/triangle.frag.glsl new file mode 100644 index 00000000..92e74502 --- /dev/null +++ b/vkpreemption/triangle.frag.glsl @@ -0,0 +1,10 @@ +#version 450 + +layout (location = 0) in vec3 inColor; + +layout (location = 0) out vec4 outFragColor; + +void main() +{ + outFragColor = vec4(inColor, 1.0); +} \ No newline at end of file diff --git a/vkpreemption/triangle.frag.inc b/vkpreemption/triangle.frag.inc new file mode 100644 index 00000000..b382d48a --- /dev/null +++ b/vkpreemption/triangle.frag.inc @@ -0,0 +1,17 @@ + // 8.13.3727 + 0x07230203,0x00010000,0x00080008,0x00000013,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x0007000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x00000009,0x0000000c,0x00030010, + 0x00000004,0x00000007,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d, + 0x00000000,0x00060005,0x00000009,0x4674756f,0x43676172,0x726f6c6f,0x00000000,0x00040005, + 0x0000000c,0x6f436e69,0x00726f6c,0x00040047,0x00000009,0x0000001e,0x00000000,0x00040047, + 0x0000000c,0x0000001e,0x00000000,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002, + 0x00030016,0x00000006,0x00000020,0x00040017,0x00000007,0x00000006,0x00000004,0x00040020, + 0x00000008,0x00000003,0x00000007,0x0004003b,0x00000008,0x00000009,0x00000003,0x00040017, + 0x0000000a,0x00000006,0x00000003,0x00040020,0x0000000b,0x00000001,0x0000000a,0x0004003b, + 0x0000000b,0x0000000c,0x00000001,0x0004002b,0x00000006,0x0000000e,0x3f800000,0x00050036, + 0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003d,0x0000000a, + 0x0000000d,0x0000000c,0x00050051,0x00000006,0x0000000f,0x0000000d,0x00000000,0x00050051, + 0x00000006,0x00000010,0x0000000d,0x00000001,0x00050051,0x00000006,0x00000011,0x0000000d, + 0x00000002,0x00070050,0x00000007,0x00000012,0x0000000f,0x00000010,0x00000011,0x0000000e, + 0x0003003e,0x00000009,0x00000012,0x000100fd,0x00010038 diff --git a/vkpreemption/triangle.vert b/vkpreemption/triangle.vert new file mode 100644 index 00000000..b74ed3ec --- /dev/null +++ b/vkpreemption/triangle.vert @@ -0,0 +1,20 @@ +#version 450 + +layout (location = 0) in vec3 inPos; +layout (location = 1) in vec3 inColor; + +layout (location = 0) out vec3 outColor; + +out gl_PerVertex { + vec4 gl_Position; +}; + +layout(push_constant) uniform PushConsts { + mat4 mvp; +} pushConsts; + +void main() +{ + outColor = inColor; + gl_Position = pushConsts.mvp * vec4(inPos.xyz, 1.0); +} diff --git a/vkpreemption/triangle.vert.glsl b/vkpreemption/triangle.vert.glsl new file mode 100644 index 00000000..b74ed3ec --- /dev/null +++ b/vkpreemption/triangle.vert.glsl @@ -0,0 +1,20 @@ +#version 450 + +layout (location = 0) in vec3 inPos; +layout (location = 1) in vec3 inColor; + +layout (location = 0) out vec3 outColor; + +out gl_PerVertex { + vec4 gl_Position; +}; + +layout(push_constant) uniform PushConsts { + mat4 mvp; +} pushConsts; + +void main() +{ + outColor = inColor; + gl_Position = pushConsts.mvp * vec4(inPos.xyz, 1.0); +} diff --git a/vkpreemption/triangle.vert.inc b/vkpreemption/triangle.vert.inc new file mode 100644 index 00000000..91d00ba5 --- /dev/null +++ b/vkpreemption/triangle.vert.inc @@ -0,0 +1,34 @@ + // 8.13.3727 + 0x07230203,0x00010000,0x00080008,0x00000024,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x0009000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x00000009,0x0000000b,0x00000010, + 0x0000001a,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d,0x00000000, + 0x00050005,0x00000009,0x4374756f,0x726f6c6f,0x00000000,0x00040005,0x0000000b,0x6f436e69, + 0x00726f6c,0x00060005,0x0000000e,0x505f6c67,0x65567265,0x78657472,0x00000000,0x00060006, + 0x0000000e,0x00000000,0x505f6c67,0x7469736f,0x006e6f69,0x00030005,0x00000010,0x00000000, + 0x00050005,0x00000014,0x68737550,0x736e6f43,0x00007374,0x00040006,0x00000014,0x00000000, + 0x0070766d,0x00050005,0x00000016,0x68737570,0x736e6f43,0x00007374,0x00040005,0x0000001a, + 0x6f506e69,0x00000073,0x00040047,0x00000009,0x0000001e,0x00000000,0x00040047,0x0000000b, + 0x0000001e,0x00000001,0x00050048,0x0000000e,0x00000000,0x0000000b,0x00000000,0x00030047, + 0x0000000e,0x00000002,0x00040048,0x00000014,0x00000000,0x00000005,0x00050048,0x00000014, + 0x00000000,0x00000023,0x00000000,0x00050048,0x00000014,0x00000000,0x00000007,0x00000010, + 0x00030047,0x00000014,0x00000002,0x00040047,0x0000001a,0x0000001e,0x00000000,0x00020013, + 0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,0x00000006,0x00000020,0x00040017, + 0x00000007,0x00000006,0x00000003,0x00040020,0x00000008,0x00000003,0x00000007,0x0004003b, + 0x00000008,0x00000009,0x00000003,0x00040020,0x0000000a,0x00000001,0x00000007,0x0004003b, + 0x0000000a,0x0000000b,0x00000001,0x00040017,0x0000000d,0x00000006,0x00000004,0x0003001e, + 0x0000000e,0x0000000d,0x00040020,0x0000000f,0x00000003,0x0000000e,0x0004003b,0x0000000f, + 0x00000010,0x00000003,0x00040015,0x00000011,0x00000020,0x00000001,0x0004002b,0x00000011, + 0x00000012,0x00000000,0x00040018,0x00000013,0x0000000d,0x00000004,0x0003001e,0x00000014, + 0x00000013,0x00040020,0x00000015,0x00000009,0x00000014,0x0004003b,0x00000015,0x00000016, + 0x00000009,0x00040020,0x00000017,0x00000009,0x00000013,0x0004003b,0x0000000a,0x0000001a, + 0x00000001,0x0004002b,0x00000006,0x0000001c,0x3f800000,0x00040020,0x00000022,0x00000003, + 0x0000000d,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005, + 0x0004003d,0x00000007,0x0000000c,0x0000000b,0x0003003e,0x00000009,0x0000000c,0x00050041, + 0x00000017,0x00000018,0x00000016,0x00000012,0x0004003d,0x00000013,0x00000019,0x00000018, + 0x0004003d,0x00000007,0x0000001b,0x0000001a,0x00050051,0x00000006,0x0000001d,0x0000001b, + 0x00000000,0x00050051,0x00000006,0x0000001e,0x0000001b,0x00000001,0x00050051,0x00000006, + 0x0000001f,0x0000001b,0x00000002,0x00070050,0x0000000d,0x00000020,0x0000001d,0x0000001e, + 0x0000001f,0x0000001c,0x00050091,0x0000000d,0x00000021,0x00000019,0x00000020,0x00050041, + 0x00000022,0x00000023,0x00000010,0x00000012,0x0003003e,0x00000023,0x00000021,0x000100fd, + 0x00010038 diff --git a/vkpreemption/vk_amd_dispatch_tunnel.h b/vkpreemption/vk_amd_dispatch_tunnel.h new file mode 100644 index 00000000..4246d1ad --- /dev/null +++ b/vkpreemption/vk_amd_dispatch_tunnel.h @@ -0,0 +1,34 @@ +/* + ****************************************************************************** + * + * Trade secret of Advanced Micro Devices, Inc. + * Copyright (c) 2014-2019, Advanced Micro Devices, Inc., (unpublished) + * + * All rights reserved. This notice is intended as a precaution against + * inadvertent publication and does not imply + * publication or any waiver of confidentiality. The year included in the + * foregoing notice is the year of creation of the work. + * + *****************************************************************************/ +#ifndef VK_AMD_DISPATCH_TUNNEL_H_ +#define VK_AMD_DISPATCH_TUNNEL_H_ + +#include "vk_internal_ext_helper.h" + +#define VK_AMD_DISPATCH_TUNNEL 1 +#define VK_AMD_DISPATCH_TUNNEL_SPEC_VERSION 1 +#define VK_AMD_DISPATCH_TUNNEL_EXTENSION_NAME "VK_AMD_dispatch_tunnel" +#define VK_AMD_DISPATCH_TUNNEL_EXTENSION_NUMBER 318 + +#define VK_AMD_DISPATCH_TUNNEL_ENUM(type, offset) \ + VK_EXTENSION_ENUM(VK_AMD_DISPATCH_TUNNEL_EXTENSION_NUMBER, type, offset) + +typedef struct VkDispatchTunnelInfoEXT { + VkStructureType sType; + const void *pNext; + bool dispatchTunneling; +} VkDispatchTunnelInfoEXT; + +#define VK_STRUCTURE_TYPE_DISPATCH_TUNNEL_INFO_AMD \ + VK_AMD_DISPATCH_TUNNEL_ENUM(VkStructureType, 0) +#endif /* VK_AMD_DISPATCH_TUNNEL_H_ */ diff --git a/vkpreemption/vk_internal_ext_helper.h b/vkpreemption/vk_internal_ext_helper.h new file mode 100644 index 00000000..7f4bb3d2 --- /dev/null +++ b/vkpreemption/vk_internal_ext_helper.h @@ -0,0 +1,33 @@ +/* + ****************************************************************************** + * + * Trade secret of Advanced Micro Devices, Inc. + * Copyright (c) 2014-2015, Advanced Micro Devices, Inc., (unpublished) + * + * All rights reserved. This notice is intended as a precaution against + * inadvertent publication and does not imply publication or any waiver + * of confidentiality. The year included in the foregoing notice is the + * year of creation of the work. + * + ****************************************************************************** +/** + ****************************************************************************** + * @file vk_internal_ext_helper.h + * @brief Helper header for unpublished extensions. + ****************************************************************************** + */ + +#ifndef VK_INTERNAL_EXT_HELPER_H_ +#define VK_INTERNAL_EXT_HELPER_H_ + +#define VK_EXTENSION_ENUM_BASE_VALUE 1000000000ull +#define VK_EXTENSION_ENUM_RANGE_SIZE 1000ull + +#define VK_EXTENSION_ENUM(extnr, type, offset) \ + ((type)(VK_EXTENSION_ENUM_BASE_VALUE + (((extnr)-1) * \ + VK_EXTENSION_ENUM_RANGE_SIZE) + (offset))) + +#define VK_EXTENSION_BIT(type, bit) \ + ((type)(1 << (bit))) + +#endif /* VK_INTERNAL_EXT_HELPER_H_ */ -- 2.25.1