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