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