--- /dev/null
+/*------------------------------------------------------------------------
+ * 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 "tcuImageCompare.hpp"
+#include "tcuTestLog.hpp"
+#include "tcuTextureUtil.hpp"
+
+#include <string.h>
+
+namespace vkt
+{
+namespace pipeline
+{
+namespace
+{
+using namespace vk;
+using de::UniquePtr;
+using de::MovePtr;
+
+struct MaxVaryingsParam
+{
+ VkShaderStageFlags outputStage;
+ VkShaderStageFlags inputStage;
+ VkShaderStageFlags stageToStressIO;
+ MaxVaryingsParam(VkShaderStageFlags out, VkShaderStageFlags in, VkShaderStageFlags stageToTest)
+ : outputStage(out), inputStage(in), stageToStressIO(stageToTest) {}
+};
+
+struct SelectedShaders
+{
+ VkShaderStageFlagBits stage;
+ std::string shaderName;
+ SelectedShaders(VkShaderStageFlagBits shaderStage, std::string name)
+ : stage(shaderStage), shaderName(name) {}
+};
+
+// 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());
+ }
+ }
+}
+
+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<VkBuffer> 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<VkBuffer> createBufferAndBindMemory (Context& context, VkDeviceSize size, VkBufferUsageFlags usage, de::MovePtr<Allocation>* 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<VkBuffer> 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 Image colorImage (vk, device, allocator, makeImageCreateInfo(renderSize, imageFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT), MemoryRequirement::Any);
+ const Unique<VkImageView> 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<VkBuffer> colorBuffer = vkt::pipeline::makeBuffer(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
+ MovePtr<Allocation> colorBufferAlloc = bindBuffer(vk, device, allocator, *colorBuffer, MemoryRequirement::HostVisible);
+
+
+ // Create vertex buffer
+ de::MovePtr<Allocation> vertexBufferMemory;
+ Move<VkBuffer> vertexBuffer = createBufferAndBindMemory(context, sizeof(tcu::Vec4) * 6u, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, &vertexBufferMemory);
+ std::vector<tcu::Vec4> 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<VkRenderPass> renderPass (makeRenderPass (vk, device, imageFormat));
+ const Unique<VkFramebuffer> framebuffer (makeFramebuffer (vk, device, *renderPass, 1u, &colorImageView.get(), static_cast<deUint32>(renderSize.x()), static_cast<deUint32>(renderSize.y())));
+ const Unique<VkPipelineLayout> pipelineLayout (makePipelineLayout(vk, device));
+ const Unique<VkCommandPool> cmdPool (createCommandPool (vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
+ const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer (vk, device, *cmdPool));
+
+ GraphicsPipelineBuilder pipelineBuilder;
+ pipelineBuilder
+ .setRenderSize(renderSize);
+
+ // Get the shaders to run
+ std::vector<SelectedShaders> shaders;
+ shaders.push_back(SelectedShaders(VK_SHADER_STAGE_VERTEX_BIT, "vert"));
+ shaders.push_back(SelectedShaders(VK_SHADER_STAGE_FRAGMENT_BIT, "frag"));
+
+ 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)
+ {
+ shaders.push_back(SelectedShaders(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, "tcs"));
+ shaders.push_back(SelectedShaders(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, "tes"));
+ }
+ if (param.inputStage == VK_SHADER_STAGE_GEOMETRY_BIT || param.outputStage == VK_SHADER_STAGE_GEOMETRY_BIT)
+ {
+ shaders.push_back(SelectedShaders(VK_SHADER_STAGE_GEOMETRY_BIT, "geom"));
+ }
+
+ for (deUint32 i = 0; i < (deUint32)shaders.size(); i++)
+ {
+ pipelineBuilder.setShader(vk, device, shaders[i].stage, context.getBinaryCollection().get(shaders[i].shaderName.c_str()), &pSpecInfo);
+ }
+
+ const Unique<VkPipeline> pipeline (pipelineBuilder.build(vk, device, *pipelineLayout, *renderPass));
+
+ // 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, *pipeline);
+ 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)
+{
+ std::vector<MaxVaryingsParam> tests;
+
+ tests.push_back(MaxVaryingsParam(VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_FRAGMENT_BIT, VK_SHADER_STAGE_VERTEX_BIT)); // Test max vertex outputs: VS-FS
+ tests.push_back(MaxVaryingsParam(VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_FRAGMENT_BIT, VK_SHADER_STAGE_FRAGMENT_BIT)); // Test max FS inputs: VS-FS
+ tests.push_back(MaxVaryingsParam(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
+ tests.push_back(MaxVaryingsParam(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, VK_SHADER_STAGE_FRAGMENT_BIT, VK_SHADER_STAGE_FRAGMENT_BIT)); // Test fragment inputs: VS-TCS-TES-FS
+ tests.push_back(MaxVaryingsParam(VK_SHADER_STAGE_GEOMETRY_BIT, VK_SHADER_STAGE_FRAGMENT_BIT, VK_SHADER_STAGE_GEOMETRY_BIT)); // Test geometry outputs: VS-GS-FS
+ tests.push_back(MaxVaryingsParam(VK_SHADER_STAGE_GEOMETRY_BIT, VK_SHADER_STAGE_FRAGMENT_BIT, VK_SHADER_STAGE_FRAGMENT_BIT)); // Test fragment inputs: VS-GS-FS
+
+ de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "max_varyings", "Max Varyings tests"));
+
+ for (deUint32 testIndex = 0; testIndex < (deUint32)tests.size(); ++testIndex)
+ {
+ MaxVaryingsParam testParams = tests[testIndex];
+ addFunctionCaseWithPrograms(group.get(), generateTestName(testParams), generateTestDescription(),
+ supportedCheck, initPrograms, test, testParams);
+ }
+
+ return group.release();
+}
+
+} // pipeline
+} // vkt