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