blob: c79ee06ea0b4ef7acb737d19271e6a31ec2a96e3 [file] [log] [blame]
/*------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2021 The Khronos Group Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*//*!
* \file
* \brief Vulkan SC pipeline identifier tests
*//*--------------------------------------------------------------------*/
#include "vktPipelineIdentifierTests.hpp"
#include <set>
#include <vector>
#include <string>
#include "vktTestCaseUtil.hpp"
#include "vkDefs.hpp"
#include "vkSafetyCriticalUtil.hpp"
#include "vkQueryUtil.hpp"
#include "vkRefUtil.hpp"
#include "tcuTestLog.hpp"
namespace vkt
{
namespace sc
{
using namespace vk;
namespace
{
enum PIPipeline
{
PIP_UNUSED = 0,
PIP_GRAPHICS,
PIP_COMPUTE
};
enum PITTestType
{
PITT_UNUSED = 0,
PITT_MISSING_ID,
PITT_NONEXISTING_ID,
PITT_MATCHCONTROL
};
enum PITMatchControl
{
PIMC_UNUSED = 0,
PIMC_UUID_EXACT_MATCH
};
struct TestParams
{
PITTestType type;
PITMatchControl matchControl;
bool single;
};
void createGraphicsShaders (SourceCollections& dst, TestParams testParams)
{
deUint32 pipelineCount = testParams.single ? 1 : 3;
for (deUint32 i = 0; i < pipelineCount; ++i)
{
std::ostringstream name, code;
name << "vertex_" << i;
code <<
"#version 450\n"
"\n"
"void main (void)\n"
"{\n"
" gl_Position = vec4( "<< i <<");\n"
"}\n";
dst.glslSources.add(name.str()) << glu::VertexSource(code.str());
}
for (deUint32 i = 0; i < pipelineCount; ++i)
{
std::ostringstream name, code;
name << "fragment_" << i;
code <<
"#version 450\n"
"\n"
"layout(location=0) out vec4 x;\n"
"void main (void)\n"
"{\n"
" x = vec4(" << i <<");\n"
"}\n";
dst.glslSources.add(name.str()) << glu::FragmentSource(code.str());
}
}
void createComputeShaders (SourceCollections& dst, TestParams testParams)
{
deUint32 pipelineCount = testParams.single ? 1 : 3;
for (deUint32 i = 0; i < pipelineCount; ++i)
{
std::ostringstream name, code;
name << "compute_" << i;
code <<
"#version 450\n"
"layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
"void main (void)\n"
"{\n"
" uvec4 x = uvec4(" << i <<");\n"
"}\n";
dst.glslSources.add(name.str()) << glu::ComputeSource(code.str());
}
}
tcu::TestStatus testGraphicsPipelineIdentifier (Context& context, TestParams testParams)
{
const vk::PlatformInterface& vkp = context.getPlatformInterface();
const InstanceInterface& vki = context.getInstanceInterface();
const VkInstance instance = context.getInstance();
const DeviceInterface& vk = context.getDeviceInterface();
const VkDevice device = context.getDevice();
const VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
deUint32 pipelineCount = testParams.single ? 1 : 3;
std::vector<Move<VkShaderModule>> shaders;
for (deUint32 i = 0; i < pipelineCount; ++i)
{
{
std::ostringstream name;
name << "vertex_" << i;
shaders.emplace_back(createShaderModule(vk, device, context.getBinaryCollection().get(name.str()), 0));
}
{
std::ostringstream name;
name << "fragment_" << i;
shaders.emplace_back(createShaderModule(vk, device, context.getBinaryCollection().get(name.str()), 0));
}
}
std::vector<std::vector<VkPipelineShaderStageCreateInfo>> shaderStageCreateInfos (pipelineCount);
for (deUint32 i = 0; i < pipelineCount; ++i)
{
shaderStageCreateInfos[i].push_back
(
{
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags;
VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStageFlagBits stage;
*shaders[2*i], // VkShaderModule shader;
"main", // const char* pName;
DE_NULL, // const VkSpecializationInfo* pSpecializationInfo;
}
);
shaderStageCreateInfos[i].push_back
(
{
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags;
VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlagBits stage;
*shaders[2*i+1], // VkShaderModule shader;
"main", // const char* pName;
DE_NULL, // const VkSpecializationInfo* pSpecializationInfo;
}
);
}
std::vector<VkPipelineVertexInputStateCreateInfo> vertexInputStateCreateInfo (pipelineCount);
std::vector<VkPipelineInputAssemblyStateCreateInfo> inputAssemblyStateCreateInfo (pipelineCount);
std::vector<VkPipelineViewportStateCreateInfo> viewPortStateCreateInfo (pipelineCount);
std::vector<VkPipelineRasterizationStateCreateInfo> rasterizationStateCreateInfo (pipelineCount);
std::vector<VkPipelineMultisampleStateCreateInfo> multisampleStateCreateInfo (pipelineCount);
std::vector<VkPipelineColorBlendAttachmentState> colorBlendAttachmentState (pipelineCount);
std::vector<VkPipelineColorBlendStateCreateInfo> colorBlendStateCreateInfo (pipelineCount);
std::vector<VkPipelineDynamicStateCreateInfo> dynamicStateCreateInfo (pipelineCount);
std::vector<std::vector<VkDynamicState>> dynamicStates
{
{ VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR },
{ VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR },
{ VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR },
};
const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo =
{
VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkPipelineLayoutCreateFlags)0u, // VkPipelineLayoutCreateFlags flags;
0u, // deUint32 setLayoutCount;
DE_NULL, // const VkDescriptorSetLayout* pSetLayouts;
0u, // deUint32 pushConstantRangeCount;
DE_NULL // const VkPushConstantRange* pPushConstantRanges;
};
Move<VkPipelineLayout> pipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
const VkFormat format = getRenderTargetFormat(vki, physicalDevice);
VkAttachmentDescription attachmentDescription;
VkAttachmentReference attachmentReference;
VkSubpassDescription subpassDescription;
VkRenderPassCreateInfo renderPassCreateInfo = prepareSimpleRenderPassCI(format, attachmentDescription, attachmentReference, subpassDescription);
Move<VkRenderPass> renderPass = createRenderPass(vk, device, &renderPassCreateInfo);
std::vector<VkGraphicsPipelineCreateInfo> graphicsPipelineCreateInfos (pipelineCount);
for (deUint32 i = 0; i < pipelineCount; ++i)
graphicsPipelineCreateInfos[i] = prepareSimpleGraphicsPipelineCI(vertexInputStateCreateInfo[i], shaderStageCreateInfos[i], inputAssemblyStateCreateInfo[i], viewPortStateCreateInfo[i],
rasterizationStateCreateInfo[i], multisampleStateCreateInfo[i], colorBlendAttachmentState[i], colorBlendStateCreateInfo[i], dynamicStateCreateInfo[i], dynamicStates[i], *pipelineLayout, *renderPass);
std::vector<std::string> sourcePID { "IDG_0000", "IDG_1111", "IDG_2222" };
std::vector<std::string> destPID;
switch (testParams.type)
{
case PITT_MISSING_ID:
case PITT_NONEXISTING_ID:
destPID = { "IDG_XXXX", "IDG_1111", "IDG_2222" };
break;
case PITT_MATCHCONTROL:
switch (testParams.matchControl)
{
case PIMC_UUID_EXACT_MATCH:
destPID = { "IDG_0000", "IDG_1111", "IDG_2222" };
break;
default:
TCU_THROW(InternalError, "Unrecognized match control");
}
break;
default:
TCU_THROW(InternalError, "Unrecognized test type");
}
// fill pipeline identifiers with initial values, apply pipeline names from sourcePID
std::vector<VkPipelineOfflineCreateInfo> pipelineIDs;
for (deUint32 i = 0; i < pipelineCount; ++i)
{
pipelineIDs.emplace_back(resetPipelineOfflineCreateInfo());
applyPipelineIdentifier(pipelineIDs[i], sourcePID[i]);
}
switch (testParams.matchControl)
{
case PIMC_UUID_EXACT_MATCH:
for (deUint32 i = 0; i < pipelineCount; ++i)
pipelineIDs[i].matchControl = VK_PIPELINE_MATCH_CONTROL_APPLICATION_UUID_EXACT_MATCH;
break;
default:
TCU_THROW(InternalError, "Unrecognized match control");
}
if (!context.getTestContext().getCommandLine().isSubProcess())
{
// If it's a main process - we create graphics pipelines only to increase VkDeviceObjectReservationCreateInfo::computePipelineRequestCount.
// We also fill all pipeline identifiers with distinct values ( otherwise the framework will create pipeline identifiers itself )
for (deUint32 i = 0; i < pipelineCount; ++i)
{
pipelineIDs[i].pNext = graphicsPipelineCreateInfos[i].pNext;
graphicsPipelineCreateInfos[i].pNext = &pipelineIDs[i];
}
std::vector<Move<VkPipeline>> pipelines;
for (deUint32 i = 0; i < pipelineCount; ++i)
pipelines.emplace_back(createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineCreateInfos[i]));
return tcu::TestStatus::pass("Pass");
}
for (deUint32 i = 0; i < pipelineCount; ++i)
context.getResourceInterface()->fillPoolEntrySize(pipelineIDs[i]);
// subprocess - we create the same pipeline, but we use vkCreateGraphicsPipelines directly to skip the framework
GetDeviceProcAddrFunc getDeviceProcAddrFunc = (GetDeviceProcAddrFunc)vkp.getInstanceProcAddr(instance, "vkGetDeviceProcAddr");
CreateGraphicsPipelinesFunc createGraphicsPipelinesFunc = (CreateGraphicsPipelinesFunc)getDeviceProcAddrFunc(device, "vkCreateGraphicsPipelines");
DestroyPipelineFunc destroyPipelineFunc = (DestroyPipelineFunc)getDeviceProcAddrFunc(device, "vkDestroyPipeline");
VkPipelineCache pipelineCache = context.getResourceInterface()->getPipelineCache(device);
std::vector<VkPipeline> pipelines (pipelineCount);
VkResult expectedResult;
std::vector<deUint8> expectedNullHandle (pipelineCount);
switch (testParams.type)
{
case PITT_MISSING_ID:
expectedResult = VK_ERROR_NO_PIPELINE_MATCH;
expectedNullHandle[0] = 1;
for (deUint32 i = 1; i < pipelineCount; ++i)
{
// we are skipping pipeline identifier at index 0
applyPipelineIdentifier(pipelineIDs[i], destPID[i]);
pipelineIDs[i].pNext = graphicsPipelineCreateInfos[i].pNext;
graphicsPipelineCreateInfos[i].pNext = &pipelineIDs[i];
expectedNullHandle[i] = 0;
}
break;
case PITT_NONEXISTING_ID:
expectedResult = VK_ERROR_NO_PIPELINE_MATCH;
for (deUint32 i = 0; i < pipelineCount; ++i)
{
// Pipeline identifier at index 0 uses wrong ID for PITT_NONEXISTING_ID test
// or a proper one for PITT_MATCHCONTROL test
applyPipelineIdentifier(pipelineIDs[i], destPID[i]);
pipelineIDs[i].pNext = graphicsPipelineCreateInfos[i].pNext;
graphicsPipelineCreateInfos[i].pNext = &pipelineIDs[i];
expectedNullHandle[i] = (i == 0);
}
break;
case PITT_MATCHCONTROL:
expectedResult = VK_SUCCESS;
for (deUint32 i = 0; i < pipelineCount; ++i)
{
// Pipeline identifier at index 0 uses wrong ID for PITT_NONEXISTING_ID test
// or a proper one for PITT_MATCHCONTROL test
applyPipelineIdentifier(pipelineIDs[i], destPID[i]);
pipelineIDs[i].pNext = graphicsPipelineCreateInfos[i].pNext;
graphicsPipelineCreateInfos[i].pNext = &pipelineIDs[i];
expectedNullHandle[i] = 0;
}
break;
default:
TCU_THROW(InternalError, "Unrecognized match control");
}
VkResult result = createGraphicsPipelinesFunc(device, pipelineCache, pipelineCount, graphicsPipelineCreateInfos.data(), DE_NULL, pipelines.data());
bool isOK = true;
for (deUint32 i = 0; i < pipelineCount; ++i)
{
if (expectedNullHandle[i] == 0 && pipelines[i] == DE_NULL)
{
context.getTestContext().getLog() << tcu::TestLog::Message << "Pipeline "<< i << " should be created" << tcu::TestLog::EndMessage;
isOK = false;
}
if (expectedNullHandle[i] != 0 && pipelines[i] != DE_NULL)
{
context.getTestContext().getLog() << tcu::TestLog::Message << "Pipeline " << i << " should not be created" << tcu::TestLog::EndMessage;
isOK = false;
}
}
if (result != expectedResult)
{
context.getTestContext().getLog() << tcu::TestLog::Message << "vkCreateGraphicsPipelines returned wrong VkResult" << tcu::TestLog::EndMessage;
isOK = false;
}
for (deUint32 i = 0; i < pipelineCount; ++i)
destroyPipelineFunc(device, pipelines[i], DE_NULL);
return isOK ? tcu::TestStatus::pass("Pass") : tcu::TestStatus::fail("Fail");
}
tcu::TestStatus testComputePipelineIdentifier (Context& context, TestParams testParams)
{
const vk::PlatformInterface& vkp = context.getPlatformInterface();
const VkInstance instance = context.getInstance();
const DeviceInterface& vk = context.getDeviceInterface();
const VkDevice device = context.getDevice();
deUint32 pipelineCount = testParams.single ? 1 : 3;
std::vector<Move<VkShaderModule>> computeShaders;
for (deUint32 i = 0; i < pipelineCount; ++i)
{
std::ostringstream name;
name << "compute_" << i;
computeShaders.emplace_back(createShaderModule(vk, device, context.getBinaryCollection().get(name.str()), 0));
}
std::vector<VkPipelineShaderStageCreateInfo> shaderStageCreateInfos (pipelineCount);
for (deUint32 i = 0; i < pipelineCount; ++i)
{
shaderStageCreateInfos[i] =
{
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags;
VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStageFlagBits stage;
*computeShaders[i], // VkShaderModule shader;
"main", // const char* pName;
DE_NULL, // const VkSpecializationInfo* pSpecializationInfo;
};
}
const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo =
{
VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkPipelineLayoutCreateFlags)0u, // VkPipelineLayoutCreateFlags flags;
0u, // deUint32 setLayoutCount;
DE_NULL, // const VkDescriptorSetLayout* pSetLayouts;
0u, // deUint32 pushConstantRangeCount;
DE_NULL // const VkPushConstantRange* pPushConstantRanges;
};
Move<VkPipelineLayout> pipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
std::vector<VkComputePipelineCreateInfo> computePipelineCreateInfos (pipelineCount);
for (deUint32 i = 0; i < pipelineCount; ++i)
computePipelineCreateInfos[i] = prepareSimpleComputePipelineCI(shaderStageCreateInfos[i], *pipelineLayout);
std::vector<std::string> sourcePID { "IDC_0000", "IDC_1111", "IDC_2222" };
std::vector<std::string> destPID;
switch (testParams.type)
{
case PITT_MISSING_ID:
case PITT_NONEXISTING_ID:
destPID = { "IDC_XXXX", "IDC_1111", "IDC_2222" };
break;
case PITT_MATCHCONTROL:
switch (testParams.matchControl)
{
case PIMC_UUID_EXACT_MATCH:
destPID = { "IDC_0000", "IDC_1111", "IDC_2222" };
break;
default:
TCU_THROW(InternalError, "Unrecognized match control");
}
break;
default:
TCU_THROW(InternalError, "Unrecognized test type");
}
// fill pipeline identifiers with initial values, apply pipeline names from sourcePID
std::vector<VkPipelineOfflineCreateInfo> pipelineIDs;
for (deUint32 i = 0; i < pipelineCount; ++i)
{
pipelineIDs.emplace_back(resetPipelineOfflineCreateInfo());
applyPipelineIdentifier(pipelineIDs[i], sourcePID[i]);
}
switch (testParams.matchControl)
{
case PIMC_UUID_EXACT_MATCH:
for (deUint32 i = 0; i < pipelineCount; ++i)
pipelineIDs[i].matchControl = VK_PIPELINE_MATCH_CONTROL_APPLICATION_UUID_EXACT_MATCH;
break;
default:
TCU_THROW(InternalError, "Unrecognized match control");
}
if (!context.getTestContext().getCommandLine().isSubProcess())
{
// If it's a main process - we create compute pipelines only to increase VkDeviceObjectReservationCreateInfo::computePipelineRequestCount.
// We also fill all pipeline identifiers with distinct values ( otherwise the framework will create pipeline identifiers itself )
for (deUint32 i = 0; i < pipelineCount; ++i)
{
pipelineIDs[i].pNext = computePipelineCreateInfos[i].pNext;
computePipelineCreateInfos[i].pNext = &pipelineIDs[i];
}
std::vector<Move<VkPipeline>> pipelines;
for (deUint32 i = 0; i < pipelineCount; ++i)
pipelines.emplace_back(createComputePipeline(vk, device, DE_NULL, &computePipelineCreateInfos[i]));
return tcu::TestStatus::pass("Pass");
}
for (deUint32 i = 0; i < pipelineCount; ++i)
context.getResourceInterface()->fillPoolEntrySize(pipelineIDs[i]);
// In subprocess we create the same pipelines, but we use vkCreateGraphicsPipelines directly to skip the framework
GetDeviceProcAddrFunc getDeviceProcAddrFunc = (GetDeviceProcAddrFunc)vkp.getInstanceProcAddr(instance, "vkGetDeviceProcAddr");
CreateComputePipelinesFunc createComputePipelinesFunc = (CreateComputePipelinesFunc)getDeviceProcAddrFunc(device, "vkCreateComputePipelines");
DestroyPipelineFunc destroyPipelineFunc = (DestroyPipelineFunc)getDeviceProcAddrFunc(device, "vkDestroyPipeline");
VkPipelineCache pipelineCache = context.getResourceInterface()->getPipelineCache(device);
std::vector<VkPipeline> pipelines (pipelineCount);
VkResult expectedResult;
std::vector<deUint8> expectedNullHandle (pipelineCount);
switch (testParams.type)
{
case PITT_MISSING_ID:
expectedResult = VK_ERROR_NO_PIPELINE_MATCH;
expectedNullHandle[0] = 1;
for (deUint32 i = 1; i < pipelineCount; ++i)
{
// we are skipping pipeline identifier at index 0
applyPipelineIdentifier(pipelineIDs[i], destPID[i]);
pipelineIDs[i].pNext = computePipelineCreateInfos[i].pNext;
computePipelineCreateInfos[i].pNext = &pipelineIDs[i];
expectedNullHandle[i] = 0;
}
break;
case PITT_NONEXISTING_ID:
expectedResult = VK_ERROR_NO_PIPELINE_MATCH;
for (deUint32 i = 0; i < pipelineCount; ++i)
{
// Pipeline identifier at index 0 uses wrong ID for PITT_NONEXISTING_ID test
// or a proper one for PITT_MATCHCONTROL test
applyPipelineIdentifier(pipelineIDs[i], destPID[i]);
pipelineIDs[i].pNext = computePipelineCreateInfos[i].pNext;
computePipelineCreateInfos[i].pNext = &pipelineIDs[i];
expectedNullHandle[i] = (i == 0);
}
break;
case PITT_MATCHCONTROL:
expectedResult = VK_SUCCESS;
for (deUint32 i = 0; i < pipelineCount; ++i)
{
// Pipeline identifier at index 0 uses wrong ID for PITT_NONEXISTING_ID test
// or a proper one for PITT_MATCHCONTROL test
applyPipelineIdentifier(pipelineIDs[i], destPID[i]);
pipelineIDs[i].pNext = computePipelineCreateInfos[i].pNext;
computePipelineCreateInfos[i].pNext = &pipelineIDs[i];
expectedNullHandle[i] = 0;
}
break;
default:
TCU_THROW(InternalError, "Unrecognized match control");
}
VkResult result = createComputePipelinesFunc(device, pipelineCache, pipelineCount, computePipelineCreateInfos.data(), DE_NULL, pipelines.data());
bool isOK = true;
for (deUint32 i = 0; i < pipelineCount; ++i)
{
if (expectedNullHandle[i] == 0 && pipelines[i] == DE_NULL)
{
context.getTestContext().getLog() << tcu::TestLog::Message << "Pipeline "<< i << " should be created" << tcu::TestLog::EndMessage;
isOK = false;
}
if (expectedNullHandle[i] != 0 && pipelines[i] != DE_NULL)
{
context.getTestContext().getLog() << tcu::TestLog::Message << "Pipeline " << i << " should not be created" << tcu::TestLog::EndMessage;
isOK = false;
}
}
if (result != expectedResult)
{
context.getTestContext().getLog() << tcu::TestLog::Message << "vkCreateComputePipelines returned wrong VkResult" << tcu::TestLog::EndMessage;
isOK = false;
}
for (deUint32 i = 0; i < pipelineCount; ++i)
destroyPipelineFunc(device, pipelines[i], DE_NULL);
return isOK ? tcu::TestStatus::pass("Pass") : tcu::TestStatus::fail("Fail");
}
} // anonymous
tcu::TestCaseGroup* createPipelineIdentifierTests (tcu::TestContext& testCtx)
{
de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "pipeline_identifier", "Tests verifying Vulkan SC pipeline identifier structure"));
const struct
{
PIPipeline pipeline;
const char* name;
FunctionPrograms1<TestParams>::Function initPrograms;
FunctionInstance1<TestParams>::Function testFunction;
} pipelineTypes[] =
{
{ PIP_GRAPHICS, "graphics", createGraphicsShaders, testGraphicsPipelineIdentifier },
{ PIP_COMPUTE, "compute", createComputeShaders, testComputePipelineIdentifier },
};
const struct
{
PITTestType type;
const char* name;
} testTypes[] =
{
{ PITT_MISSING_ID, "missing_pid" },
{ PITT_NONEXISTING_ID, "nonexisting_pid" },
{ PITT_MATCHCONTROL, "match_control" },
};
const struct
{
PITMatchControl control;
const char* name;
} matchControls[] =
{
{ PIMC_UUID_EXACT_MATCH, "exact_match" },
};
const struct
{
bool single;
const char* name;
} cardinalities[] =
{
{ true, "single" },
{ false, "multiple" },
};
for (int pipelineIdx = 0; pipelineIdx < DE_LENGTH_OF_ARRAY(pipelineTypes); ++pipelineIdx)
{
de::MovePtr<tcu::TestCaseGroup> pipelineGroup(new tcu::TestCaseGroup(testCtx, pipelineTypes[pipelineIdx].name, ""));
for (int typeIdx = 0; typeIdx < DE_LENGTH_OF_ARRAY(testTypes); ++typeIdx)
{
de::MovePtr<tcu::TestCaseGroup> typeGroup(new tcu::TestCaseGroup(testCtx, testTypes[typeIdx].name, ""));
for (int matchIdx = 0; matchIdx < DE_LENGTH_OF_ARRAY(matchControls); ++matchIdx)
{
de::MovePtr<tcu::TestCaseGroup> matchGroup(new tcu::TestCaseGroup(testCtx, matchControls[matchIdx].name, ""));
for (int cardIdx = 0; cardIdx < DE_LENGTH_OF_ARRAY(cardinalities); ++cardIdx)
{
TestParams testParams{ testTypes[typeIdx].type, matchControls[matchIdx].control, cardinalities[cardIdx].single };
addFunctionCaseWithPrograms(matchGroup.get(), cardinalities[cardIdx].name, "", pipelineTypes[pipelineIdx].initPrograms, pipelineTypes[pipelineIdx].testFunction, testParams);
}
typeGroup->addChild(matchGroup.release());
}
pipelineGroup->addChild(typeGroup.release());
}
group->addChild(pipelineGroup.release());
}
return group.release();
}
} // sc
} // vkt