1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 3.1 Module 3 * ------------------------------------------------- 4 * 5 * Copyright 2014 The Android Open Source Project 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 21 * \brief Shader built-in constant tests. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "es31fShaderBuiltinConstantTests.hpp" 25 #include "glsShaderExecUtil.hpp" 26 #include "deUniquePtr.hpp" 27 #include "deStringUtil.hpp" 28 #include "tcuTestLog.hpp" 29 #include "gluStrUtil.hpp" 30 #include "gluContextInfo.hpp" 31 #include "glwEnums.hpp" 32 #include "glwFunctions.hpp" 33 34 using std::string; 35 using std::vector; 36 using tcu::TestLog; 37 38 namespace deqp 39 { 40 namespace gles31 41 { 42 namespace Functional 43 { 44 namespace 45 { 46 47 static int getInteger (const glw::Functions& gl, deUint32 pname) 48 { 49 int value = -1; 50 gl.getIntegerv(pname, &value); 51 GLU_EXPECT_NO_ERROR(gl.getError(), ("glGetIntegerv(" + glu::getGettableStateStr((int)pname).toString() + ")").c_str()); 52 return value; 53 } 54 55 template<deUint32 Pname> 56 static int getInteger (const glw::Functions& gl) 57 { 58 return getInteger(gl, Pname); 59 } 60 61 static int getVectorsFromComps (const glw::Functions& gl, deUint32 pname) 62 { 63 int value = -1; 64 gl.getIntegerv(pname, &value); 65 GLU_EXPECT_NO_ERROR(gl.getError(), ("glGetIntegerv(" + glu::getGettableStateStr((int)pname).toString() + ")").c_str()); 66 TCU_CHECK_MSG(value%4 == 0, ("Expected " + glu::getGettableStateStr((int)pname).toString() + " to be divisible by 4").c_str()); 67 return value/4; 68 } 69 70 template<deUint32 Pname> 71 static int getVectorsFromComps (const glw::Functions& gl) 72 { 73 return getVectorsFromComps(gl, Pname); 74 } 75 76 static tcu::IVec3 getIVec3 (const glw::Functions& gl, deUint32 pname) 77 { 78 tcu::IVec3 value(-1); 79 for (int ndx = 0; ndx < 3; ndx++) 80 gl.getIntegeri_v(pname, (glw::GLuint)ndx, &value[ndx]); 81 GLU_EXPECT_NO_ERROR(gl.getError(), ("glGetIntegeri_v(" + glu::getGettableStateStr((int)pname).toString() + ")").c_str()); 82 return value; 83 } 84 85 template<deUint32 Pname> 86 static tcu::IVec3 getIVec3 (const glw::Functions& gl) 87 { 88 return getIVec3(gl, Pname); 89 } 90 91 static std::string makeCaseName (const std::string& varName) 92 { 93 DE_ASSERT(varName.length() > 3); 94 DE_ASSERT(varName.substr(0,3) == "gl_"); 95 96 std::ostringstream name; 97 name << de::toLower(char(varName[3])); 98 99 for (size_t ndx = 4; ndx < varName.length(); ndx++) 100 { 101 const char c = char(varName[ndx]); 102 if (de::isUpper(c)) 103 name << '_' << de::toLower(c); 104 else 105 name << c; 106 } 107 108 return name.str(); 109 } 110 111 enum 112 { 113 VS = (1<<glu::SHADERTYPE_VERTEX), 114 TC = (1<<glu::SHADERTYPE_TESSELLATION_CONTROL), 115 TE = (1<<glu::SHADERTYPE_TESSELLATION_EVALUATION), 116 GS = (1<<glu::SHADERTYPE_GEOMETRY), 117 FS = (1<<glu::SHADERTYPE_FRAGMENT), 118 CS = (1<<glu::SHADERTYPE_COMPUTE), 119 120 SHADER_TYPES = VS|TC|TE|GS|FS|CS 121 }; 122 123 template<typename DataType> 124 class ShaderBuiltinConstantCase : public TestCase 125 { 126 public: 127 typedef DataType (*GetConstantValueFunc) (const glw::Functions& gl); 128 129 ShaderBuiltinConstantCase (Context& context, const char* varName, GetConstantValueFunc getValue, const char* requiredExt); 130 ~ShaderBuiltinConstantCase (void); 131 132 void init (void); 133 IterateResult iterate (void); 134 135 private: 136 bool verifyInShaderType (glu::ShaderType shaderType, DataType reference); 137 138 const std::string m_varName; 139 const GetConstantValueFunc m_getValue; 140 const std::string m_requiredExt; 141 }; 142 143 template<typename DataType> 144 ShaderBuiltinConstantCase<DataType>::ShaderBuiltinConstantCase (Context& context, const char* varName, GetConstantValueFunc getValue, const char* requiredExt) 145 : TestCase (context, makeCaseName(varName).c_str(), varName) 146 , m_varName (varName) 147 , m_getValue (getValue) 148 , m_requiredExt (requiredExt ? requiredExt : "") 149 { 150 DE_ASSERT(!requiredExt == m_requiredExt.empty()); 151 } 152 153 template<typename DataType> 154 ShaderBuiltinConstantCase<DataType>::~ShaderBuiltinConstantCase (void) 155 { 156 } 157 158 template<typename DataType> 159 void ShaderBuiltinConstantCase<DataType>::init (void) 160 { 161 const bool isES32 = contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)); 162 163 if (m_requiredExt == "GL_OES_sample_variables" || m_requiredExt == "GL_EXT_geometry_shader" || m_requiredExt == "GL_EXT_tessellation_shader") 164 { 165 if(!isES32) 166 { 167 const std::string message = "The test requires a 3.2 context or support for the extension " + m_requiredExt + "."; 168 TCU_CHECK_AND_THROW(NotSupportedError, m_context.getContextInfo().isExtensionSupported(m_requiredExt.c_str()), message.c_str()); 169 } 170 } 171 else if (!m_requiredExt.empty() && !m_context.getContextInfo().isExtensionSupported(m_requiredExt.c_str())) 172 throw tcu::NotSupportedError(m_requiredExt + " not supported"); 173 174 if (!isES32 && (m_varName == "gl_MaxTessControlImageUniforms" || 175 m_varName == "gl_MaxTessEvaluationImageUniforms" || 176 m_varName == "gl_MaxTessControlAtomicCounters" || 177 m_varName == "gl_MaxTessEvaluationAtomicCounters" || 178 m_varName == "gl_MaxTessControlAtomicCounterBuffers" || 179 m_varName == "gl_MaxTessEvaluationAtomicCounterBuffers")) 180 { 181 std::string message = "The test requires a 3.2 context. The constant '" + m_varName + "' is not supported."; 182 TCU_THROW(NotSupportedError, message.c_str()); 183 } 184 } 185 186 static gls::ShaderExecUtil::ShaderExecutor* createGetConstantExecutor (const glu::RenderContext& renderCtx, 187 glu::ShaderType shaderType, 188 glu::DataType dataType, 189 const std::string& varName, 190 const std::string& extName) 191 { 192 using namespace gls::ShaderExecUtil; 193 194 const bool isES32 = contextSupports(renderCtx.getType(), glu::ApiType::es(3, 2)); 195 ShaderSpec shaderSpec; 196 197 shaderSpec.version = isES32 ? glu::GLSL_VERSION_320_ES : glu::GLSL_VERSION_310_ES; 198 shaderSpec.source = string("result = ") + varName + ";\n"; 199 200 shaderSpec.outputs.push_back(Symbol("result", glu::VarType(dataType, glu::PRECISION_HIGHP))); 201 202 if (!extName.empty() && !(isES32 && (extName == "GL_OES_sample_variables" || extName == "GL_EXT_geometry_shader" || extName == "GL_EXT_tessellation_shader"))) 203 shaderSpec.globalDeclarations = "#extension " + extName + " : require\n"; 204 205 return createExecutor(renderCtx, shaderType, shaderSpec); 206 } 207 208 template<typename DataType> 209 static void logVarValue (tcu::TestLog& log, const std::string& varName, DataType value) 210 { 211 log << TestLog::Message << varName << " = " << value << TestLog::EndMessage; 212 } 213 214 template<> 215 void logVarValue<int> (tcu::TestLog& log, const std::string& varName, int value) 216 { 217 log << TestLog::Integer(varName, varName, "", QP_KEY_TAG_NONE, value); 218 } 219 220 template<typename DataType> 221 bool ShaderBuiltinConstantCase<DataType>::verifyInShaderType (glu::ShaderType shaderType, DataType reference) 222 { 223 using namespace gls::ShaderExecUtil; 224 225 const de::UniquePtr<ShaderExecutor> shaderExecutor (createGetConstantExecutor(m_context.getRenderContext(), shaderType, glu::dataTypeOf<DataType>(), m_varName, m_requiredExt)); 226 DataType result = DataType(-1); 227 void* const outputs = &result; 228 229 if (!shaderExecutor->isOk()) 230 { 231 shaderExecutor->log(m_testCtx.getLog()); 232 TCU_FAIL("Compile failed"); 233 } 234 235 shaderExecutor->useProgram(); 236 shaderExecutor->execute(1, DE_NULL, &outputs); 237 238 logVarValue(m_testCtx.getLog(), m_varName, result); 239 240 if (result != reference) 241 { 242 m_testCtx.getLog() << TestLog::Message << "ERROR: Expected " << m_varName << " = " << reference << TestLog::EndMessage 243 << TestLog::Message << "Test shader:" << TestLog::EndMessage; 244 shaderExecutor->log(m_testCtx.getLog()); 245 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid builtin constant value"); 246 return false; 247 } 248 else 249 return true; 250 } 251 252 template<typename DataType> 253 TestCase::IterateResult ShaderBuiltinConstantCase<DataType>::iterate (void) 254 { 255 const DataType reference = m_getValue(m_context.getRenderContext().getFunctions()); 256 257 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 258 259 for (int shaderType = 0; shaderType < glu::SHADERTYPE_LAST; shaderType++) 260 { 261 if ((SHADER_TYPES & (1<<shaderType)) != 0) 262 { 263 const char* const shaderTypeName = glu::getShaderTypeName(glu::ShaderType(shaderType)); 264 const tcu::ScopedLogSection section (m_testCtx.getLog(), shaderTypeName, shaderTypeName); 265 266 try 267 { 268 const bool isOk = verifyInShaderType(glu::ShaderType(shaderType), reference); 269 DE_ASSERT(isOk || m_testCtx.getTestResult() != QP_TEST_RESULT_PASS); 270 DE_UNREF(isOk); 271 } 272 catch (const tcu::NotSupportedError& e) 273 { 274 m_testCtx.getLog() << TestLog::Message << "Not checking " << shaderTypeName << ": " << e.what() << TestLog::EndMessage; 275 } 276 catch (const tcu::TestError& e) 277 { 278 m_testCtx.getLog() << TestLog::Message << e.what() << TestLog::EndMessage; 279 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, e.getMessage()); 280 } 281 } 282 } 283 284 return STOP; 285 } 286 287 } // anonymous 288 289 ShaderBuiltinConstantTests::ShaderBuiltinConstantTests (Context& context) 290 : TestCaseGroup(context, "builtin_constants", "Built-in Constant Tests") 291 { 292 } 293 294 ShaderBuiltinConstantTests::~ShaderBuiltinConstantTests (void) 295 { 296 } 297 298 void ShaderBuiltinConstantTests::init (void) 299 { 300 // Core builtin constants 301 { 302 static const struct 303 { 304 const char* varName; 305 ShaderBuiltinConstantCase<int>::GetConstantValueFunc getValue; 306 } intConstants[] = 307 { 308 { "gl_MaxVertexAttribs", getInteger<GL_MAX_VERTEX_ATTRIBS> }, 309 { "gl_MaxVertexUniformVectors", getInteger<GL_MAX_VERTEX_UNIFORM_VECTORS> }, 310 { "gl_MaxVertexOutputVectors", getVectorsFromComps<GL_MAX_VERTEX_OUTPUT_COMPONENTS> }, 311 { "gl_MaxFragmentInputVectors", getVectorsFromComps<GL_MAX_FRAGMENT_INPUT_COMPONENTS> }, 312 { "gl_MaxFragmentUniformVectors", getInteger<GL_MAX_FRAGMENT_UNIFORM_VECTORS> }, 313 { "gl_MaxDrawBuffers", getInteger<GL_MAX_DRAW_BUFFERS> }, 314 315 { "gl_MaxVertexTextureImageUnits", getInteger<GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS> }, 316 { "gl_MaxCombinedTextureImageUnits", getInteger<GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS> }, 317 { "gl_MaxTextureImageUnits", getInteger<GL_MAX_TEXTURE_IMAGE_UNITS> }, 318 319 { "gl_MinProgramTexelOffset", getInteger<GL_MIN_PROGRAM_TEXEL_OFFSET> }, 320 { "gl_MaxProgramTexelOffset", getInteger<GL_MAX_PROGRAM_TEXEL_OFFSET> }, 321 322 { "gl_MaxImageUnits", getInteger<GL_MAX_IMAGE_UNITS> }, 323 { "gl_MaxVertexImageUniforms", getInteger<GL_MAX_VERTEX_IMAGE_UNIFORMS> }, 324 { "gl_MaxFragmentImageUniforms", getInteger<GL_MAX_FRAGMENT_IMAGE_UNIFORMS> }, 325 { "gl_MaxComputeImageUniforms", getInteger<GL_MAX_COMPUTE_IMAGE_UNIFORMS> }, 326 { "gl_MaxCombinedImageUniforms", getInteger<GL_MAX_COMBINED_IMAGE_UNIFORMS> }, 327 328 { "gl_MaxCombinedShaderOutputResources", getInteger<GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES> }, 329 330 { "gl_MaxComputeUniformComponents", getInteger<GL_MAX_COMPUTE_UNIFORM_COMPONENTS> }, 331 { "gl_MaxComputeTextureImageUnits", getInteger<GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS> }, 332 333 { "gl_MaxComputeAtomicCounters", getInteger<GL_MAX_COMPUTE_ATOMIC_COUNTERS> }, 334 { "gl_MaxComputeAtomicCounterBuffers", getInteger<GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS> }, 335 336 { "gl_MaxVertexAtomicCounters", getInteger<GL_MAX_VERTEX_ATOMIC_COUNTERS> }, 337 { "gl_MaxFragmentAtomicCounters", getInteger<GL_MAX_FRAGMENT_ATOMIC_COUNTERS> }, 338 { "gl_MaxCombinedAtomicCounters", getInteger<GL_MAX_COMBINED_ATOMIC_COUNTERS> }, 339 { "gl_MaxAtomicCounterBindings", getInteger<GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS> }, 340 341 { "gl_MaxVertexAtomicCounterBuffers", getInteger<GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS> }, 342 { "gl_MaxFragmentAtomicCounterBuffers", getInteger<GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS> }, 343 { "gl_MaxCombinedAtomicCounterBuffers", getInteger<GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS> }, 344 { "gl_MaxAtomicCounterBufferSize", getInteger<GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE> }, 345 }; 346 347 static const struct 348 { 349 const char* varName; 350 ShaderBuiltinConstantCase<tcu::IVec3>::GetConstantValueFunc getValue; 351 } ivec3Constants[] = 352 { 353 { "gl_MaxComputeWorkGroupCount", getIVec3<GL_MAX_COMPUTE_WORK_GROUP_COUNT> }, 354 { "gl_MaxComputeWorkGroupSize", getIVec3<GL_MAX_COMPUTE_WORK_GROUP_SIZE> }, 355 }; 356 357 tcu::TestCaseGroup* const coreGroup = new tcu::TestCaseGroup(m_testCtx, "core", "Core Specification"); 358 addChild(coreGroup); 359 360 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(intConstants); ndx++) 361 coreGroup->addChild(new ShaderBuiltinConstantCase<int>(m_context, intConstants[ndx].varName, intConstants[ndx].getValue, DE_NULL)); 362 363 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(ivec3Constants); ndx++) 364 coreGroup->addChild(new ShaderBuiltinConstantCase<tcu::IVec3>(m_context, ivec3Constants[ndx].varName, ivec3Constants[ndx].getValue, DE_NULL)); 365 } 366 367 // OES_sample_variables 368 { 369 tcu::TestCaseGroup* const sampleVarGroup = new tcu::TestCaseGroup(m_testCtx, "sample_variables", "GL_OES_sample_variables"); 370 addChild(sampleVarGroup); 371 sampleVarGroup->addChild(new ShaderBuiltinConstantCase<int>(m_context, "gl_MaxSamples", getInteger<GL_MAX_SAMPLES>, "GL_OES_sample_variables")); 372 } 373 374 // EXT_geometry_shader 375 { 376 static const struct 377 { 378 const char* varName; 379 ShaderBuiltinConstantCase<int>::GetConstantValueFunc getValue; 380 } intConstants[] = 381 { 382 { "gl_MaxGeometryInputComponents", getInteger<GL_MAX_GEOMETRY_INPUT_COMPONENTS> }, 383 { "gl_MaxGeometryOutputComponents", getInteger<GL_MAX_GEOMETRY_OUTPUT_COMPONENTS> }, 384 { "gl_MaxGeometryImageUniforms", getInteger<GL_MAX_GEOMETRY_IMAGE_UNIFORMS> }, 385 { "gl_MaxGeometryTextureImageUnits", getInteger<GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS> }, 386 { "gl_MaxGeometryOutputVertices", getInteger<GL_MAX_GEOMETRY_OUTPUT_VERTICES> }, 387 { "gl_MaxGeometryTotalOutputComponents", getInteger<GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS> }, 388 { "gl_MaxGeometryUniformComponents", getInteger<GL_MAX_GEOMETRY_UNIFORM_COMPONENTS> }, 389 { "gl_MaxGeometryAtomicCounters", getInteger<GL_MAX_GEOMETRY_ATOMIC_COUNTERS> }, 390 { "gl_MaxGeometryAtomicCounterBuffers", getInteger<GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS> }, 391 }; 392 393 tcu::TestCaseGroup* const geomGroup = new tcu::TestCaseGroup(m_testCtx, "geometry_shader", "GL_EXT_geometry_shader"); 394 addChild(geomGroup); 395 396 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(intConstants); ndx++) 397 geomGroup->addChild(new ShaderBuiltinConstantCase<int>(m_context, intConstants[ndx].varName, intConstants[ndx].getValue, "GL_EXT_geometry_shader")); 398 } 399 400 // EXT_tessellation_shader 401 { 402 static const struct 403 { 404 const char* varName; 405 ShaderBuiltinConstantCase<int>::GetConstantValueFunc getValue; 406 } intConstants[] = 407 { 408 { "gl_MaxTessControlInputComponents", getInteger<GL_MAX_TESS_CONTROL_INPUT_COMPONENTS> }, 409 { "gl_MaxTessControlOutputComponents", getInteger<GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS> }, 410 { "gl_MaxTessControlTextureImageUnits", getInteger<GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS> }, 411 { "gl_MaxTessControlUniformComponents", getInteger<GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS> }, 412 { "gl_MaxTessControlTotalOutputComponents", getInteger<GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS> }, 413 414 { "gl_MaxTessControlImageUniforms", getInteger<GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS> }, 415 { "gl_MaxTessEvaluationImageUniforms", getInteger<GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS> }, 416 { "gl_MaxTessControlAtomicCounters", getInteger<GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS> }, 417 { "gl_MaxTessEvaluationAtomicCounters", getInteger<GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS> }, 418 { "gl_MaxTessControlAtomicCounterBuffers", getInteger<GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS> }, 419 { "gl_MaxTessEvaluationAtomicCounterBuffers", getInteger<GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS> }, 420 421 { "gl_MaxTessEvaluationInputComponents", getInteger<GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS> }, 422 { "gl_MaxTessEvaluationOutputComponents", getInteger<GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS> }, 423 { "gl_MaxTessEvaluationTextureImageUnits", getInteger<GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS> }, 424 { "gl_MaxTessEvaluationUniformComponents", getInteger<GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS> }, 425 426 { "gl_MaxTessPatchComponents", getInteger<GL_MAX_TESS_PATCH_COMPONENTS> }, 427 428 { "gl_MaxPatchVertices", getInteger<GL_MAX_PATCH_VERTICES> }, 429 { "gl_MaxTessGenLevel", getInteger<GL_MAX_TESS_GEN_LEVEL> }, 430 }; 431 432 tcu::TestCaseGroup* const tessGroup = new tcu::TestCaseGroup(m_testCtx, "tessellation_shader", "GL_EXT_tessellation_shader"); 433 addChild(tessGroup); 434 435 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(intConstants); ndx++) 436 tessGroup->addChild(new ShaderBuiltinConstantCase<int>(m_context, intConstants[ndx].varName, intConstants[ndx].getValue, "GL_EXT_tessellation_shader")); 437 } 438 } 439 440 } // Functional 441 } // gles31 442 } // deqp 443