1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 3.0 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 Implementation-defined limit tests. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "es3fImplementationLimitTests.hpp" 25 #include "tcuTestLog.hpp" 26 #include "gluDefs.hpp" 27 #include "gluStrUtil.hpp" 28 #include "gluRenderContext.hpp" 29 30 #include <vector> 31 #include <set> 32 #include <algorithm> 33 #include <iterator> 34 #include <limits> 35 36 #include "glwEnums.hpp" 37 #include "glwFunctions.hpp" 38 39 namespace deqp 40 { 41 namespace gles3 42 { 43 namespace Functional 44 { 45 46 using std::vector; 47 using std::string; 48 using std::set; 49 using namespace glw; // GL types 50 51 namespace LimitQuery 52 { 53 54 // Query function template. 55 template<typename T> 56 T query (const glw::Functions& gl, deUint32 param); 57 58 // Compare template. 59 template<typename T> 60 inline bool compare (const T& min, const T& reported) { return min <= reported; } 61 62 // Types for queries 63 64 struct NegInt 65 { 66 GLint value; 67 NegInt (GLint value_) : value(value_) {} 68 }; 69 70 std::ostream& operator<< (std::ostream& str, const NegInt& v) { return str << v.value; } 71 72 struct FloatRange 73 { 74 float min; 75 float max; 76 FloatRange (float min_, float max_) : min(min_), max(max_) {} 77 }; 78 79 std::ostream& operator<< (std::ostream& str, const FloatRange& range) { return str << range.min << ", " << range.max; } 80 81 struct AlignmentInt 82 { 83 GLint value; 84 AlignmentInt (GLint value_) : value(value_) {} 85 }; 86 87 std::ostream& operator<< (std::ostream& str, const AlignmentInt& v) { return str << v.value; } 88 89 // For custom formatting 90 struct Boolean 91 { 92 GLboolean value; 93 Boolean (GLboolean value_) : value(value_) {} 94 }; 95 96 std::ostream& operator<< (std::ostream& str, const Boolean& boolean) { return str << (boolean.value ? "GL_TRUE" : "GL_FALSE"); } 97 98 // Query function implementations. 99 template<> 100 GLint query<GLint> (const glw::Functions& gl, deUint32 param) 101 { 102 GLint val = -1; 103 gl.getIntegerv(param, &val); 104 return val; 105 } 106 107 template<> 108 GLint64 query<GLint64> (const glw::Functions& gl, deUint32 param) 109 { 110 GLint64 val = -1; 111 gl.getInteger64v(param, &val); 112 return val; 113 } 114 115 template<> 116 GLuint64 query<GLuint64> (const glw::Functions& gl, deUint32 param) 117 { 118 GLint64 val = 0; 119 gl.getInteger64v(param, &val); 120 return (GLuint64)val; 121 } 122 123 template<> 124 GLfloat query<GLfloat> (const glw::Functions& gl,deUint32 param) 125 { 126 GLfloat val = -1000.f; 127 gl.getFloatv(param, &val); 128 return val; 129 } 130 131 template<> 132 NegInt query<NegInt> (const glw::Functions& gl, deUint32 param) 133 { 134 return NegInt(query<GLint>(gl, param)); 135 } 136 137 template<> 138 Boolean query<Boolean> (const glw::Functions& gl, deUint32 param) 139 { 140 GLboolean val = GL_FALSE; 141 gl.getBooleanv(param, &val); 142 return Boolean(val); 143 } 144 145 template<> 146 FloatRange query<FloatRange> (const glw::Functions& gl, deUint32 param) 147 { 148 float v[2] = { -1.0f, -1.0f }; 149 gl.getFloatv(param, &v[0]); 150 return FloatRange(v[0], v[1]); 151 } 152 153 template<> 154 AlignmentInt query<AlignmentInt> (const glw::Functions& gl, deUint32 param) 155 { 156 return AlignmentInt(query<GLint>(gl, param)); 157 } 158 159 // Special comparison operators 160 template<> 161 bool compare<Boolean> (const Boolean& min, const Boolean& reported) 162 { 163 return !min.value || (min.value && reported.value); 164 } 165 166 template<> 167 bool compare<NegInt> (const NegInt& min, const NegInt& reported) 168 { 169 // Reverse comparison. 170 return reported.value <= min.value; 171 } 172 173 template<> 174 bool compare<FloatRange> (const FloatRange& min, const FloatRange& reported) 175 { 176 return reported.min <= min.min && min.max <= reported.max; 177 } 178 179 template<> 180 bool compare<AlignmentInt> (const AlignmentInt& min, const AlignmentInt& reported) 181 { 182 // Reverse comparison. 183 return reported.value <= min.value; 184 } 185 186 // Special error descriptions 187 188 enum QueryClass 189 { 190 CLASS_VALUE = 0, 191 CLASS_RANGE, 192 CLASS_ALIGNMENT, 193 }; 194 195 template <QueryClass Class> 196 struct QueryClassTraits 197 { 198 static const char* const s_errorDescription; 199 }; 200 201 template <> 202 const char* const QueryClassTraits<CLASS_VALUE>::s_errorDescription = "reported value is less than minimum required value!"; 203 204 template <> 205 const char* const QueryClassTraits<CLASS_RANGE>::s_errorDescription = "reported range does not contain the minimum required range!"; 206 207 template <> 208 const char* const QueryClassTraits<CLASS_ALIGNMENT>::s_errorDescription = "reported alignment is larger than minimum required aligmnent!"; 209 210 template <typename T> 211 struct QueryTypeTraits 212 { 213 }; 214 215 template <> struct QueryTypeTraits<GLint> { enum { CLASS = CLASS_VALUE }; }; 216 template <> struct QueryTypeTraits<GLint64> { enum { CLASS = CLASS_VALUE }; }; 217 template <> struct QueryTypeTraits<GLuint64> { enum { CLASS = CLASS_VALUE }; }; 218 template <> struct QueryTypeTraits<GLfloat> { enum { CLASS = CLASS_VALUE }; }; 219 template <> struct QueryTypeTraits<Boolean> { enum { CLASS = CLASS_VALUE }; }; 220 template <> struct QueryTypeTraits<NegInt> { enum { CLASS = CLASS_VALUE }; }; 221 template <> struct QueryTypeTraits<FloatRange> { enum { CLASS = CLASS_RANGE }; }; 222 template <> struct QueryTypeTraits<AlignmentInt> { enum { CLASS = CLASS_ALIGNMENT }; }; 223 224 } // LimitQuery 225 226 using namespace LimitQuery; 227 using tcu::TestLog; 228 229 template<typename T> 230 class LimitQueryCase : public TestCase 231 { 232 public: 233 LimitQueryCase (Context& context, const char* name, const char* description, deUint32 limit, const T& minRequiredValue) 234 : TestCase (context, name, description) 235 , m_limit (limit) 236 , m_minRequiredValue (minRequiredValue) 237 { 238 } 239 240 IterateResult iterate (void) 241 { 242 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 243 const T value = query<T>(m_context.getRenderContext().getFunctions(), m_limit); 244 GLU_EXPECT_NO_ERROR(gl.getError(), "Query failed"); 245 246 const bool isOk = compare<T>(m_minRequiredValue, value); 247 248 m_testCtx.getLog() << TestLog::Message << "Reported: " << value << TestLog::EndMessage; 249 m_testCtx.getLog() << TestLog::Message << "Minimum required: " << m_minRequiredValue << TestLog::EndMessage; 250 251 if (!isOk) 252 m_testCtx.getLog() << TestLog::Message << "FAIL: " << QueryClassTraits<(QueryClass)QueryTypeTraits<T>::CLASS>::s_errorDescription << TestLog::EndMessage; 253 254 m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 255 isOk ? "Pass" : "Requirement not satisfied"); 256 return STOP; 257 } 258 259 private: 260 deUint32 m_limit; 261 T m_minRequiredValue; 262 }; 263 264 static const deUint32 s_requiredCompressedTexFormats[] = 265 { 266 GL_COMPRESSED_R11_EAC, 267 GL_COMPRESSED_SIGNED_R11_EAC, 268 GL_COMPRESSED_RG11_EAC, 269 GL_COMPRESSED_SIGNED_RG11_EAC, 270 GL_COMPRESSED_RGB8_ETC2, 271 GL_COMPRESSED_SRGB8_ETC2, 272 GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, 273 GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, 274 GL_COMPRESSED_RGBA8_ETC2_EAC, 275 GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 276 }; 277 278 class CompressedTextureFormatsQueryCase : public TestCase 279 { 280 public: 281 CompressedTextureFormatsQueryCase (Context& context) 282 : TestCase(context, "compressed_texture_formats", "GL_COMPRESSED_TEXTURE_FORMATS") 283 { 284 } 285 286 IterateResult iterate (void) 287 { 288 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 289 const GLint numFormats = query<GLint>(gl, GL_NUM_COMPRESSED_TEXTURE_FORMATS); 290 vector<GLint> formats (numFormats); 291 bool allFormatsOk = true; 292 293 if (numFormats > 0) 294 gl.getIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, &formats[0]); 295 296 GLU_EXPECT_NO_ERROR(gl.getError(), "Query failed"); 297 298 // Log formats. 299 m_testCtx.getLog() << TestLog::Message << "Reported:" << TestLog::EndMessage; 300 for (vector<GLint>::const_iterator fmt = formats.begin(); fmt != formats.end(); fmt++) 301 m_testCtx.getLog() << TestLog::Message << glu::getCompressedTextureFormatStr(*fmt) << TestLog::EndMessage; 302 303 // Check that all required formats are in list. 304 { 305 set<GLint> formatSet(formats.begin(), formats.end()); 306 307 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_requiredCompressedTexFormats); ndx++) 308 { 309 const deUint32 fmt = s_requiredCompressedTexFormats[ndx]; 310 const bool found = formatSet.find(fmt) != formatSet.end(); 311 312 if (!found) 313 { 314 m_testCtx.getLog() << TestLog::Message << "ERROR: " << glu::getCompressedTextureFormatStr(fmt) << " is missing!" << TestLog::EndMessage; 315 allFormatsOk = false; 316 } 317 } 318 } 319 320 m_testCtx.setTestResult(allFormatsOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 321 allFormatsOk ? "Pass" : "Requirement not satisfied"); 322 return STOP; 323 } 324 }; 325 326 static vector<string> queryExtensionsNonIndexed (const glw::Functions& gl) 327 { 328 const string extensionStr = (const char*)gl.getString(GL_EXTENSIONS); 329 vector<string> extensionList; 330 size_t pos = 0; 331 332 for (;;) 333 { 334 const size_t nextPos = extensionStr.find(' ', pos); 335 const size_t len = nextPos == string::npos ? extensionStr.length()-pos : nextPos-pos; 336 337 if (len > 0) 338 extensionList.push_back(extensionStr.substr(pos, len)); 339 340 if (nextPos == string::npos) 341 break; 342 else 343 pos = nextPos+1; 344 } 345 346 return extensionList; 347 } 348 349 static vector<string> queryExtensionsIndexed (const glw::Functions& gl) 350 { 351 const int numExtensions = query<GLint>(gl, GL_NUM_EXTENSIONS); 352 vector<string> extensions (numExtensions); 353 354 GLU_EXPECT_NO_ERROR(gl.getError(), "GL_NUM_EXTENSIONS query failed"); 355 356 for (int ndx = 0; ndx < numExtensions; ndx++) 357 extensions[ndx] = (const char*)gl.getStringi(GL_EXTENSIONS, (GLuint)ndx); 358 359 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetStringi(GL_EXTENSIONS) failed"); 360 361 return extensions; 362 } 363 364 static bool compareExtensionLists (const vector<string>& a, const vector<string>& b) 365 { 366 if (a.size() != b.size()) 367 return false; 368 369 set<string> extsInB(b.begin(), b.end()); 370 371 for (vector<string>::const_iterator i = a.begin(); i != a.end(); ++i) 372 { 373 if (extsInB.find(*i) == extsInB.end()) 374 return false; 375 } 376 377 return true; 378 } 379 380 class ExtensionQueryCase : public TestCase 381 { 382 public: 383 ExtensionQueryCase (Context& context) 384 : TestCase(context, "extensions", "GL_EXTENSIONS") 385 { 386 } 387 388 IterateResult iterate (void) 389 { 390 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 391 const vector<string> nonIndexedExts = queryExtensionsNonIndexed(gl); 392 const vector<string> indexedExts = queryExtensionsIndexed(gl); 393 const bool isOk = compareExtensionLists(nonIndexedExts, indexedExts); 394 395 m_testCtx.getLog() << TestLog::Message << "Extensions as reported by glGetStringi(GL_EXTENSIONS):" << TestLog::EndMessage; 396 for (vector<string>::const_iterator ext = indexedExts.begin(); ext != indexedExts.end(); ++ext) 397 m_testCtx.getLog() << TestLog::Message << *ext << TestLog::EndMessage; 398 399 if (!isOk) 400 { 401 m_testCtx.getLog() << TestLog::Message << "Extensions as reported by glGetString(GL_EXTENSIONS):" << TestLog::EndMessage; 402 for (vector<string>::const_iterator ext = nonIndexedExts.begin(); ext != nonIndexedExts.end(); ++ext) 403 m_testCtx.getLog() << TestLog::Message << *ext << TestLog::EndMessage; 404 405 m_testCtx.getLog() << TestLog::Message << "ERROR: Extension lists do not match!" << TestLog::EndMessage; 406 } 407 408 m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 409 isOk ? "Pass" : "Invalid extension list"); 410 return STOP; 411 } 412 }; 413 414 ImplementationLimitTests::ImplementationLimitTests (Context& context) 415 : TestCaseGroup(context, "implementation_limits", "Implementation-defined limits") 416 { 417 } 418 419 ImplementationLimitTests::~ImplementationLimitTests (void) 420 { 421 } 422 423 void ImplementationLimitTests::init (void) 424 { 425 const int minVertexUniformBlocks = 12; 426 const int minVertexUniformComponents = 1024; 427 428 const int minFragmentUniformBlocks = 12; 429 const int minFragmentUniformComponents = 896; 430 431 const int minUniformBlockSize = 16384; 432 const int minCombinedVertexUniformComponents = (minVertexUniformBlocks*minUniformBlockSize)/4 + minVertexUniformComponents; 433 const int minCombinedFragmentUniformComponents = (minFragmentUniformBlocks*minUniformBlockSize)/4 + minFragmentUniformComponents; 434 435 #define LIMIT_CASE(NAME, PARAM, TYPE, MIN_VAL) \ 436 addChild(new LimitQueryCase<TYPE>(m_context, #NAME, #PARAM, PARAM, MIN_VAL)) 437 438 LIMIT_CASE(max_element_index, GL_MAX_ELEMENT_INDEX, GLint64, (1<<24)-1); 439 LIMIT_CASE(subpixel_bits, GL_SUBPIXEL_BITS, GLint, 4); 440 LIMIT_CASE(max_3d_texture_size, GL_MAX_3D_TEXTURE_SIZE, GLint, 256); 441 LIMIT_CASE(max_texture_size, GL_MAX_TEXTURE_SIZE, GLint, 2048); 442 LIMIT_CASE(max_array_texture_layers, GL_MAX_ARRAY_TEXTURE_LAYERS, GLint, 256); 443 LIMIT_CASE(max_texture_lod_bias, GL_MAX_TEXTURE_LOD_BIAS, GLfloat, 2.0f); 444 LIMIT_CASE(max_cube_map_texture_size, GL_MAX_CUBE_MAP_TEXTURE_SIZE, GLint, 2048); 445 LIMIT_CASE(max_renderbuffer_size, GL_MAX_RENDERBUFFER_SIZE, GLint, 2048); 446 LIMIT_CASE(max_draw_buffers, GL_MAX_DRAW_BUFFERS, GLint, 4); 447 LIMIT_CASE(max_color_attachments, GL_MAX_COLOR_ATTACHMENTS, GLint, 4); 448 // GL_MAX_VIEWPORT_DIMS 449 LIMIT_CASE(aliased_point_size_range, GL_ALIASED_POINT_SIZE_RANGE, FloatRange, FloatRange(1,1)); 450 LIMIT_CASE(aliased_line_width_range, GL_ALIASED_LINE_WIDTH_RANGE, FloatRange, FloatRange(1,1)); 451 LIMIT_CASE(max_elements_indices, GL_MAX_ELEMENTS_INDICES, GLint, 0); 452 LIMIT_CASE(max_elements_vertices, GL_MAX_ELEMENTS_VERTICES, GLint, 0); 453 LIMIT_CASE(num_compressed_texture_formats, GL_NUM_COMPRESSED_TEXTURE_FORMATS, GLint, DE_LENGTH_OF_ARRAY(s_requiredCompressedTexFormats)); 454 addChild(new CompressedTextureFormatsQueryCase(m_context)); // GL_COMPRESSED_TEXTURE_FORMATS 455 // GL_PROGRAM_BINARY_FORMATS 456 LIMIT_CASE(num_program_binary_formats, GL_NUM_PROGRAM_BINARY_FORMATS, GLint, 0); 457 // GL_SHADER_BINARY_FORMATS 458 LIMIT_CASE(num_shader_binary_formats, GL_NUM_SHADER_BINARY_FORMATS, GLint, 0); 459 LIMIT_CASE(shader_compiler, GL_SHADER_COMPILER, Boolean, GL_TRUE); 460 // Shader data type ranges & precisions 461 LIMIT_CASE(max_server_wait_timeout, GL_MAX_SERVER_WAIT_TIMEOUT, GLuint64, 0); 462 463 // Version and extension support 464 addChild(new ExtensionQueryCase(m_context)); // GL_EXTENSIONS + consistency validation 465 LIMIT_CASE(num_extensions, GL_NUM_EXTENSIONS, GLint, 0); 466 LIMIT_CASE(major_version, GL_MAJOR_VERSION, GLint, 3); 467 LIMIT_CASE(minor_version, GL_MINOR_VERSION, GLint, 0); 468 // GL_RENDERER 469 // GL_SHADING_LANGUAGE_VERSION 470 // GL_VENDOR 471 // GL_VERSION 472 473 // Vertex shader limits 474 LIMIT_CASE(max_vertex_attribs, GL_MAX_VERTEX_ATTRIBS, GLint, 16); 475 LIMIT_CASE(max_vertex_uniform_components, GL_MAX_VERTEX_UNIFORM_COMPONENTS, GLint, minVertexUniformComponents); 476 LIMIT_CASE(max_vertex_uniform_vectors, GL_MAX_VERTEX_UNIFORM_VECTORS, GLint, minVertexUniformComponents/4); 477 LIMIT_CASE(max_vertex_uniform_blocks, GL_MAX_VERTEX_UNIFORM_BLOCKS, GLint, minVertexUniformBlocks); 478 LIMIT_CASE(max_vertex_output_components, GL_MAX_VERTEX_OUTPUT_COMPONENTS, GLint, 64); 479 LIMIT_CASE(max_vertex_texture_image_units, GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, GLint, 16); 480 481 // Fragment shader limits 482 LIMIT_CASE(max_fragment_uniform_components, GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, GLint, minFragmentUniformComponents); 483 LIMIT_CASE(max_fragment_uniform_vectors, GL_MAX_FRAGMENT_UNIFORM_VECTORS, GLint, minFragmentUniformComponents/4); 484 LIMIT_CASE(max_fragment_uniform_blocks, GL_MAX_FRAGMENT_UNIFORM_BLOCKS, GLint, minFragmentUniformBlocks); 485 LIMIT_CASE(max_fragment_input_components, GL_MAX_FRAGMENT_INPUT_COMPONENTS, GLint, 60); 486 LIMIT_CASE(max_texture_image_units, GL_MAX_TEXTURE_IMAGE_UNITS, GLint, 16); 487 LIMIT_CASE(min_program_texel_offset, GL_MIN_PROGRAM_TEXEL_OFFSET, NegInt, -8); 488 LIMIT_CASE(max_program_texel_offset, GL_MAX_PROGRAM_TEXEL_OFFSET, GLint, 7); 489 490 // Aggregate shader limits 491 LIMIT_CASE(max_uniform_buffer_bindings, GL_MAX_UNIFORM_BUFFER_BINDINGS, GLint, 24); 492 LIMIT_CASE(max_uniform_block_size, GL_MAX_UNIFORM_BLOCK_SIZE, GLint64, minUniformBlockSize); 493 LIMIT_CASE(uniform_buffer_offset_alignment, GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, AlignmentInt, 256); 494 LIMIT_CASE(max_combined_uniform_blocks, GL_MAX_COMBINED_UNIFORM_BLOCKS, GLint, 24); 495 LIMIT_CASE(max_combined_vertex_uniform_components, GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS, GLint64, minCombinedVertexUniformComponents); 496 LIMIT_CASE(max_combined_fragment_uniform_components, GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS, GLint64, minCombinedFragmentUniformComponents); 497 LIMIT_CASE(max_varying_components, GL_MAX_VARYING_COMPONENTS, GLint, 60); 498 LIMIT_CASE(max_varying_vectors, GL_MAX_VARYING_VECTORS, GLint, 15); 499 LIMIT_CASE(max_combined_texture_image_units, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, GLint, 32); 500 501 // Transform feedback limits 502 LIMIT_CASE(max_transform_feedback_interleaved_components, GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, GLint, 64); 503 LIMIT_CASE(max_transform_feedback_separate_attribs, GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, GLint, 4); 504 LIMIT_CASE(max_transform_feedback_separate_components, GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS, GLint, 4); 505 } 506 507 } // Functional 508 } // gles3 509 } // deqp 510