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 test
22 *//*--------------------------------------------------------------------*/
23
24 #include "es31fTextureMultisampleTests.hpp"
25 #include "tcuTestLog.hpp"
26 #include "tcuRenderTarget.hpp"
27 #include "tcuSurface.hpp"
28 #include "tcuStringTemplate.hpp"
29 #include "tcuTextureUtil.hpp"
30 #include "glsStateQueryUtil.hpp"
31 #include "tcuRasterizationVerifier.hpp"
32 #include "gluRenderContext.hpp"
33 #include "gluCallLogWrapper.hpp"
34 #include "gluObjectWrapper.hpp"
35 #include "gluShaderProgram.hpp"
36 #include "gluPixelTransfer.hpp"
37 #include "gluStrUtil.hpp"
38 #include "gluContextInfo.hpp"
39 #include "glwEnums.hpp"
40 #include "glwFunctions.hpp"
41 #include "deStringUtil.hpp"
42 #include "deRandom.hpp"
43
44 using namespace glw;
45
46 namespace deqp
47 {
48 namespace gles31
49 {
50 namespace Functional
51 {
52 namespace
53 {
54
55 using tcu::RasterizationArguments;
56 using tcu::TriangleSceneSpec;
57
sampleMaskToString(const std::vector<deUint32> & bitfield,int numBits)58 static std::string sampleMaskToString (const std::vector<deUint32>& bitfield, int numBits)
59 {
60 std::string result(numBits, '0');
61
62 // move from back to front and set chars to 1
63 for (int wordNdx = 0; wordNdx < (int)bitfield.size(); ++wordNdx)
64 {
65 for (int bit = 0; bit < 32; ++bit)
66 {
67 const int targetCharNdx = numBits - (wordNdx*32+bit) - 1;
68
69 // beginning of the string reached
70 if (targetCharNdx < 0)
71 return result;
72
73 if ((bitfield[wordNdx] >> bit) & 0x01)
74 result[targetCharNdx] = '1';
75 }
76 }
77
78 return result;
79 }
80
81 /*--------------------------------------------------------------------*//*!
82 * \brief Returns the number of words needed to represent mask of given length
83 *//*--------------------------------------------------------------------*/
getEffectiveSampleMaskWordCount(int highestBitNdx)84 static int getEffectiveSampleMaskWordCount (int highestBitNdx)
85 {
86 const int wordSize = 32;
87 const int maskLen = highestBitNdx + 1;
88
89 return ((maskLen - 1) / wordSize) + 1; // round_up(mask_len / wordSize)
90 }
91
92 /*--------------------------------------------------------------------*//*!
93 * \brief Creates sample mask with all less significant bits than nthBit set
94 *//*--------------------------------------------------------------------*/
genAllSetToNthBitSampleMask(int nthBit)95 static std::vector<deUint32> genAllSetToNthBitSampleMask (int nthBit)
96 {
97 const int wordSize = 32;
98 const int numWords = getEffectiveSampleMaskWordCount(nthBit - 1);
99 const deUint32 topWordBits = (deUint32)(nthBit - (numWords - 1) * wordSize);
100 std::vector<deUint32> mask (numWords);
101
102 for (int ndx = 0; ndx < numWords - 1; ++ndx)
103 mask[ndx] = 0xFFFFFFFF;
104
105 mask[numWords - 1] = (deUint32)((1ULL << topWordBits) - (deUint32)1);
106 return mask;
107 }
108
109 /*--------------------------------------------------------------------*//*!
110 * \brief Creates sample mask with nthBit set
111 *//*--------------------------------------------------------------------*/
genSetNthBitSampleMask(int nthBit)112 static std::vector<deUint32> genSetNthBitSampleMask (int nthBit)
113 {
114 const int wordSize = 32;
115 const int numWords = getEffectiveSampleMaskWordCount(nthBit);
116 const deUint32 topWordBits = (deUint32)(nthBit - (numWords - 1) * wordSize);
117 std::vector<deUint32> mask (numWords);
118
119 for (int ndx = 0; ndx < numWords - 1; ++ndx)
120 mask[ndx] = 0;
121
122 mask[numWords - 1] = (deUint32)(1ULL << topWordBits);
123 return mask;
124 }
125
specializeShader(Context & context,const char * code)126 std::string specializeShader (Context& context, const char* code)
127 {
128 const glu::ContextType contextType = context.getRenderContext().getType();
129 const glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(contextType);
130 std::map<std::string, std::string> specializationMap;
131
132 specializationMap["GLSL_VERSION_DECL"] = glu::getGLSLVersionDeclaration(glslVersion);
133
134 return tcu::StringTemplate(code).specialize(specializationMap);
135 }
136
137 class SamplePosRasterizationTest : public TestCase
138 {
139 public:
140 SamplePosRasterizationTest (Context& context, const char* name, const char* desc, int samples);
141 ~SamplePosRasterizationTest (void);
142
143 private:
144 void init (void);
145 void deinit (void);
146 IterateResult iterate (void);
147 void genMultisampleTexture (void);
148 void genSamplerProgram (void);
149 bool testMultisampleTexture (int sampleNdx);
150 void drawSample (tcu::Surface& dst, int sampleNdx);
151 void convertToSceneSpec (TriangleSceneSpec& scene, const tcu::Vec2& samplePos) const;
152
153 struct Triangle
154 {
155 tcu::Vec4 p1;
156 tcu::Vec4 p2;
157 tcu::Vec4 p3;
158 };
159
160 const int m_samples;
161 const int m_canvasSize;
162 std::vector<Triangle> m_testTriangles;
163
164 int m_iteration;
165 bool m_allIterationsOk;
166
167 GLuint m_texID;
168 GLuint m_vaoID;
169 GLuint m_vboID;
170 std::vector<tcu::Vec2> m_samplePositions;
171 int m_subpixelBits;
172
173 const glu::ShaderProgram* m_samplerProgram;
174 GLint m_samplerProgramPosLoc;
175 GLint m_samplerProgramSamplerLoc;
176 GLint m_samplerProgramSampleNdxLoc;
177 };
178
SamplePosRasterizationTest(Context & context,const char * name,const char * desc,int samples)179 SamplePosRasterizationTest::SamplePosRasterizationTest (Context& context, const char* name, const char* desc, int samples)
180 : TestCase (context, name, desc)
181 , m_samples (samples)
182 , m_canvasSize (256)
183 , m_iteration (0)
184 , m_allIterationsOk (true)
185 , m_texID (0)
186 , m_vaoID (0)
187 , m_vboID (0)
188 , m_subpixelBits (0)
189 , m_samplerProgram (DE_NULL)
190 , m_samplerProgramPosLoc (-1)
191 , m_samplerProgramSamplerLoc (-1)
192 , m_samplerProgramSampleNdxLoc (-1)
193 {
194 }
195
~SamplePosRasterizationTest(void)196 SamplePosRasterizationTest::~SamplePosRasterizationTest (void)
197 {
198 deinit();
199 }
200
init(void)201 void SamplePosRasterizationTest::init (void)
202 {
203 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
204 GLint maxSamples = 0;
205
206 // requirements
207
208 if (m_context.getRenderTarget().getWidth() < m_canvasSize || m_context.getRenderTarget().getHeight() < m_canvasSize)
209 throw tcu::NotSupportedError("render target size must be at least " + de::toString(m_canvasSize) + "x" + de::toString(m_canvasSize));
210
211 gl.getIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &maxSamples);
212 if (m_samples > maxSamples)
213 throw tcu::NotSupportedError("Requested sample count is greater than GL_MAX_COLOR_TEXTURE_SAMPLES");
214
215 m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_COLOR_TEXTURE_SAMPLES = " << maxSamples << tcu::TestLog::EndMessage;
216
217 gl.getIntegerv(GL_SUBPIXEL_BITS, &m_subpixelBits);
218 m_testCtx.getLog() << tcu::TestLog::Message << "GL_SUBPIXEL_BITS = " << m_subpixelBits << tcu::TestLog::EndMessage;
219
220 // generate textures & other gl stuff
221
222 m_testCtx.getLog() << tcu::TestLog::Message << "Creating multisample texture" << tcu::TestLog::EndMessage;
223
224 gl.genTextures (1, &m_texID);
225 gl.bindTexture (GL_TEXTURE_2D_MULTISAMPLE, m_texID);
226 gl.texStorage2DMultisample (GL_TEXTURE_2D_MULTISAMPLE, m_samples, GL_RGBA8, m_canvasSize, m_canvasSize, GL_TRUE);
227 GLU_EXPECT_NO_ERROR (gl.getError(), "texStorage2DMultisample");
228
229 gl.genVertexArrays (1, &m_vaoID);
230 gl.bindVertexArray (m_vaoID);
231 GLU_EXPECT_NO_ERROR (gl.getError(), "bindVertexArray");
232
233 gl.genBuffers (1, &m_vboID);
234 gl.bindBuffer (GL_ARRAY_BUFFER, m_vboID);
235 GLU_EXPECT_NO_ERROR (gl.getError(), "bindBuffer");
236
237 // generate test scene
238 for (int i = 0; i < 20; ++i)
239 {
240 // vertical spikes
241 Triangle tri;
242 tri.p1 = tcu::Vec4(((float)i + 1.0f / (float)(i + 1)) / 20.0f, 0.0f, 0.0f, 1.0f);
243 tri.p2 = tcu::Vec4(((float)i + 0.3f + 1.0f / (float)(i + 1)) / 20.0f, 0.0f, 0.0f, 1.0f);
244 tri.p3 = tcu::Vec4(((float)i + 1.0f / (float)(i + 1)) / 20.0f, -1.0f, 0.0f, 1.0f);
245 m_testTriangles.push_back(tri);
246 }
247 for (int i = 0; i < 20; ++i)
248 {
249 // horisontal spikes
250 Triangle tri;
251 tri.p1 = tcu::Vec4(-1.0f, ((float)i + 1.0f / (float)(i + 1)) / 20.0f, 0.0f, 1.0f);
252 tri.p2 = tcu::Vec4(-1.0f, ((float)i + 0.3f + 1.0f / (float)(i + 1)) / 20.0f, 0.0f, 1.0f);
253 tri.p3 = tcu::Vec4( 0.0f, ((float)i + 1.0f / (float)(i + 1)) / 20.0f, 0.0f, 1.0f);
254 m_testTriangles.push_back(tri);
255 }
256
257 for (int i = 0; i < 20; ++i)
258 {
259 // fan
260 const tcu::Vec2 p = tcu::Vec2(deFloatCos(((float)i)/20.0f*DE_PI*2) * 0.5f + 0.5f, deFloatSin(((float)i)/20.0f*DE_PI*2) * 0.5f + 0.5f);
261 const tcu::Vec2 d = tcu::Vec2(0.1f, 0.02f);
262
263 Triangle tri;
264 tri.p1 = tcu::Vec4(0.4f, 0.4f, 0.0f, 1.0f);
265 tri.p2 = tcu::Vec4(p.x(), p.y(), 0.0f, 1.0f);
266 tri.p3 = tcu::Vec4(p.x() + d.x(), p.y() + d.y(), 0.0f, 1.0f);
267 m_testTriangles.push_back(tri);
268 }
269 {
270 Triangle tri;
271 tri.p1 = tcu::Vec4(-0.202f, -0.202f, 0.0f, 1.0f);
272 tri.p2 = tcu::Vec4(-0.802f, -0.202f, 0.0f, 1.0f);
273 tri.p3 = tcu::Vec4(-0.802f, -0.802f, 0.0f, 1.0f);
274 m_testTriangles.push_back(tri);
275 }
276
277 // generate multisample texture (and query the sample positions in it)
278 genMultisampleTexture();
279
280 // verify queried samples are in a valid range
281 for (int sampleNdx = 0; sampleNdx < m_samples; ++sampleNdx)
282 {
283 if (m_samplePositions[sampleNdx].x() < 0.0f || m_samplePositions[sampleNdx].x() > 1.0f ||
284 m_samplePositions[sampleNdx].y() < 0.0f || m_samplePositions[sampleNdx].y() > 1.0f)
285 {
286 m_testCtx.getLog() << tcu::TestLog::Message << "// ERROR: Sample position of sample " << sampleNdx << " should be in range ([0, 1], [0, 1]). Got " << m_samplePositions[sampleNdx] << tcu::TestLog::EndMessage;
287 throw tcu::TestError("invalid sample position");
288 }
289 }
290
291 // generate sampler program
292 genSamplerProgram();
293 }
294
deinit(void)295 void SamplePosRasterizationTest::deinit (void)
296 {
297 if (m_vboID)
298 {
299 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_vboID);
300 m_vboID = 0;
301 }
302
303 if (m_vaoID)
304 {
305 m_context.getRenderContext().getFunctions().deleteVertexArrays(1, &m_vaoID);
306 m_vaoID = 0;
307 }
308
309 if (m_texID)
310 {
311 m_context.getRenderContext().getFunctions().deleteTextures(1, &m_texID);
312 m_texID = 0;
313 }
314
315 if (m_samplerProgram)
316 {
317 delete m_samplerProgram;
318 m_samplerProgram = DE_NULL;
319 }
320 }
321
iterate(void)322 SamplePosRasterizationTest::IterateResult SamplePosRasterizationTest::iterate (void)
323 {
324 m_allIterationsOk &= testMultisampleTexture(m_iteration);
325 m_iteration++;
326
327 if (m_iteration < m_samples)
328 return CONTINUE;
329
330 // End result
331 if (m_allIterationsOk)
332 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
333 else
334 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Pixel comparison failed");
335
336 return STOP;
337 }
338
genMultisampleTexture(void)339 void SamplePosRasterizationTest::genMultisampleTexture (void)
340 {
341 const char* const vertexShaderSource = "${GLSL_VERSION_DECL}\n"
342 "in highp vec4 a_position;\n"
343 "void main (void)\n"
344 "{\n"
345 " gl_Position = a_position;\n"
346 "}\n";
347 const char* const fragmentShaderSource = "${GLSL_VERSION_DECL}\n"
348 "layout(location = 0) out highp vec4 fragColor;\n"
349 "void main (void)\n"
350 "{\n"
351 " fragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
352 "}\n";
353
354 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
355 const glu::ShaderProgram program (m_context.getRenderContext(), glu::ProgramSources()
356 << glu::VertexSource(specializeShader(m_context, vertexShaderSource))
357 << glu::FragmentSource(specializeShader(m_context, fragmentShaderSource)));
358 const GLuint posLoc = gl.getAttribLocation(program.getProgram(), "a_position");
359 GLuint fboID = 0;
360
361 if (!program.isOk())
362 {
363 m_testCtx.getLog() << program;
364 throw tcu::TestError("Failed to build shader.");
365 }
366
367 gl.bindTexture (GL_TEXTURE_2D_MULTISAMPLE, m_texID);
368 gl.bindVertexArray (m_vaoID);
369 gl.bindBuffer (GL_ARRAY_BUFFER, m_vboID);
370
371 // Setup fbo for drawing and for sample position query
372
373 m_testCtx.getLog() << tcu::TestLog::Message << "Attaching texture to FBO" << tcu::TestLog::EndMessage;
374
375 gl.genFramebuffers (1, &fboID);
376 gl.bindFramebuffer (GL_FRAMEBUFFER, fboID);
377 gl.framebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, m_texID, 0);
378 GLU_EXPECT_NO_ERROR (gl.getError(), "framebufferTexture2D");
379
380 // Query sample positions of the multisample texture by querying the sample positions
381 // from an fbo which has the multisample texture as attachment.
382
383 m_testCtx.getLog() << tcu::TestLog::Message << "Sample locations:" << tcu::TestLog::EndMessage;
384
385 for (int sampleNdx = 0; sampleNdx < m_samples; ++sampleNdx)
386 {
387 gls::StateQueryUtil::StateQueryMemoryWriteGuard<float[2]> position;
388
389 gl.getMultisamplefv(GL_SAMPLE_POSITION, (deUint32)sampleNdx, position);
390 if (!position.verifyValidity(m_testCtx))
391 throw tcu::TestError("Error while querying sample positions");
392
393 m_testCtx.getLog() << tcu::TestLog::Message << "\t" << sampleNdx << ": (" << position[0] << ", " << position[1] << ")" << tcu::TestLog::EndMessage;
394 m_samplePositions.push_back(tcu::Vec2(position[0], position[1]));
395 }
396
397 // Draw test pattern to texture
398
399 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing test pattern to the texture" << tcu::TestLog::EndMessage;
400
401 gl.bufferData (GL_ARRAY_BUFFER, (glw::GLsizeiptr)(m_testTriangles.size() * sizeof(Triangle)), &m_testTriangles[0], GL_STATIC_DRAW);
402 GLU_EXPECT_NO_ERROR (gl.getError(), "bufferData");
403
404 gl.viewport (0, 0, m_canvasSize, m_canvasSize);
405 gl.clearColor (0, 0, 0, 1);
406 gl.clear (GL_COLOR_BUFFER_BIT);
407 gl.vertexAttribPointer (posLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
408 gl.enableVertexAttribArray (posLoc);
409 GLU_EXPECT_NO_ERROR (gl.getError(), "vertexAttribPointer");
410
411 gl.useProgram (program.getProgram());
412 gl.drawArrays (GL_TRIANGLES, 0, (glw::GLsizei)(m_testTriangles.size() * 3));
413 GLU_EXPECT_NO_ERROR (gl.getError(), "drawArrays");
414
415 gl.disableVertexAttribArray (posLoc);
416 gl.useProgram (0);
417 gl.deleteFramebuffers (1, &fboID);
418 GLU_EXPECT_NO_ERROR (gl.getError(), "cleanup");
419 }
420
genSamplerProgram(void)421 void SamplePosRasterizationTest::genSamplerProgram (void)
422 {
423 const char* const vertexShaderSource = "${GLSL_VERSION_DECL}\n"
424 "in highp vec4 a_position;\n"
425 "void main (void)\n"
426 "{\n"
427 " gl_Position = a_position;\n"
428 "}\n";
429 const char* const fragShaderSource = "${GLSL_VERSION_DECL}\n"
430 "layout(location = 0) out highp vec4 fragColor;\n"
431 "uniform highp sampler2DMS u_sampler;\n"
432 "uniform highp int u_sample;\n"
433 "void main (void)\n"
434 "{\n"
435 " fragColor = texelFetch(u_sampler, ivec2(int(floor(gl_FragCoord.x)), int(floor(gl_FragCoord.y))), u_sample);\n"
436 "}\n";
437 const tcu::ScopedLogSection section (m_testCtx.getLog(), "Generate sampler shader", "Generate sampler shader");
438 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
439
440 m_samplerProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(specializeShader(m_context, vertexShaderSource)) << glu::FragmentSource(specializeShader(m_context, fragShaderSource)));
441 m_testCtx.getLog() << *m_samplerProgram;
442
443 if (!m_samplerProgram->isOk())
444 throw tcu::TestError("Could not create sampler program.");
445
446 m_samplerProgramPosLoc = gl.getAttribLocation(m_samplerProgram->getProgram(), "a_position");
447 m_samplerProgramSamplerLoc = gl.getUniformLocation(m_samplerProgram->getProgram(), "u_sampler");
448 m_samplerProgramSampleNdxLoc = gl.getUniformLocation(m_samplerProgram->getProgram(), "u_sample");
449 }
450
testMultisampleTexture(int sampleNdx)451 bool SamplePosRasterizationTest::testMultisampleTexture (int sampleNdx)
452 {
453 tcu::Surface glSurface(m_canvasSize, m_canvasSize);
454 TriangleSceneSpec scene;
455
456 // Draw sample
457 drawSample(glSurface, sampleNdx);
458
459 // Draw reference(s)
460 convertToSceneSpec(scene, m_samplePositions[sampleNdx]);
461
462 // Compare
463 {
464 RasterizationArguments args;
465 args.redBits = m_context.getRenderTarget().getPixelFormat().redBits;
466 args.greenBits = m_context.getRenderTarget().getPixelFormat().greenBits;
467 args.blueBits = m_context.getRenderTarget().getPixelFormat().blueBits;
468 args.numSamples = 0;
469 args.subpixelBits = m_subpixelBits;
470
471 return tcu::verifyTriangleGroupRasterization(glSurface, scene, args, m_testCtx.getLog(), tcu::VERIFICATIONMODE_STRICT);
472 }
473 }
474
drawSample(tcu::Surface & dst,int sampleNdx)475 void SamplePosRasterizationTest::drawSample (tcu::Surface& dst, int sampleNdx)
476 {
477 // Downsample using only one sample
478 static const tcu::Vec4 fullscreenQuad[] =
479 {
480 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
481 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
482 tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f),
483 tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f)
484 };
485
486 const tcu::ScopedLogSection section (m_testCtx.getLog(), "Test sample position " + de::toString(sampleNdx+1) + "/" + de::toString(m_samples), "Test sample position " + de::toString(sampleNdx+1) + "/" + de::toString(m_samples));
487 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
488
489 gl.bindTexture (GL_TEXTURE_2D_MULTISAMPLE, m_texID);
490 gl.bindVertexArray (m_vaoID);
491 gl.bindBuffer (GL_ARRAY_BUFFER, m_vboID);
492
493 gl.bufferData (GL_ARRAY_BUFFER, sizeof(fullscreenQuad), &fullscreenQuad[0], GL_STATIC_DRAW);
494 GLU_EXPECT_NO_ERROR (gl.getError(), "bufferData");
495
496 gl.viewport (0, 0, m_canvasSize, m_canvasSize);
497 gl.clearColor (0, 0, 0, 1);
498 gl.clear (GL_COLOR_BUFFER_BIT);
499 gl.vertexAttribPointer (m_samplerProgramPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
500 gl.enableVertexAttribArray (m_samplerProgramPosLoc);
501 GLU_EXPECT_NO_ERROR (gl.getError(), "vertexAttribPointer");
502
503 gl.useProgram (m_samplerProgram->getProgram());
504 gl.uniform1i (m_samplerProgramSamplerLoc, 0);
505 gl.uniform1i (m_samplerProgramSampleNdxLoc, (deInt32)sampleNdx);
506 GLU_EXPECT_NO_ERROR (gl.getError(), "useprogram");
507
508 m_testCtx.getLog() << tcu::TestLog::Message << "Reading from texture with sample index " << sampleNdx << tcu::TestLog::EndMessage;
509
510 gl.drawArrays (GL_TRIANGLE_STRIP, 0, 4);
511 GLU_EXPECT_NO_ERROR (gl.getError(), "drawArrays");
512
513 gl.disableVertexAttribArray (m_samplerProgramPosLoc);
514 gl.useProgram (0);
515 GLU_EXPECT_NO_ERROR (gl.getError(), "cleanup");
516
517 gl.finish ();
518 glu::readPixels (m_context.getRenderContext(), 0, 0, dst.getAccess());
519 GLU_EXPECT_NO_ERROR (gl.getError(), "readPixels");
520 }
521
convertToSceneSpec(TriangleSceneSpec & scene,const tcu::Vec2 & samplePos) const522 void SamplePosRasterizationTest::convertToSceneSpec (TriangleSceneSpec& scene, const tcu::Vec2& samplePos) const
523 {
524 // Triangles are offset from the pixel center by "offset". Move the triangles back to take this into account.
525 const tcu::Vec4 offset = tcu::Vec4(samplePos.x() - 0.5f, samplePos.y() - 0.5f, 0.0f, 0.0f) / tcu::Vec4((float)m_canvasSize, (float)m_canvasSize, 1.0f, 1.0f) * 2.0f;
526
527 for (int triangleNdx = 0; triangleNdx < (int)m_testTriangles.size(); ++triangleNdx)
528 {
529 TriangleSceneSpec::SceneTriangle triangle;
530
531 triangle.positions[0] = m_testTriangles[triangleNdx].p1 - offset;
532 triangle.positions[1] = m_testTriangles[triangleNdx].p2 - offset;
533 triangle.positions[2] = m_testTriangles[triangleNdx].p3 - offset;
534
535 triangle.sharedEdge[0] = false;
536 triangle.sharedEdge[1] = false;
537 triangle.sharedEdge[2] = false;
538
539 scene.triangles.push_back(triangle);
540 }
541 }
542
543 class SampleMaskCase : public TestCase
544 {
545 public:
546 enum CaseFlags
547 {
548 FLAGS_NONE = 0,
549 FLAGS_ALPHA_TO_COVERAGE = (1ULL << 0),
550 FLAGS_SAMPLE_COVERAGE = (1ULL << 1),
551 FLAGS_HIGH_BITS = (1ULL << 2),
552 };
553
554 SampleMaskCase (Context& context, const char* name, const char* desc, int samples, int flags);
555 ~SampleMaskCase (void);
556
557 private:
558 void init (void);
559 void deinit (void);
560 IterateResult iterate (void);
561
562 void genSamplerProgram (void);
563 void genAlphaProgram (void);
564 void updateTexture (int sample);
565 bool verifyTexture (int sample);
566 void drawSample (tcu::Surface& dst, int sample);
567
568 const int m_samples;
569 const int m_canvasSize;
570 const int m_gridsize;
571 const int m_effectiveSampleMaskWordCount;
572
573 int m_flags;
574 int m_currentSample;
575 int m_allIterationsOk;
576
577 glw::GLuint m_texID;
578 glw::GLuint m_vaoID;
579 glw::GLuint m_vboID;
580 glw::GLuint m_fboID;
581
582 const glu::ShaderProgram* m_samplerProgram;
583 glw::GLint m_samplerProgramPosLoc;
584 glw::GLint m_samplerProgramSamplerLoc;
585 glw::GLint m_samplerProgramSampleNdxLoc;
586
587 const glu::ShaderProgram* m_alphaProgram;
588 glw::GLint m_alphaProgramPosLoc;
589 };
590
SampleMaskCase(Context & context,const char * name,const char * desc,int samples,int flags)591 SampleMaskCase::SampleMaskCase (Context& context, const char* name, const char* desc, int samples, int flags)
592 : TestCase (context, name, desc)
593 , m_samples (samples)
594 , m_canvasSize (256)
595 , m_gridsize (16)
596 , m_effectiveSampleMaskWordCount(getEffectiveSampleMaskWordCount(samples - 1))
597 , m_flags (flags)
598 , m_currentSample (-1)
599 , m_allIterationsOk (true)
600 , m_texID (0)
601 , m_vaoID (0)
602 , m_vboID (0)
603 , m_fboID (0)
604 , m_samplerProgram (DE_NULL)
605 , m_samplerProgramPosLoc (-1)
606 , m_samplerProgramSamplerLoc (-1)
607 , m_samplerProgramSampleNdxLoc (-1)
608 , m_alphaProgram (DE_NULL)
609 , m_alphaProgramPosLoc (-1)
610 {
611 }
612
~SampleMaskCase(void)613 SampleMaskCase::~SampleMaskCase (void)
614 {
615 deinit();
616 }
617
init(void)618 void SampleMaskCase::init (void)
619 {
620 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
621 glw::GLint maxSamples = 0;
622 glw::GLint maxSampleMaskWords = 0;
623
624 // requirements
625
626 if (m_context.getRenderTarget().getWidth() < m_canvasSize || m_context.getRenderTarget().getHeight() < m_canvasSize)
627 throw tcu::NotSupportedError("render target size must be at least " + de::toString(m_canvasSize) + "x" + de::toString(m_canvasSize));
628
629 gl.getIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &maxSampleMaskWords);
630 if (m_effectiveSampleMaskWordCount > maxSampleMaskWords)
631 throw tcu::NotSupportedError("Test requires larger GL_MAX_SAMPLE_MASK_WORDS");
632
633 gl.getIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &maxSamples);
634 if (m_samples > maxSamples)
635 throw tcu::NotSupportedError("Requested sample count is greater than GL_MAX_COLOR_TEXTURE_SAMPLES");
636
637 m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_COLOR_TEXTURE_SAMPLES = " << maxSamples << tcu::TestLog::EndMessage;
638
639 // Don't even try to test high bits if there are none
640
641 if ((m_flags & FLAGS_HIGH_BITS) && (m_samples % 32 == 0))
642 {
643 m_testCtx.getLog() << tcu::TestLog::Message << "Sample count is multiple of word size. No unused high bits in sample mask.\nSkipping." << tcu::TestLog::EndMessage;
644 throw tcu::NotSupportedError("Test requires unused high bits (sample count not multiple of 32)");
645 }
646
647 // generate textures
648
649 m_testCtx.getLog() << tcu::TestLog::Message << "Creating multisample texture with sample count " << m_samples << tcu::TestLog::EndMessage;
650
651 gl.genTextures (1, &m_texID);
652 gl.bindTexture (GL_TEXTURE_2D_MULTISAMPLE, m_texID);
653 gl.texStorage2DMultisample (GL_TEXTURE_2D_MULTISAMPLE, m_samples, GL_RGBA8, m_canvasSize, m_canvasSize, GL_FALSE);
654 GLU_EXPECT_NO_ERROR (gl.getError(), "texStorage2DMultisample");
655
656 // attach texture to fbo
657
658 m_testCtx.getLog() << tcu::TestLog::Message << "Attaching texture to FBO" << tcu::TestLog::EndMessage;
659
660 gl.genFramebuffers (1, &m_fboID);
661 gl.bindFramebuffer (GL_FRAMEBUFFER, m_fboID);
662 gl.framebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, m_texID, 0);
663 GLU_EXPECT_NO_ERROR (gl.getError(), "framebufferTexture2D");
664
665 // buffers
666
667 gl.genVertexArrays (1, &m_vaoID);
668 GLU_EXPECT_NO_ERROR (gl.getError(), "genVertexArrays");
669
670 gl.genBuffers (1, &m_vboID);
671 gl.bindBuffer (GL_ARRAY_BUFFER, m_vboID);
672 GLU_EXPECT_NO_ERROR (gl.getError(), "genBuffers");
673
674 // generate grid pattern
675 {
676 std::vector<tcu::Vec4> gridData(m_gridsize*m_gridsize*6);
677
678 for (int y = 0; y < m_gridsize; ++y)
679 for (int x = 0; x < m_gridsize; ++x)
680 {
681 gridData[(y * m_gridsize + x)*6 + 0] = tcu::Vec4(((float)(x+0) / (float)m_gridsize) * 2.0f - 1.0f, ((float)(y+0) / (float)m_gridsize) * 2.0f - 1.0f, 0.0f, 1.0f);
682 gridData[(y * m_gridsize + x)*6 + 1] = tcu::Vec4(((float)(x+0) / (float)m_gridsize) * 2.0f - 1.0f, ((float)(y+1) / (float)m_gridsize) * 2.0f - 1.0f, 0.0f, 1.0f);
683 gridData[(y * m_gridsize + x)*6 + 2] = tcu::Vec4(((float)(x+1) / (float)m_gridsize) * 2.0f - 1.0f, ((float)(y+1) / (float)m_gridsize) * 2.0f - 1.0f, 0.0f, 1.0f);
684 gridData[(y * m_gridsize + x)*6 + 3] = tcu::Vec4(((float)(x+0) / (float)m_gridsize) * 2.0f - 1.0f, ((float)(y+0) / (float)m_gridsize) * 2.0f - 1.0f, 0.0f, 1.0f);
685 gridData[(y * m_gridsize + x)*6 + 4] = tcu::Vec4(((float)(x+1) / (float)m_gridsize) * 2.0f - 1.0f, ((float)(y+1) / (float)m_gridsize) * 2.0f - 1.0f, 0.0f, 1.0f);
686 gridData[(y * m_gridsize + x)*6 + 5] = tcu::Vec4(((float)(x+1) / (float)m_gridsize) * 2.0f - 1.0f, ((float)(y+0) / (float)m_gridsize) * 2.0f - 1.0f, 0.0f, 1.0f);
687 }
688
689 gl.bufferData (GL_ARRAY_BUFFER, (int)(gridData.size() * sizeof(tcu::Vec4)), gridData[0].getPtr(), GL_STATIC_DRAW);
690 GLU_EXPECT_NO_ERROR (gl.getError(), "bufferData");
691 }
692
693 // generate programs
694
695 genSamplerProgram();
696 genAlphaProgram();
697 }
698
deinit(void)699 void SampleMaskCase::deinit (void)
700 {
701 if (m_texID)
702 {
703 m_context.getRenderContext().getFunctions().deleteTextures(1, &m_texID);
704 m_texID = 0;
705 }
706 if (m_vaoID)
707 {
708 m_context.getRenderContext().getFunctions().deleteVertexArrays(1, &m_vaoID);
709 m_vaoID = 0;
710 }
711 if (m_vboID)
712 {
713 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_vboID);
714 m_vboID = 0;
715 }
716 if (m_fboID)
717 {
718 m_context.getRenderContext().getFunctions().deleteFramebuffers(1, &m_fboID);
719 m_fboID = 0;
720 }
721
722 if (m_samplerProgram)
723 {
724 delete m_samplerProgram;
725 m_samplerProgram = DE_NULL;
726 }
727 if (m_alphaProgram)
728 {
729 delete m_alphaProgram;
730 m_alphaProgram = DE_NULL;
731 }
732 }
733
iterate(void)734 SampleMaskCase::IterateResult SampleMaskCase::iterate (void)
735 {
736 const tcu::ScopedLogSection section(m_testCtx.getLog(), "Iteration", (m_currentSample == -1) ? ("Verifying with zero mask") : (std::string() + "Verifying sample " + de::toString(m_currentSample + 1) + "/" + de::toString(m_samples)));
737
738 bool iterationOk;
739
740 // Mask only one sample, clear rest
741
742 updateTexture(m_currentSample);
743
744 // Verify only one sample set is in the texture
745
746 iterationOk = verifyTexture(m_currentSample);
747 if (!iterationOk)
748 m_allIterationsOk = false;
749
750 m_currentSample++;
751 if (m_currentSample < m_samples)
752 return CONTINUE;
753
754 // End result
755
756 if (m_allIterationsOk)
757 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
758 else if (m_flags & FLAGS_HIGH_BITS)
759 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Unused mask bits have effect");
760 else
761 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Sample test failed");
762
763 return STOP;
764 }
765
genSamplerProgram(void)766 void SampleMaskCase::genSamplerProgram (void)
767 {
768 const char* const vertexShaderSource = "${GLSL_VERSION_DECL}\n"
769 "in highp vec4 a_position;\n"
770 "void main (void)\n"
771 "{\n"
772 " gl_Position = a_position;\n"
773 "}\n";
774 const char* const fragShaderSource = "${GLSL_VERSION_DECL}\n"
775 "layout(location = 0) out highp vec4 fragColor;\n"
776 "uniform highp sampler2DMS u_sampler;\n"
777 "uniform highp int u_sample;\n"
778 "void main (void)\n"
779 "{\n"
780 " highp float correctCoverage = 0.0;\n"
781 " highp float incorrectCoverage = 0.0;\n"
782 " highp ivec2 texelPos = ivec2(int(floor(gl_FragCoord.x)), int(floor(gl_FragCoord.y)));\n"
783 "\n"
784 " for (int sampleNdx = 0; sampleNdx < ${NUMSAMPLES}; ++sampleNdx)\n"
785 " {\n"
786 " highp float sampleColor = texelFetch(u_sampler, texelPos, sampleNdx).r;\n"
787 " if (sampleNdx == u_sample)\n"
788 " correctCoverage += sampleColor;\n"
789 " else\n"
790 " incorrectCoverage += sampleColor;\n"
791 " }\n"
792 " fragColor = vec4(correctCoverage, incorrectCoverage, 0.0, 1.0);\n"
793 "}\n";
794 const tcu::ScopedLogSection section (m_testCtx.getLog(), "GenerateSamplerShader", "Generate sampler shader");
795 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
796 std::map<std::string, std::string> args;
797 const glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType());
798
799 args["GLSL_VERSION_DECL"] = glu::getGLSLVersionDeclaration(glslVersion);
800 args["NUMSAMPLES"] = de::toString(m_samples);
801
802 m_samplerProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(specializeShader(m_context, vertexShaderSource)) << glu::FragmentSource(tcu::StringTemplate(fragShaderSource).specialize(args)));
803 m_testCtx.getLog() << *m_samplerProgram;
804
805 if (!m_samplerProgram->isOk())
806 throw tcu::TestError("Could not create sampler program.");
807
808 m_samplerProgramPosLoc = gl.getAttribLocation(m_samplerProgram->getProgram(), "a_position");
809 m_samplerProgramSamplerLoc = gl.getUniformLocation(m_samplerProgram->getProgram(), "u_sampler");
810 m_samplerProgramSampleNdxLoc = gl.getUniformLocation(m_samplerProgram->getProgram(), "u_sample");
811 }
812
genAlphaProgram(void)813 void SampleMaskCase::genAlphaProgram (void)
814 {
815 const char* const vertexShaderSource = "${GLSL_VERSION_DECL}\n"
816 "in highp vec4 a_position;\n"
817 "out highp float v_alpha;\n"
818 "void main (void)\n"
819 "{\n"
820 " gl_Position = a_position;\n"
821 " v_alpha = (a_position.x * 0.5 + 0.5)*(a_position.y * 0.5 + 0.5);\n"
822 "}\n";
823 const char* const fragShaderSource = "${GLSL_VERSION_DECL}\n"
824 "layout(location = 0) out highp vec4 fragColor;\n"
825 "in mediump float v_alpha;\n"
826 "void main (void)\n"
827 "{\n"
828 " fragColor = vec4(1.0, 1.0, 1.0, v_alpha);\n"
829 "}\n";
830 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
831
832 m_alphaProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(specializeShader(m_context, vertexShaderSource)) << glu::FragmentSource(specializeShader(m_context, fragShaderSource)));
833
834 if (!m_alphaProgram->isOk())
835 {
836 m_testCtx.getLog() << *m_alphaProgram;
837 throw tcu::TestError("Could not create aplha program.");
838 }
839
840 m_alphaProgramPosLoc = gl.getAttribLocation(m_alphaProgram->getProgram(), "a_position");
841 }
842
updateTexture(int sample)843 void SampleMaskCase::updateTexture (int sample)
844 {
845 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
846
847 // prepare draw
848
849 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID);
850 gl.viewport(0, 0, m_canvasSize, m_canvasSize);
851 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
852
853 // clear all samples
854
855 m_testCtx.getLog() << tcu::TestLog::Message << "Clearing image" << tcu::TestLog::EndMessage;
856 gl.clear(GL_COLOR_BUFFER_BIT);
857
858 // set mask state
859
860 if (m_flags & FLAGS_HIGH_BITS)
861 {
862 const std::vector<deUint32> bitmask = genSetNthBitSampleMask(sample);
863 const std::vector<deUint32> effectiveMask = genAllSetToNthBitSampleMask(m_samples);
864 std::vector<deUint32> totalBitmask (effectiveMask.size());
865
866 DE_ASSERT((int)totalBitmask.size() == m_effectiveSampleMaskWordCount);
867
868 // set some arbitrary high bits to non-effective bits
869 for (int wordNdx = 0; wordNdx < (int)effectiveMask.size(); ++wordNdx)
870 {
871 const deUint32 randomMask = (deUint32)deUint32Hash(wordNdx << 2 ^ sample);
872 const deUint32 sampleMask = (wordNdx < (int)bitmask.size()) ? (bitmask[wordNdx]) : (0);
873 const deUint32 maskMask = effectiveMask[wordNdx];
874
875 totalBitmask[wordNdx] = (sampleMask & maskMask) | (randomMask & ~maskMask);
876 }
877
878 m_testCtx.getLog() << tcu::TestLog::Message << "Setting sample mask to 0b" << sampleMaskToString(totalBitmask, (int)totalBitmask.size() * 32) << tcu::TestLog::EndMessage;
879
880 gl.enable(GL_SAMPLE_MASK);
881 for (int wordNdx = 0; wordNdx < m_effectiveSampleMaskWordCount; ++wordNdx)
882 {
883 const GLbitfield wordmask = (wordNdx < (int)totalBitmask.size()) ? ((GLbitfield)(totalBitmask[wordNdx])) : (0);
884 gl.sampleMaski((deUint32)wordNdx, wordmask);
885 }
886 }
887 else
888 {
889 const std::vector<deUint32> bitmask = genSetNthBitSampleMask(sample);
890 DE_ASSERT((int)bitmask.size() <= m_effectiveSampleMaskWordCount);
891
892 m_testCtx.getLog() << tcu::TestLog::Message << "Setting sample mask to 0b" << sampleMaskToString(bitmask, m_samples) << tcu::TestLog::EndMessage;
893
894 gl.enable(GL_SAMPLE_MASK);
895 for (int wordNdx = 0; wordNdx < m_effectiveSampleMaskWordCount; ++wordNdx)
896 {
897 const GLbitfield wordmask = (wordNdx < (int)bitmask.size()) ? ((GLbitfield)(bitmask[wordNdx])) : (0);
898 gl.sampleMaski((deUint32)wordNdx, wordmask);
899 }
900 }
901 if (m_flags & FLAGS_ALPHA_TO_COVERAGE)
902 {
903 m_testCtx.getLog() << tcu::TestLog::Message << "Enabling alpha to coverage." << tcu::TestLog::EndMessage;
904 gl.enable(GL_SAMPLE_ALPHA_TO_COVERAGE);
905 }
906 if (m_flags & FLAGS_SAMPLE_COVERAGE)
907 {
908 m_testCtx.getLog() << tcu::TestLog::Message << "Enabling sample coverage. Varying sample coverage for grid cells." << tcu::TestLog::EndMessage;
909 gl.enable(GL_SAMPLE_COVERAGE);
910 }
911
912 // draw test pattern
913
914 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing test grid" << tcu::TestLog::EndMessage;
915
916 gl.bindVertexArray (m_vaoID);
917 gl.bindBuffer (GL_ARRAY_BUFFER, m_vboID);
918 gl.vertexAttribPointer (m_alphaProgramPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
919 gl.enableVertexAttribArray (m_alphaProgramPosLoc);
920 GLU_EXPECT_NO_ERROR (gl.getError(), "vertexAttribPointer");
921
922 gl.useProgram (m_alphaProgram->getProgram());
923
924 for (int y = 0; y < m_gridsize; ++y)
925 for (int x = 0; x < m_gridsize; ++x)
926 {
927 if (m_flags & FLAGS_SAMPLE_COVERAGE)
928 gl.sampleCoverage((float)(y*m_gridsize + x) / float(m_gridsize*m_gridsize), GL_FALSE);
929
930 gl.drawArrays (GL_TRIANGLES, (y*m_gridsize + x) * 6, 6);
931 GLU_EXPECT_NO_ERROR (gl.getError(), "drawArrays");
932 }
933
934 // clean state
935
936 gl.disableVertexAttribArray (m_alphaProgramPosLoc);
937 gl.useProgram (0);
938 gl.bindFramebuffer (GL_FRAMEBUFFER, 0);
939 gl.disable (GL_SAMPLE_MASK);
940 gl.disable (GL_SAMPLE_ALPHA_TO_COVERAGE);
941 gl.disable (GL_SAMPLE_COVERAGE);
942 GLU_EXPECT_NO_ERROR (gl.getError(), "clean");
943 }
944
verifyTexture(int sample)945 bool SampleMaskCase::verifyTexture (int sample)
946 {
947 tcu::Surface result (m_canvasSize, m_canvasSize);
948 tcu::Surface errorMask (m_canvasSize, m_canvasSize);
949 bool error = false;
950
951 tcu::clear(errorMask.getAccess(), tcu::RGBA::green().toVec());
952
953 // Draw sample:
954 // Sample sampleNdx is set to red channel
955 // Other samples are set to green channel
956 drawSample(result, sample);
957
958 // Check surface contains only sampleNdx
959 for (int y = 0; y < m_canvasSize; ++y)
960 for (int x = 0; x < m_canvasSize; ++x)
961 {
962 const tcu::RGBA color = result.getPixel(x, y);
963
964 // Allow missing coverage with FLAGS_ALPHA_TO_COVERAGE and FLAGS_SAMPLE_COVERAGE, or if there are no samples enabled
965 const bool allowMissingCoverage = ((m_flags & (FLAGS_ALPHA_TO_COVERAGE | FLAGS_SAMPLE_COVERAGE)) != 0) || (sample == -1);
966
967 // disabled sample was written to
968 if (color.getGreen() != 0)
969 {
970 error = true;
971 errorMask.setPixel(x, y, tcu::RGBA::red());
972 }
973 // enabled sample was not written to
974 else if (color.getRed() != 255 && !allowMissingCoverage)
975 {
976 error = true;
977 errorMask.setPixel(x, y, tcu::RGBA::red());
978 }
979 }
980
981 if (error)
982 {
983 m_testCtx.getLog()
984 << tcu::TestLog::Message << "Image verification failed, disabled samples found." << tcu::TestLog::EndMessage
985 << tcu::TestLog::ImageSet("VerificationResult", "Result of rendering")
986 << tcu::TestLog::Image("Result", "Result", result)
987 << tcu::TestLog::Image("ErrorMask", "Error Mask", errorMask)
988 << tcu::TestLog::EndImageSet;
989 return false;
990 }
991 else
992 {
993 m_testCtx.getLog() << tcu::TestLog::Message << "Image verification ok, no disabled samples found." << tcu::TestLog::EndMessage;
994 return true;
995 }
996 }
997
drawSample(tcu::Surface & dst,int sample)998 void SampleMaskCase::drawSample (tcu::Surface& dst, int sample)
999 {
1000 // Downsample using only one sample
1001 static const tcu::Vec4 fullscreenQuad[] =
1002 {
1003 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
1004 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
1005 tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f),
1006 tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f)
1007 };
1008
1009 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1010 glu::Buffer vertexBuffer (m_context.getRenderContext());
1011
1012 gl.bindTexture (GL_TEXTURE_2D_MULTISAMPLE, m_texID);
1013 gl.bindVertexArray (m_vaoID);
1014
1015 gl.bindBuffer (GL_ARRAY_BUFFER, *vertexBuffer);
1016 gl.bufferData (GL_ARRAY_BUFFER, sizeof(fullscreenQuad), &fullscreenQuad[0], GL_STATIC_DRAW);
1017 GLU_EXPECT_NO_ERROR (gl.getError(), "bufferData");
1018
1019 gl.viewport (0, 0, m_canvasSize, m_canvasSize);
1020 gl.clearColor (0, 0, 0, 1);
1021 gl.clear (GL_COLOR_BUFFER_BIT);
1022 gl.vertexAttribPointer (m_samplerProgramPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
1023 gl.enableVertexAttribArray (m_samplerProgramPosLoc);
1024 GLU_EXPECT_NO_ERROR (gl.getError(), "vertexAttribPointer");
1025
1026 gl.useProgram (m_samplerProgram->getProgram());
1027 gl.uniform1i (m_samplerProgramSamplerLoc, 0);
1028 gl.uniform1i (m_samplerProgramSampleNdxLoc, (deInt32)sample);
1029 GLU_EXPECT_NO_ERROR (gl.getError(), "useprogram");
1030
1031 m_testCtx.getLog() << tcu::TestLog::Message << "Reading from texture with sampler shader, u_sample = " << sample << tcu::TestLog::EndMessage;
1032
1033 gl.drawArrays (GL_TRIANGLE_STRIP, 0, 4);
1034 GLU_EXPECT_NO_ERROR (gl.getError(), "drawArrays");
1035
1036 gl.disableVertexAttribArray (m_samplerProgramPosLoc);
1037 gl.useProgram (0);
1038 GLU_EXPECT_NO_ERROR (gl.getError(), "cleanup");
1039
1040 gl.finish ();
1041 glu::readPixels (m_context.getRenderContext(), 0, 0, dst.getAccess());
1042 GLU_EXPECT_NO_ERROR (gl.getError(), "readPixels");
1043 }
1044
1045 class MultisampleTextureUsageCase : public TestCase
1046 {
1047 public:
1048
1049 enum TextureType
1050 {
1051 TEXTURE_COLOR_2D = 0,
1052 TEXTURE_COLOR_2D_ARRAY,
1053 TEXTURE_INT_2D,
1054 TEXTURE_INT_2D_ARRAY,
1055 TEXTURE_UINT_2D,
1056 TEXTURE_UINT_2D_ARRAY,
1057 TEXTURE_DEPTH_2D,
1058 TEXTURE_DEPTH_2D_ARRAY,
1059
1060 TEXTURE_LAST
1061 };
1062
1063 MultisampleTextureUsageCase (Context& ctx, const char* name, const char* desc, int samples, TextureType type);
1064 ~MultisampleTextureUsageCase (void);
1065
1066 private:
1067 void init (void);
1068 void deinit (void);
1069 IterateResult iterate (void);
1070
1071 void genDrawShader (void);
1072 void genSamplerShader (void);
1073
1074 void renderToTexture (float value);
1075 void sampleTexture (tcu::Surface& dst, float value);
1076 bool verifyImage (const tcu::Surface& dst);
1077
1078 static const int s_textureSize = 256;
1079 static const int s_textureArraySize = 8;
1080 static const int s_textureLayer = 3;
1081
1082 const TextureType m_type;
1083 const int m_numSamples;
1084
1085 glw::GLuint m_fboID;
1086 glw::GLuint m_textureID;
1087
1088 glu::ShaderProgram* m_drawShader;
1089 glu::ShaderProgram* m_samplerShader;
1090
1091 const bool m_isColorFormat;
1092 const bool m_isSignedFormat;
1093 const bool m_isUnsignedFormat;
1094 const bool m_isDepthFormat;
1095 const bool m_isArrayType;
1096 };
1097
MultisampleTextureUsageCase(Context & ctx,const char * name,const char * desc,int samples,TextureType type)1098 MultisampleTextureUsageCase::MultisampleTextureUsageCase (Context& ctx, const char* name, const char* desc, int samples, TextureType type)
1099 : TestCase (ctx, name, desc)
1100 , m_type (type)
1101 , m_numSamples (samples)
1102 , m_fboID (0)
1103 , m_textureID (0)
1104 , m_drawShader (DE_NULL)
1105 , m_samplerShader (DE_NULL)
1106 , m_isColorFormat (m_type == TEXTURE_COLOR_2D || m_type == TEXTURE_COLOR_2D_ARRAY)
1107 , m_isSignedFormat (m_type == TEXTURE_INT_2D || m_type == TEXTURE_INT_2D_ARRAY)
1108 , m_isUnsignedFormat(m_type == TEXTURE_UINT_2D || m_type == TEXTURE_UINT_2D_ARRAY)
1109 , m_isDepthFormat (m_type == TEXTURE_DEPTH_2D || m_type == TEXTURE_DEPTH_2D_ARRAY)
1110 , m_isArrayType (m_type == TEXTURE_COLOR_2D_ARRAY || m_type == TEXTURE_INT_2D_ARRAY || m_type == TEXTURE_UINT_2D_ARRAY || m_type == TEXTURE_DEPTH_2D_ARRAY)
1111 {
1112 DE_ASSERT(m_type < TEXTURE_LAST);
1113 }
1114
~MultisampleTextureUsageCase(void)1115 MultisampleTextureUsageCase::~MultisampleTextureUsageCase (void)
1116 {
1117 deinit();
1118 }
1119
init(void)1120 void MultisampleTextureUsageCase::init (void)
1121 {
1122 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1123 const glw::GLenum internalFormat = (m_isColorFormat) ? (GL_R8) : (m_isSignedFormat) ? (GL_R8I) : (m_isUnsignedFormat) ? (GL_R8UI) : (m_isDepthFormat) ? (GL_DEPTH_COMPONENT32F) : (0);
1124 const glw::GLenum textureTarget = (m_isArrayType) ? (GL_TEXTURE_2D_MULTISAMPLE_ARRAY) : (GL_TEXTURE_2D_MULTISAMPLE);
1125 const glw::GLenum fboAttachment = (m_isDepthFormat) ? (GL_DEPTH_ATTACHMENT) : (GL_COLOR_ATTACHMENT0);
1126 const bool supportsES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
1127
1128 DE_ASSERT(internalFormat);
1129
1130 // requirements
1131
1132 if (m_isArrayType && !supportsES32 && !m_context.getContextInfo().isExtensionSupported("GL_OES_texture_storage_multisample_2d_array"))
1133 throw tcu::NotSupportedError("Test requires OES_texture_storage_multisample_2d_array extension");
1134 if (m_context.getRenderTarget().getWidth() < s_textureSize || m_context.getRenderTarget().getHeight() < s_textureSize)
1135 throw tcu::NotSupportedError("render target size must be at least " + de::toString(static_cast<int>(s_textureSize)) + "x" + de::toString(static_cast<int>(s_textureSize)));
1136
1137 {
1138 glw::GLint maxSamples = 0;
1139 gl.getInternalformativ(textureTarget, internalFormat, GL_SAMPLES, 1, &maxSamples);
1140
1141 if (m_numSamples > maxSamples)
1142 throw tcu::NotSupportedError("Requested sample count is greater than supported");
1143
1144 m_testCtx.getLog() << tcu::TestLog::Message << "Max sample count for " << glu::getTextureFormatStr(internalFormat) << ": " << maxSamples << tcu::TestLog::EndMessage;
1145 }
1146
1147 {
1148 GLint maxTextureSize = 0;
1149 gl.getIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
1150
1151 if (s_textureSize > maxTextureSize)
1152 throw tcu::NotSupportedError("Larger GL_MAX_TEXTURE_SIZE is required");
1153 }
1154
1155 if (m_isArrayType)
1156 {
1157 GLint maxTextureLayers = 0;
1158 gl.getIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &maxTextureLayers);
1159
1160 if (s_textureArraySize > maxTextureLayers)
1161 throw tcu::NotSupportedError("Larger GL_MAX_ARRAY_TEXTURE_LAYERS is required");
1162 }
1163
1164 // create texture
1165
1166 m_testCtx.getLog() << tcu::TestLog::Message << "Creating multisample " << ((m_isDepthFormat) ? ("depth") : ("")) << " texture" << ((m_isArrayType) ? (" array") : ("")) << tcu::TestLog::EndMessage;
1167
1168 gl.genTextures(1, &m_textureID);
1169 gl.bindTexture(textureTarget, m_textureID);
1170 GLU_EXPECT_NO_ERROR(gl.getError(), "bind texture");
1171
1172 if (m_isArrayType)
1173 gl.texStorage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, m_numSamples, internalFormat, s_textureSize, s_textureSize, s_textureArraySize, GL_FALSE);
1174 else
1175 gl.texStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_numSamples, internalFormat, s_textureSize, s_textureSize, GL_FALSE);
1176 GLU_EXPECT_NO_ERROR(gl.getError(), "texstorage");
1177
1178 // create fbo for drawing
1179
1180 gl.genFramebuffers(1, &m_fboID);
1181 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID);
1182
1183 if (m_isArrayType)
1184 {
1185 m_testCtx.getLog() << tcu::TestLog::Message << "Attaching multisample texture array layer " << static_cast<int>(s_textureLayer) << " to fbo" << tcu::TestLog::EndMessage;
1186 gl.framebufferTextureLayer(GL_FRAMEBUFFER, fboAttachment, m_textureID, 0, s_textureLayer);
1187 }
1188 else
1189 {
1190 m_testCtx.getLog() << tcu::TestLog::Message << "Attaching multisample texture to fbo" << tcu::TestLog::EndMessage;
1191 gl.framebufferTexture2D(GL_FRAMEBUFFER, fboAttachment, textureTarget, m_textureID, 0);
1192 }
1193 GLU_EXPECT_NO_ERROR(gl.getError(), "gen fbo");
1194
1195 // create shader for rendering to fbo
1196 genDrawShader();
1197
1198 // create shader for sampling the texture rendered to
1199 genSamplerShader();
1200 }
1201
deinit(void)1202 void MultisampleTextureUsageCase::deinit (void)
1203 {
1204 if (m_textureID)
1205 {
1206 m_context.getRenderContext().getFunctions().deleteTextures(1, &m_textureID);
1207 m_textureID = 0;
1208 }
1209
1210 if (m_fboID)
1211 {
1212 m_context.getRenderContext().getFunctions().deleteFramebuffers(1, &m_fboID);
1213 m_fboID = 0;
1214 }
1215
1216 if (m_drawShader)
1217 {
1218 delete m_drawShader;
1219 m_drawShader = DE_NULL;
1220 }
1221
1222 if (m_samplerShader)
1223 {
1224 delete m_samplerShader;
1225 m_samplerShader = DE_NULL;
1226 }
1227 }
1228
iterate(void)1229 MultisampleTextureUsageCase::IterateResult MultisampleTextureUsageCase::iterate (void)
1230 {
1231 const tcu::ScopedLogSection section (m_testCtx.getLog(), "Sample", "Render to texture and sample texture");
1232 tcu::Surface result (s_textureSize, s_textureSize);
1233 const float minValue = (m_isColorFormat || m_isDepthFormat) ? (0.0f) : (m_isSignedFormat) ? (-100.0f) : (m_isUnsignedFormat) ? (0.0f) : ( 1.0f);
1234 const float maxValue = (m_isColorFormat || m_isDepthFormat) ? (1.0f) : (m_isSignedFormat) ? ( 100.0f) : (m_isUnsignedFormat) ? (200.0f) : (-1.0f);
1235 de::Random rnd (deUint32Hash((deUint32)m_type));
1236 const float rawValue = rnd.getFloat(minValue, maxValue);
1237 const float preparedValue = (m_isSignedFormat || m_isUnsignedFormat) ? (deFloatFloor(rawValue)) : (rawValue);
1238
1239 // draw to fbo with a random value
1240
1241 renderToTexture(preparedValue);
1242
1243 // draw from texture to front buffer
1244
1245 sampleTexture(result, preparedValue);
1246
1247 // result is ok?
1248
1249 if (verifyImage(result))
1250 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1251 else
1252 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
1253
1254 return STOP;
1255 }
1256
genDrawShader(void)1257 void MultisampleTextureUsageCase::genDrawShader (void)
1258 {
1259 const tcu::ScopedLogSection section(m_testCtx.getLog(), "RenderShader", "Generate render-to-texture shader");
1260
1261 static const char* const vertexShaderSource = "${GLSL_VERSION_DECL}\n"
1262 "in highp vec4 a_position;\n"
1263 "void main (void)\n"
1264 "{\n"
1265 " gl_Position = a_position;\n"
1266 "}\n";
1267 static const char* const fragmentShaderSourceColor = "${GLSL_VERSION_DECL}\n"
1268 "layout(location = 0) out highp ${OUTTYPE} fragColor;\n"
1269 "uniform highp float u_writeValue;\n"
1270 "void main (void)\n"
1271 "{\n"
1272 " fragColor = ${OUTTYPE}(vec4(u_writeValue, 1.0, 1.0, 1.0));\n"
1273 "}\n";
1274 static const char* const fragmentShaderSourceDepth = "${GLSL_VERSION_DECL}\n"
1275 "layout(location = 0) out highp vec4 fragColor;\n"
1276 "uniform highp float u_writeValue;\n"
1277 "void main (void)\n"
1278 "{\n"
1279 " fragColor = vec4(0.0, 0.0, 0.0, 1.0);\n"
1280 " gl_FragDepth = u_writeValue;\n"
1281 "}\n";
1282 const char* const fragmentSource = (m_isDepthFormat) ? (fragmentShaderSourceDepth) : (fragmentShaderSourceColor);
1283
1284 std::map<std::string, std::string> fragmentArguments;
1285
1286 const glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType());
1287 fragmentArguments["GLSL_VERSION_DECL"] = glu::getGLSLVersionDeclaration(glslVersion);
1288
1289 if (m_isColorFormat || m_isDepthFormat)
1290 fragmentArguments["OUTTYPE"] = "vec4";
1291 else if (m_isSignedFormat)
1292 fragmentArguments["OUTTYPE"] = "ivec4";
1293 else if (m_isUnsignedFormat)
1294 fragmentArguments["OUTTYPE"] = "uvec4";
1295 else
1296 DE_ASSERT(DE_FALSE);
1297
1298 m_drawShader = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(specializeShader(m_context, vertexShaderSource)) << glu::FragmentSource(tcu::StringTemplate(fragmentSource).specialize(fragmentArguments)));
1299 m_testCtx.getLog() << *m_drawShader;
1300
1301 if (!m_drawShader->isOk())
1302 throw tcu::TestError("could not build shader");
1303 }
1304
genSamplerShader(void)1305 void MultisampleTextureUsageCase::genSamplerShader (void)
1306 {
1307 const tcu::ScopedLogSection section(m_testCtx.getLog(), "SamplerShader", "Generate texture sampler shader");
1308
1309 static const char* const vertexShaderSource = "${GLSL_VERSION_DECL}\n"
1310 "in highp vec4 a_position;\n"
1311 "out highp float v_gradient;\n"
1312 "void main (void)\n"
1313 "{\n"
1314 " gl_Position = a_position;\n"
1315 " v_gradient = a_position.x * 0.5 + 0.5;\n"
1316 "}\n";
1317 static const char* const fragmentShaderSource = "${GLSL_VERSION_DECL}\n"
1318 "${EXTENSION_STATEMENT}"
1319 "layout(location = 0) out highp vec4 fragColor;\n"
1320 "uniform highp ${SAMPLERTYPE} u_sampler;\n"
1321 "uniform highp int u_maxSamples;\n"
1322 "uniform highp int u_layer;\n"
1323 "uniform highp float u_cmpValue;\n"
1324 "in highp float v_gradient;\n"
1325 "void main (void)\n"
1326 "{\n"
1327 " const highp vec4 okColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
1328 " const highp vec4 failColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
1329 " const highp float epsilon = ${EPSILON};\n"
1330 "\n"
1331 " highp int sampleNdx = clamp(int(floor(v_gradient * float(u_maxSamples))), 0, u_maxSamples-1);\n"
1332 " highp float value = float(texelFetch(u_sampler, ${FETCHPOS}, sampleNdx).r);\n"
1333 " fragColor = (abs(u_cmpValue - value) < epsilon) ? (okColor) : (failColor);\n"
1334 "}\n";
1335
1336 std::map<std::string, std::string> fragmentArguments;
1337
1338 const glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType());
1339 fragmentArguments["GLSL_VERSION_DECL"] = glu::getGLSLVersionDeclaration(glslVersion);
1340
1341 if (m_isArrayType)
1342 fragmentArguments["FETCHPOS"] = "ivec3(floor(gl_FragCoord.xy), u_layer)";
1343 else
1344 fragmentArguments["FETCHPOS"] = "ivec2(floor(gl_FragCoord.xy))";
1345
1346 if (m_isColorFormat || m_isDepthFormat)
1347 fragmentArguments["EPSILON"] = "0.1";
1348 else
1349 fragmentArguments["EPSILON"] = "1.0";
1350
1351 if (m_isArrayType && !glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)))
1352 fragmentArguments["EXTENSION_STATEMENT"] = "#extension GL_OES_texture_storage_multisample_2d_array : require\n";
1353 else
1354 fragmentArguments["EXTENSION_STATEMENT"] = "";
1355
1356 switch (m_type)
1357 {
1358 case TEXTURE_COLOR_2D: fragmentArguments["SAMPLERTYPE"] = "sampler2DMS"; break;
1359 case TEXTURE_COLOR_2D_ARRAY: fragmentArguments["SAMPLERTYPE"] = "sampler2DMSArray"; break;
1360 case TEXTURE_INT_2D: fragmentArguments["SAMPLERTYPE"] = "isampler2DMS"; break;
1361 case TEXTURE_INT_2D_ARRAY: fragmentArguments["SAMPLERTYPE"] = "isampler2DMSArray"; break;
1362 case TEXTURE_UINT_2D: fragmentArguments["SAMPLERTYPE"] = "usampler2DMS"; break;
1363 case TEXTURE_UINT_2D_ARRAY: fragmentArguments["SAMPLERTYPE"] = "usampler2DMSArray"; break;
1364 case TEXTURE_DEPTH_2D: fragmentArguments["SAMPLERTYPE"] = "sampler2DMS"; break;
1365 case TEXTURE_DEPTH_2D_ARRAY: fragmentArguments["SAMPLERTYPE"] = "sampler2DMSArray"; break;
1366
1367 default:
1368 DE_ASSERT(DE_FALSE);
1369 }
1370
1371 m_samplerShader = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(specializeShader(m_context, vertexShaderSource)) << glu::FragmentSource(tcu::StringTemplate(fragmentShaderSource).specialize(fragmentArguments)));
1372 m_testCtx.getLog() << *m_samplerShader;
1373
1374 if (!m_samplerShader->isOk())
1375 throw tcu::TestError("could not build shader");
1376 }
1377
renderToTexture(float value)1378 void MultisampleTextureUsageCase::renderToTexture (float value)
1379 {
1380 static const tcu::Vec4 fullscreenQuad[] =
1381 {
1382 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
1383 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
1384 tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
1385 tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f),
1386 };
1387
1388 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1389 const int posLocation = gl.getAttribLocation(m_drawShader->getProgram(), "a_position");
1390 const int valueLocation = gl.getUniformLocation(m_drawShader->getProgram(), "u_writeValue");
1391 glu::Buffer vertexAttibBuffer (m_context.getRenderContext());
1392
1393 m_testCtx.getLog() << tcu::TestLog::Message << "Filling multisample texture with value " << value << tcu::TestLog::EndMessage;
1394
1395 // upload data
1396
1397 gl.bindBuffer(GL_ARRAY_BUFFER, *vertexAttibBuffer);
1398 gl.bufferData(GL_ARRAY_BUFFER, sizeof(fullscreenQuad), fullscreenQuad[0].getPtr(), GL_STATIC_DRAW);
1399 GLU_EXPECT_NO_ERROR(gl.getError(), "bufferdata");
1400
1401 // clear buffer
1402
1403 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID);
1404 gl.viewport(0, 0, s_textureSize, s_textureSize);
1405
1406 if (m_isColorFormat)
1407 {
1408 const float clearColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
1409 gl.clearBufferfv(GL_COLOR, 0, clearColor);
1410 }
1411 else if (m_isSignedFormat)
1412 {
1413 const deInt32 clearColor[4] = { 0, 0, 0, 0 };
1414 gl.clearBufferiv(GL_COLOR, 0, clearColor);
1415 }
1416 else if (m_isUnsignedFormat)
1417 {
1418 const deUint32 clearColor[4] = { 0, 0, 0, 0 };
1419 gl.clearBufferuiv(GL_COLOR, 0, clearColor);
1420 }
1421 else if (m_isDepthFormat)
1422 {
1423 const float clearDepth = 0.5f;
1424 gl.clearBufferfv(GL_DEPTH, 0, &clearDepth);
1425 }
1426
1427 GLU_EXPECT_NO_ERROR(gl.getError(), "clear buffer");
1428
1429 // setup shader and draw
1430
1431 gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
1432 gl.enableVertexAttribArray(posLocation);
1433
1434 gl.useProgram(m_drawShader->getProgram());
1435 gl.uniform1f(valueLocation, value);
1436
1437 GLU_EXPECT_NO_ERROR(gl.getError(), "setup draw");
1438
1439 if (m_isDepthFormat)
1440 {
1441 gl.enable(GL_DEPTH_TEST);
1442 gl.depthFunc(GL_ALWAYS);
1443 }
1444
1445 gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
1446 GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
1447
1448 // clean state
1449
1450 if (m_isDepthFormat)
1451 gl.disable(GL_DEPTH_TEST);
1452
1453 gl.disableVertexAttribArray(posLocation);
1454 gl.useProgram(0);
1455 gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
1456 GLU_EXPECT_NO_ERROR(gl.getError(), "clean");
1457 }
1458
sampleTexture(tcu::Surface & dst,float value)1459 void MultisampleTextureUsageCase::sampleTexture (tcu::Surface& dst, float value)
1460 {
1461 static const tcu::Vec4 fullscreenQuad[] =
1462 {
1463 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
1464 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
1465 tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
1466 tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f),
1467 };
1468
1469 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1470 const int posLocation = gl.getAttribLocation(m_samplerShader->getProgram(), "a_position");
1471 const int samplerLocation = gl.getUniformLocation(m_samplerShader->getProgram(), "u_sampler");
1472 const int maxSamplesLocation = gl.getUniformLocation(m_samplerShader->getProgram(), "u_maxSamples");
1473 const int layerLocation = gl.getUniformLocation(m_samplerShader->getProgram(), "u_layer");
1474 const int valueLocation = gl.getUniformLocation(m_samplerShader->getProgram(), "u_cmpValue");
1475 const glw::GLenum textureTarget = (m_isArrayType) ? (GL_TEXTURE_2D_MULTISAMPLE_ARRAY) : (GL_TEXTURE_2D_MULTISAMPLE);
1476 glu::Buffer vertexAttibBuffer (m_context.getRenderContext());
1477
1478 m_testCtx.getLog() << tcu::TestLog::Message << "Sampling from texture." << tcu::TestLog::EndMessage;
1479
1480 // upload data
1481
1482 gl.bindBuffer(GL_ARRAY_BUFFER, *vertexAttibBuffer);
1483 gl.bufferData(GL_ARRAY_BUFFER, sizeof(fullscreenQuad), fullscreenQuad[0].getPtr(), GL_STATIC_DRAW);
1484 GLU_EXPECT_NO_ERROR(gl.getError(), "bufferdata");
1485
1486 // clear
1487
1488 gl.viewport(0, 0, s_textureSize, s_textureSize);
1489 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1490 gl.clear(GL_COLOR_BUFFER_BIT);
1491
1492 // setup shader and draw
1493
1494 gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
1495 gl.enableVertexAttribArray(posLocation);
1496
1497 gl.useProgram(m_samplerShader->getProgram());
1498 gl.uniform1i(samplerLocation, 0);
1499 gl.uniform1i(maxSamplesLocation, m_numSamples);
1500 if (m_isArrayType)
1501 gl.uniform1i(layerLocation, s_textureLayer);
1502 gl.uniform1f(valueLocation, value);
1503 gl.bindTexture(textureTarget, m_textureID);
1504 GLU_EXPECT_NO_ERROR(gl.getError(), "setup draw");
1505
1506 gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
1507 GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
1508
1509 // clean state
1510
1511 gl.disableVertexAttribArray(posLocation);
1512 gl.useProgram(0);
1513 GLU_EXPECT_NO_ERROR(gl.getError(), "clean");
1514
1515 // read results
1516 gl.finish();
1517 glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
1518 }
1519
verifyImage(const tcu::Surface & dst)1520 bool MultisampleTextureUsageCase::verifyImage (const tcu::Surface& dst)
1521 {
1522 bool error = false;
1523
1524 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying image." << tcu::TestLog::EndMessage;
1525
1526 for (int y = 0; y < dst.getHeight(); ++y)
1527 for (int x = 0; x < dst.getWidth(); ++x)
1528 {
1529 const tcu::RGBA color = dst.getPixel(x, y);
1530 const int colorThresholdRed = 1 << (8 - m_context.getRenderTarget().getPixelFormat().redBits);
1531 const int colorThresholdGreen = 1 << (8 - m_context.getRenderTarget().getPixelFormat().greenBits);
1532 const int colorThresholdBlue = 1 << (8 - m_context.getRenderTarget().getPixelFormat().blueBits);
1533
1534 // only green is accepted
1535 if (color.getRed() > colorThresholdRed || color.getGreen() < 255 - colorThresholdGreen || color.getBlue() > colorThresholdBlue)
1536 error = true;
1537 }
1538
1539 if (error)
1540 {
1541 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid pixels found." << tcu::TestLog::EndMessage;
1542 m_testCtx.getLog()
1543 << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
1544 << tcu::TestLog::Image("Result", "Result", dst)
1545 << tcu::TestLog::EndImageSet;
1546
1547 return false;
1548 }
1549 else
1550 {
1551 m_testCtx.getLog() << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
1552 return true;
1553 }
1554 }
1555
1556 class NegativeFramebufferCase : public TestCase
1557 {
1558 public:
1559 enum CaseType
1560 {
1561 CASE_DIFFERENT_N_SAMPLES_TEX = 0,
1562 CASE_DIFFERENT_N_SAMPLES_RBO,
1563 CASE_DIFFERENT_FIXED_TEX,
1564 CASE_DIFFERENT_FIXED_RBO,
1565 CASE_NON_ZERO_LEVEL,
1566
1567 CASE_LAST
1568 };
1569
1570 NegativeFramebufferCase (Context& context, const char* name, const char* desc, CaseType caseType);
1571 ~NegativeFramebufferCase (void);
1572
1573 private:
1574 void init (void);
1575 void deinit (void);
1576 IterateResult iterate (void);
1577
1578 void getFormatSamples (glw::GLenum target, std::vector<int>& samples);
1579
1580 const CaseType m_caseType;
1581 const int m_fboSize;
1582 const glw::GLenum m_internalFormat;
1583
1584 int m_numSamples0; // !< samples for attachment 0
1585 int m_numSamples1; // !< samples for attachment 1
1586 };
1587
NegativeFramebufferCase(Context & context,const char * name,const char * desc,CaseType caseType)1588 NegativeFramebufferCase::NegativeFramebufferCase (Context& context, const char* name, const char* desc, CaseType caseType)
1589 : TestCase (context, name, desc)
1590 , m_caseType (caseType)
1591 , m_fboSize (64)
1592 , m_internalFormat (GL_RGBA8)
1593 , m_numSamples0 (-1)
1594 , m_numSamples1 (-1)
1595 {
1596 }
1597
~NegativeFramebufferCase(void)1598 NegativeFramebufferCase::~NegativeFramebufferCase (void)
1599 {
1600 deinit();
1601 }
1602
init(void)1603 void NegativeFramebufferCase::init (void)
1604 {
1605 const bool colorAttachmentTexture = (m_caseType == CASE_DIFFERENT_N_SAMPLES_TEX) || (m_caseType == CASE_DIFFERENT_FIXED_TEX);
1606 const bool colorAttachmentRbo = (m_caseType == CASE_DIFFERENT_N_SAMPLES_RBO) || (m_caseType == CASE_DIFFERENT_FIXED_RBO);
1607 const bool useDifferentSampleCounts= (m_caseType == CASE_DIFFERENT_N_SAMPLES_TEX) || (m_caseType == CASE_DIFFERENT_N_SAMPLES_RBO);
1608 std::vector<int> textureSamples;
1609 std::vector<int> rboSamples;
1610
1611 getFormatSamples(GL_TEXTURE_2D_MULTISAMPLE, textureSamples);
1612 getFormatSamples(GL_RENDERBUFFER, rboSamples);
1613
1614 TCU_CHECK(!textureSamples.empty());
1615 TCU_CHECK(!rboSamples.empty());
1616
1617 // select sample counts
1618
1619 if (useDifferentSampleCounts)
1620 {
1621 if (colorAttachmentTexture)
1622 {
1623 m_numSamples0 = textureSamples[0];
1624
1625 if (textureSamples.size() >= 2)
1626 m_numSamples1 = textureSamples[1];
1627 else
1628 throw tcu::NotSupportedError("Test requires multiple supported sample counts");
1629 }
1630 else if (colorAttachmentRbo)
1631 {
1632 for (int texNdx = 0; texNdx < (int)textureSamples.size(); ++texNdx)
1633 for (int rboNdx = 0; rboNdx < (int)rboSamples.size(); ++rboNdx)
1634 {
1635 if (textureSamples[texNdx] != rboSamples[rboNdx])
1636 {
1637 m_numSamples0 = textureSamples[texNdx];
1638 m_numSamples1 = rboSamples[rboNdx];
1639 return;
1640 }
1641 }
1642
1643 throw tcu::NotSupportedError("Test requires multiple supported sample counts");
1644 }
1645 else
1646 DE_ASSERT(DE_FALSE);
1647 }
1648 else
1649 {
1650 if (colorAttachmentTexture)
1651 {
1652 m_numSamples0 = textureSamples[0];
1653 m_numSamples1 = textureSamples[0];
1654 }
1655 else if (colorAttachmentRbo)
1656 {
1657 for (int texNdx = 0; texNdx < (int)textureSamples.size(); ++texNdx)
1658 for (int rboNdx = 0; rboNdx < (int)rboSamples.size(); ++rboNdx)
1659 {
1660 if (textureSamples[texNdx] == rboSamples[rboNdx])
1661 {
1662 m_numSamples0 = textureSamples[texNdx];
1663 m_numSamples1 = rboSamples[rboNdx];
1664 return;
1665 }
1666 }
1667
1668 throw tcu::NotSupportedError("Test requires a sample count supported in both rbo and texture");
1669 }
1670 else
1671 {
1672 m_numSamples0 = textureSamples[0];
1673 }
1674 }
1675 }
1676
deinit(void)1677 void NegativeFramebufferCase::deinit (void)
1678 {
1679 }
1680
iterate(void)1681 NegativeFramebufferCase::IterateResult NegativeFramebufferCase::iterate (void)
1682 {
1683 const bool colorAttachmentTexture = (m_caseType == CASE_DIFFERENT_N_SAMPLES_TEX) || (m_caseType == CASE_DIFFERENT_FIXED_TEX);
1684 const bool colorAttachmentRbo = (m_caseType == CASE_DIFFERENT_N_SAMPLES_RBO) || (m_caseType == CASE_DIFFERENT_FIXED_RBO);
1685 const glw::GLboolean fixedSampleLocations0 = (m_caseType == CASE_DIFFERENT_N_SAMPLES_RBO) ? (GL_TRUE) : (GL_FALSE);
1686 const glw::GLboolean fixedSampleLocations1 = ((m_caseType == CASE_DIFFERENT_FIXED_TEX) || (m_caseType == CASE_DIFFERENT_FIXED_RBO)) ? (GL_TRUE) : (GL_FALSE);
1687 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
1688 glw::GLuint fboId = 0;
1689 glw::GLuint rboId = 0;
1690 glw::GLuint tex0Id = 0;
1691 glw::GLuint tex1Id = 0;
1692
1693 bool testFailed = false;
1694
1695 gl.enableLogging(true);
1696
1697 try
1698 {
1699 gl.glGenFramebuffers(1, &fboId);
1700 gl.glBindFramebuffer(GL_FRAMEBUFFER, fboId);
1701 GLU_EXPECT_NO_ERROR(gl.glGetError(), "gen fbo");
1702
1703 gl.glGenTextures(1, &tex0Id);
1704 gl.glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex0Id);
1705 gl.glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_numSamples0, m_internalFormat, m_fboSize, m_fboSize, fixedSampleLocations0);
1706 GLU_EXPECT_NO_ERROR(gl.glGetError(), "gen texture 0");
1707
1708 if (m_caseType == CASE_NON_ZERO_LEVEL)
1709 {
1710 glw::GLenum error;
1711
1712 // attaching non-zero level generates invalid value
1713 gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, tex0Id, 5);
1714 error = gl.glGetError();
1715
1716 if (error != GL_INVALID_VALUE)
1717 {
1718 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Expected GL_INVALID_VALUE, got " << glu::getErrorStr(error) << tcu::TestLog::EndMessage;
1719 testFailed = true;
1720 }
1721 }
1722 else
1723 {
1724 gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, tex0Id, 0);
1725 GLU_EXPECT_NO_ERROR(gl.glGetError(), "attach to c0");
1726
1727 if (colorAttachmentTexture)
1728 {
1729 gl.glGenTextures(1, &tex1Id);
1730 gl.glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex1Id);
1731 gl.glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_numSamples1, m_internalFormat, m_fboSize, m_fboSize, fixedSampleLocations1);
1732 GLU_EXPECT_NO_ERROR(gl.glGetError(), "gen texture 1");
1733
1734 gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D_MULTISAMPLE, tex1Id, 0);
1735 GLU_EXPECT_NO_ERROR(gl.glGetError(), "attach to c1");
1736 }
1737 else if (colorAttachmentRbo)
1738 {
1739 gl.glGenRenderbuffers(1, &rboId);
1740 gl.glBindRenderbuffer(GL_RENDERBUFFER, rboId);
1741 gl.glRenderbufferStorageMultisample(GL_RENDERBUFFER, m_numSamples1, m_internalFormat, m_fboSize, m_fboSize);
1742 GLU_EXPECT_NO_ERROR(gl.glGetError(), "gen rb");
1743
1744 gl.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER, rboId);
1745 GLU_EXPECT_NO_ERROR(gl.glGetError(), "attach to c1");
1746 }
1747 else
1748 DE_ASSERT(DE_FALSE);
1749
1750 // should not be complete
1751 {
1752 glw::GLenum status = gl.glCheckFramebufferStatus(GL_FRAMEBUFFER);
1753
1754 if (status != GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE)
1755 {
1756 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Expected GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE, got " << glu::getFramebufferStatusName(status) << tcu::TestLog::EndMessage;
1757 testFailed = true;
1758 }
1759 }
1760 }
1761 }
1762 catch (...)
1763 {
1764 gl.glDeleteFramebuffers(1, &fboId);
1765 gl.glDeleteRenderbuffers(1, &rboId);
1766 gl.glDeleteTextures(1, &tex0Id);
1767 gl.glDeleteTextures(1, &tex1Id);
1768 throw;
1769 }
1770
1771 gl.glDeleteFramebuffers(1, &fboId);
1772 gl.glDeleteRenderbuffers(1, &rboId);
1773 gl.glDeleteTextures(1, &tex0Id);
1774 gl.glDeleteTextures(1, &tex1Id);
1775
1776 if (testFailed)
1777 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong error code");
1778 else
1779 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1780 return STOP;
1781 }
1782
getFormatSamples(glw::GLenum target,std::vector<int> & samples)1783 void NegativeFramebufferCase::getFormatSamples (glw::GLenum target, std::vector<int>& samples)
1784 {
1785 const glw::Functions gl = m_context.getRenderContext().getFunctions();
1786 int sampleCount = 0;
1787
1788 gl.getInternalformativ(target, m_internalFormat, GL_NUM_SAMPLE_COUNTS, 1, &sampleCount);
1789 samples.resize(sampleCount);
1790
1791 if (sampleCount > 0)
1792 {
1793 gl.getInternalformativ(target, m_internalFormat, GL_SAMPLES, sampleCount, &samples[0]);
1794 GLU_EXPECT_NO_ERROR(gl.getError(), "get max samples");
1795 }
1796 }
1797
1798 class NegativeTexParameterCase : public TestCase
1799 {
1800 public:
1801 enum TexParam
1802 {
1803 TEXTURE_MIN_FILTER = 0,
1804 TEXTURE_MAG_FILTER,
1805 TEXTURE_WRAP_S,
1806 TEXTURE_WRAP_T,
1807 TEXTURE_WRAP_R,
1808 TEXTURE_MIN_LOD,
1809 TEXTURE_MAX_LOD,
1810 TEXTURE_COMPARE_MODE,
1811 TEXTURE_COMPARE_FUNC,
1812 TEXTURE_BASE_LEVEL,
1813
1814 TEXTURE_LAST
1815 };
1816
1817 NegativeTexParameterCase (Context& context, const char* name, const char* desc, TexParam param);
1818 ~NegativeTexParameterCase (void);
1819
1820 private:
1821 void init (void);
1822 void deinit (void);
1823 IterateResult iterate (void);
1824
1825 glw::GLenum getParamGLEnum (void) const;
1826 glw::GLint getParamValue (void) const;
1827 glw::GLenum getExpectedError (void) const;
1828
1829 const TexParam m_texParam;
1830 int m_iteration;
1831 };
1832
NegativeTexParameterCase(Context & context,const char * name,const char * desc,TexParam param)1833 NegativeTexParameterCase::NegativeTexParameterCase (Context& context, const char* name, const char* desc, TexParam param)
1834 : TestCase (context, name, desc)
1835 , m_texParam (param)
1836 , m_iteration (0)
1837 {
1838 DE_ASSERT(param < TEXTURE_LAST);
1839 }
1840
~NegativeTexParameterCase(void)1841 NegativeTexParameterCase::~NegativeTexParameterCase (void)
1842 {
1843 deinit();
1844 }
1845
init(void)1846 void NegativeTexParameterCase::init (void)
1847 {
1848 // default value
1849 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1850 }
1851
deinit(void)1852 void NegativeTexParameterCase::deinit (void)
1853 {
1854 }
1855
iterate(void)1856 NegativeTexParameterCase::IterateResult NegativeTexParameterCase::iterate (void)
1857 {
1858 static const struct TextureType
1859 {
1860 const char* name;
1861 glw::GLenum target;
1862 glw::GLenum internalFormat;
1863 bool isArrayType;
1864 } types[] =
1865 {
1866 { "color", GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, false },
1867 { "color array", GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_RGBA8, true },
1868 { "signed integer", GL_TEXTURE_2D_MULTISAMPLE, GL_R8I, false },
1869 { "signed integer array", GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_R8I, true },
1870 { "unsigned integer", GL_TEXTURE_2D_MULTISAMPLE, GL_R8UI, false },
1871 { "unsigned integer array", GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_R8UI, true },
1872 };
1873
1874 const tcu::ScopedLogSection scope(m_testCtx.getLog(), "Iteration", std::string() + "Testing parameter with " + types[m_iteration].name + " texture");
1875 const bool supportsES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
1876
1877 if (types[m_iteration].isArrayType && !supportsES32 && !m_context.getContextInfo().isExtensionSupported("GL_OES_texture_storage_multisample_2d_array"))
1878 m_testCtx.getLog() << tcu::TestLog::Message << "GL_OES_texture_storage_multisample_2d_array not supported, skipping target" << tcu::TestLog::EndMessage;
1879 else
1880 {
1881 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
1882 glu::Texture texture (m_context.getRenderContext());
1883 glw::GLenum error;
1884
1885 gl.enableLogging(true);
1886
1887 // gen texture
1888
1889 gl.glBindTexture(types[m_iteration].target, *texture);
1890
1891 if (types[m_iteration].isArrayType)
1892 gl.glTexStorage3DMultisample(types[m_iteration].target, 1, types[m_iteration].internalFormat, 16, 16, 16, GL_FALSE);
1893 else
1894 gl.glTexStorage2DMultisample(types[m_iteration].target, 1, types[m_iteration].internalFormat, 16, 16, GL_FALSE);
1895 GLU_EXPECT_NO_ERROR(gl.glGetError(), "setup texture");
1896
1897 // set param
1898
1899 gl.glTexParameteri(types[m_iteration].target, getParamGLEnum(), getParamValue());
1900 error = gl.glGetError();
1901
1902 // expect failure
1903
1904 if (error != getExpectedError())
1905 {
1906 m_testCtx.getLog() << tcu::TestLog::Message << "Got unexpected error: " << glu::getErrorStr(error) << ", expected: " << glu::getErrorStr(getExpectedError()) << tcu::TestLog::EndMessage;
1907 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong error code");
1908 }
1909 }
1910
1911 if (++m_iteration < DE_LENGTH_OF_ARRAY(types))
1912 return CONTINUE;
1913 return STOP;
1914 }
1915
getParamGLEnum(void) const1916 glw::GLenum NegativeTexParameterCase::getParamGLEnum (void) const
1917 {
1918 switch (m_texParam)
1919 {
1920 case TEXTURE_MIN_FILTER: return GL_TEXTURE_MIN_FILTER;
1921 case TEXTURE_MAG_FILTER: return GL_TEXTURE_MAG_FILTER;
1922 case TEXTURE_WRAP_S: return GL_TEXTURE_WRAP_S;
1923 case TEXTURE_WRAP_T: return GL_TEXTURE_WRAP_T;
1924 case TEXTURE_WRAP_R: return GL_TEXTURE_WRAP_R;
1925 case TEXTURE_MIN_LOD: return GL_TEXTURE_MIN_LOD;
1926 case TEXTURE_MAX_LOD: return GL_TEXTURE_MAX_LOD;
1927 case TEXTURE_COMPARE_MODE: return GL_TEXTURE_COMPARE_MODE;
1928 case TEXTURE_COMPARE_FUNC: return GL_TEXTURE_COMPARE_FUNC;
1929 case TEXTURE_BASE_LEVEL: return GL_TEXTURE_BASE_LEVEL;
1930 default:
1931 DE_ASSERT(DE_FALSE);
1932 return 0;
1933 }
1934 }
1935
getParamValue(void) const1936 glw::GLint NegativeTexParameterCase::getParamValue (void) const
1937 {
1938 switch (m_texParam)
1939 {
1940 case TEXTURE_MIN_FILTER: return GL_LINEAR;
1941 case TEXTURE_MAG_FILTER: return GL_LINEAR;
1942 case TEXTURE_WRAP_S: return GL_CLAMP_TO_EDGE;
1943 case TEXTURE_WRAP_T: return GL_CLAMP_TO_EDGE;
1944 case TEXTURE_WRAP_R: return GL_CLAMP_TO_EDGE;
1945 case TEXTURE_MIN_LOD: return 1;
1946 case TEXTURE_MAX_LOD: return 5;
1947 case TEXTURE_COMPARE_MODE: return GL_NONE;
1948 case TEXTURE_COMPARE_FUNC: return GL_NOTEQUAL;
1949 case TEXTURE_BASE_LEVEL: return 2;
1950 default:
1951 DE_ASSERT(DE_FALSE);
1952 return 0;
1953 }
1954 }
1955
getExpectedError(void) const1956 glw::GLenum NegativeTexParameterCase::getExpectedError (void) const
1957 {
1958 switch (m_texParam)
1959 {
1960 case TEXTURE_MIN_FILTER: return GL_INVALID_ENUM;
1961 case TEXTURE_MAG_FILTER: return GL_INVALID_ENUM;
1962 case TEXTURE_WRAP_S: return GL_INVALID_ENUM;
1963 case TEXTURE_WRAP_T: return GL_INVALID_ENUM;
1964 case TEXTURE_WRAP_R: return GL_INVALID_ENUM;
1965 case TEXTURE_MIN_LOD: return GL_INVALID_ENUM;
1966 case TEXTURE_MAX_LOD: return GL_INVALID_ENUM;
1967 case TEXTURE_COMPARE_MODE: return GL_INVALID_ENUM;
1968 case TEXTURE_COMPARE_FUNC: return GL_INVALID_ENUM;
1969 case TEXTURE_BASE_LEVEL: return GL_INVALID_OPERATION;
1970 default:
1971 DE_ASSERT(DE_FALSE);
1972 return 0;
1973 }
1974 }
1975
1976 class NegativeTexureSampleCase : public TestCase
1977 {
1978 public:
1979 enum SampleCountParam
1980 {
1981 SAMPLECOUNT_HIGH = 0,
1982 SAMPLECOUNT_ZERO,
1983
1984 SAMPLECOUNT_LAST
1985 };
1986
1987 NegativeTexureSampleCase (Context& context, const char* name, const char* desc, SampleCountParam param);
1988 private:
1989 IterateResult iterate (void);
1990
1991 const SampleCountParam m_sampleParam;
1992 };
1993
NegativeTexureSampleCase(Context & context,const char * name,const char * desc,SampleCountParam param)1994 NegativeTexureSampleCase::NegativeTexureSampleCase (Context& context, const char* name, const char* desc, SampleCountParam param)
1995 : TestCase (context, name, desc)
1996 , m_sampleParam (param)
1997 {
1998 DE_ASSERT(param < SAMPLECOUNT_LAST);
1999 }
2000
iterate(void)2001 NegativeTexureSampleCase::IterateResult NegativeTexureSampleCase::iterate (void)
2002 {
2003 const glw::GLenum expectedError = (m_sampleParam == SAMPLECOUNT_HIGH) ? (GL_INVALID_OPERATION) : (GL_INVALID_VALUE);
2004 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
2005 glu::Texture texture (m_context.getRenderContext());
2006 glw::GLenum error;
2007 int samples = -1;
2008
2009 gl.enableLogging(true);
2010
2011 // calc samples
2012
2013 if (m_sampleParam == SAMPLECOUNT_HIGH)
2014 {
2015 int maxSamples = 0;
2016
2017 gl.glGetInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, GL_SAMPLES, 1, &maxSamples);
2018 GLU_EXPECT_NO_ERROR(gl.glGetError(), "glGetInternalformativ");
2019
2020 samples = maxSamples + 1;
2021 }
2022 else if (m_sampleParam == SAMPLECOUNT_ZERO)
2023 samples = 0;
2024 else
2025 DE_ASSERT(DE_FALSE);
2026
2027 // create texture with bad values
2028
2029 gl.glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, *texture);
2030 gl.glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGBA8, 64, 64, GL_FALSE);
2031 error = gl.glGetError();
2032
2033 // expect failure
2034
2035 if (error == expectedError)
2036 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2037 else
2038 {
2039 m_testCtx.getLog() << tcu::TestLog::Message << "Got unexpected error: " << glu::getErrorStr(error) << ", expected: " << glu::getErrorStr(expectedError) << tcu::TestLog::EndMessage;
2040 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong error code");
2041 }
2042
2043 return STOP;
2044 }
2045
2046
2047 } // anonymous
2048
TextureMultisampleTests(Context & context)2049 TextureMultisampleTests::TextureMultisampleTests (Context& context)
2050 : TestCaseGroup(context, "multisample", "Multisample texture tests")
2051 {
2052 }
2053
~TextureMultisampleTests(void)2054 TextureMultisampleTests::~TextureMultisampleTests (void)
2055 {
2056 }
2057
init(void)2058 void TextureMultisampleTests::init (void)
2059 {
2060 static const int sampleCounts[] = { 1, 2, 3, 4, 8, 10, 12, 13, 16, 64 };
2061
2062 static const struct TextureType
2063 {
2064 const char* name;
2065 MultisampleTextureUsageCase::TextureType type;
2066 } textureTypes[] =
2067 {
2068 { "texture_color_2d", MultisampleTextureUsageCase::TEXTURE_COLOR_2D },
2069 { "texture_color_2d_array", MultisampleTextureUsageCase::TEXTURE_COLOR_2D_ARRAY },
2070 { "texture_int_2d", MultisampleTextureUsageCase::TEXTURE_INT_2D },
2071 { "texture_int_2d_array", MultisampleTextureUsageCase::TEXTURE_INT_2D_ARRAY },
2072 { "texture_uint_2d", MultisampleTextureUsageCase::TEXTURE_UINT_2D },
2073 { "texture_uint_2d_array", MultisampleTextureUsageCase::TEXTURE_UINT_2D_ARRAY },
2074 { "texture_depth_2d", MultisampleTextureUsageCase::TEXTURE_DEPTH_2D },
2075 { "texture_depth_2d_array", MultisampleTextureUsageCase::TEXTURE_DEPTH_2D_ARRAY },
2076 };
2077
2078 // .samples_x
2079 for (int sampleNdx = 0; sampleNdx < DE_LENGTH_OF_ARRAY(sampleCounts); ++sampleNdx)
2080 {
2081 tcu::TestCaseGroup* const sampleGroup = new tcu::TestCaseGroup(m_testCtx, (std::string("samples_") + de::toString(sampleCounts[sampleNdx])).c_str(), "Test with N samples");
2082 addChild(sampleGroup);
2083
2084 // position query works
2085 sampleGroup->addChild(new SamplePosRasterizationTest(m_context, "sample_position", "test SAMPLE_POSITION", sampleCounts[sampleNdx]));
2086
2087 // sample mask is ANDed properly
2088 sampleGroup->addChild(new SampleMaskCase(m_context, "sample_mask_only", "Test with SampleMask only", sampleCounts[sampleNdx], SampleMaskCase::FLAGS_NONE));
2089 sampleGroup->addChild(new SampleMaskCase(m_context, "sample_mask_and_alpha_to_coverage", "Test with SampleMask and alpha to coverage", sampleCounts[sampleNdx], SampleMaskCase::FLAGS_ALPHA_TO_COVERAGE));
2090 sampleGroup->addChild(new SampleMaskCase(m_context, "sample_mask_and_sample_coverage", "Test with SampleMask and sample coverage", sampleCounts[sampleNdx], SampleMaskCase::FLAGS_SAMPLE_COVERAGE));
2091 sampleGroup->addChild(new SampleMaskCase(m_context, "sample_mask_and_sample_coverage_and_alpha_to_coverage", "Test with SampleMask, sample coverage, and alpha to coverage", sampleCounts[sampleNdx], SampleMaskCase::FLAGS_ALPHA_TO_COVERAGE | SampleMaskCase::FLAGS_SAMPLE_COVERAGE));
2092
2093 // high bits cause no unexpected behavior
2094 sampleGroup->addChild(new SampleMaskCase(m_context, "sample_mask_non_effective_bits", "Test with SampleMask, set higher bits than sample count", sampleCounts[sampleNdx], SampleMaskCase::FLAGS_HIGH_BITS));
2095
2096 // usage
2097 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(textureTypes); ++typeNdx)
2098 sampleGroup->addChild(new MultisampleTextureUsageCase(m_context, (std::string("use_") + textureTypes[typeNdx].name).c_str(), textureTypes[typeNdx].name, sampleCounts[sampleNdx], textureTypes[typeNdx].type));
2099 }
2100
2101 // .negative
2102 {
2103 tcu::TestCaseGroup* const negativeGroup = new tcu::TestCaseGroup(m_testCtx, "negative", "Negative tests");
2104 addChild(negativeGroup);
2105
2106 negativeGroup->addChild(new NegativeFramebufferCase (m_context, "fbo_attach_different_sample_count_tex_tex", "Attach different sample counts", NegativeFramebufferCase::CASE_DIFFERENT_N_SAMPLES_TEX));
2107 negativeGroup->addChild(new NegativeFramebufferCase (m_context, "fbo_attach_different_sample_count_tex_rbo", "Attach different sample counts", NegativeFramebufferCase::CASE_DIFFERENT_N_SAMPLES_RBO));
2108 negativeGroup->addChild(new NegativeFramebufferCase (m_context, "fbo_attach_different_fixed_state_tex_tex", "Attach fixed and non fixed", NegativeFramebufferCase::CASE_DIFFERENT_FIXED_TEX));
2109 negativeGroup->addChild(new NegativeFramebufferCase (m_context, "fbo_attach_different_fixed_state_tex_rbo", "Attach fixed and non fixed", NegativeFramebufferCase::CASE_DIFFERENT_FIXED_RBO));
2110 negativeGroup->addChild(new NegativeFramebufferCase (m_context, "fbo_attach_non_zero_level", "Attach non-zero level", NegativeFramebufferCase::CASE_NON_ZERO_LEVEL));
2111 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_min_filter", "set TEXTURE_MIN_FILTER", NegativeTexParameterCase::TEXTURE_MIN_FILTER));
2112 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_mag_filter", "set TEXTURE_MAG_FILTER", NegativeTexParameterCase::TEXTURE_MAG_FILTER));
2113 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_wrap_s", "set TEXTURE_WRAP_S", NegativeTexParameterCase::TEXTURE_WRAP_S));
2114 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_wrap_t", "set TEXTURE_WRAP_T", NegativeTexParameterCase::TEXTURE_WRAP_T));
2115 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_wrap_r", "set TEXTURE_WRAP_R", NegativeTexParameterCase::TEXTURE_WRAP_R));
2116 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_min_lod", "set TEXTURE_MIN_LOD", NegativeTexParameterCase::TEXTURE_MIN_LOD));
2117 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_max_lod", "set TEXTURE_MAX_LOD", NegativeTexParameterCase::TEXTURE_MAX_LOD));
2118 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_compare_mode", "set TEXTURE_COMPARE_MODE", NegativeTexParameterCase::TEXTURE_COMPARE_MODE));
2119 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_compare_func", "set TEXTURE_COMPARE_FUNC", NegativeTexParameterCase::TEXTURE_COMPARE_FUNC));
2120 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_base_level", "set TEXTURE_BASE_LEVEL", NegativeTexParameterCase::TEXTURE_BASE_LEVEL));
2121 negativeGroup->addChild(new NegativeTexureSampleCase(m_context, "texture_high_sample_count", "TexStorage with high numSamples", NegativeTexureSampleCase::SAMPLECOUNT_HIGH));
2122 negativeGroup->addChild(new NegativeTexureSampleCase(m_context, "texture_zero_sample_count", "TexStorage with zero numSamples", NegativeTexureSampleCase::SAMPLECOUNT_ZERO));
2123 }
2124 }
2125
2126 } // Functional
2127 } // gles31
2128 } // deqp
2129