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 glw::GLint getMaxConformantSampleCount (glw::GLenum target, glw::GLenum internalFormat);
569
570 const int m_samples;
571 const int m_canvasSize;
572 const int m_gridsize;
573 const int m_effectiveSampleMaskWordCount;
574
575 int m_flags;
576 int m_currentSample;
577 int m_allIterationsOk;
578
579 glw::GLuint m_texID;
580 glw::GLuint m_vaoID;
581 glw::GLuint m_vboID;
582 glw::GLuint m_fboID;
583
584 const glu::ShaderProgram* m_samplerProgram;
585 glw::GLint m_samplerProgramPosLoc;
586 glw::GLint m_samplerProgramSamplerLoc;
587 glw::GLint m_samplerProgramSampleNdxLoc;
588
589 const glu::ShaderProgram* m_alphaProgram;
590 glw::GLint m_alphaProgramPosLoc;
591 };
592
SampleMaskCase(Context & context,const char * name,const char * desc,int samples,int flags)593 SampleMaskCase::SampleMaskCase (Context& context, const char* name, const char* desc, int samples, int flags)
594 : TestCase (context, name, desc)
595 , m_samples (samples)
596 , m_canvasSize (256)
597 , m_gridsize (16)
598 , m_effectiveSampleMaskWordCount(getEffectiveSampleMaskWordCount(samples - 1))
599 , m_flags (flags)
600 , m_currentSample (-1)
601 , m_allIterationsOk (true)
602 , m_texID (0)
603 , m_vaoID (0)
604 , m_vboID (0)
605 , m_fboID (0)
606 , m_samplerProgram (DE_NULL)
607 , m_samplerProgramPosLoc (-1)
608 , m_samplerProgramSamplerLoc (-1)
609 , m_samplerProgramSampleNdxLoc (-1)
610 , m_alphaProgram (DE_NULL)
611 , m_alphaProgramPosLoc (-1)
612 {
613 }
614
~SampleMaskCase(void)615 SampleMaskCase::~SampleMaskCase (void)
616 {
617 deinit();
618 }
619
init(void)620 void SampleMaskCase::init (void)
621 {
622 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
623 glw::GLint maxSamples = 0;
624 glw::GLint maxSampleMaskWords = 0;
625
626 // requirements
627
628 if (m_context.getRenderTarget().getWidth() < m_canvasSize || m_context.getRenderTarget().getHeight() < m_canvasSize)
629 throw tcu::NotSupportedError("render target size must be at least " + de::toString(m_canvasSize) + "x" + de::toString(m_canvasSize));
630
631 gl.getIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &maxSampleMaskWords);
632 if (m_effectiveSampleMaskWordCount > maxSampleMaskWords)
633 throw tcu::NotSupportedError("Test requires larger GL_MAX_SAMPLE_MASK_WORDS");
634
635 maxSamples = getMaxConformantSampleCount(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8);
636 if (m_samples > maxSamples)
637 throw tcu::NotSupportedError("Requested sample count is greater than glGetInternalformativ(GL_SAMPLES) for this target/format");
638
639 m_testCtx.getLog() << tcu::TestLog::Message << "glGetInternalformativ(GL_SAMPLES) = " << maxSamples << tcu::TestLog::EndMessage;
640
641 // Don't even try to test high bits if there are none
642
643 if ((m_flags & FLAGS_HIGH_BITS) && (m_samples % 32 == 0))
644 {
645 m_testCtx.getLog() << tcu::TestLog::Message << "Sample count is multiple of word size. No unused high bits in sample mask.\nSkipping." << tcu::TestLog::EndMessage;
646 throw tcu::NotSupportedError("Test requires unused high bits (sample count not multiple of 32)");
647 }
648
649 // generate textures
650
651 m_testCtx.getLog() << tcu::TestLog::Message << "Creating multisample texture with sample count " << m_samples << tcu::TestLog::EndMessage;
652
653 gl.genTextures (1, &m_texID);
654 gl.bindTexture (GL_TEXTURE_2D_MULTISAMPLE, m_texID);
655 gl.texStorage2DMultisample (GL_TEXTURE_2D_MULTISAMPLE, m_samples, GL_RGBA8, m_canvasSize, m_canvasSize, GL_FALSE);
656 GLU_EXPECT_NO_ERROR (gl.getError(), "texStorage2DMultisample");
657
658 // attach texture to fbo
659
660 m_testCtx.getLog() << tcu::TestLog::Message << "Attaching texture to FBO" << tcu::TestLog::EndMessage;
661
662 gl.genFramebuffers (1, &m_fboID);
663 gl.bindFramebuffer (GL_FRAMEBUFFER, m_fboID);
664 gl.framebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, m_texID, 0);
665 GLU_EXPECT_NO_ERROR (gl.getError(), "framebufferTexture2D");
666
667 // buffers
668
669 gl.genVertexArrays (1, &m_vaoID);
670 GLU_EXPECT_NO_ERROR (gl.getError(), "genVertexArrays");
671
672 gl.genBuffers (1, &m_vboID);
673 gl.bindBuffer (GL_ARRAY_BUFFER, m_vboID);
674 GLU_EXPECT_NO_ERROR (gl.getError(), "genBuffers");
675
676 // generate grid pattern
677 {
678 std::vector<tcu::Vec4> gridData(m_gridsize*m_gridsize*6);
679
680 for (int y = 0; y < m_gridsize; ++y)
681 for (int x = 0; x < m_gridsize; ++x)
682 {
683 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);
684 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);
685 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);
686 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);
687 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);
688 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);
689 }
690
691 gl.bufferData (GL_ARRAY_BUFFER, (int)(gridData.size() * sizeof(tcu::Vec4)), gridData[0].getPtr(), GL_STATIC_DRAW);
692 GLU_EXPECT_NO_ERROR (gl.getError(), "bufferData");
693 }
694
695 // generate programs
696
697 genSamplerProgram();
698 genAlphaProgram();
699 }
700
deinit(void)701 void SampleMaskCase::deinit (void)
702 {
703 if (m_texID)
704 {
705 m_context.getRenderContext().getFunctions().deleteTextures(1, &m_texID);
706 m_texID = 0;
707 }
708 if (m_vaoID)
709 {
710 m_context.getRenderContext().getFunctions().deleteVertexArrays(1, &m_vaoID);
711 m_vaoID = 0;
712 }
713 if (m_vboID)
714 {
715 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_vboID);
716 m_vboID = 0;
717 }
718 if (m_fboID)
719 {
720 m_context.getRenderContext().getFunctions().deleteFramebuffers(1, &m_fboID);
721 m_fboID = 0;
722 }
723
724 if (m_samplerProgram)
725 {
726 delete m_samplerProgram;
727 m_samplerProgram = DE_NULL;
728 }
729 if (m_alphaProgram)
730 {
731 delete m_alphaProgram;
732 m_alphaProgram = DE_NULL;
733 }
734 }
735
iterate(void)736 SampleMaskCase::IterateResult SampleMaskCase::iterate (void)
737 {
738 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)));
739
740 bool iterationOk;
741
742 // Mask only one sample, clear rest
743
744 updateTexture(m_currentSample);
745
746 // Verify only one sample set is in the texture
747
748 iterationOk = verifyTexture(m_currentSample);
749 if (!iterationOk)
750 m_allIterationsOk = false;
751
752 m_currentSample++;
753 if (m_currentSample < m_samples)
754 return CONTINUE;
755
756 // End result
757
758 if (m_allIterationsOk)
759 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
760 else if (m_flags & FLAGS_HIGH_BITS)
761 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Unused mask bits have effect");
762 else
763 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Sample test failed");
764
765 return STOP;
766 }
767
genSamplerProgram(void)768 void SampleMaskCase::genSamplerProgram (void)
769 {
770 const char* const vertexShaderSource = "${GLSL_VERSION_DECL}\n"
771 "in highp vec4 a_position;\n"
772 "void main (void)\n"
773 "{\n"
774 " gl_Position = a_position;\n"
775 "}\n";
776 const char* const fragShaderSource = "${GLSL_VERSION_DECL}\n"
777 "layout(location = 0) out highp vec4 fragColor;\n"
778 "uniform highp sampler2DMS u_sampler;\n"
779 "uniform highp int u_sample;\n"
780 "void main (void)\n"
781 "{\n"
782 " highp float correctCoverage = 0.0;\n"
783 " highp float incorrectCoverage = 0.0;\n"
784 " highp ivec2 texelPos = ivec2(int(floor(gl_FragCoord.x)), int(floor(gl_FragCoord.y)));\n"
785 "\n"
786 " for (int sampleNdx = 0; sampleNdx < ${NUMSAMPLES}; ++sampleNdx)\n"
787 " {\n"
788 " highp float sampleColor = texelFetch(u_sampler, texelPos, sampleNdx).r;\n"
789 " if (sampleNdx == u_sample)\n"
790 " correctCoverage += sampleColor;\n"
791 " else\n"
792 " incorrectCoverage += sampleColor;\n"
793 " }\n"
794 " fragColor = vec4(correctCoverage, incorrectCoverage, 0.0, 1.0);\n"
795 "}\n";
796 const tcu::ScopedLogSection section (m_testCtx.getLog(), "GenerateSamplerShader", "Generate sampler shader");
797 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
798 std::map<std::string, std::string> args;
799 const glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType());
800
801 args["GLSL_VERSION_DECL"] = glu::getGLSLVersionDeclaration(glslVersion);
802 args["NUMSAMPLES"] = de::toString(m_samples);
803
804 m_samplerProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(specializeShader(m_context, vertexShaderSource)) << glu::FragmentSource(tcu::StringTemplate(fragShaderSource).specialize(args)));
805 m_testCtx.getLog() << *m_samplerProgram;
806
807 if (!m_samplerProgram->isOk())
808 throw tcu::TestError("Could not create sampler program.");
809
810 m_samplerProgramPosLoc = gl.getAttribLocation(m_samplerProgram->getProgram(), "a_position");
811 m_samplerProgramSamplerLoc = gl.getUniformLocation(m_samplerProgram->getProgram(), "u_sampler");
812 m_samplerProgramSampleNdxLoc = gl.getUniformLocation(m_samplerProgram->getProgram(), "u_sample");
813 }
814
genAlphaProgram(void)815 void SampleMaskCase::genAlphaProgram (void)
816 {
817 const char* const vertexShaderSource = "${GLSL_VERSION_DECL}\n"
818 "in highp vec4 a_position;\n"
819 "out highp float v_alpha;\n"
820 "void main (void)\n"
821 "{\n"
822 " gl_Position = a_position;\n"
823 " v_alpha = (a_position.x * 0.5 + 0.5)*(a_position.y * 0.5 + 0.5);\n"
824 "}\n";
825 const char* const fragShaderSource = "${GLSL_VERSION_DECL}\n"
826 "layout(location = 0) out highp vec4 fragColor;\n"
827 "in mediump float v_alpha;\n"
828 "void main (void)\n"
829 "{\n"
830 " fragColor = vec4(1.0, 1.0, 1.0, v_alpha);\n"
831 "}\n";
832 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
833
834 m_alphaProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(specializeShader(m_context, vertexShaderSource)) << glu::FragmentSource(specializeShader(m_context, fragShaderSource)));
835
836 if (!m_alphaProgram->isOk())
837 {
838 m_testCtx.getLog() << *m_alphaProgram;
839 throw tcu::TestError("Could not create aplha program.");
840 }
841
842 m_alphaProgramPosLoc = gl.getAttribLocation(m_alphaProgram->getProgram(), "a_position");
843 }
844
updateTexture(int sample)845 void SampleMaskCase::updateTexture (int sample)
846 {
847 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
848
849 // prepare draw
850
851 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID);
852 gl.viewport(0, 0, m_canvasSize, m_canvasSize);
853 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
854
855 // clear all samples
856
857 m_testCtx.getLog() << tcu::TestLog::Message << "Clearing image" << tcu::TestLog::EndMessage;
858 gl.clear(GL_COLOR_BUFFER_BIT);
859
860 // set mask state
861
862 if (m_flags & FLAGS_HIGH_BITS)
863 {
864 const std::vector<deUint32> bitmask = genSetNthBitSampleMask(sample);
865 const std::vector<deUint32> effectiveMask = genAllSetToNthBitSampleMask(m_samples);
866 std::vector<deUint32> totalBitmask (effectiveMask.size());
867
868 DE_ASSERT((int)totalBitmask.size() == m_effectiveSampleMaskWordCount);
869
870 // set some arbitrary high bits to non-effective bits
871 for (int wordNdx = 0; wordNdx < (int)effectiveMask.size(); ++wordNdx)
872 {
873 const deUint32 randomMask = (deUint32)deUint32Hash(wordNdx << 2 ^ sample);
874 const deUint32 sampleMask = (wordNdx < (int)bitmask.size()) ? (bitmask[wordNdx]) : (0);
875 const deUint32 maskMask = effectiveMask[wordNdx];
876
877 totalBitmask[wordNdx] = (sampleMask & maskMask) | (randomMask & ~maskMask);
878 }
879
880 m_testCtx.getLog() << tcu::TestLog::Message << "Setting sample mask to 0b" << sampleMaskToString(totalBitmask, (int)totalBitmask.size() * 32) << tcu::TestLog::EndMessage;
881
882 gl.enable(GL_SAMPLE_MASK);
883 for (int wordNdx = 0; wordNdx < m_effectiveSampleMaskWordCount; ++wordNdx)
884 {
885 const GLbitfield wordmask = (wordNdx < (int)totalBitmask.size()) ? ((GLbitfield)(totalBitmask[wordNdx])) : (0);
886 gl.sampleMaski((deUint32)wordNdx, wordmask);
887 }
888 }
889 else
890 {
891 const std::vector<deUint32> bitmask = genSetNthBitSampleMask(sample);
892 DE_ASSERT((int)bitmask.size() <= m_effectiveSampleMaskWordCount);
893
894 m_testCtx.getLog() << tcu::TestLog::Message << "Setting sample mask to 0b" << sampleMaskToString(bitmask, m_samples) << tcu::TestLog::EndMessage;
895
896 gl.enable(GL_SAMPLE_MASK);
897 for (int wordNdx = 0; wordNdx < m_effectiveSampleMaskWordCount; ++wordNdx)
898 {
899 const GLbitfield wordmask = (wordNdx < (int)bitmask.size()) ? ((GLbitfield)(bitmask[wordNdx])) : (0);
900 gl.sampleMaski((deUint32)wordNdx, wordmask);
901 }
902 }
903 if (m_flags & FLAGS_ALPHA_TO_COVERAGE)
904 {
905 m_testCtx.getLog() << tcu::TestLog::Message << "Enabling alpha to coverage." << tcu::TestLog::EndMessage;
906 gl.enable(GL_SAMPLE_ALPHA_TO_COVERAGE);
907 }
908 if (m_flags & FLAGS_SAMPLE_COVERAGE)
909 {
910 m_testCtx.getLog() << tcu::TestLog::Message << "Enabling sample coverage. Varying sample coverage for grid cells." << tcu::TestLog::EndMessage;
911 gl.enable(GL_SAMPLE_COVERAGE);
912 }
913
914 // draw test pattern
915
916 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing test grid" << tcu::TestLog::EndMessage;
917
918 gl.bindVertexArray (m_vaoID);
919 gl.bindBuffer (GL_ARRAY_BUFFER, m_vboID);
920 gl.vertexAttribPointer (m_alphaProgramPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
921 gl.enableVertexAttribArray (m_alphaProgramPosLoc);
922 GLU_EXPECT_NO_ERROR (gl.getError(), "vertexAttribPointer");
923
924 gl.useProgram (m_alphaProgram->getProgram());
925
926 for (int y = 0; y < m_gridsize; ++y)
927 for (int x = 0; x < m_gridsize; ++x)
928 {
929 if (m_flags & FLAGS_SAMPLE_COVERAGE)
930 gl.sampleCoverage((float)(y*m_gridsize + x) / float(m_gridsize*m_gridsize), GL_FALSE);
931
932 gl.drawArrays (GL_TRIANGLES, (y*m_gridsize + x) * 6, 6);
933 GLU_EXPECT_NO_ERROR (gl.getError(), "drawArrays");
934 }
935
936 // clean state
937
938 gl.disableVertexAttribArray (m_alphaProgramPosLoc);
939 gl.useProgram (0);
940 gl.bindFramebuffer (GL_FRAMEBUFFER, 0);
941 gl.disable (GL_SAMPLE_MASK);
942 gl.disable (GL_SAMPLE_ALPHA_TO_COVERAGE);
943 gl.disable (GL_SAMPLE_COVERAGE);
944 GLU_EXPECT_NO_ERROR (gl.getError(), "clean");
945 }
946
verifyTexture(int sample)947 bool SampleMaskCase::verifyTexture (int sample)
948 {
949 tcu::Surface result (m_canvasSize, m_canvasSize);
950 tcu::Surface errorMask (m_canvasSize, m_canvasSize);
951 bool error = false;
952
953 tcu::clear(errorMask.getAccess(), tcu::RGBA::green().toVec());
954
955 // Draw sample:
956 // Sample sampleNdx is set to red channel
957 // Other samples are set to green channel
958 drawSample(result, sample);
959
960 // Check surface contains only sampleNdx
961 for (int y = 0; y < m_canvasSize; ++y)
962 for (int x = 0; x < m_canvasSize; ++x)
963 {
964 const tcu::RGBA color = result.getPixel(x, y);
965
966 // Allow missing coverage with FLAGS_ALPHA_TO_COVERAGE and FLAGS_SAMPLE_COVERAGE, or if there are no samples enabled
967 const bool allowMissingCoverage = ((m_flags & (FLAGS_ALPHA_TO_COVERAGE | FLAGS_SAMPLE_COVERAGE)) != 0) || (sample == -1);
968
969 // disabled sample was written to
970 if (color.getGreen() != 0)
971 {
972 error = true;
973 errorMask.setPixel(x, y, tcu::RGBA::red());
974 }
975 // enabled sample was not written to
976 else if (color.getRed() != 255 && !allowMissingCoverage)
977 {
978 error = true;
979 errorMask.setPixel(x, y, tcu::RGBA::red());
980 }
981 }
982
983 if (error)
984 {
985 m_testCtx.getLog()
986 << tcu::TestLog::Message << "Image verification failed, disabled samples found." << tcu::TestLog::EndMessage
987 << tcu::TestLog::ImageSet("VerificationResult", "Result of rendering")
988 << tcu::TestLog::Image("Result", "Result", result)
989 << tcu::TestLog::Image("ErrorMask", "Error Mask", errorMask)
990 << tcu::TestLog::EndImageSet;
991 return false;
992 }
993 else
994 {
995 m_testCtx.getLog() << tcu::TestLog::Message << "Image verification ok, no disabled samples found." << tcu::TestLog::EndMessage;
996 return true;
997 }
998 }
999
drawSample(tcu::Surface & dst,int sample)1000 void SampleMaskCase::drawSample (tcu::Surface& dst, int sample)
1001 {
1002 // Downsample using only one sample
1003 static const tcu::Vec4 fullscreenQuad[] =
1004 {
1005 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
1006 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
1007 tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f),
1008 tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f)
1009 };
1010
1011 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1012 glu::Buffer vertexBuffer (m_context.getRenderContext());
1013
1014 gl.bindTexture (GL_TEXTURE_2D_MULTISAMPLE, m_texID);
1015 gl.bindVertexArray (m_vaoID);
1016
1017 gl.bindBuffer (GL_ARRAY_BUFFER, *vertexBuffer);
1018 gl.bufferData (GL_ARRAY_BUFFER, sizeof(fullscreenQuad), &fullscreenQuad[0], GL_STATIC_DRAW);
1019 GLU_EXPECT_NO_ERROR (gl.getError(), "bufferData");
1020
1021 gl.viewport (0, 0, m_canvasSize, m_canvasSize);
1022 gl.clearColor (0, 0, 0, 1);
1023 gl.clear (GL_COLOR_BUFFER_BIT);
1024 gl.vertexAttribPointer (m_samplerProgramPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
1025 gl.enableVertexAttribArray (m_samplerProgramPosLoc);
1026 GLU_EXPECT_NO_ERROR (gl.getError(), "vertexAttribPointer");
1027
1028 gl.useProgram (m_samplerProgram->getProgram());
1029 gl.uniform1i (m_samplerProgramSamplerLoc, 0);
1030 gl.uniform1i (m_samplerProgramSampleNdxLoc, (deInt32)sample);
1031 GLU_EXPECT_NO_ERROR (gl.getError(), "useprogram");
1032
1033 m_testCtx.getLog() << tcu::TestLog::Message << "Reading from texture with sampler shader, u_sample = " << sample << tcu::TestLog::EndMessage;
1034
1035 gl.drawArrays (GL_TRIANGLE_STRIP, 0, 4);
1036 GLU_EXPECT_NO_ERROR (gl.getError(), "drawArrays");
1037
1038 gl.disableVertexAttribArray (m_samplerProgramPosLoc);
1039 gl.useProgram (0);
1040 GLU_EXPECT_NO_ERROR (gl.getError(), "cleanup");
1041
1042 gl.finish ();
1043 glu::readPixels (m_context.getRenderContext(), 0, 0, dst.getAccess());
1044 GLU_EXPECT_NO_ERROR (gl.getError(), "readPixels");
1045 }
1046
getMaxConformantSampleCount(glw::GLenum target,glw::GLenum internalFormat)1047 glw::GLint SampleMaskCase::getMaxConformantSampleCount(glw::GLenum target, glw::GLenum internalFormat)
1048 {
1049 deInt32 maxTextureSamples = 0;
1050 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1051 if (m_context.getContextInfo().isExtensionSupported("GL_NV_internalformat_sample_query"))
1052 {
1053 glw::GLint gl_sample_counts = 0;
1054 gl.getInternalformativ(target, internalFormat, GL_NUM_SAMPLE_COUNTS, 1, &gl_sample_counts);
1055 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetInternalformativ() failed for GL_NUM_SAMPLE_COUNTS pname");
1056 /* Check and return the first conformant sample count */
1057 glw::GLint* gl_supported_samples = new glw::GLint[gl_sample_counts];
1058 if (gl_supported_samples)
1059 {
1060 gl.getInternalformativ(target, internalFormat, GL_SAMPLES, gl_sample_counts, gl_supported_samples);
1061 for (glw::GLint i = 0; i < gl_sample_counts; i++)
1062 {
1063 glw::GLint isConformant = 0;
1064 gl.getInternalformatSampleivNV(target, internalFormat, gl_supported_samples[i], GL_CONFORMANT_NV, 1,
1065 &isConformant);
1066 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetInternalformatSampleivNV() call(s) failed");
1067 if (isConformant && gl_supported_samples[i] > maxTextureSamples)
1068 {
1069 maxTextureSamples = gl_supported_samples[i];
1070 }
1071 }
1072 delete[] gl_supported_samples;
1073 }
1074 }
1075 else
1076 {
1077 gl.getInternalformativ(target, internalFormat, GL_SAMPLES, 1, &maxTextureSamples);
1078 }
1079 return maxTextureSamples;
1080 }
1081
1082
1083 class MultisampleTextureUsageCase : public TestCase
1084 {
1085 public:
1086
1087 enum TextureType
1088 {
1089 TEXTURE_COLOR_2D = 0,
1090 TEXTURE_COLOR_2D_ARRAY,
1091 TEXTURE_INT_2D,
1092 TEXTURE_INT_2D_ARRAY,
1093 TEXTURE_UINT_2D,
1094 TEXTURE_UINT_2D_ARRAY,
1095 TEXTURE_DEPTH_2D,
1096 TEXTURE_DEPTH_2D_ARRAY,
1097
1098 TEXTURE_LAST
1099 };
1100
1101 MultisampleTextureUsageCase (Context& ctx, const char* name, const char* desc, int samples, TextureType type);
1102 ~MultisampleTextureUsageCase (void);
1103
1104 private:
1105 void init (void);
1106 void deinit (void);
1107 IterateResult iterate (void);
1108
1109 void genDrawShader (void);
1110 void genSamplerShader (void);
1111
1112 void renderToTexture (float value);
1113 void sampleTexture (tcu::Surface& dst, float value);
1114 bool verifyImage (const tcu::Surface& dst);
1115
1116 static const int s_textureSize = 256;
1117 static const int s_textureArraySize = 8;
1118 static const int s_textureLayer = 3;
1119
1120 const TextureType m_type;
1121 const int m_numSamples;
1122
1123 glw::GLuint m_fboID;
1124 glw::GLuint m_vaoID;
1125 glw::GLuint m_textureID;
1126
1127 glu::ShaderProgram* m_drawShader;
1128 glu::ShaderProgram* m_samplerShader;
1129
1130 const bool m_isColorFormat;
1131 const bool m_isSignedFormat;
1132 const bool m_isUnsignedFormat;
1133 const bool m_isDepthFormat;
1134 const bool m_isArrayType;
1135 };
1136
MultisampleTextureUsageCase(Context & ctx,const char * name,const char * desc,int samples,TextureType type)1137 MultisampleTextureUsageCase::MultisampleTextureUsageCase (Context& ctx, const char* name, const char* desc, int samples, TextureType type)
1138 : TestCase (ctx, name, desc)
1139 , m_type (type)
1140 , m_numSamples (samples)
1141 , m_fboID (0)
1142 , m_vaoID (0)
1143 , m_textureID (0)
1144 , m_drawShader (DE_NULL)
1145 , m_samplerShader (DE_NULL)
1146 , m_isColorFormat (m_type == TEXTURE_COLOR_2D || m_type == TEXTURE_COLOR_2D_ARRAY)
1147 , m_isSignedFormat (m_type == TEXTURE_INT_2D || m_type == TEXTURE_INT_2D_ARRAY)
1148 , m_isUnsignedFormat(m_type == TEXTURE_UINT_2D || m_type == TEXTURE_UINT_2D_ARRAY)
1149 , m_isDepthFormat (m_type == TEXTURE_DEPTH_2D || m_type == TEXTURE_DEPTH_2D_ARRAY)
1150 , 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)
1151 {
1152 DE_ASSERT(m_type < TEXTURE_LAST);
1153 }
1154
~MultisampleTextureUsageCase(void)1155 MultisampleTextureUsageCase::~MultisampleTextureUsageCase (void)
1156 {
1157 deinit();
1158 }
1159
init(void)1160 void MultisampleTextureUsageCase::init (void)
1161 {
1162 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1163 const glw::GLenum internalFormat = (m_isColorFormat) ? (GL_R8) : (m_isSignedFormat) ? (GL_R8I) : (m_isUnsignedFormat) ? (GL_R8UI) : (m_isDepthFormat) ? (GL_DEPTH_COMPONENT32F) : (0);
1164 const glw::GLenum textureTarget = (m_isArrayType) ? (GL_TEXTURE_2D_MULTISAMPLE_ARRAY) : (GL_TEXTURE_2D_MULTISAMPLE);
1165 const glw::GLenum fboAttachment = (m_isDepthFormat) ? (GL_DEPTH_ATTACHMENT) : (GL_COLOR_ATTACHMENT0);
1166 const bool supportsES32orGL45 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) ||
1167 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
1168
1169 DE_ASSERT(internalFormat);
1170
1171 // requirements
1172
1173 if (m_isArrayType && !supportsES32orGL45 && !m_context.getContextInfo().isExtensionSupported("GL_OES_texture_storage_multisample_2d_array"))
1174 throw tcu::NotSupportedError("Test requires OES_texture_storage_multisample_2d_array extension");
1175 if (m_context.getRenderTarget().getWidth() < s_textureSize || m_context.getRenderTarget().getHeight() < s_textureSize)
1176 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)));
1177
1178 {
1179 glw::GLint maxSamples = 0;
1180 gl.getInternalformativ(textureTarget, internalFormat, GL_SAMPLES, 1, &maxSamples);
1181
1182 if (m_numSamples > maxSamples)
1183 throw tcu::NotSupportedError("Requested sample count is greater than supported");
1184
1185 m_testCtx.getLog() << tcu::TestLog::Message << "Max sample count for " << glu::getTextureFormatStr(internalFormat) << ": " << maxSamples << tcu::TestLog::EndMessage;
1186 }
1187
1188 {
1189 GLint maxTextureSize = 0;
1190 gl.getIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
1191
1192 if (s_textureSize > maxTextureSize)
1193 throw tcu::NotSupportedError("Larger GL_MAX_TEXTURE_SIZE is required");
1194 }
1195
1196 if (m_isArrayType)
1197 {
1198 GLint maxTextureLayers = 0;
1199 gl.getIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &maxTextureLayers);
1200
1201 if (s_textureArraySize > maxTextureLayers)
1202 throw tcu::NotSupportedError("Larger GL_MAX_ARRAY_TEXTURE_LAYERS is required");
1203 }
1204
1205 // create texture
1206
1207 m_testCtx.getLog() << tcu::TestLog::Message << "Creating multisample " << ((m_isDepthFormat) ? ("depth") : ("")) << " texture" << ((m_isArrayType) ? (" array") : ("")) << tcu::TestLog::EndMessage;
1208
1209 gl.genTextures(1, &m_textureID);
1210 gl.bindTexture(textureTarget, m_textureID);
1211 GLU_EXPECT_NO_ERROR(gl.getError(), "bind texture");
1212
1213 if (m_isArrayType)
1214 gl.texStorage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, m_numSamples, internalFormat, s_textureSize, s_textureSize, s_textureArraySize, GL_FALSE);
1215 else
1216 gl.texStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_numSamples, internalFormat, s_textureSize, s_textureSize, GL_FALSE);
1217 GLU_EXPECT_NO_ERROR(gl.getError(), "texstorage");
1218
1219 // create fbo for drawing
1220
1221 gl.genFramebuffers(1, &m_fboID);
1222 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID);
1223
1224 if (m_isArrayType)
1225 {
1226 m_testCtx.getLog() << tcu::TestLog::Message << "Attaching multisample texture array layer " << static_cast<int>(s_textureLayer) << " to fbo" << tcu::TestLog::EndMessage;
1227 gl.framebufferTextureLayer(GL_FRAMEBUFFER, fboAttachment, m_textureID, 0, s_textureLayer);
1228 }
1229 else
1230 {
1231 m_testCtx.getLog() << tcu::TestLog::Message << "Attaching multisample texture to fbo" << tcu::TestLog::EndMessage;
1232 gl.framebufferTexture2D(GL_FRAMEBUFFER, fboAttachment, textureTarget, m_textureID, 0);
1233 }
1234 GLU_EXPECT_NO_ERROR(gl.getError(), "gen fbo");
1235
1236 // create vao if context is GL4.5
1237 if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
1238 gl.genVertexArrays(1, &m_vaoID);
1239
1240 // create shader for rendering to fbo
1241 genDrawShader();
1242
1243 // create shader for sampling the texture rendered to
1244 genSamplerShader();
1245 }
1246
deinit(void)1247 void MultisampleTextureUsageCase::deinit (void)
1248 {
1249 if (m_textureID)
1250 {
1251 m_context.getRenderContext().getFunctions().deleteTextures(1, &m_textureID);
1252 m_textureID = 0;
1253 }
1254
1255 if (m_fboID)
1256 {
1257 m_context.getRenderContext().getFunctions().deleteFramebuffers(1, &m_fboID);
1258 m_fboID = 0;
1259 }
1260
1261 if (m_vaoID)
1262 {
1263 m_context.getRenderContext().getFunctions().deleteVertexArrays(1, &m_vaoID);
1264 m_vaoID = 0;
1265 }
1266
1267 if (m_drawShader)
1268 {
1269 delete m_drawShader;
1270 m_drawShader = DE_NULL;
1271 }
1272
1273 if (m_samplerShader)
1274 {
1275 delete m_samplerShader;
1276 m_samplerShader = DE_NULL;
1277 }
1278 }
1279
iterate(void)1280 MultisampleTextureUsageCase::IterateResult MultisampleTextureUsageCase::iterate (void)
1281 {
1282 const tcu::ScopedLogSection section (m_testCtx.getLog(), "Sample", "Render to texture and sample texture");
1283 tcu::Surface result (s_textureSize, s_textureSize);
1284 const float minValue = (m_isColorFormat || m_isDepthFormat) ? (0.0f) : (m_isSignedFormat) ? (-100.0f) : (m_isUnsignedFormat) ? (0.0f) : ( 1.0f);
1285 const float maxValue = (m_isColorFormat || m_isDepthFormat) ? (1.0f) : (m_isSignedFormat) ? ( 100.0f) : (m_isUnsignedFormat) ? (200.0f) : (-1.0f);
1286 de::Random rnd (deUint32Hash((deUint32)m_type));
1287 const float rawValue = rnd.getFloat(minValue, maxValue);
1288 const float preparedValue = (m_isSignedFormat || m_isUnsignedFormat) ? (deFloatFloor(rawValue)) : (rawValue);
1289
1290 // draw to fbo with a random value
1291
1292 renderToTexture(preparedValue);
1293
1294 // draw from texture to front buffer
1295
1296 sampleTexture(result, preparedValue);
1297
1298 // result is ok?
1299
1300 if (verifyImage(result))
1301 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1302 else
1303 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
1304
1305 return STOP;
1306 }
1307
genDrawShader(void)1308 void MultisampleTextureUsageCase::genDrawShader (void)
1309 {
1310 const tcu::ScopedLogSection section(m_testCtx.getLog(), "RenderShader", "Generate render-to-texture shader");
1311
1312 static const char* const vertexShaderSource = "${GLSL_VERSION_DECL}\n"
1313 "in highp vec4 a_position;\n"
1314 "void main (void)\n"
1315 "{\n"
1316 " gl_Position = a_position;\n"
1317 "}\n";
1318 static const char* const fragmentShaderSourceColor = "${GLSL_VERSION_DECL}\n"
1319 "layout(location = 0) out highp ${OUTTYPE} fragColor;\n"
1320 "uniform highp float u_writeValue;\n"
1321 "void main (void)\n"
1322 "{\n"
1323 " fragColor = ${OUTTYPE}(vec4(u_writeValue, 1.0, 1.0, 1.0));\n"
1324 "}\n";
1325 static const char* const fragmentShaderSourceDepth = "${GLSL_VERSION_DECL}\n"
1326 "layout(location = 0) out highp vec4 fragColor;\n"
1327 "uniform highp float u_writeValue;\n"
1328 "void main (void)\n"
1329 "{\n"
1330 " fragColor = vec4(0.0, 0.0, 0.0, 1.0);\n"
1331 " gl_FragDepth = u_writeValue;\n"
1332 "}\n";
1333 const char* const fragmentSource = (m_isDepthFormat) ? (fragmentShaderSourceDepth) : (fragmentShaderSourceColor);
1334
1335 std::map<std::string, std::string> fragmentArguments;
1336
1337 const glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType());
1338 fragmentArguments["GLSL_VERSION_DECL"] = glu::getGLSLVersionDeclaration(glslVersion);
1339
1340 if (m_isColorFormat || m_isDepthFormat)
1341 fragmentArguments["OUTTYPE"] = "vec4";
1342 else if (m_isSignedFormat)
1343 fragmentArguments["OUTTYPE"] = "ivec4";
1344 else if (m_isUnsignedFormat)
1345 fragmentArguments["OUTTYPE"] = "uvec4";
1346 else
1347 DE_ASSERT(DE_FALSE);
1348
1349 m_drawShader = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(specializeShader(m_context, vertexShaderSource)) << glu::FragmentSource(tcu::StringTemplate(fragmentSource).specialize(fragmentArguments)));
1350 m_testCtx.getLog() << *m_drawShader;
1351
1352 if (!m_drawShader->isOk())
1353 throw tcu::TestError("could not build shader");
1354 }
1355
genSamplerShader(void)1356 void MultisampleTextureUsageCase::genSamplerShader (void)
1357 {
1358 const tcu::ScopedLogSection section(m_testCtx.getLog(), "SamplerShader", "Generate texture sampler shader");
1359
1360 static const char* const vertexShaderSource = "${GLSL_VERSION_DECL}\n"
1361 "in highp vec4 a_position;\n"
1362 "out highp float v_gradient;\n"
1363 "void main (void)\n"
1364 "{\n"
1365 " gl_Position = a_position;\n"
1366 " v_gradient = a_position.x * 0.5 + 0.5;\n"
1367 "}\n";
1368 static const char* const fragmentShaderSource = "${GLSL_VERSION_DECL}\n"
1369 "${EXTENSION_STATEMENT}"
1370 "layout(location = 0) out highp vec4 fragColor;\n"
1371 "uniform highp ${SAMPLERTYPE} u_sampler;\n"
1372 "uniform highp int u_maxSamples;\n"
1373 "uniform highp int u_layer;\n"
1374 "uniform highp float u_cmpValue;\n"
1375 "in highp float v_gradient;\n"
1376 "void main (void)\n"
1377 "{\n"
1378 " const highp vec4 okColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
1379 " const highp vec4 failColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
1380 " const highp float epsilon = ${EPSILON};\n"
1381 "\n"
1382 " highp int sampleNdx = clamp(int(floor(v_gradient * float(u_maxSamples))), 0, u_maxSamples-1);\n"
1383 " highp float value = float(texelFetch(u_sampler, ${FETCHPOS}, sampleNdx).r);\n"
1384 " fragColor = (abs(u_cmpValue - value) < epsilon) ? (okColor) : (failColor);\n"
1385 "}\n";
1386
1387 std::map<std::string, std::string> fragmentArguments;
1388
1389 const glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType());
1390 fragmentArguments["GLSL_VERSION_DECL"] = glu::getGLSLVersionDeclaration(glslVersion);
1391
1392 const bool supportsES32orGL45 =
1393 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) ||
1394 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
1395
1396 if (m_isArrayType)
1397 fragmentArguments["FETCHPOS"] = "ivec3(floor(gl_FragCoord.xy), u_layer)";
1398 else
1399 fragmentArguments["FETCHPOS"] = "ivec2(floor(gl_FragCoord.xy))";
1400
1401 if (m_isColorFormat || m_isDepthFormat)
1402 fragmentArguments["EPSILON"] = "0.1";
1403 else
1404 fragmentArguments["EPSILON"] = "1.0";
1405
1406 if (m_isArrayType && !supportsES32orGL45)
1407 fragmentArguments["EXTENSION_STATEMENT"] = "#extension GL_OES_texture_storage_multisample_2d_array : require\n";
1408 else
1409 fragmentArguments["EXTENSION_STATEMENT"] = "";
1410
1411 switch (m_type)
1412 {
1413 case TEXTURE_COLOR_2D: fragmentArguments["SAMPLERTYPE"] = "sampler2DMS"; break;
1414 case TEXTURE_COLOR_2D_ARRAY: fragmentArguments["SAMPLERTYPE"] = "sampler2DMSArray"; break;
1415 case TEXTURE_INT_2D: fragmentArguments["SAMPLERTYPE"] = "isampler2DMS"; break;
1416 case TEXTURE_INT_2D_ARRAY: fragmentArguments["SAMPLERTYPE"] = "isampler2DMSArray"; break;
1417 case TEXTURE_UINT_2D: fragmentArguments["SAMPLERTYPE"] = "usampler2DMS"; break;
1418 case TEXTURE_UINT_2D_ARRAY: fragmentArguments["SAMPLERTYPE"] = "usampler2DMSArray"; break;
1419 case TEXTURE_DEPTH_2D: fragmentArguments["SAMPLERTYPE"] = "sampler2DMS"; break;
1420 case TEXTURE_DEPTH_2D_ARRAY: fragmentArguments["SAMPLERTYPE"] = "sampler2DMSArray"; break;
1421
1422 default:
1423 DE_ASSERT(DE_FALSE);
1424 }
1425
1426 m_samplerShader = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(specializeShader(m_context, vertexShaderSource)) << glu::FragmentSource(tcu::StringTemplate(fragmentShaderSource).specialize(fragmentArguments)));
1427 m_testCtx.getLog() << *m_samplerShader;
1428
1429 if (!m_samplerShader->isOk())
1430 throw tcu::TestError("could not build shader");
1431 }
1432
renderToTexture(float value)1433 void MultisampleTextureUsageCase::renderToTexture (float value)
1434 {
1435 static const tcu::Vec4 fullscreenQuad[] =
1436 {
1437 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
1438 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
1439 tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
1440 tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f),
1441 };
1442
1443 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1444 const int posLocation = gl.getAttribLocation(m_drawShader->getProgram(), "a_position");
1445 const int valueLocation = gl.getUniformLocation(m_drawShader->getProgram(), "u_writeValue");
1446 glu::Buffer vertexAttibBuffer (m_context.getRenderContext());
1447
1448 m_testCtx.getLog() << tcu::TestLog::Message << "Filling multisample texture with value " << value << tcu::TestLog::EndMessage;
1449
1450 // upload data
1451
1452 gl.bindBuffer(GL_ARRAY_BUFFER, *vertexAttibBuffer);
1453 gl.bufferData(GL_ARRAY_BUFFER, sizeof(fullscreenQuad), fullscreenQuad[0].getPtr(), GL_STATIC_DRAW);
1454 GLU_EXPECT_NO_ERROR(gl.getError(), "bufferdata");
1455
1456 // clear buffer
1457
1458 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID);
1459 gl.viewport(0, 0, s_textureSize, s_textureSize);
1460
1461 if (m_isColorFormat)
1462 {
1463 const float clearColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
1464 gl.clearBufferfv(GL_COLOR, 0, clearColor);
1465 }
1466 else if (m_isSignedFormat)
1467 {
1468 const deInt32 clearColor[4] = { 0, 0, 0, 0 };
1469 gl.clearBufferiv(GL_COLOR, 0, clearColor);
1470 }
1471 else if (m_isUnsignedFormat)
1472 {
1473 const deUint32 clearColor[4] = { 0, 0, 0, 0 };
1474 gl.clearBufferuiv(GL_COLOR, 0, clearColor);
1475 }
1476 else if (m_isDepthFormat)
1477 {
1478 const float clearDepth = 0.5f;
1479 gl.clearBufferfv(GL_DEPTH, 0, &clearDepth);
1480 }
1481
1482 GLU_EXPECT_NO_ERROR(gl.getError(), "clear buffer");
1483
1484 // setup shader and draw
1485 if (m_vaoID)
1486 gl.bindVertexArray(m_vaoID);
1487
1488 gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
1489 gl.enableVertexAttribArray(posLocation);
1490
1491 gl.useProgram(m_drawShader->getProgram());
1492 gl.uniform1f(valueLocation, value);
1493
1494 GLU_EXPECT_NO_ERROR(gl.getError(), "setup draw");
1495
1496 if (m_isDepthFormat)
1497 {
1498 gl.enable(GL_DEPTH_TEST);
1499 gl.depthFunc(GL_ALWAYS);
1500 }
1501
1502 gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
1503 GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
1504
1505 // clean state
1506
1507 if (m_isDepthFormat)
1508 gl.disable(GL_DEPTH_TEST);
1509
1510 gl.disableVertexAttribArray(posLocation);
1511 gl.useProgram(0);
1512 gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
1513 GLU_EXPECT_NO_ERROR(gl.getError(), "clean");
1514 }
1515
sampleTexture(tcu::Surface & dst,float value)1516 void MultisampleTextureUsageCase::sampleTexture (tcu::Surface& dst, float value)
1517 {
1518 static const tcu::Vec4 fullscreenQuad[] =
1519 {
1520 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
1521 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
1522 tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
1523 tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f),
1524 };
1525
1526 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1527 const int posLocation = gl.getAttribLocation(m_samplerShader->getProgram(), "a_position");
1528 const int samplerLocation = gl.getUniformLocation(m_samplerShader->getProgram(), "u_sampler");
1529 const int maxSamplesLocation = gl.getUniformLocation(m_samplerShader->getProgram(), "u_maxSamples");
1530 const int layerLocation = gl.getUniformLocation(m_samplerShader->getProgram(), "u_layer");
1531 const int valueLocation = gl.getUniformLocation(m_samplerShader->getProgram(), "u_cmpValue");
1532 const glw::GLenum textureTarget = (m_isArrayType) ? (GL_TEXTURE_2D_MULTISAMPLE_ARRAY) : (GL_TEXTURE_2D_MULTISAMPLE);
1533 glu::Buffer vertexAttibBuffer (m_context.getRenderContext());
1534
1535 m_testCtx.getLog() << tcu::TestLog::Message << "Sampling from texture." << tcu::TestLog::EndMessage;
1536
1537 // upload data
1538
1539 gl.bindBuffer(GL_ARRAY_BUFFER, *vertexAttibBuffer);
1540 gl.bufferData(GL_ARRAY_BUFFER, sizeof(fullscreenQuad), fullscreenQuad[0].getPtr(), GL_STATIC_DRAW);
1541 GLU_EXPECT_NO_ERROR(gl.getError(), "bufferdata");
1542
1543 // clear
1544
1545 gl.viewport(0, 0, s_textureSize, s_textureSize);
1546 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1547 gl.clear(GL_COLOR_BUFFER_BIT);
1548
1549 // setup shader and draw
1550
1551 gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
1552 gl.enableVertexAttribArray(posLocation);
1553
1554 gl.useProgram(m_samplerShader->getProgram());
1555 gl.uniform1i(samplerLocation, 0);
1556 gl.uniform1i(maxSamplesLocation, m_numSamples);
1557 if (m_isArrayType)
1558 gl.uniform1i(layerLocation, s_textureLayer);
1559 gl.uniform1f(valueLocation, value);
1560 gl.bindTexture(textureTarget, m_textureID);
1561 GLU_EXPECT_NO_ERROR(gl.getError(), "setup draw");
1562
1563 gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
1564 GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
1565
1566 // clean state
1567
1568 gl.disableVertexAttribArray(posLocation);
1569 gl.useProgram(0);
1570 GLU_EXPECT_NO_ERROR(gl.getError(), "clean");
1571
1572 // read results
1573 gl.finish();
1574 glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
1575 }
1576
verifyImage(const tcu::Surface & dst)1577 bool MultisampleTextureUsageCase::verifyImage (const tcu::Surface& dst)
1578 {
1579 bool error = false;
1580
1581 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying image." << tcu::TestLog::EndMessage;
1582
1583 for (int y = 0; y < dst.getHeight(); ++y)
1584 for (int x = 0; x < dst.getWidth(); ++x)
1585 {
1586 const tcu::RGBA color = dst.getPixel(x, y);
1587 const int colorThresholdRed = 1 << (8 - m_context.getRenderTarget().getPixelFormat().redBits);
1588 const int colorThresholdGreen = 1 << (8 - m_context.getRenderTarget().getPixelFormat().greenBits);
1589 const int colorThresholdBlue = 1 << (8 - m_context.getRenderTarget().getPixelFormat().blueBits);
1590
1591 // only green is accepted
1592 if (color.getRed() > colorThresholdRed || color.getGreen() < 255 - colorThresholdGreen || color.getBlue() > colorThresholdBlue)
1593 error = true;
1594 }
1595
1596 if (error)
1597 {
1598 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid pixels found." << tcu::TestLog::EndMessage;
1599 m_testCtx.getLog()
1600 << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
1601 << tcu::TestLog::Image("Result", "Result", dst)
1602 << tcu::TestLog::EndImageSet;
1603
1604 return false;
1605 }
1606 else
1607 {
1608 m_testCtx.getLog() << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
1609 return true;
1610 }
1611 }
1612
1613 class NegativeFramebufferCase : public TestCase
1614 {
1615 public:
1616 enum CaseType
1617 {
1618 CASE_DIFFERENT_N_SAMPLES_TEX = 0,
1619 CASE_DIFFERENT_N_SAMPLES_RBO,
1620 CASE_DIFFERENT_FIXED_TEX,
1621 CASE_DIFFERENT_FIXED_RBO,
1622 CASE_NON_ZERO_LEVEL,
1623
1624 CASE_LAST
1625 };
1626
1627 NegativeFramebufferCase (Context& context, const char* name, const char* desc, CaseType caseType);
1628 ~NegativeFramebufferCase (void);
1629
1630 private:
1631 void init (void);
1632 void deinit (void);
1633 IterateResult iterate (void);
1634
1635 void getFormatSamples (glw::GLenum target, std::vector<int>& samples);
1636
1637 const CaseType m_caseType;
1638 const int m_fboSize;
1639 const glw::GLenum m_internalFormat;
1640
1641 int m_numSamples0; // !< samples for attachment 0
1642 int m_numSamples1; // !< samples for attachment 1
1643 };
1644
NegativeFramebufferCase(Context & context,const char * name,const char * desc,CaseType caseType)1645 NegativeFramebufferCase::NegativeFramebufferCase (Context& context, const char* name, const char* desc, CaseType caseType)
1646 : TestCase (context, name, desc)
1647 , m_caseType (caseType)
1648 , m_fboSize (64)
1649 , m_internalFormat (GL_RGBA8)
1650 , m_numSamples0 (-1)
1651 , m_numSamples1 (-1)
1652 {
1653 }
1654
~NegativeFramebufferCase(void)1655 NegativeFramebufferCase::~NegativeFramebufferCase (void)
1656 {
1657 deinit();
1658 }
1659
init(void)1660 void NegativeFramebufferCase::init (void)
1661 {
1662 const bool colorAttachmentTexture = (m_caseType == CASE_DIFFERENT_N_SAMPLES_TEX) || (m_caseType == CASE_DIFFERENT_FIXED_TEX);
1663 const bool colorAttachmentRbo = (m_caseType == CASE_DIFFERENT_N_SAMPLES_RBO) || (m_caseType == CASE_DIFFERENT_FIXED_RBO);
1664 const bool useDifferentSampleCounts= (m_caseType == CASE_DIFFERENT_N_SAMPLES_TEX) || (m_caseType == CASE_DIFFERENT_N_SAMPLES_RBO);
1665 std::vector<int> textureSamples;
1666 std::vector<int> rboSamples;
1667
1668 getFormatSamples(GL_TEXTURE_2D_MULTISAMPLE, textureSamples);
1669 getFormatSamples(GL_RENDERBUFFER, rboSamples);
1670
1671 TCU_CHECK(!textureSamples.empty());
1672 TCU_CHECK(!rboSamples.empty());
1673
1674 // select sample counts
1675
1676 if (useDifferentSampleCounts)
1677 {
1678 if (colorAttachmentTexture)
1679 {
1680 m_numSamples0 = textureSamples[0];
1681
1682 if (textureSamples.size() >= 2)
1683 m_numSamples1 = textureSamples[1];
1684 else
1685 throw tcu::NotSupportedError("Test requires multiple supported sample counts");
1686 }
1687 else if (colorAttachmentRbo)
1688 {
1689 for (int texNdx = 0; texNdx < (int)textureSamples.size(); ++texNdx)
1690 for (int rboNdx = 0; rboNdx < (int)rboSamples.size(); ++rboNdx)
1691 {
1692 if (textureSamples[texNdx] != rboSamples[rboNdx])
1693 {
1694 m_numSamples0 = textureSamples[texNdx];
1695 m_numSamples1 = rboSamples[rboNdx];
1696 return;
1697 }
1698 }
1699
1700 throw tcu::NotSupportedError("Test requires multiple supported sample counts");
1701 }
1702 else
1703 DE_ASSERT(DE_FALSE);
1704 }
1705 else
1706 {
1707 if (colorAttachmentTexture)
1708 {
1709 m_numSamples0 = textureSamples[0];
1710 m_numSamples1 = textureSamples[0];
1711 }
1712 else if (colorAttachmentRbo)
1713 {
1714 for (int texNdx = 0; texNdx < (int)textureSamples.size(); ++texNdx)
1715 for (int rboNdx = 0; rboNdx < (int)rboSamples.size(); ++rboNdx)
1716 {
1717 if (textureSamples[texNdx] == rboSamples[rboNdx])
1718 {
1719 m_numSamples0 = textureSamples[texNdx];
1720 m_numSamples1 = rboSamples[rboNdx];
1721 return;
1722 }
1723 }
1724
1725 throw tcu::NotSupportedError("Test requires a sample count supported in both rbo and texture");
1726 }
1727 else
1728 {
1729 m_numSamples0 = textureSamples[0];
1730 }
1731 }
1732 }
1733
deinit(void)1734 void NegativeFramebufferCase::deinit (void)
1735 {
1736 }
1737
iterate(void)1738 NegativeFramebufferCase::IterateResult NegativeFramebufferCase::iterate (void)
1739 {
1740 const bool colorAttachmentTexture = (m_caseType == CASE_DIFFERENT_N_SAMPLES_TEX) || (m_caseType == CASE_DIFFERENT_FIXED_TEX);
1741 const bool colorAttachmentRbo = (m_caseType == CASE_DIFFERENT_N_SAMPLES_RBO) || (m_caseType == CASE_DIFFERENT_FIXED_RBO);
1742 const glw::GLboolean fixedSampleLocations0 = (m_caseType == CASE_DIFFERENT_N_SAMPLES_RBO) ? (GL_TRUE) : (GL_FALSE);
1743 const glw::GLboolean fixedSampleLocations1 = ((m_caseType == CASE_DIFFERENT_FIXED_TEX) || (m_caseType == CASE_DIFFERENT_FIXED_RBO)) ? (GL_TRUE) : (GL_FALSE);
1744 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
1745 glw::GLuint fboId = 0;
1746 glw::GLuint rboId = 0;
1747 glw::GLuint tex0Id = 0;
1748 glw::GLuint tex1Id = 0;
1749
1750 bool testFailed = false;
1751
1752 gl.enableLogging(true);
1753
1754 try
1755 {
1756 gl.glGenFramebuffers(1, &fboId);
1757 gl.glBindFramebuffer(GL_FRAMEBUFFER, fboId);
1758 GLU_EXPECT_NO_ERROR(gl.glGetError(), "gen fbo");
1759
1760 gl.glGenTextures(1, &tex0Id);
1761 gl.glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex0Id);
1762 gl.glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_numSamples0, m_internalFormat, m_fboSize, m_fboSize, fixedSampleLocations0);
1763 GLU_EXPECT_NO_ERROR(gl.glGetError(), "gen texture 0");
1764
1765 if (m_caseType == CASE_NON_ZERO_LEVEL)
1766 {
1767 glw::GLenum error;
1768
1769 // attaching non-zero level generates invalid value
1770 gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, tex0Id, 5);
1771 error = gl.glGetError();
1772
1773 if (error != GL_INVALID_VALUE)
1774 {
1775 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Expected GL_INVALID_VALUE, got " << glu::getErrorStr(error) << tcu::TestLog::EndMessage;
1776 testFailed = true;
1777 }
1778 }
1779 else
1780 {
1781 gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, tex0Id, 0);
1782 GLU_EXPECT_NO_ERROR(gl.glGetError(), "attach to c0");
1783
1784 if (colorAttachmentTexture)
1785 {
1786 gl.glGenTextures(1, &tex1Id);
1787 gl.glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex1Id);
1788 gl.glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_numSamples1, m_internalFormat, m_fboSize, m_fboSize, fixedSampleLocations1);
1789 GLU_EXPECT_NO_ERROR(gl.glGetError(), "gen texture 1");
1790
1791 gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D_MULTISAMPLE, tex1Id, 0);
1792 GLU_EXPECT_NO_ERROR(gl.glGetError(), "attach to c1");
1793 }
1794 else if (colorAttachmentRbo)
1795 {
1796 gl.glGenRenderbuffers(1, &rboId);
1797 gl.glBindRenderbuffer(GL_RENDERBUFFER, rboId);
1798 gl.glRenderbufferStorageMultisample(GL_RENDERBUFFER, m_numSamples1, m_internalFormat, m_fboSize, m_fboSize);
1799 GLU_EXPECT_NO_ERROR(gl.glGetError(), "gen rb");
1800
1801 gl.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER, rboId);
1802 GLU_EXPECT_NO_ERROR(gl.glGetError(), "attach to c1");
1803 }
1804 else
1805 DE_ASSERT(DE_FALSE);
1806
1807 // should not be complete
1808 {
1809 glw::GLenum status = gl.glCheckFramebufferStatus(GL_FRAMEBUFFER);
1810
1811 if (status != GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE)
1812 {
1813 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Expected GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE, got " << glu::getFramebufferStatusName(status) << tcu::TestLog::EndMessage;
1814 testFailed = true;
1815 }
1816 }
1817 }
1818 }
1819 catch (...)
1820 {
1821 gl.glDeleteFramebuffers(1, &fboId);
1822 gl.glDeleteRenderbuffers(1, &rboId);
1823 gl.glDeleteTextures(1, &tex0Id);
1824 gl.glDeleteTextures(1, &tex1Id);
1825 throw;
1826 }
1827
1828 gl.glDeleteFramebuffers(1, &fboId);
1829 gl.glDeleteRenderbuffers(1, &rboId);
1830 gl.glDeleteTextures(1, &tex0Id);
1831 gl.glDeleteTextures(1, &tex1Id);
1832
1833 if (testFailed)
1834 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong error code");
1835 else
1836 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1837 return STOP;
1838 }
1839
getFormatSamples(glw::GLenum target,std::vector<int> & samples)1840 void NegativeFramebufferCase::getFormatSamples (glw::GLenum target, std::vector<int>& samples)
1841 {
1842 const glw::Functions gl = m_context.getRenderContext().getFunctions();
1843 int sampleCount = 0;
1844
1845 gl.getInternalformativ(target, m_internalFormat, GL_NUM_SAMPLE_COUNTS, 1, &sampleCount);
1846 samples.resize(sampleCount);
1847
1848 if (sampleCount > 0)
1849 {
1850 gl.getInternalformativ(target, m_internalFormat, GL_SAMPLES, sampleCount, &samples[0]);
1851 GLU_EXPECT_NO_ERROR(gl.getError(), "get max samples");
1852 }
1853 }
1854
1855 class NegativeTexParameterCase : public TestCase
1856 {
1857 public:
1858 enum TexParam
1859 {
1860 TEXTURE_MIN_FILTER = 0,
1861 TEXTURE_MAG_FILTER,
1862 TEXTURE_WRAP_S,
1863 TEXTURE_WRAP_T,
1864 TEXTURE_WRAP_R,
1865 TEXTURE_MIN_LOD,
1866 TEXTURE_MAX_LOD,
1867 TEXTURE_COMPARE_MODE,
1868 TEXTURE_COMPARE_FUNC,
1869 TEXTURE_BASE_LEVEL,
1870
1871 TEXTURE_LAST
1872 };
1873
1874 NegativeTexParameterCase (Context& context, const char* name, const char* desc, TexParam param);
1875 ~NegativeTexParameterCase (void);
1876
1877 private:
1878 void init (void);
1879 void deinit (void);
1880 IterateResult iterate (void);
1881
1882 glw::GLenum getParamGLEnum (void) const;
1883 glw::GLint getParamValue (void) const;
1884 glw::GLenum getExpectedError (void) const;
1885
1886 const TexParam m_texParam;
1887 int m_iteration;
1888 };
1889
NegativeTexParameterCase(Context & context,const char * name,const char * desc,TexParam param)1890 NegativeTexParameterCase::NegativeTexParameterCase (Context& context, const char* name, const char* desc, TexParam param)
1891 : TestCase (context, name, desc)
1892 , m_texParam (param)
1893 , m_iteration (0)
1894 {
1895 DE_ASSERT(param < TEXTURE_LAST);
1896 }
1897
~NegativeTexParameterCase(void)1898 NegativeTexParameterCase::~NegativeTexParameterCase (void)
1899 {
1900 deinit();
1901 }
1902
init(void)1903 void NegativeTexParameterCase::init (void)
1904 {
1905 // default value
1906 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1907 }
1908
deinit(void)1909 void NegativeTexParameterCase::deinit (void)
1910 {
1911 }
1912
iterate(void)1913 NegativeTexParameterCase::IterateResult NegativeTexParameterCase::iterate (void)
1914 {
1915 static const struct TextureType
1916 {
1917 const char* name;
1918 glw::GLenum target;
1919 glw::GLenum internalFormat;
1920 bool isArrayType;
1921 } types[] =
1922 {
1923 { "color", GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, false },
1924 { "color array", GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_RGBA8, true },
1925 { "signed integer", GL_TEXTURE_2D_MULTISAMPLE, GL_R8I, false },
1926 { "signed integer array", GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_R8I, true },
1927 { "unsigned integer", GL_TEXTURE_2D_MULTISAMPLE, GL_R8UI, false },
1928 { "unsigned integer array", GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_R8UI, true },
1929 };
1930
1931 const tcu::ScopedLogSection scope(m_testCtx.getLog(), "Iteration", std::string() + "Testing parameter with " + types[m_iteration].name + " texture");
1932 const bool supportsES32orGL45 =
1933 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) ||
1934 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
1935
1936 if (types[m_iteration].isArrayType && !supportsES32orGL45 && !m_context.getContextInfo().isExtensionSupported("GL_OES_texture_storage_multisample_2d_array"))
1937 m_testCtx.getLog() << tcu::TestLog::Message << "GL_OES_texture_storage_multisample_2d_array not supported, skipping target" << tcu::TestLog::EndMessage;
1938 else
1939 {
1940 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
1941 glu::Texture texture (m_context.getRenderContext());
1942 glw::GLenum error;
1943
1944 gl.enableLogging(true);
1945
1946 // gen texture
1947
1948 gl.glBindTexture(types[m_iteration].target, *texture);
1949
1950 if (types[m_iteration].isArrayType)
1951 gl.glTexStorage3DMultisample(types[m_iteration].target, 1, types[m_iteration].internalFormat, 16, 16, 16, GL_FALSE);
1952 else
1953 gl.glTexStorage2DMultisample(types[m_iteration].target, 1, types[m_iteration].internalFormat, 16, 16, GL_FALSE);
1954 GLU_EXPECT_NO_ERROR(gl.glGetError(), "setup texture");
1955
1956 // set param
1957
1958 gl.glTexParameteri(types[m_iteration].target, getParamGLEnum(), getParamValue());
1959 error = gl.glGetError();
1960
1961 // expect failure
1962
1963 if (error != getExpectedError())
1964 {
1965 m_testCtx.getLog() << tcu::TestLog::Message << "Got unexpected error: " << glu::getErrorStr(error) << ", expected: " << glu::getErrorStr(getExpectedError()) << tcu::TestLog::EndMessage;
1966 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong error code");
1967 }
1968 }
1969
1970 if (++m_iteration < DE_LENGTH_OF_ARRAY(types))
1971 return CONTINUE;
1972 return STOP;
1973 }
1974
getParamGLEnum(void) const1975 glw::GLenum NegativeTexParameterCase::getParamGLEnum (void) const
1976 {
1977 switch (m_texParam)
1978 {
1979 case TEXTURE_MIN_FILTER: return GL_TEXTURE_MIN_FILTER;
1980 case TEXTURE_MAG_FILTER: return GL_TEXTURE_MAG_FILTER;
1981 case TEXTURE_WRAP_S: return GL_TEXTURE_WRAP_S;
1982 case TEXTURE_WRAP_T: return GL_TEXTURE_WRAP_T;
1983 case TEXTURE_WRAP_R: return GL_TEXTURE_WRAP_R;
1984 case TEXTURE_MIN_LOD: return GL_TEXTURE_MIN_LOD;
1985 case TEXTURE_MAX_LOD: return GL_TEXTURE_MAX_LOD;
1986 case TEXTURE_COMPARE_MODE: return GL_TEXTURE_COMPARE_MODE;
1987 case TEXTURE_COMPARE_FUNC: return GL_TEXTURE_COMPARE_FUNC;
1988 case TEXTURE_BASE_LEVEL: return GL_TEXTURE_BASE_LEVEL;
1989 default:
1990 DE_ASSERT(DE_FALSE);
1991 return 0;
1992 }
1993 }
1994
getParamValue(void) const1995 glw::GLint NegativeTexParameterCase::getParamValue (void) const
1996 {
1997 switch (m_texParam)
1998 {
1999 case TEXTURE_MIN_FILTER: return GL_LINEAR;
2000 case TEXTURE_MAG_FILTER: return GL_LINEAR;
2001 case TEXTURE_WRAP_S: return GL_CLAMP_TO_EDGE;
2002 case TEXTURE_WRAP_T: return GL_CLAMP_TO_EDGE;
2003 case TEXTURE_WRAP_R: return GL_CLAMP_TO_EDGE;
2004 case TEXTURE_MIN_LOD: return 1;
2005 case TEXTURE_MAX_LOD: return 5;
2006 case TEXTURE_COMPARE_MODE: return GL_NONE;
2007 case TEXTURE_COMPARE_FUNC: return GL_NOTEQUAL;
2008 case TEXTURE_BASE_LEVEL: return 2;
2009 default:
2010 DE_ASSERT(DE_FALSE);
2011 return 0;
2012 }
2013 }
2014
getExpectedError(void) const2015 glw::GLenum NegativeTexParameterCase::getExpectedError (void) const
2016 {
2017 switch (m_texParam)
2018 {
2019 case TEXTURE_MIN_FILTER: return GL_INVALID_ENUM;
2020 case TEXTURE_MAG_FILTER: return GL_INVALID_ENUM;
2021 case TEXTURE_WRAP_S: return GL_INVALID_ENUM;
2022 case TEXTURE_WRAP_T: return GL_INVALID_ENUM;
2023 case TEXTURE_WRAP_R: return GL_INVALID_ENUM;
2024 case TEXTURE_MIN_LOD: return GL_INVALID_ENUM;
2025 case TEXTURE_MAX_LOD: return GL_INVALID_ENUM;
2026 case TEXTURE_COMPARE_MODE: return GL_INVALID_ENUM;
2027 case TEXTURE_COMPARE_FUNC: return GL_INVALID_ENUM;
2028 case TEXTURE_BASE_LEVEL: return GL_INVALID_OPERATION;
2029 default:
2030 DE_ASSERT(DE_FALSE);
2031 return 0;
2032 }
2033 }
2034
2035 class NegativeTexureSampleCase : public TestCase
2036 {
2037 public:
2038 enum SampleCountParam
2039 {
2040 SAMPLECOUNT_HIGH = 0,
2041 SAMPLECOUNT_ZERO,
2042
2043 SAMPLECOUNT_LAST
2044 };
2045
2046 NegativeTexureSampleCase (Context& context, const char* name, const char* desc, SampleCountParam param);
2047 private:
2048 IterateResult iterate (void);
2049
2050 const SampleCountParam m_sampleParam;
2051 };
2052
NegativeTexureSampleCase(Context & context,const char * name,const char * desc,SampleCountParam param)2053 NegativeTexureSampleCase::NegativeTexureSampleCase (Context& context, const char* name, const char* desc, SampleCountParam param)
2054 : TestCase (context, name, desc)
2055 , m_sampleParam (param)
2056 {
2057 DE_ASSERT(param < SAMPLECOUNT_LAST);
2058 }
2059
iterate(void)2060 NegativeTexureSampleCase::IterateResult NegativeTexureSampleCase::iterate (void)
2061 {
2062 const glw::GLenum expectedError = (m_sampleParam == SAMPLECOUNT_HIGH) ? (GL_INVALID_OPERATION) : (GL_INVALID_VALUE);
2063 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
2064 glu::Texture texture (m_context.getRenderContext());
2065 glw::GLenum error;
2066 int samples = -1;
2067
2068 gl.enableLogging(true);
2069
2070 // calc samples
2071
2072 if (m_sampleParam == SAMPLECOUNT_HIGH)
2073 {
2074 int maxSamples = 0;
2075
2076 gl.glGetInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, GL_SAMPLES, 1, &maxSamples);
2077 GLU_EXPECT_NO_ERROR(gl.glGetError(), "glGetInternalformativ");
2078
2079 samples = maxSamples + 1;
2080 }
2081 else if (m_sampleParam == SAMPLECOUNT_ZERO)
2082 samples = 0;
2083 else
2084 DE_ASSERT(DE_FALSE);
2085
2086 // create texture with bad values
2087
2088 gl.glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, *texture);
2089 gl.glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGBA8, 64, 64, GL_FALSE);
2090 error = gl.glGetError();
2091
2092 // expect failure
2093
2094 if (error == expectedError)
2095 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2096 else
2097 {
2098 m_testCtx.getLog() << tcu::TestLog::Message << "Got unexpected error: " << glu::getErrorStr(error) << ", expected: " << glu::getErrorStr(expectedError) << tcu::TestLog::EndMessage;
2099 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong error code");
2100 }
2101
2102 return STOP;
2103 }
2104
2105
2106 } // anonymous
2107
TextureMultisampleTests(Context & context)2108 TextureMultisampleTests::TextureMultisampleTests (Context& context)
2109 : TestCaseGroup(context, "multisample", "Multisample texture tests")
2110 {
2111 }
2112
~TextureMultisampleTests(void)2113 TextureMultisampleTests::~TextureMultisampleTests (void)
2114 {
2115 }
2116
init(void)2117 void TextureMultisampleTests::init (void)
2118 {
2119 static const int sampleCounts[] = { 1, 2, 3, 4, 8, 10, 12, 13, 16, 64 };
2120
2121 static const struct TextureType
2122 {
2123 const char* name;
2124 MultisampleTextureUsageCase::TextureType type;
2125 } textureTypes[] =
2126 {
2127 { "texture_color_2d", MultisampleTextureUsageCase::TEXTURE_COLOR_2D },
2128 { "texture_color_2d_array", MultisampleTextureUsageCase::TEXTURE_COLOR_2D_ARRAY },
2129 { "texture_int_2d", MultisampleTextureUsageCase::TEXTURE_INT_2D },
2130 { "texture_int_2d_array", MultisampleTextureUsageCase::TEXTURE_INT_2D_ARRAY },
2131 { "texture_uint_2d", MultisampleTextureUsageCase::TEXTURE_UINT_2D },
2132 { "texture_uint_2d_array", MultisampleTextureUsageCase::TEXTURE_UINT_2D_ARRAY },
2133 { "texture_depth_2d", MultisampleTextureUsageCase::TEXTURE_DEPTH_2D },
2134 { "texture_depth_2d_array", MultisampleTextureUsageCase::TEXTURE_DEPTH_2D_ARRAY },
2135 };
2136
2137 // .samples_x
2138 for (int sampleNdx = 0; sampleNdx < DE_LENGTH_OF_ARRAY(sampleCounts); ++sampleNdx)
2139 {
2140 tcu::TestCaseGroup* const sampleGroup = new tcu::TestCaseGroup(m_testCtx, (std::string("samples_") + de::toString(sampleCounts[sampleNdx])).c_str(), "Test with N samples");
2141 addChild(sampleGroup);
2142
2143 // position query works
2144 sampleGroup->addChild(new SamplePosRasterizationTest(m_context, "sample_position", "test SAMPLE_POSITION", sampleCounts[sampleNdx]));
2145
2146 // sample mask is ANDed properly
2147 sampleGroup->addChild(new SampleMaskCase(m_context, "sample_mask_only", "Test with SampleMask only", sampleCounts[sampleNdx], SampleMaskCase::FLAGS_NONE));
2148 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));
2149 sampleGroup->addChild(new SampleMaskCase(m_context, "sample_mask_and_sample_coverage", "Test with SampleMask and sample coverage", sampleCounts[sampleNdx], SampleMaskCase::FLAGS_SAMPLE_COVERAGE));
2150 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));
2151
2152 // high bits cause no unexpected behavior
2153 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));
2154
2155 // usage
2156 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(textureTypes); ++typeNdx)
2157 sampleGroup->addChild(new MultisampleTextureUsageCase(m_context, (std::string("use_") + textureTypes[typeNdx].name).c_str(), textureTypes[typeNdx].name, sampleCounts[sampleNdx], textureTypes[typeNdx].type));
2158 }
2159
2160 // .negative
2161 {
2162 tcu::TestCaseGroup* const negativeGroup = new tcu::TestCaseGroup(m_testCtx, "negative", "Negative tests");
2163 addChild(negativeGroup);
2164
2165 negativeGroup->addChild(new NegativeFramebufferCase (m_context, "fbo_attach_different_sample_count_tex_tex", "Attach different sample counts", NegativeFramebufferCase::CASE_DIFFERENT_N_SAMPLES_TEX));
2166 negativeGroup->addChild(new NegativeFramebufferCase (m_context, "fbo_attach_different_sample_count_tex_rbo", "Attach different sample counts", NegativeFramebufferCase::CASE_DIFFERENT_N_SAMPLES_RBO));
2167 negativeGroup->addChild(new NegativeFramebufferCase (m_context, "fbo_attach_different_fixed_state_tex_tex", "Attach fixed and non fixed", NegativeFramebufferCase::CASE_DIFFERENT_FIXED_TEX));
2168 negativeGroup->addChild(new NegativeFramebufferCase (m_context, "fbo_attach_different_fixed_state_tex_rbo", "Attach fixed and non fixed", NegativeFramebufferCase::CASE_DIFFERENT_FIXED_RBO));
2169 negativeGroup->addChild(new NegativeFramebufferCase (m_context, "fbo_attach_non_zero_level", "Attach non-zero level", NegativeFramebufferCase::CASE_NON_ZERO_LEVEL));
2170 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_min_filter", "set TEXTURE_MIN_FILTER", NegativeTexParameterCase::TEXTURE_MIN_FILTER));
2171 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_mag_filter", "set TEXTURE_MAG_FILTER", NegativeTexParameterCase::TEXTURE_MAG_FILTER));
2172 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_wrap_s", "set TEXTURE_WRAP_S", NegativeTexParameterCase::TEXTURE_WRAP_S));
2173 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_wrap_t", "set TEXTURE_WRAP_T", NegativeTexParameterCase::TEXTURE_WRAP_T));
2174 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_wrap_r", "set TEXTURE_WRAP_R", NegativeTexParameterCase::TEXTURE_WRAP_R));
2175 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_min_lod", "set TEXTURE_MIN_LOD", NegativeTexParameterCase::TEXTURE_MIN_LOD));
2176 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_max_lod", "set TEXTURE_MAX_LOD", NegativeTexParameterCase::TEXTURE_MAX_LOD));
2177 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_compare_mode", "set TEXTURE_COMPARE_MODE", NegativeTexParameterCase::TEXTURE_COMPARE_MODE));
2178 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_compare_func", "set TEXTURE_COMPARE_FUNC", NegativeTexParameterCase::TEXTURE_COMPARE_FUNC));
2179 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_base_level", "set TEXTURE_BASE_LEVEL", NegativeTexParameterCase::TEXTURE_BASE_LEVEL));
2180 negativeGroup->addChild(new NegativeTexureSampleCase(m_context, "texture_high_sample_count", "TexStorage with high numSamples", NegativeTexureSampleCase::SAMPLECOUNT_HIGH));
2181 negativeGroup->addChild(new NegativeTexureSampleCase(m_context, "texture_zero_sample_count", "TexStorage with zero numSamples", NegativeTexureSampleCase::SAMPLECOUNT_ZERO));
2182 }
2183 }
2184
2185 } // Functional
2186 } // gles31
2187 } // deqp
2188