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