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