Always apply flat qualifier to double inputs, same as int/uint
[platform/upstream/VK-GL-CTS.git] / external / openglcts / modules / common / glcSampleVariablesTests.cpp
1 /*-------------------------------------------------------------------------
2  * OpenGL Conformance Test Suite
3  * -----------------------------
4  *
5  * Copyright (c) 2014-2016 The Khronos Group Inc.
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
22  */ /*-------------------------------------------------------------------*/
23
24 #include "glcSampleVariablesTests.hpp"
25 #include "deMath.h"
26 #include "deRandom.hpp"
27 #include "deStringUtil.hpp"
28 #include "gluContextInfo.hpp"
29 #include "gluDrawUtil.hpp"
30 #include "gluPixelTransfer.hpp"
31 #include "gluShaderProgram.hpp"
32 #include "glw.h"
33 #include "glwFunctions.hpp"
34 #include "tcuCommandLine.hpp"
35 #include "tcuStringTemplate.hpp"
36 #include "tcuSurface.hpp"
37 #include "tcuTestLog.hpp"
38
39 namespace tcu
40 {
41 static bool operator<(tcu::Vec4 const& k1, tcu::Vec4 const& k2)
42 {
43         if (k1.y() < k2.y())
44         {
45                 return true;
46         }
47         else if (k1.y() == k2.y())
48         {
49                 return k1.x() < k2.x();
50         }
51         else
52         {
53                 return false;
54         }
55 }
56 }
57
58 namespace deqp
59 {
60
61 using tcu::TestLog;
62 using std::string;
63 using std::vector;
64
65 static std::string specializeVersion(std::string const& source, glu::GLSLVersion version,
66                                                                          std::string const& sampler = "", std::string const& outType = "")
67 {
68         DE_ASSERT(version == glu::GLSL_VERSION_310_ES || version >= glu::GLSL_VERSION_400);
69         std::map<std::string, std::string> args;
70         args["VERSION_DECL"] = glu::getGLSLVersionDeclaration(version);
71         args["SAMPLER"]          = sampler;
72         args["OUT_TYPE"]         = outType;
73         if (version == glu::GLSL_VERSION_310_ES)
74         {
75                 args["OES_SV_RQ"] = "#extension GL_OES_sample_variables : require\n";
76                 args["OES_SV_EN"] = "#extension GL_OES_sample_variables : enable\n";
77         }
78         else
79         {
80                 args["OES_SV_RQ"] = "";
81                 args["OES_SV_EN"] = "";
82         }
83         return tcu::StringTemplate(source.c_str()).specialize(args);
84 }
85
86 class SampleShadingExtensionCase : public TestCase
87 {
88 public:
89         SampleShadingExtensionCase(Context& context, const char* name, const char* description,
90                                                            glu::GLSLVersion glslVersion);
91         ~SampleShadingExtensionCase();
92
93         IterateResult iterate();
94
95 protected:
96         glu::GLSLVersion m_glslVersion;
97 };
98
99 SampleShadingExtensionCase::SampleShadingExtensionCase(Context& context, const char* name, const char* description,
100                                                                                                            glu::GLSLVersion glslVersion)
101         : TestCase(context, name, description), m_glslVersion(glslVersion)
102 {
103         DE_ASSERT(glslVersion == glu::GLSL_VERSION_310_ES);
104 }
105
106 SampleShadingExtensionCase::~SampleShadingExtensionCase()
107 {
108 }
109
110 SampleShadingExtensionCase::IterateResult SampleShadingExtensionCase::iterate()
111 {
112         TestLog& log = m_testCtx.getLog();
113
114         if (!m_context.getContextInfo().isExtensionSupported("GL_OES_sample_variables"))
115         {
116                 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_OES_sample_variables");
117                 return STOP;
118         }
119
120         static char const* vss = "${VERSION_DECL}\n"
121                                                          "in highp vec4 a_position;\n"
122                                                          "void main()\n"
123                                                          "{\n"
124                                                          "    gl_Position = a_position;\n"
125                                                          "}\n";
126
127         {
128                 static char const* fss = "${VERSION_DECL}\n"
129                                                                  "${OES_SV_RQ}"
130                                                                  "out highp vec4 o_color;\n"
131                                                                  "void main()\n"
132                                                                  "{\n"
133                                                                  "    for (int i = 0; i < (gl_MaxSamples + 31) / 32; ++i) {\n"
134                                                                  "        gl_SampleMask[i] = gl_SampleMaskIn[i];\n"
135                                                                  "    }\n"
136                                                                  "    o_color = vec4(gl_SampleID, gl_SamplePosition.x, gl_SamplePosition.y, 1);\n"
137                                                                  "}\n";
138
139                 glu::ShaderProgram programRequire(m_context.getRenderContext(),
140                                                                                   glu::makeVtxFragSources(specializeVersion(vss, m_glslVersion).c_str(),
141                                                                                                                                   specializeVersion(fss, m_glslVersion).c_str()));
142                 log << programRequire;
143                 if (!programRequire.isOk())
144                 {
145                         TCU_FAIL("Compile failed");
146                 }
147         }
148
149         {
150                 static char const* fss = "${VERSION_DECL}\n"
151                                                                  "${OES_SV_EN}"
152                                                                  "out highp vec4 o_color;\n"
153                                                                  "void main()\n"
154                                                                  "{\n"
155                                                                  "#if !GL_OES_sample_variables\n"
156                                                                  "    this is broken\n"
157                                                                  "#endif\n"
158                                                                  "    for (int i = 0; i < (gl_MaxSamples + 31) / 32; ++i) {\n"
159                                                                  "        gl_SampleMask[i] = gl_SampleMaskIn[i];\n"
160                                                                  "    }\n"
161                                                                  "    o_color = vec4(gl_SampleID, gl_SamplePosition.x, gl_SamplePosition.y, 1);\n"
162                                                                  "}\n";
163
164                 glu::ShaderProgram programEnable(m_context.getRenderContext(),
165                                                                                  glu::makeVtxFragSources(specializeVersion(vss, m_glslVersion).c_str(),
166                                                                                                                                  specializeVersion(fss, m_glslVersion).c_str()));
167                 log << programEnable;
168                 if (!programEnable.isOk())
169                 {
170                         TCU_FAIL("Compile failed");
171                 }
172         }
173
174         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
175         return STOP;
176 }
177
178 class SampleShadingMaskCase : public TestCase
179 {
180 public:
181         SampleShadingMaskCase(Context& context, const char* name, const char* description, glu::GLSLVersion glslVersion,
182                                                   GLenum internalFormat, tcu::TextureFormat const& texFormat, const char* sampler,
183                                                   const char* outType, GLint samples, GLint sampleMask);
184         ~SampleShadingMaskCase();
185
186         IterateResult iterate();
187
188 protected:
189         glu::GLSLVersion   m_glslVersion;
190         GLenum                     m_internalFormat;
191         tcu::TextureFormat m_texFormat;
192         std::string                m_sampler;
193         std::string                m_outType;
194         GLint                      m_samples;
195         GLint                      m_sampleMask;
196
197         enum
198         {
199                 WIDTH           = 16,
200                 HEIGHT          = 16,
201                 MAX_SAMPLES = 4,
202         };
203 };
204
205 SampleShadingMaskCase::SampleShadingMaskCase(Context& context, const char* name, const char* description,
206                                                                                          glu::GLSLVersion glslVersion, GLenum internalFormat,
207                                                                                          tcu::TextureFormat const& texFormat, const char* sampler,
208                                                                                          const char* outType, GLint samples, GLint sampleMask)
209         : TestCase(context, name, description)
210         , m_glslVersion(glslVersion)
211         , m_internalFormat(internalFormat)
212         , m_texFormat(texFormat)
213         , m_sampler(sampler)
214         , m_outType(outType)
215         , m_samples(samples)
216         , m_sampleMask(sampleMask)
217 {
218         DE_ASSERT(glslVersion == glu::GLSL_VERSION_310_ES || glslVersion >= glu::GLSL_VERSION_400);
219 }
220
221 SampleShadingMaskCase::~SampleShadingMaskCase()
222 {
223 }
224
225 SampleShadingMaskCase::IterateResult SampleShadingMaskCase::iterate()
226 {
227         TestLog&                          log                     = m_testCtx.getLog();
228         const glw::Functions& gl                          = m_context.getRenderContext().getFunctions();
229         bool                              isOk                    = true;
230         bool                              supportsRgba32f = false;
231
232         if (m_glslVersion == glu::GLSL_VERSION_310_ES &&
233                 !m_context.getContextInfo().isExtensionSupported("GL_OES_sample_variables"))
234         {
235                 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_OES_sample_variables");
236                 return STOP;
237         }
238
239         supportsRgba32f = isContextTypeGLCore(m_context.getRenderContext().getType()) ?
240                                                   true :
241                                                   (m_context.getContextInfo().isExtensionSupported("GL_EXT_color_buffer_float") ||
242                                                    m_context.getContextInfo().isExtensionSupported("GL_ARB_color_buffer_float"));
243
244         if (m_internalFormat == GL_RGBA32F && !supportsRgba32f)
245         {
246                 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Internalformat rgba32f not supported");
247                 return STOP;
248         }
249
250         GLint maxSamples;
251         if (((m_texFormat.type == tcu::TextureFormat::FLOAT) && (m_texFormat.order == tcu::TextureFormat::RGBA)) ||
252                 ((m_texFormat.type == tcu::TextureFormat::FLOAT) && (m_texFormat.order == tcu::TextureFormat::RG)) ||
253                 ((m_texFormat.type == tcu::TextureFormat::FLOAT) && (m_texFormat.order == tcu::TextureFormat::R)) ||
254                 ((m_texFormat.type == tcu::TextureFormat::HALF_FLOAT) && (m_texFormat.order == tcu::TextureFormat::RGBA)))
255         {
256                 gl.getInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, m_internalFormat, GL_SAMPLES, 1, &maxSamples);
257                 if (m_samples > maxSamples)
258                 {
259                         m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED,
260                                                                         "Test sample count greater than samples that the format supports");
261                         return STOP;
262                 }
263         }
264         else if (m_texFormat.type == tcu::TextureFormat::SIGNED_INT8 ||
265                          m_texFormat.type == tcu::TextureFormat::UNSIGNED_INT8)
266         {
267                 gl.getIntegerv(GL_MAX_INTEGER_SAMPLES, &maxSamples);
268                 if (m_samples > maxSamples)
269                 {
270                         m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Test sample count greater than MAX_INTEGER_SAMPLES");
271                         return STOP;
272                 }
273         }
274         else
275         {
276                 gl.getIntegerv(GL_MAX_SAMPLES, &maxSamples);
277                 if (m_samples > maxSamples)
278                 {
279                         m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Test sample count greater than MAX_SAMPLES");
280                         return STOP;
281                 }
282         }
283
284         // Create a multisample texture, or a regular texture if samples is zero.
285         GLuint tex;
286         gl.genTextures(1, &tex);
287         GLenum target;
288         if (m_samples)
289         {
290                 target = GL_TEXTURE_2D_MULTISAMPLE;
291                 gl.bindTexture(target, tex);
292                 gl.texStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_samples, m_internalFormat, WIDTH, HEIGHT, GL_FALSE);
293         }
294         else
295         {
296                 target = GL_TEXTURE_2D;
297                 gl.bindTexture(target, tex);
298                 gl.texStorage2D(GL_TEXTURE_2D, 1, m_internalFormat, WIDTH, HEIGHT);
299                 if (m_texFormat.type == tcu::TextureFormat::SIGNED_INT8 ||
300                         m_texFormat.type == tcu::TextureFormat::UNSIGNED_INT8 || m_texFormat.type == tcu::TextureFormat::FLOAT)
301                 {
302                         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
303                         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
304                 }
305         }
306
307         // Create a framebuffer with the texture attached and clear to "green".
308         GLuint fboMs;
309         gl.genFramebuffers(1, &fboMs);
310         gl.bindFramebuffer(GL_FRAMEBUFFER, fboMs);
311         gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, tex, 0);
312         gl.viewport(0, 0, WIDTH, HEIGHT);
313         if (m_texFormat.type == tcu::TextureFormat::SIGNED_INT8)
314         {
315                 GLint color[4] = { 0, 1, 0, 1 };
316                 gl.clearBufferiv(GL_COLOR, 0, color);
317         }
318         else if (m_texFormat.type == tcu::TextureFormat::UNSIGNED_INT8)
319         {
320                 GLuint color[4] = { 0, 1, 0, 1 };
321                 gl.clearBufferuiv(GL_COLOR, 0, color);
322         }
323         else
324         {
325                 GLfloat color[4] = { 0.0f, 1.0f, 0.0f, 1.0f };
326                 gl.clearBufferfv(GL_COLOR, 0, color);
327         }
328
329         static deUint16 const quadIndices[] = { 0, 1, 2, 2, 1, 3 };
330
331         {
332                 // Draw a quad setting all samples to "red". We only expect "red"
333                 // to be written if the sample mask bit for that sample is 1.
334
335                 static char const* vss = "${VERSION_DECL}\n"
336                                                                  "in highp vec2 a_position;\n"
337                                                                  "void main()\n"
338                                                                  "{\n"
339                                                                  "   gl_Position = vec4(a_position, 0.0, 1.0);\n"
340                                                                  "}\n";
341
342                 static char const* fss = "${VERSION_DECL}\n"
343                                                                  "${OES_SV_RQ}"
344                                                                  "layout(location = 0) out highp ${OUT_TYPE} o_color;\n"
345                                                                  "uniform int u_sampleMask;\n"
346                                                                  "void main()\n"
347                                                                  "{\n"
348                                                                  "    for (int i = 0; i < (gl_NumSamples + 31) / 32; ++i) {\n"
349                                                                  "        gl_SampleMask[i] = u_sampleMask & gl_SampleMaskIn[i];\n"
350                                                                  "    }\n"
351                                                                  "    o_color = ${OUT_TYPE}(1, 0, 0, 1);\n"
352                                                                  "}\n";
353
354                 glu::ShaderProgram program(
355                         m_context.getRenderContext(),
356                         glu::makeVtxFragSources(specializeVersion(vss, m_glslVersion, m_sampler, m_outType).c_str(),
357                                                                         specializeVersion(fss, m_glslVersion, m_sampler, m_outType).c_str()));
358                 log << program;
359                 if (!program.isOk())
360                 {
361                         TCU_FAIL("Compile failed");
362                 }
363
364                 static float const position[] = {
365                         -1.0f, -1.0f, -1.0f, +1.0f, +1.0f, -1.0f, +1.0f, +1.0f,
366                 };
367
368                 gl.useProgram(program.getProgram());
369                 gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_sampleMask"), m_sampleMask);
370
371                 glu::VertexArrayBinding vertexArrays[] = {
372                         glu::va::Float("a_position", 2, 4, 0, &position[0]),
373                 };
374                 glu::draw(m_context.getRenderContext(), program.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays),
375                                   &vertexArrays[0], glu::pr::TriangleStrip(DE_LENGTH_OF_ARRAY(quadIndices), &quadIndices[0]));
376
377                 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw quad");
378         }
379
380         gl.bindFramebuffer(GL_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer());
381         gl.deleteFramebuffers(1, &fboMs);
382
383         GLsizei width = WIDTH * ((m_samples) ? m_samples : 1);
384
385         GLuint rbo;
386         gl.genRenderbuffers(1, &rbo);
387         gl.bindRenderbuffer(GL_RENDERBUFFER, rbo);
388         gl.renderbufferStorage(GL_RENDERBUFFER, m_internalFormat, width, HEIGHT);
389
390         GLuint fbo;
391         gl.genFramebuffers(1, &fbo);
392         gl.bindFramebuffer(GL_FRAMEBUFFER, fbo);
393         gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
394         gl.viewport(0, 0, width, HEIGHT);
395
396         {
397                 // Resolve the multi-sample texture into a render-buffer sized such that
398                 // the width can hold all samples of a pixel.
399                 static char const* vss = "${VERSION_DECL}\n"
400                                                                  "in highp vec2 a_position;\n"
401                                                                  "void main(void)\n"
402                                                                  "{\n"
403                                                                  "   gl_Position = vec4(a_position, 0.0, 1.0);\n"
404                                                                  "}\n";
405
406                 static char const* fss = "${VERSION_DECL}\n"
407                                                                  "uniform highp ${SAMPLER} u_tex;\n"
408                                                                  "uniform highp ${SAMPLER}MS u_texMS;\n"
409                                                                  "uniform int u_samples;\n"
410                                                                  "layout(location = 0) out highp ${OUT_TYPE} o_color;\n"
411                                                                  "void main(void)\n"
412                                                                  "{\n"
413                                                                  "    if (u_samples > 0) {\n"
414                                                                  "        ivec2 coord = ivec2(int(gl_FragCoord.x) / u_samples, gl_FragCoord.y);\n"
415                                                                  "        int sampleId = int(gl_FragCoord.x) % u_samples;\n"
416                                                                  "        o_color = texelFetch(u_texMS, coord, sampleId);\n"
417                                                                  "    } else {\n"
418                                                                  "        ivec2 coord = ivec2(gl_FragCoord.x, gl_FragCoord.y);\n"
419                                                                  "       o_color = texelFetch(u_tex, coord, 0);\n"
420                                                                  "    }\n"
421                                                                  "}\n";
422
423                 glu::ShaderProgram program(
424                         m_context.getRenderContext(),
425                         glu::makeVtxFragSources(specializeVersion(vss, m_glslVersion, m_sampler, m_outType).c_str(),
426                                                                         specializeVersion(fss, m_glslVersion, m_sampler, m_outType).c_str()));
427                 log << program;
428                 if (!program.isOk())
429                 {
430                         TCU_FAIL("Compile failed");
431                 }
432
433                 static float const position[] = {
434                         -1.0f, -1.0f, -1.0f, +1.0f, +1.0f, -1.0f, +1.0f, +1.0f,
435                 };
436
437                 gl.useProgram(program.getProgram());
438                 gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_samples"), m_samples);
439                 if (m_samples > 0)
440                 {
441                         // only MS sampler needed, TU 1 is not used
442                         gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_tex"), 1);
443                         gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_texMS"), 0);
444                 }
445                 else
446                 {
447                         // only non-MS sampler needed, TU 1 is not used
448                         gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_tex"), 0);
449                         gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_texMS"), 1);
450                 }
451
452                 glu::VertexArrayBinding vertexArrays[] = {
453                         glu::va::Float("a_position", 2, 4, 0, &position[0]),
454                 };
455                 glu::draw(m_context.getRenderContext(), program.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays),
456                                   &vertexArrays[0], glu::pr::TriangleStrip(DE_LENGTH_OF_ARRAY(quadIndices), &quadIndices[0]));
457
458                 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw quad");
459         }
460
461         tcu::TextureLevel         results(m_texFormat, width, HEIGHT);
462         tcu::PixelBufferAccess pixels = results.getAccess();
463         std::vector<tcu::Vec4> result(pixels.getHeight() * pixels.getWidth());
464
465         if (pixels.getFormat().type == tcu::TextureFormat::SIGNED_INT8)
466         {
467                 std::vector<GLint> data(pixels.getHeight() * pixels.getWidth() * 4);
468                 gl.readPixels(0, 0, pixels.getWidth(), pixels.getHeight(), GL_RGBA_INTEGER, GL_INT, &data[0]);
469                 for (unsigned int i = 0; i < data.size(); i += 4)
470                 {
471                         result[i / 4] =
472                                 tcu::Vec4((GLfloat)data[i], (GLfloat)data[i + 1], (GLfloat)data[i + 2], (GLfloat)data[i + 3]);
473                 }
474         }
475         else if (pixels.getFormat().type == tcu::TextureFormat::UNSIGNED_INT8)
476         {
477                 std::vector<GLuint> data(pixels.getHeight() * pixels.getWidth() * 4);
478                 gl.readPixels(0, 0, pixels.getWidth(), pixels.getHeight(), GL_RGBA_INTEGER, GL_UNSIGNED_INT, &data[0]);
479                 for (unsigned int i = 0; i < data.size(); i += 4)
480                 {
481                         result[i / 4] =
482                                 tcu::Vec4((GLfloat)data[i], (GLfloat)data[i + 1], (GLfloat)data[i + 2], (GLfloat)data[i + 3]);
483                 }
484         }
485         else
486         {
487                 glu::readPixels(m_context.getRenderContext(), 0, 0, pixels);
488         }
489
490         for (int y = 0; y < HEIGHT; ++y)
491         {
492                 for (int x = 0; x < WIDTH; ++x)
493                 {
494                         GLint samples = (m_samples) ? m_samples : 1;
495                         for (int sample = 0; sample < samples; ++sample)
496                         {
497                                 tcu::Vec4 pixel;
498                                 if (pixels.getFormat().type == tcu::TextureFormat::SIGNED_INT8 ||
499                                         pixels.getFormat().type == tcu::TextureFormat::UNSIGNED_INT8)
500                                 {
501                                         pixel = result[y * WIDTH + x * samples + sample];
502                                 }
503                                 else
504                                 {
505                                         pixel = pixels.getPixel(x * samples + sample, y);
506                                 }
507
508                                 // Make sure only those samples where the sample mask bit is
509                                 // non-zero have the "red" pixel values.
510                                 if (!m_samples || (m_sampleMask & (1 << sample)))
511                                 {
512                                         if (pixel != tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f))
513                                         {
514                                                 isOk = false;
515                                         }
516                                 }
517                                 else
518                                 {
519                                         if (pixel != tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f))
520                                         {
521                                                 isOk = false;
522                                         }
523                                 }
524                         }
525                 }
526         }
527
528         gl.bindFramebuffer(GL_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer());
529         gl.deleteFramebuffers(1, &fbo);
530
531         gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
532         gl.deleteRenderbuffers(1, &rbo);
533
534         gl.bindTexture(target, 0);
535         gl.deleteTextures(1, &tex);
536
537         m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, isOk ? "Pass" : "Fail");
538         return STOP;
539 }
540
541 class SampleShadingPositionCase : public TestCase
542 {
543 public:
544         SampleShadingPositionCase(Context& context, const char* name, const char* description, glu::GLSLVersion glslVersion,
545                                                           GLint samples, GLboolean fixedSampleLocations);
546         ~SampleShadingPositionCase();
547
548         IterateResult iterate();
549
550 protected:
551         glu::GLSLVersion m_glslVersion;
552         GLint                    m_samples;
553         GLboolean                m_fixedSampleLocations;
554
555         enum
556         {
557                 WIDTH           = 8,
558                 HEIGHT          = 8,
559                 MAX_SAMPLES = 8,
560         };
561 };
562
563 SampleShadingPositionCase::SampleShadingPositionCase(Context& context, const char* name, const char* description,
564                                                                                                          glu::GLSLVersion glslVersion, GLint samples,
565                                                                                                          GLboolean fixedSampleLocations)
566         : TestCase(context, name, description)
567         , m_glslVersion(glslVersion)
568         , m_samples(samples)
569         , m_fixedSampleLocations(fixedSampleLocations)
570 {
571         DE_ASSERT(glslVersion == glu::GLSL_VERSION_310_ES || glslVersion >= glu::GLSL_VERSION_400);
572 }
573
574 SampleShadingPositionCase::~SampleShadingPositionCase()
575 {
576 }
577
578 SampleShadingPositionCase::IterateResult SampleShadingPositionCase::iterate()
579 {
580         TestLog&                          log  = m_testCtx.getLog();
581         const glw::Functions& gl   = m_context.getRenderContext().getFunctions();
582         bool                              isOk = true;
583
584         if (m_glslVersion == glu::GLSL_VERSION_310_ES &&
585                 !m_context.getContextInfo().isExtensionSupported("GL_OES_sample_variables"))
586         {
587                 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_OES_sample_variables");
588                 return STOP;
589         }
590
591         GLint maxSamples;
592         gl.getIntegerv(GL_MAX_SAMPLES, &maxSamples);
593         if (m_samples > maxSamples)
594         {
595                 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Test sample count great than MAX_SAMPLES");
596                 return STOP;
597         }
598
599         // Create a multisample texture, or a regular texture if samples is zero.
600         GLuint tex;
601         gl.genTextures(1, &tex);
602         GLenum target;
603         if (m_samples)
604         {
605                 target = GL_TEXTURE_2D_MULTISAMPLE;
606                 gl.bindTexture(target, tex);
607                 gl.texStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_samples, GL_RGBA8, WIDTH, HEIGHT,
608                                                                    m_fixedSampleLocations);
609         }
610         else
611         {
612                 target = GL_TEXTURE_2D;
613                 gl.bindTexture(target, tex);
614                 gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, WIDTH, HEIGHT);
615         }
616
617         // Attach the texture to the framebuffer to render to it.
618         GLuint fboMs;
619         gl.genFramebuffers(1, &fboMs);
620         gl.bindFramebuffer(GL_FRAMEBUFFER, fboMs);
621         gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, tex, 0);
622         gl.viewport(0, 0, WIDTH, HEIGHT);
623
624         // Save all the sample positions for this multisample framebuffer.
625         std::vector<tcu::Vec4> samplePositions;
626         if (m_samples)
627         {
628                 samplePositions.resize(m_samples);
629                 for (int sample = 0; sample < m_samples; ++sample)
630                 {
631                         GLfloat position[2];
632                         gl.getMultisamplefv(GL_SAMPLE_POSITION, sample, position);
633                         samplePositions[sample] = tcu::Vec4(position[0], position[1], 0.0f, 1.0f);
634                 }
635         }
636
637         static deUint16 const quadIndices[] = { 0, 1, 2, 2, 1, 3 };
638
639         {
640                 // Render all the sample positions to each pixel sample.
641
642                 static char const* vss = "${VERSION_DECL}\n"
643                                                                  "in highp vec2 a_position;\n"
644                                                                  "void main()\n"
645                                                                  "{\n"
646                                                                  "   gl_Position = vec4(a_position, 0.0, 1.0);\n"
647                                                                  "}\n";
648
649                 static char const* fss = "${VERSION_DECL}\n"
650                                                                  "${OES_SV_RQ}"
651                                                                  "layout(location = 0) out highp vec4 o_color;\n"
652                                                                  "void main()\n"
653                                                                  "{\n"
654                                                                  "    o_color = vec4(gl_SamplePosition, 0, 1);\n"
655                                                                  "}\n";
656
657                 glu::ShaderProgram program(m_context.getRenderContext(),
658                                                                    glu::makeVtxFragSources(specializeVersion(vss, m_glslVersion).c_str(),
659                                                                                                                    specializeVersion(fss, m_glslVersion).c_str()));
660                 log << program;
661                 if (!program.isOk())
662                 {
663                         TCU_FAIL("Compile failed");
664                 }
665
666                 const float position[] = {
667                         -1.0f, -1.0f, -1.0f, +1.0f, +1.0f, -1.0f, +1.0f, +1.0f,
668                 };
669
670                 gl.useProgram(program.getProgram());
671
672                 glu::VertexArrayBinding vertexArrays[] = {
673                         glu::va::Float("a_position", 2, 4, 0, &position[0]),
674                 };
675
676                 glu::draw(m_context.getRenderContext(), program.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays),
677                                   &vertexArrays[0], glu::pr::TriangleStrip(DE_LENGTH_OF_ARRAY(quadIndices), &quadIndices[0]));
678
679                 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw quad");
680         }
681
682         gl.bindFramebuffer(GL_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer());
683         gl.deleteFramebuffers(1, &fboMs);
684
685         // Create a regular non-multisample render buffer to resolve to multisample texture into.
686         // The width is increased to save all samples of the pixel.
687
688         GLsizei width = WIDTH * ((m_samples) ? m_samples : 1);
689
690         GLuint rbo;
691         gl.genRenderbuffers(1, &rbo);
692         gl.bindRenderbuffer(GL_RENDERBUFFER, rbo);
693         gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, HEIGHT);
694
695         GLuint fbo;
696         gl.genFramebuffers(1, &fbo);
697         gl.bindFramebuffer(GL_FRAMEBUFFER, fbo);
698         gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
699         gl.viewport(0, 0, width, HEIGHT);
700
701         {
702                 // Resolve the multisample texture to the renderbuffer.
703
704                 static char const* vss = "${VERSION_DECL}\n"
705                                                                  "in highp vec2 a_position;\n"
706                                                                  "void main(void)\n"
707                                                                  "{\n"
708                                                                  "   gl_Position = vec4(a_position, 0.0, 1.0);\n"
709                                                                  "}\n";
710
711                 static char const* fss = "${VERSION_DECL}\n"
712                                                                  "uniform highp sampler2D u_tex;\n"
713                                                                  "uniform highp sampler2DMS u_texMS;\n"
714                                                                  "uniform int u_samples;\n"
715                                                                  "layout(location = 0) out highp vec4 o_color;\n"
716                                                                  "void main(void)\n"
717                                                                  "{\n"
718                                                                  "    if (u_samples > 0) {\n"
719                                                                  "        ivec2 coord = ivec2(int(gl_FragCoord.x) / u_samples, gl_FragCoord.y);\n"
720                                                                  "        int sampleId = int(gl_FragCoord.x) % u_samples;\n"
721                                                                  "        o_color = texelFetch(u_texMS, coord, sampleId);\n"
722                                                                  "    } else {\n"
723                                                                  "        ivec2 coord = ivec2(gl_FragCoord.x, gl_FragCoord.y);\n"
724                                                                  "        o_color = texelFetch(u_tex, coord, 0);\n"
725                                                                  "    }\n"
726                                                                  "}\n";
727
728                 glu::ShaderProgram program(m_context.getRenderContext(),
729                                                                    glu::makeVtxFragSources(specializeVersion(vss, m_glslVersion).c_str(),
730                                                                                                                    specializeVersion(fss, m_glslVersion).c_str()));
731                 log << program;
732                 if (!program.isOk())
733                 {
734                         TCU_FAIL("Compile failed");
735                 }
736
737                 static float const position[] = {
738                         -1.0f, -1.0f, -1.0f, +1.0f, +1.0f, -1.0f, +1.0f, +1.0f,
739                 };
740
741                 gl.useProgram(program.getProgram());
742                 gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_samples"), m_samples);
743                 if (m_samples > 0)
744                 {
745                         // only MS sampler needed, TU 1 is not used
746                         gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_tex"), 1);
747                         gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_texMS"), 0);
748                 }
749                 else
750                 {
751                         // only non-MS sampler needed, TU 1 is not used
752                         gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_tex"), 0);
753                         gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_texMS"), 1);
754                 }
755
756                 glu::VertexArrayBinding vertexArrays[] = {
757                         glu::va::Float("a_position", 2, 4, 0, &position[0]),
758                 };
759                 glu::draw(m_context.getRenderContext(), program.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays),
760                                   &vertexArrays[0], glu::pr::TriangleStrip(DE_LENGTH_OF_ARRAY(quadIndices), &quadIndices[0]));
761
762                 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw quad");
763         }
764
765         // Read the renderbuffer pixels and verify we get back what we're expecting.
766         tcu::TextureLevel results(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), width,
767                                                           HEIGHT);
768         tcu::PixelBufferAccess pixels = results.getAccess();
769         glu::readPixels(m_context.getRenderContext(), 0, 0, pixels);
770         if (m_samples)
771         {
772                 // If m_fixedSampleLocations are used make sure the first pixel's samples
773                 // all match the SAMPLE_POSITION state saved earlier.
774                 std::set<tcu::Vec4> fixedSampleLocations;
775                 if (m_fixedSampleLocations)
776                 {
777                         for (int sample = 0; sample < m_samples; ++sample)
778                         {
779                                 tcu::Vec4 pixel = pixels.getPixel(sample, 0);
780                                 fixedSampleLocations.insert(pixel);
781                                 if (deFloatAbs(pixel.x() - samplePositions[sample].x()) > 0.01 ||
782                                         deFloatAbs(pixel.y() - samplePositions[sample].y()) > 0.01)
783                                 {
784
785                                         isOk = false;
786                                 }
787                         }
788                 }
789
790                 // Verify all samples of every pixel to make sure each position is unique.
791                 for (int y = 0; y < HEIGHT; ++y)
792                 {
793                         for (int x = 0; x < WIDTH; ++x)
794                         {
795                                 std::set<tcu::Vec4> uniquePixels;
796                                 for (int sample = 0; sample < m_samples; ++sample)
797                                 {
798                                         uniquePixels.insert(pixels.getPixel(x * m_samples + sample, y));
799                                 }
800                                 if ((GLint)uniquePixels.size() != m_samples)
801                                 {
802                                         isOk = false;
803                                 }
804                                 // For the m_fixedSampleLocations case make sure each position
805                                 // matches the sample positions of pixel(0, 0) saved earlier.
806                                 if (m_fixedSampleLocations)
807                                 {
808                                         if (fixedSampleLocations != uniquePixels)
809                                         {
810                                                 isOk = false;
811                                         }
812                                 }
813                         }
814                 }
815         }
816         else
817         {
818                 // For the non-multisample case make sure all the positions are (0.5,0.5).
819                 for (int y = 0; y < pixels.getHeight(); ++y)
820                 {
821                         for (int x = 0; x < pixels.getWidth(); ++x)
822                         {
823                                 tcu::Vec4 pixel = pixels.getPixel(x, y);
824                                 if (deFloatAbs(pixel.x() - 0.5f) > 0.01 || deFloatAbs(pixel.y() - 0.5f) > 0.01 || pixel.z() != 0.0f ||
825                                         pixel.w() != 1.0f)
826                                 {
827                                         isOk = false;
828                                 }
829                         }
830                 }
831         }
832
833         gl.bindFramebuffer(GL_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer());
834         gl.deleteFramebuffers(1, &fbo);
835
836         gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
837         gl.deleteRenderbuffers(1, &rbo);
838
839         gl.bindTexture(target, 0);
840         gl.deleteTextures(1, &tex);
841
842         m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, isOk ? "Pass" : "Fail");
843         return STOP;
844 }
845
846 SampleVariablesTests::SampleVariablesTests(Context& context, glu::GLSLVersion glslVersion)
847         : TestCaseGroup(context, "sample_variables", "Sample Variables tests"), m_glslVersion(glslVersion)
848 {
849 }
850
851 SampleVariablesTests::~SampleVariablesTests()
852 {
853 }
854
855 void SampleVariablesTests::init()
856 {
857         de::Random rnd(m_context.getTestContext().getCommandLine().getBaseSeed());
858
859         struct Sample
860         {
861                 char const* name;
862                 GLint           samples;
863         } samples[] = {
864                 { "samples_0", 0 }, { "samples_1", 1 }, { "samples_2", 2 }, { "samples_4", 4 }, { "samples_8", 8 },
865         };
866
867         // sample_variables.extension
868         if (m_glslVersion == glu::GLSL_VERSION_310_ES)
869         {
870                 tcu::TestCaseGroup* extensionCaseGroup = new tcu::TestCaseGroup(m_testCtx, "verification", "");
871                 extensionCaseGroup->addChild(
872                         new SampleShadingExtensionCase(m_context, "extension", "#extension verification", m_glslVersion));
873                 addChild(extensionCaseGroup);
874         }
875
876         // sample_variables.mask
877         tcu::TestCaseGroup* maskGroup = new tcu::TestCaseGroup(m_testCtx, "mask", "gl_SampleMask tests");
878         addChild(maskGroup);
879         struct Format
880         {
881                 char const*                name;
882                 GLenum                     internalFormat;
883                 tcu::TextureFormat textureFormat;
884                 char const*                sampler;
885                 char const*                outType;
886         } formats[] = {
887                 { "rgba8", GL_RGBA8, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), "sampler2D",
888                   "vec4" },
889                 { "rgba8i", GL_RGBA8I, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT8),
890                   "isampler2D", "ivec4" },
891                 { "rgba8ui", GL_RGBA8UI, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT8),
892                   "usampler2D", "uvec4" },
893                 { "rgba32f", GL_RGBA32F, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT), "sampler2D",
894                   "vec4" },
895         };
896         for (int format = 0; format < DE_LENGTH_OF_ARRAY(formats); ++format)
897         {
898                 tcu::TestCaseGroup* maskFormatGroup = new tcu::TestCaseGroup(m_testCtx, formats[format].name, "");
899                 maskGroup->addChild(maskFormatGroup);
900
901                 for (int sample = 0; sample < DE_LENGTH_OF_ARRAY(samples); ++sample)
902                 {
903                         tcu::TestCaseGroup* maskFormatSampleGroup = new tcu::TestCaseGroup(m_testCtx, samples[sample].name, "");
904                         maskFormatGroup->addChild(maskFormatSampleGroup);
905
906                         maskFormatSampleGroup->addChild(
907                                 new SampleShadingMaskCase(m_context, "mask_zero", "", m_glslVersion, formats[format].internalFormat,
908                                                                                   formats[format].textureFormat, formats[format].sampler,
909                                                                                   formats[format].outType, samples[sample].samples, 0));
910
911                         for (int mask = 0; mask < SAMPLE_MASKS; ++mask)
912                         {
913                                 std::stringstream ss;
914                                 ss << "mask_" << mask;
915                                 maskFormatSampleGroup->addChild(new SampleShadingMaskCase(
916                                         m_context, ss.str().c_str(), "", m_glslVersion, formats[format].internalFormat,
917                                         formats[format].textureFormat, formats[format].sampler, formats[format].outType,
918                                         samples[sample].samples, rnd.getUint32()));
919                         }
920                 }
921         }
922
923         // sample_variables.position
924         tcu::TestCaseGroup* positionGroup = new tcu::TestCaseGroup(m_testCtx, "position", "gl_SamplePosition tests");
925         addChild(positionGroup);
926         struct Fixed
927         {
928                 char const* name;
929                 GLboolean   fixedSampleLocations;
930         } fixed[] = {
931                 { "non-fixed", GL_FALSE }, { "fixed", GL_TRUE },
932         };
933         for (int j = 0; j < DE_LENGTH_OF_ARRAY(fixed); ++j)
934         {
935                 tcu::TestCaseGroup* positionFixedGroup = new tcu::TestCaseGroup(m_testCtx, fixed[j].name, "");
936                 positionGroup->addChild(positionFixedGroup);
937                 for (int sample = 0; sample < DE_LENGTH_OF_ARRAY(samples); ++sample)
938                 {
939                         positionFixedGroup->addChild(new SampleShadingPositionCase(m_context, samples[sample].name, "",
940                                                                                                                                            m_glslVersion, samples[sample].samples,
941                                                                                                                                            fixed[j].fixedSampleLocations));
942                 }
943         }
944 }
945
946 } // glcts