[PATCH] Add vkpreemption for gfx9 mcbp
jiadong.zhu at amd.com
jiadong.zhu at amd.com
Wed Nov 30 07:26:44 UTC 2022
From: jiadozhu <jiadong.zhu at amd.com>
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 at amd.com>
---
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
More information about the amd-gfx
mailing list