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