/*------------------------------------------------------------------------ * OpenGL Conformance Tests * ------------------------ * * Copyright (c) 2017-2019 The Khronos Group Inc. * Copyright (c) 2017 Codeplay Software Ltd. * Copyright (c) 2019 NVIDIA 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 Subgroups Tests */ /*--------------------------------------------------------------------*/ #include "glcSubgroupsBallotBroadcastTests.hpp" #include "glcSubgroupsTestsUtils.hpp" #include #include using namespace tcu; using namespace std; namespace glc { namespace subgroups { namespace { enum OpType { OPTYPE_BROADCAST = 0, OPTYPE_BROADCAST_FIRST, OPTYPE_LAST }; static bool checkVertexPipelineStages(std::vector datas, deUint32 width, deUint32) { return glc::subgroups::check(datas, width, 3); } static bool checkComputeStages(std::vector datas, const deUint32 numWorkgroups[3], const deUint32 localSize[3], deUint32) { return glc::subgroups::checkCompute(datas, numWorkgroups, localSize, 3); } std::string getOpTypeName(int opType) { switch (opType) { default: DE_FATAL("Unsupported op type"); return ""; case OPTYPE_BROADCAST: return "subgroupBroadcast"; case OPTYPE_BROADCAST_FIRST: return "subgroupBroadcastFirst"; } } struct CaseDefinition { int opType; ShaderStageFlags shaderStage; Format format; }; std::string getBodySource(CaseDefinition caseDef) { std::ostringstream bdy; bdy << " uvec4 mask = subgroupBallot(true);\n"; bdy << " uint tempResult = 0u;\n"; if (OPTYPE_BROADCAST == caseDef.opType) { bdy << " tempResult = 0x3u;\n"; for (int i = 0; i < (int)subgroups::maxSupportedSubgroupSize(); i++) { bdy << " {\n" << " const uint id = "<< i << "u;\n" << " " << subgroups::getFormatNameForGLSL(caseDef.format) << " op = subgroupBroadcast(data1[gl_SubgroupInvocationID], id);\n" << " if ((id < gl_SubgroupSize) && subgroupBallotBitExtract(mask, id))\n" << " {\n" << " if (op != data1[id])\n" << " {\n" << " tempResult = 0u;\n" << " }\n" << " }\n" << " }\n"; } } else { bdy << " uint firstActive = 0u;\n" << " for (uint i = 0u; i < gl_SubgroupSize; i++)\n" << " {\n" << " if (subgroupBallotBitExtract(mask, i))\n" << " {\n" << " firstActive = i;\n" << " break;\n" << " }\n" << " }\n" << " tempResult |= (subgroupBroadcastFirst(data1[gl_SubgroupInvocationID]) == data1[firstActive]) ? 0x1u : 0u;\n" << " // make the firstActive invocation inactive now\n" << " if (firstActive == gl_SubgroupInvocationID)\n" << " {\n" << " for (uint i = 0u; i < gl_SubgroupSize; i++)\n" << " {\n" << " if (subgroupBallotBitExtract(mask, i))\n" << " {\n" << " firstActive = i;\n" << " break;\n" << " }\n" << " }\n" << " tempResult |= (subgroupBroadcastFirst(data1[gl_SubgroupInvocationID]) == data1[firstActive]) ? 0x2u : 0u;\n" << " }\n" << " else\n" << " {\n" << " // the firstActive invocation didn't partake in the second result so set it to true\n" << " tempResult |= 0x2u;\n" << " }\n"; } return bdy.str(); } void initFrameBufferPrograms(SourceCollections& programCollection, CaseDefinition caseDef) { subgroups::setFragmentShaderFrameBuffer(programCollection); if (SHADER_STAGE_VERTEX_BIT != caseDef.shaderStage) subgroups::setVertexShaderFrameBuffer(programCollection); std::string bdyStr = getBodySource(caseDef); if (SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage) { std::ostringstream vertex; vertex << "${VERSION_DECL}\n" << "#extension GL_KHR_shader_subgroup_ballot: enable\n" << "layout(location = 0) in highp vec4 in_position;\n" << "layout(location = 0) out float out_color;\n" << "layout(binding = 0, std140) uniform Buffer0\n" << "{\n" << " " << subgroups::getFormatNameForGLSL(caseDef.format) << " data1[" << subgroups::maxSupportedSubgroupSize() << "];\n" << "};\n" << "\n" << "void main (void)\n" << "{\n" << bdyStr << " out_color = float(tempResult);\n" << " gl_Position = in_position;\n" << " gl_PointSize = 1.0f;\n" << "}\n"; programCollection.add("vert") << glu::VertexSource(vertex.str()); } else if (SHADER_STAGE_GEOMETRY_BIT == caseDef.shaderStage) { std::ostringstream geometry; geometry << "${VERSION_DECL}\n" << "#extension GL_KHR_shader_subgroup_ballot: enable\n" << "layout(points) in;\n" << "layout(points, max_vertices = 1) out;\n" << "layout(location = 0) out float out_color;\n" << "layout(binding = 0, std140) uniform Buffer0\n" << "{\n" << " " << subgroups::getFormatNameForGLSL(caseDef.format) << " data1[" < graphicGroup(new deqp::TestCaseGroup( testCtx, "graphics", "Subgroup ballot broadcast category tests: graphics")); de::MovePtr computeGroup(new deqp::TestCaseGroup( testCtx, "compute", "Subgroup ballot broadcast category tests: compute")); de::MovePtr framebufferGroup(new deqp::TestCaseGroup( testCtx, "framebuffer", "Subgroup ballot broadcast category tests: framebuffer")); const ShaderStageFlags stages[] = { SHADER_STAGE_VERTEX_BIT, SHADER_STAGE_TESS_EVALUATION_BIT, SHADER_STAGE_TESS_CONTROL_BIT, SHADER_STAGE_GEOMETRY_BIT, }; const Format formats[] = { FORMAT_R32_SINT, FORMAT_R32G32_SINT, FORMAT_R32G32B32_SINT, FORMAT_R32G32B32A32_SINT, FORMAT_R32_UINT, FORMAT_R32G32_UINT, FORMAT_R32G32B32_UINT, FORMAT_R32G32B32A32_UINT, FORMAT_R32_SFLOAT, FORMAT_R32G32_SFLOAT, FORMAT_R32G32B32_SFLOAT, FORMAT_R32G32B32A32_SFLOAT, FORMAT_R64_SFLOAT, FORMAT_R64G64_SFLOAT, FORMAT_R64G64B64_SFLOAT, FORMAT_R64G64B64A64_SFLOAT, FORMAT_R32_BOOL, FORMAT_R32G32_BOOL, FORMAT_R32G32B32_BOOL, FORMAT_R32G32B32A32_BOOL, }; for (int formatIndex = 0; formatIndex < DE_LENGTH_OF_ARRAY(formats); ++formatIndex) { const Format format = formats[formatIndex]; for (int opTypeIndex = 0; opTypeIndex < OPTYPE_LAST; ++opTypeIndex) { const std::string op = de::toLower(getOpTypeName(opTypeIndex)); const std::string name = op + "_" + subgroups::getFormatNameForGLSL(format); { CaseDefinition caseDef = {opTypeIndex, SHADER_STAGE_COMPUTE_BIT, format}; SubgroupFactory::addFunctionCaseWithPrograms(computeGroup.get(), name, "", supportedCheck, initPrograms, test, caseDef); } { const CaseDefinition caseDef = {opTypeIndex, SHADER_STAGE_ALL_GRAPHICS, format}; SubgroupFactory::addFunctionCaseWithPrograms(graphicGroup.get(), name, "", supportedCheck, initPrograms, test, caseDef); } for (int stageIndex = 0; stageIndex < DE_LENGTH_OF_ARRAY(stages); ++stageIndex) { const CaseDefinition caseDef = {opTypeIndex, stages[stageIndex], format}; SubgroupFactory::addFunctionCaseWithPrograms(framebufferGroup.get(), name + getShaderStageName(caseDef.shaderStage), "", supportedCheck, initFrameBufferPrograms, noSSBOtest, caseDef); } } } de::MovePtr group(new deqp::TestCaseGroup( testCtx, "ballot_broadcast", "Subgroup ballot broadcast category tests")); group->addChild(graphicGroup.release()); group->addChild(computeGroup.release()); group->addChild(framebufferGroup.release()); return group.release(); } } // subgroups } // glc