/*------------------------------------------------------------------------ * Vulkan Conformance Tests * ------------------------ * * Copyright (c) 2019 The Khronos Group Inc. * Copyright (c) 2019 Valve Corporation. * * 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 Max Varying Tests *//*--------------------------------------------------------------------*/ #include "vktPipelineMaxVaryingsTests.hpp" #include "vktTestGroupUtil.hpp" #include "vktTestCaseUtil.hpp" #include "vkTypeUtil.hpp" #include "vkImageUtil.hpp" #include "vkObjUtil.hpp" #include "vktPipelineMakeUtil.hpp" #include "vkBuilderUtil.hpp" #include "vkCmdUtil.hpp" #include "vkRefUtil.hpp" #include "vkMemUtil.hpp" #include "vkBarrierUtil.hpp" #include "vktPipelineSpecConstantUtil.hpp" #include "vkImageWithMemory.hpp" #include "tcuImageCompare.hpp" #include "tcuTestLog.hpp" #include "tcuTextureUtil.hpp" #include namespace vkt { namespace pipeline { namespace { using namespace vk; using de::UniquePtr; using de::MovePtr; struct MaxVaryingsParam { PipelineConstructionType pipelineConstructionType; VkShaderStageFlags outputStage; VkShaderStageFlags inputStage; VkShaderStageFlags stageToStressIO; }; // Helper functions std::string getShaderStageName(VkShaderStageFlags stage) { switch (stage) { default: DE_FATAL("Unhandled stage!"); return ""; case VK_SHADER_STAGE_COMPUTE_BIT: return "compute"; case VK_SHADER_STAGE_FRAGMENT_BIT: return "fragment"; case VK_SHADER_STAGE_VERTEX_BIT: return "vertex"; case VK_SHADER_STAGE_GEOMETRY_BIT: return "geometry"; case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: return "tess_control"; case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: return "tess_eval"; } } const std::string generateTestName (struct MaxVaryingsParam param) { std::ostringstream result; result << "test_" << getShaderStageName(param.stageToStressIO) << "_io_between_"; result << getShaderStageName(param.outputStage) << "_"; result << getShaderStageName(param.inputStage); return result.str(); } const std::string generateTestDescription () { std::string result("Tests to check max varyings per stage"); return result; } void initPrograms (SourceCollections& programCollection, MaxVaryingsParam param) { const vk::ShaderBuildOptions buildOptions (programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_3, 0u); // Vertex shader. SPIR-V generated from: // #version 450 // layout(location = 0) in highp vec4 pos; // layout(constant_id = 0) const int arraySize = 1; // layout(location = 0) out ivec4 outputData[arraySize]; // out gl_PerVertex { // vec4 gl_Position; // }; // // void main() // { // gl_Position = pos; // int i; // for (i = 0; i < arraySize; i++) // { // outputData[i] = ivec4(i); // } // } std::ostringstream vertex_out; vertex_out << "OpCapability Shader\n" << "%1 = OpExtInstImport \"GLSL.std.450\"\n" << "OpMemoryModel Logical GLSL450\n" << "OpEntryPoint Vertex %4 \"main\" %10 %14 %32\n" << "OpMemberDecorate %8 0 BuiltIn Position\n" << "OpDecorate %8 Block\n" << "OpDecorate %14 Location 0\n" << "OpDecorate %26 SpecId 0\n" << "OpDecorate %32 Location 0\n" << "%2 = OpTypeVoid\n" << "%3 = OpTypeFunction %2\n" << "%6 = OpTypeFloat 32\n" << "%7 = OpTypeVector %6 4\n" << "%8 = OpTypeStruct %7\n" << "%9 = OpTypePointer Output %8\n" << "%10 = OpVariable %9 Output\n" << "%11 = OpTypeInt 32 1\n" << "%12 = OpConstant %11 0\n" << "%13 = OpTypePointer Input %7\n" << "%14 = OpVariable %13 Input\n" << "%16 = OpTypePointer Output %7\n" << "%18 = OpTypePointer Function %11\n" << "%26 = OpSpecConstant %11 1\n" << "%27 = OpTypeBool\n" << "%29 = OpTypeVector %11 4\n" << "%30 = OpTypeArray %29 %26\n" << "%31 = OpTypePointer Output %30\n" << "%32 = OpVariable %31 Output\n" << "%36 = OpTypePointer Output %29\n" << "%39 = OpConstant %11 1\n" << "%4 = OpFunction %2 None %3\n" << "%5 = OpLabel\n" << "%19 = OpVariable %18 Function\n" << "%15 = OpLoad %7 %14\n" << "%17 = OpAccessChain %16 %10 %12\n" << "OpStore %17 %15\n" << "OpStore %19 %12\n" << "OpBranch %20\n" << "%20 = OpLabel\n" << "OpLoopMerge %22 %23 None\n" << "OpBranch %24\n" << "%24 = OpLabel\n" << "%25 = OpLoad %11 %19\n" << "%28 = OpSLessThan %27 %25 %26\n" << "OpBranchConditional %28 %21 %22\n" << "%21 = OpLabel\n" << "%33 = OpLoad %11 %19\n" << "%34 = OpLoad %11 %19\n" << "%35 = OpCompositeConstruct %29 %34 %34 %34 %34\n" << "%37 = OpAccessChain %36 %32 %33\n" << "OpStore %37 %35\n" << "OpBranch %23\n" << "%23 = OpLabel\n" << "%38 = OpLoad %11 %19\n" << "%40 = OpIAdd %11 %38 %39\n" << "OpStore %19 %40\n" << "OpBranch %20\n" << "%22 = OpLabel\n" << "OpReturn\n" << "OpFunctionEnd\n"; // Vertex shader passthrough. SPIR-V generated from: // #version 450 // layout(location = 0) in highp vec4 pos; // out gl_PerVertex { // vec4 gl_Position; // }; // void main() // { // gl_Position = pos; // } std::ostringstream vertex_passthrough; vertex_passthrough << "OpCapability Shader\n" << "%1 = OpExtInstImport \"GLSL.std.450\"\n" << "OpMemoryModel Logical GLSL450\n" << "OpEntryPoint Vertex %4 \"main\" %10 %14\n" << "OpMemberDecorate %8 0 BuiltIn Position\n" << "OpDecorate %8 Block\n" << "OpDecorate %14 Location 0\n" << "%2 = OpTypeVoid\n" << "%3 = OpTypeFunction %2\n" << "%6 = OpTypeFloat 32\n" << "%7 = OpTypeVector %6 4\n" << "%8 = OpTypeStruct %7\n" << "%9 = OpTypePointer Output %8\n" << "%10 = OpVariable %9 Output\n" << "%11 = OpTypeInt 32 1\n" << "%12 = OpConstant %11 0\n" << "%13 = OpTypePointer Input %7\n" << "%14 = OpVariable %13 Input\n" << "%16 = OpTypePointer Output %7\n" << "%4 = OpFunction %2 None %3\n" << "%5 = OpLabel\n" << "%15 = OpLoad %7 %14\n" << "%17 = OpAccessChain %16 %10 %12\n" << "OpStore %17 %15\n" << "OpReturn\n" << "OpFunctionEnd\n"; // Tesselation Control shader. SPIR-V generated from: // #version 450 // layout(vertices = 3) out; // in gl_PerVertex // { // vec4 gl_Position; // } gl_in[]; // out gl_PerVertex // { // vec4 gl_Position; // } gl_out[]; // void main(void) // { // if (gl_InvocationID == 0) { // gl_TessLevelInner[0] = 1.0; // gl_TessLevelInner[1] = 1.0; // gl_TessLevelOuter[0] = 1.0; // gl_TessLevelOuter[1] = 1.0; // gl_TessLevelOuter[2] = 1.0; // gl_TessLevelOuter[3] = 1.0; // } // gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position; // } std::ostringstream tcs_passthrough; tcs_passthrough << "OpCapability Tessellation\n" << "%1 = OpExtInstImport \"GLSL.std.450\"\n" << "OpMemoryModel Logical GLSL450\n" << "OpEntryPoint TessellationControl %4 \"main\" %8 %20 %29 %41 %47\n" << "OpExecutionMode %4 OutputVertices 3\n" << "OpDecorate %8 BuiltIn InvocationId\n" << "OpDecorate %20 Patch\n" << "OpDecorate %20 BuiltIn TessLevelInner\n" << "OpDecorate %29 Patch\n" << "OpDecorate %29 BuiltIn TessLevelOuter\n" << "OpMemberDecorate %37 0 BuiltIn Position\n" << "OpDecorate %37 Block\n" << "OpMemberDecorate %43 0 BuiltIn Position\n" << "OpDecorate %43 Block\n" << "%2 = OpTypeVoid\n" << "%3 = OpTypeFunction %2\n" << "%6 = OpTypeInt 32 1\n" << "%7 = OpTypePointer Input %6\n" << "%8 = OpVariable %7 Input\n" << "%10 = OpConstant %6 0\n" << "%11 = OpTypeBool\n" << "%15 = OpTypeFloat 32\n" << "%16 = OpTypeInt 32 0\n" << "%17 = OpConstant %16 2\n" << "%18 = OpTypeArray %15 %17\n" << "%19 = OpTypePointer Output %18\n" << "%20 = OpVariable %19 Output\n" << "%21 = OpConstant %15 1\n" << "%22 = OpTypePointer Output %15\n" << "%24 = OpConstant %6 1\n" << "%26 = OpConstant %16 4\n" << "%27 = OpTypeArray %15 %26\n" << "%28 = OpTypePointer Output %27\n" << "%29 = OpVariable %28 Output\n" << "%32 = OpConstant %6 2\n" << "%34 = OpConstant %6 3\n" << "%36 = OpTypeVector %15 4\n" << "%37 = OpTypeStruct %36\n" << "%38 = OpConstant %16 3\n" << "%39 = OpTypeArray %37 %38\n" << "%40 = OpTypePointer Output %39\n" << "%41 = OpVariable %40 Output\n" << "%43 = OpTypeStruct %36\n" << "%44 = OpConstant %16 32\n" << "%45 = OpTypeArray %43 %44\n" << "%46 = OpTypePointer Input %45\n" << "%47 = OpVariable %46 Input\n" << "%49 = OpTypePointer Input %36\n" << "%52 = OpTypePointer Output %36\n" << "%4 = OpFunction %2 None %3\n" << "%5 = OpLabel\n" << "%9 = OpLoad %6 %8\n" << "%12 = OpIEqual %11 %9 %10\n" << "OpSelectionMerge %14 None\n" << "OpBranchConditional %12 %13 %14\n" << "%13 = OpLabel\n" << "%23 = OpAccessChain %22 %20 %10\n" << "OpStore %23 %21\n" << "%25 = OpAccessChain %22 %20 %24\n" << "OpStore %25 %21\n" << "%30 = OpAccessChain %22 %29 %10\n" << "OpStore %30 %21\n" << "%31 = OpAccessChain %22 %29 %24\n" << "OpStore %31 %21\n" << "%33 = OpAccessChain %22 %29 %32\n" << "OpStore %33 %21\n" << "%35 = OpAccessChain %22 %29 %34\n" << "OpStore %35 %21\n" << "OpBranch %14\n" << "%14 = OpLabel\n" << "%42 = OpLoad %6 %8\n" << "%48 = OpLoad %6 %8\n" << "%50 = OpAccessChain %49 %47 %48 %10\n" << "%51 = OpLoad %36 %50\n" << "%53 = OpAccessChain %52 %41 %42 %10\n" << "OpStore %53 %51\n" << "OpReturn\n" << "OpFunctionEnd\n"; // Tessellation Evaluation shader. SPIR-V generated from: // #version 450 // layout(triangles, equal_spacing, cw) in; // layout(constant_id = 0) const int arraySize = 1; // layout(location = 0) out ivec4 outputData[arraySize]; // in gl_PerVertex { // vec4 gl_Position; // } gl_in[]; // out gl_PerVertex { // vec4 gl_Position; // }; // void main(void) // { // gl_Position = (gl_TessCoord.x * gl_in[0].gl_Position + // gl_TessCoord.y * gl_in[1].gl_Position + // gl_TessCoord.z * gl_in[2].gl_Position); // int j; // for (j = 0; j < arraySize; j++) // { // outputData[j] = ivec4(j); // } // } std::ostringstream tes_out; tes_out << "OpCapability Tessellation\n" << "%1 = OpExtInstImport \"GLSL.std.450\"\n" << "OpMemoryModel Logical GLSL450\n" << "OpEntryPoint TessellationEvaluation %4 \"main\" %10 %15 %25 %62\n" << "OpExecutionMode %4 Triangles\n" << "OpExecutionMode %4 SpacingEqual\n" << "OpExecutionMode %4 VertexOrderCw\n" << "OpMemberDecorate %8 0 BuiltIn Position\n" << "OpDecorate %8 Block\n" << "OpDecorate %15 BuiltIn TessCoord\n" << "OpMemberDecorate %21 0 BuiltIn Position\n" << "OpDecorate %21 Block\n" << "OpDecorate %56 SpecId 0\n" << "OpDecorate %62 Location 0\n" << "%2 = OpTypeVoid\n" << "%3 = OpTypeFunction %2\n" << "%6 = OpTypeFloat 32\n" << "%7 = OpTypeVector %6 4\n" << "%8 = OpTypeStruct %7\n" << "%9 = OpTypePointer Output %8\n" << "%10 = OpVariable %9 Output\n" << "%11 = OpTypeInt 32 1\n" << "%12 = OpConstant %11 0\n" << "%13 = OpTypeVector %6 3\n" << "%14 = OpTypePointer Input %13\n" << "%15 = OpVariable %14 Input\n" << "%16 = OpTypeInt 32 0\n" << "%17 = OpConstant %16 0\n" << "%18 = OpTypePointer Input %6\n" << "%21 = OpTypeStruct %7\n" << "%22 = OpConstant %16 32\n" << "%23 = OpTypeArray %21 %22\n" << "%24 = OpTypePointer Input %23\n" << "%25 = OpVariable %24 Input\n" << "%26 = OpTypePointer Input %7\n" << "%30 = OpConstant %16 1\n" << "%33 = OpConstant %11 1\n" << "%38 = OpConstant %16 2\n" << "%41 = OpConstant %11 2\n" << "%46 = OpTypePointer Output %7\n" << "%48 = OpTypePointer Function %11\n" << "%56 = OpSpecConstant %11 1\n" << "%57 = OpTypeBool\n" << "%59 = OpTypeVector %11 4\n" << "%60 = OpTypeArray %59 %56\n" << "%61 = OpTypePointer Output %60\n" << "%62 = OpVariable %61 Output\n" << "%66 = OpTypePointer Output %59\n" << "%4 = OpFunction %2 None %3\n" << "%5 = OpLabel\n" << "%49 = OpVariable %48 Function\n" << "%19 = OpAccessChain %18 %15 %17\n" << "%20 = OpLoad %6 %19\n" << "%27 = OpAccessChain %26 %25 %12 %12\n" << "%28 = OpLoad %7 %27\n" << "%29 = OpVectorTimesScalar %7 %28 %20\n" << "%31 = OpAccessChain %18 %15 %30\n" << "%32 = OpLoad %6 %31\n" << "%34 = OpAccessChain %26 %25 %33 %12\n" << "%35 = OpLoad %7 %34\n" << "%36 = OpVectorTimesScalar %7 %35 %32\n" << "%37 = OpFAdd %7 %29 %36\n" << "%39 = OpAccessChain %18 %15 %38\n" << "%40 = OpLoad %6 %39\n" << "%42 = OpAccessChain %26 %25 %41 %12\n" << "%43 = OpLoad %7 %42\n" << "%44 = OpVectorTimesScalar %7 %43 %40\n" << "%45 = OpFAdd %7 %37 %44\n" << "%47 = OpAccessChain %46 %10 %12\n" << "OpStore %47 %45\n" << "OpStore %49 %12\n" << "OpBranch %50\n" << "%50 = OpLabel\n" << "OpLoopMerge %52 %53 None\n" << "OpBranch %54\n" << "%54 = OpLabel\n" << "%55 = OpLoad %11 %49\n" << "%58 = OpSLessThan %57 %55 %56\n" << "OpBranchConditional %58 %51 %52\n" << "%51 = OpLabel\n" << "%63 = OpLoad %11 %49\n" << "%64 = OpLoad %11 %49\n" << "%65 = OpCompositeConstruct %59 %64 %64 %64 %64\n" << "%67 = OpAccessChain %66 %62 %63\n" << "OpStore %67 %65\n" << "OpBranch %53\n" << "%53 = OpLabel\n" << "%68 = OpLoad %11 %49\n" << "%69 = OpIAdd %11 %68 %33\n" << "OpStore %49 %69\n" << "OpBranch %50\n" << "%52 = OpLabel\n" << "OpReturn\n" << "OpFunctionEnd\n"; // Geometry shader. SPIR-V generated from: // #version 450 // layout (triangles) in; // layout (triangle_strip, max_vertices = 3) out; // layout(constant_id = 0) const int arraySize = 1; // layout(location = 0) out ivec4 outputData[arraySize]; // in gl_PerVertex { // vec4 gl_Position; // } gl_in[]; // void main() // { // int i; // int j; // for(i = 0; i < gl_in.length(); i++) // { // gl_Position = gl_in[i].gl_Position; // for (j = 0; j < arraySize; j++) // { // outputData[j] = ivec4(j); // } // EmitVertex(); // } // EndPrimitive(); // } std::ostringstream geom_out; geom_out << "OpCapability Geometry\n" << "%1 = OpExtInstImport \"GLSL.std.450\"\n" << "OpMemoryModel Logical GLSL450\n" << "OpEntryPoint Geometry %4 \"main\" %26 %31 %50\n" << "OpExecutionMode %4 Triangles\n" << "OpExecutionMode %4 Invocations 1\n" << "OpExecutionMode %4 OutputTriangleStrip\n" << "OpExecutionMode %4 OutputVertices 3\n" << "OpMemberDecorate %24 0 BuiltIn Position\n" << "OpDecorate %24 Block\n" << "OpMemberDecorate %27 0 BuiltIn Position\n" << "OpDecorate %27 Block\n" << "OpDecorate %45 SpecId 0\n" << "OpDecorate %50 Location 0\n" << "%2 = OpTypeVoid\n" << "%3 = OpTypeFunction %2\n" << "%6 = OpTypeInt 32 1\n" << "%7 = OpTypePointer Function %6\n" << "%9 = OpConstant %6 0\n" << "%16 = OpConstant %6 3\n" << "%17 = OpTypeBool\n" << "%19 = OpTypeFloat 32\n" << "%20 = OpTypeVector %19 4\n" << "%21 = OpTypeInt 32 0\n" << "%22 = OpConstant %21 1\n" << "%23 = OpTypeArray %19 %22\n" << "%24 = OpTypeStruct %20\n" << "%25 = OpTypePointer Output %24\n" << "%26 = OpVariable %25 Output\n" << "%27 = OpTypeStruct %20\n" << "%28 = OpConstant %21 3\n" << "%29 = OpTypeArray %27 %28\n" << "%30 = OpTypePointer Input %29\n" << "%31 = OpVariable %30 Input\n" << "%33 = OpTypePointer Input %20\n" << "%36 = OpTypePointer Output %20\n" << "%45 = OpSpecConstant %6 1\n" << "%47 = OpTypeVector %6 4\n" << "%48 = OpTypeArray %47 %45\n" << "%49 = OpTypePointer Output %48\n" << "%50 = OpVariable %49 Output\n" << "%54 = OpTypePointer Output %47\n" << "%57 = OpConstant %6 1\n" << "%4 = OpFunction %2 None %3\n" << "%5 = OpLabel\n" << "%8 = OpVariable %7 Function\n" << "%38 = OpVariable %7 Function\n" << "OpStore %8 %9\n" << "OpBranch %10\n" << "%10 = OpLabel\n" << "OpLoopMerge %12 %13 None\n" << "OpBranch %14\n" << "%14 = OpLabel\n" << "%15 = OpLoad %6 %8\n" << "%18 = OpSLessThan %17 %15 %16\n" << "OpBranchConditional %18 %11 %12\n" << "%11 = OpLabel\n" << "%32 = OpLoad %6 %8\n" << "%34 = OpAccessChain %33 %31 %32 %9\n" << "%35 = OpLoad %20 %34\n" << "%37 = OpAccessChain %36 %26 %9\n" << "OpStore %37 %35\n" << "OpStore %38 %9\n" << "OpBranch %39\n" << "%39 = OpLabel\n" << "OpLoopMerge %41 %42 None\n" << "OpBranch %43\n" << "%43 = OpLabel\n" << "%44 = OpLoad %6 %38\n" << "%46 = OpSLessThan %17 %44 %45\n" << "OpBranchConditional %46 %40 %41\n" << "%40 = OpLabel\n" << "%51 = OpLoad %6 %38\n" << "%52 = OpLoad %6 %38\n" << "%53 = OpCompositeConstruct %47 %52 %52 %52 %52\n" << "%55 = OpAccessChain %54 %50 %51\n" << "OpStore %55 %53\n" << "OpBranch %42\n" << "%42 = OpLabel\n" << "%56 = OpLoad %6 %38\n" << "%58 = OpIAdd %6 %56 %57\n" << "OpStore %38 %58\n" << "OpBranch %39\n" << "%41 = OpLabel\n" << "OpEmitVertex\n" << "OpBranch %13\n" << "%13 = OpLabel\n" << "%59 = OpLoad %6 %8\n" << "%60 = OpIAdd %6 %59 %57\n" << "OpStore %8 %60\n" << "OpBranch %10\n" << "%12 = OpLabel\n" << "OpEndPrimitive\n" << "OpReturn\n" << "OpFunctionEnd\n"; // Fragment shader. SPIR-V code generated from: // // #version 450 // layout(constant_id = 0) const int arraySize = 1; // layout(location = 0) flat in ivec4 inputData[arraySize]; // layout(location = 0) out vec4 color; // void main() // { // color = vec4(1.0, 0.0, 0.0, 1.0); // int i; // bool result = true; // for (i = 0; i < arraySize; i++) // { // if (result && inputData[i] != ivec4(i)) // result = false; // } // if (result) // color = vec4(0.0, 1.0, 0.0, 1.0); // } std::ostringstream fragment_in; fragment_in << "OpCapability Shader\n" << "%1 = OpExtInstImport \"GLSL.std.450\"\n" << "OpMemoryModel Logical GLSL450\n" << "OpEntryPoint Fragment %4 \"main\" %9 %35\n" << "OpExecutionMode %4 OriginUpperLeft\n" << "OpDecorate %9 Location 0\n" << "OpDecorate %27 SpecId 0\n" << "OpDecorate %35 Flat\n" << "OpDecorate %35 Location 0\n" << "%2 = OpTypeVoid\n" << "%3 = OpTypeFunction %2\n" << "%6 = OpTypeFloat 32\n" << "%7 = OpTypeVector %6 4\n" << "%8 = OpTypePointer Output %7\n" << "%9 = OpVariable %8 Output\n" << "%10 = OpConstant %6 1\n" << "%11 = OpConstant %6 0\n" << "%12 = OpConstantComposite %7 %10 %11 %11 %10\n" << "%13 = OpTypeBool\n" << "%14 = OpTypePointer Function %13\n" << "%16 = OpConstantTrue %13\n" << "%17 = OpTypeInt 32 1\n" << "%18 = OpTypePointer Function %17\n" << "%20 = OpConstant %17 0\n" << "%27 = OpSpecConstant %17 1\n" << "%32 = OpTypeVector %17 4\n" << "%33 = OpTypeArray %32 %27\n" << "%34 = OpTypePointer Input %33\n" << "%35 = OpVariable %34 Input\n" << "%37 = OpTypePointer Input %32\n" << "%42 = OpTypeVector %13 4\n" << "%48 = OpConstantFalse %13\n" << "%50 = OpConstant %17 1\n" << "%55 = OpConstantComposite %7 %11 %10 %11 %10\n" << "%4 = OpFunction %2 None %3\n" << "%5 = OpLabel\n" << "%15 = OpVariable %14 Function\n" << "%19 = OpVariable %18 Function\n" << "OpStore %9 %12\n" << "OpStore %15 %16\n" << "OpStore %19 %20\n" << "OpBranch %21\n" << "%21 = OpLabel\n" << "OpLoopMerge %23 %24 None\n" << "OpBranch %25\n" << "%25 = OpLabel\n" << "%26 = OpLoad %17 %19\n" << "%28 = OpSLessThan %13 %26 %27\n" << "OpBranchConditional %28 %22 %23\n" << "%22 = OpLabel\n" << "%29 = OpLoad %13 %15\n" << "OpSelectionMerge %31 None\n" << "OpBranchConditional %29 %30 %31\n" << "%30 = OpLabel\n" << "%36 = OpLoad %17 %19\n" << "%38 = OpAccessChain %37 %35 %36\n" << "%39 = OpLoad %32 %38\n" << "%40 = OpLoad %17 %19\n" << "%41 = OpCompositeConstruct %32 %40 %40 %40 %40\n" << "%43 = OpINotEqual %42 %39 %41\n" << "%44 = OpAny %13 %43\n" << "OpBranch %31\n" << "%31 = OpLabel\n" << "%45 = OpPhi %13 %29 %22 %44 %30\n" << "OpSelectionMerge %47 None\n" << "OpBranchConditional %45 %46 %47\n" << "%46 = OpLabel\n" << "OpStore %15 %48\n" << "OpBranch %47\n" << "%47 = OpLabel\n" << "OpBranch %24\n" << "%24 = OpLabel\n" << "%49 = OpLoad %17 %19\n" << "%51 = OpIAdd %17 %49 %50\n" << "OpStore %19 %51\n" << "OpBranch %21\n" << "%23 = OpLabel\n" << "%52 = OpLoad %13 %15\n" << "OpSelectionMerge %54 None\n" << "OpBranchConditional %52 %53 %54\n" << "%53 = OpLabel\n" << "OpStore %9 %55\n" << "OpBranch %54\n" << "%54 = OpLabel\n" << "OpReturn\n" << "OpFunctionEnd\n"; if (param.outputStage == VK_SHADER_STAGE_VERTEX_BIT) { programCollection.spirvAsmSources.add("vert") << vertex_out.str().c_str(); if (param.inputStage == VK_SHADER_STAGE_FRAGMENT_BIT) { programCollection.spirvAsmSources.add("frag") << fragment_in.str().c_str(); return; } } programCollection.spirvAsmSources.add("vert") << vertex_passthrough.str().c_str(); if (param.outputStage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) { programCollection.spirvAsmSources.add("tcs") << tcs_passthrough.str().c_str(); programCollection.spirvAsmSources.add("tes") << tes_out.str().c_str(); if (param.inputStage == VK_SHADER_STAGE_FRAGMENT_BIT) { programCollection.spirvAsmSources.add("frag") << fragment_in.str().c_str(); return; } } if (param.outputStage == VK_SHADER_STAGE_GEOMETRY_BIT) { programCollection.spirvAsmSources.add("geom") << geom_out.str().c_str(); programCollection.spirvAsmSources.add("frag") << fragment_in.str().c_str(); return; } DE_FATAL("Unsupported combination"); } void supportedCheck (Context& context, MaxVaryingsParam param) { const vk::InstanceInterface& vki = context.getInstanceInterface(); VkPhysicalDeviceFeatures features; vki.getPhysicalDeviceFeatures(context.getPhysicalDevice(), &features); // Check support for the tessellation and geometry shaders on the device if ((param.inputStage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT || param.inputStage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT || param.outputStage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT || param.outputStage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) && !features.tessellationShader) { TCU_THROW(NotSupportedError, "Device does not support tessellation shaders"); } if ((param.inputStage == VK_SHADER_STAGE_GEOMETRY_BIT || param.outputStage == VK_SHADER_STAGE_GEOMETRY_BIT) && !features.geometryShader) { TCU_THROW(NotSupportedError, "Device does not support geometry shaders"); } // Check data sizes, throw unsupported if the case cannot be tested. VkPhysicalDeviceProperties properties; vki.getPhysicalDeviceProperties(context.getPhysicalDevice(), &properties); std::ostringstream error; if (param.stageToStressIO == VK_SHADER_STAGE_VERTEX_BIT) { DE_ASSERT(param.outputStage == VK_SHADER_STAGE_VERTEX_BIT); if (param.inputStage == VK_SHADER_STAGE_FRAGMENT_BIT && properties.limits.maxFragmentInputComponents < (properties.limits.maxVertexOutputComponents - 4)) { error << "Device supports smaller number of FS inputs (" << properties.limits.maxFragmentInputComponents << ") than VS outputs (" << properties.limits.maxVertexOutputComponents << " - 4 built-ins)"; TCU_THROW(NotSupportedError, error.str().c_str()); } } if (param.stageToStressIO == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) { if (param.inputStage == VK_SHADER_STAGE_FRAGMENT_BIT && properties.limits.maxFragmentInputComponents < (properties.limits.maxTessellationEvaluationOutputComponents - 4)) { error << "Device supports smaller number of FS inputs (" << properties.limits.maxFragmentInputComponents << ") than TES outputs (" << properties.limits.maxTessellationEvaluationOutputComponents << " - 4 builtins)"; TCU_THROW(NotSupportedError, error.str().c_str()); } } if (param.stageToStressIO == VK_SHADER_STAGE_GEOMETRY_BIT) { if (param.inputStage == VK_SHADER_STAGE_FRAGMENT_BIT && properties.limits.maxFragmentInputComponents < (properties.limits.maxGeometryOutputComponents - 4)) { error << "Device supports smaller number of FS inputs (" << properties.limits.maxFragmentInputComponents << ") than GS outputs (" << properties.limits.maxGeometryOutputComponents << " - 4 built-ins)"; TCU_THROW(NotSupportedError, error.str().c_str()); } } if (param.stageToStressIO == VK_SHADER_STAGE_FRAGMENT_BIT) { DE_ASSERT(param.inputStage == VK_SHADER_STAGE_FRAGMENT_BIT); if (param.outputStage == VK_SHADER_STAGE_VERTEX_BIT && (properties.limits.maxVertexOutputComponents - 4) < properties.limits.maxFragmentInputComponents) { error << "Device supports smaller number of VS outputs (" << properties.limits.maxVertexOutputComponents << " - 4 built-ins) than FS inputs (" << properties.limits.maxFragmentInputComponents << ")"; TCU_THROW(NotSupportedError, error.str().c_str()); } if (param.outputStage == VK_SHADER_STAGE_GEOMETRY_BIT && (properties.limits.maxGeometryOutputComponents - 4) < properties.limits.maxFragmentInputComponents) { error << "Device supports smaller number of GS outputs (" << properties.limits.maxGeometryOutputComponents << " - 4 built-ins) than FS inputs (" << properties.limits.maxFragmentInputComponents << ")"; TCU_THROW(NotSupportedError, error.str().c_str()); } if (param.outputStage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT && (properties.limits.maxTessellationEvaluationOutputComponents - 4) < properties.limits.maxFragmentInputComponents) { error << "Device supports smaller number of TES outputs (" << properties.limits.maxTessellationEvaluationOutputComponents << " - 4 built-ins) than FS inputs (" << properties.limits.maxFragmentInputComponents << ")"; TCU_THROW(NotSupportedError, error.str().c_str()); } } checkPipelineLibraryRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), param.pipelineConstructionType); } VkImageCreateInfo makeImageCreateInfo (const tcu::IVec2& size, const VkFormat format, const VkImageUsageFlags usage) { 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(size.x(), size.y(), 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; } Move makeBuffer (const DeviceInterface& vk, const VkDevice device, const VkDeviceSize bufferSize, const VkBufferUsageFlags usage) { const VkBufferCreateInfo bufferCreateInfo = makeBufferCreateInfo(bufferSize, usage); return createBuffer(vk, device, &bufferCreateInfo); } void recordImageBarrier (const DeviceInterface& vk, const VkCommandBuffer cmdBuffer, const VkImage image, const VkImageAspectFlags aspect, const VkPipelineStageFlags srcStageMask, const VkPipelineStageFlags dstStageMask, const VkAccessFlags srcAccessMask, const VkAccessFlags dstAccessMask, const VkImageLayout oldLayout, const VkImageLayout newLayout, const VkSampleLocationsInfoEXT* pSampleLocationsInfo = DE_NULL) { const VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType; pSampleLocationsInfo, // const void* pNext; srcAccessMask, // VkAccessFlags srcAccessMask; dstAccessMask, // VkAccessFlags dstAccessMask; oldLayout, // VkImageLayout oldLayout; newLayout, // VkImageLayout newLayout; VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex; VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex; image, // VkImage image; makeImageSubresourceRange(aspect, 0u, 1u, 0u, 1u), // VkImageSubresourceRange subresourceRange; }; vk.cmdPipelineBarrier(cmdBuffer, srcStageMask, dstStageMask, (VkDependencyFlags)0, 0u, DE_NULL, 0u, DE_NULL, 1u, &barrier); } void recordCopyImageToBuffer (const DeviceInterface& vk, const VkCommandBuffer cmdBuffer, const tcu::IVec2& imageSize, const VkImage srcImage, const VkBuffer dstBuffer) { // Resolve image -> host buffer { const VkBufferImageCopy region = { 0ull, // VkDeviceSize bufferOffset; 0u, // uint32_t bufferRowLength; 0u, // uint32_t bufferImageHeight; makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u), // VkImageSubresourceLayers imageSubresource; makeOffset3D(0, 0, 0), // VkOffset3D imageOffset; makeExtent3D(imageSize.x(), imageSize.y(), 1u), // VkExtent3D imageExtent; }; vk.cmdCopyImageToBuffer(cmdBuffer, srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dstBuffer, 1u, ®ion); } // Buffer write barrier { const VkBufferMemoryBarrier barrier = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType; DE_NULL, // const void* pNext; VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask; VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask; VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex; VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex; dstBuffer, // VkBuffer buffer; 0ull, // VkDeviceSize offset; VK_WHOLE_SIZE, // VkDeviceSize size; }; vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0, 0u, DE_NULL, 1u, &barrier, DE_NULL, 0u); } } 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(); 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); *pAlloc = context.getDefaultAllocator().allocate(getBufferMemoryRequirements(vk, vkDevice, *vertexBuffer), MemoryRequirement::HostVisible); VK_CHECK(vk.bindBufferMemory(vkDevice, *vertexBuffer, (*pAlloc)->getMemory(), (*pAlloc)->getOffset())); return vertexBuffer; } deInt32 getMaxIOComponents(deBool input, VkShaderStageFlags stage, VkPhysicalDeviceProperties properties) { deInt32 data = 0u; switch (stage) { case VK_SHADER_STAGE_VERTEX_BIT: DE_ASSERT(!input); data = (properties.limits.maxVertexOutputComponents / 4) - 1; // outputData + gl_Position break; case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: if (input) data = properties.limits.maxTessellationEvaluationInputComponents / 4; else data = (properties.limits.maxTessellationEvaluationOutputComponents / 4) - 1; // outputData + gl_Position break; case VK_SHADER_STAGE_GEOMETRY_BIT: if (input) data = properties.limits.maxGeometryInputComponents / 4; else data = (properties.limits.maxGeometryOutputComponents / 4) - 1; // outputData + gl_Position break; case VK_SHADER_STAGE_FRAGMENT_BIT: DE_ASSERT(input); data = (properties.limits.maxFragmentInputComponents / 4); // inputData break; default: DE_FATAL("Unsupported shader"); } return data; } tcu::TestStatus test(Context& context, const MaxVaryingsParam param) { const InstanceInterface& vki = context.getInstanceInterface(); const DeviceInterface& vk = context.getDeviceInterface(); const VkDevice device = context.getDevice(); const VkQueue queue = context.getUniversalQueue(); const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex(); Allocator& allocator = context.getDefaultAllocator(); tcu::TestLog &log = context.getTestContext().getLog(); // Color attachment const tcu::IVec2 renderSize = tcu::IVec2(32, 32); const VkFormat imageFormat = VK_FORMAT_R8G8B8A8_UNORM; const ImageWithMemory colorImage (vk, device, allocator, makeImageCreateInfo(renderSize, imageFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT), MemoryRequirement::Any); const Unique colorImageView (makeImageView(vk, device, *colorImage, VK_IMAGE_VIEW_TYPE_2D, imageFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u))); const VkDeviceSize colorBufferSize = renderSize.x() * renderSize.y() * tcu::getPixelSize(mapVkFormat(imageFormat)); Move colorBuffer = vkt::pipeline::makeBuffer(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT); MovePtr colorBufferAlloc = bindBuffer(vk, device, allocator, *colorBuffer, MemoryRequirement::HostVisible); // Create vertex buffer de::MovePtr vertexBufferMemory; Move vertexBuffer = createBufferAndBindMemory(context, sizeof(tcu::Vec4) * 6u, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, &vertexBufferMemory); std::vector vertices; { vertices.push_back(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f)); vertices.push_back(tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f)); vertices.push_back(tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f)); vertices.push_back(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f)); vertices.push_back(tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f)); vertices.push_back(tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f)); // Load vertices into vertex buffer deMemcpy(vertexBufferMemory->getHostPtr(), vertices.data(), vertices.size() * sizeof(tcu::Vec4)); flushAlloc(vk, device, *vertexBufferMemory); } // Specialization VkPhysicalDeviceProperties properties; vki.getPhysicalDeviceProperties(context.getPhysicalDevice(), &properties); VkPhysicalDeviceFeatures features; vki.getPhysicalDeviceFeatures(context.getPhysicalDevice(), &features); deInt32 data = 0u; size_t dataSize = sizeof(data); deInt32 maxOutput = getMaxIOComponents(false, param.outputStage, properties); deInt32 maxInput = getMaxIOComponents(true, param.inputStage, properties); data = deMin32(maxOutput, maxInput); DE_ASSERT(data != 0u); log << tcu::TestLog::Message << "Testing " << data * 4 << " input components for stage " << getShaderStageName(param.stageToStressIO).c_str() << tcu::TestLog::EndMessage; VkSpecializationMapEntry mapEntries = { 0u, // deUint32 constantID; 0u, // deUint32 offset; dataSize // size_t size; }; VkSpecializationInfo pSpecInfo = { 1u, // deUint32 mapEntryCount; &mapEntries, // const VkSpecializationMapEntry* pMapEntries; dataSize, // size_t dataSize; &data // const void* pData; }; // Pipeline const Unique renderPass (makeRenderPass (vk, device, imageFormat)); const Unique framebuffer (makeFramebuffer (vk, device, *renderPass, 1u, &colorImageView.get(), static_cast(renderSize.x()), static_cast(renderSize.y()))); const Unique pipelineLayout (makePipelineLayout(vk, device)); const Unique cmdPool (createCommandPool (vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex)); const Unique cmdBuffer (makeCommandBuffer (vk, device, *cmdPool)); vk::BinaryCollection& binaryCollection(context.getBinaryCollection()); VkPrimitiveTopology topology (VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST); const std::vector viewport { makeViewport(renderSize) }; const std::vector scissor { makeRect2D(renderSize) }; Move vertShaderModule = createShaderModule(vk, device, binaryCollection.get("vert"), 0u); Move tescShaderModule; Move teseShaderModule; Move geomShaderModule; Move fragShaderModule = createShaderModule(vk, device, binaryCollection.get("frag"), 0u); if (param.inputStage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT || param.outputStage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT || param.inputStage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT || param.outputStage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) { tescShaderModule = createShaderModule(vk, device, binaryCollection.get("tcs"), 0u); teseShaderModule = createShaderModule(vk, device, binaryCollection.get("tes"), 0u); topology = VK_PRIMITIVE_TOPOLOGY_PATCH_LIST; } if (param.inputStage == VK_SHADER_STAGE_GEOMETRY_BIT || param.outputStage == VK_SHADER_STAGE_GEOMETRY_BIT) geomShaderModule = createShaderModule(vk, device, binaryCollection.get("geom"), 0u); GraphicsPipelineWrapper graphicsPipeline(vk, device, param.pipelineConstructionType); graphicsPipeline.setDefaultTopology(topology) .setDefaultRasterizationState() .setDefaultDepthStencilState() .setDefaultMultisampleState() .setDefaultColorBlendState() .setupVertexInputState() .setupPreRasterizationShaderState(viewport, scissor, *pipelineLayout, *renderPass, 0u, *vertShaderModule, 0u, *tescShaderModule, *teseShaderModule, *geomShaderModule, &pSpecInfo) .setupFragmentShaderState(*pipelineLayout, *renderPass, 0u, *fragShaderModule, DE_NULL, DE_NULL, &pSpecInfo) .setupFragmentOutputState(*renderPass) .setMonolithicPipelineLayout(*pipelineLayout) .buildPipeline(); // Draw commands const VkRect2D renderArea = makeRect2D(renderSize); const tcu::Vec4 clearColor (0.0f, 0.0f, 0.0f, 1.0f); beginCommandBuffer(vk, *cmdBuffer); { const VkImageSubresourceRange imageFullSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u); const VkImageMemoryBarrier barrierColorAttachmentSetInitialLayout = makeImageMemoryBarrier( 0u, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, *colorImage, imageFullSubresourceRange); vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &barrierColorAttachmentSetInitialLayout); } beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor); vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline.getPipeline()); const VkDeviceSize vertexBufferOffset = 0ull; vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset); // Draw one vertex vk.cmdDraw(*cmdBuffer, (deUint32)vertices.size(), 1u, 0u, 0u); endRenderPass(vk, *cmdBuffer); // Resolve image -> host buffer recordImageBarrier(vk, *cmdBuffer, *colorImage, VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspect, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags srcStageMask, VK_PIPELINE_STAGE_TRANSFER_BIT, // VkPipelineStageFlags dstStageMask, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask, VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags dstAccessMask, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout oldLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); // VkImageLayout newLayout) recordCopyImageToBuffer(vk, *cmdBuffer, renderSize, *colorImage, *colorBuffer); endCommandBuffer(vk, *cmdBuffer); submitCommandsAndWait(vk, device, queue, *cmdBuffer); // Verify results { invalidateAlloc(vk, device, *colorBufferAlloc); const tcu::ConstPixelBufferAccess resultImage (mapVkFormat(imageFormat), renderSize.x(), renderSize.y(), 1u, colorBufferAlloc->getHostPtr()); tcu::TextureLevel referenceImage (mapVkFormat(imageFormat), renderSize.x(), renderSize.y()); tcu::clear(referenceImage.getAccess(), tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f)); if (!tcu::floatThresholdCompare(log, "Compare", "Result comparison", referenceImage.getAccess(), resultImage, tcu::Vec4(0.02f), tcu::COMPARE_LOG_RESULT)) TCU_FAIL("Rendered image is not correct"); } return tcu::TestStatus::pass("OK"); } } // anonymous tcu::TestCaseGroup* createMaxVaryingsTests (tcu::TestContext& testCtx, PipelineConstructionType pipelineConstructionType) { std::vector tests { { pipelineConstructionType, VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_FRAGMENT_BIT, VK_SHADER_STAGE_VERTEX_BIT }, // Test max vertex outputs: VS-FS { pipelineConstructionType, VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_FRAGMENT_BIT, VK_SHADER_STAGE_FRAGMENT_BIT }, // Test max FS inputs: VS-FS { pipelineConstructionType, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, VK_SHADER_STAGE_FRAGMENT_BIT, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT }, // Test max tess evaluation outputs: VS-TCS-TES-FS { pipelineConstructionType, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, VK_SHADER_STAGE_FRAGMENT_BIT, VK_SHADER_STAGE_FRAGMENT_BIT }, // Test fragment inputs: VS-TCS-TES-FS { pipelineConstructionType, VK_SHADER_STAGE_GEOMETRY_BIT, VK_SHADER_STAGE_FRAGMENT_BIT, VK_SHADER_STAGE_GEOMETRY_BIT }, // Test geometry outputs: VS-GS-FS { pipelineConstructionType, VK_SHADER_STAGE_GEOMETRY_BIT, VK_SHADER_STAGE_FRAGMENT_BIT, VK_SHADER_STAGE_FRAGMENT_BIT }, // Test fragment inputs: VS-GS-FS }; de::MovePtr group (new tcu::TestCaseGroup(testCtx, "max_varyings", "Max Varyings tests")); for (const auto& testParams : tests) { addFunctionCaseWithPrograms(group.get(), generateTestName(testParams), generateTestDescription(), supportedCheck, initPrograms, test, testParams); } return group.release(); } } // pipeline } // vkt