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