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