| /*------------------------------------------------------------------------ |
| * Vulkan Conformance Tests |
| * ------------------------ |
| * |
| * Copyright (c) 2022 The Khronos Group Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| *//*! |
| * \file vktGlobalPriorityQueueTests.cpp |
| * \brief Global Priority Queue Tests |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "vktGlobalPriorityQueueTests.hpp" |
| #include "vktGlobalPriorityQueueUtils.hpp" |
| |
| #include "vkBarrierUtil.hpp" |
| #include "vkQueryUtil.hpp" |
| #include "vkBuilderUtil.hpp" |
| #include "vkCmdUtil.hpp" |
| #include "vkImageUtil.hpp" |
| #include "../image/vktImageTestsUtil.hpp" |
| #include "vkTypeUtil.hpp" |
| #include "vkObjUtil.hpp" |
| #include "vkStrUtil.hpp" |
| #include "vkRefUtil.hpp" |
| |
| #include "vktTestGroupUtil.hpp" |
| #include "vktTestCase.hpp" |
| |
| #include "deDefs.h" |
| #include "deMath.h" |
| #include "deRandom.h" |
| #include "deRandom.hpp" |
| #include "deSharedPtr.hpp" |
| #include "deString.h" |
| #include "deMemory.h" |
| |
| #include "tcuStringTemplate.hpp" |
| |
| #include <string> |
| #include <sstream> |
| #include <map> |
| |
| using namespace vk; |
| |
| namespace vkt |
| { |
| namespace synchronization |
| { |
| namespace |
| { |
| |
| enum class SyncType |
| { |
| None, |
| Semaphore |
| }; |
| |
| struct TestConfig |
| { |
| VkQueueFlagBits transitionFrom; |
| VkQueueFlagBits transitionTo; |
| VkQueueGlobalPriorityKHR priorityFrom; |
| VkQueueGlobalPriorityKHR priorityTo; |
| bool enableProtected; |
| bool enableSparseBinding; |
| SyncType syncType; |
| deUint32 width; |
| deUint32 height; |
| VkFormat format; |
| bool selectFormat (const InstanceInterface& vk, VkPhysicalDevice dev, std::initializer_list<VkFormat> formats); |
| }; |
| |
| bool TestConfig::selectFormat (const InstanceInterface& vk, VkPhysicalDevice dev, std::initializer_list<VkFormat> formats) |
| { |
| auto doesFormatMatch = [](const VkFormat fmt) -> bool |
| { |
| const auto tcuFmt = mapVkFormat(fmt); |
| return tcuFmt.order == tcu::TextureFormat::ChannelOrder::R; |
| }; |
| VkFormatProperties2 props{}; |
| const VkFormatFeatureFlags flags = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT |
| | VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT; |
| for (auto i = formats.begin(); i != formats.end(); ++i) |
| { |
| props.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2; |
| props.pNext = nullptr; |
| props.formatProperties = {}; |
| const VkFormat fmt = *i; |
| vk.getPhysicalDeviceFormatProperties2(dev, fmt, &props); |
| if (doesFormatMatch(fmt) && ((props.formatProperties.optimalTilingFeatures & flags) == flags)) |
| { |
| this->format = fmt; |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| struct CheckerboardBuilder |
| { |
| CheckerboardBuilder (uint32_t width, uint32_t height) |
| : m_width(width), m_height(height) {} |
| |
| static uint32_t blackFieldCount (uint32_t w, uint32_t h) |
| { |
| return ((w+1)/2)*((h+1)/2)+(w/2)*(h/2); |
| } |
| |
| uint32_t blackFieldCount () const |
| { |
| return blackFieldCount(m_width, m_height); |
| } |
| |
| uint32_t fieldIndex (uint32_t x, uint32_t y) const |
| { |
| return blackFieldCount(m_width, y) + (x / 2); |
| } |
| |
| void buildVerticesAndIndices (std::vector<float>& vertices, std::vector<uint32_t>& indices) const |
| { |
| const uint32_t vertPerQuad = 4; |
| const uint32_t indexPerQuad = 6; |
| const uint32_t quadCount = blackFieldCount(); |
| const uint32_t compPerQuad = vertPerQuad * 2; |
| const uint32_t vertCount = quadCount * vertPerQuad; |
| const uint32_t indexCount = quadCount * indexPerQuad; |
| |
| vertices.resize(vertCount * 2); |
| indices.resize(indexCount); |
| |
| for (uint32_t z = 0; z < 2; ++z) |
| for (uint32_t y = 0; y < m_height; ++y) |
| for (uint32_t x = 0; x < m_width; ++x) |
| { |
| if (((x + y) % 2) == 1) |
| continue; |
| |
| const float x1 = float(x) / float(m_width); |
| const float y1 = float(y) / float(m_height); |
| const float x2 = (float(x) + 1.0f) / float(m_width); |
| const float y2 = (float(y) + 1.0f) / float(m_height); |
| |
| const float xx1 = x1 * 2.0f - 1.0f; |
| const float yy1 = y1 * 2.0f - 1.0f; |
| const float xx2 = x2 * 2.0f - 1.0f; |
| const float yy2 = y2 * 2.0f - 1.0f; |
| |
| const uint32_t quad = fieldIndex(x, y); |
| |
| if (z == 0) |
| { |
| vertices[ quad * compPerQuad + 0 ] = xx1; |
| vertices[ quad * compPerQuad + 1 ] = yy1; |
| vertices[ quad * compPerQuad + 2 ] = xx2; |
| vertices[ quad * compPerQuad + 3 ] = yy1; |
| |
| indices[ quad * indexPerQuad + 0 ] = quad * vertPerQuad + 0; |
| indices[ quad * indexPerQuad + 1 ] = quad * vertPerQuad + 1; |
| indices[ quad * indexPerQuad + 2 ] = quad * vertPerQuad + 2; |
| } |
| else |
| { |
| vertices[ quad * compPerQuad + 4 ] = xx2; |
| vertices[ quad * compPerQuad + 5 ] = yy2; |
| vertices[ quad * compPerQuad + 6 ] = xx1; |
| vertices[ quad * compPerQuad + 7 ] = yy2; |
| |
| indices[ quad * indexPerQuad + 3 ] = quad * vertPerQuad + 2; |
| indices[ quad * indexPerQuad + 4 ] = quad * vertPerQuad + 3; |
| indices[ quad * indexPerQuad + 5 ] = quad * vertPerQuad + 0; |
| } |
| } |
| } |
| |
| private: |
| uint32_t m_width; |
| uint32_t m_height; |
| }; |
| |
| template<class T, class P = T(*)[1]> |
| auto begin (void* p) -> decltype(std::begin(*std::declval<P>())) |
| { |
| return std::begin(*static_cast<P>(p)); |
| } |
| |
| class GPQInstanceBase : public TestInstance |
| { |
| public: |
| typedef std::initializer_list<VkDescriptorSetLayout> DSLayouts; |
| typedef tcu::ConstPixelBufferAccess BufferAccess; |
| |
| GPQInstanceBase (Context& ctx, |
| const TestConfig& cfg); |
| template<class PushConstant = void> |
| auto createPipelineLayout (DSLayouts setLayouts) const -> Move<VkPipelineLayout>; |
| auto createGraphicsPipeline (VkPipelineLayout pipelineLayout, |
| VkRenderPass renderPass) -> Move<VkPipeline>; |
| auto createComputePipeline (VkPipelineLayout pipelineLayout) -> Move<VkPipeline>; |
| auto createImage (VkImageUsageFlags usage, |
| deUint32 queueFamilyIdx, |
| VkQueue queue) const -> de::MovePtr<ImageWithMemory>; |
| auto createView (VkImage image, |
| VkImageSubresourceRange& range) const -> Move<VkImageView>; |
| void submitCommands (VkCommandBuffer producerCmd, |
| VkCommandBuffer consumerCmd) const; |
| bool verify (const BufferAccess& result, |
| deUint32 blackColor, |
| deUint32 whiteColor) const; |
| protected: |
| auto createPipelineLayout (const VkPushConstantRange* pRange, |
| DSLayouts setLayouts) const -> Move<VkPipelineLayout>; |
| const TestConfig m_config; |
| const SpecialDevice m_device; |
| Move<VkShaderModule> m_vertex; |
| Move<VkShaderModule> m_fragment; |
| Move<VkShaderModule> m_compute; |
| }; |
| GPQInstanceBase::GPQInstanceBase (Context& ctx, const TestConfig& cfg) |
| : TestInstance (ctx) |
| , m_config (cfg) |
| , m_device (ctx, |
| cfg.transitionFrom, cfg.transitionTo, |
| cfg.priorityFrom, cfg.priorityTo, |
| cfg.enableProtected, cfg.enableSparseBinding) |
| , m_vertex () |
| , m_fragment () |
| , m_compute () |
| { |
| } |
| |
| de::MovePtr<ImageWithMemory> GPQInstanceBase::createImage (VkImageUsageFlags usage, deUint32 queueFamilyIdx, VkQueue queue) const |
| { |
| const InstanceInterface& vki = m_context.getInstanceInterface(); |
| const DeviceInterface& vkd = m_context.getDeviceInterface(); |
| const VkPhysicalDevice phys = m_context.getPhysicalDevice(); |
| const VkDevice dev = m_device.device; |
| Allocator& alloc = m_device.getAllocator(); |
| VkImageCreateFlags flags = 0; |
| |
| if (m_config.enableProtected) flags |= VK_IMAGE_CREATE_PROTECTED_BIT; |
| if (m_config.enableSparseBinding) flags |= (VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT); |
| |
| VkImageCreateInfo imageInfo{}; |
| imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; |
| imageInfo.pNext = nullptr; |
| imageInfo.flags = flags; |
| imageInfo.imageType = VK_IMAGE_TYPE_2D; |
| imageInfo.format = m_config.format; |
| imageInfo.extent.width = m_config.width; |
| imageInfo.extent.height = m_config.height; |
| imageInfo.extent.depth = 1; |
| imageInfo.mipLevels = 1; |
| imageInfo.arrayLayers = 1; |
| imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; |
| imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; |
| imageInfo.usage = usage; |
| imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; |
| imageInfo.queueFamilyIndexCount = 1; |
| imageInfo.pQueueFamilyIndices = &queueFamilyIdx; |
| imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; |
| |
| return de::MovePtr<ImageWithMemory>(new ImageWithMemory(vki, vkd, phys, dev, alloc, imageInfo, queue)); |
| } |
| |
| Move<VkImageView> GPQInstanceBase::createView (VkImage image, VkImageSubresourceRange& range) const |
| { |
| const DeviceInterface& vkd = m_context.getDeviceInterface(); |
| const VkDevice dev = m_device.device; |
| |
| range = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1); |
| return makeImageView(vkd, dev, image, VK_IMAGE_VIEW_TYPE_2D, m_config.format, range); |
| } |
| |
| Move<VkPipelineLayout> GPQInstanceBase::createPipelineLayout (const VkPushConstantRange* pRange, DSLayouts setLayouts) const |
| { |
| std::vector<VkDescriptorSetLayout> layouts(setLayouts.size()); |
| auto ii = setLayouts.begin(); |
| for (auto i = ii; i != setLayouts.end(); ++i) |
| layouts[std::distance(ii, i)] = *i; |
| |
| VkPipelineLayoutCreateInfo info{}; |
| info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; |
| info.pNext = nullptr; |
| info.flags = VkPipelineLayoutCreateFlags(0); |
| info.setLayoutCount = static_cast<uint32_t>(layouts.size()); |
| info.pSetLayouts = layouts.size() ? layouts.data() : nullptr; |
| info.pushConstantRangeCount = pRange ? 1 : 0; |
| info.pPushConstantRanges = pRange; |
| |
| return ::vk::createPipelineLayout(m_context.getDeviceInterface(), m_device.device, &info); |
| } |
| |
| template<> Move<VkPipelineLayout> DE_UNUSED_FUNCTION GPQInstanceBase::createPipelineLayout<void> (DSLayouts setLayouts) const |
| { |
| return createPipelineLayout(nullptr, setLayouts); |
| } |
| |
| template<class PushConstant> Move<VkPipelineLayout> GPQInstanceBase::createPipelineLayout (DSLayouts setLayouts) const |
| { |
| VkPushConstantRange range{}; |
| range.stageFlags = VK_SHADER_STAGE_ALL; |
| range.offset = 0; |
| range.size = static_cast<uint32_t>(sizeof(PushConstant)); |
| return createPipelineLayout(&range, setLayouts); |
| } |
| |
| Move<VkPipeline> GPQInstanceBase::createGraphicsPipeline (VkPipelineLayout pipelineLayout, VkRenderPass renderPass) |
| { |
| const DeviceInterface& vkd = m_context.getDeviceInterface(); |
| const VkDevice dev = m_device.device; |
| |
| m_vertex = createShaderModule(vkd, dev, m_context.getBinaryCollection().get("vert")); |
| m_fragment = createShaderModule(vkd, dev, m_context.getBinaryCollection().get("frag")); |
| |
| const std::vector<VkViewport> viewports { makeViewport(m_config.width, m_config.height) }; |
| const std::vector<VkRect2D> scissors { makeRect2D(m_config.width, m_config.height) }; |
| const auto vertexBinding = makeVertexInputBindingDescription(0u, static_cast<deUint32>(2 * sizeof(float)), VK_VERTEX_INPUT_RATE_VERTEX); |
| const auto vertexAttrib = makeVertexInputAttributeDescription(0u, 0u, VK_FORMAT_R32G32_SFLOAT, 0u); |
| const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo |
| { |
| vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType; |
| nullptr, // const void* pNext; |
| 0u, // VkPipelineVertexInputStateCreateFlags flags; |
| 1u, // deUint32 vertexBindingDescriptionCount; |
| &vertexBinding, // const VkVertexInputBindingDescription* pVertexBindingDescriptions; |
| 1u, // deUint32 vertexAttributeDescriptionCount; |
| &vertexAttrib // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions; |
| }; |
| |
| return makeGraphicsPipeline(vkd, dev, pipelineLayout,*m_vertex,VkShaderModule(0), |
| VkShaderModule(0),VkShaderModule(0),*m_fragment,renderPass,viewports, scissors, |
| VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,0,0,&vertexInputStateCreateInfo); |
| |
| |
| } |
| |
| Move<VkPipeline> GPQInstanceBase::createComputePipeline (VkPipelineLayout pipelineLayout) |
| { |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| const VkDevice dev = m_device.device; |
| |
| m_compute = createShaderModule(vk, dev, m_context.getBinaryCollection().get("comp")); |
| |
| VkPipelineShaderStageCreateInfo sci{}; |
| sci.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; |
| sci.pNext = nullptr; |
| sci.flags = VkPipelineShaderStageCreateFlags(0); |
| sci.stage = VK_SHADER_STAGE_COMPUTE_BIT; |
| sci.module = *m_compute; |
| sci.pName = "main"; |
| sci.pSpecializationInfo = nullptr; |
| |
| VkComputePipelineCreateInfo ci{}; |
| ci.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; |
| ci.pNext = nullptr; |
| ci.flags = VkPipelineCreateFlags(0); |
| ci.stage = sci; |
| ci.layout = pipelineLayout; |
| ci.basePipelineHandle = VkPipeline(0); |
| ci.basePipelineIndex = 0; |
| |
| return vk::createComputePipeline(vk, dev, VkPipelineCache(0), &ci, nullptr); |
| } |
| |
| VkPipelineStageFlags queueFlagBitToPipelineStage (VkQueueFlagBits bit); |
| void GPQInstanceBase::submitCommands (VkCommandBuffer producerCmd, VkCommandBuffer consumerCmd) const |
| { |
| const DeviceInterface& vkd = m_context.getDeviceInterface(); |
| const VkDevice dev = m_device.device; |
| |
| Move<VkSemaphore> sem = createSemaphore(vkd, dev); |
| Move<VkFence> fence = createFence(vkd, dev); |
| |
| const VkSubmitInfo semSubmitProducer |
| { |
| VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType; |
| nullptr, // const void* pNext; |
| 0, // deUint32 waitSemaphoreCount; |
| nullptr, // const VkSemaphore* pWaitSemaphores; |
| nullptr, // const VkPipelineStageFlags* pWaitDstStageMask; |
| 1u, // deUint32 commandBufferCount; |
| &producerCmd, // const VkCommandBuffer* pCommandBuffers; |
| 1u, // deUint32 signalSemaphoreCount; |
| &sem.get(), // const VkSemaphore* pSignalSemaphores; |
| }; |
| |
| const VkPipelineStageFlags waitStage = queueFlagBitToPipelineStage(m_config.transitionFrom); |
| const VkSubmitInfo semSubmitConsumer |
| { |
| VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType; |
| nullptr, // const void* pNext; |
| 1u, // deUint32 waitSemaphoreCount; |
| &(*sem), // const VkSemaphore* pWaitSemaphores; |
| &waitStage, // const VkPipelineStageFlags* pWaitDstStageMask; |
| 1u, // deUint32 commandBufferCount; |
| &consumerCmd, // const VkCommandBuffer* pCommandBuffers; |
| 0, // deUint32 signalSemaphoreCount; |
| nullptr, // const VkSemaphore* pSignalSemaphores; |
| }; |
| |
| switch (m_config.syncType) |
| { |
| case SyncType::None: |
| submitCommandsAndWait(vkd, dev, m_device.queueFrom, producerCmd); |
| submitCommandsAndWait(vkd, dev, m_device.queueTo, consumerCmd); |
| break; |
| case SyncType::Semaphore: |
| VK_CHECK(vkd.queueSubmit(m_device.queueFrom, 1u, &semSubmitProducer, VkFence(0))); |
| VK_CHECK(vkd.queueSubmit(m_device.queueTo, 1u, &semSubmitConsumer, *fence)); |
| VK_CHECK(vkd.waitForFences(dev, 1u, &fence.get(), DE_TRUE, ~0ull)); |
| break; |
| } |
| } |
| |
| template<VkQueueFlagBits, VkQueueFlagBits> class GPQInstance; |
| #define DECLARE_INSTANCE(flagsFrom_, flagsTo_) \ |
| template<> class GPQInstance<flagsFrom_, flagsTo_> : public GPQInstanceBase \ |
| { public: GPQInstance (Context& ctx, const TestConfig& cfg) \ |
| : GPQInstanceBase(ctx, cfg) { } \ |
| virtual tcu::TestStatus iterate (void) override; } |
| |
| DECLARE_INSTANCE(VK_QUEUE_GRAPHICS_BIT, VK_QUEUE_COMPUTE_BIT); |
| DECLARE_INSTANCE(VK_QUEUE_COMPUTE_BIT, VK_QUEUE_GRAPHICS_BIT); |
| |
| class GPQCase; |
| typedef TestInstance* (GPQCase::* CreateInstanceProc)(Context&) const; |
| typedef std::pair<VkQueueFlagBits,VkQueueFlagBits> CreateInstanceKey; |
| typedef std::map<CreateInstanceKey, CreateInstanceProc> CreateInstanceMap; |
| #define MAPENTRY(from_,to_) m_createInstanceMap[{from_,to_}] = &GPQCase::createInstance<from_,to_> |
| |
| class GPQCase : public TestCase |
| { |
| public: |
| GPQCase (tcu::TestContext& ctx, |
| const std::string& name, |
| const TestConfig& cfg, |
| const std::string& desc = {}); |
| void initPrograms (SourceCollections& programs) const override; |
| TestInstance* createInstance (Context& context) const override; |
| void checkSupport (Context& context) const override; |
| static deUint32 testValue; |
| |
| private: |
| template<VkQueueFlagBits, VkQueueFlagBits> |
| TestInstance* createInstance (Context& context) const; |
| mutable TestConfig m_config; |
| CreateInstanceMap m_createInstanceMap; |
| }; |
| deUint32 GPQCase::testValue = 113; |
| |
| GPQCase::GPQCase (tcu::TestContext& ctx, |
| const std::string& name, |
| const TestConfig& cfg, |
| const std::string& desc) |
| : TestCase (ctx, name, desc) |
| , m_config (cfg) |
| , m_createInstanceMap () |
| { |
| MAPENTRY(VK_QUEUE_GRAPHICS_BIT, VK_QUEUE_COMPUTE_BIT); |
| MAPENTRY(VK_QUEUE_COMPUTE_BIT, VK_QUEUE_GRAPHICS_BIT); |
| } |
| |
| VkPipelineStageFlags queueFlagBitToPipelineStage (VkQueueFlagBits bit) |
| { |
| switch (bit) { |
| case VK_QUEUE_COMPUTE_BIT: |
| return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; |
| case VK_QUEUE_GRAPHICS_BIT: |
| return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; |
| default: |
| DE_ASSERT(VK_FALSE); |
| } |
| return VK_QUEUE_FLAG_BITS_MAX_ENUM; |
| } |
| |
| template<VkQueueFlagBits flagsFrom, VkQueueFlagBits flagsTo> |
| TestInstance* GPQCase::createInstance (Context& context) const |
| { |
| return new GPQInstance<flagsFrom, flagsTo>(context, m_config); |
| } |
| |
| TestInstance* GPQCase::createInstance (Context& context) const |
| { |
| const CreateInstanceKey key(m_config.transitionFrom, m_config.transitionTo); |
| return (this->*(m_createInstanceMap.at(key)))(context); |
| } |
| |
| std::ostream& operator<<(std::ostream& str, const VkQueueFlagBits& bit) |
| { |
| const char* s = nullptr; |
| const auto d = std::to_string(bit); |
| switch (bit) |
| { |
| case VK_QUEUE_GRAPHICS_BIT: s = "VK_QUEUE_GRAPHICS_BIT"; break; |
| case VK_QUEUE_COMPUTE_BIT: s = "VK_QUEUE_COMPUTE_BIT"; break; |
| case VK_QUEUE_TRANSFER_BIT: s = "VK_QUEUE_TRANSFER_BIT"; break; |
| case VK_QUEUE_SPARSE_BINDING_BIT: s = "VK_QUEUE_SPARSE_BINDING_BIT"; break; |
| case VK_QUEUE_PROTECTED_BIT: s = "VK_QUEUE_PROTECTED_BIT"; break; |
| default: s = d.c_str(); break; |
| } |
| return (str << s); |
| } |
| |
| void GPQCase::checkSupport (Context& context) const |
| { |
| const InstanceInterface& vki = context.getInstanceInterface(); |
| const VkPhysicalDevice dev = context.getPhysicalDevice(); |
| |
| context.requireDeviceFunctionality("VK_EXT_global_priority"); |
| |
| if (!m_config.selectFormat(vki, dev, { VK_FORMAT_R32_SINT, VK_FORMAT_R32_UINT, VK_FORMAT_R8_SINT, VK_FORMAT_R8_UINT })) |
| { |
| TCU_THROW(NotSupportedError, "Unable to find a proper format"); |
| } |
| |
| VkPhysicalDeviceProtectedMemoryFeatures memFeatures |
| { |
| VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES, |
| nullptr, |
| VK_FALSE |
| }; |
| VkPhysicalDeviceFeatures2 devFeatures |
| { |
| VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, |
| &memFeatures, |
| {} |
| }; |
| vki.getPhysicalDeviceFeatures2(dev, &devFeatures); |
| |
| if (m_config.enableProtected && (VK_FALSE == memFeatures.protectedMemory)) |
| { |
| TCU_THROW(NotSupportedError, "Queue families with VK_QUEUE_PROTECTED_BIT not supported"); |
| } |
| |
| const VkBool32 sparseEnabled = devFeatures.features.sparseBinding & devFeatures.features.sparseResidencyBuffer & devFeatures.features.sparseResidencyImage2D; |
| if (m_config.enableSparseBinding && (VK_FALSE == sparseEnabled)) |
| { |
| TCU_THROW(NotSupportedError, "Queue families with VK_QUEUE_SPARSE_BINDING_BIT not supported"); |
| } |
| |
| auto assertUnavailableQueue = [](const deUint32 qIdx, VkQueueFlagBits qfb, VkQueueGlobalPriorityKHR qgp) |
| { |
| if (qIdx == INVALID_UINT32) { |
| std::ostringstream buf; |
| buf << "Unable to create a queue " << qfb << " with a priority " << qgp; |
| buf.flush(); |
| TCU_THROW(NotSupportedError, buf.str()); |
| } |
| }; |
| |
| const bool priorityQueryEnabled = context.isDeviceFunctionalitySupported("VK_EXT_global_priority_query"); |
| |
| VkQueueFlags flagFrom = m_config.transitionFrom; |
| VkQueueFlags flagTo = m_config.transitionTo; |
| if (m_config.enableProtected) |
| { |
| flagFrom |= VK_QUEUE_PROTECTED_BIT; |
| flagTo |= VK_QUEUE_PROTECTED_BIT; |
| } |
| if (m_config.enableSparseBinding) |
| { |
| flagFrom |= VK_QUEUE_SPARSE_BINDING_BIT; |
| flagTo |= VK_QUEUE_SPARSE_BINDING_BIT; |
| } |
| |
| const deUint32 queueFromIndex = findQueueFamilyIndex(vki, dev, flagFrom, |
| SpecialDevice::getColissionFlags(m_config.transitionFrom), |
| priorityQueryEnabled, |
| QueueGlobalPriorities({m_config.priorityFrom})); |
| assertUnavailableQueue(queueFromIndex, m_config.transitionFrom, m_config.priorityFrom); |
| |
| const deUint32 queueToIndex = findQueueFamilyIndex(vki, dev, flagTo, |
| SpecialDevice::getColissionFlags(m_config.transitionTo), |
| priorityQueryEnabled, |
| QueueGlobalPriorities({m_config.priorityTo})); |
| assertUnavailableQueue(queueToIndex, m_config.transitionTo, m_config.priorityTo); |
| |
| if (queueFromIndex == queueToIndex) |
| { |
| std::ostringstream buf; |
| buf << "Unable to find separate queues " << m_config.transitionFrom << " and " << m_config.transitionTo; |
| buf.flush(); |
| TCU_THROW(NotSupportedError, buf.str()); |
| } |
| } |
| |
| std::string getShaderImageBufferType (const tcu::TextureFormat& format) |
| { |
| return image::getFormatPrefix(format) + "imageBuffer"; |
| } |
| |
| void GPQCase::initPrograms (SourceCollections& programs) const |
| { |
| const std::string producerComp(R"glsl( |
| #version 450 |
| layout(std430, push_constant) uniform PC |
| { uint width, height; } pc; |
| struct Index { uint k; }; |
| struct Quad { vec2 c[4]; }; |
| layout(set=0, binding=0) buffer Quads |
| { Quad data[]; } quads; |
| layout(set=0, binding=1) buffer Indices |
| { Index data[]; } indices; |
| uint fieldCount (uint w, uint h) { |
| return ((w+1)/2)*((h+1)/2)+(w/2)*(h/2); |
| } |
| uint fieldIndex () { |
| return fieldCount(pc.width, gl_GlobalInvocationID.y) + (gl_GlobalInvocationID.x / 2); |
| } |
| void main() { |
| float x1 = float(gl_GlobalInvocationID.x) / float(pc.width); |
| float y1 = float(gl_GlobalInvocationID.y) / float(pc.height); |
| float x2 = (float(gl_GlobalInvocationID.x) + 1.0) / float(pc.width); |
| float y2 = (float(gl_GlobalInvocationID.y) + 1.0) / float(pc.height); |
| |
| float xx1 = x1 * 2.0 - 1.0; |
| float yy1 = y1 * 2.0 - 1.0; |
| float xx2 = x2 * 2.0 - 1.0; |
| float yy2 = y2 * 2.0 - 1.0; |
| |
| if (((gl_GlobalInvocationID.x + gl_GlobalInvocationID.y) % 2) == 0) |
| { |
| uint at = fieldIndex(); |
| |
| if (gl_GlobalInvocationID.z == 0) |
| { |
| quads.data[at].c[0] = vec2(xx1, yy1); |
| quads.data[at].c[1] = vec2(xx2, yy1); |
| indices.data[at*6+0].k = at * 4 + 0; |
| indices.data[at*6+1].k = at * 4 + 1; |
| indices.data[at*6+2].k = at * 4 + 2; |
| } |
| else |
| { |
| quads.data[at].c[2] = vec2(xx2, yy2); |
| quads.data[at].c[3] = vec2(xx1, yy2); |
| indices.data[at*6+3].k = at * 4 + 2; |
| indices.data[at*6+4].k = at * 4 + 3; |
| indices.data[at*6+5].k = at * 4 + 0; |
| } |
| } |
| } |
| )glsl"); |
| |
| const tcu::StringTemplate consumerComp(R"glsl( |
| #version 450 |
| layout(std430, push_constant) uniform PC |
| { uint width, height; } pc; |
| struct Pixel { uint k; }; |
| layout(${IMAGE_FORMAT}, set=0, binding=0) readonly uniform ${IMAGE_TYPE} srcImage; |
| layout(binding=1) writeonly coherent buffer Pixels { Pixel data[]; } pixels; |
| void main() |
| { |
| ivec2 pos2 = ivec2(gl_GlobalInvocationID.xy); |
| int pos1 = int(gl_GlobalInvocationID.y * pc.width + gl_GlobalInvocationID.x); |
| pixels.data[pos1].k = uint(imageLoad(srcImage, pos2).r) + 1; |
| } |
| )glsl"); |
| |
| const std::string vert(R"glsl( |
| #version 450 |
| layout(location = 0) in vec2 pos; |
| void main() |
| { |
| gl_Position = vec4(pos, 0, 1); |
| } |
| )glsl"); |
| |
| const tcu::StringTemplate frag(R"glsl( |
| #version 450 |
| layout(location = 0) out ${COLOR_TYPE} color; |
| void main() |
| { |
| color = ${COLOR_TYPE}(${TEST_VALUE},0,0,1); |
| } |
| )glsl"); |
| |
| const auto format = mapVkFormat(m_config.format); |
| const auto imageFormat = image::getShaderImageFormatQualifier(format); |
| const auto imageType = image::getShaderImageType(format, image::ImageType::IMAGE_TYPE_2D, false); |
| const auto imageBuffer = getShaderImageBufferType(format); |
| const auto colorType = image::getGlslAttachmentType(m_config.format); // ivec4 |
| |
| const std::map<std::string, std::string> abbreviations |
| { |
| { std::string("TEST_VALUE"), std::to_string(testValue) }, |
| { std::string("IMAGE_FORMAT"), std::string(imageFormat) }, |
| { std::string("IMAGE_TYPE"), std::string(imageType) }, |
| { std::string("IMAGE_BUFFER"), std::string(imageBuffer) }, |
| { std::string("COLOR_TYPE"), std::string(colorType) }, |
| }; |
| |
| programs.glslSources.add("comp") << glu::ComputeSource( |
| m_config.transitionFrom == VK_QUEUE_COMPUTE_BIT |
| ? producerComp |
| : consumerComp.specialize(abbreviations)); |
| programs.glslSources.add("vert") << glu::VertexSource(vert); |
| programs.glslSources.add("frag") << glu::FragmentSource(frag.specialize(abbreviations)); |
| } |
| |
| |
| tcu::TestStatus GPQInstance<VK_QUEUE_COMPUTE_BIT, VK_QUEUE_GRAPHICS_BIT>::iterate (void) |
| { |
| VkResult deviceStatus = VK_SUCCESS; |
| if (!m_device.isValid(deviceStatus)) |
| { |
| if (VK_ERROR_NOT_PERMITTED_KHR == deviceStatus) |
| return tcu::TestStatus::pass(getResultName(deviceStatus)); |
| TCU_CHECK(deviceStatus); |
| } |
| |
| const InstanceInterface& vki = m_context.getInstanceInterface(); |
| const DeviceInterface& vkd = m_context.getDeviceInterface(); |
| const VkPhysicalDevice phys = m_context.getPhysicalDevice(); |
| const VkDevice device = m_device.device; |
| Allocator& allocator = m_device.getAllocator(); |
| const deUint32 producerIndex = m_device.queueFamilyIndexFrom; |
| const deUint32 consumerIndex = m_device.queueFamilyIndexTo; |
| const VkQueue producerQueue = m_device.queueFrom; DE_UNREF(producerQueue); |
| const VkQueue consumerQueue = m_device.queueTo; DE_UNREF(consumerQueue); |
| |
| const uint32_t width = m_config.width; |
| const uint32_t height = m_config.height; |
| const uint32_t clearComp = 97; |
| const VkClearValue clearColor = makeClearValueColorU32(clearComp, clearComp, clearComp, clearComp); |
| const uint32_t quadCount = CheckerboardBuilder::blackFieldCount(width, height); |
| const uint32_t vertexCount = 4 * quadCount; |
| const uint32_t indexCount = 6 * quadCount; |
| const MemoryRequirement memReqs = (m_config.enableProtected ? MemoryRequirement::Protected : MemoryRequirement::Any); |
| |
| VkBufferCreateFlags buffsCreateFlags = 0; |
| if (m_config.enableProtected) buffsCreateFlags |= VK_BUFFER_CREATE_PROTECTED_BIT; |
| if (m_config.enableSparseBinding) buffsCreateFlags |= VK_BUFFER_CREATE_SPARSE_BINDING_BIT; |
| const VkBufferUsageFlags vertBuffUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; |
| const VkBufferUsageFlags indexBuffUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT; |
| const VkDeviceSize vertBuffSize = vertexCount * mapVkFormat(VK_FORMAT_R32G32_SFLOAT).getPixelSize(); |
| const VkDeviceSize indexBuffSize = indexCount * sizeof(uint32_t); |
| const VkDeviceSize resultBuffSize = (width * height * mapVkFormat(m_config.format).getPixelSize()); |
| const VkBufferCreateInfo vertBuffInfo = makeBufferCreateInfo(vertBuffSize, vertBuffUsage, {producerIndex}, buffsCreateFlags); |
| const VkBufferCreateInfo indexBuffInfo = makeBufferCreateInfo(indexBuffSize, indexBuffUsage, {producerIndex}, buffsCreateFlags); |
| const VkBufferCreateInfo resultBuffInfo = makeBufferCreateInfo(resultBuffSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT); |
| BufferWithMemory vertexBuffer (vki, vkd, phys, device, allocator, vertBuffInfo, memReqs, producerQueue); |
| BufferWithMemory indexBuffer (vki, vkd, phys, device, allocator, indexBuffInfo, memReqs, producerQueue); |
| BufferWithMemory resultBuffer (vki, vkd, phys, device, allocator, resultBuffInfo, MemoryRequirement::HostVisible); |
| |
| const VkDescriptorBufferInfo dsVertInfo = makeDescriptorBufferInfo(vertexBuffer.get(), 0ull, vertBuffSize); |
| const VkDescriptorBufferInfo dsIndexInfo = makeDescriptorBufferInfo(indexBuffer.get(), 0ull, indexBuffSize); |
| Move<VkDescriptorPool> dsPool = DescriptorPoolBuilder() |
| .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) |
| .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) |
| .build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u); |
| Move<VkDescriptorSetLayout> dsLayout = DescriptorSetLayoutBuilder() |
| .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL) |
| .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL) |
| .build(vkd, device); |
| Move<VkDescriptorSet> descriptorSet = makeDescriptorSet(vkd, device, *dsPool, *dsLayout); |
| DescriptorSetUpdateBuilder() |
| .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &dsVertInfo) |
| .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &dsIndexInfo) |
| .update(vkd, device); |
| |
| VkImageSubresourceRange colorResourceRange {}; |
| const VkImageUsageFlags imageUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT); |
| de::MovePtr<ImageWithMemory> image = this->createImage(imageUsage, consumerIndex, consumerQueue); |
| Move<VkImageView> view = createView(**image, colorResourceRange); |
| Move<VkRenderPass> renderPass = makeRenderPass(vkd, device, m_config.format); |
| Move<VkFramebuffer> framebuffer = makeFramebuffer(vkd, device, *renderPass, *view, width, height); |
| const VkImageMemoryBarrier colorReadyBarrier = makeImageMemoryBarrier(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, |
| **image, colorResourceRange); |
| const VkBufferImageCopy colorCopyRegion = makeBufferImageCopy(makeExtent3D(width, height, 1), |
| makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u)); |
| const VkMemoryBarrier resultReadyBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT); |
| struct PushConstant |
| { uint32_t width, height; } pc { width, height }; |
| Move<VkPipelineLayout> pipelineLayout = createPipelineLayout<PushConstant>({ *dsLayout }); |
| Move<VkPipeline> producerPipeline = createComputePipeline(*pipelineLayout); |
| Move<VkPipeline> consumerPipeline = createGraphicsPipeline(*pipelineLayout, *renderPass); |
| |
| Move<VkCommandPool> producerPool = makeCommandPool(vkd, device, producerIndex); |
| Move<VkCommandPool> consumerPool = makeCommandPool(vkd, device, consumerIndex); |
| Move<VkCommandBuffer> producerCmd = allocateCommandBuffer(vkd, device, *producerPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY); |
| Move<VkCommandBuffer> consumerCmd = allocateCommandBuffer(vkd, device, *consumerPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY); |
| |
| beginCommandBuffer(vkd, *producerCmd); |
| vkd.cmdBindDescriptorSets(*producerCmd, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0, 1, &(*descriptorSet), 0, nullptr); |
| vkd.cmdBindPipeline(*producerCmd, VK_PIPELINE_BIND_POINT_COMPUTE, *producerPipeline); |
| vkd.cmdPushConstants(*producerCmd, *pipelineLayout, VK_SHADER_STAGE_ALL, 0, static_cast<uint32_t>(sizeof(PushConstant)), &pc); |
| vkd.cmdDispatch(*producerCmd, width, height, 2); |
| endCommandBuffer(vkd, *producerCmd); |
| |
| beginCommandBuffer(vkd, *consumerCmd); |
| vkd.cmdBindPipeline(*consumerCmd, VK_PIPELINE_BIND_POINT_GRAPHICS, *consumerPipeline); |
| vkd.cmdBindIndexBuffer(*consumerCmd, *indexBuffer, 0, VK_INDEX_TYPE_UINT32); |
| vkd.cmdBindVertexBuffers(*consumerCmd, 0, 1, &static_cast<const VkBuffer&>(*vertexBuffer), &static_cast<const VkDeviceSize&>(0)); |
| beginRenderPass(vkd, *consumerCmd, *renderPass, *framebuffer, makeRect2D(width, height), clearColor); |
| vkd.cmdDrawIndexed(*consumerCmd, indexCount, 1, 0, 0, 0); |
| endRenderPass(vkd, *consumerCmd); |
| vkd.cmdPipelineBarrier(*consumerCmd, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &colorReadyBarrier); |
| vkd.cmdCopyImageToBuffer(*consumerCmd, **image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *resultBuffer, 1u, &colorCopyRegion); |
| vkd.cmdPipelineBarrier(*consumerCmd, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &resultReadyBarrier, 0u, nullptr, 0u, nullptr); |
| endCommandBuffer(vkd, *consumerCmd); |
| |
| submitCommands(*producerCmd, *consumerCmd); |
| |
| resultBuffer.invalidateAlloc(vkd, device); |
| const tcu::ConstPixelBufferAccess resultBufferAccess(mapVkFormat(m_config.format), width, height, 1, resultBuffer.getHostPtr()); |
| |
| return verify(resultBufferAccess, GPQCase::testValue, clearComp) ? tcu::TestStatus::pass("") : tcu::TestStatus::fail(""); |
| } |
| |
| tcu::TestStatus GPQInstance<VK_QUEUE_GRAPHICS_BIT, VK_QUEUE_COMPUTE_BIT>::iterate (void) |
| { |
| VkResult deviceStatus = VK_SUCCESS; |
| if (!m_device.isValid(deviceStatus)) |
| { |
| if (VK_ERROR_NOT_PERMITTED_KHR == deviceStatus) |
| return tcu::TestStatus::pass(getResultName(deviceStatus)); |
| TCU_CHECK(deviceStatus); |
| } |
| |
| const InstanceInterface& vki = m_context.getInstanceInterface(); |
| const DeviceInterface& vkd = m_context.getDeviceInterface(); |
| const VkPhysicalDevice phys = m_context.getPhysicalDevice(); |
| const VkDevice device = m_device.device; |
| Allocator& allocator = m_device.getAllocator(); |
| const deUint32 producerIndex = m_device.queueFamilyIndexFrom; |
| const deUint32 consumerIndex = m_device.queueFamilyIndexTo; |
| const VkQueue producerQueue = m_device.queueFrom; DE_UNREF(producerQueue); |
| const VkQueue consumerQueue = m_device.queueTo; DE_UNREF(consumerQueue); |
| |
| const uint32_t width = m_config.width; |
| const uint32_t height = m_config.height; |
| const uint32_t clearComp = GPQCase::testValue - 11; |
| const VkClearValue clearColor = makeClearValueColorU32(clearComp, clearComp, clearComp, clearComp); |
| const uint32_t quadCount = CheckerboardBuilder::blackFieldCount(width, height); |
| const uint32_t vertexCount = 4 * quadCount; |
| const uint32_t indexCount = 6 * quadCount; |
| |
| const VkBufferCreateFlags graphCreateFlags = 0; |
| const MemoryRequirement graphBuffsMemReqs = (MemoryRequirement::HostVisible); |
| |
| const VkBufferUsageFlags vertBuffUsage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; |
| const VkDeviceSize vertBuffSize = vertexCount * mapVkFormat(VK_FORMAT_R32G32_SFLOAT).getPixelSize(); |
| const VkBufferCreateInfo vertBuffInfo = makeBufferCreateInfo(vertBuffSize, vertBuffUsage, {producerIndex}, graphCreateFlags); |
| BufferWithMemory vertexBuffer (vki, vkd, phys, device, allocator, vertBuffInfo, graphBuffsMemReqs, producerQueue); |
| |
| const VkBufferUsageFlags indexBuffUsage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT; |
| const VkDeviceSize indexBuffSize = indexCount * sizeof(uint32_t); |
| const VkBufferCreateInfo indexBuffInfo = makeBufferCreateInfo(indexBuffSize, indexBuffUsage, {producerIndex}, graphCreateFlags); |
| BufferWithMemory indexBuffer (vki, vkd, phys, device, allocator, indexBuffInfo, graphBuffsMemReqs, producerQueue); |
| |
| VkImageSubresourceRange producerResRange {}; |
| const VkImageUsageFlags producerUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT); |
| de::MovePtr<ImageWithMemory> producerImage = this->createImage(producerUsage, producerIndex, producerQueue); |
| Move<VkImageView> producerView = createView(**producerImage, producerResRange); |
| const VkDescriptorImageInfo producerImageInfo = makeDescriptorImageInfo(VkSampler(0), *producerView, VK_IMAGE_LAYOUT_GENERAL); |
| |
| const VkBufferCreateFlags consumerCreateFlags = graphCreateFlags; |
| const MemoryRequirement consumerMemReqs = MemoryRequirement::HostVisible | MemoryRequirement::Coherent; |
| const VkBufferUsageFlags consumerUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; |
| const VkDeviceSize consumerBuffSize = (width * height * sizeof(uint32_t)); |
| const VkBufferCreateInfo consumerBuffInfo = makeBufferCreateInfo(consumerBuffSize, consumerUsage, {consumerIndex}, consumerCreateFlags); |
| BufferWithMemory consumerBuffer (vki, vkd, phys, device, allocator, consumerBuffInfo, consumerMemReqs, consumerQueue); |
| const VkDescriptorBufferInfo consumerInfo = makeDescriptorBufferInfo(*consumerBuffer, 0, consumerBuffSize); |
| |
| const VkBufferCreateFlags tmpCreateFlags = graphCreateFlags; |
| const MemoryRequirement tmpMemReqs = MemoryRequirement::HostVisible | MemoryRequirement::Coherent; |
| const VkBufferUsageFlags tmpUsage = (VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); |
| const VkDeviceSize tmpBuffSize = (width * height * sizeof(uint32_t)); |
| const VkBufferCreateInfo tmpBuffInfo = makeBufferCreateInfo(tmpBuffSize, tmpUsage, {consumerIndex}, tmpCreateFlags); |
| BufferWithMemory tmpBuffer (vki, vkd, phys, device, allocator, tmpBuffInfo, tmpMemReqs, consumerQueue); |
| const VkBufferImageCopy tmpCopyRegion = makeBufferImageCopy(makeExtent3D(width, height, 1), |
| makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u)); |
| |
| Move<VkDescriptorPool> dsPool = DescriptorPoolBuilder() |
| .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) |
| .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) |
| .build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u); |
| Move<VkDescriptorSetLayout> dsLayout = DescriptorSetLayoutBuilder() |
| .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_ALL) |
| .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL) |
| .build(vkd, device); |
| Move<VkDescriptorSet> descriptorSet = makeDescriptorSet(vkd, device, *dsPool, *dsLayout); |
| |
| DescriptorSetUpdateBuilder() |
| .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &producerImageInfo) |
| .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &consumerInfo) |
| .update(vkd, device); |
| |
| Move<VkRenderPass> renderPass = makeRenderPass(vkd, device, m_config.format); |
| Move<VkFramebuffer> framebuffer = makeFramebuffer(vkd, device, *renderPass, *producerView, width, height); |
| |
| const VkImageMemoryBarrier producerReadyBarrier= makeImageMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_NONE, |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL, |
| **producerImage, producerResRange); |
| // const VkBufferMemoryBarrier consumerReadyBarrier= makeBufferMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_NONE, |
| // *consumerBuffer, 0, consumerBuffSize, |
| // consumerIndex, consumerIndex); |
| //const VkMemoryBarrier tmpReadyBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT); |
| // const VkBufferMemoryBarrier tmpReadyBarrier = makeBufferMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_NONE, |
| // *tmpBuffer, 0, tmpBuffSize, |
| // consumerIndex, consumerIndex); |
| const VkBufferMemoryBarrier consumerBarriers[] { makeBufferMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_NONE, |
| *consumerBuffer, 0, consumerBuffSize, |
| consumerIndex, consumerIndex), |
| makeBufferMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_NONE, |
| *tmpBuffer, 0, tmpBuffSize, |
| consumerIndex, consumerIndex) }; |
| struct PushConstant |
| { uint32_t width, height; } pc { width, height }; |
| Move<VkPipelineLayout> pipelineLayout = createPipelineLayout<PushConstant>({ *dsLayout }); |
| Move<VkPipeline> producerPipeline = createGraphicsPipeline(*pipelineLayout, *renderPass); |
| Move<VkPipeline> consumerPipeline = createComputePipeline(*pipelineLayout); |
| |
| Move<VkCommandPool> producerPool = makeCommandPool(vkd, device, producerIndex); |
| Move<VkCommandPool> consumerPool = makeCommandPool(vkd, device, consumerIndex); |
| Move<VkCommandBuffer> producerCmd = allocateCommandBuffer(vkd, device, *producerPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY); |
| Move<VkCommandBuffer> consumerCmd = allocateCommandBuffer(vkd, device, *consumerPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY); |
| |
| { |
| std::vector<float> vertices; |
| std::vector<uint32_t> indices; |
| CheckerboardBuilder builder(width, height); |
| builder.buildVerticesAndIndices(vertices, indices); |
| DE_ASSERT(vertices.size() == (vertexCount * 2)); |
| DE_ASSERT(indices.size() == indexCount); |
| std::copy(vertices.begin(), vertices.end(), begin<float>(vertexBuffer.getHostPtr())); |
| std::copy(indices.begin(), indices.end(), begin<uint32_t>(indexBuffer.getHostPtr())); |
| vertexBuffer.flushAlloc(vkd, device); |
| indexBuffer.flushAlloc(vkd, device); |
| } |
| |
| beginCommandBuffer(vkd, *producerCmd); |
| vkd.cmdBindPipeline(*producerCmd, VK_PIPELINE_BIND_POINT_GRAPHICS, *producerPipeline); |
| vkd.cmdBindVertexBuffers(*producerCmd, 0, 1, &static_cast<const VkBuffer&>(*vertexBuffer), &static_cast<const VkDeviceSize&>(0)); |
| vkd.cmdBindIndexBuffer(*producerCmd, *indexBuffer, 0, VK_INDEX_TYPE_UINT32); |
| beginRenderPass(vkd, *producerCmd, *renderPass, *framebuffer, makeRect2D(width, height), clearColor); |
| vkd.cmdDrawIndexed(*producerCmd, indexCount, 1, 0, 0, 0); |
| endRenderPass(vkd, *producerCmd); |
| vkd.cmdPipelineBarrier(*producerCmd, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VkDependencyFlags(0), |
| 0u, nullptr, 0u, nullptr, 1u, &producerReadyBarrier); |
| endCommandBuffer(vkd, *producerCmd); |
| |
| beginCommandBuffer(vkd, *consumerCmd); |
| vkd.cmdBindPipeline(*consumerCmd, VK_PIPELINE_BIND_POINT_COMPUTE, *consumerPipeline); |
| vkd.cmdBindDescriptorSets(*consumerCmd, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0, 1, &descriptorSet.get(), 0, nullptr); |
| vkd.cmdCopyImageToBuffer(*consumerCmd, **producerImage, VK_IMAGE_LAYOUT_GENERAL, *tmpBuffer, 1u, &tmpCopyRegion); |
| vkd.cmdPushConstants(*consumerCmd, *pipelineLayout, VK_SHADER_STAGE_ALL, 0, static_cast<uint32_t>(sizeof(PushConstant)), &pc); |
| vkd.cmdDispatch(*consumerCmd, width, height, 1); |
| vkd.cmdPipelineBarrier(*consumerCmd, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VkDependencyFlags(0), |
| 0, nullptr, DE_LENGTH_OF_ARRAY(consumerBarriers), consumerBarriers, 0, nullptr); |
| endCommandBuffer(vkd, *consumerCmd); |
| |
| submitCommands(*producerCmd, *consumerCmd); |
| |
| tmpBuffer.invalidateAlloc(vkd, device); |
| const tcu::ConstPixelBufferAccess tmpBufferAccess(mapVkFormat(m_config.format), width, height, 1, tmpBuffer.getHostPtr()); |
| const bool tmpRes = verify(tmpBufferAccess, GPQCase::testValue, clearComp); |
| |
| consumerBuffer.invalidateAlloc(vkd, device); |
| const tcu::ConstPixelBufferAccess resultBufferAccess(mapVkFormat(m_config.format), width, height, 1, consumerBuffer.getHostPtr()); |
| |
| return (tmpRes && verify(resultBufferAccess, (GPQCase::testValue + 1), (clearComp + 1))) ? tcu::TestStatus::pass("") : tcu::TestStatus::fail(""); |
| } |
| |
| bool GPQInstanceBase::verify (const BufferAccess& result, deUint32 blackColor, deUint32 whiteColor) const |
| { |
| bool ok = true; |
| |
| for (deUint32 y = 0; ok && y < m_config.height; ++y) |
| { |
| for (deUint32 x = 0; ok && x < m_config.width; ++x) |
| { |
| const deUint32 color = result.getPixelT<deUint32>(x, y).x(); |
| if (((x + y) % 2) == 0) |
| { |
| ok = color == blackColor; |
| } |
| else |
| { |
| ok = color == whiteColor; |
| } |
| } |
| } |
| return ok; |
| } |
| |
| } // anonymous |
| |
| tcu::TestCaseGroup* createGlobalPriorityQueueTests (tcu::TestContext& testCtx) |
| { |
| typedef std::pair<VkQueueFlagBits, const char*> TransitionItem; |
| TransitionItem const transitions[] |
| { |
| { VK_QUEUE_GRAPHICS_BIT, "graphics" }, |
| { VK_QUEUE_COMPUTE_BIT, "compute" }, |
| }; |
| |
| auto mkGroupName = [](const TransitionItem& from, const TransitionItem& to) -> std::string |
| { |
| return std::string("from_") + from.second + std::string("_to_") + to.second; |
| }; |
| |
| std::pair<VkQueueFlags, const char*> |
| const modifiers[] |
| { |
| { 0, "no_modifiers" }, |
| { VK_QUEUE_SPARSE_BINDING_BIT, "sparse" }, |
| { VK_QUEUE_PROTECTED_BIT, "protected" }, |
| { VK_QUEUE_SPARSE_BINDING_BIT|VK_QUEUE_PROTECTED_BIT, "sparse_protected" }, |
| }; |
| |
| std::pair<VkQueueGlobalPriorityKHR, const char*> |
| const prios[] |
| { |
| { VK_QUEUE_GLOBAL_PRIORITY_LOW_KHR, "low" }, |
| { VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR, "medium" }, |
| { VK_QUEUE_GLOBAL_PRIORITY_HIGH_KHR, "high" }, |
| { VK_QUEUE_GLOBAL_PRIORITY_REALTIME_KHR, "realtime" }, |
| }; |
| |
| std::pair<SyncType, const char*> |
| const syncs[] |
| { |
| { SyncType::None, "no_sync" }, |
| { SyncType::Semaphore, "semaphore" }, |
| }; |
| |
| const uint32_t dim0 = 34; |
| const uint32_t dim1 = 25; |
| bool swap = true; |
| |
| auto rootGroup = new tcu::TestCaseGroup(testCtx, "global_priority_transition", "Global Priority Queue Tests"); |
| |
| for (const auto& prio : prios) |
| { |
| auto prioGroup = new tcu::TestCaseGroup(testCtx, prio.second, ""); |
| |
| for (const auto& sync : syncs) |
| { |
| auto syncGroup = new tcu::TestCaseGroup(testCtx, sync.second, ""); |
| |
| for (const auto& mod : modifiers) |
| { |
| auto modGroup = new tcu::TestCaseGroup(testCtx, mod.second, ""); |
| |
| for (const auto& transitionFrom : transitions) |
| { |
| for (const auto& transitionTo : transitions) |
| { |
| if (transitionFrom != transitionTo) |
| { |
| TestConfig cfg{}; |
| cfg.transitionFrom = transitionFrom.first; |
| cfg.transitionTo = transitionTo.first; |
| cfg.priorityFrom = prio.first; |
| cfg.priorityTo = prio.first; |
| cfg.syncType = sync.first; |
| cfg.enableProtected = (mod.first & VK_QUEUE_PROTECTED_BIT) != 0; |
| cfg.enableSparseBinding = (mod.first & VK_QUEUE_SPARSE_BINDING_BIT) != 0; |
| // Note that format is changing in GPQCase::checkSupport(...) |
| cfg.format = VK_FORMAT_R32G32B32A32_SFLOAT; |
| cfg.width = swap ? dim0 : dim1; |
| cfg.height = swap ? dim1 : dim0; |
| |
| swap ^= true; |
| |
| modGroup->addChild(new GPQCase(testCtx, mkGroupName(transitionFrom, transitionTo), cfg)); |
| } |
| } |
| } |
| syncGroup->addChild(modGroup); |
| } |
| prioGroup->addChild(syncGroup); |
| } |
| rootGroup->addChild(prioGroup); |
| } |
| |
| return rootGroup; |
| } |
| |
| } // synchronization |
| } // vkt |