| /*------------------------------------------------------------------------ |
| * Vulkan Conformance Tests |
| * ------------------------ |
| * |
| * Copyright (c) 2021 The Khronos Group Inc. |
| * Copyright (c) 2023 LunarG, Inc. |
| * Copyright (c) 2023 Nintendo |
| * |
| * 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 |
| * \brief Tests Verifying Graphics Pipeline Libraries |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "vktPipelineLibraryTests.hpp" |
| |
| #include "tcuTextureUtil.hpp" |
| #include "vkDefs.hpp" |
| #include "vkCmdUtil.hpp" |
| #include "vkObjUtil.hpp" |
| #include "vkTypeUtil.hpp" |
| #include "vkQueryUtil.hpp" |
| #include "vkImageUtil.hpp" |
| #include "vkBarrierUtil.hpp" |
| #include "vkBufferWithMemory.hpp" |
| #include "vkImageWithMemory.hpp" |
| #include "vkBuilderUtil.hpp" |
| #include "vkRayTracingUtil.hpp" |
| #include "vktTestCase.hpp" |
| #include "vktTestGroupUtil.hpp" |
| #include "vktCustomInstancesDevices.hpp" |
| #include "tcuCommandLine.hpp" |
| #include "tcuImageCompare.hpp" |
| #include "tcuTestLog.hpp" |
| #include "tcuRGBA.hpp" |
| |
| #include "../draw/vktDrawCreateInfoUtil.hpp" |
| #include "deMath.h" |
| #include "deRandom.hpp" |
| #include "deClock.h" |
| |
| #include <vector> |
| #include <chrono> |
| #include <set> |
| #include <limits> |
| |
| namespace vkt |
| { |
| namespace pipeline |
| { |
| namespace |
| { |
| using namespace vk; |
| using namespace vkt; |
| using namespace tcu; |
| |
| static const uint32_t RENDER_SIZE_WIDTH = 16u; |
| static const uint32_t RENDER_SIZE_HEIGHT = 16u; |
| static const VkColorComponentFlags COLOR_COMPONENTS_NO_RED = |
| VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; |
| static const VkColorComponentFlags ALL_COLOR_COMPONENTS = |
| VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; |
| static const int numClipDistances = 5; |
| static const int numCullDistances = 3; |
| static const VkGraphicsPipelineLibraryFlagBitsEXT GRAPHICS_PIPELINE_LIBRARY_FLAGS[] = { |
| VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT, |
| VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT, |
| VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT, |
| VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT, |
| }; |
| static const VkGraphicsPipelineLibraryFlagsEXT ALL_GRAPHICS_PIPELINE_LIBRARY_FLAGS = |
| static_cast<VkGraphicsPipelineLibraryFlagsEXT>(VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT) | |
| static_cast<VkGraphicsPipelineLibraryFlagsEXT>(VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT) | |
| static_cast<VkGraphicsPipelineLibraryFlagsEXT>(VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT) | |
| static_cast<VkGraphicsPipelineLibraryFlagsEXT>(VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT); |
| |
| struct PipelineTreeNode |
| { |
| int32_t parentIndex; |
| uint32_t shaderCount; |
| }; |
| |
| typedef std::vector<PipelineTreeNode> PipelineTreeConfiguration; |
| |
| struct TestParams |
| { |
| PipelineTreeConfiguration pipelineTreeConfiguration; |
| bool optimize; |
| bool delayedShaderCreate; |
| bool useMaintenance5; |
| }; |
| |
| struct RuntimePipelineTreeNode |
| { |
| int32_t parentIndex; |
| VkGraphicsPipelineLibraryFlagsEXT graphicsPipelineLibraryFlags; |
| VkGraphicsPipelineLibraryFlagsEXT subtreeGraphicsPipelineLibraryFlags; |
| Move<VkPipeline> pipeline; |
| std::vector<VkPipeline> pipelineLibraries; |
| // We need to track the linked libraries too, included in VkPipelineLibraryCreateInfoKHR->pLibraries |
| std::vector<VkGraphicsPipelineLibraryFlagsEXT> linkedLibraryFlags; |
| }; |
| |
| typedef std::vector<RuntimePipelineTreeNode> RuntimePipelineTreeConfiguration; |
| |
| inline UVec4 ivec2uvec(const IVec4 &ivec) |
| { |
| return UVec4{ |
| static_cast<uint32_t>(ivec[0]), |
| static_cast<uint32_t>(ivec[1]), |
| static_cast<uint32_t>(ivec[2]), |
| static_cast<uint32_t>(ivec[3]), |
| }; |
| } |
| |
| inline std::string getTestName(const PipelineTreeConfiguration &pipelineTreeConfiguration) |
| { |
| std::string result; |
| int level = pipelineTreeConfiguration[0].parentIndex; |
| |
| for (const auto &node : pipelineTreeConfiguration) |
| { |
| if (level != node.parentIndex) |
| { |
| DE_ASSERT(level < node.parentIndex); |
| |
| result += '_'; |
| |
| level = node.parentIndex; |
| } |
| |
| result += de::toString(node.shaderCount); |
| } |
| |
| return result; |
| } |
| |
| inline VkPipelineCreateFlags calcPipelineCreateFlags(bool optimize, bool buildLibrary) |
| { |
| VkPipelineCreateFlags result = 0; |
| |
| if (buildLibrary) |
| result |= static_cast<VkPipelineCreateFlags>(VK_PIPELINE_CREATE_LIBRARY_BIT_KHR); |
| |
| if (optimize) |
| { |
| if (buildLibrary) |
| result |= static_cast<VkPipelineCreateFlags>(VK_PIPELINE_CREATE_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT); |
| else |
| result |= static_cast<VkPipelineCreateFlags>(VK_PIPELINE_CREATE_LINK_TIME_OPTIMIZATION_BIT_EXT); |
| } |
| |
| return result; |
| } |
| |
| inline VkRenderPass getRenderPass(VkGraphicsPipelineLibraryFlagsEXT subset, VkRenderPass renderPass) |
| { |
| static const VkGraphicsPipelineLibraryFlagsEXT subsetRequiresRenderPass = |
| static_cast<VkGraphicsPipelineLibraryFlagsEXT>(VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT) | |
| static_cast<VkGraphicsPipelineLibraryFlagsEXT>(VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT) | |
| static_cast<VkGraphicsPipelineLibraryFlagsEXT>(VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT); |
| if ((subsetRequiresRenderPass & subset) != 0) |
| return renderPass; |
| |
| return VK_NULL_HANDLE; |
| } |
| |
| inline VkGraphicsPipelineLibraryCreateInfoEXT makeGraphicsPipelineLibraryCreateInfo( |
| const VkGraphicsPipelineLibraryFlagsEXT flags) |
| { |
| const VkGraphicsPipelineLibraryCreateInfoEXT graphicsPipelineLibraryCreateInfo = { |
| VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_LIBRARY_CREATE_INFO_EXT, // VkStructureType sType; |
| DE_NULL, // void* pNext; |
| flags, // VkGraphicsPipelineLibraryFlagsEXT flags; |
| }; |
| |
| return graphicsPipelineLibraryCreateInfo; |
| } |
| |
| inline VkPipelineLibraryCreateInfoKHR makePipelineLibraryCreateInfo(const std::vector<VkPipeline> &pipelineLibraries) |
| { |
| const uint32_t libraryCount = static_cast<uint32_t>(pipelineLibraries.size()); |
| const VkPipeline *libraries = de::dataOrNull(pipelineLibraries); |
| const VkPipelineLibraryCreateInfoKHR pipelineLibraryCreateInfo = { |
| VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| libraryCount, // uint32_t libraryCount; |
| libraries, // const VkPipeline* pLibraries; |
| }; |
| |
| return pipelineLibraryCreateInfo; |
| } |
| |
| inline std::string getGraphicsPipelineLibraryFlagsString(const VkGraphicsPipelineLibraryFlagsEXT flags) |
| { |
| std::string result; |
| |
| if ((flags & VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT) != 0) |
| result += "VERTEX_INPUT_INTERFACE "; |
| if ((flags & VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT) != 0) |
| result += "PRE_RASTERIZATION_SHADERS "; |
| if ((flags & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT) != 0) |
| result += "FRAGMENT_SHADER "; |
| if ((flags & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT) != 0) |
| result += "FRAGMENT_OUTPUT_INTERFACE "; |
| |
| if (!result.empty()) |
| result.resize(result.size() - 1); |
| |
| return result; |
| }; |
| |
| VkImageCreateInfo makeColorImageCreateInfo(const VkFormat format, const uint32_t width, const uint32_t height) |
| { |
| const VkImageUsageFlags usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; |
| const VkImageCreateInfo imageInfo = { |
| VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkImageCreateFlags)0, // VkImageCreateFlags flags; |
| VK_IMAGE_TYPE_2D, // VkImageType imageType; |
| format, // VkFormat format; |
| makeExtent3D(width, height, 1), // VkExtent3D extent; |
| 1u, // uint32_t mipLevels; |
| 1u, // uint32_t arrayLayers; |
| VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; |
| VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; |
| usage, // VkImageUsageFlags usage; |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; |
| 0u, // uint32_t queueFamilyIndexCount; |
| DE_NULL, // const uint32_t* pQueueFamilyIndices; |
| VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; |
| }; |
| |
| return imageInfo; |
| } |
| |
| VkImageViewCreateInfo makeImageViewCreateInfo(VkImage image, VkFormat format, VkImageAspectFlags aspectMask) |
| { |
| const VkComponentMapping components = { |
| VK_COMPONENT_SWIZZLE_R, |
| VK_COMPONENT_SWIZZLE_G, |
| VK_COMPONENT_SWIZZLE_B, |
| VK_COMPONENT_SWIZZLE_A, |
| }; |
| const VkImageSubresourceRange subresourceRange = { |
| aspectMask, // VkImageAspectFlags aspectMask; |
| 0, // uint32_t baseMipLevel; |
| 1, // uint32_t levelCount; |
| 0, // uint32_t baseArrayLayer; |
| 1, // uint32_t layerCount; |
| }; |
| const VkImageViewCreateInfo result = { |
| VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkImageViewCreateFlags flags; |
| image, // VkImage image; |
| VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType; |
| format, // VkFormat format; |
| components, // VkComponentMapping components; |
| subresourceRange, // VkImageSubresourceRange subresourceRange; |
| }; |
| |
| return result; |
| } |
| |
| VkImageCreateInfo makeDepthImageCreateInfo(const VkFormat format, const uint32_t width, const uint32_t height) |
| { |
| const VkImageUsageFlags usage = |
| VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; |
| const VkImageCreateInfo imageInfo = { |
| VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkImageCreateFlags)0, // VkImageCreateFlags flags; |
| VK_IMAGE_TYPE_2D, // VkImageType imageType; |
| format, // VkFormat format; |
| makeExtent3D(width, height, 1), // VkExtent3D extent; |
| 1u, // uint32_t mipLevels; |
| 1u, // uint32_t arrayLayers; |
| VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; |
| VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; |
| usage, // VkImageUsageFlags usage; |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; |
| 0u, // uint32_t queueFamilyIndexCount; |
| DE_NULL, // const uint32_t* pQueueFamilyIndices; |
| VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; |
| }; |
| |
| return imageInfo; |
| } |
| |
| const VkFramebufferCreateInfo makeFramebufferCreateInfo(const VkRenderPass renderPass, const uint32_t attachmentCount, |
| const VkImageView *attachments, const uint32_t width, |
| const uint32_t height) |
| { |
| const VkFramebufferCreateInfo result = { |
| VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0, // VkFramebufferCreateFlags flags; |
| renderPass, // VkRenderPass renderPass; |
| attachmentCount, // uint32_t attachmentCount; |
| attachments, // const VkImageView* pAttachments; |
| width, // uint32_t width; |
| height, // uint32_t height; |
| 1, // uint32_t layers; |
| }; |
| |
| return result; |
| } |
| |
| const VkPipelineMultisampleStateCreateInfo makePipelineMultisampleStateCreateInfo(void) |
| { |
| const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo = { |
| VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkPipelineMultisampleStateCreateFlags flags; |
| VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples; |
| false, // VkBool32 sampleShadingEnable; |
| 0.0f, // float minSampleShading; |
| DE_NULL, // const VkSampleMask* pSampleMask; |
| false, // VkBool32 alphaToCoverageEnable; |
| false, // VkBool32 alphaToOneEnable; |
| }; |
| |
| return pipelineMultisampleStateCreateInfo; |
| } |
| |
| class GraphicsPipelineCreateInfo : public ::vkt::Draw::PipelineCreateInfo |
| { |
| public: |
| GraphicsPipelineCreateInfo(vk::VkPipelineLayout _layout, vk::VkRenderPass _renderPass, int _subpass, |
| vk::VkPipelineCreateFlags _flags) |
| : ::vkt::Draw::PipelineCreateInfo(_layout, _renderPass, _subpass, _flags) |
| , m_vertexInputBindingDescription() |
| , m_vertexInputAttributeDescription() |
| , m_shaderModuleCreateInfoCount(0) |
| , m_shaderModuleCreateInfo{initVulkanStructure(), initVulkanStructure()} |
| , m_pipelineShaderStageCreateInfo() |
| , m_vertModule() |
| , m_fragModule() |
| { |
| } |
| |
| VkVertexInputBindingDescription m_vertexInputBindingDescription; |
| VkVertexInputAttributeDescription m_vertexInputAttributeDescription; |
| uint32_t m_shaderModuleCreateInfoCount; |
| VkShaderModuleCreateInfo m_shaderModuleCreateInfo[2]; |
| std::vector<VkPipelineShaderStageCreateInfo> m_pipelineShaderStageCreateInfo; |
| Move<VkShaderModule> m_vertModule; |
| Move<VkShaderModule> m_fragModule; |
| Move<VkShaderModule> m_meshModule; |
| }; |
| |
| void updateVertexInputInterface(Context &context, GraphicsPipelineCreateInfo &graphicsPipelineCreateInfo, |
| VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, |
| uint32_t vertexDescriptionCount = 1u) |
| { |
| DE_UNREF(context); |
| |
| graphicsPipelineCreateInfo.m_vertexInputBindingDescription = { |
| 0u, // uint32_t binding; |
| sizeof(tcu::Vec4), // uint32_t strideInBytes; |
| VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate; |
| }; |
| graphicsPipelineCreateInfo.m_vertexInputAttributeDescription = { |
| 0u, // uint32_t location; |
| 0u, // uint32_t binding; |
| VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format; |
| 0u // uint32_t offsetInBytes; |
| }; |
| |
| const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo{ |
| VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkPipelineVertexInputStateCreateFlags flags; |
| vertexDescriptionCount, // uint32_t vertexBindingDescriptionCount; |
| &graphicsPipelineCreateInfo |
| .m_vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions; |
| vertexDescriptionCount, // uint32_t vertexAttributeDescriptionCount; |
| &graphicsPipelineCreateInfo |
| .m_vertexInputAttributeDescription, // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions; |
| }; |
| const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo{ |
| VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkPipelineInputAssemblyStateCreateFlags flags; |
| topology, // VkPrimitiveTopology topology; |
| VK_FALSE, // VkBool32 primitiveRestartEnable; |
| }; |
| |
| graphicsPipelineCreateInfo.addState(vertexInputStateCreateInfo); |
| graphicsPipelineCreateInfo.addState(inputAssemblyStateCreateInfo); |
| } |
| |
| void updatePreRasterization(Context &context, GraphicsPipelineCreateInfo &graphicsPipelineCreateInfo, |
| bool delayedShaderCreate, bool useDynamicViewPort = false, bool useMeshShader = false, |
| VkPolygonMode polygonMode = VK_POLYGON_MODE_FILL, |
| const VkSpecializationInfo *specializationInfo = DE_NULL) |
| { |
| const std::string shaderName = (useMeshShader ? "mesh" : "vert"); |
| const ProgramBinary &shaderBinary = context.getBinaryCollection().get(shaderName); |
| VkShaderModuleCreateInfo &shaderModuleCreateInfo = |
| graphicsPipelineCreateInfo.m_shaderModuleCreateInfo[graphicsPipelineCreateInfo.m_shaderModuleCreateInfoCount]; |
| |
| DE_ASSERT(graphicsPipelineCreateInfo.m_shaderModuleCreateInfoCount < |
| DE_LENGTH_OF_ARRAY(graphicsPipelineCreateInfo.m_shaderModuleCreateInfo)); |
| |
| shaderModuleCreateInfo = { |
| VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkShaderModuleCreateFlags flags; |
| (uintptr_t)shaderBinary.getSize(), // uintptr_t codeSize; |
| (uint32_t *)shaderBinary.getBinary(), // const uint32_t* pCode; |
| }; |
| |
| if (!delayedShaderCreate) |
| { |
| const DeviceInterface &vk = context.getDeviceInterface(); |
| const VkDevice device = context.getDevice(); |
| |
| Move<VkShaderModule> shaderMod = createShaderModule(vk, device, &shaderModuleCreateInfo); |
| if (useMeshShader) |
| graphicsPipelineCreateInfo.m_meshModule = shaderMod; |
| else |
| graphicsPipelineCreateInfo.m_vertModule = shaderMod; |
| } |
| |
| const void *pNext = delayedShaderCreate ? &shaderModuleCreateInfo : DE_NULL; |
| const VkShaderModule shaderModule = |
| delayedShaderCreate ? |
| VK_NULL_HANDLE : |
| (useMeshShader ? *graphicsPipelineCreateInfo.m_meshModule : *graphicsPipelineCreateInfo.m_vertModule); |
| const VkPipelineShaderStageCreateInfo pipelineShaderStageCreateInfo = { |
| VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; |
| pNext, // const void* pNext; |
| 0u, // VkPipelineShaderStageCreateFlags flags; |
| (useMeshShader ? VK_SHADER_STAGE_MESH_BIT_EXT // VkShaderStageFlagBits stage; |
| : |
| VK_SHADER_STAGE_VERTEX_BIT), |
| shaderModule, // VkShaderModule module; |
| "main", // const char* pName; |
| specializationInfo // const VkSpecializationInfo* pSpecializationInfo; |
| }; |
| |
| shaderBinary.setUsed(); |
| |
| // Within the VkPipelineLayout, all bindings that affect the specified shader stages |
| const VkViewport viewport = makeViewport(RENDER_SIZE_WIDTH, RENDER_SIZE_HEIGHT); |
| const VkRect2D scissor = makeRect2D(3 * RENDER_SIZE_WIDTH / 4, RENDER_SIZE_HEIGHT); |
| const VkPipelineViewportStateCreateInfo pipelineViewportStateCreateInfo = { |
| VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkPipelineViewportStateCreateFlags flags; |
| 1u, // uint32_t viewportCount; |
| &viewport, // const VkViewport* pViewports; |
| 1u, // uint32_t scissorCount; |
| &scissor // const VkRect2D* pScissors; |
| }; |
| std::vector<VkDynamicState> dynamicStates = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR}; |
| const VkPipelineDynamicStateCreateInfo pipelineDynamicState = { |
| VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType; |
| nullptr, // const void* pNext; |
| 0u, // VkPipelineDynamicStateCreateFlags flags; |
| de::sizeU32(dynamicStates), // uint32_t dynamicStateCount; |
| de::dataOrNull(dynamicStates) // const VkDynamicState* pDynamicStates; |
| }; |
| const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateCreateInfo = { |
| VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkPipelineRasterizationStateCreateFlags flags; |
| VK_FALSE, // VkBool32 depthClampEnable; |
| VK_FALSE, // VkBool32 rasterizerDiscardEnable; |
| polygonMode, // VkPolygonMode polygonMode; |
| VK_CULL_MODE_NONE, // VkCullModeFlags cullMode; |
| VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace; |
| VK_FALSE, // VkBool32 depthBiasEnable; |
| 0.0f, // float depthBiasConstantFactor; |
| 0.0f, // float depthBiasClamp; |
| 0.0f, // float depthBiasSlopeFactor; |
| 1.0f, // float lineWidth; |
| }; |
| |
| graphicsPipelineCreateInfo.m_shaderModuleCreateInfoCount++; |
| |
| graphicsPipelineCreateInfo.addShader(pipelineShaderStageCreateInfo); |
| graphicsPipelineCreateInfo.addState(pipelineViewportStateCreateInfo); |
| graphicsPipelineCreateInfo.addState(pipelineRasterizationStateCreateInfo); |
| |
| if (useDynamicViewPort) |
| graphicsPipelineCreateInfo.addState(pipelineDynamicState); |
| } |
| |
| void updatePostRasterization(Context &context, GraphicsPipelineCreateInfo &graphicsPipelineCreateInfo, |
| bool delayedShaderCreate, bool enableDepth = true, |
| const VkSpecializationInfo *specializationInfo = DE_NULL) |
| { |
| const ProgramBinary &shaderBinary = context.getBinaryCollection().get("frag"); |
| VkShaderModuleCreateInfo &shaderModuleCreateInfo = |
| graphicsPipelineCreateInfo.m_shaderModuleCreateInfo[graphicsPipelineCreateInfo.m_shaderModuleCreateInfoCount]; |
| |
| DE_ASSERT(graphicsPipelineCreateInfo.m_shaderModuleCreateInfoCount < |
| DE_LENGTH_OF_ARRAY(graphicsPipelineCreateInfo.m_shaderModuleCreateInfo)); |
| |
| shaderModuleCreateInfo = { |
| VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkShaderModuleCreateFlags flags; |
| (uintptr_t)shaderBinary.getSize(), // uintptr_t codeSize; |
| (uint32_t *)shaderBinary.getBinary(), // const uint32_t* pCode; |
| }; |
| |
| if (!delayedShaderCreate) |
| { |
| const DeviceInterface &vk = context.getDeviceInterface(); |
| const VkDevice device = context.getDevice(); |
| |
| graphicsPipelineCreateInfo.m_fragModule = createShaderModule(vk, device, &shaderModuleCreateInfo); |
| } |
| |
| const void *pNext = delayedShaderCreate ? &shaderModuleCreateInfo : DE_NULL; |
| const VkShaderModule shaderModule = delayedShaderCreate ? VK_NULL_HANDLE : *graphicsPipelineCreateInfo.m_fragModule; |
| const VkPipelineShaderStageCreateInfo pipelineShaderStageCreateInfo = { |
| VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; |
| pNext, // const void* pNext; |
| 0u, // VkPipelineShaderStageCreateFlags flags; |
| VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlagBits stage; |
| shaderModule, // VkShaderModule module; |
| "main", // const char* pName; |
| specializationInfo // const VkSpecializationInfo* pSpecializationInfo; |
| }; |
| |
| shaderBinary.setUsed(); |
| |
| // Within the VkPipelineLayout, all bindings that affect the fragment shader stage |
| |
| const VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateCreateInfo = { |
| VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkPipelineDepthStencilStateCreateFlags flags; |
| enableDepth, // VkBool32 depthTestEnable; |
| enableDepth, // VkBool32 depthWriteEnable; |
| VK_COMPARE_OP_LESS_OR_EQUAL, // VkCompareOp depthCompareOp; |
| VK_FALSE, // VkBool32 depthBoundsTestEnable; |
| VK_FALSE, // VkBool32 stencilTestEnable; |
| { |
| // VkStencilOpState front; |
| VK_STENCIL_OP_KEEP, // VkStencilOp failOp; |
| VK_STENCIL_OP_KEEP, // VkStencilOp passOp; |
| VK_STENCIL_OP_KEEP, // VkStencilOp depthFailOp; |
| VK_COMPARE_OP_NEVER, // VkCompareOp compareOp; |
| 0u, // uint32_t compareMask; |
| 0u, // uint32_t writeMask; |
| 0u, // uint32_t reference; |
| }, |
| { |
| // VkStencilOpState back; |
| VK_STENCIL_OP_KEEP, // VkStencilOp failOp; |
| VK_STENCIL_OP_KEEP, // VkStencilOp passOp; |
| VK_STENCIL_OP_KEEP, // VkStencilOp depthFailOp; |
| VK_COMPARE_OP_NEVER, // VkCompareOp compareOp; |
| 0u, // uint32_t compareMask; |
| 0u, // uint32_t writeMask; |
| 0u, // uint32_t reference; |
| }, |
| 0.0f, // float minDepthBounds; |
| 1.0f, // float maxDepthBounds; |
| }; |
| |
| graphicsPipelineCreateInfo.m_shaderModuleCreateInfoCount++; |
| graphicsPipelineCreateInfo.addShader(pipelineShaderStageCreateInfo); |
| |
| DE_ASSERT(graphicsPipelineCreateInfo.pDepthStencilState == DE_NULL); |
| graphicsPipelineCreateInfo.addState(pipelineDepthStencilStateCreateInfo); |
| |
| if (graphicsPipelineCreateInfo.pMultisampleState == DE_NULL) |
| { |
| const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo = |
| makePipelineMultisampleStateCreateInfo(); |
| |
| graphicsPipelineCreateInfo.addState(pipelineMultisampleStateCreateInfo); |
| } |
| } |
| |
| void updateFragmentOutputInterface(Context &context, GraphicsPipelineCreateInfo &graphicsPipelineCreateInfo, |
| VkColorComponentFlags colorWriteMask = COLOR_COMPONENTS_NO_RED) |
| { |
| DE_UNREF(context); |
| |
| // Number of blend attachments must equal the number of color attachments during any subpass. |
| const VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState = { |
| VK_FALSE, // VkBool32 blendEnable; |
| VK_BLEND_FACTOR_ONE, // VkBlendFactor srcColorBlendFactor; |
| VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor; |
| VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp; |
| VK_BLEND_FACTOR_ONE, // VkBlendFactor srcAlphaBlendFactor; |
| VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor; |
| VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp; |
| colorWriteMask, // VkColorComponentFlags colorWriteMask; |
| }; |
| const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateCreateInfo = { |
| VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineColorBlendStateCreateFlags)0, // VkPipelineColorBlendStateCreateFlags flags; |
| VK_FALSE, // VkBool32 logicOpEnable; |
| VK_LOGIC_OP_COPY, // VkLogicOp logicOp; |
| 1u, // uint32_t attachmentCount; |
| &pipelineColorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments; |
| {0.0f, 0.0f, 0.0f, 0.0f}, // float blendConstants[4]; |
| }; |
| |
| graphicsPipelineCreateInfo.addState(pipelineColorBlendStateCreateInfo); |
| |
| if (graphicsPipelineCreateInfo.pMultisampleState == DE_NULL) |
| { |
| const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo = |
| makePipelineMultisampleStateCreateInfo(); |
| |
| graphicsPipelineCreateInfo.addState(pipelineMultisampleStateCreateInfo); |
| } |
| } |
| |
| /* |
| To test that each of graphics pipeline libraries have influence on final pipeline |
| the functions have following features: |
| |
| updateVertexInputInterface |
| VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST |
| VK_VERTEX_INPUT_RATE_VERTEX |
| Z is read from uniform and written in shader |
| |
| updatePreRasterization |
| VkRect2D scissor = makeRect2D(3 * RENDER_SIZE_WIDTH / 4, RENDER_SIZE_HEIGHT); |
| |
| updatePostRasterization |
| Fragment shader top and bottom colors read from uniform buffer |
| |
| updateFragmentOutputInterface |
| Cut off red component |
| */ |
| |
| class PipelineLibraryTestInstance : public TestInstance |
| { |
| public: |
| PipelineLibraryTestInstance(Context &context, const TestParams &data); |
| ~PipelineLibraryTestInstance(void); |
| tcu::TestStatus iterate(void); |
| |
| protected: |
| de::MovePtr<BufferWithMemory> makeVertexBuffer(void); |
| de::MovePtr<BufferWithMemory> makeZCoordBuffer(void); |
| de::MovePtr<BufferWithMemory> makePaletteBuffer(void); |
| Move<VkDescriptorPool> createDescriptorPool(void); |
| Move<VkDescriptorSetLayout> createDescriptorSetLayout(const VkBuffer vertShaderBuffer, |
| const VkBuffer fragShaderBuffer); |
| Move<VkDescriptorSet> createDescriptorSet(const VkDescriptorPool pool, const VkDescriptorSetLayout layout, |
| const VkBuffer vertShaderBuffer, const VkBuffer fragShaderBuffer); |
| bool verifyColorImage(const tcu::ConstPixelBufferAccess &pba); |
| bool verifyDepthImage(const tcu::ConstPixelBufferAccess &pba); |
| bool runTest(RuntimePipelineTreeConfiguration &runtimePipelineTreeConfiguration, const bool optimize, |
| const bool delayedShaderCreate); |
| |
| private: |
| TestParams m_data; |
| std::vector<tcu::Vec4> m_vertexData; |
| std::vector<tcu::Vec4> m_paletteData; |
| std::vector<tcu::Vec4> m_zCoordData; |
| }; |
| |
| PipelineLibraryTestInstance::PipelineLibraryTestInstance(Context &context, const TestParams &data) |
| : vkt::TestInstance(context) |
| , m_data(data) |
| , m_vertexData() |
| , m_paletteData() |
| { |
| m_vertexData = { |
| {-1.0f, -1.0f, 0.0f, 1.0f}, {+1.0f, -1.0f, 0.5f, 1.0f}, {-1.0f, +1.0f, 0.5f, 1.0f}, |
| {-1.0f, +1.0f, 0.5f, 1.0f}, {+1.0f, -1.0f, 0.5f, 1.0f}, {+1.0f, +1.0f, 1.0f, 1.0f}, |
| }; |
| m_paletteData = { |
| {0.25f, 1.0f, 0.0f, 1.0f}, |
| {0.75f, 0.0f, 1.0f, 1.0f}, |
| }; |
| m_zCoordData = { |
| {0.25f, 0.75f, 0.0f, 1.0f}, |
| }; |
| } |
| |
| PipelineLibraryTestInstance::~PipelineLibraryTestInstance(void) |
| { |
| } |
| |
| de::MovePtr<BufferWithMemory> PipelineLibraryTestInstance::makeVertexBuffer(void) |
| { |
| const DeviceInterface &vk = m_context.getDeviceInterface(); |
| const VkDevice device = m_context.getDevice(); |
| Allocator &allocator = m_context.getDefaultAllocator(); |
| const size_t bufferDataSize = de::dataSize(m_vertexData); |
| const VkBufferCreateInfo bufferCreateInfo = makeBufferCreateInfo(bufferDataSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); |
| de::MovePtr<BufferWithMemory> buffer = de::MovePtr<BufferWithMemory>( |
| new BufferWithMemory(vk, device, allocator, bufferCreateInfo, MemoryRequirement::HostVisible)); |
| |
| deMemcpy(buffer->getAllocation().getHostPtr(), m_vertexData.data(), bufferDataSize); |
| flushAlloc(vk, device, buffer->getAllocation()); |
| |
| return buffer; |
| } |
| |
| de::MovePtr<BufferWithMemory> PipelineLibraryTestInstance::makeZCoordBuffer(void) |
| { |
| const DeviceInterface &vk = m_context.getDeviceInterface(); |
| const VkDevice device = m_context.getDevice(); |
| Allocator &allocator = m_context.getDefaultAllocator(); |
| const size_t bufferDataSize = de::dataSize(m_zCoordData); |
| const VkBufferCreateInfo bufferCreateInfo = |
| makeBufferCreateInfo(bufferDataSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); |
| de::MovePtr<BufferWithMemory> buffer = de::MovePtr<BufferWithMemory>( |
| new BufferWithMemory(vk, device, allocator, bufferCreateInfo, MemoryRequirement::HostVisible)); |
| |
| deMemcpy(buffer->getAllocation().getHostPtr(), m_zCoordData.data(), bufferDataSize); |
| flushAlloc(vk, device, buffer->getAllocation()); |
| |
| return buffer; |
| } |
| |
| de::MovePtr<BufferWithMemory> PipelineLibraryTestInstance::makePaletteBuffer(void) |
| { |
| const DeviceInterface &vk = m_context.getDeviceInterface(); |
| const VkDevice device = m_context.getDevice(); |
| Allocator &allocator = m_context.getDefaultAllocator(); |
| const size_t bufferDataSize = de::dataSize(m_paletteData); |
| const VkBufferCreateInfo bufferCreateInfo = |
| makeBufferCreateInfo(bufferDataSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); |
| de::MovePtr<BufferWithMemory> buffer = de::MovePtr<BufferWithMemory>( |
| new BufferWithMemory(vk, device, allocator, bufferCreateInfo, MemoryRequirement::HostVisible)); |
| |
| deMemcpy(buffer->getAllocation().getHostPtr(), m_paletteData.data(), bufferDataSize); |
| flushAlloc(vk, device, buffer->getAllocation()); |
| |
| return buffer; |
| } |
| |
| Move<VkDescriptorPool> PipelineLibraryTestInstance::createDescriptorPool(void) |
| { |
| const DeviceInterface &vk = m_context.getDeviceInterface(); |
| const VkDevice device = m_context.getDevice(); |
| |
| return DescriptorPoolBuilder() |
| .addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 4) |
| .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 3); |
| } |
| |
| Move<VkDescriptorSetLayout> PipelineLibraryTestInstance::createDescriptorSetLayout(const VkBuffer vertShaderBuffer, |
| const VkBuffer fragShaderBuffer) |
| { |
| const DeviceInterface &vk = m_context.getDeviceInterface(); |
| const VkDevice device = m_context.getDevice(); |
| DescriptorSetLayoutBuilder builder; |
| |
| if (vertShaderBuffer != VK_NULL_HANDLE) |
| builder.addIndexedBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1u, VK_SHADER_STAGE_VERTEX_BIT, 0u, DE_NULL); |
| |
| if (fragShaderBuffer != VK_NULL_HANDLE) |
| builder.addIndexedBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1u, VK_SHADER_STAGE_FRAGMENT_BIT, 1u, DE_NULL); |
| |
| return builder.build(vk, device); |
| } |
| |
| Move<VkDescriptorSet> PipelineLibraryTestInstance::createDescriptorSet(const VkDescriptorPool pool, |
| const VkDescriptorSetLayout layout, |
| const VkBuffer vertShaderBuffer, |
| const VkBuffer fragShaderBuffer) |
| { |
| const DeviceInterface &vk = m_context.getDeviceInterface(); |
| const VkDevice device = m_context.getDevice(); |
| const VkDescriptorSetAllocateInfo allocInfo = { |
| VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| pool, // VkDescriptorPool descriptorPool; |
| 1u, // uint32_t descriptorSetCount; |
| &layout // const VkDescriptorSetLayout* pSetLayouts; |
| }; |
| Move<VkDescriptorSet> descriptorSet = allocateDescriptorSet(vk, device, &allocInfo); |
| DescriptorSetUpdateBuilder builder; |
| |
| if (vertShaderBuffer != VK_NULL_HANDLE) |
| { |
| const VkDeviceSize vertShaderBufferSize = de::dataSize(m_zCoordData); |
| const VkDescriptorBufferInfo vertShaderBufferInfo = |
| makeDescriptorBufferInfo(vertShaderBuffer, 0u, vertShaderBufferSize); |
| |
| builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), |
| VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &vertShaderBufferInfo); |
| } |
| |
| if (fragShaderBuffer != VK_NULL_HANDLE) |
| { |
| const VkDeviceSize fragShaderBufferSize = de::dataSize(m_paletteData); |
| const VkDescriptorBufferInfo fragShaderBufferInfo = |
| makeDescriptorBufferInfo(fragShaderBuffer, 0u, fragShaderBufferSize); |
| |
| builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), |
| VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &fragShaderBufferInfo); |
| } |
| |
| builder.update(vk, device); |
| |
| return descriptorSet; |
| } |
| |
| VkFormat getSupportedDepthFormat(const InstanceInterface &vk, const VkPhysicalDevice physicalDevice) |
| { |
| VkFormatProperties properties; |
| |
| const VkFormat DepthFormats[] = {VK_FORMAT_D32_SFLOAT, VK_FORMAT_X8_D24_UNORM_PACK32, VK_FORMAT_D24_UNORM_S8_UINT, |
| VK_FORMAT_D32_SFLOAT_S8_UINT}; |
| |
| for (const auto format : DepthFormats) |
| { |
| vk.getPhysicalDeviceFormatProperties(physicalDevice, format, &properties); |
| |
| if (properties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) |
| return format; |
| } |
| |
| TCU_THROW(NotSupportedError, "Depth format is not supported"); |
| } |
| |
| bool PipelineLibraryTestInstance::runTest(RuntimePipelineTreeConfiguration &runtimePipelineTreeConfiguration, |
| const bool optimize, const bool delayedShaderCreate) |
| { |
| const DeviceInterface &vk = m_context.getDeviceInterface(); |
| const VkDevice device = m_context.getDevice(); |
| const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); |
| Allocator &allocator = m_context.getDefaultAllocator(); |
| tcu::TestLog &log = m_context.getTestContext().getLog(); |
| const VkFormat colorFormat = VK_FORMAT_R8G8B8A8_UNORM; |
| const VkFormat depthFormat = |
| getSupportedDepthFormat(m_context.getInstanceInterface(), m_context.getPhysicalDevice()); |
| const VkGraphicsPipelineLibraryFlagsEXT vertPipelineFlags = |
| static_cast<VkGraphicsPipelineLibraryFlagsEXT>(VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT); |
| const VkGraphicsPipelineLibraryFlagsEXT fragPipelineFlags = |
| static_cast<VkGraphicsPipelineLibraryFlagsEXT>(VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT); |
| const VkGraphicsPipelineLibraryFlagsEXT samePipelineFlags = vertPipelineFlags | fragPipelineFlags; |
| const int32_t nodeNdxLast = static_cast<int32_t>(runtimePipelineTreeConfiguration.size()) - 1; |
| const Move<VkRenderPass> renderPass = makeRenderPass(vk, device, colorFormat, depthFormat); |
| const de::MovePtr<BufferWithMemory> zCoordBuffer = makeZCoordBuffer(); |
| const de::MovePtr<BufferWithMemory> paletteBuffer = makePaletteBuffer(); |
| const Move<VkDescriptorPool> descriptorPool = createDescriptorPool(); |
| |
| const Move<VkDescriptorSetLayout> descriptorSetLayoutVert = |
| createDescriptorSetLayout(**zCoordBuffer, VK_NULL_HANDLE); |
| const Move<VkDescriptorSetLayout> descriptorSetLayoutFrag = |
| createDescriptorSetLayout(VK_NULL_HANDLE, **paletteBuffer); |
| const Move<VkDescriptorSetLayout> descriptorSetLayoutBoth = |
| createDescriptorSetLayout(**zCoordBuffer, **paletteBuffer); |
| const Move<VkDescriptorSet> descriptorSetVert = |
| createDescriptorSet(*descriptorPool, *descriptorSetLayoutVert, **zCoordBuffer, VK_NULL_HANDLE); |
| const Move<VkDescriptorSet> descriptorSetFrag = |
| createDescriptorSet(*descriptorPool, *descriptorSetLayoutFrag, VK_NULL_HANDLE, **paletteBuffer); |
| |
| VkDescriptorSet vecDescriptorSetBoth[2] = {*descriptorSetVert, *descriptorSetFrag}; |
| |
| VkDescriptorSetLayout vecLayoutVert[2] = {*descriptorSetLayoutVert, VK_NULL_HANDLE}; |
| VkDescriptorSetLayout vecLayoutFrag[2] = {VK_NULL_HANDLE, *descriptorSetLayoutFrag}; |
| VkDescriptorSetLayout vecLayoutBoth[2] = {*descriptorSetLayoutVert, *descriptorSetLayoutFrag}; |
| |
| VkPipelineLayoutCreateFlags pipelineLayoutCreateFlag = 0u; |
| if (!m_data.useMaintenance5 && (m_data.delayedShaderCreate || (m_data.pipelineTreeConfiguration.size() > 1))) |
| pipelineLayoutCreateFlag = VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT; |
| |
| const Move<VkCommandPool> cmdPool = |
| createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex); |
| const Move<VkCommandBuffer> cmdBuffer = |
| allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY); |
| const Move<VkPipelineLayout> pipelineLayoutSame = |
| makePipelineLayout(vk, device, 2, vecLayoutBoth, pipelineLayoutCreateFlag); |
| Move<VkPipelineLayout> pipelineLayoutVert; |
| Move<VkPipelineLayout> pipelineLayoutFrag; |
| Move<VkPipeline> rootPipeline; |
| |
| // Go through tree nodes and create library for each up to root |
| for (int32_t nodeNdx = nodeNdxLast; nodeNdx >= 0; |
| --nodeNdx) // We expect only backward node reference, thus build pipielines from end is safe |
| { |
| RuntimePipelineTreeNode &node = runtimePipelineTreeConfiguration[nodeNdx]; |
| const bool buildLibrary = (nodeNdx != 0); |
| const VkPipelineCreateFlags pipelineCreateFlags = calcPipelineCreateFlags(optimize, buildLibrary); |
| const VkGraphicsPipelineLibraryFlagsEXT subtreeGraphicsPipelineLibraryFlags = |
| node.subtreeGraphicsPipelineLibraryFlags | node.graphicsPipelineLibraryFlags; |
| const bool samePipelineLayout = samePipelineFlags == (samePipelineFlags & subtreeGraphicsPipelineLibraryFlags); |
| const bool vertPipelineLayout = vertPipelineFlags == (vertPipelineFlags & subtreeGraphicsPipelineLibraryFlags); |
| const bool fragPipelineLayout = fragPipelineFlags == (fragPipelineFlags & subtreeGraphicsPipelineLibraryFlags); |
| |
| if (samePipelineLayout) |
| ; // pipelineLayoutSame is always built before. |
| else if (vertPipelineLayout) |
| { |
| if (!pipelineLayoutVert) |
| pipelineLayoutVert = makePipelineLayout(vk, device, 2, vecLayoutVert, pipelineLayoutCreateFlag); |
| } |
| else if (fragPipelineLayout) |
| { |
| if (!pipelineLayoutFrag) |
| pipelineLayoutFrag = makePipelineLayout(vk, device, 2, vecLayoutFrag, pipelineLayoutCreateFlag); |
| } |
| |
| const VkPipelineLayout pipelineLayout = samePipelineLayout ? *pipelineLayoutSame : |
| vertPipelineLayout ? *pipelineLayoutVert : |
| fragPipelineLayout ? *pipelineLayoutFrag : |
| VK_NULL_HANDLE; |
| const VkRenderPass renderPassHandle = getRenderPass(node.graphicsPipelineLibraryFlags, *renderPass); |
| VkGraphicsPipelineLibraryCreateInfoEXT graphicsPipelineLibraryCreateInfo = |
| makeGraphicsPipelineLibraryCreateInfo(node.graphicsPipelineLibraryFlags); |
| VkPipelineLibraryCreateInfoKHR linkingInfo = makePipelineLibraryCreateInfo(node.pipelineLibraries); |
| GraphicsPipelineCreateInfo graphicsPipelineCreateInfo(pipelineLayout, renderPassHandle, 0, pipelineCreateFlags); |
| |
| for (const auto subsetFlag : GRAPHICS_PIPELINE_LIBRARY_FLAGS) |
| { |
| if ((node.graphicsPipelineLibraryFlags & subsetFlag) != 0) |
| { |
| switch (subsetFlag) |
| { |
| case VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT: |
| updateVertexInputInterface(m_context, graphicsPipelineCreateInfo); |
| break; |
| case VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT: |
| updatePreRasterization(m_context, graphicsPipelineCreateInfo, delayedShaderCreate); |
| break; |
| case VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT: |
| updatePostRasterization(m_context, graphicsPipelineCreateInfo, delayedShaderCreate); |
| break; |
| case VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT: |
| updateFragmentOutputInterface(m_context, graphicsPipelineCreateInfo); |
| break; |
| default: |
| TCU_THROW(InternalError, "Unknown pipeline subset"); |
| } |
| } |
| } |
| |
| VkGraphicsPipelineLibraryFlagsEXT linkedLibrariesFlags = 0; |
| |
| for (auto flag : node.linkedLibraryFlags) |
| linkedLibrariesFlags |= flag; |
| |
| // When pLibraries have any pipeline library with fragment shader state and current pipeline we try to create doesn't, |
| // we need to set a MS info. |
| if ((linkedLibrariesFlags & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT) && |
| !(node.graphicsPipelineLibraryFlags & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT) && |
| (graphicsPipelineCreateInfo.pMultisampleState == DE_NULL)) |
| { |
| const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo = |
| makePipelineMultisampleStateCreateInfo(); |
| |
| graphicsPipelineCreateInfo.addState(pipelineMultisampleStateCreateInfo); |
| } |
| |
| if (!m_data.useMaintenance5 && linkedLibrariesFlags != ALL_GRAPHICS_PIPELINE_LIBRARY_FLAGS && |
| graphicsPipelineLibraryCreateInfo.flags != 0) |
| appendStructurePtrToVulkanChain(&graphicsPipelineCreateInfo.pNext, &graphicsPipelineLibraryCreateInfo); |
| |
| if (linkingInfo.libraryCount != 0) |
| { |
| appendStructurePtrToVulkanChain(&graphicsPipelineCreateInfo.pNext, &linkingInfo); |
| graphicsPipelineCreateInfo.layout = *pipelineLayoutSame; |
| } |
| |
| linkedLibrariesFlags |= node.graphicsPipelineLibraryFlags; |
| |
| // if current pipeline that we try to create and pLibraries have all states of pipelines, we are not allowed to create a pipeline library. |
| if (linkedLibrariesFlags == ALL_GRAPHICS_PIPELINE_LIBRARY_FLAGS) |
| { |
| DE_ASSERT(!buildLibrary); |
| graphicsPipelineCreateInfo.flags &= ~VK_PIPELINE_CREATE_LIBRARY_BIT_KHR; |
| } |
| |
| node.pipeline = createGraphicsPipeline(vk, device, VK_NULL_HANDLE, &graphicsPipelineCreateInfo); |
| |
| if (buildLibrary) |
| { |
| DE_ASSERT(de::inBounds(node.parentIndex, 0, static_cast<int32_t>(runtimePipelineTreeConfiguration.size()))); |
| |
| runtimePipelineTreeConfiguration[node.parentIndex].pipelineLibraries.push_back(*node.pipeline); |
| runtimePipelineTreeConfiguration[node.parentIndex].linkedLibraryFlags.push_back(linkedLibrariesFlags); |
| } |
| else |
| { |
| DE_ASSERT(node.parentIndex == -1); |
| |
| rootPipeline = node.pipeline; |
| } |
| } |
| |
| // Queue commands and read results. |
| { |
| const tcu::UVec2 renderSize = {RENDER_SIZE_WIDTH, RENDER_SIZE_HEIGHT}; |
| const VkRect2D renderArea = makeRect2D(renderSize.x(), renderSize.y()); |
| const de::MovePtr<BufferWithMemory> vertexBuffer = makeVertexBuffer(); |
| const uint32_t vertexCount = static_cast<uint32_t>(m_vertexData.size()); |
| const VkDeviceSize vertexBufferOffset = 0; |
| const Vec4 colorClearColor(0.0f, 0.0f, 0.0f, 1.0f); |
| const VkImageCreateInfo colorImageCreateInfo = |
| makeColorImageCreateInfo(colorFormat, renderSize.x(), renderSize.y()); |
| const ImageWithMemory colorImage(vk, device, allocator, colorImageCreateInfo, MemoryRequirement::Any); |
| const VkImageViewCreateInfo colorImageViewCreateInfo = makeImageViewCreateInfo( |
| *colorImage, colorFormat, static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_COLOR_BIT)); |
| const Move<VkImageView> colorImageView = createImageView(vk, device, &colorImageViewCreateInfo); |
| const VkImageCreateInfo depthImageCreateInfo = |
| makeDepthImageCreateInfo(depthFormat, renderSize.x(), renderSize.y()); |
| const ImageWithMemory depthImage(vk, device, allocator, depthImageCreateInfo, MemoryRequirement::Any); |
| const VkImageViewCreateInfo depthImageViewCreateInfo = makeImageViewCreateInfo( |
| *depthImage, depthFormat, static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_DEPTH_BIT)); |
| const Move<VkImageView> depthImageView = createImageView(vk, device, &depthImageViewCreateInfo); |
| const float depthClearDepth = 1.0f; |
| const uint32_t depthClearStencil = 0u; |
| const VkDeviceSize colorBufferDataSize = |
| static_cast<VkDeviceSize>(renderSize.x() * renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat))); |
| const VkBufferCreateInfo colorBufferCreateInfo = makeBufferCreateInfo( |
| colorBufferDataSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); |
| const BufferWithMemory colorBuffer(vk, device, allocator, colorBufferCreateInfo, |
| MemoryRequirement::HostVisible); |
| const VkDeviceSize depthBufferDataSize = |
| static_cast<VkDeviceSize>(renderSize.x() * renderSize.y() * tcu::getPixelSize(mapVkFormat(depthFormat))); |
| const VkBufferCreateInfo depthBufferCreateInfo = makeBufferCreateInfo( |
| depthBufferDataSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); |
| const BufferWithMemory depthBuffer(vk, device, allocator, depthBufferCreateInfo, |
| MemoryRequirement::HostVisible); |
| const VkImageView attachments[] = {*colorImageView, *depthImageView}; |
| const VkFramebufferCreateInfo framebufferCreateInfo = makeFramebufferCreateInfo( |
| *renderPass, DE_LENGTH_OF_ARRAY(attachments), attachments, renderSize.x(), renderSize.y()); |
| const Move<VkFramebuffer> framebuffer = createFramebuffer(vk, device, &framebufferCreateInfo); |
| |
| vk::beginCommandBuffer(vk, *cmdBuffer, 0u); |
| { |
| beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, colorClearColor, depthClearDepth, |
| depthClearStencil); |
| { |
| vk.cmdBindVertexBuffers(*cmdBuffer, 0, 1, &vertexBuffer->get(), &vertexBufferOffset); |
| vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *rootPipeline); |
| vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayoutSame, 0u, 2u, |
| vecDescriptorSetBoth, 0u, DE_NULL); |
| vk.cmdDraw(*cmdBuffer, vertexCount, 1u, 0u, 0u); |
| } |
| endRenderPass(vk, *cmdBuffer); |
| |
| const tcu::IVec2 size = {(int32_t)renderSize.x(), (int32_t)renderSize.y()}; |
| copyImageToBuffer(vk, *cmdBuffer, *colorImage, *colorBuffer, size); |
| copyImageToBuffer(vk, *cmdBuffer, *depthImage, *depthBuffer, size, |
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, |
| VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 1u, VK_IMAGE_ASPECT_DEPTH_BIT, |
| VK_IMAGE_ASPECT_DEPTH_BIT); |
| } |
| vk::endCommandBuffer(vk, *cmdBuffer); |
| vk::submitCommandsAndWait(vk, device, m_context.getUniversalQueue(), cmdBuffer.get()); |
| |
| vk::invalidateAlloc(vk, device, colorBuffer.getAllocation()); |
| vk::invalidateAlloc(vk, device, depthBuffer.getAllocation()); |
| |
| const tcu::ConstPixelBufferAccess colorPixelAccess(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1, |
| colorBuffer.getAllocation().getHostPtr()); |
| const tcu::ConstPixelBufferAccess depthPixelAccess(mapVkFormat(depthFormat), renderSize.x(), renderSize.y(), 1, |
| depthBuffer.getAllocation().getHostPtr()); |
| |
| if (!verifyColorImage(colorPixelAccess)) |
| { |
| log << tcu::TestLog::Image("color", "Rendered image", colorPixelAccess); |
| |
| return false; |
| } |
| |
| if (!verifyDepthImage(depthPixelAccess)) |
| { |
| log << tcu::TestLog::Image("depth", "Rendered image", depthPixelAccess); |
| |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| bool PipelineLibraryTestInstance::verifyColorImage(const ConstPixelBufferAccess &pba) |
| { |
| tcu::TestLog &log = m_context.getTestContext().getLog(); |
| TextureLevel referenceImage(pba.getFormat(), pba.getWidth(), pba.getHeight()); |
| PixelBufferAccess reference(referenceImage); |
| const int horzEdge = 3 * reference.getWidth() / 4; |
| const int vertEdge = reference.getHeight() / 2; |
| const UVec4 green = ivec2uvec(RGBA::green().toIVec()); |
| const UVec4 blue = ivec2uvec(RGBA::blue().toIVec()); |
| const UVec4 black = ivec2uvec(RGBA::black().toIVec()); |
| |
| for (int y = 0; y < reference.getHeight(); ++y) |
| { |
| for (int x = 0; x < reference.getWidth(); ++x) |
| { |
| if (x < horzEdge) |
| { |
| if (y < vertEdge) |
| reference.setPixel(green, x, y); |
| else |
| reference.setPixel(blue, x, y); |
| } |
| else |
| reference.setPixel(black, x, y); |
| } |
| } |
| |
| return intThresholdCompare(log, "colorImage", "colorImage", reference, pba, UVec4(), COMPARE_LOG_RESULT); |
| } |
| |
| bool PipelineLibraryTestInstance::verifyDepthImage(const ConstPixelBufferAccess &pba) |
| { |
| tcu::TestLog &log = m_context.getTestContext().getLog(); |
| const VkFormat compareFormat = VK_FORMAT_R8_UNORM; |
| TextureLevel referenceImage(mapVkFormat(compareFormat), pba.getWidth(), pba.getHeight()); |
| PixelBufferAccess reference(referenceImage); |
| TextureLevel resultImage(mapVkFormat(compareFormat), pba.getWidth(), pba.getHeight()); |
| PixelBufferAccess result(resultImage); |
| const int horzEdge = 3 * reference.getWidth() / 4; |
| const int diagonalEdge = (reference.getWidth() + reference.getHeight()) / 2 - 1; |
| const UVec4 red100 = ivec2uvec(RGBA::red().toIVec()); |
| const UVec4 red025 = UVec4(red100[0] / 4, red100[1] / 4, red100[2] / 4, red100[3]); |
| const UVec4 red075 = UVec4(3 * red100[0] / 4, 3 * red100[1] / 4, 3 * red100[2] / 4, red100[3]); |
| |
| for (int y = 0; y < result.getHeight(); ++y) |
| for (int x = 0; x < result.getWidth(); ++x) |
| { |
| const UVec4 pix(static_cast<uint32_t>(static_cast<float>(red100[0]) * pba.getPixDepth(x, y)), 0, 0, 0); |
| |
| result.setPixel(pix, x, y); |
| } |
| |
| for (int y = 0; y < reference.getHeight(); ++y) |
| { |
| for (int x = 0; x < reference.getWidth(); ++x) |
| { |
| if (x < horzEdge) |
| { |
| if (x + y < diagonalEdge) |
| reference.setPixel(red025, x, y); |
| else |
| reference.setPixel(red075, x, y); |
| } |
| else |
| reference.setPixel(red100, x, y); |
| } |
| } |
| |
| return intThresholdCompare(log, "depthImage", "depthImage", reference, result, UVec4(), COMPARE_LOG_RESULT); |
| } |
| |
| tcu::TestStatus PipelineLibraryTestInstance::iterate(void) |
| { |
| VkGraphicsPipelineLibraryFlagBitsEXT graphicsPipelineLibraryFlags[] = { |
| VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT, |
| VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT, |
| VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT, |
| VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT, |
| }; |
| const auto graphicsPipelineLibraryFlagsBegin = graphicsPipelineLibraryFlags; |
| const auto graphicsPipelineLibraryFlagsEnd = |
| graphicsPipelineLibraryFlags + DE_LENGTH_OF_ARRAY(graphicsPipelineLibraryFlags); |
| uint32_t permutationId = 0; |
| std::set<uint32_t> was; |
| bool result = true; |
| |
| do |
| { |
| RuntimePipelineTreeConfiguration runtimePipelineTreeConfiguration(m_data.pipelineTreeConfiguration.size()); |
| size_t subsetNdxStart = 0; |
| uint32_t uniqueTreeSubsetCode = 0; |
| |
| for (size_t nodeNdx = 0; nodeNdx < runtimePipelineTreeConfiguration.size(); ++nodeNdx) |
| { |
| const uint32_t shaderCount = m_data.pipelineTreeConfiguration[nodeNdx].shaderCount; |
| RuntimePipelineTreeNode &node = runtimePipelineTreeConfiguration[nodeNdx]; |
| |
| node.parentIndex = m_data.pipelineTreeConfiguration[nodeNdx].parentIndex; |
| node.graphicsPipelineLibraryFlags = 0u; |
| |
| for (size_t subsetNdx = 0; subsetNdx < shaderCount; ++subsetNdx) |
| node.graphicsPipelineLibraryFlags |= static_cast<VkGraphicsPipelineLibraryFlagsEXT>( |
| graphicsPipelineLibraryFlags[subsetNdxStart + subsetNdx]); |
| |
| if (node.parentIndex > 0) |
| runtimePipelineTreeConfiguration[node.parentIndex].subtreeGraphicsPipelineLibraryFlags |= |
| node.graphicsPipelineLibraryFlags; |
| |
| // Each shader subset should be tested in each node of tree |
| subsetNdxStart += shaderCount; |
| |
| uniqueTreeSubsetCode = (uniqueTreeSubsetCode << 4) | node.graphicsPipelineLibraryFlags; |
| } |
| |
| // Check whether this configuration has been tried |
| if (was.find(uniqueTreeSubsetCode) == was.end()) |
| was.insert(uniqueTreeSubsetCode); |
| else |
| continue; |
| |
| result = result && runTest(runtimePipelineTreeConfiguration, m_data.optimize, m_data.delayedShaderCreate); |
| |
| if (!result) |
| { |
| tcu::TestLog &log = m_context.getTestContext().getLog(); |
| std::ostringstream ess; |
| |
| for (size_t nodeNdx = 0; nodeNdx < runtimePipelineTreeConfiguration.size(); ++nodeNdx) |
| { |
| const RuntimePipelineTreeNode &node = runtimePipelineTreeConfiguration[nodeNdx]; |
| |
| ess << node.parentIndex << " {"; |
| |
| for (size_t subsetNdx = 0; subsetNdx < DE_LENGTH_OF_ARRAY(graphicsPipelineLibraryFlags); ++subsetNdx) |
| { |
| if ((node.graphicsPipelineLibraryFlags & graphicsPipelineLibraryFlags[subsetNdx]) == 0) |
| continue; |
| |
| ess << getGraphicsPipelineLibraryFlagsString(graphicsPipelineLibraryFlags[subsetNdx]) << " "; |
| } |
| |
| ess << "}" << std::endl; |
| } |
| |
| log << tcu::TestLog::Message << ess.str() << tcu::TestLog::EndMessage; |
| |
| return tcu::TestStatus::fail("At permutation " + de::toString(permutationId)); |
| } |
| |
| ++permutationId; |
| } while (std::next_permutation(graphicsPipelineLibraryFlagsBegin, graphicsPipelineLibraryFlagsEnd)); |
| |
| return tcu::TestStatus::pass("OK"); |
| } |
| |
| class PipelineLibraryTestCase : public TestCase |
| { |
| public: |
| PipelineLibraryTestCase(tcu::TestContext &context, const char *name, const TestParams data); |
| ~PipelineLibraryTestCase(void); |
| |
| virtual void checkSupport(Context &context) const; |
| virtual void initPrograms(SourceCollections &programCollection) const; |
| virtual TestInstance *createInstance(Context &context) const; |
| |
| private: |
| TestParams m_data; |
| }; |
| |
| PipelineLibraryTestCase::PipelineLibraryTestCase(tcu::TestContext &context, const char *name, const TestParams data) |
| : vkt::TestCase(context, name) |
| , m_data(data) |
| { |
| } |
| |
| PipelineLibraryTestCase::~PipelineLibraryTestCase(void) |
| { |
| } |
| |
| void PipelineLibraryTestCase::checkSupport(Context &context) const |
| { |
| if (m_data.useMaintenance5) |
| { |
| context.requireDeviceFunctionality("VK_KHR_maintenance5"); |
| return; |
| } |
| |
| context.requireDeviceFunctionality("VK_KHR_pipeline_library"); |
| |
| if (m_data.delayedShaderCreate || (m_data.pipelineTreeConfiguration.size() > 1)) |
| { |
| context.requireDeviceFunctionality("VK_EXT_graphics_pipeline_library"); |
| |
| const VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT &graphicsPipelineLibraryFeaturesEXT = |
| context.getGraphicsPipelineLibraryFeaturesEXT(); |
| |
| if (!graphicsPipelineLibraryFeaturesEXT.graphicsPipelineLibrary) |
| TCU_THROW(NotSupportedError, "graphicsPipelineLibraryFeaturesEXT.graphicsPipelineLibrary required"); |
| } |
| } |
| |
| void PipelineLibraryTestCase::initPrograms(SourceCollections &programCollection) const |
| { |
| std::string vert = "#version 450\n" |
| "layout(location = 0) in vec4 in_position;\n" |
| "layout(set = 0, binding = 0) uniform buf\n" |
| "{\n" |
| " vec4 z_coord;\n" |
| "};\n" |
| "\n" |
| "out gl_PerVertex\n" |
| "{\n" |
| " vec4 gl_Position;\n" |
| "};\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " const float z = gl_VertexIndex < 3 ? z_coord.x : z_coord.y;\n" |
| " gl_Position = vec4(in_position.x, in_position.y, z, 1.0f);\n" |
| "}\n"; |
| |
| programCollection.glslSources.add("vert") << glu::VertexSource(vert); |
| |
| std::string frag = "#version 450\n" |
| "layout(location = 0) out highp vec4 o_color;\n" |
| "layout(set = 1, binding = 1) uniform buf\n" |
| "{\n" |
| " vec4 colorTop;\n" |
| " vec4 colorBot;\n" |
| "};\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " const int middle = " + |
| de::toString(RENDER_SIZE_HEIGHT / 2) + |
| ";\n" |
| " o_color = int(gl_FragCoord.y - 0.5f) < middle ? colorTop : colorBot;\n" |
| "}\n"; |
| |
| programCollection.glslSources.add("frag") << glu::FragmentSource(frag); |
| } |
| |
| TestInstance *PipelineLibraryTestCase::createInstance(Context &context) const |
| { |
| return new PipelineLibraryTestInstance(context, m_data); |
| } |
| |
| enum class MiscTestMode |
| { |
| INDEPENDENT_PIPELINE_LAYOUT_SETS_FAST_LINKED = 0, |
| INDEPENDENT_PIPELINE_LAYOUT_SETS_WITH_LINK_TIME_OPTIMIZATION_UNION_HANDLE, |
| BIND_NULL_DESCRIPTOR_SET, |
| BIND_NULL_DESCRIPTOR_SET_IN_MONOLITHIC_PIPELINE, |
| COMPARE_LINK_TIMES, |
| SHADER_MODULE_CREATE_INFO_COMP, |
| SHADER_MODULE_CREATE_INFO_RT, |
| SHADER_MODULE_CREATE_INFO_RT_LIB, |
| NULL_RENDERING_CREATE_INFO, |
| COMMON_FRAG_LIBRARY, |
| VIEW_INDEX_FROM_DEVICE_INDEX_IN_ALL_STAGES, |
| VIEW_INDEX_FROM_DEVICE_INDEX_IN_MESH_STAGES, |
| }; |
| |
| struct MiscTestParams |
| { |
| MiscTestMode mode; |
| |
| // attributes used in BIND_NULL_DESCRIPTOR_SET mode |
| uint32_t layoutsCount; |
| uint32_t layoutsBits; |
| }; |
| |
| class PipelineLibraryMiscTestInstance : public TestInstance |
| { |
| public: |
| PipelineLibraryMiscTestInstance(Context &context, const MiscTestParams ¶ms); |
| ~PipelineLibraryMiscTestInstance(void) = default; |
| tcu::TestStatus iterate(void); |
| |
| protected: |
| tcu::TestStatus runNullDescriptorSet(void); |
| tcu::TestStatus runNullDescriptorSetInMonolithicPipeline(void); |
| tcu::TestStatus runIndependentPipelineLayoutSets(bool useLinkTimeOptimization = false); |
| tcu::TestStatus runCompareLinkTimes(void); |
| tcu::TestStatus runCommonFragLibraryTest(void); |
| |
| struct VerificationData |
| { |
| const tcu::IVec2 point; |
| const tcu::IVec4 color; |
| }; |
| tcu::TestStatus verifyResult(const std::vector<VerificationData> &verificationData, |
| const tcu::ConstPixelBufferAccess &colorPixelAccess) const; |
| // verification for test mode: COMMON_FRAG_LIBRARY_FAST_LINKED |
| bool verifyOnePipelineLibraryResult(const tcu::ConstPixelBufferAccess &colorPixelAccess, const int numBars) const; |
| |
| private: |
| MiscTestParams m_testParams; |
| const VkFormat m_colorFormat; |
| const Vec4 m_colorClearColor; |
| const VkRect2D m_renderArea; |
| |
| de::MovePtr<ImageWithMemory> m_colorImage; |
| Move<VkImageView> m_colorImageView; |
| |
| Move<VkRenderPass> m_renderPass; |
| Move<VkFramebuffer> m_framebuffer; |
| |
| Move<VkCommandPool> m_cmdPool; |
| Move<VkCommandBuffer> m_cmdBuffer; |
| }; |
| |
| PipelineLibraryMiscTestInstance::PipelineLibraryMiscTestInstance(Context &context, const MiscTestParams ¶ms) |
| : vkt::TestInstance(context) |
| , m_testParams(params) |
| , m_colorFormat(VK_FORMAT_R8G8B8A8_UNORM) |
| , m_colorClearColor(0.0f, 0.0f, 0.0f, 1.0f) |
| , m_renderArea(makeRect2D(RENDER_SIZE_WIDTH, RENDER_SIZE_HEIGHT)) |
| { |
| } |
| |
| tcu::TestStatus PipelineLibraryMiscTestInstance::iterate(void) |
| { |
| const DeviceInterface &vk = m_context.getDeviceInterface(); |
| const VkDevice device = m_context.getDevice(); |
| Allocator &allocator = m_context.getDefaultAllocator(); |
| |
| // create image and image view that will hold rendered frame |
| const VkImageCreateInfo colorImageCreateInfo = |
| makeColorImageCreateInfo(m_colorFormat, m_renderArea.extent.width, m_renderArea.extent.height); |
| m_colorImage = de::MovePtr<ImageWithMemory>( |
| new ImageWithMemory(vk, device, allocator, colorImageCreateInfo, MemoryRequirement::Any)); |
| const VkImageViewCreateInfo colorImageViewCreateInfo = makeImageViewCreateInfo( |
| **m_colorImage, m_colorFormat, static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_COLOR_BIT)); |
| const Move<VkImageView> colorImageView = createImageView(vk, device, &colorImageViewCreateInfo); |
| |
| // create renderpass and framebuffer |
| m_renderPass = makeRenderPass(vk, device, m_colorFormat); |
| const VkFramebufferCreateInfo framebufferCreateInfo = makeFramebufferCreateInfo( |
| *m_renderPass, 1u, &*colorImageView, m_renderArea.extent.width, m_renderArea.extent.height); |
| m_framebuffer = createFramebuffer(vk, device, &framebufferCreateInfo); |
| |
| // create command pool and command buffer |
| const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); |
| m_cmdPool = createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex); |
| m_cmdBuffer = allocateCommandBuffer(vk, device, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY); |
| |
| // run selected test |
| if (m_testParams.mode == MiscTestMode::BIND_NULL_DESCRIPTOR_SET) |
| return runNullDescriptorSet(); |
| else if (m_testParams.mode == MiscTestMode::BIND_NULL_DESCRIPTOR_SET_IN_MONOLITHIC_PIPELINE) |
| return runNullDescriptorSetInMonolithicPipeline(); |
| else if (m_testParams.mode == MiscTestMode::INDEPENDENT_PIPELINE_LAYOUT_SETS_FAST_LINKED) |
| return runIndependentPipelineLayoutSets(); |
| else if (m_testParams.mode == |
| MiscTestMode::INDEPENDENT_PIPELINE_LAYOUT_SETS_WITH_LINK_TIME_OPTIMIZATION_UNION_HANDLE) |
| return runIndependentPipelineLayoutSets(true); |
| else if (m_testParams.mode == MiscTestMode::COMPARE_LINK_TIMES) |
| return runCompareLinkTimes(); |
| else if (m_testParams.mode == MiscTestMode::COMMON_FRAG_LIBRARY) |
| return runCommonFragLibraryTest(); |
| |
| DE_ASSERT(false); |
| return tcu::TestStatus::fail("Fail"); |
| } |
| |
| tcu::TestStatus PipelineLibraryMiscTestInstance::runNullDescriptorSet(void) |
| { |
| const DeviceInterface &vk = m_context.getDeviceInterface(); |
| const VkDevice device = m_context.getDevice(); |
| Allocator &allocator = m_context.getDefaultAllocator(); |
| |
| const VkDeviceSize colorBufferDataSize = static_cast<VkDeviceSize>( |
| m_renderArea.extent.width * m_renderArea.extent.height * tcu::getPixelSize(mapVkFormat(m_colorFormat))); |
| const VkBufferCreateInfo colorBufferCreateInfo = makeBufferCreateInfo( |
| colorBufferDataSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); |
| const BufferWithMemory colorBuffer(vk, device, allocator, colorBufferCreateInfo, MemoryRequirement::HostVisible); |
| |
| VkDeviceSize uniformBufferDataSize = sizeof(tcu::Vec4); |
| const VkBufferCreateInfo uniformBufferCreateInfo = |
| makeBufferCreateInfo(uniformBufferDataSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); |
| de::MovePtr<BufferWithMemory> uniformBuffer[2]; |
| |
| // setup data in uniform buffers that will give us expected result for validation |
| const tcu::Vec4 uniformBuffData[]{ |
| {-1.00f, 1.00f, 2.0f, -2.00f}, |
| {0.00f, 0.20f, 0.6f, 0.75f}, |
| }; |
| |
| for (uint32_t i = 0; i < 2; ++i) |
| { |
| uniformBuffer[i] = de::MovePtr<BufferWithMemory>( |
| new BufferWithMemory(vk, device, allocator, uniformBufferCreateInfo, MemoryRequirement::HostVisible)); |
| deMemcpy(uniformBuffer[i]->getAllocation().getHostPtr(), uniformBuffData[i].getPtr(), |
| (size_t)uniformBufferDataSize); |
| flushAlloc(vk, device, uniformBuffer[i]->getAllocation()); |
| } |
| |
| const uint32_t maxBitsCount = 8 * sizeof(m_testParams.layoutsBits); |
| VkDescriptorSetLayout vertDescriptorSetLayouts[maxBitsCount]; |
| VkDescriptorSetLayout fragDescriptorSetLayouts[maxBitsCount]; |
| VkDescriptorSetLayout allDescriptorSetLayouts[maxBitsCount]; |
| |
| // set all layouts to NULL |
| deMemset(&vertDescriptorSetLayouts, 0, maxBitsCount * sizeof(VkDescriptorSetLayout)); |
| deMemset(&fragDescriptorSetLayouts, 0, maxBitsCount * sizeof(VkDescriptorSetLayout)); |
| |
| // create used descriptor set layouts |
| Move<VkDescriptorSetLayout> usedDescriptorSetLayouts[]{ |
| DescriptorSetLayoutBuilder() |
| .addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT) |
| .build(vk, device), |
| DescriptorSetLayoutBuilder() |
| .addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT) |
| .build(vk, device)}; |
| |
| // create descriptor set layouts that are not used by shaders in test - finalPipelineLayout, |
| // needs to always be the complete pipeline layout with no holes; we can put NULLs in |
| // DescriptorSetLayouts used by partial pipelines (vertDescriptorSetLayouts and fragDescriptorSetLayouts) |
| Move<VkDescriptorSetLayout> unusedDescriptorSetLayouts[maxBitsCount]; |
| for (uint32_t i = 0u; i < m_testParams.layoutsCount; ++i) |
| { |
| unusedDescriptorSetLayouts[i] = DescriptorSetLayoutBuilder().build(vk, device); |
| |
| // by default allDescriptorSetLayouts is filled with unused layouts but later |
| // if test requires this proper indexes are replaced with used layouts |
| allDescriptorSetLayouts[i] = *unusedDescriptorSetLayouts[i]; |
| } |
| |
| VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = initVulkanStructure(); |
| pipelineLayoutCreateInfo.flags = VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT; |
| |
| // find set bits |
| std::vector<uint32_t> bitsThatAreSet; |
| for (uint32_t i = 0u; i < m_testParams.layoutsCount; ++i) |
| { |
| if (m_testParams.layoutsBits & (1 << (maxBitsCount - 1 - i))) |
| bitsThatAreSet.push_back(i); |
| } |
| |
| uint32_t usedDescriptorSets = static_cast<uint32_t>(bitsThatAreSet.size()); |
| DE_ASSERT(usedDescriptorSets && (usedDescriptorSets < 3u)); |
| |
| uint32_t vertSetIndex = bitsThatAreSet[0]; |
| uint32_t fragSetIndex = 0u; |
| vertDescriptorSetLayouts[vertSetIndex] = *usedDescriptorSetLayouts[0]; |
| allDescriptorSetLayouts[vertSetIndex] = *usedDescriptorSetLayouts[0]; |
| pipelineLayoutCreateInfo.setLayoutCount = vertSetIndex + 1u; |
| pipelineLayoutCreateInfo.pSetLayouts = vertDescriptorSetLayouts; |
| |
| Move<VkPipelineLayout> vertPipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo); |
| Move<VkPipelineLayout> fragPipelineLayout; |
| |
| if (usedDescriptorSets == 2u) |
| { |
| fragSetIndex = bitsThatAreSet[1]; |
| fragDescriptorSetLayouts[fragSetIndex] = *usedDescriptorSetLayouts[1]; |
| allDescriptorSetLayouts[fragSetIndex] = *usedDescriptorSetLayouts[1]; |
| pipelineLayoutCreateInfo.setLayoutCount = fragSetIndex + 1u; |
| pipelineLayoutCreateInfo.pSetLayouts = fragDescriptorSetLayouts; |
| |
| fragPipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo); |
| } |
| else |
| { |
| pipelineLayoutCreateInfo.setLayoutCount = 0u; |
| pipelineLayoutCreateInfo.pSetLayouts = DE_NULL; |
| fragPipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo); |
| } |
| |
| // create descriptor pool |
| Move<VkDescriptorPool> descriptorPool = |
| DescriptorPoolBuilder() |
| .addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, usedDescriptorSets) |
| .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, usedDescriptorSets); |
| |
| const VkDescriptorBufferInfo vertShaderBufferInfo = |
| makeDescriptorBufferInfo(**uniformBuffer[0], 0u, uniformBufferDataSize); |
| Move<VkDescriptorSet> vertDescriptorSet = |
| makeDescriptorSet(vk, device, *descriptorPool, *usedDescriptorSetLayouts[0]); |
| Move<VkDescriptorSet> fragDescriptorSet; |
| |
| if (usedDescriptorSets == 1u) |
| { |
| // update single descriptors with actual buffer |
| DescriptorSetUpdateBuilder() |
| .writeSingle(*vertDescriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), |
| VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &vertShaderBufferInfo) |
| .update(vk, device); |
| } |
| else |
| { |
| const VkDescriptorBufferInfo fragShaderBufferInfo = |
| makeDescriptorBufferInfo(**uniformBuffer[1], 0u, uniformBufferDataSize); |
| fragDescriptorSet = makeDescriptorSet(vk, device, *descriptorPool, *usedDescriptorSetLayouts[1]); |
| |
| // update both descriptors with actual buffers |
| DescriptorSetUpdateBuilder() |
| .writeSingle(*vertDescriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), |
| VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &vertShaderBufferInfo) |
| .writeSingle(*fragDescriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), |
| VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &fragShaderBufferInfo) |
| .update(vk, device); |
| } |
| |
| pipelineLayoutCreateInfo.setLayoutCount = m_testParams.layoutsCount; |
| pipelineLayoutCreateInfo.pSetLayouts = allDescriptorSetLayouts; |
| Move<VkPipelineLayout> finalPipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo); |
| |
| const uint32_t commonPipelinePartFlags = uint32_t(VK_PIPELINE_CREATE_LIBRARY_BIT_KHR); |
| GraphicsPipelineCreateInfo partialPipelineCreateInfo[]{ |
| {*vertPipelineLayout, *m_renderPass, 0, commonPipelinePartFlags}, |
| {*fragPipelineLayout, *m_renderPass, 0, commonPipelinePartFlags}, |
| }; |
| |
| // fill proper portion of pipeline state |
| updateVertexInputInterface(m_context, partialPipelineCreateInfo[0], VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 0u); |
| updatePreRasterization(m_context, partialPipelineCreateInfo[0], false); |
| updatePostRasterization(m_context, partialPipelineCreateInfo[1], false); |
| updateFragmentOutputInterface(m_context, partialPipelineCreateInfo[1]); |
| |
| Move<VkPipeline> vertPipelinePart; |
| Move<VkPipeline> fragPipelinePart; |
| |
| // extend pNext chain and create partial pipelines |
| { |
| VkGraphicsPipelineLibraryCreateInfoEXT libraryCreateInfo = |
| makeGraphicsPipelineLibraryCreateInfo(VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT | |
| VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT); |
| appendStructurePtrToVulkanChain(&partialPipelineCreateInfo[0].pNext, &libraryCreateInfo); |
| vertPipelinePart = createGraphicsPipeline(vk, device, VK_NULL_HANDLE, &partialPipelineCreateInfo[0]); |
| |
| libraryCreateInfo.flags = VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT | |
| VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT, |
| appendStructurePtrToVulkanChain(&partialPipelineCreateInfo[1].pNext, &libraryCreateInfo); |
| fragPipelinePart = createGraphicsPipeline(vk, device, VK_NULL_HANDLE, &partialPipelineCreateInfo[1]); |
| } |
| |
| // create final pipeline out of two parts |
| std::vector<VkPipeline> rawParts = {*vertPipelinePart, *fragPipelinePart}; |
| VkPipelineLibraryCreateInfoKHR linkingInfo = makePipelineLibraryCreateInfo(rawParts); |
| VkGraphicsPipelineCreateInfo finalPipelineInfo = initVulkanStructure(); |
| |
| finalPipelineInfo.layout = *finalPipelineLayout; |
| appendStructurePtrToVulkanChain(&finalPipelineInfo.pNext, &linkingInfo); |
| Move<VkPipeline> pipeline = createGraphicsPipeline(vk, device, VK_NULL_HANDLE, &finalPipelineInfo); |
| |
| vk::beginCommandBuffer(vk, *m_cmdBuffer, 0u); |
| { |
| // change color image layout |
| const VkImageMemoryBarrier initialImageBarrier = makeImageMemoryBarrier( |
| 0, // VkAccessFlags srcAccessMask; |
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags dstAccessMask; |
| VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout; |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout newLayout; |
| **m_colorImage, // VkImage image; |
| {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u} // VkImageSubresourceRange subresourceRange; |
| ); |
| vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, |
| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, (VkDependencyFlags)0, 0, DE_NULL, 0, |
| DE_NULL, 1, &initialImageBarrier); |
| |
| // wait for uniform buffers |
| std::vector<VkBufferMemoryBarrier> initialBufferBarriers( |
| 2u, makeBufferMemoryBarrier(VK_ACCESS_HOST_WRITE_BIT, // VkAccessFlags2KHR srcAccessMask |
| VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags2KHR dstAccessMask |
| uniformBuffer[0]->get(), // VkBuffer buffer |
| 0u, // VkDeviceSize offset |
| uniformBufferDataSize // VkDeviceSize size |
| )); |
| initialBufferBarriers[1].buffer = uniformBuffer[1]->get(); |
| vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, |
| (VkDependencyFlags)0, 0, DE_NULL, 2, initialBufferBarriers.data(), 0, DE_NULL); |
| |
| beginRenderPass(vk, *m_cmdBuffer, *m_renderPass, *m_framebuffer, m_renderArea, m_colorClearColor); |
| |
| vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline); |
| |
| vk.cmdBindDescriptorSets(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *finalPipelineLayout, vertSetIndex, 1u, |
| &*vertDescriptorSet, 0u, DE_NULL); |
| if (usedDescriptorSets == 2u) |
| vk.cmdBindDescriptorSets(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *finalPipelineLayout, fragSetIndex, |
| 1u, &*fragDescriptorSet, 0u, DE_NULL); |
| |
| vk.cmdDraw(*m_cmdBuffer, 4, 1u, 0u, 0u); |
| |
| endRenderPass(vk, *m_cmdBuffer); |
| |
| const tcu::IVec2 size{(int32_t)m_renderArea.extent.width, (int32_t)m_renderArea.extent.height}; |
| copyImageToBuffer(vk, *m_cmdBuffer, **m_colorImage, *colorBuffer, size); |
| } |
| vk::endCommandBuffer(vk, *m_cmdBuffer); |
| vk::submitCommandsAndWait(vk, device, m_context.getUniversalQueue(), *m_cmdBuffer); |
| |
| vk::invalidateAlloc(vk, device, colorBuffer.getAllocation()); |
| const tcu::ConstPixelBufferAccess colorPixelAccess(mapVkFormat(m_colorFormat), m_renderArea.extent.width, |
| m_renderArea.extent.height, 1, |
| colorBuffer.getAllocation().getHostPtr()); |
| |
| // verify result |
| int32_t width = (int32_t)m_renderArea.extent.width; |
| int32_t height = (int32_t)m_renderArea.extent.height; |
| const std::vector<VerificationData> verificationData{ |
| {{1, 1}, {0, 51, 153, 191}}, // note COLOR_COMPONENTS_NO_RED is used |
| {{width / 2, height / 2}, {0, 51, 153, 191}}, |
| {{width - 2, height - 2}, {0, 0, 0, 255}} // clear color |
| }; |
| return verifyResult(verificationData, colorPixelAccess); |
| } |
| |
| tcu::TestStatus PipelineLibraryMiscTestInstance::runNullDescriptorSetInMonolithicPipeline() |
| { |
| // VK_NULL_HANDLE can be used for descriptor set layouts when creating a pipeline layout whether independent sets are used or not, |
| // as long as graphics pipeline libraries are enabled; VK_NULL_HANDLE is also alowed for a descriptor set under the same conditions |
| // when using vkCmdBindDescriptorSets |
| |
| const DeviceInterface &vk = m_context.getDeviceInterface(); |
| const VkDevice device = m_context.getDevice(); |
| Allocator &allocator = m_context.getDefaultAllocator(); |
| |
| const VkDeviceSize colorBufferDataSize = static_cast<VkDeviceSize>( |
| m_renderArea.extent.width * m_renderArea.extent.height * tcu::getPixelSize(mapVkFormat(m_colorFormat))); |
| const VkBufferCreateInfo colorBufferCreateInfo = makeBufferCreateInfo( |
| colorBufferDataSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); |
| const BufferWithMemory colorBuffer(vk, device, allocator, colorBufferCreateInfo, MemoryRequirement::HostVisible); |
| |
| const tcu::Vec4 uniformBuffData{0.0f, 0.20f, 0.6f, 0.75f}; |
| VkDeviceSize uniformBufferDataSize = sizeof(tcu::Vec4); |
| const VkBufferCreateInfo uniformBufferCreateInfo = |
| makeBufferCreateInfo(uniformBufferDataSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); |
| |
| de::MovePtr<BufferWithMemory> uniformBuffer = de::MovePtr<BufferWithMemory>( |
| new BufferWithMemory(vk, device, allocator, uniformBufferCreateInfo, MemoryRequirement::HostVisible)); |
| deMemcpy(uniformBuffer->getAllocation().getHostPtr(), uniformBuffData.getPtr(), (size_t)uniformBufferDataSize); |
| flushAlloc(vk, device, uniformBuffer->getAllocation()); |
| |
| // create descriptor set layouts - first unused, second used |
| Move<VkDescriptorSetLayout> descriptorSetLayout{ |
| DescriptorSetLayoutBuilder() |
| .addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT) |
| .build(vk, device)}; |
| |
| Move<VkDescriptorPool> allDescriptorPool = |
| DescriptorPoolBuilder() |
| .addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1) |
| .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1); |
| |
| // create descriptor set |
| Move<VkDescriptorSet> descriptorSet = makeDescriptorSet(vk, device, *allDescriptorPool, *descriptorSetLayout); |
| |
| // update descriptor with actual buffer |
| const VkDescriptorBufferInfo shaderBufferInfo = |
| makeDescriptorBufferInfo(**uniformBuffer, 0u, uniformBufferDataSize); |
| DescriptorSetUpdateBuilder() |
| .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), |
| VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &shaderBufferInfo) |
| .update(vk, device); |
| |
| // create a pipeline layout with its first descriptor set layout as VK_NULL_HANDLE |
| // and a second with a valid descriptor set layout containing a buffer |
| VkDescriptorSet rawDescriptorSets[] = {VK_NULL_HANDLE, *descriptorSet}; |
| VkDescriptorSetLayout rawDescriptorSetLayouts[] = {VK_NULL_HANDLE, *descriptorSetLayout}; |
| |
| VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = initVulkanStructure(); |
| pipelineLayoutCreateInfo.setLayoutCount = 2u; |
| pipelineLayoutCreateInfo.pSetLayouts = rawDescriptorSetLayouts; |
| Move<VkPipelineLayout> pipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo); |
| |
| // create monolithic graphics pipeline |
| GraphicsPipelineCreateInfo pipelineCreateInfo(*pipelineLayout, *m_renderPass, 0, 0u); |
| updateVertexInputInterface(m_context, pipelineCreateInfo, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 0u); |
| updatePreRasterization(m_context, pipelineCreateInfo, false); |
| updatePostRasterization(m_context, pipelineCreateInfo, false); |
| updateFragmentOutputInterface(m_context, pipelineCreateInfo); |
| Move<VkPipeline> pipeline = createGraphicsPipeline(vk, device, VK_NULL_HANDLE, &pipelineCreateInfo); |
| |
| vk::beginCommandBuffer(vk, *m_cmdBuffer, 0u); |
| { |
| // change color image layout |
| const VkImageMemoryBarrier initialImageBarrier = makeImageMemoryBarrier( |
| 0, // VkAccessFlags srcAccessMask; |
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags dstAccessMask; |
| VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout; |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout newLayout; |
| **m_colorImage, // VkImage image; |
| {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u} // VkImageSubresourceRange subresourceRange; |
| ); |
| vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, |
| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, (VkDependencyFlags)0, 0, DE_NULL, 0, |
| DE_NULL, 1, &initialImageBarrier); |
| |
| // wait for uniform buffer |
| const VkBufferMemoryBarrier initialBufferBarrier = |
| makeBufferMemoryBarrier(VK_ACCESS_HOST_WRITE_BIT, // VkAccessFlags2KHR srcAccessMask |
| VK_ACCESS_UNIFORM_READ_BIT, // VkAccessFlags2KHR dstAccessMask |
| uniformBuffer->get(), // VkBuffer buffer |
| 0u, // VkDeviceSize offset |
| uniformBufferDataSize // VkDeviceSize size |
| ); |
| vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, |
| (VkDependencyFlags)0, 0, DE_NULL, 1, &initialBufferBarrier, 0, DE_NULL); |
| |
| beginRenderPass(vk, *m_cmdBuffer, *m_renderPass, *m_framebuffer, m_renderArea, m_colorClearColor); |
| |
| vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline); |
| vk.cmdBindDescriptorSets(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 2u, |
| rawDescriptorSets, 0u, DE_NULL); |
| vk.cmdDraw(*m_cmdBuffer, 4, 1u, 0u, 0u); |
| |
| endRenderPass(vk, *m_cmdBuffer); |
| |
| const tcu::IVec2 size{(int32_t)m_renderArea.extent.width, (int32_t)m_renderArea.extent.height}; |
| copyImageToBuffer(vk, *m_cmdBuffer, **m_colorImage, *colorBuffer, size); |
| } |
| vk::endCommandBuffer(vk, *m_cmdBuffer); |
| vk::submitCommandsAndWait(vk, device, m_context.getUniversalQueue(), *m_cmdBuffer); |
| |
| vk::invalidateAlloc(vk, device, colorBuffer.getAllocation()); |
| const tcu::ConstPixelBufferAccess colorPixelAccess(mapVkFormat(m_colorFormat), m_renderArea.extent.width, |
| m_renderArea.extent.height, 1, |
| colorBuffer.getAllocation().getHostPtr()); |
| |
| // verify result |
| int32_t width = (int32_t)m_renderArea.extent.width; |
| int32_t height = (int32_t)m_renderArea.extent.height; |
| tcu::IVec4 outColor{0, // r is 0 because COLOR_COMPONENTS_NO_RED is used |
| static_cast<int>(uniformBuffData[1] * 255), static_cast<int>(uniformBuffData[2] * 255), |
| static_cast<int>(uniformBuffData[3] * 255)}; |
| const std::vector<VerificationData> verificationData{ |
| {{1, 1}, outColor}, |
| {{width / 2, height / 2}, outColor}, |
| {{width - 2, height - 2}, {0, 0, 0, 255}} // clear color |
| }; |
| |
| return verifyResult(verificationData, colorPixelAccess); |
| } |
| |
| tcu::TestStatus PipelineLibraryMiscTestInstance::runIndependentPipelineLayoutSets(bool useLinkTimeOptimization) |
| { |
| const DeviceInterface &vk = m_context.getDeviceInterface(); |
| const VkDevice device = m_context.getDevice(); |
| Allocator &allocator = m_context.getDefaultAllocator(); |
| |
| const VkDeviceSize colorBufferDataSize = static_cast<VkDeviceSize>( |
| m_renderArea.extent.width * m_renderArea.extent.height * tcu::getPixelSize(mapVkFormat(m_colorFormat))); |
| const VkBufferCreateInfo colorBufferCreateInfo = makeBufferCreateInfo( |
| colorBufferDataSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); |
| const BufferWithMemory colorBuffer(vk, device, allocator, colorBufferCreateInfo, MemoryRequirement::HostVisible); |
| |
| VkDeviceSize uniformBufferDataSize = sizeof(tcu::Vec4); |
| const VkBufferCreateInfo uniformBufferCreateInfo = |
| makeBufferCreateInfo(uniformBufferDataSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); |
| |
| de::MovePtr<BufferWithMemory> uniformBuffer[3]; |
| |
| // setup data in uniform buffers that will give us expected result for validation |
| const tcu::Vec4 uniformBuffData[3]{ |
| {4.00f, 3.00f, -1.0f, 4.00f}, |
| {0.10f, 0.25f, -0.5f, 0.05f}, |
| {-5.00f, -2.00f, 3.0f, -6.00f}, |
| }; |
| |
| for (uint32_t i = 0; i < 3; ++i) |
| { |
| uniformBuffer[i] = de::MovePtr<BufferWithMemory>( |
| new BufferWithMemory(vk, device, allocator, uniformBufferCreateInfo, MemoryRequirement::HostVisible)); |
| deMemcpy(uniformBuffer[i]->getAllocation().getHostPtr(), uniformBuffData[i].getPtr(), |
| (size_t)uniformBufferDataSize); |
| flushAlloc(vk, device, uniformBuffer[i]->getAllocation()); |
| } |
| |
| // create three descriptor set layouts |
| Move<VkDescriptorSetLayout> descriptorSetLayouts[3]; |
| descriptorSetLayouts[0] = DescriptorSetLayoutBuilder() |
| .addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, |
| VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT) |
| .build(vk, device); |
| descriptorSetLayouts[1] = DescriptorSetLayoutBuilder() |
| .addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT) |
| .build(vk, device); |
| descriptorSetLayouts[2] = DescriptorSetLayoutBuilder() |
| .addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT) |
| .build(vk, device); |
| |
| // for the link time opt (and when null handle is used) use total pipeline layout recreated without the INDEPENDENT SETS bit |
| uint32_t allLayoutsFlag = uint32_t(VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT); |
| if (useLinkTimeOptimization) |
| allLayoutsFlag = 0u; |
| |
| // Pre-rasterization stage library has sets 0, 1, 2 |
| // * set 0 has descriptors |
| // * set 1 has no descriptors |
| // * set 2 has descriptors |
| // Fragment stage library has sets 0, 1 |
| // * set 0 has descriptors |
| // * set 1 has descriptors |
| VkDescriptorSetLayout vertDescriptorSetLayouts[] = {*descriptorSetLayouts[0], VK_NULL_HANDLE, |
| *descriptorSetLayouts[2]}; |
| VkDescriptorSetLayout fragDescriptorSetLayouts[] = {*descriptorSetLayouts[0], *descriptorSetLayouts[1]}; |
| VkDescriptorSetLayout allDescriptorSetLayouts[] = {*descriptorSetLayouts[0], *descriptorSetLayouts[1], |
| *descriptorSetLayouts[2]}; |
| |
| VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = initVulkanStructure(); |
| pipelineLayoutCreateInfo.flags = allLayoutsFlag; |
| pipelineLayoutCreateInfo.setLayoutCount = 3u; |
| pipelineLayoutCreateInfo.pSetLayouts = allDescriptorSetLayouts; |
| Move<VkPipelineLayout> allLayouts = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo); |
| pipelineLayoutCreateInfo.flags = uint32_t(VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT); |
| pipelineLayoutCreateInfo.pSetLayouts = vertDescriptorSetLayouts; |
| Move<VkPipelineLayout> vertLayouts = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo); |
| pipelineLayoutCreateInfo.setLayoutCount = 2u; |
| pipelineLayoutCreateInfo.pSetLayouts = fragDescriptorSetLayouts; |
| Move<VkPipelineLayout> fragLayouts = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo); |
| |
| Move<VkDescriptorPool> allDescriptorPool = |
| DescriptorPoolBuilder() |
| .addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 3) |
| .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 3); |
| |
| // create three descriptor sets |
| Move<VkDescriptorSet> descriptorSetA = makeDescriptorSet(vk, device, *allDescriptorPool, *descriptorSetLayouts[0]); |
| Move<VkDescriptorSet> descriptorSetB = makeDescriptorSet(vk, device, *allDescriptorPool, *descriptorSetLayouts[1]); |
| Move<VkDescriptorSet> descriptorSetC = makeDescriptorSet(vk, device, *allDescriptorPool, *descriptorSetLayouts[2]); |
| VkDescriptorSet allDescriptorSets[] = {*descriptorSetA, *descriptorSetB, *descriptorSetC}; |
| |
| // update descriptors with actual buffers |
| const VkDescriptorBufferInfo shaderBufferAInfo = |
| makeDescriptorBufferInfo(**uniformBuffer[0], 0u, uniformBufferDataSize); |
| const VkDescriptorBufferInfo shaderBufferBInfo = |
| makeDescriptorBufferInfo(**uniformBuffer[1], 0u, uniformBufferDataSize); |
| const VkDescriptorBufferInfo shaderBufferCInfo = |
| makeDescriptorBufferInfo(**uniformBuffer[2], 0u, uniformBufferDataSize); |
| DescriptorSetUpdateBuilder() |
| .writeSingle(*descriptorSetA, DescriptorSetUpdateBuilder::Location::binding(0u), |
| VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &shaderBufferAInfo) |
| .writeSingle(*descriptorSetB, DescriptorSetUpdateBuilder::Location::binding(0u), |
| VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &shaderBufferBInfo) |
| .writeSingle(*descriptorSetC, DescriptorSetUpdateBuilder::Location::binding(0u), |
| VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &shaderBufferCInfo) |
| .update(vk, device); |
| |
| uint32_t commonPipelinePartFlags = uint32_t(VK_PIPELINE_CREATE_LIBRARY_BIT_KHR); |
| uint32_t finalPipelineFlag = 0u; |
| if (useLinkTimeOptimization) |
| { |
| commonPipelinePartFlags |= uint32_t(VK_PIPELINE_CREATE_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT); |
| finalPipelineFlag = uint32_t(VK_PIPELINE_CREATE_LINK_TIME_OPTIMIZATION_BIT_EXT); |
| } |
| |
| GraphicsPipelineCreateInfo partialPipelineCreateInfo[]{{VK_NULL_HANDLE, *m_renderPass, 0, commonPipelinePartFlags}, |
| {*vertLayouts, *m_renderPass, 0, commonPipelinePartFlags}, |
| {*fragLayouts, *m_renderPass, 0, commonPipelinePartFlags}, |
| {VK_NULL_HANDLE, *m_renderPass, 0, commonPipelinePartFlags}}; |
| |
| // fill proper portion of pipeline state |
| updateVertexInputInterface(m_context, partialPipelineCreateInfo[0], VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 0u); |
| updatePreRasterization(m_context, partialPipelineCreateInfo[1], false); |
| updatePostRasterization(m_context, partialPipelineCreateInfo[2], false); |
| updateFragmentOutputInterface(m_context, partialPipelineCreateInfo[3]); |
| |
| // extend pNext chain and create all partial pipelines |
| std::vector<VkPipeline> rawParts(4u, VK_NULL_HANDLE); |
| std::vector<Move<VkPipeline>> pipelineParts; |
| pipelineParts.reserve(4u); |
| VkGraphicsPipelineLibraryCreateInfoEXT libraryCreateInfo = |
| makeGraphicsPipelineLibraryCreateInfo(VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT); |
| for (uint32_t i = 0; i < 4u; ++i) |
| { |
| libraryCreateInfo.flags = GRAPHICS_PIPELINE_LIBRARY_FLAGS[i]; |
| appendStructurePtrToVulkanChain(&partialPipelineCreateInfo[i].pNext, &libraryCreateInfo); |
| pipelineParts.emplace_back(createGraphicsPipeline(vk, device, VK_NULL_HANDLE, &partialPipelineCreateInfo[i])); |
| rawParts[i] = *pipelineParts[i]; |
| } |
| |
| // create final pipeline out of four parts |
| VkPipelineLibraryCreateInfoKHR linkingInfo = makePipelineLibraryCreateInfo(rawParts); |
| VkGraphicsPipelineCreateInfo finalPipelineInfo = initVulkanStructure(); |
| |
| finalPipelineInfo.flags = finalPipelineFlag; |
| finalPipelineInfo.layout = *allLayouts; |
| |
| appendStructurePtrToVulkanChain(&finalPipelineInfo.pNext, &linkingInfo); |
| Move<VkPipeline> pipeline = createGraphicsPipeline(vk, device, VK_NULL_HANDLE, &finalPipelineInfo); |
| |
| vk::beginCommandBuffer(vk, *m_cmdBuffer, 0u); |
| { |
| // change color image layout |
| const VkImageMemoryBarrier initialImageBarrier = makeImageMemoryBarrier( |
| 0, // VkAccessFlags srcAccessMask; |
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags dstAccessMask; |
| VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout; |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout newLayout; |
| **m_colorImage, // VkImage image; |
| {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u} // VkImageSubresourceRange subresourceRange; |
| ); |
| vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, |
| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, (VkDependencyFlags)0, 0, DE_NULL, 0, |
| DE_NULL, 1, &initialImageBarrier); |
| |
| // wait for uniform buffers |
| std::vector<VkBufferMemoryBarrier> initialBufferBarriers( |
| 3u, makeBufferMemoryBarrier(VK_ACCESS_HOST_WRITE_BIT, // VkAccessFlags2KHR srcAccessMask |
| VK_ACCESS_UNIFORM_READ_BIT, // VkAccessFlags2KHR dstAccessMask |
| uniformBuffer[0]->get(), // VkBuffer buffer |
| 0u, // VkDeviceSize offset |
| uniformBufferDataSize // VkDeviceSize size |
| )); |
| initialBufferBarriers[1].buffer = uniformBuffer[1]->get(); |
| initialBufferBarriers[2].buffer = uniformBuffer[2]->get(); |
| vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, |
| (VkDependencyFlags)0, 0, DE_NULL, 3, initialBufferBarriers.data(), 0, DE_NULL); |
| |
| beginRenderPass(vk, *m_cmdBuffer, *m_renderPass, *m_framebuffer, m_renderArea, m_colorClearColor); |
| |
| vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline); |
| vk.cmdBindDescriptorSets(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *allLayouts, 0u, 3u, allDescriptorSets, |
| 0u, DE_NULL); |
| vk.cmdDraw(*m_cmdBuffer, 4, 1u, 0u, 0u); |
| |
| endRenderPass(vk, *m_cmdBuffer); |
| |
| const tcu::IVec2 size{(int32_t)m_renderArea.extent.width, (int32_t)m_renderArea.extent.height}; |
| copyImageToBuffer(vk, *m_cmdBuffer, **m_colorImage, *colorBuffer, size); |
| } |
| vk::endCommandBuffer(vk, *m_cmdBuffer); |
| vk::submitCommandsAndWait(vk, device, m_context.getUniversalQueue(), *m_cmdBuffer); |
| |
| vk::invalidateAlloc(vk, device, colorBuffer.getAllocation()); |
| const tcu::ConstPixelBufferAccess colorPixelAccess(mapVkFormat(m_colorFormat), m_renderArea.extent.width, |
| m_renderArea.extent.height, 1, |
| colorBuffer.getAllocation().getHostPtr()); |
| |
| // verify result |
| int32_t width = (int32_t)m_renderArea.extent.width; |
| int32_t height = (int32_t)m_renderArea.extent.height; |
| const std::vector<VerificationData> verificationData{ |
| {{1, 1}, {0, 191, 127, 51}}, // note COLOR_COMPONENTS_NO_RED is used |
| {{width / 2, height / 2}, {0, 191, 127, 51}}, |
| {{width - 2, height - 2}, {0, 0, 0, 255}} // clear color |
| }; |
| return verifyResult(verificationData, colorPixelAccess); |
| } |
| |
| tcu::TestStatus PipelineLibraryMiscTestInstance::runCompareLinkTimes(void) |
| { |
| const uint32_t uniqueLibrariesCount = 2u; |
| const uint32_t pipelinesCount = 4u * uniqueLibrariesCount; |
| |
| const DeviceInterface &vk = m_context.getDeviceInterface(); |
| const VkDevice device = m_context.getDevice(); |
| tcu::TestLog &log = m_context.getTestContext().getLog(); |
| bool allChecksPassed = true; |
| VkPipelineLayoutCreateInfo pipelineLayoutParams = initVulkanStructure(); |
| Move<VkPipelineLayout> layout = createPipelineLayout(vk, device, &pipelineLayoutParams); |
| |
| GraphicsPipelineCreateInfo partialPipelineCreateInfo[]{ |
| {*layout, *m_renderPass, 0, VK_PIPELINE_CREATE_LIBRARY_BIT_KHR}, |
| {*layout, *m_renderPass, 0, VK_PIPELINE_CREATE_LIBRARY_BIT_KHR}, |
| {*layout, *m_renderPass, 0, VK_PIPELINE_CREATE_LIBRARY_BIT_KHR}, |
| {*layout, *m_renderPass, 0, VK_PIPELINE_CREATE_LIBRARY_BIT_KHR}, |
| {*layout, *m_renderPass, 0, VK_PIPELINE_CREATE_LIBRARY_BIT_KHR}, |
| {*layout, *m_renderPass, 0, VK_PIPELINE_CREATE_LIBRARY_BIT_KHR}, |
| {*layout, *m_renderPass, 0, VK_PIPELINE_CREATE_LIBRARY_BIT_KHR}, |
| {*layout, *m_renderPass, 0, VK_PIPELINE_CREATE_LIBRARY_BIT_KHR}, |
| }; |
| |
| de::Random rnd(static_cast<uint32_t>(deGetMicroseconds())); |
| |
| const uint32_t vertexRandSpecConsts[] = {rnd.getUint32() * 2, rnd.getUint32() * 2}; |
| const uint32_t fragmentRandSpecConsts[] = {rnd.getUint32() * 2, rnd.getUint32() * 2}; |
| |
| const VkSpecializationMapEntry entry = { |
| 0, // uint32_t constantID; |
| 0, // uint32_t offset; |
| sizeof(int32_t) // size_t size; |
| }; |
| |
| const VkSpecializationInfo vertexSpecializationInfos[] = { |
| { |
| 1u, // uint32_t mapEntryCount; |
| &entry, // const VkSpecializationMapEntry* pMapEntries; |
| sizeof(int32_t), // size_t dataSize; |
| &vertexRandSpecConsts[0] // const void* pData; |
| }, |
| { |
| 1u, // uint32_t mapEntryCount; |
| &entry, // const VkSpecializationMapEntry* pMapEntries; |
| sizeof(int32_t), // size_t dataSize; |
| &vertexRandSpecConsts[1] // const void* pData; |
| }}; |
| |
| const VkSpecializationInfo fragmentSpecializationInfos[] = { |
| { |
| 1u, // uint32_t mapEntryCount; |
| &entry, // const VkSpecializationMapEntry* pMapEntries; |
| sizeof(int32_t), // size_t dataSize; |
| &fragmentRandSpecConsts[0] // const void* pData; |
| }, |
| { |
| 1u, // uint32_t mapEntryCount; |
| &entry, // const VkSpecializationMapEntry* pMapEntries; |
| sizeof(int32_t), // size_t dataSize; |
| &fragmentRandSpecConsts[1] // const void* pData; |
| }}; |
| |
| // fill proper portion of pipeline state - this cant be easily done in a scalable loop |
| updateVertexInputInterface(m_context, partialPipelineCreateInfo[0], VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP); |
| updateVertexInputInterface(m_context, partialPipelineCreateInfo[1], VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST); |
| updatePreRasterization(m_context, partialPipelineCreateInfo[2], false, false, false, VK_POLYGON_MODE_FILL, |
| &vertexSpecializationInfos[0]); |
| updatePreRasterization(m_context, partialPipelineCreateInfo[3], false, false, false, VK_POLYGON_MODE_LINE, |
| &vertexSpecializationInfos[1]); |
| updatePostRasterization(m_context, partialPipelineCreateInfo[4], false, true, &fragmentSpecializationInfos[0]); |
| updatePostRasterization(m_context, partialPipelineCreateInfo[5], false, false, &fragmentSpecializationInfos[1]); |
| updateFragmentOutputInterface(m_context, partialPipelineCreateInfo[6], 0xf); |
| updateFragmentOutputInterface(m_context, partialPipelineCreateInfo[7]); |
| |
| // construct all pipeline parts and mesure time it took |
| struct PipelinePartData |
| { |
| Move<VkPipeline> pipelineHandle; |
| std::chrono::duration<int64_t, std::nano> creationDuration; |
| }; |
| std::vector<PipelinePartData> pipelinePartData(pipelinesCount); |
| VkGraphicsPipelineLibraryCreateInfoEXT libraryCreateInfo = |
| makeGraphicsPipelineLibraryCreateInfo(VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT); |
| for (uint32_t i = 0; i < pipelinesCount; ++i) |
| { |
| appendStructurePtrToVulkanChain(&partialPipelineCreateInfo[i].pNext, &libraryCreateInfo); |
| libraryCreateInfo.flags = GRAPHICS_PIPELINE_LIBRARY_FLAGS[i / 2]; |
| |
| auto &partData = pipelinePartData[i]; |
| auto timeStart = std::chrono::high_resolution_clock::now(); |
| partData.pipelineHandle = createGraphicsPipeline(vk, device, VK_NULL_HANDLE, partialPipelineCreateInfo + i); |
| partData.creationDuration = std::chrono::high_resolution_clock::now() - timeStart; |
| } |
| |
| // iterate over all combinations of parts |
| for (uint32_t i = 0u; i < (uint32_t)dePow(4, uniqueLibrariesCount); ++i) |
| { |
| // select new unique combination of parts |
| uint32_t vertexInputIndex = (i) % 2; |
| uint32_t preRasterizationIndex = (i / 2) % 2; |
| uint32_t fragmentStateIndex = (i / 4) % 2; |
| uint32_t fragmentOutputIndex = (i / 8) % 2; |
| |
| const auto &vertexInputData = pipelinePartData[vertexInputIndex]; |
| const auto &preRasterizationData = pipelinePartData[uniqueLibrariesCount + preRasterizationIndex]; |
| const auto &fragmentStateData = pipelinePartData[2 * uniqueLibrariesCount + fragmentStateIndex]; |
| const auto &fragmentOutputData = pipelinePartData[3 * uniqueLibrariesCount + fragmentOutputIndex]; |
| |
| std::vector<VkPipeline> pipelinesToLink{ |
| *vertexInputData.pipelineHandle, |
| *preRasterizationData.pipelineHandle, |
| *fragmentStateData.pipelineHandle, |
| *fragmentOutputData.pipelineHandle, |
| }; |
| |
| VkPipelineLibraryCreateInfoKHR linkingInfo = makePipelineLibraryCreateInfo(pipelinesToLink); |
| VkGraphicsPipelineCreateInfo finalPipelineInfo = initVulkanStructure(); |
| finalPipelineInfo.layout = *layout; |
| |
| appendStructurePtrToVulkanChain(&finalPipelineInfo.pNext, &linkingInfo); |
| |
| // link pipeline without the optimised bit, and record the time taken to link it |
| auto timeStart = std::chrono::high_resolution_clock::now(); |
| Move<VkPipeline> pipeline = createGraphicsPipeline(vk, device, VK_NULL_HANDLE, &finalPipelineInfo); |
| const auto linkingTime = std::chrono::high_resolution_clock::now() - timeStart; |
| const auto creationTime = preRasterizationData.creationDuration + fragmentStateData.creationDuration; |
| |
| if (linkingTime > (10 * creationTime)) |
| { |
| allChecksPassed = false; |
| log << tcu::TestLog::Message << "Liking time (" << linkingTime.count() << ") of combination " << i |
| << " is more then ten times greater than creation of both pre-rasterization and fragment states (" |
| << creationTime.count() << ")" << tcu::TestLog::EndMessage; |
| } |
| } |
| |
| if (allChecksPassed) |
| return tcu::TestStatus::pass("Pass"); |
| |
| return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Liking of one or more combinations took to long"); |
| } |
| |
| /* |
| Middle bar should contain clip distance with linear values between 0 and 1. |
| Cull distance is always 0.5 when enabled. |
| */ |
| void makeReferenceImage(tcu::PixelBufferAccess &reference, IVec2 clipRegion, const int numBars, int barIdx, |
| const tcu::Vec4 &clipAreaColor) |
| { |
| for (int y = 0; y < reference.getHeight(); ++y) |
| for (int x = 0; x < reference.getWidth(); ++x) |
| { |
| if (x < clipRegion.x() && y < clipRegion.y()) |
| { |
| reference.setPixel(clipAreaColor, x, y); |
| continue; |
| } |
| |
| const int barWidth = reference.getWidth() / numBars; |
| const bool insideBar = x >= barWidth * barIdx && x < barWidth * (barIdx + 1); |
| const float expectedClipDistance = |
| insideBar ? (((((float)y + 0.5f) / (float)reference.getHeight()) - 0.5f) * 2.0f) : 0.0f; |
| float expectedCullDistance = 0.5f; |
| const float height = (float)reference.getHeight(); |
| |
| if (y >= (reference.getHeight() / 2)) |
| expectedCullDistance = expectedCullDistance * (1.0f + (2.0f * (float)y) - height) / height; |
| else |
| expectedCullDistance = 0.0f; |
| |
| const tcu::Vec4 expectedColor = Vec4(1.0, expectedClipDistance, expectedCullDistance, 1.0); |
| reference.setPixel(expectedColor, x, y); |
| } |
| } |
| |
| de::MovePtr<BufferWithMemory> makeVertexBuffer(const DeviceInterface &vk, const VkDevice device, Allocator &allocator, |
| std::vector<tcu::Vec4> &vertexData, VkBufferUsageFlagBits usageFlags) |
| { |
| const size_t bufferDataSize = de::dataSize(vertexData); |
| const VkBufferCreateInfo bufferCreateInfo = makeBufferCreateInfo(bufferDataSize, usageFlags); |
| de::MovePtr<BufferWithMemory> buffer = de::MovePtr<BufferWithMemory>( |
| new BufferWithMemory(vk, device, allocator, bufferCreateInfo, MemoryRequirement::HostVisible)); |
| |
| deMemcpy(buffer->getAllocation().getHostPtr(), vertexData.data(), bufferDataSize); |
| flushAlloc(vk, device, buffer->getAllocation()); |
| |
| return buffer; |
| } |
| |
| /* |
| Pipeline libraries: |
| Compile a fragment only pipeline library L1. |
| Compile a mesh only pipeline library L2. |
| Compile a vertex only pipeline library L3. |
| Fast link L2 & L1. |
| Fast link L3 & L1. |
| Shaders: |
| Vertex and mesh shaders write clip distance and cull distance. |
| Fragment shader reads clip distance and cull distance. |
| Clip and cull tests taken from vktClippingTests. |
| */ |
| tcu::TestStatus PipelineLibraryMiscTestInstance::runCommonFragLibraryTest(void) |
| { |
| const DeviceInterface &vk = m_context.getDeviceInterface(); |
| const VkDevice device = m_context.getDevice(); |
| Allocator &allocator = m_context.getDefaultAllocator(); |
| |
| // create output buffer for verification |
| const VkDeviceSize outputBufferDataSize = static_cast<VkDeviceSize>( |
| m_renderArea.extent.width * m_renderArea.extent.height * tcu::getPixelSize(mapVkFormat(m_colorFormat))); |
| const VkBufferCreateInfo outputBufferCreateInfo = makeBufferCreateInfo( |
| outputBufferDataSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); |
| const BufferWithMemory outputBuffer(vk, device, allocator, outputBufferCreateInfo, MemoryRequirement::HostVisible); |
| |
| const int numBars = numClipDistances + numCullDistances; |
| |
| // vertex shader input |
| std::vector<Vec4> vertices; |
| { |
| const float dx = 2.0f / numBars; |
| for (int i = 0; i < numBars; ++i) |
| { |
| const float x = -1.0f + dx * static_cast<float>(i); |
| |
| vertices.push_back(Vec4(x, -1.0f, 0.0f, 1.0f)); |
| vertices.push_back(Vec4(x, 1.0f, 0.0f, 1.0f)); |
| vertices.push_back(Vec4(x + dx, -1.0f, 0.0f, 1.0f)); |
| |
| vertices.push_back(Vec4(x, 1.0f, 0.0f, 1.0f)); |
| vertices.push_back(Vec4(x + dx, 1.0f, 0.0f, 1.0f)); |
| vertices.push_back(Vec4(x + dx, -1.0f, 0.0f, 1.0f)); |
| } |
| } |
| |
| const auto vertexBufferStages = (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_MESH_BIT_EXT); |
| const auto vertexBufferSize = static_cast<VkDeviceSize>(de::dataSize(vertices)); |
| const auto vertexCount = de::sizeU32(vertices); |
| const auto vertexBufferUsage = (VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); |
| const auto vertexBufferLoc = DescriptorSetUpdateBuilder::Location::binding(0u); |
| const auto vertexBufferType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; |
| |
| // Vertex buffer. |
| const de::MovePtr<BufferWithMemory> vertexBuffer = |
| makeVertexBuffer(vk, device, allocator, vertices, (VkBufferUsageFlagBits)vertexBufferUsage); |
| |
| // for the link time opt (and when null handle is used) use total pipeline layout recreated without the INDEPENDENT SETS bit |
| const auto allLayoutsFlag = VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT; |
| |
| // Set layout. |
| DescriptorSetLayoutBuilder layoutBuilder; |
| layoutBuilder.addSingleBinding(vertexBufferType, vertexBufferStages); |
| const auto descriptorSetLayout = layoutBuilder.build(vk, device); |
| |
| // Descriptor pool. |
| DescriptorPoolBuilder poolBuilder; |
| poolBuilder.addType(vertexBufferType); |
| const auto descriptorPool = poolBuilder.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u); |
| |
| // Descriptor set. |
| const auto descriptorSet = makeDescriptorSet(vk, device, descriptorPool.get(), descriptorSetLayout.get()); |
| |
| // Update descriptor set. |
| DescriptorSetUpdateBuilder updateBuilder; |
| const auto vertexBufferDescInfo = makeDescriptorBufferInfo(vertexBuffer->get(), 0ull, vertexBufferSize); |
| updateBuilder.writeSingle(descriptorSet.get(), vertexBufferLoc, vertexBufferType, &vertexBufferDescInfo); |
| updateBuilder.update(vk, device); |
| |
| // Setup pipeline libraries |
| VkDescriptorSet allDescriptorSets[] = {*descriptorSet}; |
| |
| VkDescriptorSetLayout meshDescriptorSetLayouts[] = {*descriptorSetLayout}; |
| VkDescriptorSetLayout allDescriptorSetLayouts[] = {*descriptorSetLayout}; |
| |
| VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = initVulkanStructure(); |
| pipelineLayoutCreateInfo.flags = allLayoutsFlag; |
| pipelineLayoutCreateInfo.setLayoutCount = 1u; |
| pipelineLayoutCreateInfo.pSetLayouts = allDescriptorSetLayouts; |
| Move<VkPipelineLayout> allLayouts = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo); |
| |
| pipelineLayoutCreateInfo.pSetLayouts = meshDescriptorSetLayouts; |
| Move<VkPipelineLayout> meshLayouts = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo); |
| |
| pipelineLayoutCreateInfo.setLayoutCount = 0u; |
| pipelineLayoutCreateInfo.pSetLayouts = nullptr; |
| Move<VkPipelineLayout> vertLayouts = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo); |
| Move<VkPipelineLayout> fragLayouts = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo); |
| Move<VkPipelineLayout> nullLayout = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo); |
| |
| const uint32_t commonPipelinePartFlags = uint32_t(VK_PIPELINE_CREATE_LIBRARY_BIT_KHR); |
| |
| enum |
| { |
| PIPELINE_CREATEINFO_IDX_VII = 0, |
| PIPELINE_CREATEINFO_IDX_PRERAST_VERT, |
| PIPELINE_CREATEINFO_IDX_PRERAST_MESH, |
| PIPELINE_CREATEINFO_IDX_POSTRAST, |
| PIPELINE_CREATEINFO_IDX_FO, |
| PIPELINE_CREATEINFO_IDX_MAX |
| }; |
| |
| const VkGraphicsPipelineLibraryFlagBitsEXT map_pipeline_createinfo_to_flags[PIPELINE_CREATEINFO_IDX_MAX] = { |
| VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT, |
| VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT, // pre-rasterization (vert) |
| VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT, // pre-rasterization (mesh) |
| VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT, |
| VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT}; |
| |
| GraphicsPipelineCreateInfo allPipelineCreateInfos[]{ |
| {VK_NULL_HANDLE, *m_renderPass, 0, |
| commonPipelinePartFlags}, // [PIPELINE_CREATEINFO_IDX_VII]: vertex input interface |
| {*vertLayouts, *m_renderPass, 0, |
| commonPipelinePartFlags}, // [PIPELINE_CREATEINFO_IDX_PRERAST_VERT]: pre-rasterization (vert) |
| {*meshLayouts, *m_renderPass, 0, |
| commonPipelinePartFlags}, // [PIPELINE_CREATEINFO_IDX_PRERAST_MESH]: pre-rasterization (mesh) |
| {*fragLayouts, *m_renderPass, 0, |
| commonPipelinePartFlags}, // [PIPELINE_CREATEINFO_IDX_POSTRAST]: post-rasterization (frag) |
| {VK_NULL_HANDLE, *m_renderPass, 0, |
| commonPipelinePartFlags}, // [PIPELINE_CREATEINFO_IDX_FO]: frag output interface |
| }; |
| |
| // initialize VkGraphicsPipelineLibraryCreateInfoEXT for each library |
| std::vector<VkGraphicsPipelineLibraryCreateInfoEXT> libraryCreateInfos; |
| for (uint32_t i = 0; i < PIPELINE_CREATEINFO_IDX_MAX; i++) |
| { |
| VkGraphicsPipelineLibraryFlagBitsEXT flag = map_pipeline_createinfo_to_flags[i]; |
| libraryCreateInfos.push_back(makeGraphicsPipelineLibraryCreateInfo(flag)); |
| } |
| |
| // vertex-only pipeline parts |
| uint32_t pipelineCreateInfoIdx = PIPELINE_CREATEINFO_IDX_VII; |
| updateVertexInputInterface(m_context, allPipelineCreateInfos[pipelineCreateInfoIdx], |
| VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 1u); |
| appendStructurePtrToVulkanChain(&allPipelineCreateInfos[pipelineCreateInfoIdx].pNext, |
| &libraryCreateInfos[pipelineCreateInfoIdx]); |
| |
| pipelineCreateInfoIdx = PIPELINE_CREATEINFO_IDX_PRERAST_VERT; |
| updatePreRasterization(m_context, allPipelineCreateInfos[pipelineCreateInfoIdx], false, true); |
| appendStructurePtrToVulkanChain(&allPipelineCreateInfos[pipelineCreateInfoIdx].pNext, |
| &libraryCreateInfos[pipelineCreateInfoIdx]); |
| |
| // mesh-only pipeline parts |
| pipelineCreateInfoIdx = PIPELINE_CREATEINFO_IDX_PRERAST_MESH; |
| updatePreRasterization(m_context, allPipelineCreateInfos[pipelineCreateInfoIdx], false, true, true); |
| appendStructurePtrToVulkanChain(&allPipelineCreateInfos[pipelineCreateInfoIdx].pNext, |
| &libraryCreateInfos[pipelineCreateInfoIdx]); |
| |
| // fragment-only pipeline parts, always linked |
| pipelineCreateInfoIdx = PIPELINE_CREATEINFO_IDX_POSTRAST; |
| updatePostRasterization(m_context, allPipelineCreateInfos[PIPELINE_CREATEINFO_IDX_POSTRAST], false, false); |
| appendStructurePtrToVulkanChain(&allPipelineCreateInfos[pipelineCreateInfoIdx].pNext, |
| &libraryCreateInfos[pipelineCreateInfoIdx]); |
| |
| pipelineCreateInfoIdx = PIPELINE_CREATEINFO_IDX_FO; |
| updateFragmentOutputInterface(m_context, allPipelineCreateInfos[pipelineCreateInfoIdx], ALL_COLOR_COMPONENTS); |
| appendStructurePtrToVulkanChain(&allPipelineCreateInfos[pipelineCreateInfoIdx].pNext, |
| &libraryCreateInfos[pipelineCreateInfoIdx]); |
| |
| // final pipeline libraries, pipelines[0]: vertex+frag and pipelines[1]: mesh+frag |
| std::vector<Move<VkPipeline>> pipelines; |
| pipelines.reserve(2u); |
| |
| enum |
| { |
| PIPELINE_LIB_VERT_FRAG = 0, |
| PIPELINE_LIB_MESH_FRAG, |
| PIPELINE_LIB_MAX |
| }; |
| |
| // create parts of each of the two final pipelines and then create the final pipelines |
| std::vector<VkPipeline> rawParts[PIPELINE_LIB_MAX]; |
| std::vector<Move<VkPipeline>> pipelineParts[PIPELINE_LIB_MAX]; |
| for (uint32_t combo = PIPELINE_LIB_VERT_FRAG; combo < PIPELINE_LIB_MAX; combo++) |
| { |
| uint32_t numParts = 0; |
| std::vector<uint32_t> createInfoIndices; |
| VkGraphicsPipelineCreateInfo finalPipelineInfo = initVulkanStructure(); |
| finalPipelineInfo.flags = 0u; |
| |
| if (combo == PIPELINE_LIB_VERT_FRAG) |
| { |
| // pipeline parts are 4 for vertex+frag pipeline |
| // vertex inout interface, pre-rasterization (vertex), post-rasterization, frag output interface |
| numParts = 4u; |
| finalPipelineInfo.layout = *nullLayout; |
| createInfoIndices.push_back(PIPELINE_CREATEINFO_IDX_VII); |
| createInfoIndices.push_back(PIPELINE_CREATEINFO_IDX_PRERAST_VERT); |
| createInfoIndices.push_back(PIPELINE_CREATEINFO_IDX_POSTRAST); |
| createInfoIndices.push_back(PIPELINE_CREATEINFO_IDX_FO); |
| } |
| else |
| { |
| // pipeline parts are 3 for mesh+frag pipeline |
| // pre-rasterization (mesh), post-rasterization, frag output interface |
| numParts = 3u; |
| finalPipelineInfo.layout = *allLayouts; |
| createInfoIndices.push_back(PIPELINE_CREATEINFO_IDX_PRERAST_MESH); |
| createInfoIndices.push_back(PIPELINE_CREATEINFO_IDX_POSTRAST); |
| createInfoIndices.push_back(PIPELINE_CREATEINFO_IDX_FO); |
| } |
| |
| // extend pNext chain and create all partial pipelines |
| rawParts[combo].resize(numParts, VK_NULL_HANDLE); |
| pipelineParts[combo].reserve(numParts); |
| |
| uint32_t partsIdx = 0; |
| for (const auto &idx : createInfoIndices) |
| { |
| pipelineParts[combo].emplace_back( |
| createGraphicsPipeline(vk, device, VK_NULL_HANDLE, &allPipelineCreateInfos[idx])); |
| rawParts[combo][partsIdx] = *(pipelineParts[combo][partsIdx]); |
| partsIdx++; |
| } |
| |
| // create final pipeline out of the parts |
| VkPipelineLibraryCreateInfoKHR linkingInfo = makePipelineLibraryCreateInfo(rawParts[combo]); |
| appendStructurePtrToVulkanChain(&finalPipelineInfo.pNext, &linkingInfo); |
| pipelines.emplace_back(createGraphicsPipeline(vk, device, VK_NULL_HANDLE, &finalPipelineInfo)); |
| } |
| |
| // execute both pipelines one after the other and verify the result of each |
| bool testOk = true; |
| const VkViewport viewport = makeViewport(m_renderArea.extent.width, m_renderArea.extent.height); |
| const VkRect2D scissor = makeRect2D(m_renderArea.extent.width, m_renderArea.extent.height); |
| |
| for (uint32_t combo = PIPELINE_LIB_VERT_FRAG; (combo < PIPELINE_LIB_MAX) && (testOk != false); combo++) |
| { |
| // only the render pass is shared between the two pipelines |
| const VkImageCreateInfo colorImageCreateInfo = |
| makeColorImageCreateInfo(m_colorFormat, m_renderArea.extent.width, m_renderArea.extent.height); |
| de::MovePtr<ImageWithMemory> localColorImage = de::MovePtr<ImageWithMemory>( |
| new ImageWithMemory(vk, device, allocator, colorImageCreateInfo, MemoryRequirement::Any)); |
| const VkImageViewCreateInfo colorImageViewCreateInfo = makeImageViewCreateInfo( |
| **localColorImage, m_colorFormat, static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_COLOR_BIT)); |
| const Move<VkImageView> colorImageView = createImageView(vk, device, &colorImageViewCreateInfo); |
| |
| const VkFramebufferCreateInfo framebufferCreateInfo = makeFramebufferCreateInfo( |
| *m_renderPass, 1u, &*colorImageView, m_renderArea.extent.width, m_renderArea.extent.height); |
| Move<VkFramebuffer> localFramebuffer = createFramebuffer(vk, device, &framebufferCreateInfo); |
| |
| Move<VkCommandBuffer> localCmdBuffer = |
| allocateCommandBuffer(vk, device, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY); |
| |
| vk::beginCommandBuffer(vk, *localCmdBuffer, 0u); |
| { |
| |
| const VkDeviceSize zeroOffset = 0ull; |
| beginRenderPass(vk, *localCmdBuffer, *m_renderPass, *localFramebuffer, m_renderArea, m_colorClearColor); |
| |
| vk.cmdBindPipeline(*localCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelines[combo]); |
| vk.cmdSetViewport(*localCmdBuffer, 0, 1, &viewport); |
| vk.cmdSetScissor(*localCmdBuffer, 0, 1, &scissor); |
| |
| if (combo == PIPELINE_LIB_VERT_FRAG) |
| { |
| vk.cmdBindVertexBuffers(*localCmdBuffer, 0u, 1u, &vertexBuffer->get(), &zeroOffset); |
| vk.cmdDraw(*localCmdBuffer, vertexCount, 1u, 0u, 0u); |
| } |
| else |
| { |
| vk.cmdBindDescriptorSets(*localCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *allLayouts, 0u, 1u, |
| allDescriptorSets, 0u, nullptr); |
| uint32_t num_workgroups = 1u; |
| vk.cmdDrawMeshTasksEXT(*localCmdBuffer, num_workgroups, 1u, 1u); |
| } |
| |
| endRenderPass(vk, *localCmdBuffer); |
| |
| const tcu::IVec2 size{(int32_t)m_renderArea.extent.width, (int32_t)m_renderArea.extent.height}; |
| copyImageToBuffer(vk, *localCmdBuffer, **localColorImage, *outputBuffer, size); |
| } |
| vk::endCommandBuffer(vk, *localCmdBuffer); |
| vk::submitCommandsAndWait(vk, device, m_context.getUniversalQueue(), *localCmdBuffer); |
| |
| { |
| vk::invalidateAlloc(vk, device, outputBuffer.getAllocation()); |
| |
| const tcu::TextureFormat tcuFormat = vk::mapVkFormat(m_colorFormat); |
| const tcu::ConstPixelBufferAccess resultAccess(tcuFormat, m_renderArea.extent.width, |
| m_renderArea.extent.height, 1, |
| outputBuffer.getAllocation().getHostPtr()); |
| testOk = verifyOnePipelineLibraryResult(resultAccess, numBars); |
| } |
| } |
| |
| return (testOk == true ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Rendered image(s) are incorrect")); |
| } |
| |
| tcu::TestStatus PipelineLibraryMiscTestInstance::verifyResult(const std::vector<VerificationData> &verificationData, |
| const tcu::ConstPixelBufferAccess &colorPixelAccess) const |
| { |
| const int32_t epsilon = 1; |
| for (const auto &v : verificationData) |
| { |
| const IVec4 pixel = colorPixelAccess.getPixelInt(v.point.x(), v.point.y()); |
| const IVec4 diff = pixel - v.color; |
| for (uint32_t compNdx = 0; compNdx < 4u; ++compNdx) |
| { |
| if (de::abs(diff[compNdx]) > epsilon) |
| { |
| const Vec4 pixelBias(0.0f); |
| const Vec4 pixelScale(1.0f); |
| |
| m_context.getTestContext().getLog() |
| << TestLog::Image("Result", "Result", colorPixelAccess, pixelScale, pixelBias) |
| << tcu::TestLog::Message << "For texel " << v.point << " expected color " << v.color |
| << " got: " << pixel << tcu::TestLog::EndMessage; |
| |
| return tcu::TestStatus::fail("Fail"); |
| } |
| } |
| } |
| |
| return tcu::TestStatus::pass("Pass"); |
| } |
| |
| bool PipelineLibraryMiscTestInstance::verifyOnePipelineLibraryResult(const tcu::ConstPixelBufferAccess &resultAccess, |
| const int numBars) const |
| { |
| bool testOk = true; |
| tcu::TestLog &log = m_context.getTestContext().getLog(); |
| |
| const tcu::TextureFormat tcuFormat = vk::mapVkFormat(m_colorFormat); |
| tcu::TextureLevel referenceLevel(tcuFormat, m_renderArea.extent.width, m_renderArea.extent.height); |
| auto referenceAccess = referenceLevel.getAccess(); |
| const tcu::Vec4 bgColor = Vec4(1.0f, 0.0f, 0.0f, 1.0f); // red |
| const tcu::Vec4 clipAreaColor = Vec4(0.0f, 0.0f, 0.0f, 1.0f); // black |
| const IVec2 clipRegion = |
| IVec2(numClipDistances * m_renderArea.extent.width / numBars, m_renderArea.extent.height / 2); |
| tcu::clear(referenceAccess, bgColor); |
| makeReferenceImage(referenceAccess, clipRegion, numBars, numClipDistances / 2, clipAreaColor); |
| |
| const float colorThres = 0.005f; // 1/255 < 0.005 < 2/255 |
| const tcu::Vec4 threshold(0.0f, colorThres, colorThres, 0.0f); |
| |
| if (!tcu::floatThresholdCompare(log, "Result", "Reference", referenceAccess, resultAccess, threshold, |
| tcu::COMPARE_LOG_ON_ERROR)) |
| testOk = false; |
| |
| return testOk; |
| } |
| |
| class PipelineLibraryShaderModuleInfoInstance : public TestInstance |
| { |
| public: |
| PipelineLibraryShaderModuleInfoInstance(Context &context) |
| : TestInstance(context) |
| , m_vkd(m_context.getDeviceInterface()) |
| , m_device(m_context.getDevice()) |
| , m_alloc(m_context.getDefaultAllocator()) |
| , m_queueIndex(m_context.getUniversalQueueFamilyIndex()) |
| , m_queue(m_context.getUniversalQueue()) |
| , m_outVector(kOutputBufferElements, std::numeric_limits<uint32_t>::max()) |
| , m_cmdBuffer(DE_NULL) |
| { |
| } |
| virtual ~PipelineLibraryShaderModuleInfoInstance(void) |
| { |
| } |
| |
| static constexpr size_t kOutputBufferElements = 64u; |
| |
| protected: |
| void prepareOutputBuffer(VkShaderStageFlags stages); |
| void allocateCmdBuffers(void); |
| void addModule(const std::string &moduleName, VkShaderStageFlagBits stage); |
|