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 Multisample texture size tests
22 *//*--------------------------------------------------------------------*/
23
24 #include "es31fShaderTextureSizeTests.hpp"
25 #include "gluRenderContext.hpp"
26 #include "gluShaderProgram.hpp"
27 #include "gluPixelTransfer.hpp"
28 #include "gluContextInfo.hpp"
29 #include "glwEnums.hpp"
30 #include "glwFunctions.hpp"
31 #include "tcuTestLog.hpp"
32 #include "tcuStringTemplate.hpp"
33 #include "tcuSurface.hpp"
34 #include "tcuRenderTarget.hpp"
35 #include "deStringUtil.hpp"
36
37 using namespace glw;
38
39 namespace deqp
40 {
41 namespace gles31
42 {
43 namespace Functional
44 {
45 namespace
46 {
47
48 static const char* const s_positionVertexShaderSource = "#version 310 es\n"
49 "in highp vec4 a_position;\n"
50 "void main (void)\n"
51 "{\n"
52 " gl_Position = a_position;\n"
53 "}\n";
54
55 class TextureSizeCase : public TestCase
56 {
57 public:
58 enum TextureType
59 {
60 TEXTURE_FLOAT_2D = 0,
61 TEXTURE_FLOAT_2D_ARRAY,
62 TEXTURE_INT_2D,
63 TEXTURE_INT_2D_ARRAY,
64 TEXTURE_UINT_2D,
65 TEXTURE_UINT_2D_ARRAY,
66
67 TEXTURE_LAST
68 };
69
70 TextureSizeCase (Context& context, const char* name, const char* desc, TextureType type, int samples);
71 ~TextureSizeCase (void);
72
73 private:
74 void init (void);
75 void deinit (void);
76 IterateResult iterate (void);
77
78 std::string genFragmentSource (void);
79 glw::GLenum getTextureGLTarget (void);
80 glw::GLenum getTextureGLInternalFormat (void);
81
82 void createTexture (const tcu::IVec3& size);
83 void deleteTexture (void);
84 void runShader (tcu::Surface& dst, const tcu::IVec3& size);
85 bool verifyImage (const tcu::Surface& dst);
86
87 const TextureType m_type;
88 const int m_numSamples;
89 const bool m_isArrayType;
90
91 glw::GLuint m_texture;
92 glw::GLuint m_vbo;
93 glu::ShaderProgram* m_shader;
94 std::vector<tcu::IVec3> m_iterations;
95 int m_iteration;
96
97 bool m_allIterationsPassed;
98 bool m_allCasesSkipped;
99 };
100
TextureSizeCase(Context & context,const char * name,const char * desc,TextureType type,int samples)101 TextureSizeCase::TextureSizeCase (Context& context, const char* name, const char* desc, TextureType type, int samples)
102 : TestCase (context, name, desc)
103 , m_type (type)
104 , m_numSamples (samples)
105 , m_isArrayType (m_type == TEXTURE_FLOAT_2D_ARRAY || m_type == TEXTURE_INT_2D_ARRAY || m_type == TEXTURE_UINT_2D_ARRAY)
106 , m_texture (0)
107 , m_vbo (0)
108 , m_shader (DE_NULL)
109 , m_iteration (0)
110 , m_allIterationsPassed (true)
111 , m_allCasesSkipped (true)
112 {
113 DE_ASSERT(type < TEXTURE_LAST);
114 }
115
~TextureSizeCase(void)116 TextureSizeCase::~TextureSizeCase (void)
117 {
118 deinit();
119 }
120
init(void)121 void TextureSizeCase::init (void)
122 {
123 static const tcu::IVec2 testSizes2D[] =
124 {
125 tcu::IVec2(1, 1),
126 tcu::IVec2(1, 4),
127 tcu::IVec2(4, 8),
128 tcu::IVec2(21, 11),
129 tcu::IVec2(107, 254),
130 tcu::IVec2(-1, 3),
131 tcu::IVec2(3, -1),
132 };
133 static const tcu::IVec3 testSizes3D[] =
134 {
135 tcu::IVec3(1, 1, 1),
136 tcu::IVec3(1, 4, 7),
137 tcu::IVec3(4, 8, 12),
138 tcu::IVec3(21, 11, 9),
139 tcu::IVec3(107, 254, 2),
140 tcu::IVec3(-1, 3, 3),
141 tcu::IVec3(3, -1, 3),
142 tcu::IVec3(4, 4, -1),
143 };
144 static const tcu::Vec4 fullscreenQuad[] =
145 {
146 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
147 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
148 tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f),
149 tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f)
150 };
151
152 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
153
154 // requirements
155 if (m_isArrayType && !m_context.getContextInfo().isExtensionSupported("GL_OES_texture_storage_multisample_2d_array"))
156 TCU_THROW(NotSupportedError, "Test requires OES_texture_storage_multisample_2d_array extension");
157
158 if (m_context.getRenderTarget().getWidth() < 1 || m_context.getRenderTarget().getHeight() < 1)
159 TCU_THROW(NotSupportedError, "rendertarget size must be at least 1x1");
160
161 glw::GLint maxTextureSize = 0;
162 glw::GLint maxTextureLayers = 0;
163 glw::GLint maxSamples = 0;
164
165 gl.getIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
166 gl.getIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &maxTextureLayers);
167 gl.getInternalformativ(getTextureGLTarget(), getTextureGLInternalFormat(), GL_SAMPLES, 1, &maxSamples);
168
169 if (m_numSamples > maxSamples)
170 TCU_THROW(NotSupportedError, "sample count is not supported");
171
172 // gen shade
173
174 m_shader = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(s_positionVertexShaderSource) << glu::FragmentSource(genFragmentSource()));
175 m_testCtx.getLog() << *m_shader;
176 if (!m_shader->isOk())
177 throw tcu::TestError("shader build failed");
178
179 // gen buffer
180
181 gl.genBuffers(1, &m_vbo);
182 gl.bindBuffer(GL_ARRAY_BUFFER, m_vbo);
183 gl.bufferData(GL_ARRAY_BUFFER, sizeof(fullscreenQuad), fullscreenQuad, GL_STATIC_DRAW);
184
185 // gen iterations
186
187 m_testCtx.getLog()
188 << tcu::TestLog::Message
189 << "GL_MAX_TEXTURE_SIZE = " << maxTextureSize << "\n"
190 << "GL_MAX_ARRAY_TEXTURE_LAYERS = " << maxTextureLayers
191 << tcu::TestLog::EndMessage;
192
193 if (!m_isArrayType)
194 {
195 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(testSizes2D); ++ndx)
196 {
197 if (testSizes2D[ndx].x() <= maxTextureSize && testSizes2D[ndx].y() <= maxTextureSize)
198 {
199 const int w = (testSizes2D[ndx].x() < 0) ? (maxTextureSize) : (testSizes2D[ndx].x());
200 const int h = (testSizes2D[ndx].y() < 0) ? (maxTextureSize) : (testSizes2D[ndx].y());
201
202 m_iterations.push_back(tcu::IVec3(w, h, 0));
203 }
204 }
205 }
206 else
207 {
208 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(testSizes3D); ++ndx)
209 {
210 if (testSizes3D[ndx].x() <= maxTextureSize && testSizes3D[ndx].y() <= maxTextureSize && testSizes3D[ndx].z() <= maxTextureLayers)
211 {
212 const int w = (testSizes3D[ndx].x() < 0) ? (maxTextureSize) : (testSizes3D[ndx].x());
213 const int h = (testSizes3D[ndx].y() < 0) ? (maxTextureSize) : (testSizes3D[ndx].y());
214 const int d = (testSizes3D[ndx].z() < 0) ? (maxTextureLayers) : (testSizes3D[ndx].z());
215
216 m_iterations.push_back(tcu::IVec3(w, h, d));
217 }
218 }
219 }
220 }
221
deinit(void)222 void TextureSizeCase::deinit (void)
223 {
224 if (m_texture)
225 {
226 m_context.getRenderContext().getFunctions().deleteTextures(1, &m_texture);
227 m_texture = 0;
228 }
229
230 if (m_vbo)
231 {
232 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_vbo);
233 m_vbo = 0;
234 }
235
236 if (m_shader)
237 {
238 delete m_shader;
239 m_shader = DE_NULL;
240 }
241 }
242
iterate(void)243 TextureSizeCase::IterateResult TextureSizeCase::iterate (void)
244 {
245 tcu::Surface result (1, 1);
246 bool skipTest = false;
247
248 m_testCtx.getLog() << tcu::TestLog::Message << "\nIteration " << (m_iteration+1) << " / " << (int)m_iterations.size() << tcu::TestLog::EndMessage;
249
250 try
251 {
252 // set texture size
253
254 createTexture(m_iterations[m_iteration]);
255
256 // query texture size
257
258 runShader(result, m_iterations[m_iteration]);
259 }
260 catch (glu::OutOfMemoryError&)
261 {
262 m_testCtx.getLog() << tcu::TestLog::Message << "Got GL_OUT_OF_MEMORY, skipping this size" << tcu::TestLog::EndMessage;
263
264 skipTest = true;
265 }
266
267 // free resources
268
269 deleteTexture();
270
271 // queried value was correct?
272
273 if (!skipTest)
274 {
275 m_allCasesSkipped = false;
276
277 if (!verifyImage(result))
278 m_allIterationsPassed = false;
279 }
280
281 // final result
282
283 if (++m_iteration < (int)m_iterations.size())
284 return CONTINUE;
285
286 if (!m_allIterationsPassed)
287 {
288 m_testCtx.getLog() << tcu::TestLog::Message << "One or more test sizes failed." << tcu::TestLog::EndMessage;
289 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid texture size");
290 }
291 else if (m_allCasesSkipped)
292 {
293 m_testCtx.getLog() << tcu::TestLog::Message << "Could not test any texture size, texture creation failed." << tcu::TestLog::EndMessage;
294 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "All test texture creations failed");
295 }
296 else
297 {
298 m_testCtx.getLog() << tcu::TestLog::Message << "All texture sizes passed." << tcu::TestLog::EndMessage;
299 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
300 }
301
302 return STOP;
303 }
304
genFragmentSource(void)305 std::string TextureSizeCase::genFragmentSource (void)
306 {
307 static const char* const templateSource = "#version 310 es\n"
308 "${EXTENSION_STATEMENT}"
309 "layout(location = 0) out highp vec4 fragColor;\n"
310 "uniform highp ${SAMPLERTYPE} u_sampler;\n"
311 "uniform highp ${SIZETYPE} u_size;\n"
312 "void main (void)\n"
313 "{\n"
314 " const highp vec4 okColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
315 " const highp vec4 failColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
316 " fragColor = (textureSize(u_sampler) == u_size) ? (okColor) : (failColor);\n"
317 "}\n";
318
319 std::map<std::string, std::string> args;
320
321 switch (m_type)
322 {
323 case TEXTURE_FLOAT_2D: args["SAMPLERTYPE"] = "sampler2DMS"; break;
324 case TEXTURE_FLOAT_2D_ARRAY: args["SAMPLERTYPE"] = "sampler2DMSArray"; break;
325 case TEXTURE_INT_2D: args["SAMPLERTYPE"] = "isampler2DMS"; break;
326 case TEXTURE_INT_2D_ARRAY: args["SAMPLERTYPE"] = "isampler2DMSArray"; break;
327 case TEXTURE_UINT_2D: args["SAMPLERTYPE"] = "usampler2DMS"; break;
328 case TEXTURE_UINT_2D_ARRAY: args["SAMPLERTYPE"] = "usampler2DMSArray"; break;
329 default:
330 DE_ASSERT(DE_FALSE);
331 }
332
333 if (!m_isArrayType)
334 args["SIZETYPE"] = "ivec2";
335 else
336 args["SIZETYPE"] = "ivec3";
337
338 if (m_isArrayType)
339 args["EXTENSION_STATEMENT"] = "#extension GL_OES_texture_storage_multisample_2d_array : require\n";
340 else
341 args["EXTENSION_STATEMENT"] = "";
342
343 return tcu::StringTemplate(templateSource).specialize(args);
344 }
345
getTextureGLTarget(void)346 glw::GLenum TextureSizeCase::getTextureGLTarget (void)
347 {
348 switch (m_type)
349 {
350 case TEXTURE_FLOAT_2D: return GL_TEXTURE_2D_MULTISAMPLE;
351 case TEXTURE_FLOAT_2D_ARRAY: return GL_TEXTURE_2D_MULTISAMPLE_ARRAY;
352 case TEXTURE_INT_2D: return GL_TEXTURE_2D_MULTISAMPLE;
353 case TEXTURE_INT_2D_ARRAY: return GL_TEXTURE_2D_MULTISAMPLE_ARRAY;
354 case TEXTURE_UINT_2D: return GL_TEXTURE_2D_MULTISAMPLE;
355 case TEXTURE_UINT_2D_ARRAY: return GL_TEXTURE_2D_MULTISAMPLE_ARRAY;
356 default:
357 DE_ASSERT(DE_FALSE);
358 return 0;
359 }
360 }
361
getTextureGLInternalFormat(void)362 glw::GLenum TextureSizeCase::getTextureGLInternalFormat (void)
363 {
364 switch (m_type)
365 {
366 case TEXTURE_FLOAT_2D: return GL_RGBA8;
367 case TEXTURE_FLOAT_2D_ARRAY: return GL_RGBA8;
368 case TEXTURE_INT_2D: return GL_R8I;
369 case TEXTURE_INT_2D_ARRAY: return GL_R8I;
370 case TEXTURE_UINT_2D: return GL_R8UI;
371 case TEXTURE_UINT_2D_ARRAY: return GL_R8UI;
372 default:
373 DE_ASSERT(DE_FALSE);
374 return 0;
375 }
376 }
377
createTexture(const tcu::IVec3 & size)378 void TextureSizeCase::createTexture (const tcu::IVec3& size)
379 {
380 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
381
382 if (!m_isArrayType)
383 m_testCtx.getLog() << tcu::TestLog::Message << "Creating texture with size " << size.x() << "x" << size.y() << tcu::TestLog::EndMessage;
384 else
385 m_testCtx.getLog() << tcu::TestLog::Message << "Creating texture with size " << size.x() << "x" << size.y() << "x" << size.z() << tcu::TestLog::EndMessage;
386
387 gl.genTextures(1, &m_texture);
388 gl.bindTexture(getTextureGLTarget(), m_texture);
389 GLU_EXPECT_NO_ERROR(gl.getError(), "texture gen");
390
391 if (!m_isArrayType)
392 gl.texStorage2DMultisample(getTextureGLTarget(), m_numSamples, getTextureGLInternalFormat(), size.x(), size.y(), GL_FALSE);
393 else
394 gl.texStorage3DMultisample(getTextureGLTarget(), m_numSamples, getTextureGLInternalFormat(), size.x(), size.y(), size.z(), GL_FALSE);
395 GLU_EXPECT_NO_ERROR(gl.getError(), "texStorage");
396 }
397
deleteTexture(void)398 void TextureSizeCase::deleteTexture (void)
399 {
400 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
401
402 if (m_texture)
403 {
404 gl.deleteTextures(1, &m_texture);
405 m_texture = 0;
406
407 GLU_EXPECT_NO_ERROR(gl.getError(), "texture delete");
408 }
409 }
410
runShader(tcu::Surface & dst,const tcu::IVec3 & size)411 void TextureSizeCase::runShader (tcu::Surface& dst, const tcu::IVec3& size)
412 {
413 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
414 const int positionLoc = gl.getAttribLocation(m_shader->getProgram(), "a_position");
415 const int shaderSamplerLoc = gl.getUniformLocation(m_shader->getProgram(), "u_sampler");
416 const int shaderSizeLoc = gl.getUniformLocation(m_shader->getProgram(), "u_size");
417
418 m_testCtx.getLog() << tcu::TestLog::Message << "Running the verification shader." << tcu::TestLog::EndMessage;
419
420 GLU_EXPECT_NO_ERROR(gl.getError(), "preclear");
421 gl.viewport(0, 0, 1, 1);
422 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
423 gl.clear(GL_COLOR_BUFFER_BIT);
424 GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
425
426 gl.bindBuffer(GL_ARRAY_BUFFER, m_vbo);
427 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
428 gl.enableVertexAttribArray(positionLoc);
429 GLU_EXPECT_NO_ERROR(gl.getError(), "vertexAttrib");
430
431 gl.useProgram(m_shader->getProgram());
432 gl.uniform1i(shaderSamplerLoc, 0);
433 if (m_isArrayType)
434 gl.uniform3iv(shaderSizeLoc, 1, size.getPtr());
435 else
436 gl.uniform2iv(shaderSizeLoc, 1, size.getPtr());
437 GLU_EXPECT_NO_ERROR(gl.getError(), "setup program");
438
439 gl.bindTexture(getTextureGLTarget(), m_texture);
440 GLU_EXPECT_NO_ERROR(gl.getError(), "bindtex");
441
442 gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
443 GLU_EXPECT_NO_ERROR(gl.getError(), "drawArrays");
444
445 gl.disableVertexAttribArray(positionLoc);
446 gl.useProgram(0);
447 GLU_EXPECT_NO_ERROR(gl.getError(), "cleanup");
448
449 gl.finish();
450 glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
451 GLU_EXPECT_NO_ERROR(gl.getError(), "readPixels");
452 }
453
verifyImage(const tcu::Surface & dst)454 bool TextureSizeCase::verifyImage (const tcu::Surface& dst)
455 {
456 DE_ASSERT(dst.getWidth() == 1 && dst.getHeight() == 1);
457
458 const int colorThresholdRed = 1 << (8 - m_context.getRenderTarget().getPixelFormat().redBits);
459 const int colorThresholdGreen = 1 << (8 - m_context.getRenderTarget().getPixelFormat().greenBits);
460 const int colorThresholdBlue = 1 << (8 - m_context.getRenderTarget().getPixelFormat().blueBits);
461 const tcu::RGBA color = dst.getPixel(0,0);
462
463 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying image." << tcu::TestLog::EndMessage;
464
465 // green
466 if (color.getRed() < colorThresholdRed && color.getGreen() > 255 - colorThresholdGreen && color.getBlue() < colorThresholdBlue)
467 {
468 m_testCtx.getLog() << tcu::TestLog::Message << "Result ok." << tcu::TestLog::EndMessage;
469 return true;
470 }
471 // red
472 else if (color.getRed() > 255 - colorThresholdRed && color.getGreen() < colorThresholdGreen && color.getBlue() < colorThresholdBlue)
473 {
474 m_testCtx.getLog() << tcu::TestLog::Message << "Image size incorrect." << tcu::TestLog::EndMessage;
475 return false;
476 }
477
478 m_testCtx.getLog() << tcu::TestLog::Message << "Expected either green or red pixel, got " << color << tcu::TestLog::EndMessage;
479 return false;
480 }
481
482 } // anonymous
483
ShaderTextureSizeTests(Context & context)484 ShaderTextureSizeTests::ShaderTextureSizeTests (Context& context)
485 : TestCaseGroup(context, "texture_size", "Texture size tests")
486 {
487 }
488
~ShaderTextureSizeTests(void)489 ShaderTextureSizeTests::~ShaderTextureSizeTests (void)
490 {
491 }
492
init(void)493 void ShaderTextureSizeTests::init (void)
494 {
495 static const struct SamplerType
496 {
497 TextureSizeCase::TextureType type;
498 const char* name;
499 } samplerTypes[] =
500 {
501 { TextureSizeCase::TEXTURE_FLOAT_2D, "texture_2d" },
502 { TextureSizeCase::TEXTURE_FLOAT_2D_ARRAY, "texture_2d_array" },
503 { TextureSizeCase::TEXTURE_INT_2D, "texture_int_2d" },
504 { TextureSizeCase::TEXTURE_INT_2D_ARRAY, "texture_int_2d_array" },
505 { TextureSizeCase::TEXTURE_UINT_2D, "texture_uint_2d" },
506 { TextureSizeCase::TEXTURE_UINT_2D_ARRAY, "texture_uint_2d_array" },
507 };
508
509 static const int sampleCounts[] = { 1, 4 };
510
511 for (int samplerTypeNdx = 0; samplerTypeNdx < DE_LENGTH_OF_ARRAY(samplerTypes); ++samplerTypeNdx)
512 {
513 for (int sampleCountNdx = 0; sampleCountNdx < DE_LENGTH_OF_ARRAY(sampleCounts); ++sampleCountNdx)
514 {
515 const std::string name = std::string() + "samples_" + de::toString(sampleCounts[sampleCountNdx]) + "_" + samplerTypes[samplerTypeNdx].name;
516 const std::string desc = std::string() + "samples count = " + de::toString(sampleCounts[sampleCountNdx]) + ", type = " + samplerTypes[samplerTypeNdx].name;
517
518 addChild(new TextureSizeCase(m_context, name.c_str(), desc.c_str(), samplerTypes[samplerTypeNdx].type, sampleCounts[sampleCountNdx]));
519 }
520 }
521 }
522
523 } // Functional
524 } // gles31
525 } // deqp
526