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