1/*------------------------------------------------------------------------- 2* OpenGL Conformance Test Suite 3* ----------------------------- 4* 5* Copyright (c) 2017 The Khronos Group Inc. 6* 7* Licensed under the Apache License, Version 2.0 (the "License"); 8* you may not use this file except in compliance with the License. 9* You may obtain a copy of the License at 10* 11* http://www.apache.org/licenses/LICENSE-2.0 12* 13* Unless required by applicable law or agreed to in writing, software 14* distributed under the License is distributed on an "AS IS" BASIS, 15* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16* See the License for the specific language governing permissions and 17* limitations under the License. 18* 19*/ /*! 20* \file glcShaderGroupVoteTests.cpp 21* \brief Conformance tests for the ARB_shader_group_vote functionality. 22*/ /*-------------------------------------------------------------------*/ 23 24#include "glcShaderGroupVoteTests.hpp" 25#include "gluContextInfo.hpp" 26#include "gluDefs.hpp" 27#include "gluDrawUtil.hpp" 28#include "gluObjectWrapper.hpp" 29#include "gluShaderProgram.hpp" 30#include "glwEnums.hpp" 31#include "glwFunctions.hpp" 32#include "tcuRenderTarget.hpp" 33#include "tcuTestLog.hpp" 34 35using namespace glw; 36 37namespace glcts 38{ 39 40// Helper structure that wpraps workgroup size 41struct WorkGroupSize 42{ 43 WorkGroupSize(deqp::Context& context) 44 { 45 width = 16; 46 height = 16; 47 if (glu::isContextTypeES(context.getRenderContext().getType())) 48 height = 8; 49 } 50 51 GLsizei width; 52 GLsizei height; 53}; 54 55ShaderGroupVoteTestCaseBase::ComputeShader::ComputeShader(const std::string& name, const std::string& shader) 56 : m_name(name), m_shader(shader), m_program(NULL), m_compileOnly(true) 57{ 58} 59 60ShaderGroupVoteTestCaseBase::ComputeShader::ComputeShader(const std::string& name, const std::string& shader, 61 const tcu::IVec4& desiredColor) 62 : m_name(name), m_shader(shader), m_program(NULL), m_desiredColor(desiredColor), m_compileOnly(false) 63{ 64} 65 66ShaderGroupVoteTestCaseBase::ComputeShader::~ComputeShader() 67{ 68 if (m_program) 69 { 70 delete m_program; 71 } 72} 73 74void ShaderGroupVoteTestCaseBase::ComputeShader::create(deqp::Context& context) 75{ 76 glu::ProgramSources sourcesCompute; 77 sourcesCompute.sources[glu::SHADERTYPE_COMPUTE].push_back(m_shader); 78 m_program = new glu::ShaderProgram(context.getRenderContext(), sourcesCompute); 79 80 if (!m_program->isOk()) 81 { 82 context.getTestContext().getLog() 83 << tcu::TestLog::Message << m_shader << m_program->getShaderInfo(glu::SHADERTYPE_COMPUTE).infoLog 84 << m_program->getProgramInfo().infoLog << tcu::TestLog::EndMessage; 85 TCU_FAIL("Shader compilation failed"); 86 } 87} 88 89void ShaderGroupVoteTestCaseBase::ComputeShader::execute(deqp::Context& context) 90{ 91 if (m_compileOnly) 92 { 93 return; 94 } 95 96 const glw::Functions& gl = context.getRenderContext().getFunctions(); 97 const glu::Texture outputTexture(context.getRenderContext()); 98 const WorkGroupSize renderSize(context); 99 100 gl.clearColor(0.5f, 0.5f, 0.5f, 1.0f); 101 gl.clear(GL_COLOR_BUFFER_BIT); 102 103 gl.useProgram(m_program->getProgram()); 104 GLU_EXPECT_NO_ERROR(gl.getError(), "useProgram failed"); 105 106 // output image 107 gl.bindTexture(GL_TEXTURE_2D, *outputTexture); 108 gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, renderSize.width, renderSize.height); 109 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 110 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 111 GLU_EXPECT_NO_ERROR(gl.getError(), "Uploading image data failed"); 112 113 // bind image 114 gl.bindImageTexture(2, *outputTexture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8); 115 GLU_EXPECT_NO_ERROR(gl.getError(), "bindImageTexture failed"); 116 117 // dispatch compute 118 gl.dispatchCompute(1, 1, 1); 119 GLU_EXPECT_NO_ERROR(gl.getError(), "dispatchCompute failed"); 120 121 glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(context.getRenderContext().getType()); 122 const char* versionDeclaration = glu::getGLSLVersionDeclaration(glslVersion); 123 124 // render output texture 125 std::string vs = versionDeclaration; 126 vs += "\n" 127 "in highp vec2 position;\n" 128 "in highp vec2 inTexcoord;\n" 129 "out highp vec2 texcoord;\n" 130 "void main()\n" 131 "{\n" 132 " texcoord = inTexcoord;\n" 133 " gl_Position = vec4(position, 0.0, 1.0);\n" 134 "}\n"; 135 136 std::string fs = versionDeclaration; 137 fs += "\n" 138 "uniform highp sampler2D sampler;\n" 139 "in highp vec2 texcoord;\n" 140 "out highp vec4 color;\n" 141 "void main()\n" 142 "{\n" 143 " color = texture(sampler, texcoord);\n" 144 "}\n"; 145 146 glu::ProgramSources sources; 147 sources.sources[glu::SHADERTYPE_VERTEX].push_back(vs); 148 sources.sources[glu::SHADERTYPE_FRAGMENT].push_back(fs); 149 glu::ShaderProgram renderShader(context.getRenderContext(), sources); 150 151 if (!m_program->isOk()) 152 { 153 TCU_FAIL("Shader compilation failed"); 154 } 155 156 gl.bindTexture(GL_TEXTURE_2D, *outputTexture); 157 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed."); 158 159 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 160 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 161 GLU_EXPECT_NO_ERROR(gl.getError(), "texParameteri failed"); 162 163 gl.useProgram(renderShader.getProgram()); 164 GLU_EXPECT_NO_ERROR(gl.getError(), "useProgram failed"); 165 166 gl.uniform1i(gl.getUniformLocation(renderShader.getProgram(), "sampler"), 0); 167 GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i failed"); 168 169 deUint16 const quadIndices[] = { 0, 1, 2, 2, 1, 3 }; 170 171 float const position[] = { -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f }; 172 173 float const texCoord[] = { 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f }; 174 175 glu::VertexArrayBinding vertexArrays[] = { glu::va::Float("position", 2, 4, 0, position), 176 glu::va::Float("inTexcoord", 2, 4, 0, texCoord) }; 177 178 gl.viewport(0, 0, renderSize.width, renderSize.height); 179 glu::draw(context.getRenderContext(), renderShader.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays), vertexArrays, 180 glu::pr::TriangleStrip(DE_LENGTH_OF_ARRAY(quadIndices), quadIndices)); 181 182 GLU_EXPECT_NO_ERROR(gl.getError(), "glu::draw error"); 183 184 gl.flush(); 185} 186 187void ShaderGroupVoteTestCaseBase::ComputeShader::validate(deqp::Context& context) 188{ 189 if (m_compileOnly) 190 { 191 return; 192 } 193 194 bool validationResult = validateScreenPixels(context, m_desiredColor); 195 std::string validationErrorMsg = "Validation failed for " + m_name + " test"; 196 197 TCU_CHECK_MSG(validationResult, validationErrorMsg.c_str()); 198} 199 200bool ShaderGroupVoteTestCaseBase::ComputeShader::validateScreenPixels(deqp::Context& context, tcu::IVec4 desiredColor) 201{ 202 const glw::Functions& gl = context.getRenderContext().getFunctions(); 203 const WorkGroupSize renderSize(context); 204 std::size_t totalSize = renderSize.width * renderSize.height * 4; 205 std::vector<glw::GLubyte> pixels(totalSize, 128); 206 207 // read pixels 208 gl.readPixels(0, 0, renderSize.width, renderSize.height, GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]); 209 210 // compare pixels to desired color 211 for (std::size_t i = 0; i < totalSize; i += 4) 212 { 213 if ((pixels[i + 0] != desiredColor.x()) || (pixels[i + 1] != desiredColor.y()) || 214 (pixels[i + 2] != desiredColor.z())) 215 return false; 216 } 217 218 return true; 219} 220 221/** Constructor. 222* 223* @param context Rendering context 224* @param name Test name 225* @param description Test description 226*/ 227ShaderGroupVoteTestCaseBase::ShaderGroupVoteTestCaseBase(deqp::Context& context, ExtParameters& extParam, 228 const char* name, const char* description) 229 : TestCaseBase(context, glcts::ExtParameters(glu::GLSL_VERSION_450, glcts::EXTENSIONTYPE_EXT), name, description) 230 , m_extensionSupported(true) 231{ 232 const WorkGroupSize workGroupSize(context); 233 glu::ContextType contextType = m_context.getRenderContext().getType(); 234 m_specializationMap["VERSION"] = glu::getGLSLVersionDeclaration(extParam.glslVersion); 235 236 std::stringstream stream; 237 stream << workGroupSize.width << " " << workGroupSize.height; 238 stream >> m_specializationMap["SIZE_X"] >> m_specializationMap["SIZE_Y"]; 239 240 if (glu::contextSupports(contextType, glu::ApiType::core(4, 6))) 241 { 242 m_specializationMap["GROUP_VOTE_EXTENSION"] = ""; 243 m_specializationMap["EXT_TYPE"] = ""; 244 } 245 else 246 { 247 bool isCoreGL = glu::isContextTypeGLCore(contextType); 248 std::string extensionName = isCoreGL ? "GL_ARB_shader_group_vote" : "GL_EXT_shader_group_vote"; 249 m_extensionSupported = context.getContextInfo().isExtensionSupported(extensionName.c_str()); 250 std::stringstream extensionString; 251 extensionString << "#extension " + extensionName + " : enable"; 252 253 m_specializationMap["GROUP_VOTE_EXTENSION"] = extensionString.str(); 254 m_specializationMap["EXT_TYPE"] = isCoreGL ? "ARB" : "EXT"; 255 } 256} 257 258void ShaderGroupVoteTestCaseBase::init() 259{ 260 if (m_extensionSupported) 261 { 262 for (ComputeShaderIter iter = m_shaders.begin(); iter != m_shaders.end(); ++iter) 263 { 264 (*iter)->create(m_context); 265 } 266 } 267} 268 269void ShaderGroupVoteTestCaseBase::deinit() 270{ 271 for (ComputeShaderIter iter = m_shaders.begin(); iter != m_shaders.end(); ++iter) 272 { 273 delete (*iter); 274 } 275} 276 277tcu::TestNode::IterateResult ShaderGroupVoteTestCaseBase::iterate() 278{ 279 if (!m_extensionSupported) 280 { 281 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not supported"); 282 return STOP; 283 } 284 285 for (ComputeShaderIter iter = m_shaders.begin(); iter != m_shaders.end(); ++iter) 286 { 287 (*iter)->execute(m_context); 288 (*iter)->validate(m_context); 289 } 290 291 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 292 return STOP; 293} 294 295/** Constructor. 296* 297* @param context Rendering context 298*/ 299ShaderGroupVoteAvailabilityTestCase::ShaderGroupVoteAvailabilityTestCase(deqp::Context& context, 300 ExtParameters& extParam) 301 : ShaderGroupVoteTestCaseBase(context, extParam, "availability", "Implements ...") 302{ 303 const char* shader = "${VERSION}\n" 304 "${GROUP_VOTE_EXTENSION}\n" 305 "layout(rgba8, binding = 2) writeonly uniform highp image2D destImage;\n" 306 "layout(local_size_x = ${SIZE_X}, local_size_y = ${SIZE_Y}) in;\n" 307 "void main (void)\n" 308 "{\n" 309 " vec4 outColor = vec4(0.0);\n" 310 " outColor.r = allInvocations${EXT_TYPE}(true) ? 1.0 : 0.0;\n" 311 " outColor.g = anyInvocation${EXT_TYPE}(true) ? 1.0 : 0.0;\n" 312 " outColor.b = allInvocationsEqual${EXT_TYPE}(true) ? 1.0 : 0.0;\n" 313 " imageStore(destImage, ivec2(gl_GlobalInvocationID.xy), outColor);\n" 314 "}\n"; 315 316 m_shaders.push_back(new ComputeShader("availability", specializeShader(1, &shader))); 317} 318 319/** Constructor. 320* 321* @param context Rendering context 322* @param name Test name 323* @param description Test description 324*/ 325ShaderGroupVoteFunctionTestCaseBase::ShaderGroupVoteFunctionTestCaseBase(deqp::Context& context, 326 ExtParameters& extParam, const char* name, 327 const char* description) 328 : ShaderGroupVoteTestCaseBase(context, extParam, name, description) 329{ 330 m_shaderBase += "${VERSION}\n" 331 "${GROUP_VOTE_EXTENSION}\n" 332 "layout(rgba8, binding = 2) writeonly uniform highp image2D destImage;\n" 333 "layout(local_size_x = ${SIZE_X}, local_size_y = ${SIZE_Y}) in;\n" 334 "void main (void)\n" 335 "{\n" 336 " bool result = ${FUNC}${EXT_TYPE}(${FUNC_PARAMETER});\n" 337 " vec4 outColor = vec4(vec3(result ? 1.0 : 0.0), 1.0);\n" 338 " imageStore(destImage, ivec2(gl_GlobalInvocationID.xy), outColor);\n" 339 "}\n"; 340} 341 342/** Constructor. 343* 344* @param context Rendering context 345*/ 346ShaderGroupVoteAllInvocationsTestCase::ShaderGroupVoteAllInvocationsTestCase(deqp::Context& context, 347 ExtParameters& extParam) 348 : ShaderGroupVoteFunctionTestCaseBase(context, extParam, "all_invocations", "Implements ...") 349{ 350 const char* shaderBase = m_shaderBase.c_str(); 351 m_specializationMap["FUNC"] = "allInvocations"; 352 m_specializationMap["FUNC_PARAMETER"] = "true"; 353 354 m_shaders.push_back( 355 new ComputeShader("allInvocationsARB", specializeShader(1, &shaderBase), tcu::IVec4(255, 255, 255, 255))); 356} 357 358/** Constructor. 359* 360* @param context Rendering context 361*/ 362ShaderGroupVoteAnyInvocationTestCase::ShaderGroupVoteAnyInvocationTestCase(deqp::Context& context, 363 ExtParameters& extParam) 364 : ShaderGroupVoteFunctionTestCaseBase(context, extParam, "any_invocation", "Implements ...") 365{ 366 const char* shaderBase = m_shaderBase.c_str(); 367 m_specializationMap["FUNC"] = "anyInvocation"; 368 m_specializationMap["FUNC_PARAMETER"] = "false"; 369 370 m_shaders.push_back( 371 new ComputeShader("anyInvocationARB", specializeShader(1, &shaderBase), tcu::IVec4(0, 0, 0, 255))); 372} 373 374/** Constructor. 375* 376* @param context Rendering context 377*/ 378ShaderGroupVoteAllInvocationsEqualTestCase::ShaderGroupVoteAllInvocationsEqualTestCase(deqp::Context& context, 379 ExtParameters& extParam) 380 : ShaderGroupVoteFunctionTestCaseBase(context, extParam, "all_invocations_equal", "Implements ...") 381{ 382 const char* shaderBase = m_shaderBase.c_str(); 383 m_specializationMap["FUNC"] = "allInvocationsEqual"; 384 m_specializationMap["FUNC_PARAMETER"] = "true"; 385 m_shaders.push_back( 386 new ComputeShader("allInvocationsEqualARB", specializeShader(1, &shaderBase), tcu::IVec4(255, 255, 255, 255))); 387 388 m_specializationMap["FUNC"] = "allInvocationsEqual"; 389 m_specializationMap["FUNC_PARAMETER"] = "false"; 390 m_shaders.push_back( 391 new ComputeShader("allInvocationsEqualARB", specializeShader(1, &shaderBase), tcu::IVec4(255, 255, 255, 255))); 392} 393 394/** Constructor. 395* 396* @param context Rendering context 397*/ 398ShaderGroupVoteWithVariablesTestCase::ShaderGroupVoteWithVariablesTestCase(deqp::Context& context, 399 ExtParameters& extParam) 400 : ShaderGroupVoteTestCaseBase(context, extParam, "invocations_with_variables", "Implements ...") 401{ 402 const char* shaderBase = "${VERSION}\n" 403 "${GROUP_VOTE_EXTENSION}\n" 404 "layout(rgba8, binding = 2) writeonly uniform highp image2D destImage;\n" 405 "layout(local_size_x = ${SIZE_X}, local_size_y = ${SIZE_Y}) in;\n" 406 "void main (void)\n" 407 "{\n" 408 " bool result = ${EXPRESSION};\n" 409 " vec4 outColor = vec4(vec3(result ? 1.0 : 0.0), 1.0);\n" 410 " imageStore(destImage, ivec2(gl_GlobalInvocationID.xy), outColor);\n" 411 "}\n"; 412 413 // first specialization EXPRESSION and then whole shader 414 const char* expression1 = "allInvocations${EXT_TYPE}((gl_LocalInvocationIndex % 2u) == 1u) && " 415 "anyInvocation${EXT_TYPE}((gl_LocalInvocationIndex % 2u) == 0u) && " 416 "anyInvocation${EXT_TYPE}((gl_LocalInvocationIndex % 2u) == 1u)"; 417 m_specializationMap["EXPRESSION"] = specializeShader(1, &expression1); 418 m_shaders.push_back( 419 new ComputeShader("allInvocations", specializeShader(1, &shaderBase), tcu::IVec4(0, 0, 0, 255))); 420 421 const char* expression2 = "anyInvocation${EXT_TYPE}(gl_LocalInvocationIndex < 256u)"; 422 m_specializationMap["EXPRESSION"] = specializeShader(1, &expression2); 423 m_shaders.push_back( 424 new ComputeShader("anyInvocation", specializeShader(1, &shaderBase), tcu::IVec4(255, 255, 255, 255))); 425 426 const char* expression3 = "allInvocationsEqual${EXT_TYPE}(gl_WorkGroupID.x == 0u)"; 427 m_specializationMap["EXPRESSION"] = specializeShader(1, &expression3); 428 m_shaders.push_back( 429 new ComputeShader("anyInvocation", specializeShader(1, &shaderBase), tcu::IVec4(255, 255, 255, 255))); 430} 431 432/** Constructor. 433* 434* @param context Rendering context. 435*/ 436ShaderGroupVote::ShaderGroupVote(deqp::Context& context) 437 : TestCaseGroup(context, "shader_group_vote", 438 "Verify conformance of shader_group_vote functionality implementation") 439{ 440} 441 442/** Initializes the test group contents. */ 443void ShaderGroupVote::init() 444{ 445 glu::GLSLVersion glslVersion = getContextTypeGLSLVersion(m_context.getRenderContext().getType()); 446 ExtParameters extParam = glcts::ExtParameters(glslVersion, glcts::EXTENSIONTYPE_EXT); 447 448 addChild(new ShaderGroupVoteAvailabilityTestCase(m_context, extParam)); 449 addChild(new ShaderGroupVoteAllInvocationsTestCase(m_context, extParam)); 450 addChild(new ShaderGroupVoteAnyInvocationTestCase(m_context, extParam)); 451 addChild(new ShaderGroupVoteAllInvocationsEqualTestCase(m_context, extParam)); 452 addChild(new ShaderGroupVoteWithVariablesTestCase(m_context, extParam)); 453} 454} /* glcts namespace */ 455