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 }
57
58 namespace gl4cts
59 {
60 namespace es31compatibility
61 {
62
63 using tcu::TestLog;
64 using std::string;
65 using std::vector;
66 using deqp::Context;
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), m_glslVersion(glslVersion)
105 {
106 DE_ASSERT(glslVersion == glu::GLSL_VERSION_310_ES);
107 }
108
~SampleShadingExtensionCase()109 SampleShadingExtensionCase::~SampleShadingExtensionCase()
110 {
111 }
112
iterate()113 SampleShadingExtensionCase::IterateResult SampleShadingExtensionCase::iterate()
114 {
115 TestLog& log = m_testCtx.getLog();
116
117 /* OpenGL support query. */
118 bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)));
119 bool is_arb_es31_compatibility = m_context.getContextInfo().isExtensionSupported("GL_ARB_ES3_1_compatibility");
120
121 if (!(is_at_least_gl_45 || is_arb_es31_compatibility))
122 {
123 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_ARB_ES3_1_compatibility");
124 return STOP;
125 }
126
127 static char const* vss = "${VERSION_DECL}\n"
128 "in highp vec4 a_position;\n"
129 "void main()\n"
130 "{\n"
131 " gl_Position = a_position;\n"
132 "}\n";
133
134 {
135 static char const* fss = "${VERSION_DECL}\n"
136 "${OES_SV_RQ}"
137 "out highp vec4 o_color;\n"
138 "void main()\n"
139 "{\n"
140 " for (int i = 0; i < (gl_MaxSamples + 31) / 32; ++i) {\n"
141 " gl_SampleMask[i] = gl_SampleMaskIn[i];\n"
142 " }\n"
143 " o_color = vec4(gl_SampleID, gl_SamplePosition.x, gl_SamplePosition.y, 1);\n"
144 "}\n";
145
146 glu::ShaderProgram programRequire(m_context.getRenderContext(),
147 glu::makeVtxFragSources(specializeVersion(vss, m_glslVersion).c_str(),
148 specializeVersion(fss, m_glslVersion).c_str()));
149 log << programRequire;
150 if (!programRequire.isOk())
151 {
152 TCU_FAIL("Compile failed");
153 }
154 }
155
156 {
157 static char const* fss = "${VERSION_DECL}\n"
158 "${OES_SV_EN}"
159 "out highp vec4 o_color;\n"
160 "void main()\n"
161 "{\n"
162 "#if !GL_OES_sample_variables\n"
163 " this is broken\n"
164 "#endif\n"
165 " for (int i = 0; i < (gl_MaxSamples + 31) / 32; ++i) {\n"
166 " gl_SampleMask[i] = gl_SampleMaskIn[i];\n"
167 " }\n"
168 " o_color = vec4(gl_SampleID, gl_SamplePosition.x, gl_SamplePosition.y, 1);\n"
169 "}\n";
170
171 glu::ShaderProgram programEnable(m_context.getRenderContext(),
172 glu::makeVtxFragSources(specializeVersion(vss, m_glslVersion).c_str(),
173 specializeVersion(fss, m_glslVersion).c_str()));
174 log << programEnable;
175 if (!programEnable.isOk())
176 {
177 TCU_FAIL("Compile failed");
178 }
179 }
180
181 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
182 return STOP;
183 }
184
185 class SampleShadingMaskCase : public deqp::TestCase
186 {
187 public:
188 SampleShadingMaskCase(Context& context, const char* name, const char* description, glu::GLSLVersion glslVersion,
189 GLenum internalFormat, tcu::TextureFormat const& texFormat, const char* sampler,
190 const char* outType, GLint samples, GLint sampleMask);
191 ~SampleShadingMaskCase();
192
193 IterateResult iterate();
194
195 protected:
196 glu::GLSLVersion m_glslVersion;
197 GLenum m_internalFormat;
198 tcu::TextureFormat m_texFormat;
199 std::string m_sampler;
200 std::string m_outType;
201 GLint m_samples;
202 GLint m_sampleMask;
203
204 enum
205 {
206 WIDTH = 16,
207 HEIGHT = 16,
208 MAX_SAMPLES = 4,
209 };
210 };
211
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)212 SampleShadingMaskCase::SampleShadingMaskCase(Context& context, const char* name, const char* description,
213 glu::GLSLVersion glslVersion, GLenum internalFormat,
214 tcu::TextureFormat const& texFormat, const char* sampler,
215 const char* outType, GLint samples, GLint sampleMask)
216 : TestCase(context, name, description)
217 , m_glslVersion(glslVersion)
218 , m_internalFormat(internalFormat)
219 , m_texFormat(texFormat)
220 , m_sampler(sampler)
221 , m_outType(outType)
222 , m_samples(samples)
223 , m_sampleMask(sampleMask)
224 {
225 DE_ASSERT(glslVersion == glu::GLSL_VERSION_310_ES || glslVersion >= glu::GLSL_VERSION_400);
226 }
227
~SampleShadingMaskCase()228 SampleShadingMaskCase::~SampleShadingMaskCase()
229 {
230 }
231
iterate()232 SampleShadingMaskCase::IterateResult SampleShadingMaskCase::iterate()
233 {
234 TestLog& log = m_testCtx.getLog();
235 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
236 bool isOk = true;
237
238 /* OpenGL support query. */
239 bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)));
240 bool is_arb_es31_compatibility = m_context.getContextInfo().isExtensionSupported("GL_ARB_ES3_1_compatibility");
241
242 if (!(is_at_least_gl_45 || is_arb_es31_compatibility))
243 {
244 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_ARB_ES3_1_compatibility");
245 return STOP;
246 }
247
248 GLint maxSamples;
249 if (((m_texFormat.type == tcu::TextureFormat::FLOAT) && (m_texFormat.order == tcu::TextureFormat::RGBA)) ||
250 ((m_texFormat.type == tcu::TextureFormat::FLOAT) && (m_texFormat.order == tcu::TextureFormat::RG)) ||
251 ((m_texFormat.type == tcu::TextureFormat::FLOAT) && (m_texFormat.order == tcu::TextureFormat::R)) ||
252 ((m_texFormat.type == tcu::TextureFormat::HALF_FLOAT) && (m_texFormat.order == tcu::TextureFormat::RGBA)))
253 {
254 gl.getInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, m_internalFormat, GL_SAMPLES, 1, &maxSamples);
255 if (m_samples > maxSamples)
256 {
257 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED,
258 "Test sample count greater than samples that the format supports");
259 return STOP;
260 }
261 }
262 else if (m_texFormat.type == tcu::TextureFormat::SIGNED_INT8 ||
263 m_texFormat.type == tcu::TextureFormat::UNSIGNED_INT8)
264 {
265 gl.getIntegerv(GL_MAX_INTEGER_SAMPLES, &maxSamples);
266 if (m_samples > maxSamples)
267 {
268 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Test sample count greater than MAX_INTEGER_SAMPLES");
269 return STOP;
270 }
271 }
272 else
273 {
274 gl.getIntegerv(GL_MAX_SAMPLES, &maxSamples);
275 if (m_samples > maxSamples)
276 {
277 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Test sample count greater than MAX_SAMPLES");
278 return STOP;
279 }
280 }
281
282 // Create a multisample texture, or a regular texture if samples is zero.
283 GLuint tex;
284 gl.genTextures(1, &tex);
285 GLenum target;
286 if (m_samples)
287 {
288 target = GL_TEXTURE_2D_MULTISAMPLE;
289 gl.bindTexture(target, tex);
290 gl.texStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_samples, m_internalFormat, WIDTH, HEIGHT, GL_FALSE);
291 }
292 else
293 {
294 target = GL_TEXTURE_2D;
295 gl.bindTexture(target, tex);
296 gl.texStorage2D(GL_TEXTURE_2D, 1, m_internalFormat, WIDTH, HEIGHT);
297 if (m_texFormat.type == tcu::TextureFormat::SIGNED_INT8 ||
298 m_texFormat.type == tcu::TextureFormat::UNSIGNED_INT8 || m_texFormat.type == tcu::TextureFormat::FLOAT)
299 {
300 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
301 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
302 }
303 }
304
305 // Create a framebuffer with the texture attached and clear to "green".
306 GLuint fboMs;
307 gl.genFramebuffers(1, &fboMs);
308 gl.bindFramebuffer(GL_FRAMEBUFFER, fboMs);
309 gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, tex, 0);
310 gl.viewport(0, 0, WIDTH, HEIGHT);
311 if (m_texFormat.type == tcu::TextureFormat::SIGNED_INT8)
312 {
313 GLint color[4] = { 0, 1, 0, 1 };
314 gl.clearBufferiv(GL_COLOR, 0, color);
315 }
316 else if (m_texFormat.type == tcu::TextureFormat::UNSIGNED_INT8)
317 {
318 GLuint color[4] = { 0, 1, 0, 1 };
319 gl.clearBufferuiv(GL_COLOR, 0, color);
320 }
321 else
322 {
323 GLfloat color[4] = { 0.0f, 1.0f, 0.0f, 1.0f };
324 gl.clearBufferfv(GL_COLOR, 0, color);
325 }
326
327 static deUint16 const quadIndices[] = { 0, 1, 2, 2, 1, 3 };
328
329 {
330 // Draw a quad setting all samples to "red". We only expect "red"
331 // to be written if the sample mask bit for that sample is 1.
332
333 static char const* vss = "${VERSION_DECL}\n"
334 "in highp vec2 a_position;\n"
335 "void main()\n"
336 "{\n"
337 " gl_Position = vec4(a_position, 0.0, 1.0);\n"
338 "}\n";
339
340 static char const* fss = "${VERSION_DECL}\n"
341 "${OES_SV_RQ}"
342 "layout(location = 0) out highp ${OUT_TYPE} o_color;\n"
343 "uniform int u_sampleMask;\n"
344 "void main()\n"
345 "{\n"
346 " for (int i = 0; i < (gl_NumSamples + 31) / 32; ++i) {\n"
347 " gl_SampleMask[i] = u_sampleMask & gl_SampleMaskIn[i];\n"
348 " }\n"
349 " o_color = ${OUT_TYPE}(1, 0, 0, 1);\n"
350 "}\n";
351
352 glu::ShaderProgram program(
353 m_context.getRenderContext(),
354 glu::makeVtxFragSources(specializeVersion(vss, m_glslVersion, m_sampler, m_outType).c_str(),
355 specializeVersion(fss, m_glslVersion, m_sampler, m_outType).c_str()));
356 log << program;
357 if (!program.isOk())
358 {
359 TCU_FAIL("Compile failed");
360 }
361
362 static float const position[] = {
363 -1.0f, -1.0f, -1.0f, +1.0f, +1.0f, -1.0f, +1.0f, +1.0f,
364 };
365
366 gl.useProgram(program.getProgram());
367 gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_sampleMask"), m_sampleMask);
368
369 glu::VertexArrayBinding vertexArrays[] = {
370 glu::va::Float("a_position", 2, 4, 0, &position[0]),
371 };
372 glu::draw(m_context.getRenderContext(), program.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays),
373 &vertexArrays[0], glu::pr::TriangleStrip(DE_LENGTH_OF_ARRAY(quadIndices), &quadIndices[0]));
374
375 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw quad");
376 }
377
378 gl.bindFramebuffer(GL_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer());
379 gl.deleteFramebuffers(1, &fboMs);
380
381 GLsizei width = WIDTH * ((m_samples) ? m_samples : 1);
382
383 GLuint rbo;
384 gl.genRenderbuffers(1, &rbo);
385 gl.bindRenderbuffer(GL_RENDERBUFFER, rbo);
386 gl.renderbufferStorage(GL_RENDERBUFFER, m_internalFormat, width, HEIGHT);
387
388 GLuint fbo;
389 gl.genFramebuffers(1, &fbo);
390 gl.bindFramebuffer(GL_FRAMEBUFFER, fbo);
391 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
392 gl.viewport(0, 0, width, HEIGHT);
393
394 {
395 // Resolve the multi-sample texture into a render-buffer sized such that
396 // the width can hold all samples of a pixel.
397 static char const* vss = "${VERSION_DECL}\n"
398 "in highp vec2 a_position;\n"
399 "void main(void)\n"
400 "{\n"
401 " gl_Position = vec4(a_position, 0.0, 1.0);\n"
402 "}\n";
403
404 static char const* fss = "${VERSION_DECL}\n"
405 "uniform highp ${SAMPLER} u_tex;\n"
406 "uniform highp ${SAMPLER}MS u_texMS;\n"
407 "uniform int u_samples;\n"
408 "layout(location = 0) out highp ${OUT_TYPE} o_color;\n"
409 "void main(void)\n"
410 "{\n"
411 " if (u_samples > 0) {\n"
412 " ivec2 coord = ivec2(int(gl_FragCoord.x) / u_samples, gl_FragCoord.y);\n"
413 " int sampleId = int(gl_FragCoord.x) % u_samples;\n"
414 " o_color = texelFetch(u_texMS, coord, sampleId);\n"
415 " } else {\n"
416 " ivec2 coord = ivec2(gl_FragCoord.x, gl_FragCoord.y);\n"
417 " o_color = texelFetch(u_tex, coord, 0);\n"
418 " }\n"
419 "}\n";
420
421 glu::ShaderProgram program(
422 m_context.getRenderContext(),
423 glu::makeVtxFragSources(specializeVersion(vss, m_glslVersion, m_sampler, m_outType).c_str(),
424 specializeVersion(fss, m_glslVersion, m_sampler, m_outType).c_str()));
425 log << program;
426 if (!program.isOk())
427 {
428 TCU_FAIL("Compile failed");
429 }
430
431 static float const position[] = {
432 -1.0f, -1.0f, -1.0f, +1.0f, +1.0f, -1.0f, +1.0f, +1.0f,
433 };
434
435 gl.useProgram(program.getProgram());
436 gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_samples"), m_samples);
437 if (m_samples > 0)
438 {
439 // only MS sampler needed, TU 1 is not used
440 gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_tex"), 1);
441 gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_texMS"), 0);
442 }
443 else
444 {
445 // only non-MS sampler needed, TU 1 is not used
446 gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_tex"), 0);
447 gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_texMS"), 1);
448 }
449
450 glu::VertexArrayBinding vertexArrays[] = {
451 glu::va::Float("a_position", 2, 4, 0, &position[0]),
452 };
453 glu::draw(m_context.getRenderContext(), program.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays),
454 &vertexArrays[0], glu::pr::TriangleStrip(DE_LENGTH_OF_ARRAY(quadIndices), &quadIndices[0]));
455
456 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw quad");
457 }
458
459 tcu::TextureLevel textureLevel(m_texFormat, width, HEIGHT);
460 tcu::PixelBufferAccess pixels = textureLevel.getAccess();
461 std::vector<tcu::Vec4> result(pixels.getHeight() * pixels.getWidth());
462
463 if (pixels.getFormat().type == tcu::TextureFormat::SIGNED_INT8)
464 {
465 std::vector<GLint> data(pixels.getHeight() * pixels.getWidth() * 4);
466 gl.readPixels(0, 0, pixels.getWidth(), pixels.getHeight(), GL_RGBA_INTEGER, GL_INT, &data[0]);
467 for (unsigned int i = 0; i < data.size(); i += 4)
468 {
469 result[i / 4] =
470 tcu::Vec4((GLfloat)data[i], (GLfloat)data[i + 1], (GLfloat)data[i + 2], (GLfloat)data[i + 3]);
471 }
472 }
473 else if (pixels.getFormat().type == tcu::TextureFormat::UNSIGNED_INT8)
474 {
475 std::vector<GLuint> data(pixels.getHeight() * pixels.getWidth() * 4);
476 gl.readPixels(0, 0, pixels.getWidth(), pixels.getHeight(), GL_RGBA_INTEGER, GL_UNSIGNED_INT, &data[0]);
477 for (unsigned int i = 0; i < data.size(); i += 4)
478 {
479 result[i / 4] =
480 tcu::Vec4((GLfloat)data[i], (GLfloat)data[i + 1], (GLfloat)data[i + 2], (GLfloat)data[i + 3]);
481 }
482 }
483 else
484 {
485 glu::readPixels(m_context.getRenderContext(), 0, 0, pixels);
486 }
487
488 for (int y = 0; y < HEIGHT; ++y)
489 {
490 for (int x = 0; x < WIDTH; ++x)
491 {
492 GLint samples = (m_samples) ? m_samples : 1;
493 for (int sample = 0; sample < samples; ++sample)
494 {
495 tcu::Vec4 pixel;
496 if (pixels.getFormat().type == tcu::TextureFormat::SIGNED_INT8 ||
497 pixels.getFormat().type == tcu::TextureFormat::UNSIGNED_INT8)
498 {
499 pixel = result[y * WIDTH + x * samples + sample];
500 }
501 else
502 {
503 pixel = pixels.getPixel(x * samples + sample, y);
504 }
505
506 // Make sure only those samples where the sample mask bit is
507 // non-zero have the "red" pixel values.
508 if (!m_samples || (m_sampleMask & (1 << sample)))
509 {
510 if (pixel != tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f))
511 {
512 isOk = false;
513 }
514 }
515 else
516 {
517 if (pixel != tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f))
518 {
519 isOk = false;
520 }
521 }
522 }
523 }
524 }
525
526 gl.bindFramebuffer(GL_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer());
527 gl.deleteFramebuffers(1, &fbo);
528
529 gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
530 gl.deleteRenderbuffers(1, &rbo);
531
532 gl.bindTexture(target, 0);
533 gl.deleteTextures(1, &tex);
534
535 m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, isOk ? "Pass" : "Fail");
536 return STOP;
537 }
538
539 class SampleShadingPositionCase : public deqp::TestCase
540 {
541 public:
542 SampleShadingPositionCase(Context& context, const char* name, const char* description, glu::GLSLVersion glslVersion,
543 GLint samples, GLboolean fixedSampleLocations);
544 ~SampleShadingPositionCase();
545
546 IterateResult iterate();
547
548 protected:
549 glu::GLSLVersion m_glslVersion;
550 GLint m_samples;
551 GLboolean m_fixedSampleLocations;
552
553 enum
554 {
555 WIDTH = 8,
556 HEIGHT = 8,
557 MAX_SAMPLES = 8,
558 };
559 };
560
SampleShadingPositionCase(Context & context,const char * name,const char * description,glu::GLSLVersion glslVersion,GLint samples,GLboolean fixedSampleLocations)561 SampleShadingPositionCase::SampleShadingPositionCase(Context& context, const char* name, const char* description,
562 glu::GLSLVersion glslVersion, GLint samples,
563 GLboolean fixedSampleLocations)
564 : TestCase(context, name, description)
565 , m_glslVersion(glslVersion)
566 , m_samples(samples)
567 , m_fixedSampleLocations(fixedSampleLocations)
568 {
569 DE_ASSERT(glslVersion == glu::GLSL_VERSION_310_ES || glslVersion >= glu::GLSL_VERSION_400);
570 }
571
~SampleShadingPositionCase()572 SampleShadingPositionCase::~SampleShadingPositionCase()
573 {
574 }
575
iterate()576 SampleShadingPositionCase::IterateResult SampleShadingPositionCase::iterate()
577 {
578 TestLog& log = m_testCtx.getLog();
579 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
580 bool isOk = true;
581
582 /* OpenGL support query. */
583 bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)));
584 bool is_arb_es31_compatibility = m_context.getContextInfo().isExtensionSupported("GL_ARB_ES3_1_compatibility");
585
586 if (!(is_at_least_gl_45 || is_arb_es31_compatibility))
587 {
588 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_ARB_ES3_1_compatibility");
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 deUint16 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
663 if (!program.isOk())
664 {
665 TCU_FAIL("Compile failed");
666 }
667
668 const float position[] = {
669 -1.0f, -1.0f, -1.0f, +1.0f, +1.0f, -1.0f, +1.0f, +1.0f,
670 };
671
672 gl.useProgram(program.getProgram());
673
674 glu::VertexArrayBinding vertexArrays[] = {
675 glu::va::Float("a_position", 2, 4, 0, &position[0]),
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"), m_glslVersion(glslVersion)
849 {
850 }
851
~SampleVariablesTests()852 SampleVariablesTests::~SampleVariablesTests()
853 {
854 }
855
init()856 void SampleVariablesTests::init()
857 {
858 de::Random rnd(m_context.getTestContext().getCommandLine().getBaseSeed());
859
860 struct Sample
861 {
862 char const* name;
863 GLint samples;
864 } samples[] = {
865 { "samples_0", 0 }, { "samples_1", 1 }, { "samples_2", 2 }, { "samples_4", 4 }, { "samples_8", 8 },
866 };
867
868 // sample_variables.extension
869 if (m_glslVersion == glu::GLSL_VERSION_310_ES)
870 {
871 addChild(new SampleShadingExtensionCase(m_context, "extension", "#extension verification", m_glslVersion));
872 }
873
874 // sample_variables.mask
875 tcu::TestCaseGroup* maskGroup = new tcu::TestCaseGroup(m_testCtx, "mask", "gl_SampleMask tests");
876 addChild(maskGroup);
877 struct Format
878 {
879 char const* name;
880 GLenum internalFormat;
881 tcu::TextureFormat textureFormat;
882 char const* sampler;
883 char const* outType;
884 } formats[] = {
885 { "rgba8", GL_RGBA8, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), "sampler2D",
886 "vec4" },
887 { "rgba8i", GL_RGBA8I, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT8),
888 "isampler2D", "ivec4" },
889 { "rgba8ui", GL_RGBA8UI, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT8),
890 "usampler2D", "uvec4" },
891 { "rgba32f", GL_RGBA32F, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT), "sampler2D",
892 "vec4" },
893 };
894 for (int format = 0; format < DE_LENGTH_OF_ARRAY(formats); ++format)
895 {
896 tcu::TestCaseGroup* maskFormatGroup = new tcu::TestCaseGroup(m_testCtx, formats[format].name, "");
897 maskGroup->addChild(maskFormatGroup);
898
899 for (int sample = 0; sample < DE_LENGTH_OF_ARRAY(samples); ++sample)
900 {
901 tcu::TestCaseGroup* maskFormatSampleGroup = new tcu::TestCaseGroup(m_testCtx, samples[sample].name, "");
902 maskFormatGroup->addChild(maskFormatSampleGroup);
903
904 maskFormatSampleGroup->addChild(
905 new SampleShadingMaskCase(m_context, "mask_zero", "", m_glslVersion, formats[format].internalFormat,
906 formats[format].textureFormat, formats[format].sampler,
907 formats[format].outType, samples[sample].samples, 0));
908
909 for (int mask = 0; mask < SAMPLE_MASKS; ++mask)
910 {
911 std::stringstream ss;
912 ss << "mask_" << mask;
913 maskFormatSampleGroup->addChild(new SampleShadingMaskCase(
914 m_context, ss.str().c_str(), "", m_glslVersion, formats[format].internalFormat,
915 formats[format].textureFormat, formats[format].sampler, formats[format].outType,
916 samples[sample].samples, rnd.getUint32()));
917 }
918 }
919 }
920
921 // sample_variables.position
922 tcu::TestCaseGroup* positionGroup = new tcu::TestCaseGroup(m_testCtx, "position", "gl_SamplePosition tests");
923 addChild(positionGroup);
924 struct Fixed
925 {
926 char const* name;
927 GLboolean fixedSampleLocations;
928 } fixed[] = {
929 { "non-fixed", GL_FALSE }, { "fixed", GL_TRUE },
930 };
931 for (int j = 0; j < DE_LENGTH_OF_ARRAY(fixed); ++j)
932 {
933 tcu::TestCaseGroup* positionFixedGroup = new tcu::TestCaseGroup(m_testCtx, fixed[j].name, "");
934 positionGroup->addChild(positionFixedGroup);
935 for (int sample = 0; sample < DE_LENGTH_OF_ARRAY(samples); ++sample)
936 {
937 positionFixedGroup->addChild(new SampleShadingPositionCase(m_context, samples[sample].name, "",
938 m_glslVersion, samples[sample].samples,
939 fixed[j].fixedSampleLocations));
940 }
941 }
942 }
943
944 } // es31compatibility
945 } // gl4cts
946