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