From: Rocky Shi Date: Thu, 10 Mar 2016 21:20:06 +0000 (-0800) Subject: Add pipeline cache tests X-Git-Tag: upstream/0.1.0~438^2~333^2~2^2~2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=483b4c524ea87effe6a5dedebd22d30327a0460d;p=platform%2Fupstream%2FVK-GL-CTS.git Add pipeline cache tests --- diff --git a/external/vulkancts/modules/vulkan/pipeline/CMakeLists.txt b/external/vulkancts/modules/vulkan/pipeline/CMakeLists.txt index e1dd8e7..328210f 100644 --- a/external/vulkancts/modules/vulkan/pipeline/CMakeLists.txt +++ b/external/vulkancts/modules/vulkan/pipeline/CMakeLists.txt @@ -42,6 +42,8 @@ set(DEQP_VK_PIPELINE_SRCS vktPipelineVertexUtil.hpp vktPipelineEarlyFragmentTests.cpp vktPipelineEarlyFragmentTests.hpp + vktPipelineCacheTests.cpp + vktPipelineCacheTests.hpp ) set(DEQP_VK_PIPELINE_LIBS diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineCacheTests.cpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineCacheTests.cpp new file mode 100644 index 0000000..2faf5b3 --- /dev/null +++ b/external/vulkancts/modules/vulkan/pipeline/vktPipelineCacheTests.cpp @@ -0,0 +1,1626 @@ +/*------------------------------------------------------------------------ + * Vulkan Conformance Tests + * ------------------------ + * + * Copyright (c) 2015 The Khronos Group Inc. + * Copyright (c) 2015 ARM Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and/or associated documentation files (the + * "Materials"), to deal in the Materials without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Materials, and to + * permit persons to whom the Materials are furnished to do so, subject to + * the following conditions: + * + * The above copyright notice(s) and this permission notice shall be included + * in all copies or substantial portions of the Materials. + * + * The Materials are Confidential Information as defined by the + * Khronos Membership Agreement until designated non-confidential by Khronos, + * at which point this condition clause shall be removed. + * + * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + * + *//*! + * \file + * \brief Pipeline Cache Tests + *//*--------------------------------------------------------------------*/ + +#include "vktPipelineCacheTests.hpp" +#include "vktPipelineClearUtil.hpp" +#include "vktPipelineImageUtil.hpp" +#include "vktPipelineVertexUtil.hpp" +#include "vktTestCase.hpp" +#include "vktTestCaseUtil.hpp" +#include "vkImageUtil.hpp" +#include "vkMemUtil.hpp" +#include "vkPrograms.hpp" +#include "vkBuilderUtil.hpp" +#include "vkQueryUtil.hpp" +#include "vkRef.hpp" +#include "vkRefUtil.hpp" +#include "tcuImageCompare.hpp" +#include "deUniquePtr.hpp" +#include "deMemory.h" +#include "vkTypeUtil.hpp" + +#include +#include + +namespace vkt +{ +namespace pipeline +{ + +using namespace vk; + +namespace +{ +enum +{ + VK_MAX_SHADER_STAGES = 6, +}; + +// helper functions + +std::string getShaderFlagStr (const VkShaderStageFlagBits shader, + bool isDescription) +{ + std::ostringstream desc; + switch(shader) + { + case VK_SHADER_STAGE_VERTEX_BIT: + { + desc << ((isDescription) ? "vertex stage" : "vertex_stage"); + break; + } + case VK_SHADER_STAGE_FRAGMENT_BIT: + { + desc << ((isDescription) ? "fragment stage" : "fragment_stage"); + break; + } + case VK_SHADER_STAGE_GEOMETRY_BIT: + { + desc << ((isDescription) ? "geometry stage" : "geometry_stage"); + break; + } + case VK_SHADER_STAGE_COMPUTE_BIT: + { + desc << ((isDescription) ? "compute stage" : "compute_stage"); + break; + } + case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: + { + desc << ((isDescription) ? "tessellation control stage" : "tessellation_control_stage"); + break; + } + case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: + { + desc << ((isDescription) ? "tessellation evaluation stage" : "tessellation_evaluation_stage"); + break; + } + default: + desc << "unknown shader stage!"; + DE_ASSERT(!"Unknown shader Stage!"); + break; + }; + + return desc.str(); +} + +// helper classes +class CacheTestParam +{ +public: + CacheTestParam (const VkShaderStageFlagBits* shaders, + deUint32 count); + virtual ~CacheTestParam (void); + virtual const std::string generateTestName (void) const; + virtual const std::string generateTestDescription (void) const; + VkShaderStageFlagBits getShaderFlag (deUint32 ndx) const { return m_shaders[ndx]; } + deUint32 getShaderCount (void) const { return (deUint32)m_shaderCount; } +protected: + VkShaderStageFlagBits m_shaders[VK_MAX_SHADER_STAGES]; + size_t m_shaderCount; +}; + +CacheTestParam::CacheTestParam (const VkShaderStageFlagBits* shaders, deUint32 count) +{ + DE_ASSERT(count <= VK_MAX_SHADER_STAGES); + for (deUint32 ndx = 0; ndx < count; ndx++) + m_shaders[ndx] = shaders[ndx]; + m_shaderCount = count; +} + +CacheTestParam::~CacheTestParam (void) +{ +} + +const std::string CacheTestParam::generateTestName (void) const +{ + std::string result(getShaderFlagStr(m_shaders[0], false)); + + for(deUint32 ndx = 1; ndx < m_shaderCount; ndx++) + result += '_' + getShaderFlagStr(m_shaders[ndx], false) ; + + return result; +} + +const std::string CacheTestParam::generateTestDescription (void) const +{ + std::string result("Create pipeline cache with " + getShaderFlagStr(m_shaders[0], true)); + + for(deUint32 ndx = 1; ndx < m_shaderCount; ndx++) + result += ' ' + getShaderFlagStr(m_shaders[ndx], true); + + return result; +} + +class SimpleGraphicsPipelineBuilder +{ +public: + SimpleGraphicsPipelineBuilder (Context& context); + ~SimpleGraphicsPipelineBuilder (void) { } + void bindShaderStage (VkShaderStageFlagBits stage, + const char* sourceName, + const char* entryName); + void enableTessellationStage (deUint32 patchControlPoints); + Move buildPipeline (tcu::UVec2 renderSize, + VkRenderPass renderPass, + VkPipelineCache cache); +protected: + Context& m_context; + + Move m_shaderModules[VK_MAX_SHADER_STAGES]; + deUint32 m_shaderStageCount; + VkPipelineShaderStageCreateInfo m_shaderStageInfo[VK_MAX_SHADER_STAGES]; + + deUint32 m_patchControlPoints; + + Move m_pipelineLayout; + Move m_graphicsPipelines; + +}; + +SimpleGraphicsPipelineBuilder::SimpleGraphicsPipelineBuilder (Context& context) + : m_context(context) +{ + m_patchControlPoints = 0; + m_shaderStageCount = 0; +} + +void SimpleGraphicsPipelineBuilder::bindShaderStage (VkShaderStageFlagBits stage, + const char* sourceName, + const char* entryName) +{ + const DeviceInterface& vk = m_context.getDeviceInterface(); + const VkDevice vkDevice = m_context.getDevice(); + + // Create shader module + deUint32* code = (deUint32*)m_context.getBinaryCollection().get(sourceName).getBinary(); + deUint32 codeSize = (deUint32)m_context.getBinaryCollection().get(sourceName).getSize(); + + const VkShaderModuleCreateInfo moduleCreateInfo = + { + VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkShaderModuleCreateFlags flags; + codeSize, // deUintptr codeSize; + code, // const deUint32* pCode; + }; + + m_shaderModules[m_shaderStageCount] = createShaderModule(vk, vkDevice, &moduleCreateInfo); + + // Prepare shader stage info + m_shaderStageInfo[m_shaderStageCount].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + m_shaderStageInfo[m_shaderStageCount].pNext = DE_NULL; + m_shaderStageInfo[m_shaderStageCount].flags = 0u; + m_shaderStageInfo[m_shaderStageCount].stage = stage; + m_shaderStageInfo[m_shaderStageCount].module = *m_shaderModules[m_shaderStageCount]; + m_shaderStageInfo[m_shaderStageCount].pName = entryName; + m_shaderStageInfo[m_shaderStageCount].pSpecializationInfo = DE_NULL; + + m_shaderStageCount++; +} + +Move SimpleGraphicsPipelineBuilder::buildPipeline (tcu::UVec2 renderSize, VkRenderPass renderPass, VkPipelineCache cache) +{ + const DeviceInterface& vk = m_context.getDeviceInterface(); + const VkDevice vkDevice = m_context.getDevice(); + + // Create pipeline layout + { + const VkPipelineLayoutCreateInfo pipelineLayoutParams = + { + VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkPipelineLayoutCreateFlags flags; + 0u, // deUint32 setLayoutCount; + DE_NULL, // const VkDescriptorSetLayout* pSetLayouts; + 0u, // deUint32 pushConstantRangeCount; + DE_NULL // const VkPushConstantRange* pPushConstantRanges; + }; + + m_pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams); + } + + // Create pipeline + const VkVertexInputBindingDescription vertexInputBindingDescription = + { + 0u, // deUint32 binding; + sizeof(Vertex4RGBA), // deUint32 strideInBytes; + VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate; + }; + + const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] = + { + { + 0u, // deUint32 location; + 0u, // deUint32 binding; + VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format; + 0u // deUint32 offsetInBytes; + }, + { + 1u, // deUint32 location; + 0u, // deUint32 binding; + VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format; + DE_OFFSET_OF(Vertex4RGBA, color), // deUint32 offsetInBytes; + } + }; + + const VkPipelineVertexInputStateCreateInfo vertexInputStateParams = + { + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkPipelineVertexInputStateCreateFlags flags; + 1u, // deUint32 vertexBindingDescriptionCount; + &vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions; + 2u, // deUint32 vertexAttributeDescriptionCount; + vertexInputAttributeDescriptions, // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions; + }; + + const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateParams = + { + VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkPipelineInputAssemblyStateCreateFlags flags; + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // VkPrimitiveTopology topology; + VK_FALSE, // VkBool32 primitiveRestartEnable; + }; + + const VkViewport viewport = + { + 0.0f, // float originX; + 0.0f, // float originY; + (float)renderSize.x(), // float width; + (float)renderSize.y(), // float height; + 0.0f, // float minDepth; + 1.0f // float maxDepth; + }; + const VkRect2D scissor = + { + { 0, 0 }, // VkOffset2D offset; + { renderSize.x(), renderSize.y() } // VkExtent2D extent; + }; + const VkPipelineViewportStateCreateInfo viewportStateParams = + { + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkPipelineViewportStateCreateFlags flags; + 1u, // deUint32 viewportCount; + &viewport, // const VkViewport* pViewports; + 1u, // deUint32 scissorCount; + &scissor // const VkRect2D* pScissors; + }; + + const VkPipelineRasterizationStateCreateInfo rasterStateParams = + { + 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; + VK_POLYGON_MODE_FILL, // 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; + }; + + const VkPipelineColorBlendAttachmentState colorBlendAttachmentState = + { + 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; + VK_COLOR_COMPONENT_R_BIT | + VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | + VK_COLOR_COMPONENT_A_BIT // VkColorComponentFlags colorWriteMask; + }; + + const VkPipelineColorBlendStateCreateInfo colorBlendStateParams = + { + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkPipelineColorBlendStateCreateFlags flags; + VK_FALSE, // VkBool32 logicOpEnable; + VK_LOGIC_OP_COPY, // VkLogicOp logicOp; + 1u, // deUint32 attachmentCount; + &colorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments; + { 0.0f, 0.0f, 0.0f, 0.0f }, // float blendConst[4]; + }; + + const VkPipelineMultisampleStateCreateInfo multisampleStateParams = + { + 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; + VK_FALSE, // VkBool32 sampleShadingEnable; + 0.0f, // float minSampleShading; + DE_NULL, // const VkSampleMask* pSampleMask; + VK_FALSE, // VkBool32 alphaToCoverageEnable; + VK_FALSE, // VkBool32 alphaToOneEnable; + }; + + const VkPipelineDynamicStateCreateInfo dynamicStateParams = + { + VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkPipelineDynamicStateCreateFlags flags; + 0u, // deUint32 dynamicStateCount; + DE_NULL, // const VkDynamicState* pDynamicStates; + }; + + VkPipelineDepthStencilStateCreateInfo depthStencilStateParams = + { + VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkPipelineDepthStencilStateCreateFlags flags; + VK_TRUE, // VkBool32 depthTestEnable; + VK_TRUE, // 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, // deUint32 compareMask; + 0u, // deUint32 writeMask; + 0u, // deUint32 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, // deUint32 compareMask; + 0u, // deUint32 writeMask; + 0u, // deUint32 reference; + }, + -1.0f, // float minDepthBounds; + +1.0f, // float maxDepthBounds; + }; + + const VkPipelineTessellationStateCreateInfo* pTessCreateInfo = DE_NULL; + if (m_patchControlPoints > 0) + { + const VkPipelineTessellationStateCreateInfo tessStateCreateInfo = + { + VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkPipelineTesselationStateCreateFlags flags; + m_patchControlPoints, // deUint32 patchControlPoints; + }; + + pTessCreateInfo = &tessStateCreateInfo; + } + + const VkGraphicsPipelineCreateInfo graphicsPipelineParams = + { + VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkPipelineCreateFlags flags; + m_shaderStageCount, // deUint32 stageCount; + m_shaderStageInfo, // const VkPipelineShaderStageCreateInfo* pStages; + &vertexInputStateParams, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState; + &inputAssemblyStateParams, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState; + pTessCreateInfo, // const VkPipelineTessellationStateCreateInfo* pTessellationState; + &viewportStateParams, // const VkPipelineViewportStateCreateInfo* pViewportState; + &rasterStateParams, // const VkPipelineRasterizationStateCreateInfo* pRasterState; + &multisampleStateParams, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState; + &depthStencilStateParams, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState; + &colorBlendStateParams, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState; + &dynamicStateParams, // const VkPipelineDynamicStateCreateInfo* pDynamicState; + *m_pipelineLayout, // VkPipelineLayout layout; + renderPass, // VkRenderPass renderPass; + 0u, // deUint32 subpass; + 0u, // VkPipeline basePipelineHandle; + 0, // deInt32 basePipelineIndex; + }; + + return createGraphicsPipeline(vk, vkDevice, cache, &graphicsPipelineParams); +} + +void SimpleGraphicsPipelineBuilder::enableTessellationStage (deUint32 patchControlPoints) +{ + m_patchControlPoints = patchControlPoints; +} + +template +vkt::TestCase* newTestCase (tcu::TestContext& testContext, + const CacheTestParam* testParam) +{ + return new Test(testContext, + testParam->generateTestName().c_str(), + testParam->generateTestDescription().c_str(), + testParam); +} + +Move createBufferAndBindMemory (Context& context, VkDeviceSize size, VkBufferUsageFlags usage, de::MovePtr* pAlloc) +{ + const DeviceInterface& vk = context.getDeviceInterface(); + const VkDevice vkDevice = context.getDevice(); + const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex(); + SimpleAllocator* memAlloc = new SimpleAllocator(vk, vkDevice, getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice())); + + const VkBufferCreateInfo vertexBufferParams = + { + VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkBufferCreateFlags flags; + size, // VkDeviceSize size; + usage, // VkBufferUsageFlags usage; + VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; + 1u, // deUint32 queueFamilyCount; + &queueFamilyIndex // const deUint32* pQueueFamilyIndices; + }; + + Move vertexBuffer = createBuffer(vk, vkDevice, &vertexBufferParams); + + DE_ASSERT(pAlloc); + *pAlloc = memAlloc->allocate(getBufferMemoryRequirements(vk, vkDevice, *vertexBuffer), MemoryRequirement::HostVisible); + VK_CHECK(vk.bindBufferMemory(vkDevice, *vertexBuffer, (*pAlloc)->getMemory(), (*pAlloc)->getOffset())); + + return vertexBuffer; +} + +Move createImage2DAndBindMemory (Context& context, + VkFormat format, + deUint32 width, + deUint32 height, + VkImageUsageFlags usage, + VkSampleCountFlagBits sampleCount, + de::details::MovePtr* pAlloc) +{ + const DeviceInterface& vk = context.getDeviceInterface(); + const VkDevice vkDevice = context.getDevice(); + const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex(); + SimpleAllocator* memAlloc = new SimpleAllocator(vk, vkDevice, getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice())); + + const VkImageCreateInfo colorImageParams = + { + VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkImageCreateFlags flags; + VK_IMAGE_TYPE_2D, // VkImageType imageType; + format, // VkFormat format; + { width, height, 1u }, // VkExtent3D extent; + 1u, // deUint32 mipLevels; + 1u, // deUint32 arraySize; + sampleCount, // deUint32 samples; + VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; + usage, // VkImageUsageFlags usage; + VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; + 1u, // deUint32 queueFamilyCount; + &queueFamilyIndex, // const deUint32* pQueueFamilyIndices; + VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; + }; + + Move image = createImage(vk, vkDevice, &colorImageParams); + + DE_ASSERT(pAlloc); + *pAlloc = memAlloc->allocate(getImageMemoryRequirements(vk, vkDevice, *image), MemoryRequirement::Any); + VK_CHECK(vk.bindImageMemory(vkDevice, *image, (*pAlloc)->getMemory(), (*pAlloc)->getOffset())); + + return image; +} + +// Test Classes +class CacheTest : public vkt::TestCase +{ +public: + CacheTest(tcu::TestContext& testContext, + const std::string& name, + const std::string& description, + const CacheTestParam* param) + : vkt::TestCase (testContext, name, description) + , m_param (*param) + { } + virtual ~CacheTest (void) { } +protected: + const CacheTestParam m_param; +}; + +class CacheTestInstance : public vkt::TestInstance +{ +public: + enum + { + PIPELINE_CACHE_NDX_NO_CACHE, + PIPELINE_CACHE_NDX_CACHED, + PIPELINE_CACHE_NDX_COUNT, + }; + CacheTestInstance (Context& context, + const CacheTestParam* param); + virtual ~CacheTestInstance (void); + virtual tcu::TestStatus iterate (void); +protected: + virtual tcu::TestStatus verifyTestResult (void) = 0; + virtual void prepareCommandBuffer (void) = 0; +protected: + const CacheTestParam* m_param; + + Move m_cmdPool; + Move m_cmdBuffer; + Move m_fence; + Move m_cache; +}; + +CacheTestInstance::CacheTestInstance (Context& context, + const CacheTestParam* param) + : TestInstance (context) + , m_param (param) +{ + const DeviceInterface& vk = m_context.getDeviceInterface(); + const VkDevice vkDevice = m_context.getDevice(); + const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex(); + + // Create command pool + { + const VkCommandPoolCreateInfo cmdPoolParams = + { + VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, // VkCmdPoolCreateFlags flags; + queueFamilyIndex, // deUint32 queueFamilyIndex; + }; + + m_cmdPool = createCommandPool(vk, vkDevice, &cmdPoolParams); + } + + // Create command buffer + { + const VkCommandBufferAllocateInfo cmdAllocateParams = + { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + *m_cmdPool, // VkCommandPool cmdPool; + VK_COMMAND_BUFFER_LEVEL_PRIMARY, // VkCommandBufferLevel level; + 1u, // deUint32 bufferCount; + }; + + m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, &cmdAllocateParams); + } + + // Create fence + { + const VkFenceCreateInfo fenceParams = + { + VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkFenceCreateFlags flags; + }; + + m_fence = createFence(vk, vkDevice, &fenceParams); + } + + // Create the Pipeline Cache + { + const VkPipelineCacheCreateInfo pipelineCacheCreateInfo = + { + VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkPipelineCacheCreateFlags flags; + 0u, // deUintptr initialDataSize; + DE_NULL, // const void* pInitialData; + }; + + m_cache = createPipelineCache(vk, vkDevice, &pipelineCacheCreateInfo); + } +} + +CacheTestInstance::~CacheTestInstance (void) +{ +} + +tcu::TestStatus CacheTestInstance::iterate (void) +{ + const DeviceInterface& vk = m_context.getDeviceInterface(); + const VkDevice vkDevice = m_context.getDevice(); + const VkQueue queue = m_context.getUniversalQueue(); + + prepareCommandBuffer(); + + VK_CHECK(vk.resetFences(vkDevice, 1u, &m_fence.get())); + + const VkSubmitInfo submitInfo = + { + VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // deUint32 waitSemaphoreCount; + DE_NULL, // const VkSemaphore* pWaitSemaphores; + (const VkPipelineStageFlags*)DE_NULL, // const VkPipelineStageFlags* pWaitDstStageMask; + 1u, // deUint32 commandBufferCount; + &m_cmdBuffer.get(), // const VkCommandBuffer* pCommandBuffers; + 0u, // deUint32 signalSemaphoreCount; + DE_NULL, // const VkSemaphore* pSignalSemaphores; + }; + VK_CHECK(vk.queueSubmit(queue, 1u, &submitInfo, *m_fence)); + + VK_CHECK(vk.waitForFences(vkDevice, 1u, &m_fence.get(), true, ~(0ull) /* infinity*/)); + + return verifyTestResult(); +} + +class GraphicsCacheTest : public CacheTest +{ +public: + GraphicsCacheTest (tcu::TestContext& testContext, + const std::string& name, + const std::string& description, + const CacheTestParam* param) + : CacheTest (testContext, name, description, param) + { } + virtual ~GraphicsCacheTest (void) { } + virtual void initPrograms (SourceCollections& programCollection) const; + virtual TestInstance* createInstance (Context& context) const; +}; + +class GraphicsCacheTestInstance : public CacheTestInstance +{ +public: + GraphicsCacheTestInstance (Context& context, + const CacheTestParam* param); + virtual ~GraphicsCacheTestInstance (void); +protected: + void prepareRenderPass (VkFramebuffer framebuffer, VkPipeline pipeline); + virtual void prepareCommandBuffer (void); + virtual tcu::TestStatus verifyTestResult (void); + +protected: + const tcu::UVec2 m_renderSize; + const VkFormat m_colorFormat; + const VkFormat m_depthFormat; + + Move m_depthImage; + de::MovePtr m_depthImageAlloc; + de::MovePtr m_colorImageAlloc; + Move m_depthAttachmentView; + + Move m_vertexBuffer; + std::vector m_vertices; + + SimpleGraphicsPipelineBuilder m_pipelineBuilder; + Move m_renderPass; + + Move m_colorImage[PIPELINE_CACHE_NDX_COUNT]; + Move m_colorAttachmentView[PIPELINE_CACHE_NDX_COUNT]; + Move m_framebuffer[PIPELINE_CACHE_NDX_COUNT]; + Move m_pipeline[PIPELINE_CACHE_NDX_COUNT]; +}; + +void GraphicsCacheTest::initPrograms (SourceCollections& programCollection) const +{ + for (deUint32 shaderNdx = 0; shaderNdx < m_param.getShaderCount(); shaderNdx++) + { + switch(m_param.getShaderFlag(shaderNdx)) + { + case VK_SHADER_STAGE_VERTEX_BIT: + programCollection.glslSources.add("color_vert") << glu::VertexSource( + "#version 310 es\n" + "layout(location = 0) in vec4 position;\n" + "layout(location = 1) in vec4 color;\n" + "layout(location = 0) out highp vec4 vtxColor;\n" + "void main (void)\n" + "{\n" + " gl_Position = position;\n" + " vtxColor = color;\n" + "}\n"); + break; + + case VK_SHADER_STAGE_FRAGMENT_BIT: + programCollection.glslSources.add("color_frag") << glu::FragmentSource( + "#version 310 es\n" + "layout(location = 0) in highp vec4 vtxColor;\n" + "layout(location = 0) out highp vec4 fragColor;\n" + "void main (void)\n" + "{\n" + " fragColor = vtxColor;\n" + "}\n"); + break; + + case VK_SHADER_STAGE_GEOMETRY_BIT: + programCollection.glslSources.add("dummy_geo") << glu::GeometrySource( + "#version 450 \n" + "layout (triangles) in;\n" + "layout (triangle_strip, max_vertices = 3) out;\n" + "void main (void)\n" + "{\n" + " for(int ndx=0; ndx<3; ndx++)\n" + " {\n" + " gl_Position = gl_in[ndx].gl_Position;\n" + " EmitVertex();\n" + " }\n" + " EndPrimitive();\n" + "}\n"); + break; + + case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: + programCollection.glslSources.add("basic_tcs") << glu::TessellationControlSource( + "#version 450 \n" + "layout(vertices = 3) out;\n" + "in highp vec4 color[];\n" + "out highp vec4 vtxColor[];\n" + "void main()\n" + "{\n" + " gl_TessLevelOuter[0] = 4.0;\n" + " gl_TessLevelOuter[1] = 4.0;\n" + " gl_TessLevelOuter[2] = 4.0;\n" + " gl_TessLevelInner[0] = 4.0;\n" + " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n" + " vtxColor[gl_InvocationID] = color[gl_InvocationID];\n" + "}\n"); + break; + + case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: + programCollection.glslSources.add("basic_tes") << glu::TessellationEvaluationSource( + "#version 450 \n" + "layout(triangles, fractional_even_spacing, ccw) in;\n" + "in highp vec4 colors[];\n" + "out highp vec4 vtxColor;\n" + "void main() \n" + "{\n" + " float u = gl_TessCoord.x;\n" + " float v = gl_TessCoord.y;\n" + " float w = gl_TessCoord.z;\n" + " vec4 pos = vec4(0);\n" + " vec4 color = vec4(0);\n" + " pos.xyz += u * gl_in[0].gl_Position.xyz;\n" + " color.xyz += u * colors[0].xyz;\n" + " pos.xyz += v * gl_in[1].gl_Position.xyz;\n" + " color.xyz += v * colors[1].xyz;\n" + " pos.xyz += w * gl_in[2].gl_Position.xyz;\n" + " color.xyz += w * colors[2].xyz;\n" + " pos.w = 1.0;\n" + " color.w = 1.0;\n" + " gl_Position = pos;\n" + " vtxColor = color;\n" + "}\n"); + break; + + default: + DE_ASSERT(!"Unknown Shader Stage!"); + break; + }; + } +} + +TestInstance* GraphicsCacheTest::createInstance (Context& context) const +{ + return new GraphicsCacheTestInstance(context, &m_param); +} + +GraphicsCacheTestInstance::GraphicsCacheTestInstance (Context& context, + const CacheTestParam* param) + : CacheTestInstance (context,param) + , m_renderSize (32u, 32u) + , m_colorFormat (VK_FORMAT_R8G8B8A8_UNORM) + , m_depthFormat (VK_FORMAT_D24_UNORM_S8_UINT) + , m_pipelineBuilder (context) +{ + const DeviceInterface& vk = m_context.getDeviceInterface(); + const VkDevice vkDevice = m_context.getDevice(); + + // Create vertex buffer + { + de::MovePtr bufferAlloc; + m_vertexBuffer = createBufferAndBindMemory(m_context, 1024u, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, &bufferAlloc); + + m_vertices = createOverlappingQuads(); + // Load vertices into vertex buffer + deMemcpy(bufferAlloc->getHostPtr(), m_vertices.data(), m_vertices.size() * sizeof(Vertex4RGBA)); + flushMappedMemoryRange(vk, vkDevice, bufferAlloc->getMemory(), bufferAlloc->getOffset(), 1024u); + } + + // Create render pass + { + const VkAttachmentDescription colorAttachmentDescription = + { + 0u, // VkAttachmentDescriptionFlags flags; + m_colorFormat, // VkFormat format; + VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; + VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp; + VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp; + VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp; + VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp; + VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout; + }; + + const VkAttachmentDescription depthAttachmentDescription = + { + 0u, // VkAttachmentDescriptionFlags flags; + m_depthFormat, // VkFormat format; + VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; + VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp; + VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp storeOp; + VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp; + VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp; + VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout; + }; + + const VkAttachmentDescription attachments[2] = + { + colorAttachmentDescription, + depthAttachmentDescription + }; + + const VkAttachmentReference colorAttachmentReference = + { + 0u, // deUint32 attachment; + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout; + }; + + const VkAttachmentReference depthAttachmentReference = + { + 1u, // deUint32 attachment; + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL // VkImageLayout layout; + }; + + const VkSubpassDescription subpassDescription = + { + 0u, // VkSubpassDescriptionFlags flags; + VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint; + 0u, // deUint32 inputAttachmentCount; + DE_NULL, // const VkAttachmentReference* pInputAttachments; + 1u, // deUint32 colorAttachmentCount; + &colorAttachmentReference, // const VkAttachmentReference* pColorAttachments; + DE_NULL, // const VkAttachmentReference* pResolveAttachments; + &depthAttachmentReference, // const VkAttachmentReference* pDepthStencilAttachment; + 0u, // deUint32 preserveAttachmentCount; + DE_NULL // const VkAttachmentReference* pPreserveAttachments; + }; + + const VkRenderPassCreateInfo renderPassParams = + { + VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkRenderPassCreateFlags flags; + 2u, // deUint32 attachmentCount; + attachments, // const VkAttachmentDescription* pAttachments; + 1u, // deUint32 subpassCount; + &subpassDescription, // const VkSubpassDescription* pSubpasses; + 0u, // deUint32 dependencyCount; + DE_NULL // const VkSubpassDependency* pDependencies; + }; + + m_renderPass = createRenderPass(vk, vkDevice, &renderPassParams); + } + + const VkComponentMapping ComponentMappingRGBA = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A}; + // Create color image + { + m_colorImage[PIPELINE_CACHE_NDX_NO_CACHE] = createImage2DAndBindMemory(m_context, + m_colorFormat, + m_renderSize.x(), + m_renderSize.y(), + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, + VK_SAMPLE_COUNT_1_BIT, + &m_colorImageAlloc); + m_colorImage[PIPELINE_CACHE_NDX_CACHED] = createImage2DAndBindMemory(m_context, + m_colorFormat, + m_renderSize.x(), + m_renderSize.y(), + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, + VK_SAMPLE_COUNT_1_BIT, + &m_colorImageAlloc); + } + + // Create depth image + { + m_depthImage = createImage2DAndBindMemory(m_context, + m_depthFormat, + m_renderSize.x(), + m_renderSize.y(), + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, + VK_SAMPLE_COUNT_1_BIT, + &m_depthImageAlloc); + } + + // Create color attachment view + { + VkImageViewCreateInfo colorAttachmentViewParams = + { + VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkImageViewCreateFlags flags; + *m_colorImage[PIPELINE_CACHE_NDX_NO_CACHE], // VkImage image; + VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType; + m_colorFormat, // VkFormat format; + ComponentMappingRGBA, // VkComponentMapping components; + { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }, // VkImageSubresourceRange subresourceRange; + }; + + m_colorAttachmentView[PIPELINE_CACHE_NDX_NO_CACHE] = createImageView(vk, vkDevice, &colorAttachmentViewParams); + + colorAttachmentViewParams.image = *m_colorImage[PIPELINE_CACHE_NDX_CACHED]; + m_colorAttachmentView[PIPELINE_CACHE_NDX_CACHED] = createImageView(vk, vkDevice, &colorAttachmentViewParams); + } + + // Create depth attachment view + { + const VkImageViewCreateInfo depthAttachmentViewParams = + { + VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkImageViewCreateFlags flags; + *m_depthImage, // VkImage image; + VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType; + m_depthFormat, // VkFormat format; + ComponentMappingRGBA, // VkComponentMapping components; + { VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 1u, 0u, 1u }, // VkImageSubresourceRange subresourceRange; + }; + + m_depthAttachmentView = createImageView(vk, vkDevice, &depthAttachmentViewParams); + } + + // Create framebuffer + { + VkImageView attachmentBindInfos[2] = + { + *m_colorAttachmentView[PIPELINE_CACHE_NDX_NO_CACHE], + *m_depthAttachmentView, + }; + + const VkFramebufferCreateInfo framebufferParams = + { + VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkFramebufferCreateFlags flags; + *m_renderPass, // VkRenderPass renderPass; + 2u, // deUint32 attachmentCount; + attachmentBindInfos, // const VkImageView* pAttachments; + (deUint32)m_renderSize.x(), // deUint32 width; + (deUint32)m_renderSize.y(), // deUint32 height; + 1u, // deUint32 layers; + }; + + m_framebuffer[PIPELINE_CACHE_NDX_NO_CACHE] = createFramebuffer(vk, vkDevice, &framebufferParams); + + attachmentBindInfos[0] = *m_colorAttachmentView[PIPELINE_CACHE_NDX_CACHED]; + m_framebuffer[PIPELINE_CACHE_NDX_CACHED] = createFramebuffer(vk, vkDevice, &framebufferParams); + } + + // Bind shader stages + VkPhysicalDeviceFeatures features = m_context.getDeviceFeatures(); + for (deUint32 shaderNdx = 0; shaderNdx < m_param->getShaderCount(); shaderNdx++) + { + switch(m_param->getShaderFlag(shaderNdx)) + { + case VK_SHADER_STAGE_VERTEX_BIT: + m_pipelineBuilder.bindShaderStage(VK_SHADER_STAGE_VERTEX_BIT, "color_vert", "main"); + break; + case VK_SHADER_STAGE_FRAGMENT_BIT: + m_pipelineBuilder.bindShaderStage(VK_SHADER_STAGE_FRAGMENT_BIT, "color_frag", "main"); + break; + case VK_SHADER_STAGE_GEOMETRY_BIT: + if (features.geometryShader == VK_FALSE) + { + TCU_THROW(NotSupportedError, "Geometry Shader Not Supported"); + } + else + { + m_pipelineBuilder.bindShaderStage(VK_SHADER_STAGE_GEOMETRY_BIT, "dummy_geo", "main"); + } + break; + case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: + if (features.tessellationShader == VK_FALSE) + { + TCU_THROW(NotSupportedError, "Tessellation Not Supported"); + } + else + { + m_pipelineBuilder.bindShaderStage(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, "basic_tcs", "main"); + } + break; + case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: + if (features.tessellationShader == VK_FALSE) + { + TCU_THROW(NotSupportedError, "Tessellation Not Supported"); + } + else + { + m_pipelineBuilder.bindShaderStage(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, "basic_tes", "main"); + } + break; + default: + DE_ASSERT(!"Unknown Shader Stage!"); + break; + }; + } + + m_pipeline[PIPELINE_CACHE_NDX_NO_CACHE] = m_pipelineBuilder.buildPipeline(m_renderSize, *m_renderPass, *m_cache); + m_pipeline[PIPELINE_CACHE_NDX_CACHED] = m_pipelineBuilder.buildPipeline(m_renderSize, *m_renderPass, *m_cache); +} + +GraphicsCacheTestInstance::~GraphicsCacheTestInstance (void) +{ +} + +void GraphicsCacheTestInstance::prepareRenderPass (VkFramebuffer framebuffer, VkPipeline pipeline) +{ + const DeviceInterface& vk = m_context.getDeviceInterface(); + + const VkClearValue attachmentClearValues[2] = + { + defaultClearValue(m_colorFormat), + defaultClearValue(m_depthFormat), + }; + + const VkRenderPassBeginInfo renderPassBeginInfo = + { + VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + *m_renderPass, // VkRenderPass renderPass; + framebuffer, // VkFramebuffer framebuffer; + { { 0, 0 }, { m_renderSize.x(), m_renderSize.y() } }, // VkRect2D renderArea; + 2u, // deUint32 clearValueCount; + attachmentClearValues // const VkClearValue* pClearValues; + }; + + vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + + vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); + VkDeviceSize offsets = 0u; + vk.cmdBindVertexBuffers(*m_cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &offsets); + vk.cmdDraw(*m_cmdBuffer, (deUint32)m_vertices.size(), 1u, 0u, 0u); + + vk.cmdEndRenderPass(*m_cmdBuffer); +} + +void GraphicsCacheTestInstance::prepareCommandBuffer (void) +{ + const DeviceInterface& vk = m_context.getDeviceInterface(); + + const VkCommandBufferBeginInfo cmdBufferBeginInfo = + { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkCommandBufferUsageFlags flags; + (const VkCommandBufferInheritanceInfo*)DE_NULL, + }; + + VK_CHECK(vk.beginCommandBuffer(*m_cmdBuffer, &cmdBufferBeginInfo)); + + prepareRenderPass(*m_framebuffer[PIPELINE_CACHE_NDX_NO_CACHE], *m_pipeline[PIPELINE_CACHE_NDX_NO_CACHE]); + + prepareRenderPass(*m_framebuffer[PIPELINE_CACHE_NDX_CACHED], *m_pipeline[PIPELINE_CACHE_NDX_CACHED]); + + VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer)); +} + +tcu::TestStatus GraphicsCacheTestInstance::verifyTestResult (void) +{ + const DeviceInterface& vk = m_context.getDeviceInterface(); + const VkDevice vkDevice = m_context.getDevice(); + const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); + SimpleAllocator* memAlloc = new SimpleAllocator(vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice())); + + const VkQueue queue = m_context.getUniversalQueue(); + de::MovePtr resultNoCache = readColorAttachment(vk, + vkDevice, + queue, + queueFamilyIndex, + *memAlloc, + *m_colorImage[PIPELINE_CACHE_NDX_NO_CACHE], + m_colorFormat, + m_renderSize); + de::MovePtr resultCache = readColorAttachment(vk, + vkDevice, + queue, + queueFamilyIndex, + *memAlloc, + *m_colorImage[PIPELINE_CACHE_NDX_CACHED], + m_colorFormat, + m_renderSize); + + bool compareOk = tcu::intThresholdCompare(m_context.getTestContext().getLog(), + "IntImageCompare", + "Image comparison", + resultNoCache->getAccess(), + resultCache->getAccess(), + tcu::UVec4(1, 1, 1, 1), + tcu::COMPARE_LOG_RESULT); + + if (compareOk) + return tcu::TestStatus::pass("Render images w/o cached pipeline match."); + else + return tcu::TestStatus::fail("Render Images mismatch."); +} + +class ComputeCacheTest : public CacheTest +{ +public: + ComputeCacheTest (tcu::TestContext& testContext, + const std::string& name, + const std::string& description, + const CacheTestParam* param) + : CacheTest (testContext, name, description, param) + { } + virtual ~ComputeCacheTest (void) { } + virtual void initPrograms (SourceCollections& programCollection) const; + virtual TestInstance* createInstance (Context& context) const; +}; + +class ComputeCacheTestInstance : public CacheTestInstance +{ +public: + ComputeCacheTestInstance (Context& context, + const CacheTestParam* param); + virtual ~ComputeCacheTestInstance (void); + virtual void prepareCommandBuffer (void); +protected: + virtual tcu::TestStatus verifyTestResult (void); + void buildBuffers (void); + void buildDescriptorSets (deUint32 ndx); + void buildShader (void); + void buildPipeline (deUint32 ndx); +protected: + Move m_inputBuf; + Move m_computeShaderModule; + + Move m_outputBuf[PIPELINE_CACHE_NDX_COUNT]; + de::MovePtr m_outputBufferAlloc[PIPELINE_CACHE_NDX_COUNT]; + + Move m_descriptorPool[PIPELINE_CACHE_NDX_COUNT]; + Move m_descriptorSetLayout[PIPELINE_CACHE_NDX_COUNT]; + Move m_descriptorSet[PIPELINE_CACHE_NDX_COUNT]; + + Move m_pipelineLayout[PIPELINE_CACHE_NDX_COUNT]; + Move m_pipeline[PIPELINE_CACHE_NDX_COUNT]; +}; + +void ComputeCacheTest::initPrograms (SourceCollections& programCollection) const +{ + programCollection.glslSources.add("basic_compute") << glu::ComputeSource( + "#version 310 es\n" + "layout(local_size_x = 128) in;\n" + "layout(std430) buffer;\n" + "layout(binding = 0) readonly buffer Input0\n" + "{\n" + " vec4 elements[];\n" + "} input_data0;\n" + "layout(binding = 1) writeonly buffer Output\n" + "{\n" + " vec4 elements[];\n" + "} output_data;\n" + "void main()\n" + "{\n" + " uint ident = gl_GlobalInvocationID.x;\n" + " output_data.elements[ident] = input_data0.elements[ident] * input_data0.elements[ident];\n" + "}"); +} + +TestInstance* ComputeCacheTest::createInstance (Context& context) const +{ + return new ComputeCacheTestInstance(context, &m_param); +} + +void ComputeCacheTestInstance::buildBuffers (void) +{ + const DeviceInterface& vk = m_context.getDeviceInterface(); + const VkDevice vkDevice = m_context.getDevice(); + + // Create buffer object, allocate storage, and generate input data + const VkDeviceSize size = sizeof(tcu::Vec4) * 128u; + de::MovePtr bufferAlloc; + m_inputBuf = createBufferAndBindMemory(m_context, size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, &bufferAlloc); + + // Initialize input buffer + tcu::Vec4* pVec = reinterpret_cast(bufferAlloc->getHostPtr()); + for (deUint32 ndx = 0u; ndx < 128u; ndx++) + { + for (deUint32 component = 0u; component < 4u; component++) + pVec[ndx][component]= (float)(ndx * (component + 1u)); + } + flushMappedMemoryRange(vk, vkDevice, bufferAlloc->getMemory(), bufferAlloc->getOffset(), size); + + // Clear the output buffer + for (deUint32 ndx = 0; ndx < PIPELINE_CACHE_NDX_COUNT; ndx++) + { + m_outputBuf[ndx] = createBufferAndBindMemory(m_context, size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, &m_outputBufferAlloc[ndx]); + + pVec = reinterpret_cast(m_outputBufferAlloc[ndx]->getHostPtr()); + memset(pVec, 0u, size); + flushMappedMemoryRange(vk, vkDevice, m_outputBufferAlloc[ndx]->getMemory(), m_outputBufferAlloc[ndx]->getOffset(), size); + } +} + +void ComputeCacheTestInstance::buildDescriptorSets (deUint32 ndx) +{ + const DeviceInterface& vk = m_context.getDeviceInterface(); + const VkDevice vkDevice = m_context.getDevice(); + + // Create descriptor set layout + DescriptorSetLayoutBuilder descLayoutBuilder; + + for (deUint32 bindingNdx = 0u; bindingNdx < 2u; bindingNdx++) + descLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT); + + m_descriptorSetLayout[ndx] = descLayoutBuilder.build(vk, vkDevice); + + std::vector descriptorInfos; + descriptorInfos.push_back(makeDescriptorBufferInfo(*m_inputBuf, 0u, sizeof(tcu::Vec4) * 128u)); + descriptorInfos.push_back(makeDescriptorBufferInfo(*m_outputBuf[ndx], 0u, sizeof(tcu::Vec4) * 128u)); + + // Create descriptor pool + m_descriptorPool[ndx] = DescriptorPoolBuilder().addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2u).build(vk, + vkDevice, + VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, + 1u); + + // Create descriptor set + const VkDescriptorSetAllocateInfo descriptorSetAllocInfo = + { + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + *m_descriptorPool[ndx], // VkDescriptorPool descriptorPool; + 1u, // deUint32 setLayoutCount; + &m_descriptorSetLayout[ndx].get(), // const VkDescriptorSetLayout* pSetLayouts; + }; + m_descriptorSet[ndx] = allocateDescriptorSet(vk, vkDevice, &descriptorSetAllocInfo); + + DescriptorSetUpdateBuilder builder; + for (deUint32 descriptorNdx = 0u; descriptorNdx < 2u; descriptorNdx++) + { + builder.writeSingle(*m_descriptorSet[ndx], + DescriptorSetUpdateBuilder::Location::binding(descriptorNdx), + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + &descriptorInfos[descriptorNdx]); + } + builder.update(vk, vkDevice); +} + +void ComputeCacheTestInstance::buildShader (void) +{ + const DeviceInterface& vk = m_context.getDeviceInterface(); + const VkDevice vkDevice = m_context.getDevice(); + + // Create compute shader + VkShaderModuleCreateInfo shaderModuleCreateInfo = + { + VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkShaderModuleCreateFlags flags; + m_context.getBinaryCollection().get("basic_compute").getSize(), // deUintptr codeSize; + (deUint32*)m_context.getBinaryCollection().get("basic_compute").getBinary(), // const deUint32* pCode; + }; + m_computeShaderModule = createShaderModule(vk, vkDevice, &shaderModuleCreateInfo); +} + +void ComputeCacheTestInstance::buildPipeline (deUint32 ndx) +{ + const DeviceInterface& vk = m_context.getDeviceInterface(); + const VkDevice vkDevice = m_context.getDevice(); + + // Create compute pipeline layout + const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = + { + VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkPipelineLayoutCreateFlags flags; + 1u, // deUint32 setLayoutCount; + &m_descriptorSetLayout[ndx].get(), // const VkDescriptorSetLayout* pSetLayouts; + 0u, // deUint32 pushConstantRangeCount; + DE_NULL, // const VkPushConstantRange* pPushConstantRanges; + }; + + m_pipelineLayout[ndx] = createPipelineLayout(vk, vkDevice, &pipelineLayoutCreateInfo); + + const VkPipelineShaderStageCreateInfo stageCreateInfo = + { + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkPipelineShaderStageCreateFlags flags; + VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStageFlagBits stage; + *m_computeShaderModule, // VkShaderModule module; + "main", // const char* pName; + DE_NULL, // const VkSpecializationInfo* pSpecializationInfo; + }; + + const VkComputePipelineCreateInfo pipelineCreateInfo = + { + VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkPipelineCreateFlags flags; + stageCreateInfo, // VkPipelineShaderStageCreateInfo stage; + *m_pipelineLayout[ndx], // VkPipelineLayout layout; + (VkPipeline)0, // VkPipeline basePipelineHandle; + 0u, // deInt32 basePipelineIndex; + }; + + m_pipeline[ndx] = createComputePipeline(vk, vkDevice, *m_cache, &pipelineCreateInfo); +} + +ComputeCacheTestInstance::ComputeCacheTestInstance (Context& context, + const CacheTestParam* param) + : CacheTestInstance (context, param) +{ + buildBuffers(); + + buildDescriptorSets(PIPELINE_CACHE_NDX_NO_CACHE); + + buildDescriptorSets(PIPELINE_CACHE_NDX_CACHED); + + buildShader(); + + buildPipeline(PIPELINE_CACHE_NDX_NO_CACHE); + + buildPipeline(PIPELINE_CACHE_NDX_CACHED); +} + +ComputeCacheTestInstance::~ComputeCacheTestInstance (void) +{ +} + +void ComputeCacheTestInstance::prepareCommandBuffer (void) +{ + const DeviceInterface& vk = m_context.getDeviceInterface(); + + const VkCommandBufferBeginInfo cmdBufferBeginInfo = + { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkCommandBufferUsageFlags flags; + (const VkCommandBufferInheritanceInfo*)DE_NULL, + }; + + VK_CHECK(vk.beginCommandBuffer(*m_cmdBuffer, &cmdBufferBeginInfo)); + + for (deUint32 ndx = 0; ndx < PIPELINE_CACHE_NDX_COUNT; ndx++) + { + vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *m_pipeline[ndx]); + vk.cmdBindDescriptorSets(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *m_pipelineLayout[ndx], 0u, 1u, &m_descriptorSet[ndx].get(), 0u, DE_NULL); + vk.cmdDispatch(*m_cmdBuffer, 128u, 1u, 1u); + } + + VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer)); +} + +tcu::TestStatus ComputeCacheTestInstance::verifyTestResult (void) +{ + const DeviceInterface& vk = m_context.getDeviceInterface(); + const VkDevice vkDevice = m_context.getDevice(); + + // Read the content of output buffers + invalidateMappedMemoryRange(vk, + vkDevice, + m_outputBufferAlloc[PIPELINE_CACHE_NDX_NO_CACHE]->getMemory(), + m_outputBufferAlloc[PIPELINE_CACHE_NDX_NO_CACHE]->getOffset(), + sizeof(tcu::Vec4) * 128u); + + invalidateMappedMemoryRange(vk, + vkDevice, + m_outputBufferAlloc[PIPELINE_CACHE_NDX_CACHED]->getMemory(), + m_outputBufferAlloc[PIPELINE_CACHE_NDX_CACHED]->getOffset(), + sizeof(tcu::Vec4) * 128u); + // Compare the content + deUint8* bufNoCache = reinterpret_cast(m_outputBufferAlloc[PIPELINE_CACHE_NDX_NO_CACHE]->getHostPtr()); + deUint8* bufCached = reinterpret_cast(m_outputBufferAlloc[PIPELINE_CACHE_NDX_CACHED]->getHostPtr()); + for (deUint32 ndx = 0u; ndx < sizeof(tcu::Vec4) * 128u; ndx++) + { + if (bufNoCache[ndx] != bufCached[ndx]) + { + return tcu::TestStatus::fail("Output buffers w/o cached pipeline mismatch."); + } + } + + return tcu::TestStatus::pass("Output buffers w/o cached pipeline match."); +} + +class MergeCacheTest : public GraphicsCacheTest +{ +public: + MergeCacheTest (tcu::TestContext& testContext, + const std::string& name, + const std::string& description, + const CacheTestParam* param) + : GraphicsCacheTest (testContext, name, description, param) + { } + virtual ~MergeCacheTest (void) { } + virtual TestInstance* createInstance (Context& context) const; +}; + +class MergeCacheTestInstance : public GraphicsCacheTestInstance +{ +public: + MergeCacheTestInstance (Context& context, + const CacheTestParam* param); + virtual ~MergeCacheTestInstance (void); +protected: +protected: + Move m_cacheGetData; + Move m_cacheEmpty; + Move m_cacheMerged; + deUint8* m_data; +}; + +TestInstance* MergeCacheTest::createInstance (Context& context) const +{ + return new MergeCacheTestInstance(context, &m_param); +} + +MergeCacheTestInstance::MergeCacheTestInstance (Context& context, const CacheTestParam* param) + : GraphicsCacheTestInstance (context, param) + , m_data (DE_NULL) +{ + const DeviceInterface& vk = m_context.getDeviceInterface(); + const VkDevice vkDevice = m_context.getDevice(); + + // Create more pipeline caches + { + // Create a empty cache as one of source cache + VkPipelineCacheCreateInfo pipelineCacheCreateInfo = + { + VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkPipelineCacheCreateFlags flags; + 0u, // deUintptr initialDataSize; + DE_NULL, // const void* pInitialData; + }; + m_cacheEmpty = createPipelineCache(vk, vkDevice, &pipelineCacheCreateInfo); + + // Create a empty cache for merge destination cache + m_cacheMerged = createPipelineCache(vk, vkDevice, &pipelineCacheCreateInfo); + + // Create a cache with init data from m_cache + size_t dataSize = 0u; + VK_CHECK(vk.getPipelineCacheData(vkDevice, *m_cache, (deUintptr*)&dataSize, DE_NULL)); + + m_data = new deUint8[dataSize]; + DE_ASSERT(m_data); + VK_CHECK(vk.getPipelineCacheData(vkDevice, *m_cache, (deUintptr*)&dataSize, (void*)m_data)); + + pipelineCacheCreateInfo.initialDataSize = dataSize; + pipelineCacheCreateInfo.pInitialData = m_data; + m_cacheGetData = createPipelineCache(vk, vkDevice, &pipelineCacheCreateInfo); + } + + // Merge the caches + const VkPipelineCache sourceCaches[] = + { + *m_cacheEmpty, + *m_cacheGetData, + }; + VK_CHECK(vk.mergePipelineCaches(vkDevice, *m_cacheMerged, 2u, sourceCaches)); + + // Create pipeline from merged cache + m_pipeline[PIPELINE_CACHE_NDX_CACHED] = m_pipelineBuilder.buildPipeline(m_renderSize, *m_renderPass, *m_cacheMerged); +} + +MergeCacheTestInstance::~MergeCacheTestInstance (void) +{ + delete[] m_data; +} + +} // anonymous + +tcu::TestCaseGroup* createCacheTests (tcu::TestContext& testCtx) +{ + + de::MovePtr cacheTests (new tcu::TestCaseGroup(testCtx, "cache", "pipeline cache tests")); + + // Graphics Pipeline Tests + { + de::MovePtr graphicsTests (new tcu::TestCaseGroup(testCtx, "graphics_tests", "Test pipeline cache with graphics pipeline.")); + + const VkShaderStageFlagBits testParamShaders0[] = + { + VK_SHADER_STAGE_VERTEX_BIT, + VK_SHADER_STAGE_FRAGMENT_BIT, + }; + const VkShaderStageFlagBits testParamShaders1[] = + { + VK_SHADER_STAGE_VERTEX_BIT, + VK_SHADER_STAGE_GEOMETRY_BIT, + VK_SHADER_STAGE_FRAGMENT_BIT, + }; + const VkShaderStageFlagBits testParamShaders2[] = + { + VK_SHADER_STAGE_VERTEX_BIT, + VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, + VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, + VK_SHADER_STAGE_FRAGMENT_BIT, + }; + const CacheTestParam* testParams[] = + { + new CacheTestParam(testParamShaders0, DE_LENGTH_OF_ARRAY(testParamShaders0)), + new CacheTestParam(testParamShaders1, DE_LENGTH_OF_ARRAY(testParamShaders1)), + new CacheTestParam(testParamShaders2, DE_LENGTH_OF_ARRAY(testParamShaders2)), + }; + + for(deUint32 i = 0; i < DE_LENGTH_OF_ARRAY(testParams); i++) + { + graphicsTests->addChild(newTestCase(testCtx,testParams[i])); + delete testParams[i]; + } + cacheTests->addChild(graphicsTests.release()); + } + + // Graphics Pipeline Tests + { + de::MovePtr computeTests (new tcu::TestCaseGroup(testCtx, "compute_tests", "Test pipeline cache with compute pipeline.")); + + const VkShaderStageFlagBits testParamShaders0[] = + { + VK_SHADER_STAGE_COMPUTE_BIT, + }; + + const CacheTestParam* testParams[] = + { + new CacheTestParam(testParamShaders0, DE_LENGTH_OF_ARRAY(testParamShaders0)), + }; + for(deUint32 i = 0; i < DE_LENGTH_OF_ARRAY(testParams); i++) + { + computeTests->addChild(newTestCase(testCtx,testParams[i])); + delete testParams[i]; + } + cacheTests->addChild(computeTests.release()); + } + + // Misc Tests + { + de::MovePtr miscTests (new tcu::TestCaseGroup(testCtx, "misc_tests", "Misc tests that can not be categorized to other group.")); + + const VkShaderStageFlagBits testParamShaders[] = + { + VK_SHADER_STAGE_VERTEX_BIT, + VK_SHADER_STAGE_FRAGMENT_BIT, + }; + + CacheTestParam* testParam = new CacheTestParam(testParamShaders, DE_LENGTH_OF_ARRAY(testParamShaders)); + miscTests->addChild(new MergeCacheTest(testCtx, + "merge_cache_test", + "Merge the caches test.", + testParam)); + delete testParam; + + cacheTests->addChild(miscTests.release()); + } + + return cacheTests.release(); +} + +} // pipeline + +} // vkt diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineCacheTests.hpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineCacheTests.hpp new file mode 100644 index 0000000..705ea22 --- /dev/null +++ b/external/vulkancts/modules/vulkan/pipeline/vktPipelineCacheTests.hpp @@ -0,0 +1,50 @@ +#ifndef _VKTPIPELINECACHETESTS_HPP +#define _VKTPIPELINECACHETESTS_HPP +/*------------------------------------------------------------------------ + * Vulkan Conformance Tests + * ------------------------ + * + * Copyright (c) 2015 The Khronos Group Inc. + * Copyright (c) 2015 ARM Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and/or associated documentation files (the + * "Materials"), to deal in the Materials without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Materials, and to + * permit persons to whom the Materials are furnished to do so, subject to + * the following conditions: + * + * The above copyright notice(s) and this permission notice shall be included + * in all copies or substantial portions of the Materials. + * + * The Materials are Confidential Information as defined by the + * Khronos Membership Agreement until designated non-confidential by Khronos, + * at which point this condition clause shall be removed. + * + * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + * + *//*! + * \file + * \brief Pipeline Cache Tests + *//*--------------------------------------------------------------------*/ + +#include "vktTestCase.hpp" + +namespace vkt +{ +namespace pipeline +{ + +tcu::TestCaseGroup* createCacheTests (tcu::TestContext& testCtx); + +} // pipeline +} // vkt + +#endif // _VKTPIPELINECACHETESTS_HPP diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineTests.cpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineTests.cpp index c16ce51..6616716 100644 --- a/external/vulkancts/modules/vulkan/pipeline/vktPipelineTests.cpp +++ b/external/vulkancts/modules/vulkan/pipeline/vktPipelineTests.cpp @@ -42,6 +42,7 @@ #include "vktPipelineVertexInputTests.hpp" #include "vktPipelineTimestampTests.hpp" #include "vktPipelineEarlyFragmentTests.hpp" +#include "vktPipelineCacheTests.hpp" #include "vktTestGroupUtil.hpp" namespace vkt @@ -68,6 +69,7 @@ void createChildren (tcu::TestCaseGroup* pipelineTests) pipelineTests->addChild(createInputAssemblyTests(testCtx)); pipelineTests->addChild(createTimestampTests (testCtx)); pipelineTests->addChild(createEarlyFragmentTests(testCtx)); + pipelineTests->addChild(createCacheTests (testCtx)); } } // anonymous