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