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
FormatSamplesCase(Context & ctx,const char * name,const char * desc,glw::GLenum target,glw::GLenum internalFormat,FormatType type)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
init(void)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 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
iterate(void)88 FormatSamplesCase::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
211 class NumSampleCountsBufferCase : public TestCase
212 {
213 public:
214 NumSampleCountsBufferCase (Context& ctx, const char* name, const char* desc);
215
216 private:
217 IterateResult iterate (void);
218 };
219
NumSampleCountsBufferCase(Context & ctx,const char * name,const char * desc)220 NumSampleCountsBufferCase::NumSampleCountsBufferCase (Context& ctx, const char* name, const char* desc)
221 : TestCase(ctx, name, desc)
222 {
223 }
224
iterate(void)225 NumSampleCountsBufferCase::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
270 class SamplesBufferCase : public TestCase
271 {
272 public:
273 SamplesBufferCase (Context& ctx, const char* name, const char* desc);
274
275 private:
276 IterateResult iterate (void);
277 };
278
SamplesBufferCase(Context & ctx,const char * name,const char * desc)279 SamplesBufferCase::SamplesBufferCase (Context& ctx, const char* name, const char* desc)
280 : TestCase(ctx, name, desc)
281 {
282 }
283
iterate(void)284 SamplesBufferCase::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
InternalFormatQueryTests(Context & context)365 InternalFormatQueryTests::InternalFormatQueryTests (Context& context)
366 : TestCaseGroup(context, "internal_format", "Internal format queries")
367 {
368 }
369
~InternalFormatQueryTests(void)370 InternalFormatQueryTests::~InternalFormatQueryTests (void)
371 {
372 }
373
init(void)374 void 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