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