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 Internal format query tests 22 *//*--------------------------------------------------------------------*/ 23 24 #include "es31fInternalFormatQueryTests.hpp" 25 #include "tcuTestLog.hpp" 26 #include "gluRenderContext.hpp" 27 #include "gluStrUtil.hpp" 28 #include "gluContextInfo.hpp" 29 #include "glwFunctions.hpp" 30 #include "glwEnums.hpp" 31 32 namespace deqp 33 { 34 namespace gles31 35 { 36 namespace Functional 37 { 38 namespace 39 { 40 41 class FormatSamplesCase : public TestCase 42 { 43 public: 44 enum FormatType 45 { 46 FORMAT_COLOR, 47 FORMAT_INT, 48 FORMAT_DEPTH_STENCIL 49 }; 50 51 FormatSamplesCase (Context& ctx, const char* name, const char* desc, glw::GLenum texTarget, glw::GLenum internalFormat, FormatType type); 52 private: 53 void init (void); 54 IterateResult iterate (void); 55 56 const glw::GLenum m_target; 57 const glw::GLenum m_internalFormat; 58 const FormatType m_type; 59 }; 60 61 FormatSamplesCase::FormatSamplesCase (Context& ctx, const char* name, const char* desc, glw::GLenum target, glw::GLenum internalFormat, FormatType type) 62 : TestCase (ctx, name, desc) 63 , m_target (target) 64 , m_internalFormat (internalFormat) 65 , m_type (type) 66 { 67 DE_ASSERT(m_target == GL_TEXTURE_2D_MULTISAMPLE || 68 m_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY || 69 m_target == GL_RENDERBUFFER); 70 } 71 72 void FormatSamplesCase::init (void) 73 { 74 const bool isTextureTarget = (m_target == GL_TEXTURE_2D_MULTISAMPLE) || 75 (m_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY); 76 const bool supportsES32 = contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)); 77 78 if (!supportsES32 && m_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY && !m_context.getContextInfo().isExtensionSupported("GL_OES_texture_storage_multisample_2d_array")) 79 TCU_THROW(NotSupportedError, "Test requires OES_texture_storage_multisample_2d_array extension or a context version equal or higher than 3.2"); 80 81 // stencil8 textures are not supported without GL_OES_texture_stencil8 extension 82 if (!supportsES32 && isTextureTarget && m_internalFormat == GL_STENCIL_INDEX8 && !m_context.getContextInfo().isExtensionSupported("GL_OES_texture_stencil8")) 83 TCU_THROW(NotSupportedError, "Test requires GL_OES_texture_stencil8 extension or a context version equal or higher than 3.2"); 84 } 85 86 FormatSamplesCase::IterateResult FormatSamplesCase::iterate (void) 87 { 88 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 89 bool isFloatFormat = false; 90 bool error = false; 91 glw::GLint maxSamples = 0; 92 glw::GLint numSampleCounts = 0; 93 const bool supportsES32 = contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)); 94 95 if (!supportsES32) 96 { 97 if (m_internalFormat == GL_RGBA16F || m_internalFormat == GL_R32F || m_internalFormat == GL_RG32F || m_internalFormat == GL_RGBA32F || m_internalFormat == GL_R16F || m_internalFormat == GL_RG16F || m_internalFormat == GL_R11F_G11F_B10F) 98 { 99 TCU_THROW(NotSupportedError, "The internal format is not supported in a context lower than 3.2"); 100 } 101 } 102 else if (m_internalFormat == GL_RGBA16F || m_internalFormat == GL_R32F || m_internalFormat == GL_RG32F || m_internalFormat == GL_RGBA32F) 103 { 104 isFloatFormat = true; 105 } 106 107 // Lowest limit 108 { 109 const glw::GLenum samplesEnum = (m_type == FORMAT_COLOR) ? (GL_MAX_COLOR_TEXTURE_SAMPLES) : (m_type == FORMAT_INT) ? (GL_MAX_INTEGER_SAMPLES) : (GL_MAX_DEPTH_TEXTURE_SAMPLES); 110 m_testCtx.getLog() << tcu::TestLog::Message << "Format must support sample count of " << glu::getGettableStateStr(samplesEnum) << tcu::TestLog::EndMessage; 111 112 gl.getIntegerv(samplesEnum, &maxSamples); 113 GLU_EXPECT_NO_ERROR(gl.getError(), "get MAX_*_SAMPLES"); 114 115 m_testCtx.getLog() << tcu::TestLog::Message << glu::getGettableStateStr(samplesEnum) << " = " << maxSamples << tcu::TestLog::EndMessage; 116 117 if (maxSamples < 1) 118 { 119 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR: minimum value of " << glu::getGettableStateStr(samplesEnum) << " is 1" << tcu::TestLog::EndMessage; 120 error = true; 121 } 122 } 123 124 // Number of sample counts 125 { 126 gl.getInternalformativ(m_target, m_internalFormat, GL_NUM_SAMPLE_COUNTS, 1, &numSampleCounts); 127 GLU_EXPECT_NO_ERROR(gl.getError(), "get GL_NUM_SAMPLE_COUNTS"); 128 129 m_testCtx.getLog() << tcu::TestLog::Message << "GL_NUM_SAMPLE_COUNTS = " << numSampleCounts << tcu::TestLog::EndMessage; 130 131 if (!isFloatFormat) 132 { 133 if (numSampleCounts < 1) 134 { 135 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR: Format MUST support some multisample configuration, got GL_NUM_SAMPLE_COUNTS = " << numSampleCounts << tcu::TestLog::EndMessage; 136 error = true; 137 } 138 } 139 } 140 141 // Sample counts 142 { 143 tcu::MessageBuilder samplesMsg (&m_testCtx.getLog()); 144 std::vector<glw::GLint> samples (numSampleCounts > 0 ? numSampleCounts : 1); 145 146 if (numSampleCounts > 0 || isFloatFormat) 147 { 148 gl.getInternalformativ(m_target, m_internalFormat, GL_SAMPLES, numSampleCounts, &samples[0]); 149 GLU_EXPECT_NO_ERROR(gl.getError(), "get GL_SAMPLES"); 150 } 151 else 152 TCU_FAIL("glGetInternalFormativ() reported 0 supported sample counts"); 153 154 // make a pretty log 155 156 samplesMsg << "GL_SAMPLES = ["; 157 for (size_t ndx = 0; ndx < samples.size(); ++ndx) 158 { 159 if (ndx) 160 samplesMsg << ", "; 161 samplesMsg << samples[ndx]; 162 } 163 samplesMsg << "]" << tcu::TestLog::EndMessage; 164 165 // Samples are in order 166 for (size_t ndx = 1; ndx < samples.size(); ++ndx) 167 { 168 if (samples[ndx-1] <= samples[ndx]) 169 { 170 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR: Samples must be ordered descending." << tcu::TestLog::EndMessage; 171 error = true; 172 break; 173 } 174 } 175 176 // samples are positive 177 for (size_t ndx = 1; ndx < samples.size(); ++ndx) 178 { 179 if (samples[ndx-1] <= 0) 180 { 181 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR: Only positive SAMPLES allowed." << tcu::TestLog::EndMessage; 182 error = true; 183 break; 184 } 185 } 186 187 // maxSamples must be supported 188 if (!isFloatFormat) 189 { 190 if (samples[0] < maxSamples) 191 { 192 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR: MAX_*_SAMPLES must be supported." << tcu::TestLog::EndMessage; 193 error = true; 194 } 195 } 196 } 197 198 // Result 199 if (!error) 200 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 201 else 202 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid value"); 203 204 return STOP; 205 } 206 207 class NumSampleCountsBufferCase : public TestCase 208 { 209 public: 210 NumSampleCountsBufferCase (Context& ctx, const char* name, const char* desc); 211 212 private: 213 IterateResult iterate (void); 214 }; 215 216 NumSampleCountsBufferCase::NumSampleCountsBufferCase (Context& ctx, const char* name, const char* desc) 217 : TestCase(ctx, name, desc) 218 { 219 } 220 221 NumSampleCountsBufferCase::IterateResult NumSampleCountsBufferCase::iterate (void) 222 { 223 const glw::GLint defaultValue = -123; // queries always return positive values 224 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 225 bool error = false; 226 227 // Query to larger buffer 228 { 229 glw::GLint buffer[2] = { defaultValue, defaultValue }; 230 231 m_testCtx.getLog() << tcu::TestLog::Message << "Querying GL_NUM_SAMPLE_COUNTS to larger-than-needed buffer." << tcu::TestLog::EndMessage; 232 gl.getInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, GL_NUM_SAMPLE_COUNTS, 2, buffer); 233 GLU_EXPECT_NO_ERROR(gl.getError(), "get GL_NUM_SAMPLE_COUNTS"); 234 235 if (buffer[1] != defaultValue) 236 { 237 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR: trailing values were modified." << tcu::TestLog::EndMessage; 238 error = true; 239 } 240 } 241 242 // Query to empty buffer 243 { 244 glw::GLint buffer[1] = { defaultValue }; 245 246 m_testCtx.getLog() << tcu::TestLog::Message << "Querying GL_NUM_SAMPLE_COUNTS to zero-sized buffer." << tcu::TestLog::EndMessage; 247 gl.getInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, GL_NUM_SAMPLE_COUNTS, 0, buffer); 248 GLU_EXPECT_NO_ERROR(gl.getError(), "get GL_NUM_SAMPLE_COUNTS"); 249 250 if (buffer[0] != defaultValue) 251 { 252 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR: Query wrote over buffer bounds." << tcu::TestLog::EndMessage; 253 error = true; 254 } 255 } 256 257 // Result 258 if (!error) 259 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 260 else 261 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Unexpected buffer modification"); 262 263 return STOP; 264 } 265 266 class SamplesBufferCase : public TestCase 267 { 268 public: 269 SamplesBufferCase (Context& ctx, const char* name, const char* desc); 270 271 private: 272 IterateResult iterate (void); 273 }; 274 275 SamplesBufferCase::SamplesBufferCase (Context& ctx, const char* name, const char* desc) 276 : TestCase(ctx, name, desc) 277 { 278 } 279 280 SamplesBufferCase::IterateResult SamplesBufferCase::iterate (void) 281 { 282 const glw::GLint defaultValue = -123; // queries always return positive values 283 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 284 bool error = false; 285 286 glw::GLint numSampleCounts = 0; 287 288 // Number of sample counts 289 { 290 gl.getInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, GL_NUM_SAMPLE_COUNTS, 1, &numSampleCounts); 291 GLU_EXPECT_NO_ERROR(gl.getError(), "get GL_NUM_SAMPLE_COUNTS"); 292 293 m_testCtx.getLog() << tcu::TestLog::Message << "GL_NUM_SAMPLE_COUNTS = " << numSampleCounts << tcu::TestLog::EndMessage; 294 } 295 296 if (numSampleCounts < 1) 297 { 298 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR: Format MUST support some multisample configuration, got GL_NUM_SAMPLE_COUNTS = " << numSampleCounts << tcu::TestLog::EndMessage; 299 error = true; 300 } 301 else 302 { 303 // Query to larger buffer 304 { 305 std::vector<glw::GLint> buffer(numSampleCounts + 1, defaultValue); 306 307 m_testCtx.getLog() << tcu::TestLog::Message << "Querying GL_SAMPLES to larger-than-needed buffer." << tcu::TestLog::EndMessage; 308 gl.getInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, GL_SAMPLES, (glw::GLsizei)buffer.size(), &buffer[0]); 309 GLU_EXPECT_NO_ERROR(gl.getError(), "get GL_SAMPLES"); 310 311 if (buffer.back() != defaultValue) 312 { 313 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR: trailing value was modified." << tcu::TestLog::EndMessage; 314 error = true; 315 } 316 } 317 318 // Query to smaller buffer 319 if (numSampleCounts > 2) 320 { 321 glw::GLint buffer[3] = { defaultValue, defaultValue, defaultValue }; 322 323 m_testCtx.getLog() << tcu::TestLog::Message << "Querying GL_SAMPLES to buffer with bufSize=2." << tcu::TestLog::EndMessage; 324 gl.getInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, GL_SAMPLES, 2, buffer); 325 GLU_EXPECT_NO_ERROR(gl.getError(), "get GL_SAMPLES"); 326 327 if (buffer[2] != defaultValue) 328 { 329 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR: Query wrote over buffer bounds." << tcu::TestLog::EndMessage; 330 error = true; 331 } 332 } 333 334 // Query to empty buffer 335 { 336 glw::GLint buffer[1] = { defaultValue }; 337 338 m_testCtx.getLog() << tcu::TestLog::Message << "Querying GL_SAMPLES to zero-sized buffer." << tcu::TestLog::EndMessage; 339 gl.getInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, GL_SAMPLES, 0, buffer); 340 GLU_EXPECT_NO_ERROR(gl.getError(), "get GL_SAMPLES"); 341 342 if (buffer[0] != defaultValue) 343 { 344 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR: Query wrote over buffer bounds." << tcu::TestLog::EndMessage; 345 error = true; 346 } 347 } 348 } 349 350 // Result 351 if (!error) 352 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 353 else 354 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Unexpected buffer modification"); 355 356 return STOP; 357 } 358 359 } // anonymous 360 361 InternalFormatQueryTests::InternalFormatQueryTests (Context& context) 362 : TestCaseGroup(context, "internal_format", "Internal format queries") 363 { 364 } 365 366 InternalFormatQueryTests::~InternalFormatQueryTests (void) 367 { 368 } 369 370 void InternalFormatQueryTests::init (void) 371 { 372 static const struct InternalFormat 373 { 374 const char* name; 375 glw::GLenum format; 376 FormatSamplesCase::FormatType type; 377 } internalFormats[] = 378 { 379 // color renderable 380 { "r8", GL_R8, FormatSamplesCase::FORMAT_COLOR }, 381 { "rg8", GL_RG8, FormatSamplesCase::FORMAT_COLOR }, 382 { "rgb8", GL_RGB8, FormatSamplesCase::FORMAT_COLOR }, 383 { "rgb565", GL_RGB565, FormatSamplesCase::FORMAT_COLOR }, 384 { "rgba4", GL_RGBA4, FormatSamplesCase::FORMAT_COLOR }, 385 { "rgb5_a1", GL_RGB5_A1, FormatSamplesCase::FORMAT_COLOR }, 386 { "rgba8", GL_RGBA8, FormatSamplesCase::FORMAT_COLOR }, 387 { "rgb10_a2", GL_RGB10_A2, FormatSamplesCase::FORMAT_COLOR }, 388 { "rgb10_a2ui", GL_RGB10_A2UI, FormatSamplesCase::FORMAT_INT }, 389 { "srgb8_alpha8", GL_SRGB8_ALPHA8, FormatSamplesCase::FORMAT_COLOR }, 390 { "r8i", GL_R8I, FormatSamplesCase::FORMAT_INT }, 391 { "r8ui", GL_R8UI, FormatSamplesCase::FORMAT_INT }, 392 { "r16i", GL_R16I, FormatSamplesCase::FORMAT_INT }, 393 { "r16ui", GL_R16UI, FormatSamplesCase::FORMAT_INT }, 394 { "r32i", GL_R32I, FormatSamplesCase::FORMAT_INT }, 395 { "r32ui", GL_R32UI, FormatSamplesCase::FORMAT_INT }, 396 { "rg8i", GL_RG8I, FormatSamplesCase::FORMAT_INT }, 397 { "rg8ui", GL_RG8UI, FormatSamplesCase::FORMAT_INT }, 398 { "rg16i", GL_RG16I, FormatSamplesCase::FORMAT_INT }, 399 { "rg16ui", GL_RG16UI, FormatSamplesCase::FORMAT_INT }, 400 { "rg32i", GL_RG32I, FormatSamplesCase::FORMAT_INT }, 401 { "rg32ui", GL_RG32UI, FormatSamplesCase::FORMAT_INT }, 402 { "rgba8i", GL_RGBA8I, FormatSamplesCase::FORMAT_INT }, 403 { "rgba8ui", GL_RGBA8UI, FormatSamplesCase::FORMAT_INT }, 404 { "rgba16i", GL_RGBA16I, FormatSamplesCase::FORMAT_INT }, 405 { "rgba16ui", GL_RGBA16UI, FormatSamplesCase::FORMAT_INT }, 406 { "rgba32i", GL_RGBA32I, FormatSamplesCase::FORMAT_INT }, 407 { "rgba32ui", GL_RGBA32UI, FormatSamplesCase::FORMAT_INT }, 408 409 // float formats 410 { "r16f", GL_R16F, FormatSamplesCase::FORMAT_COLOR }, 411 { "rg16f", GL_RG16F, FormatSamplesCase::FORMAT_COLOR }, 412 { "rgba16f", GL_RGBA16F, FormatSamplesCase::FORMAT_COLOR }, 413 { "r32f", GL_R32F, FormatSamplesCase::FORMAT_INT }, 414 { "rg32f", GL_RG32F, FormatSamplesCase::FORMAT_INT }, 415 { "rgba32f", GL_RGBA32F, FormatSamplesCase::FORMAT_INT }, 416 { "r11f_g11f_b10f", GL_R11F_G11F_B10F, FormatSamplesCase::FORMAT_COLOR }, 417 418 // depth renderable 419 { "depth_component16", GL_DEPTH_COMPONENT16, FormatSamplesCase::FORMAT_DEPTH_STENCIL }, 420 { "depth_component24", GL_DEPTH_COMPONENT24, FormatSamplesCase::FORMAT_DEPTH_STENCIL }, 421 { "depth_component32f", GL_DEPTH_COMPONENT32F, FormatSamplesCase::FORMAT_DEPTH_STENCIL }, 422 { "depth24_stencil8", GL_DEPTH24_STENCIL8, FormatSamplesCase::FORMAT_DEPTH_STENCIL }, 423 { "depth32f_stencil8", GL_DEPTH32F_STENCIL8, FormatSamplesCase::FORMAT_DEPTH_STENCIL }, 424 425 // stencil renderable 426 { "stencil_index8", GL_STENCIL_INDEX8, FormatSamplesCase::FORMAT_DEPTH_STENCIL } 427 // DEPTH24_STENCIL8, duplicate 428 // DEPTH32F_STENCIL8 duplicate 429 }; 430 431 static const struct 432 { 433 const char* name; 434 deUint32 target; 435 } textureTargets[] = 436 { 437 { "renderbuffer", GL_RENDERBUFFER }, 438 { "texture_2d_multisample", GL_TEXTURE_2D_MULTISAMPLE }, 439 { "texture_2d_multisample_array", GL_TEXTURE_2D_MULTISAMPLE_ARRAY }, 440 }; 441 442 for (int groupNdx = 0; groupNdx < DE_LENGTH_OF_ARRAY(textureTargets); ++groupNdx) 443 { 444 tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, textureTargets[groupNdx].name, glu::getInternalFormatTargetName(textureTargets[groupNdx].target)); 445 const glw::GLenum texTarget = textureTargets[groupNdx].target; 446 447 addChild(group); 448 449 for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(internalFormats); ++caseNdx) 450 { 451 const std::string name = std::string(internalFormats[caseNdx].name) + "_samples"; 452 const std::string desc = std::string("Verify GL_SAMPLES of ") + internalFormats[caseNdx].name; 453 454 group->addChild(new FormatSamplesCase(m_context, name.c_str(), desc.c_str(), texTarget, internalFormats[caseNdx].format, internalFormats[caseNdx].type)); 455 } 456 } 457 458 // Check buffer sizes are honored 459 { 460 tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "partial_query", "Query data to too short a buffer"); 461 462 addChild(group); 463 464 group->addChild(new NumSampleCountsBufferCase (m_context, "num_sample_counts", "Query GL_NUM_SAMPLE_COUNTS to too short a buffer")); 465 group->addChild(new SamplesBufferCase (m_context, "samples", "Query GL_SAMPLES to too short a buffer")); 466 } 467 } 468 469 } // Functional 470 } // gles31 471 } // deqp 472