blob: 9d0b8c96a10ad4910874ae1e0115e9bf05d44c30 [file] [log] [blame]
/*------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2019 The Khronos Group Inc.
* Copyright (c) 2019 Google Inc.
* Copyright (c) 2017 Codeplay Software Ltd.
*
* 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 Subgroups Tests
*/ /*--------------------------------------------------------------------*/
#include "vktSubgroupsBasicTests.hpp"
#include "vktSubgroupsTestsUtils.hpp"
#include <string>
#include <vector>
using namespace tcu;
using namespace std;
using namespace vk;
using namespace vkt;
namespace
{
static const deUint32 ELECTED_VALUE = 42u;
static const deUint32 UNELECTED_VALUE = 13u;
static const vk::VkDeviceSize SHADER_BUFFER_SIZE = 4096ull; // min(maxUniformBufferRange, maxImageDimension1D)
static bool _checkFragmentSubgroupBarriersNoSSBO(std::vector<const void*> datas,
deUint32 width, deUint32 height, bool withImage)
{
const float* const resultData = reinterpret_cast<const float*>(datas[0]);
for (deUint32 x = 0u; x < width; ++x)
{
for (deUint32 y = 0u; y < height; ++y)
{
const deUint32 ndx = (x * height + y) * 4u;
if (!withImage && 0.0f == resultData[ndx])
{
return false;
}
else if (1.0f == resultData[ndx +2])
{
if(resultData[ndx] != resultData[ndx +1])
{
return false;
}
}
else if (resultData[ndx] != resultData[ndx +3])
{
return false;
}
}
}
return true;
}
static bool checkFragmentSubgroupBarriersNoSSBO(const void *internalData, std::vector<const void*> datas,
deUint32 width, deUint32 height, deUint32)
{
DE_UNREF(internalData);
return _checkFragmentSubgroupBarriersNoSSBO(datas, width, height, false);
}
static bool checkFragmentSubgroupBarriersWithImageNoSSBO(const void* internalData, std::vector<const void*> datas,
deUint32 width, deUint32 height, deUint32)
{
DE_UNREF(internalData);
return _checkFragmentSubgroupBarriersNoSSBO(datas, width, height, true);
}
static bool checkVertexPipelineStagesSubgroupElectNoSSBO(const void* internalData, std::vector<const void*> datas,
deUint32 width, deUint32)
{
DE_UNREF(internalData);
const float* const resultData = reinterpret_cast<const float*>(datas[0]);
float poisonValuesFound = 0.0f;
float numSubgroupsUsed = 0.0f;
for (deUint32 x = 0; x < width; ++x)
{
deUint32 val = static_cast<deUint32>(resultData[x * 2]);
numSubgroupsUsed += resultData[x * 2 + 1];
switch (val)
{
default:
// some garbage value was found!
return false;
case UNELECTED_VALUE:
break;
case ELECTED_VALUE:
poisonValuesFound += 1.0f;
break;
}
}
return numSubgroupsUsed == poisonValuesFound;
}
static bool checkVertexPipelineStagesSubgroupElect(const void* internalData, std::vector<const void*> datas,
deUint32 width, deUint32, bool multipleCallsPossible)
{
DE_UNREF(internalData);
const deUint32* const resultData =
reinterpret_cast<const deUint32*>(datas[0]);
deUint32 poisonValuesFound = 0;
for (deUint32 x = 0; x < width; ++x)
{
deUint32 val = resultData[x];
switch (val)
{
default:
// some garbage value was found!
return false;
case UNELECTED_VALUE:
break;
case ELECTED_VALUE:
poisonValuesFound++;
break;
}
}
// we used an atomicly incremented counter to note how many subgroups we used for the vertex shader
const deUint32 numSubgroupsUsed =
*reinterpret_cast<const deUint32*>(datas[1]);
return (multipleCallsPossible ? (numSubgroupsUsed >= poisonValuesFound) : (numSubgroupsUsed == poisonValuesFound));
}
static bool checkVertexPipelineStagesSubgroupBarriers(const void* internalData, std::vector<const void*> datas,
deUint32 width, deUint32)
{
DE_UNREF(internalData);
const deUint32* const resultData = reinterpret_cast<const deUint32*>(datas[0]);
// We used this SSBO to generate our unique value!
const deUint32 ref = *reinterpret_cast<const deUint32*>(datas[3]);
for (deUint32 x = 0; x < width; ++x)
{
deUint32 val = resultData[x];
if (val != ref)
return false;
}
return true;
}
static bool _checkVertexPipelineStagesSubgroupBarriersNoSSBO(std::vector<const void*> datas,
deUint32 width, bool withImage)
{
const float* const resultData = reinterpret_cast<const float*>(datas[0]);
for (deUint32 x = 0u; x < width; ++x)
{
const deUint32 ndx = x*4u;
if (!withImage && 0.0f == resultData[ndx])
{
return false;
}
else if (1.0f == resultData[ndx +2])
{
if(resultData[ndx] != resultData[ndx +1])
return false;
}
else if (resultData[ndx] != resultData[ndx +3])
{
return false;
}
}
return true;
}
static bool checkVertexPipelineStagesSubgroupBarriersNoSSBO(const void* internalData, std::vector<const void*> datas,
deUint32 width, deUint32)
{
DE_UNREF(internalData);
return _checkVertexPipelineStagesSubgroupBarriersNoSSBO(datas, width, false);
}
static bool checkVertexPipelineStagesSubgroupBarriersWithImageNoSSBO(const void* internalData, std::vector<const void*> datas,
deUint32 width, deUint32)
{
DE_UNREF(internalData);
return _checkVertexPipelineStagesSubgroupBarriersNoSSBO(datas, width, true);
}
static bool _checkTessellationEvaluationSubgroupBarriersNoSSBO(std::vector<const void*> datas,
deUint32 width, deUint32, bool withImage)
{
const float* const resultData = reinterpret_cast<const float*>(datas[0]);
for (deUint32 x = 0u; x < width; ++x)
{
const deUint32 ndx = x*4u;
if (!withImage && 0.0f == resultData[ndx])
{
return false;
}
else if (0.0f == resultData[ndx +2] && resultData[ndx] != resultData[ndx +3])
{
return false;
}
}
return true;
}
static bool checkTessellationEvaluationSubgroupBarriersWithImageNoSSBO(const void* internalData, std::vector<const void*> datas,
deUint32 width, deUint32 height)
{
DE_UNREF(internalData);
return _checkTessellationEvaluationSubgroupBarriersNoSSBO(datas, width, height, true);
}
static bool checkTessellationEvaluationSubgroupBarriersNoSSBO(const void* internalData, std::vector<const void*> datas,
deUint32 width, deUint32 height)
{
DE_UNREF(internalData);
return _checkTessellationEvaluationSubgroupBarriersNoSSBO(datas, width, height, false);
}
static bool checkComputeSubgroupElect(const void* internalData, std::vector<const void*> datas,
const deUint32 numWorkgroups[3], const deUint32 localSize[3],
deUint32)
{
DE_UNREF(internalData);
return vkt::subgroups::checkCompute(datas, numWorkgroups, localSize, 1);
}
static bool checkComputeSubgroupBarriers(const void* internalData, std::vector<const void*> datas,
const deUint32 numWorkgroups[3], const deUint32 localSize[3],
deUint32)
{
DE_UNREF(internalData);
// We used this SSBO to generate our unique value!
const deUint32 ref = *reinterpret_cast<const deUint32*>(datas[2]);
return vkt::subgroups::checkCompute(datas, numWorkgroups, localSize, ref);
}
enum OpType
{
OPTYPE_ELECT = 0,
OPTYPE_SUBGROUP_BARRIER,
OPTYPE_SUBGROUP_MEMORY_BARRIER,
OPTYPE_SUBGROUP_MEMORY_BARRIER_BUFFER,
OPTYPE_SUBGROUP_MEMORY_BARRIER_SHARED,
OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE,
OPTYPE_LAST
};
std::string getOpTypeName(int opType)
{
switch (opType)
{
default:
DE_FATAL("Unsupported op type");
return "";
case OPTYPE_ELECT:
return "subgroupElect";
case OPTYPE_SUBGROUP_BARRIER:
return "subgroupBarrier";
case OPTYPE_SUBGROUP_MEMORY_BARRIER:
return "subgroupMemoryBarrier";
case OPTYPE_SUBGROUP_MEMORY_BARRIER_BUFFER:
return "subgroupMemoryBarrierBuffer";
case OPTYPE_SUBGROUP_MEMORY_BARRIER_SHARED:
return "subgroupMemoryBarrierShared";
case OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE:
return "subgroupMemoryBarrierImage";
}
}
struct CaseDefinition
{
int opType;
VkShaderStageFlags shaderStage;
de::SharedPtr<bool> geometryPointSizeSupported;
deBool requiredSubgroupSize;
};
void initFrameBufferPrograms(SourceCollections& programCollection, CaseDefinition caseDef)
{
const vk::ShaderBuildOptions buildOptions (programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_3, 0u);
const vk::SpirVAsmBuildOptions buildOptionsSpr (programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_3);
if(VK_SHADER_STAGE_FRAGMENT_BIT != caseDef.shaderStage)
{
/*
"layout(location = 0) in vec4 in_color;\n"
"layout(location = 0) out vec4 out_color;\n"
"void main()\n"
{\n"
" out_color = in_color;\n"
"}\n";
*/
const string fragment =
"; SPIR-V\n"
"; Version: 1.3\n"
"; Generator: Khronos Glslang Reference Front End; 2\n"
"; Bound: 13\n"
"; Schema: 0\n"
"OpCapability Shader\n"
"%1 = OpExtInstImport \"GLSL.std.450\"\n"
"OpMemoryModel Logical GLSL450\n"
"OpEntryPoint Fragment %4 \"main\" %9 %11\n"
"OpExecutionMode %4 OriginUpperLeft\n"
"OpDecorate %9 Location 0\n"
"OpDecorate %11 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 = OpTypePointer Input %7\n"
"%11 = OpVariable %10 Input\n"
"%4 = OpFunction %2 None %3\n"
"%5 = OpLabel\n"
"%12 = OpLoad %7 %11\n"
"OpStore %9 %12\n"
"OpReturn\n"
"OpFunctionEnd\n";
programCollection.spirvAsmSources.add("fragment") << fragment;
}
if (VK_SHADER_STAGE_FRAGMENT_BIT == caseDef.shaderStage)
{
/*
"#version 450\n"
"void main (void)\n"
"{\n"
" vec2 uv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);\n"
" gl_Position = vec4(uv * 2.0f + -1.0f, 0.0f, 1.0f);\n"
" gl_PointSize = 1.0f;\n"
"}\n";
*/
const string vertex =
"; SPIR-V\n"
"; Version: 1.3\n"
"; Generator: Khronos Glslang Reference Front End; 2\n"
"; Bound: 44\n"
"; Schema: 0\n"
"OpCapability Shader\n"
"%1 = OpExtInstImport \"GLSL.std.450\"\n"
"OpMemoryModel Logical GLSL450\n"
"OpEntryPoint Vertex %4 \"main\" %12 %29\n"
"OpDecorate %12 BuiltIn VertexIndex\n"
"OpMemberDecorate %27 0 BuiltIn Position\n"
"OpMemberDecorate %27 1 BuiltIn PointSize\n"
"OpMemberDecorate %27 2 BuiltIn ClipDistance\n"
"OpMemberDecorate %27 3 BuiltIn CullDistance\n"
"OpDecorate %27 Block\n"
"%2 = OpTypeVoid\n"
"%3 = OpTypeFunction %2\n"
"%6 = OpTypeFloat 32\n"
"%7 = OpTypeVector %6 2\n"
"%8 = OpTypePointer Function %7\n"
"%10 = OpTypeInt 32 1\n"
"%11 = OpTypePointer Input %10\n"
"%12 = OpVariable %11 Input\n"
"%14 = OpConstant %10 1\n"
"%16 = OpConstant %10 2\n"
"%23 = OpTypeVector %6 4\n"
"%24 = OpTypeInt 32 0\n"
"%25 = OpConstant %24 1\n"
"%26 = OpTypeArray %6 %25\n"
"%27 = OpTypeStruct %23 %6 %26 %26\n"
"%28 = OpTypePointer Output %27\n"
"%29 = OpVariable %28 Output\n"
"%30 = OpConstant %10 0\n"
"%32 = OpConstant %6 2\n"
"%34 = OpConstant %6 -1\n"
"%37 = OpConstant %6 0\n"
"%38 = OpConstant %6 1\n"
"%42 = OpTypePointer Output %23\n"
"%44 = OpTypePointer Output %6\n"
"%4 = OpFunction %2 None %3\n"
"%5 = OpLabel\n"
"%9 = OpVariable %8 Function\n"
"%13 = OpLoad %10 %12\n"
"%15 = OpShiftLeftLogical %10 %13 %14\n"
"%17 = OpBitwiseAnd %10 %15 %16\n"
"%18 = OpConvertSToF %6 %17\n"
"%19 = OpLoad %10 %12\n"
"%20 = OpBitwiseAnd %10 %19 %16\n"
"%21 = OpConvertSToF %6 %20\n"
"%22 = OpCompositeConstruct %7 %18 %21\n"
"OpStore %9 %22\n"
"%31 = OpLoad %7 %9\n"
"%33 = OpVectorTimesScalar %7 %31 %32\n"
"%35 = OpCompositeConstruct %7 %34 %34\n"
"%36 = OpFAdd %7 %33 %35\n"
"%39 = OpCompositeExtract %6 %36 0\n"
"%40 = OpCompositeExtract %6 %36 1\n"
"%41 = OpCompositeConstruct %23 %39 %40 %37 %38\n"
"%43 = OpAccessChain %42 %29 %30\n"
"OpStore %43 %41\n"
"%45 = OpAccessChain %44 %29 %14\n"
"OpStore %45 %38\n"
"OpReturn\n"
"OpFunctionEnd\n";
programCollection.spirvAsmSources.add("vert") << vertex;
}
else if (VK_SHADER_STAGE_VERTEX_BIT != caseDef.shaderStage)
subgroups::setVertexShaderFrameBuffer(programCollection);
if (OPTYPE_ELECT == caseDef.opType)
{
std::ostringstream electedValue ;
std::ostringstream unelectedValue;
electedValue << ELECTED_VALUE;
unelectedValue << UNELECTED_VALUE;
if (VK_SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
{
/*
"#extension GL_KHR_shader_subgroup_basic: enable\n"
"layout(location = 0) out vec4 out_color;\n"
"layout(location = 0) in highp vec4 in_position;\n"
"\n"
"void main (void)\n"
"{\n"
" if (subgroupElect())\n"
" {\n"
" out_color.r = " << ELECTED_VALUE << ";\n"
" out_color.g = 1.0f;\n"
" }\n"
" else\n"
" {\n"
" out_color.r = " << UNELECTED_VALUE << ";\n"
" out_color.g = 0.0f;\n"
" }\n"
" gl_Position = in_position;\n"
" gl_PointSize = 1.0f;\n"
"}\n";
*/
const string vertex =
"; SPIR-V\n"
"; Version: 1.3\n"
"; Generator: Khronos Glslang Reference Front End; 2\n"
"; Bound: 38\n"
"; Schema: 0\n"
"OpCapability Shader\n"
"OpCapability GroupNonUniform\n"
"%1 = OpExtInstImport \"GLSL.std.450\"\n"
"OpMemoryModel Logical GLSL450\n"
"OpEntryPoint Vertex %4 \"main\" %15 %31 %35\n"
"OpDecorate %15 Location 0\n"
"OpMemberDecorate %29 0 BuiltIn Position\n"
"OpMemberDecorate %29 1 BuiltIn PointSize\n"
"OpMemberDecorate %29 2 BuiltIn ClipDistance\n"
"OpMemberDecorate %29 3 BuiltIn CullDistance\n"
"OpDecorate %29 Block\n"
"OpDecorate %35 Location 0\n"
"%2 = OpTypeVoid\n"
"%3 = OpTypeFunction %2\n"
"%6 = OpTypeBool\n"
"%7 = OpTypeInt 32 0\n"
"%8 = OpConstant %7 3\n"
"%12 = OpTypeFloat 32\n"
"%13 = OpTypeVector %12 4\n"
"%14 = OpTypePointer Output %13\n"
"%15 = OpVariable %14 Output\n"
"%16 = OpConstant %12 " + electedValue.str() + "\n"
"%17 = OpConstant %7 0\n"
"%18 = OpTypePointer Output %12\n"
"%20 = OpConstant %12 1\n"
"%21 = OpConstant %7 1\n"
"%24 = OpConstant %12 " + unelectedValue.str() + "\n"
"%26 = OpConstant %12 0\n"
"%28 = OpTypeArray %12 %21\n"
"%29 = OpTypeStruct %13 %12 %28 %28\n"
"%30 = OpTypePointer Output %29\n"
"%31 = OpVariable %30 Output\n"
"%32 = OpTypeInt 32 1\n"
"%33 = OpConstant %32 0\n"
"%34 = OpTypePointer Input %13\n"
"%35 = OpVariable %34 Input\n"
"%38 = OpConstant %32 1\n"
"%4 = OpFunction %2 None %3\n"
"%5 = OpLabel\n"
"%9 = OpGroupNonUniformElect %6 %8\n"
"OpSelectionMerge %11 None\n"
"OpBranchConditional %9 %10 %23\n"
"%10 = OpLabel\n"
"%19 = OpAccessChain %18 %15 %17\n"
"OpStore %19 %16\n"
"%22 = OpAccessChain %18 %15 %21\n"
"OpStore %22 %20\n"
"OpBranch %11\n"
"%23 = OpLabel\n"
"%25 = OpAccessChain %18 %15 %17\n"
"OpStore %25 %24\n"
"%27 = OpAccessChain %18 %15 %21\n"
"OpStore %27 %26\n"
"OpBranch %11\n"
"%11 = OpLabel\n"
"%36 = OpLoad %13 %35\n"
"%37 = OpAccessChain %14 %31 %33\n"
"OpStore %37 %36\n"
"%39 = OpAccessChain %18 %31 %38\n"
"OpStore %39 %20\n"
"OpReturn\n"
"OpFunctionEnd\n";
programCollection.spirvAsmSources.add("vert") << vertex << buildOptionsSpr;
}
else if (VK_SHADER_STAGE_GEOMETRY_BIT == caseDef.shaderStage)
{
/*
"#version 450\n"
"#extension GL_KHR_shader_subgroup_basic: enable\n"
"layout(points) in;\n"
"layout(points, max_vertices = 1) out;\n"
"layout(location = 0) out vec4 out_color;\n"
"void main (void)\n"
"{\n"
" if (subgroupElect())\n"
" {\n"
" out_color.r = " << ELECTED_VALUE << ";\n"
" out_color.g = 1.0f;\n"
" }\n"
" else\n"
" {\n"
" out_color.r = " << UNELECTED_VALUE << ";\n"
" out_color.g = 0.0f;\n"
" }\n"
" gl_Position = gl_in[0].gl_Position;\n"
" gl_PointSize = gl_in[0].gl_PointSize;\n"
" EmitVertex();\n"
" EndPrimitive();\n"
"}\n";
*/
std::ostringstream geometry;
geometry
<< "; SPIR-V\n"
<< "; Version: 1.3\n"
<< "; Generator: Khronos Glslang Reference Front End; 2\n"
<< "; Bound: 42\n"
<< "; Schema: 0\n"
<< "OpCapability Geometry\n"
<< (*caseDef.geometryPointSizeSupported ?
"OpCapability GeometryPointSize\n" : "")
<< "OpCapability GroupNonUniform\n"
<< "%1 = OpExtInstImport \"GLSL.std.450\"\n"
<< "OpMemoryModel Logical GLSL450\n"
<< "OpEntryPoint Geometry %4 \"main\" %15 %31 %37\n"
<< "OpExecutionMode %4 InputPoints\n"
<< "OpExecutionMode %4 Invocations 1\n"
<< "OpExecutionMode %4 OutputPoints\n"
<< "OpExecutionMode %4 OutputVertices 1\n"
<< "OpDecorate %15 Location 0\n"
<< "OpMemberDecorate %29 0 BuiltIn Position\n"
<< "OpMemberDecorate %29 1 BuiltIn PointSize\n"
<< "OpMemberDecorate %29 2 BuiltIn ClipDistance\n"
<< "OpMemberDecorate %29 3 BuiltIn CullDistance\n"
<< "OpDecorate %29 Block\n"
<< "OpMemberDecorate %34 0 BuiltIn Position\n"
<< "OpMemberDecorate %34 1 BuiltIn PointSize\n"
<< "OpMemberDecorate %34 2 BuiltIn ClipDistance\n"
<< "OpMemberDecorate %34 3 BuiltIn CullDistance\n"
<< "OpDecorate %34 Block\n"
<< "%2 = OpTypeVoid\n"
<< "%3 = OpTypeFunction %2\n"
<< "%6 = OpTypeBool\n"
<< "%7 = OpTypeInt 32 0\n"
<< "%8 = OpConstant %7 3\n"
<< "%12 = OpTypeFloat 32\n"
<< "%13 = OpTypeVector %12 4\n"
<< "%14 = OpTypePointer Output %13\n"
<< "%15 = OpVariable %14 Output\n"
<< "%16 = OpConstant %12 " << electedValue.str() << "\n"
<< "%17 = OpConstant %7 0\n"
<< "%18 = OpTypePointer Output %12\n"
<< "%20 = OpConstant %12 1\n"
<< "%21 = OpConstant %7 1\n"
<< "%24 = OpConstant %12 " << unelectedValue.str() << "\n"
<< "%26 = OpConstant %12 0\n"
<< "%28 = OpTypeArray %12 %21\n"
<< "%29 = OpTypeStruct %13 %12 %28 %28\n"
<< "%30 = OpTypePointer Output %29\n"
<< "%31 = OpVariable %30 Output\n"
<< "%32 = OpTypeInt 32 1\n"
<< "%33 = OpConstant %32 0\n"
<< "%34 = OpTypeStruct %13 %12 %28 %28\n"
<< "%35 = OpTypeArray %34 %21\n"
<< "%36 = OpTypePointer Input %35\n"
<< "%37 = OpVariable %36 Input\n"
<< "%38 = OpTypePointer Input %13\n"
<< (*caseDef.geometryPointSizeSupported ?
"%42 = OpConstant %32 1\n"
"%43 = OpTypePointer Input %12\n"
"%44 = OpTypePointer Output %12\n" : "")
<< "%4 = OpFunction %2 None %3\n"
<< "%5 = OpLabel\n"
<< "%9 = OpGroupNonUniformElect %6 %8\n"
<< "OpSelectionMerge %11 None\n"
<< "OpBranchConditional %9 %10 %23\n"
<< "%10 = OpLabel\n"
<< "%19 = OpAccessChain %18 %15 %17\n"
<< "OpStore %19 %16\n"
<< "%22 = OpAccessChain %18 %15 %21\n"
<< "OpStore %22 %20\n"
<< "OpBranch %11\n"
<< "%23 = OpLabel\n"
<< "%25 = OpAccessChain %18 %15 %17\n"
<< "OpStore %25 %24\n"
<< "%27 = OpAccessChain %18 %15 %21\n"
<< "OpStore %27 %26\n"
<< "OpBranch %11\n"
<< "%11 = OpLabel\n"
<< "%39 = OpAccessChain %38 %37 %33 %33\n"
<< "%40 = OpLoad %13 %39\n"
<< "%41 = OpAccessChain %14 %31 %33\n"
<< "OpStore %41 %40\n"
<< (*caseDef.geometryPointSizeSupported ?
"%45 = OpAccessChain %43 %37 %33 %42\n"
"%46 = OpLoad %12 %45\n"
"%47 = OpAccessChain %44 %31 %42\n"
"OpStore %47 %46\n" : "" )
<< "OpEmitVertex\n"
<< "OpEndPrimitive\n"
<< "OpReturn\n"
<< "OpFunctionEnd\n";
programCollection.spirvAsmSources.add("geometry") << geometry.str() << buildOptionsSpr;
}
else if (VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT == caseDef.shaderStage)
{
/*
<< "#extension GL_KHR_shader_subgroup_basic: enable\n"
<< "#extension GL_EXT_tessellation_shader : require\n"
<< "layout(vertices = 2) out;\n"
<< "void main (void)\n"
<< "{\n"
<< " if (gl_InvocationID == 0)\n"
<< " {\n"
<< " gl_TessLevelOuter[0] = 1.0f;\n"
<< " gl_TessLevelOuter[1] = 1.0f;\n"
<< " }\n"
<< " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
<< "}\n";
*/
const string controlSource =
"; SPIR-V\n"
"; Version: 1.3\n"
"; Generator: Khronos Glslang Reference Front End; 2\n"
"; Bound: 46\n"
"; Schema: 0\n"
"OpCapability Tessellation\n"
"%1 = OpExtInstImport \"GLSL.std.450\"\n"
"OpMemoryModel Logical GLSL450\n"
"OpEntryPoint TessellationControl %4 \"main\" %8 %20 %33 %39\n"
"OpExecutionMode %4 OutputVertices 2\n"
"OpDecorate %8 BuiltIn InvocationId\n"
"OpDecorate %20 Patch\n"
"OpDecorate %20 BuiltIn TessLevelOuter\n"
"OpMemberDecorate %29 0 BuiltIn Position\n"
"OpMemberDecorate %29 1 BuiltIn PointSize\n"
"OpMemberDecorate %29 2 BuiltIn ClipDistance\n"
"OpMemberDecorate %29 3 BuiltIn CullDistance\n"
"OpDecorate %29 Block\n"
"OpMemberDecorate %35 0 BuiltIn Position\n"
"OpMemberDecorate %35 1 BuiltIn PointSize\n"
"OpMemberDecorate %35 2 BuiltIn ClipDistance\n"
"OpMemberDecorate %35 3 BuiltIn CullDistance\n"
"OpDecorate %35 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 4\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 = OpTypeVector %15 4\n"
"%27 = OpConstant %16 1\n"
"%28 = OpTypeArray %15 %27\n"
"%29 = OpTypeStruct %26 %15 %28 %28\n"
"%30 = OpConstant %16 2\n"
"%31 = OpTypeArray %29 %30\n"
"%32 = OpTypePointer Output %31\n"
"%33 = OpVariable %32 Output\n"
"%35 = OpTypeStruct %26 %15 %28 %28\n"
"%36 = OpConstant %16 32\n"
"%37 = OpTypeArray %35 %36\n"
"%38 = OpTypePointer Input %37\n"
"%39 = OpVariable %38 Input\n"
"%41 = OpTypePointer Input %26\n"
"%44 = OpTypePointer Output %26\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"
"OpBranch %14\n"
"%14 = OpLabel\n"
"%34 = OpLoad %6 %8\n"
"%40 = OpLoad %6 %8\n"
"%42 = OpAccessChain %41 %39 %40 %10\n"
"%43 = OpLoad %26 %42\n"
"%45 = OpAccessChain %44 %33 %34 %10\n"
"OpStore %45 %43\n"
"OpReturn\n"
"OpFunctionEnd\n";
programCollection.spirvAsmSources.add("tesc") << controlSource << buildOptionsSpr;
/*
"#extension GL_KHR_shader_subgroup_basic: enable\n"
"#extension GL_EXT_tessellation_shader : require\n"
"layout(isolines, equal_spacing, ccw ) in;\n"
"layout(location = 0) out vec4 out_color;\n"
"\n"
"void main (void)\n"
"{\n"
" if (subgroupElect())\n"
" {\n"
" out_color.r = " << 2 * ELECTED_VALUE - UNELECTED_VALUE << ";\n"
" out_color.g = 2.0f;\n"
" }\n"
" else\n"
" {\n"
" out_color.r = " << UNELECTED_VALUE << ";\n"
" out_color.g = 0.0f;\n"
" }\n"
" gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n"
"}\n";
*/
const string evaluationSource =
"; SPIR-V\n"
"; Version: 1.3\n"
"; Generator: Khronos Glslang Reference Front End; 2\n"
"; Bound: 54\n"
"; Schema: 0\n"
"OpCapability Tessellation\n"
"OpCapability GroupNonUniform\n"
"%1 = OpExtInstImport \"GLSL.std.450\"\n"
"OpMemoryModel Logical GLSL450\n"
"OpEntryPoint TessellationEvaluation %4 \"main\" %15 %31 %38 %47\n"
"OpExecutionMode %4 Isolines\n"
"OpExecutionMode %4 SpacingEqual\n"
"OpExecutionMode %4 VertexOrderCcw\n"
"OpDecorate %15 Location 0\n"
"OpMemberDecorate %29 0 BuiltIn Position\n"
"OpMemberDecorate %29 1 BuiltIn PointSize\n"
"OpMemberDecorate %29 2 BuiltIn ClipDistance\n"
"OpMemberDecorate %29 3 BuiltIn CullDistance\n"
"OpDecorate %29 Block\n"
"OpMemberDecorate %34 0 BuiltIn Position\n"
"OpMemberDecorate %34 1 BuiltIn PointSize\n"
"OpMemberDecorate %34 2 BuiltIn ClipDistance\n"
"OpMemberDecorate %34 3 BuiltIn CullDistance\n"
"OpDecorate %34 Block\n"
"OpDecorate %47 BuiltIn TessCoord\n"
"%2 = OpTypeVoid\n"
"%3 = OpTypeFunction %2\n"
"%6 = OpTypeBool\n"
"%7 = OpTypeInt 32 0\n"
"%8 = OpConstant %7 3\n"
"%12 = OpTypeFloat 32\n"
"%13 = OpTypeVector %12 4\n"
"%14 = OpTypePointer Output %13\n"
"%15 = OpVariable %14 Output\n"
"%16 = OpConstant %12 71\n"//electedValue
"%17 = OpConstant %7 0\n"
"%18 = OpTypePointer Output %12\n"
"%20 = OpConstant %12 2\n"
"%21 = OpConstant %7 1\n"
"%24 = OpConstant %12 " + unelectedValue.str() + "\n"
"%26 = OpConstant %12 0\n"
"%28 = OpTypeArray %12 %21\n"
"%29 = OpTypeStruct %13 %12 %28 %28\n"
"%30 = OpTypePointer Output %29\n"
"%31 = OpVariable %30 Output\n"
"%32 = OpTypeInt 32 1\n"
"%33 = OpConstant %32 0\n"
"%34 = OpTypeStruct %13 %12 %28 %28\n"
"%35 = OpConstant %7 32\n"
"%36 = OpTypeArray %34 %35\n"
"%37 = OpTypePointer Input %36\n"
"%38 = OpVariable %37 Input\n"
"%39 = OpTypePointer Input %13\n"
"%42 = OpConstant %32 1\n"
"%45 = OpTypeVector %12 3\n"
"%46 = OpTypePointer Input %45\n"
"%47 = OpVariable %46 Input\n"
"%48 = OpTypePointer Input %12\n"
"%4 = OpFunction %2 None %3\n"
"%5 = OpLabel\n"
"%9 = OpGroupNonUniformElect %6 %8\n"
"OpSelectionMerge %11 None\n"
"OpBranchConditional %9 %10 %23\n"
"%10 = OpLabel\n"
"%19 = OpAccessChain %18 %15 %17\n"
"OpStore %19 %16\n"
"%22 = OpAccessChain %18 %15 %21\n"
"OpStore %22 %20\n"
"OpBranch %11\n"
"%23 = OpLabel\n"
"%25 = OpAccessChain %18 %15 %17\n"
"OpStore %25 %24\n"
"%27 = OpAccessChain %18 %15 %21\n"
"OpStore %27 %26\n"
"OpBranch %11\n"
"%11 = OpLabel\n"
"%40 = OpAccessChain %39 %38 %33 %33\n"
"%41 = OpLoad %13 %40\n"
"%43 = OpAccessChain %39 %38 %42 %33\n"
"%44 = OpLoad %13 %43\n"
"%49 = OpAccessChain %48 %47 %17\n"
"%50 = OpLoad %12 %49\n"
"%51 = OpCompositeConstruct %13 %50 %50 %50 %50\n"
"%52 = OpExtInst %13 %1 FMix %41 %44 %51\n"
"%53 = OpAccessChain %14 %31 %33\n"
"OpStore %53 %52\n"
"OpReturn\n"
"OpFunctionEnd\n";
programCollection.spirvAsmSources.add("tese") << evaluationSource << buildOptionsSpr;
}
else if (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT == caseDef.shaderStage)
{
/*
"#extension GL_KHR_shader_subgroup_basic: enable\n"
"#extension GL_EXT_tessellation_shader : require\n"
"layout(vertices = 2) out;\n"
"layout(location = 0) out vec4 out_color[];\n"
"void main (void)\n"
"{\n"
" if (gl_InvocationID == 0)\n"
" {\n"
" gl_TessLevelOuter[0] = 1.0f;\n"
" gl_TessLevelOuter[1] = 1.0f;\n"
" }\n"
" if (subgroupElect())\n"
" {\n"
" out_color[gl_InvocationID].r = " << ELECTED_VALUE << ";\n"
" out_color[gl_InvocationID].g = 1.0f;\n"
" }\n"
" else\n"
" {\n"
" out_color[gl_InvocationID].r = " << UNELECTED_VALUE << ";\n"
" out_color[gl_InvocationID].g = 0.0f;\n"
" }\n"
" gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
"}\n";
*/
const string controlSource =
"; SPIR-V\n"
"; Version: 1.3\n"
"; Generator: Khronos Glslang Reference Front End; 2\n"
"; Bound: 66\n"
"; Schema: 0\n"
"OpCapability Tessellation\n"
"OpCapability GroupNonUniform\n"
"%1 = OpExtInstImport \"GLSL.std.450\"\n"
"OpMemoryModel Logical GLSL450\n"
"OpEntryPoint TessellationControl %4 \"main\" %8 %20 %34 %53 %59\n"
"OpExecutionMode %4 OutputVertices 2\n"
"OpDecorate %8 BuiltIn InvocationId\n"
"OpDecorate %20 Patch\n"
"OpDecorate %20 BuiltIn TessLevelOuter\n"
"OpDecorate %34 Location 0\n"
"OpMemberDecorate %50 0 BuiltIn Position\n"
"OpMemberDecorate %50 1 BuiltIn PointSize\n"
"OpMemberDecorate %50 2 BuiltIn ClipDistance\n"
"OpMemberDecorate %50 3 BuiltIn CullDistance\n"
"OpDecorate %50 Block\n"
"OpMemberDecorate %55 0 BuiltIn Position\n"
"OpMemberDecorate %55 1 BuiltIn PointSize\n"
"OpMemberDecorate %55 2 BuiltIn ClipDistance\n"
"OpMemberDecorate %55 3 BuiltIn CullDistance\n"
"OpDecorate %55 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 4\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 3\n"
"%30 = OpTypeVector %15 4\n"
"%31 = OpConstant %16 2\n"
"%32 = OpTypeArray %30 %31\n"
"%33 = OpTypePointer Output %32\n"
"%34 = OpVariable %33 Output\n"
"%36 = OpConstant %15 " + electedValue.str() + "\n"
"%37 = OpConstant %16 0\n"
"%40 = OpConstant %16 1\n"
"%44 = OpConstant %15 " + unelectedValue.str() + "\n"
"%47 = OpConstant %15 0\n"
"%49 = OpTypeArray %15 %40\n"
"%50 = OpTypeStruct %30 %15 %49 %49\n"
"%51 = OpTypeArray %50 %31\n"
"%52 = OpTypePointer Output %51\n"
"%53 = OpVariable %52 Output\n"
"%55 = OpTypeStruct %30 %15 %49 %49\n"
"%56 = OpConstant %16 32\n"
"%57 = OpTypeArray %55 %56\n"
"%58 = OpTypePointer Input %57\n"
"%59 = OpVariable %58 Input\n"
"%61 = OpTypePointer Input %30\n"
"%64 = OpTypePointer Output %30\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"
"OpBranch %14\n"
"%14 = OpLabel\n"
"%27 = OpGroupNonUniformElect %11 %26\n"
"OpSelectionMerge %29 None\n"
"OpBranchConditional %27 %28 %42\n"
"%28 = OpLabel\n"
"%35 = OpLoad %6 %8\n"
"%38 = OpAccessChain %22 %34 %35 %37\n"
"OpStore %38 %36\n"
"%39 = OpLoad %6 %8\n"
"%41 = OpAccessChain %22 %34 %39 %40\n"
"OpStore %41 %21\n"
"OpBranch %29\n"
"%42 = OpLabel\n"
"%43 = OpLoad %6 %8\n"
"%45 = OpAccessChain %22 %34 %43 %37\n"
"OpStore %45 %44\n"
"%46 = OpLoad %6 %8\n"
"%48 = OpAccessChain %22 %34 %46 %40\n"
"OpStore %48 %47\n"
"OpBranch %29\n"
"%29 = OpLabel\n"
"%54 = OpLoad %6 %8\n"
"%60 = OpLoad %6 %8\n"
"%62 = OpAccessChain %61 %59 %60 %10\n"
"%63 = OpLoad %30 %62\n"
"%65 = OpAccessChain %64 %53 %54 %10\n"
"OpStore %65 %63\n"
"OpReturn\n"
"OpFunctionEnd\n";
programCollection.spirvAsmSources.add("tesc") << controlSource << buildOptionsSpr;
/*
"#extension GL_KHR_shader_subgroup_ballot: enable\n"
"#extension GL_EXT_tessellation_shader : require\n"
"layout(isolines, equal_spacing, ccw ) in;\n"
"layout(location = 0) in vec4 in_color[];\n"
"layout(location = 0) out vec4 out_color;\n"
"\n"
"void main (void)\n"
"{\n"
" gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n"
" out_color = in_color[0];\n"
"}\n";
*/
const string evaluationSource =
"; SPIR-V\n"
"; Version: 1.3\n"
"; Generator: Khronos Glslang Reference Front End; 2\n"
"; Bound: 44\n"
"; Schema: 0\n"
"OpCapability Tessellation\n"
"%1 = OpExtInstImport \"GLSL.std.450\"\n"
"OpMemoryModel Logical GLSL450\n"
"OpEntryPoint TessellationEvaluation %4 \"main\" %13 %20 %29 %38 %41\n"
"OpExecutionMode %4 Isolines\n"
"OpExecutionMode %4 SpacingEqual\n"
"OpExecutionMode %4 VertexOrderCcw\n"
"OpMemberDecorate %11 0 BuiltIn Position\n"
"OpMemberDecorate %11 1 BuiltIn PointSize\n"
"OpMemberDecorate %11 2 BuiltIn ClipDistance\n"
"OpMemberDecorate %11 3 BuiltIn CullDistance\n"
"OpDecorate %11 Block\n"
"OpMemberDecorate %16 0 BuiltIn Position\n"
"OpMemberDecorate %16 1 BuiltIn PointSize\n"
"OpMemberDecorate %16 2 BuiltIn ClipDistance\n"
"OpMemberDecorate %16 3 BuiltIn CullDistance\n"
"OpDecorate %16 Block\n"
"OpDecorate %29 BuiltIn TessCoord\n"
"OpDecorate %38 Location 0\n"
"OpDecorate %41 Location 0\n"
"%2 = OpTypeVoid\n"
"%3 = OpTypeFunction %2\n"
"%6 = OpTypeFloat 32\n"
"%7 = OpTypeVector %6 4\n"
"%8 = OpTypeInt 32 0\n"
"%9 = OpConstant %8 1\n"
"%10 = OpTypeArray %6 %9\n"
"%11 = OpTypeStruct %7 %6 %10 %10\n"
"%12 = OpTypePointer Output %11\n"
"%13 = OpVariable %12 Output\n"
"%14 = OpTypeInt 32 1\n"
"%15 = OpConstant %14 0\n"
"%16 = OpTypeStruct %7 %6 %10 %10\n"
"%17 = OpConstant %8 32\n"
"%18 = OpTypeArray %16 %17\n"
"%19 = OpTypePointer Input %18\n"
"%20 = OpVariable %19 Input\n"
"%21 = OpTypePointer Input %7\n"
"%24 = OpConstant %14 1\n"
"%27 = OpTypeVector %6 3\n"
"%28 = OpTypePointer Input %27\n"
"%29 = OpVariable %28 Input\n"
"%30 = OpConstant %8 0\n"
"%31 = OpTypePointer Input %6\n"
"%36 = OpTypePointer Output %7\n"
"%38 = OpVariable %36 Output\n"
"%39 = OpTypeArray %7 %17\n"
"%40 = OpTypePointer Input %39\n"
"%41 = OpVariable %40 Input\n"
"%4 = OpFunction %2 None %3\n"
"%5 = OpLabel\n"
"%22 = OpAccessChain %21 %20 %15 %15\n"
"%23 = OpLoad %7 %22\n"
"%25 = OpAccessChain %21 %20 %24 %15\n"
"%26 = OpLoad %7 %25\n"
"%32 = OpAccessChain %31 %29 %30\n"
"%33 = OpLoad %6 %32\n"
"%34 = OpCompositeConstruct %7 %33 %33 %33 %33\n"
"%35 = OpExtInst %7 %1 FMix %23 %26 %34\n"
"%37 = OpAccessChain %36 %13 %15\n"
"OpStore %37 %35\n"
"%42 = OpAccessChain %21 %41 %15\n"
"%43 = OpLoad %7 %42\n"
"OpStore %38 %43\n"
"OpReturn\n"
"OpFunctionEnd\n";
programCollection.spirvAsmSources.add("tese") << evaluationSource << buildOptionsSpr;
}
else
{
DE_FATAL("Unsupported shader stage");
}
}
else
{
std::ostringstream bdy;
string color = (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT == caseDef.shaderStage) ? "out_color[gl_InvocationID].b = 1.0f;\n" : "out_color.b = 1.0f;\n";
switch (caseDef.opType)
{
default:
DE_FATAL("Unhandled op type!");
break;
case OPTYPE_SUBGROUP_BARRIER:
case OPTYPE_SUBGROUP_MEMORY_BARRIER:
case OPTYPE_SUBGROUP_MEMORY_BARRIER_BUFFER:
{
bdy << " tempResult2 = tempBuffer[id];\n"
<< " if (subgroupElect())\n"
<< " {\n"
<< " tempResult = value;\n"
<< " " << color
<< " }\n"
<< " else\n"
<< " {\n"
<< " tempResult = tempBuffer[id];\n"
<< " }\n"
<< " " << getOpTypeName(caseDef.opType) << "();\n";
break;
}
case OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE:
bdy <<"tempResult2 = imageLoad(tempImage, ivec2(id, 0)).x;\n"
<< " if (subgroupElect())\n"
<< " {\n"
<< " tempResult = value;\n"
<< " " << color
<< " }\n"
<< " else\n"
<< " {\n"
<< " tempResult = imageLoad(tempImage, ivec2(id, 0)).x;\n"
<< " }\n"
<< " subgroupMemoryBarrierImage();\n";
break;
}
if (VK_SHADER_STAGE_FRAGMENT_BIT == caseDef.shaderStage)
{
std::ostringstream fragment;
fragment << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450)<<"\n"
<< "#extension GL_KHR_shader_subgroup_basic: enable\n"
<< "#extension GL_KHR_shader_subgroup_ballot: enable\n"
<< "layout(location = 0) out vec4 out_color;\n"
<< "\n"
<< "layout(set = 0, binding = 0) uniform Buffer1\n"
<< "{\n"
<< " uint tempBuffer["<<SHADER_BUFFER_SIZE/4ull<<"];\n"
<< "};\n"
<< "\n"
<< "layout(set = 0, binding = 1) uniform Buffer2\n"
<< "{\n"
<< " uint value;\n"
<< "};\n"
<< (OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType ? "layout(set = 0, binding = 2, r32ui) readonly uniform highp uimage2D tempImage;\n" : "\n")
<< "void main (void)\n"
<< "{\n"
<< " if (gl_HelperInvocation) return;\n"
<< " uint id = 0;\n"
<< " if (subgroupElect())\n"
<< " {\n"
<< " id = uint(gl_FragCoord.x);\n"
<< " }\n"
<< " id = subgroupBroadcastFirst(id);\n"
<< " uint localId = id;\n"
<< " uint tempResult = 0u;\n"
<< " uint tempResult2 = 0u;\n"
<< " out_color.b = 0.0f;\n"
<< bdy.str()
<< " out_color.r = float(tempResult);\n"
<< " out_color.g = float(value);\n"
<< " out_color.a = float(tempResult2);\n"
<< "}\n";
programCollection.glslSources.add("fragment")
<< glu::FragmentSource(fragment.str()) << buildOptions;
}
else if (VK_SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
{
std::ostringstream vertex;
vertex << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450)<<"\n"
<< "#extension GL_KHR_shader_subgroup_basic: enable\n"
<< "#extension GL_KHR_shader_subgroup_ballot: enable\n"
<<"\n"
<< "layout(location = 0) out vec4 out_color;\n"
<< "layout(location = 0) in highp vec4 in_position;\n"
<< "\n"
<< "layout(set = 0, binding = 0) uniform Buffer1\n"
<< "{\n"
<< " uint tempBuffer["<<SHADER_BUFFER_SIZE/4ull<<"];\n"
<< "};\n"
<< "\n"
<< "layout(set = 0, binding = 1) uniform Buffer2\n"
<< "{\n"
<< " uint value;\n"
<< "};\n"
<< (OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType ? "layout(set = 0, binding = 2, r32ui) readonly uniform highp uimage2D tempImage;\n" : "\n")
<< "void main (void)\n"
<< "{\n"
<< " uint id = 0;\n"
<< " if (subgroupElect())\n"
<< " {\n"
<< " id = gl_VertexIndex;\n"
<< " }\n"
<< " id = subgroupBroadcastFirst(id);\n"
<< " uint tempResult = 0u;\n"
<< " uint tempResult2 = 0u;\n"
<< " out_color.b = 0.0f;\n"
<< bdy.str()
<< " out_color.r = float(tempResult);\n"
<< " out_color.g = float(value);\n"
<< " out_color.a = float(tempResult2);\n"
<< " gl_Position = in_position;\n"
<< " gl_PointSize = 1.0f;\n"
<< "}\n";
programCollection.glslSources.add("vert")
<< glu::VertexSource(vertex.str()) << buildOptions;
}
else if (VK_SHADER_STAGE_GEOMETRY_BIT == caseDef.shaderStage)
{
std::ostringstream geometry;
geometry << "#version 450\n"
<< "#extension GL_KHR_shader_subgroup_ballot: enable\n"
<< "#extension GL_KHR_shader_subgroup_basic: enable\n"
<< "layout(points) in;\n"
<< "layout(points, max_vertices = 1) out;\n"
<< "layout(location = 0) out vec4 out_color;\n"
<< "layout(set = 0, binding = 0) uniform Buffer1\n"
<< "{\n"
<< " uint tempBuffer["<<SHADER_BUFFER_SIZE/4ull<<"];\n"
<< "};\n"
<< "\n"
<< "layout(set = 0, binding = 1) uniform Buffer2\n"
<< "{\n"
<< " uint value;\n"
<< "};\n"
<< (OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType ? "layout(set = 0, binding = 2, r32ui) readonly uniform highp uimage2D tempImage;\n" : "\n")
<< "void main (void)\n"
<< "{\n"
<< " uint id = 0;\n"
<< " if (subgroupElect())\n"
<< " {\n"
<< " id = gl_InvocationID;\n"
<< " }\n"
<< " id = subgroupBroadcastFirst(id);\n"
<< " uint tempResult = 0u;\n"
<< " uint tempResult2 = 0u;\n"
<< " out_color.b = 0.0f;\n"
<< bdy.str()
<< " out_color.r = float(tempResult);\n"
<< " out_color.g = float(value);\n"
<< " out_color.a = float(tempResult2);\n"
<< " gl_Position = gl_in[0].gl_Position;\n"
<< (*caseDef.geometryPointSizeSupported ? " gl_PointSize = gl_in[0].gl_PointSize;\n" : "" )
<< " EmitVertex();\n"
<< " EndPrimitive();\n"
<< "}\n";
programCollection.glslSources.add("geometry")
<< glu::GeometrySource(geometry.str()) << buildOptions;
}
else if (VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT == caseDef.shaderStage)
{
std::ostringstream controlSource;
std::ostringstream evaluationSource;
controlSource << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450)<<"\n"
<< "#extension GL_EXT_tessellation_shader : require\n"
<< "layout(vertices = 2) out;\n"
<< "void main (void)\n"
<< "{\n"
<< " if (gl_InvocationID == 0)\n"
<<" {\n"
<< " gl_TessLevelOuter[0] = 1.0f;\n"
<< " gl_TessLevelOuter[1] = 1.0f;\n"
<< " }\n"
<< " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
<< (*caseDef.geometryPointSizeSupported ? " gl_out[gl_InvocationID].gl_PointSize = gl_in[gl_InvocationID].gl_PointSize;\n" : "" )
<< "}\n";
evaluationSource << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450)<<"\n"
<< "#extension GL_KHR_shader_subgroup_basic: enable\n"
<< "#extension GL_KHR_shader_subgroup_ballot: enable\n"
<< "#extension GL_EXT_tessellation_shader : require\n"
<< "layout(isolines, equal_spacing, ccw ) in;\n"
<< "layout(location = 0) out vec4 out_color;\n"
<< "layout(set = 0, binding = 0) uniform Buffer1\n"
<< "{\n"
<< " uint tempBuffer["<<SHADER_BUFFER_SIZE/4ull<<"];\n"
<< "};\n"
<< "\n"
<< "layout(set = 0, binding = 1) uniform Buffer2\n"
<< "{\n"
<< " uint value;\n"
<< "};\n"
<< (OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType ? "layout(set = 0, binding = 2, r32ui) readonly uniform highp uimage2D tempImage;\n" : "\n")
<< "void main (void)\n"
<< "{\n"
<< " uint id = 0;\n"
<< " if (subgroupElect())\n"
<< " {\n"
<< " id = gl_PrimitiveID;\n"
<< " }\n"
<< " id = subgroupBroadcastFirst(id);\n"
<< " uint tempResult = 0u;\n"
<< " uint tempResult2 = 0u;\n"
<< " out_color.b = 0.0f;\n"
<< bdy.str()
<< " out_color.r = float(tempResult);\n"
<< " out_color.g = float(value);\n"
<< " out_color.a = float(tempResult2);\n"
<< " gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n"
<< (*caseDef.geometryPointSizeSupported ? " gl_PointSize = gl_in[0].gl_PointSize;\n" : "" )
<< "}\n";
programCollection.glslSources.add("tesc")
<< glu::TessellationControlSource(controlSource.str()) << buildOptions;
programCollection.glslSources.add("tese")
<< glu::TessellationEvaluationSource(evaluationSource.str()) << buildOptions;
}
else if (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT == caseDef.shaderStage)
{
std::ostringstream controlSource;
std::ostringstream evaluationSource;
controlSource << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450)<<"\n"
<< "#extension GL_KHR_shader_subgroup_basic: enable\n"
<< "#extension GL_KHR_shader_subgroup_ballot: enable\n"
<< "#extension GL_EXT_tessellation_shader : require\n"
<< "layout(vertices = 2) out;\n"
<< "layout(location = 0) out vec4 out_color[];\n"
<< "layout(set = 0, binding = 0) uniform Buffer1\n"
<< "{\n"
<< " uint tempBuffer["<<SHADER_BUFFER_SIZE/4ull<<"];\n"
<< "};\n"
<< "\n"
<< "layout(set = 0, binding = 1) uniform Buffer2\n"
<< "{\n"
<< " uint value;\n"
<< "};\n"
<< (OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType ? "layout(set = 0, binding = 2, r32ui) readonly uniform highp uimage2D tempImage;\n" : "\n")
<< "void main (void)\n"
<< "{\n"
<< " uint id = 0;\n"
<< " if (gl_InvocationID == 0)\n"
<<" {\n"
<< " gl_TessLevelOuter[0] = 1.0f;\n"
<< " gl_TessLevelOuter[1] = 1.0f;\n"
<< " }\n"
<< " if (subgroupElect())\n"
<< " {\n"
<< " id = gl_InvocationID;\n"
<< " }\n"
<< " id = subgroupBroadcastFirst(id);\n"
<< " uint tempResult = 0u;\n"
<< " uint tempResult2 = 0u;\n"
<< " out_color[gl_InvocationID].b = 0.0f;\n"
<< bdy.str()
<< " out_color[gl_InvocationID].r = float(tempResult);\n"
<< " out_color[gl_InvocationID].g = float(value);\n"
<< " out_color[gl_InvocationID].a = float(tempResult2);\n"
<< " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
<< (*caseDef.geometryPointSizeSupported ? " gl_out[gl_InvocationID].gl_PointSize = gl_in[gl_InvocationID].gl_PointSize;\n" : "" )
<< "}\n";
evaluationSource << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450)<<"\n"
<< "#extension GL_KHR_shader_subgroup_ballot: enable\n"
<< "#extension GL_EXT_tessellation_shader : require\n"
<< "layout(isolines, equal_spacing, ccw ) in;\n"
<< "layout(location = 0) in vec4 in_color[];\n"
<< "layout(location = 0) out vec4 out_color;\n"
<< "\n"
<< "void main (void)\n"
<< "{\n"
<< " gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n"
<< (*caseDef.geometryPointSizeSupported ? " gl_PointSize = gl_in[0].gl_PointSize;\n" : "" )
<< " out_color = in_color[0];\n"
<< "}\n";
programCollection.glslSources.add("tesc")
<< glu::TessellationControlSource(controlSource.str()) << buildOptions;
programCollection.glslSources.add("tese")
<< glu::TessellationEvaluationSource(evaluationSource.str()) << buildOptions;
}
else
{
DE_FATAL("Unsupported shader stage");
}
}
}
void initPrograms(SourceCollections& programCollection, CaseDefinition caseDef)
{
if (OPTYPE_ELECT == caseDef.opType)
{
if (VK_SHADER_STAGE_COMPUTE_BIT == caseDef.shaderStage)
{
std::ostringstream src;
src << "#version 450\n"
<< "#extension GL_KHR_shader_subgroup_basic: enable\n"
<< "layout (local_size_x_id = 0, local_size_y_id = 1, "
"local_size_z_id = 2) in;\n"
<< "layout(set = 0, binding = 0, std430) buffer Buffer1\n"
<< "{\n"
<< " uint result[];\n"
<< "};\n"
<< "\n"
<< subgroups::getSharedMemoryBallotHelper()
<< "void main (void)\n"
<< "{\n"
<< " uvec3 globalSize = gl_NumWorkGroups * gl_WorkGroupSize;\n"
<< " highp uint offset = globalSize.x * ((globalSize.y * "
"gl_GlobalInvocationID.z) + gl_GlobalInvocationID.y) + "
"gl_GlobalInvocationID.x;\n"
<< " uint value = " << UNELECTED_VALUE << ";\n"
<< " if (subgroupElect())\n"
<< " {\n"
<< " value = " << ELECTED_VALUE << ";\n"
<< " }\n"
<< " uvec4 bits = bitCount(sharedMemoryBallot(value == " << ELECTED_VALUE << "));\n"
<< " result[offset] = bits.x + bits.y + bits.z + bits.w;\n"
<< "}\n";
programCollection.glslSources.add("comp")
<< glu::ComputeSource(src.str()) << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_3, 0u);
}
else
{
std::ostringstream testSrc;
testSrc << " uint tempRes;\n"
<< " if (subgroupElect())\n"
<< " {\n"
<< " tempRes = " << ELECTED_VALUE << ";\n"
<< " atomicAdd(numSubgroupsExecuted, 1);\n"
<< " }\n"
<< " else\n"
<< " {\n"
<< " tempRes = " << UNELECTED_VALUE << ";\n"
<< " }\n";
{
std::ostringstream vertex;
vertex << "#version 450\n"
<< "#extension GL_KHR_shader_subgroup_basic: enable\n"
<< "layout(set = 0, binding = 0, std430) buffer Buffer1\n"
<< "{\n"
<< " uint result[];\n"
<< "};\n"
<< "layout(set = 0, binding = 4, std430) buffer Buffer2\n"
<< "{\n"
<< " uint numSubgroupsExecuted;\n"
<< "};\n"
<< "\n"
<< "void main (void)\n"
<< "{\n"
<< testSrc.str()
<< " result[gl_VertexIndex] = tempRes;\n"
<< " float pixelSize = 2.0f/1024.0f;\n"
<< " float pixelPosition = pixelSize/2.0f - 1.0f;\n"
<< " gl_Position = vec4(float(gl_VertexIndex) * pixelSize + pixelPosition, 0.0f, 0.0f, 1.0f);\n"
<< " gl_PointSize = 1.0f;\n"
<< "}\n";
programCollection.glslSources.add("vert")
<< glu::VertexSource(vertex.str()) << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_3, 0u);
}
{
std::ostringstream tesc;
tesc << "#version 450\n"
<< "#extension GL_KHR_shader_subgroup_basic: enable\n"
<< "layout(vertices=1) out;\n"
<< "layout(set = 0, binding = 1, std430) buffer Buffer1\n"
<< "{\n"
<< " uint result[];\n"
<< "};\n"
<< "layout(set = 0, binding = 5, std430) buffer Buffer2\n"
<< "{\n"
<< " uint numSubgroupsExecuted;\n"
<< "};\n"
<< "\n"
<< "void main (void)\n"
<< "{\n"
<< testSrc.str()
<< " result[gl_PrimitiveID] = tempRes;\n"
<< " if (gl_InvocationID == 0)\n"
<< " {\n"
<< " gl_TessLevelOuter[0] = 1.0f;\n"
<< " gl_TessLevelOuter[1] = 1.0f;\n"
<< " }\n"
<< " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
<< (*caseDef.geometryPointSizeSupported ? " gl_out[gl_InvocationID].gl_PointSize = gl_in[0].gl_PointSize;\n" : "" )
<< "}\n";
programCollection.glslSources.add("tesc")
<< glu::TessellationControlSource(tesc.str()) << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_3, 0u);
}
{
std::ostringstream tese;
tese << "#version 450\n"
<< "#extension GL_KHR_shader_subgroup_basic: enable\n"
<< "layout(isolines) in;\n"
<< "layout(set = 0, binding = 2, std430) buffer Buffer1\n"
<< "{\n"
<< " uint result[];\n"
<< "};\n"
<< "layout(set = 0, binding = 6, std430) buffer Buffer2\n"
<< "{\n"
<< " uint numSubgroupsExecuted;\n"
<< "};\n"
<< "\n"
<< "void main (void)\n"
<< "{\n"
<< testSrc.str()
<< " result[gl_PrimitiveID * 2 + uint(gl_TessCoord.x + 0.5)] = tempRes;\n"
<< " float pixelSize = 2.0f/1024.0f;\n"
<< " gl_Position = gl_in[0].gl_Position + gl_TessCoord.x * pixelSize / 2.0f;\n"
<< (*caseDef.geometryPointSizeSupported ? " gl_PointSize = gl_in[0].gl_PointSize;\n" : "" )
<< "}\n";
programCollection.glslSources.add("tese")
<< glu::TessellationEvaluationSource(tese.str()) << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_3, 0u);
}
{
std::ostringstream geometry;
geometry << "#version 450\n"
<< "#extension GL_KHR_shader_subgroup_basic: enable\n"
<< "layout(${TOPOLOGY}) in;\n"
<< "layout(points, max_vertices = 1) out;\n"
<< "layout(set = 0, binding = 3, std430) buffer Buffer1\n"
<< "{\n"
<< " uint result[];\n"
<< "};\n"
<< "layout(set = 0, binding = 7, std430) buffer Buffer2\n"
<< "{\n"
<< " uint numSubgroupsExecuted;\n"
<< "};\n"
<< "\n"
<< "void main (void)\n"
<< "{\n"
<< testSrc.str()
<< " result[gl_PrimitiveIDIn] = tempRes;\n"
<< " gl_Position = gl_in[0].gl_Position;\n"
<< (*caseDef.geometryPointSizeSupported ? " gl_PointSize = gl_in[0].gl_PointSize;\n" : "" )
<< " EmitVertex();\n"
<< " EndPrimitive();\n"
<< "}\n";
subgroups::addGeometryShadersFromTemplate(geometry.str(), vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_3, 0u),
programCollection.glslSources);
}
{
std::ostringstream fragment;
fragment << "#version 450\n"
<< "#extension GL_KHR_shader_subgroup_basic: enable\n"
<< "layout(location = 0) out uint data;\n"
<< "layout(set = 0, binding = 8, std430) buffer Buffer\n"
<< "{\n"
<< " uint numSubgroupsExecuted;\n"
<< "};\n"
<< "void main (void)\n"
<< "{\n"
<< " if (gl_HelperInvocation) return;\n"
<< testSrc.str()
<< " data = tempRes;\n"
<< "}\n";
programCollection.glslSources.add("fragment")
<< glu::FragmentSource(fragment.str())<< vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_3, 0u);
}
subgroups::addNoSubgroupShader(programCollection);
}
}
else
{
std::ostringstream bdy;
switch (caseDef.opType)
{
default:
DE_FATAL("Unhandled op type!");
break;
case OPTYPE_SUBGROUP_BARRIER:
case OPTYPE_SUBGROUP_MEMORY_BARRIER:
case OPTYPE_SUBGROUP_MEMORY_BARRIER_BUFFER:
bdy << " if (subgroupElect())\n"
<< " {\n"
<< " tempBuffer[id] = value;\n"
<< " }\n"
<< " " << getOpTypeName(caseDef.opType) << "();\n"
<< " tempResult = tempBuffer[id];\n";
break;
case OPTYPE_SUBGROUP_MEMORY_BARRIER_SHARED:
bdy << " if (subgroupElect())\n"
<< " {\n"
<< " tempShared[localId] = value;\n"
<< " }\n"
<< " subgroupMemoryBarrierShared();\n"
<< " tempResult = tempShared[localId];\n";
break;
case OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE:
bdy << " if (subgroupElect())\n"
<< " {\n"
<< " imageStore(tempImage, ivec2(id, 0), ivec4(value));\n"
<< " }\n"
<< " subgroupMemoryBarrierImage();\n"
<< " tempResult = imageLoad(tempImage, ivec2(id, 0)).x;\n";
break;
}
if (VK_SHADER_STAGE_COMPUTE_BIT == caseDef.shaderStage)
{
std::ostringstream src;
src << "#version 450\n"
<< "#extension GL_KHR_shader_subgroup_basic: enable\n"
<< "layout (local_size_x_id = 0, local_size_y_id = 1, "
"local_size_z_id = 2) in;\n"
<< "layout(set = 0, binding = 0, std430) buffer Buffer1\n"
<< "{\n"
<< " uint result[];\n"
<< "};\n"
<< "layout(set = 0, binding = 1, std430) buffer Buffer2\n"
<< "{\n"
<< " uint tempBuffer[];\n"
<< "};\n"
<< "layout(set = 0, binding = 2, std430) buffer Buffer3\n"
<< "{\n"
<< " uint value;\n"
<< "};\n"
<< "layout(set = 0, binding = 3, r32ui) uniform uimage2D tempImage;\n"
<< "shared uint tempShared[gl_WorkGroupSize.x * gl_WorkGroupSize.y * gl_WorkGroupSize.z];\n"
<< "\n"
<< "void main (void)\n"
<< "{\n"
<< " uvec3 globalSize = gl_NumWorkGroups * gl_WorkGroupSize;\n"
<< " highp uint offset = globalSize.x * ((globalSize.y * "
"gl_GlobalInvocationID.z) + gl_GlobalInvocationID.y) + "
"gl_GlobalInvocationID.x;\n"
<< " uint localId = gl_SubgroupID;\n"
<< " uint id = globalSize.x * ((globalSize.y * "
"gl_WorkGroupID.z) + gl_WorkGroupID.y) + "
"gl_WorkGroupID.x + localId;\n"
<< " uint tempResult = 0;\n"
<< bdy.str()
<< " result[offset] = tempResult;\n"
<< "}\n";
programCollection.glslSources.add("comp")
<< glu::ComputeSource(src.str()) << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_3, 0u);
}
else
{
{
const string vertex =
"#version 450\n"
"#extension GL_KHR_shader_subgroup_basic: enable\n"
"#extension GL_KHR_shader_subgroup_ballot: enable\n"
"layout(set = 0, binding = 0, std430) buffer Buffer1\n"
"{\n"
" uint result[];\n"
"};\n"
"layout(set = 0, binding = 4, std430) buffer Buffer2\n"
"{\n"
" uint tempBuffer[];\n"
"};\n"
"layout(set = 0, binding = 5, std430) buffer Buffer3\n"
"{\n"
" uint subgroupID;\n"
"};\n"
"layout(set = 0, binding = 6, std430) buffer Buffer4\n"
"{\n"
" uint value;\n"
"};\n"
"layout(set = 0, binding = 7, r32ui) uniform uimage2D tempImage;\n"
"void main (void)\n"
"{\n"
" uint id = 0;\n"
" if (subgroupElect())\n"
" {\n"
" id = atomicAdd(subgroupID, 1);\n"
" }\n"
" id = subgroupBroadcastFirst(id);\n"
" uint localId = id;\n"
" uint tempResult = 0;\n"
+ bdy.str() +
" result[gl_VertexIndex] = tempResult;\n"
" float pixelSize = 2.0f/1024.0f;\n"
" float pixelPosition = pixelSize/2.0f - 1.0f;\n"
" gl_Position = vec4(float(gl_VertexIndex) * pixelSize + pixelPosition, 0.0f, 0.0f, 1.0f);\n"
" gl_PointSize = 1.0f;\n"
"}\n";
programCollection.glslSources.add("vert")
<< glu::VertexSource(vertex) << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_3, 0u);
}
{
const string tesc =
"#version 450\n"
"#extension GL_KHR_shader_subgroup_basic: enable\n"
"#extension GL_KHR_shader_subgroup_ballot: enable\n"
"layout(vertices=1) out;\n"
"layout(set = 0, binding = 1, std430) buffer Buffer1\n"
"{\n"
" uint result[];\n"
"};\n"
"layout(set = 0, binding = 8, std430) buffer Buffer2\n"
"{\n"
" uint tempBuffer[];\n"
"};\n"
"layout(set = 0, binding = 9, std430) buffer Buffer3\n"
"{\n"
" uint subgroupID;\n"
"};\n"
"layout(set = 0, binding = 10, std430) buffer Buffer4\n"
"{\n"
" uint value;\n"
"};\n"
"layout(set = 0, binding = 11, r32ui) uniform uimage2D tempImage;\n"
"void main (void)\n"
"{\n"
" uint id = 0;\n"
" if (subgroupElect())\n"
" {\n"
" id = atomicAdd(subgroupID, 1);\n"
" }\n"
" id = subgroupBroadcastFirst(id);\n"
" uint localId = id;\n"
" uint tempResult = 0;\n"
+ bdy.str() +
" result[gl_PrimitiveID] = tempResult;\n"
" if (gl_InvocationID == 0)\n"
" {\n"
" gl_TessLevelOuter[0] = 1.0f;\n"
" gl_TessLevelOuter[1] = 1.0f;\n"
" }\n"
" gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
+ (*caseDef.geometryPointSizeSupported ? " gl_out[gl_InvocationID].gl_PointSize = gl_in[gl_InvocationID].gl_PointSize;\n" : "" )
+ "}\n";
programCollection.glslSources.add("tesc")
<< glu::TessellationControlSource(tesc) << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_3, 0u);
}
{
const string tese =
"#version 450\n"
"#extension GL_KHR_shader_subgroup_basic: enable\n"
"#extension GL_KHR_shader_subgroup_ballot: enable\n"
"layout(isolines) in;\n"
"layout(set = 0, binding = 2, std430) buffer Buffer1\n"
"{\n"
" uint result[];\n"
"};\n"
"layout(set = 0, binding = 12, std430) buffer Buffer2\n"
"{\n"
" uint tempBuffer[];\n"
"};\n"
"layout(set = 0, binding = 13, std430) buffer Buffer3\n"
"{\n"
" uint subgroupID;\n"
"};\n"
"layout(set = 0, binding = 14, std430) buffer Buffer4\n"
"{\n"
" uint value;\n"
"};\n"
"layout(set = 0, binding = 15, r32ui) uniform uimage2D tempImage;\n"
"void main (void)\n"
"{\n"
" uint id = 0;\n"
" if (subgroupElect())\n"
" {\n"
" id = atomicAdd(subgroupID, 1);\n"
" }\n"
" id = subgroupBroadcastFirst(id);\n"
" uint localId = id;\n"
" uint tempResult = 0;\n"
+ bdy.str() +
" result[gl_PrimitiveID * 2 + uint(gl_TessCoord.x + 0.5)] = tempResult;\n"
" float pixelSize = 2.0f/1024.0f;\n"
" gl_Position = gl_in[0].gl_Position + gl_TessCoord.x * pixelSize / 2.0f;\n"
+ (*caseDef.geometryPointSizeSupported ? " gl_PointSize = gl_in[0].gl_PointSize;\n" : "" )
+ "}\n";
programCollection.glslSources.add("tese")
<< glu::TessellationEvaluationSource(tese) << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_3, 0u);
}
{
const string geometry =
"#version 450\n"
"#extension GL_KHR_shader_subgroup_basic: enable\n"
"#extension GL_KHR_shader_subgroup_ballot: enable\n"
"layout(${TOPOLOGY}) in;\n"
"layout(points, max_vertices = 1) out;\n"
"layout(set = 0, binding = 3, std430) buffer Buffer1\n"
"{\n"
" uint result[];\n"
"};\n"
"layout(set = 0, binding = 16, std430) buffer Buffer2\n"
"{\n"
" uint tempBuffer[];\n"
"};\n"
"layout(set = 0, binding = 17, std430) buffer Buffer3\n"
"{\n"
" uint subgroupID;\n"
"};\n"
"layout(set = 0, binding = 18, std430) buffer Buffer4\n"
"{\n"
" uint value;\n"
"};\n"
"layout(set = 0, binding = 19, r32ui) uniform uimage2D tempImage;\n"
"void main (void)\n"
"{\n"
" uint id = 0;\n"
" if (subgroupElect())\n"
" {\n"
" id = atomicAdd(subgroupID, 1);\n"
" }\n"
" id = subgroupBroadcastFirst(id);\n"
" uint localId = id;\n"
" uint tempResult = 0;\n"
+ bdy.str() +
" result[gl_PrimitiveIDIn] = tempResult;\n"
" gl_Position = gl_in[0].gl_Position;\n"
+ (*caseDef.geometryPointSizeSupported ? " gl_PointSize = gl_in[0].gl_PointSize;\n" : "" ) +
" EmitVertex();\n"
" EndPrimitive();\n"
"}\n";
subgroups::addGeometryShadersFromTemplate(geometry, vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_3, 0u),
programCollection.glslSources);
}
{
const string fragment =
"#version 450\n"
"#extension GL_KHR_shader_subgroup_basic: enable\n"
"#extension GL_KHR_shader_subgroup_ballot: enable\n"
"layout(location = 0) out uint result;\n"
"layout(set = 0, binding = 20, std430) buffer Buffer1\n"
"{\n"
" uint tempBuffer[];\n"
"};\n"
"layout(set = 0, binding = 21, std430) buffer Buffer2\n"
"{\n"
" uint subgroupID;\n"
"};\n"
"layout(set = 0, binding = 22, std430) buffer Buffer3\n"
"{\n"
" uint value;\n"
"};\n"
"layout(set = 0, binding = 23, r32ui) uniform uimage2D tempImage;\n"
"void main (void)\n"
"{\n"
" if (gl_HelperInvocation) return;\n"
" uint id = 0;\n"
" if (subgroupElect())\n"
" {\n"
" id = atomicAdd(subgroupID, 1);\n"
" }\n"
" id = subgroupBroadcastFirst(id);\n"
" uint localId = id;\n"
" uint tempResult = 0;\n"
+ bdy.str() +
" result = tempResult;\n"
"}\n";
programCollection.glslSources.add("fragment")
<< glu::FragmentSource(fragment)<< vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_3, 0u);
}
subgroups::addNoSubgroupShader(programCollection);
}
}
}
void supportedCheck (Context& context, CaseDefinition caseDef)
{
DE_UNREF(caseDef);
if (!subgroups::isSubgroupSupported(context))
TCU_THROW(NotSupportedError, "Subgroup operations are not supported");
if (caseDef.requiredSubgroupSize)
{
if (!context.requireDeviceFunctionality("VK_EXT_subgroup_size_control"))
TCU_THROW(NotSupportedError, "Device does not support VK_EXT_subgroup_size_control extension");
VkPhysicalDeviceSubgroupSizeControlFeaturesEXT subgroupSizeControlFeatures;
subgroupSizeControlFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT;
subgroupSizeControlFeatures.pNext = DE_NULL;
VkPhysicalDeviceFeatures2 features;
features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
features.pNext = &subgroupSizeControlFeatures;
context.getInstanceInterface().getPhysicalDeviceFeatures2(context.getPhysicalDevice(), &features);
if (subgroupSizeControlFeatures.subgroupSizeControl == DE_FALSE)
TCU_THROW(NotSupportedError, "Device does not support varying subgroup sizes nor required subgroup size");
if (subgroupSizeControlFeatures.computeFullSubgroups == DE_FALSE)
TCU_THROW(NotSupportedError, "Device does not support full subgroups in compute shaders");
VkPhysicalDeviceSubgroupSizeControlPropertiesEXT subgroupSizeControlProperties;
subgroupSizeControlProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES_EXT;
subgroupSizeControlProperties.pNext = DE_NULL;
VkPhysicalDeviceProperties2 properties;
properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
properties.pNext = &subgroupSizeControlProperties;
context.getInstanceInterface().getPhysicalDeviceProperties2(context.getPhysicalDevice(), &properties);
if ((subgroupSizeControlProperties.requiredSubgroupSizeStages & caseDef.shaderStage) != caseDef.shaderStage)
TCU_THROW(NotSupportedError, "Required subgroup size is not supported for shader stage");
}
*caseDef.geometryPointSizeSupported = subgroups::isTessellationAndGeometryPointSizeSupported(context);
}
tcu::TestStatus noSSBOtest (Context& context, const CaseDefinition caseDef)
{
if (!subgroups::areSubgroupOperationsSupportedForStage(
context, caseDef.shaderStage))
{
if (subgroups::areSubgroupOperationsRequiredForStage(
caseDef.shaderStage))
{
return tcu::TestStatus::fail(
"Shader stage " +
subgroups::getShaderStageName(caseDef.shaderStage) +
" is required to support subgroup operations!");
}
else
{
TCU_THROW(NotSupportedError, "Device does not support subgroup operations for this stage");
}
}
if (!subgroups::isSubgroupFeatureSupportedForDevice(context, VK_SUBGROUP_FEATURE_BASIC_BIT))
{
return tcu::TestStatus::fail(
"Subgroup feature " +
subgroups::getSubgroupFeatureName(VK_SUBGROUP_FEATURE_BASIC_BIT) +
" is a required capability!");
}
if (OPTYPE_ELECT != caseDef.opType && VK_SHADER_STAGE_COMPUTE_BIT != caseDef.shaderStage)
{
if (!subgroups::isSubgroupFeatureSupportedForDevice(context, VK_SUBGROUP_FEATURE_BALLOT_BIT))
{
TCU_THROW(NotSupportedError, "Subgroup basic operation non-compute stage test required that ballot operations are supported!");
}
}
const deUint32 inputDatasCount = OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType ? 3u : 2u;
std::vector<subgroups::SSBOData> inputDatas (inputDatasCount);
inputDatas[0].format = VK_FORMAT_R32_UINT;
inputDatas[0].layout = subgroups::SSBOData::LayoutStd140;
inputDatas[0].numElements = SHADER_BUFFER_SIZE/4ull;
inputDatas[0].initializeType = subgroups::SSBOData::InitializeNonZero;
inputDatas[1].format = VK_FORMAT_R32_UINT;
inputDatas[1].layout = subgroups::SSBOData::LayoutStd140;
inputDatas[1].numElements = 1ull;
inputDatas[1].initializeType = subgroups::SSBOData::InitializeNonZero;
if(OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType )
{
inputDatas[2].format = VK_FORMAT_R32_UINT;
inputDatas[2].layout = subgroups::SSBOData::LayoutPacked;
inputDatas[2].numElements = SHADER_BUFFER_SIZE;
inputDatas[2].initializeType = subgroups::SSBOData::InitializeNone;
inputDatas[2].isImage = true;
}
if (VK_SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
{
if (OPTYPE_ELECT == caseDef.opType)
return subgroups::makeVertexFrameBufferTest(context, VK_FORMAT_R32G32_SFLOAT, DE_NULL, 0u, DE_NULL, checkVertexPipelineStagesSubgroupElectNoSSBO);
else
return subgroups::makeVertexFrameBufferTest(context, VK_FORMAT_R32G32B32A32_SFLOAT, &inputDatas[0], inputDatasCount, DE_NULL,
(OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType) ?
checkVertexPipelineStagesSubgroupBarriersWithImageNoSSBO :
checkVertexPipelineStagesSubgroupBarriersNoSSBO
);
}
else if (VK_SHADER_STAGE_FRAGMENT_BIT == caseDef.shaderStage)
{
return subgroups::makeFragmentFrameBufferTest(context, VK_FORMAT_R32G32B32A32_SFLOAT, &inputDatas[0], inputDatasCount, DE_NULL,
(OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType) ?
checkFragmentSubgroupBarriersWithImageNoSSBO :
checkFragmentSubgroupBarriersNoSSBO
);
}
else if (VK_SHADER_STAGE_GEOMETRY_BIT == caseDef.shaderStage)
{
if (OPTYPE_ELECT == caseDef.opType)
return subgroups::makeGeometryFrameBufferTest(context, VK_FORMAT_R32G32_SFLOAT, DE_NULL, 0u, DE_NULL, checkVertexPipelineStagesSubgroupElectNoSSBO);
else
return subgroups::makeGeometryFrameBufferTest(context, VK_FORMAT_R32G32B32A32_SFLOAT, &inputDatas[0], inputDatasCount, DE_NULL,
(OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType) ?
checkVertexPipelineStagesSubgroupBarriersWithImageNoSSBO :
checkVertexPipelineStagesSubgroupBarriersNoSSBO
);
}
if (OPTYPE_ELECT == caseDef.opType)
return subgroups::makeTessellationEvaluationFrameBufferTest(context, VK_FORMAT_R32G32_SFLOAT, DE_NULL, 0u, DE_NULL, checkVertexPipelineStagesSubgroupElectNoSSBO, caseDef.shaderStage);
return subgroups::makeTessellationEvaluationFrameBufferTest(context, VK_FORMAT_R32G32B32A32_SFLOAT, &inputDatas[0], inputDatasCount, DE_NULL,
(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT == caseDef.shaderStage) ?
((OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType) ?
checkVertexPipelineStagesSubgroupBarriersWithImageNoSSBO :
checkVertexPipelineStagesSubgroupBarriersNoSSBO) :
((OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType) ?
checkTessellationEvaluationSubgroupBarriersWithImageNoSSBO :
checkTessellationEvaluationSubgroupBarriersNoSSBO),
caseDef.shaderStage);
}
tcu::TestStatus test(Context& context, const CaseDefinition caseDef)
{
if (!subgroups::isSubgroupFeatureSupportedForDevice(context, VK_SUBGROUP_FEATURE_BASIC_BIT))
{
return tcu::TestStatus::fail(
"Subgroup feature " +
subgroups::getSubgroupFeatureName(VK_SUBGROUP_FEATURE_BASIC_BIT) +
" is a required capability!");
}
if (OPTYPE_ELECT != caseDef.opType && VK_SHADER_STAGE_COMPUTE_BIT != caseDef.shaderStage)
{
if (!subgroups::isSubgroupFeatureSupportedForDevice(context, VK_SUBGROUP_FEATURE_BALLOT_BIT))
{
TCU_THROW(NotSupportedError, "Subgroup basic operation non-compute stage test required that ballot operations are supported!");
}
}
if (VK_SHADER_STAGE_COMPUTE_BIT == caseDef.shaderStage)
{
if (!subgroups::areSubgroupOperationsSupportedForStage(context, caseDef.shaderStage))
{
return tcu::TestStatus::fail("Shader stage " +
subgroups::getShaderStageName(caseDef.shaderStage) +
" is required to support subgroup operations!");
}
if (OPTYPE_ELECT == caseDef.opType)
{
if (caseDef.requiredSubgroupSize == DE_FALSE)
return subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, DE_NULL, 0, DE_NULL, checkComputeSubgroupElect);
tcu::TestLog& log = context.getTestContext().getLog();
VkPhysicalDeviceSubgroupSizeControlPropertiesEXT subgroupSizeControlProperties;
subgroupSizeControlProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES_EXT;
subgroupSizeControlProperties.pNext = DE_NULL;
VkPhysicalDeviceProperties2 properties;
properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
properties.pNext = &subgroupSizeControlProperties;
context.getInstanceInterface().getPhysicalDeviceProperties2(context.getPhysicalDevice(), &properties);
log << tcu::TestLog::Message << "Testing required subgroup size range [" << subgroupSizeControlProperties.minSubgroupSize << ", "
<< subgroupSizeControlProperties.maxSubgroupSize << "]" << tcu::TestLog::EndMessage;
// According to the spec, requiredSubgroupSize must be a power-of-two integer.
for (deUint32 size = subgroupSizeControlProperties.minSubgroupSize; size <= subgroupSizeControlProperties.maxSubgroupSize; size *= 2)
{
tcu::TestStatus result = subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, DE_NULL, 0u, DE_NULL, checkComputeSubgroupElect,
size, VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT);
if (result.getCode() != QP_TEST_RESULT_PASS)
{
log << tcu::TestLog::Message << "subgroupSize " << size << " failed" << tcu::TestLog::EndMessage;
return result;
}
}
return tcu::TestStatus::pass("OK");
}
else
{
const deUint32 inputDatasCount = 3;
subgroups::SSBOData inputDatas[inputDatasCount];
inputDatas[0].format = VK_FORMAT_R32_UINT;
inputDatas[0].layout = subgroups::SSBOData::LayoutStd430;
inputDatas[0].numElements = SHADER_BUFFER_SIZE;
inputDatas[0].initializeType = subgroups::SSBOData::InitializeNone;
inputDatas[1].format = VK_FORMAT_R32_UINT;
inputDatas[1].layout = subgroups::SSBOData::LayoutStd430;
inputDatas[1].numElements = 1;
inputDatas[1].initializeType = subgroups::SSBOData::InitializeNonZero;
inputDatas[2].format = VK_FORMAT_R32_UINT;
inputDatas[2].layout = subgroups::SSBOData::LayoutPacked;
inputDatas[2].numElements = SHADER_BUFFER_SIZE;
inputDatas[2].initializeType = subgroups::SSBOData::InitializeNone;
inputDatas[2].isImage = true;
if (caseDef.requiredSubgroupSize == DE_FALSE)
return subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, inputDatas, inputDatasCount, DE_NULL, checkComputeSubgroupBarriers);
tcu::TestLog& log = context.getTestContext().getLog();
VkPhysicalDeviceSubgroupSizeControlPropertiesEXT subgroupSizeControlProperties;
subgroupSizeControlProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES_EXT;
subgroupSizeControlProperties.pNext = DE_NULL;
VkPhysicalDeviceProperties2 properties;
properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
properties.pNext = &subgroupSizeControlProperties;
context.getInstanceInterface().getPhysicalDeviceProperties2(context.getPhysicalDevice(), &properties);
log << tcu::TestLog::Message << "Testing required subgroup size range [" << subgroupSizeControlProperties.minSubgroupSize << ", "
<< subgroupSizeControlProperties.maxSubgroupSize << "]" << tcu::TestLog::EndMessage;
// According to the spec, requiredSubgroupSize must be a power-of-two integer.
for (deUint32 size = subgroupSizeControlProperties.minSubgroupSize; size <= subgroupSizeControlProperties.maxSubgroupSize; size *= 2)
{
tcu::TestStatus result = subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, inputDatas, inputDatasCount, DE_NULL, checkComputeSubgroupBarriers,
size, VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT);
if (result.getCode() != QP_TEST_RESULT_PASS)
{
log << tcu::TestLog::Message << "subgroupSize " << size << " failed" << tcu::TestLog::EndMessage;
return result;
}
}
return tcu::TestStatus::pass("OK");
}
}
else
{
if (!subgroups::isFragmentSSBOSupportedForDevice(context))
{
TCU_THROW(NotSupportedError, "Subgroup basic operation require that the fragment stage be able to write to SSBOs!");
}
VkPhysicalDeviceSubgroupProperties subgroupProperties;
subgroupProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
subgroupProperties.pNext = DE_NULL;
VkPhysicalDeviceProperties2 properties;
properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
properties.pNext = &subgroupProperties;
context.getInstanceInterface().getPhysicalDeviceProperties2(context.getPhysicalDevice(), &properties);
VkShaderStageFlagBits stages = (VkShaderStageFlagBits)(caseDef.shaderStage & subgroupProperties.supportedStages);
if ( VK_SHADER_STAGE_FRAGMENT_BIT != stages && !subgroups::isVertexSSBOSupportedForDevice(context))
{
if ( (stages & VK_SHADER_STAGE_FRAGMENT_BIT) == 0)
TCU_THROW(NotSupportedError, "Device does not support vertex stage SSBO writes");
else
stages = VK_SHADER_STAGE_FRAGMENT_BIT;
}
if ((VkShaderStageFlagBits)0u == stages)
TCU_THROW(NotSupportedError, "Subgroup operations are not supported for any graphic shader");
if (OPTYPE_ELECT == caseDef.opType)
{
const deUint32 inputCount = 5u;
subgroups::SSBOData inputData[inputCount];
inputData[0].format = VK_FORMAT_R32_UINT;
inputData[0].layout = subgroups::SSBOData::LayoutStd430;
inputData[0].numElements = 1;
inputData[0].initializeType = subgroups::SSBOData::InitializeZero;
inputData[0].binding = 4u;
inputData[0].stages = VK_SHADER_STAGE_VERTEX_BIT;
inputData[1].format = VK_FORMAT_R32_UINT;
inputData[1].layout = subgroups::SSBOData::LayoutStd430;
inputData[1].numElements = 1;
inputData[1].initializeType = subgroups::SSBOData::InitializeZero;
inputData[1].binding = 5u;
inputData[1].stages = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
inputData[2].format = VK_FORMAT_R32_UINT;
inputData[2].layout = subgroups::SSBOData::LayoutStd430;
inputData[2].numElements = 1;
inputData[2].initializeType = subgroups::SSBOData::InitializeZero;
inputData[2].binding = 6u;
inputData[2].stages = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
inputData[3].format = VK_FORMAT_R32_UINT;
inputData[3].layout = subgroups::SSBOData::LayoutStd430;
inputData[3].numElements = 1;
inputData[3].initializeType = subgroups::SSBOData::InitializeZero;
inputData[3].binding = 7u;
inputData[3].stages = VK_SHADER_STAGE_GEOMETRY_BIT;
inputData[4].format = VK_FORMAT_R32_UINT;
inputData[4].layout = subgroups::SSBOData::LayoutStd430;
inputData[4].numElements = 1;
inputData[4].initializeType = subgroups::SSBOData::InitializeZero;
inputData[4].binding = 8u;
inputData[4].stages = VK_SHADER_STAGE_FRAGMENT_BIT;
return subgroups::allStages(context, VK_FORMAT_R32_UINT, inputData, inputCount, DE_NULL, checkVertexPipelineStagesSubgroupElect, stages);
}
else
{
const VkShaderStageFlagBits stagesBits[] =
{
VK_SHADER_STAGE_VERTEX_BIT,
VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
VK_SHADER_STAGE_GEOMETRY_BIT,
VK_SHADER_STAGE_FRAGMENT_BIT,
};
const deUint32 inputDatasCount = DE_LENGTH_OF_ARRAY(stagesBits) * 4u;
subgroups::SSBOData inputDatas[inputDatasCount];
for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(stagesBits); ++ndx)
{
const deUint32 index = ndx*4;
inputDatas[index].format = VK_FORMAT_R32_UINT;
inputDatas[index].layout = subgroups::SSBOData::LayoutStd430;
inputDatas[index].numElements = SHADER_BUFFER_SIZE;
inputDatas[index].initializeType = subgroups::SSBOData::InitializeNonZero;
inputDatas[index].binding = index + 4u;
inputDatas[index].stages = stagesBits[ndx];
inputDatas[index + 1].format = VK_FORMAT_R32_UINT;
inputDatas[index + 1].layout = subgroups::SSBOData::LayoutStd430;
inputDatas[index + 1].numElements = 1;
inputDatas[index + 1].initializeType = subgroups::SSBOData::InitializeZero;
inputDatas[index + 1].binding = index + 5u;
inputDatas[index + 1].stages = stagesBits[ndx];
inputDatas[index + 2].format = VK_FORMAT_R32_UINT;
inputDatas[index + 2].layout = subgroups::SSBOData::LayoutStd430;
inputDatas[index + 2].numElements = 1;
inputDatas[index + 2].initializeType = subgroups::SSBOData::InitializeNonZero;
inputDatas[index + 2].binding = index + 6u;
inputDatas[index + 2].stages = stagesBits[ndx];
inputDatas[index + 3].format = VK_FORMAT_R32_UINT;
inputDatas[index + 3].layout = subgroups::SSBOData::LayoutStd430;
inputDatas[index + 3].numElements = SHADER_BUFFER_SIZE;
inputDatas[index + 3].initializeType = subgroups::SSBOData::InitializeNone;
inputDatas[index + 3].isImage = true;
inputDatas[index + 3].binding = index + 7u;
inputDatas[index + 3].stages = stagesBits[ndx];
}
return subgroups::allStages(context, VK_FORMAT_R32_UINT, inputDatas, inputDatasCount, DE_NULL, checkVertexPipelineStagesSubgroupBarriers, stages);
}
}
}
}
namespace vkt
{
namespace subgroups
{
tcu::TestCaseGroup* createSubgroupsBasicTests(tcu::TestContext& testCtx)
{
de::MovePtr<tcu::TestCaseGroup> graphicGroup(new tcu::TestCaseGroup(
testCtx, "graphics", "Subgroup basic category tests: graphics"));
de::MovePtr<tcu::TestCaseGroup> computeGroup(new tcu::TestCaseGroup(
testCtx, "compute", "Subgroup basic category tests: compute"));
de::MovePtr<tcu::TestCaseGroup> framebufferGroup(new tcu::TestCaseGroup(
testCtx, "framebuffer", "Subgroup basic category tests: framebuffer"));
const VkShaderStageFlags stages[] =
{
VK_SHADER_STAGE_FRAGMENT_BIT,
VK_SHADER_STAGE_VERTEX_BIT,
VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
VK_SHADER_STAGE_GEOMETRY_BIT,
};
for (int opTypeIndex = 0; opTypeIndex < OPTYPE_LAST; ++opTypeIndex)
{
const std::string op = de::toLower(getOpTypeName(opTypeIndex));
{
CaseDefinition caseDef = {opTypeIndex, VK_SHADER_STAGE_COMPUTE_BIT, de::SharedPtr<bool>(new bool), DE_FALSE};
addFunctionCaseWithPrograms(computeGroup.get(), op, "",
supportedCheck, initPrograms, test, caseDef);
caseDef.requiredSubgroupSize = DE_TRUE;
addFunctionCaseWithPrograms(computeGroup.get(), op + "_requiredsubgroupsize", "",
supportedCheck, initPrograms, test, caseDef);
}
if (OPTYPE_SUBGROUP_MEMORY_BARRIER_SHARED == opTypeIndex)
{
// Shared isn't available in non compute shaders.
continue;
}
{
const CaseDefinition caseDef = {opTypeIndex, VK_SHADER_STAGE_ALL_GRAPHICS, de::SharedPtr<bool>(new bool), DE_FALSE};
addFunctionCaseWithPrograms(graphicGroup.get(),
op, "",
supportedCheck, initPrograms, test, caseDef);
}
for (int stageIndex = 0; stageIndex < DE_LENGTH_OF_ARRAY(stages); ++stageIndex)
{
if (OPTYPE_ELECT == opTypeIndex && stageIndex == 0)
continue; // This is not tested. I don't know why.
const CaseDefinition caseDefFrag = {opTypeIndex, stages[stageIndex], de::SharedPtr<bool>(new bool), DE_FALSE};
addFunctionCaseWithPrograms(framebufferGroup.get(),
op + "_" + getShaderStageName(caseDefFrag.shaderStage), "",
supportedCheck, initFrameBufferPrograms, noSSBOtest, caseDefFrag);
}
}
de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(
testCtx, "basic", "Subgroup basic category tests"));
group->addChild(graphicGroup.release());
group->addChild(computeGroup.release());
group->addChild(framebufferGroup.release());
return group.release();
}
} // subgroups
} // vkt