1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.1 Module
3 * -------------------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Multisample texture test
22 *//*--------------------------------------------------------------------*/
24 #include "es31fTextureMultisampleTests.hpp"
25 #include "tcuTestLog.hpp"
26 #include "tcuRenderTarget.hpp"
27 #include "tcuSurface.hpp"
28 #include "tcuStringTemplate.hpp"
29 #include "tcuTextureUtil.hpp"
30 #include "glsStateQueryUtil.hpp"
31 #include "tcuRasterizationVerifier.hpp"
32 #include "gluRenderContext.hpp"
33 #include "gluCallLogWrapper.hpp"
34 #include "gluObjectWrapper.hpp"
35 #include "gluShaderProgram.hpp"
36 #include "gluPixelTransfer.hpp"
37 #include "gluStrUtil.hpp"
38 #include "gluContextInfo.hpp"
39 #include "glwEnums.hpp"
40 #include "glwFunctions.hpp"
41 #include "deStringUtil.hpp"
42 #include "deRandom.hpp"
55 using tcu::RasterizationArguments;
56 using tcu::TriangleSceneSpec;
58 static std::string sampleMaskToString (const std::vector<deUint32>& bitfield, int numBits)
60 std::string result(numBits, '0');
62 // move from back to front and set chars to 1
63 for (int wordNdx = 0; wordNdx < (int)bitfield.size(); ++wordNdx)
65 for (int bit = 0; bit < 32; ++bit)
67 const int targetCharNdx = numBits - (wordNdx*32+bit) - 1;
69 // beginning of the string reached
70 if (targetCharNdx < 0)
73 if ((bitfield[wordNdx] >> bit) & 0x01)
74 result[targetCharNdx] = '1';
81 /*--------------------------------------------------------------------*//*!
82 * \brief Returns the number of words needed to represent mask of given length
83 *//*--------------------------------------------------------------------*/
84 static int getEffectiveSampleMaskWordCount (int highestBitNdx)
86 const int wordSize = 32;
87 const int maskLen = highestBitNdx + 1;
89 return ((maskLen - 1) / wordSize) + 1; // round_up(mask_len / wordSize)
92 /*--------------------------------------------------------------------*//*!
93 * \brief Creates sample mask with all less significant bits than nthBit set
94 *//*--------------------------------------------------------------------*/
95 static std::vector<deUint32> genAllSetToNthBitSampleMask (int nthBit)
97 const int wordSize = 32;
98 const int numWords = getEffectiveSampleMaskWordCount(nthBit - 1);
99 const deUint32 topWordBits = (deUint32)(nthBit - (numWords - 1) * wordSize);
100 std::vector<deUint32> mask (numWords);
102 for (int ndx = 0; ndx < numWords - 1; ++ndx)
103 mask[ndx] = 0xFFFFFFFF;
105 mask[numWords - 1] = (deUint32)((1ULL << topWordBits) - (deUint32)1);
109 /*--------------------------------------------------------------------*//*!
110 * \brief Creates sample mask with nthBit set
111 *//*--------------------------------------------------------------------*/
112 static std::vector<deUint32> genSetNthBitSampleMask (int nthBit)
114 const int wordSize = 32;
115 const int numWords = getEffectiveSampleMaskWordCount(nthBit);
116 const deUint32 topWordBits = (deUint32)(nthBit - (numWords - 1) * wordSize);
117 std::vector<deUint32> mask (numWords);
119 for (int ndx = 0; ndx < numWords - 1; ++ndx)
122 mask[numWords - 1] = (deUint32)(1ULL << topWordBits);
126 std::string specializeShader (Context& context, const char* code)
128 const glu::ContextType contextType = context.getRenderContext().getType();
129 const glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(contextType);
130 std::map<std::string, std::string> specializationMap;
132 specializationMap["GLSL_VERSION_DECL"] = glu::getGLSLVersionDeclaration(glslVersion);
134 return tcu::StringTemplate(code).specialize(specializationMap);
137 class SamplePosRasterizationTest : public TestCase
140 SamplePosRasterizationTest (Context& context, const char* name, const char* desc, int samples);
141 ~SamplePosRasterizationTest (void);
146 IterateResult iterate (void);
147 void genMultisampleTexture (void);
148 void genSamplerProgram (void);
149 bool testMultisampleTexture (int sampleNdx);
150 void drawSample (tcu::Surface& dst, int sampleNdx);
151 void convertToSceneSpec (TriangleSceneSpec& scene, const tcu::Vec2& samplePos) const;
161 const int m_canvasSize;
162 std::vector<Triangle> m_testTriangles;
165 bool m_allIterationsOk;
170 std::vector<tcu::Vec2> m_samplePositions;
173 const glu::ShaderProgram* m_samplerProgram;
174 GLint m_samplerProgramPosLoc;
175 GLint m_samplerProgramSamplerLoc;
176 GLint m_samplerProgramSampleNdxLoc;
179 SamplePosRasterizationTest::SamplePosRasterizationTest (Context& context, const char* name, const char* desc, int samples)
180 : TestCase (context, name, desc)
181 , m_samples (samples)
184 , m_allIterationsOk (true)
189 , m_samplerProgram (DE_NULL)
190 , m_samplerProgramPosLoc (-1)
191 , m_samplerProgramSamplerLoc (-1)
192 , m_samplerProgramSampleNdxLoc (-1)
196 SamplePosRasterizationTest::~SamplePosRasterizationTest (void)
201 void SamplePosRasterizationTest::init (void)
203 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
204 GLint maxSamples = 0;
208 if (m_context.getRenderTarget().getWidth() < m_canvasSize || m_context.getRenderTarget().getHeight() < m_canvasSize)
209 throw tcu::NotSupportedError("render target size must be at least " + de::toString(m_canvasSize) + "x" + de::toString(m_canvasSize));
211 gl.getIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &maxSamples);
212 if (m_samples > maxSamples)
213 throw tcu::NotSupportedError("Requested sample count is greater than GL_MAX_COLOR_TEXTURE_SAMPLES");
215 m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_COLOR_TEXTURE_SAMPLES = " << maxSamples << tcu::TestLog::EndMessage;
217 gl.getIntegerv(GL_SUBPIXEL_BITS, &m_subpixelBits);
218 m_testCtx.getLog() << tcu::TestLog::Message << "GL_SUBPIXEL_BITS = " << m_subpixelBits << tcu::TestLog::EndMessage;
220 // generate textures & other gl stuff
222 m_testCtx.getLog() << tcu::TestLog::Message << "Creating multisample texture" << tcu::TestLog::EndMessage;
224 gl.genTextures (1, &m_texID);
225 gl.bindTexture (GL_TEXTURE_2D_MULTISAMPLE, m_texID);
226 gl.texStorage2DMultisample (GL_TEXTURE_2D_MULTISAMPLE, m_samples, GL_RGBA8, m_canvasSize, m_canvasSize, GL_TRUE);
227 GLU_EXPECT_NO_ERROR (gl.getError(), "texStorage2DMultisample");
229 gl.genVertexArrays (1, &m_vaoID);
230 gl.bindVertexArray (m_vaoID);
231 GLU_EXPECT_NO_ERROR (gl.getError(), "bindVertexArray");
233 gl.genBuffers (1, &m_vboID);
234 gl.bindBuffer (GL_ARRAY_BUFFER, m_vboID);
235 GLU_EXPECT_NO_ERROR (gl.getError(), "bindBuffer");
237 // generate test scene
238 for (int i = 0; i < 20; ++i)
242 tri.p1 = tcu::Vec4(((float)i + 1.0f / (float)(i + 1)) / 20.0f, 0.0f, 0.0f, 1.0f);
243 tri.p2 = tcu::Vec4(((float)i + 0.3f + 1.0f / (float)(i + 1)) / 20.0f, 0.0f, 0.0f, 1.0f);
244 tri.p3 = tcu::Vec4(((float)i + 1.0f / (float)(i + 1)) / 20.0f, -1.0f, 0.0f, 1.0f);
245 m_testTriangles.push_back(tri);
247 for (int i = 0; i < 20; ++i)
251 tri.p1 = tcu::Vec4(-1.0f, ((float)i + 1.0f / (float)(i + 1)) / 20.0f, 0.0f, 1.0f);
252 tri.p2 = tcu::Vec4(-1.0f, ((float)i + 0.3f + 1.0f / (float)(i + 1)) / 20.0f, 0.0f, 1.0f);
253 tri.p3 = tcu::Vec4( 0.0f, ((float)i + 1.0f / (float)(i + 1)) / 20.0f, 0.0f, 1.0f);
254 m_testTriangles.push_back(tri);
257 for (int i = 0; i < 20; ++i)
260 const tcu::Vec2 p = tcu::Vec2(deFloatCos(((float)i)/20.0f*DE_PI*2) * 0.5f + 0.5f, deFloatSin(((float)i)/20.0f*DE_PI*2) * 0.5f + 0.5f);
261 const tcu::Vec2 d = tcu::Vec2(0.1f, 0.02f);
264 tri.p1 = tcu::Vec4(0.4f, 0.4f, 0.0f, 1.0f);
265 tri.p2 = tcu::Vec4(p.x(), p.y(), 0.0f, 1.0f);
266 tri.p3 = tcu::Vec4(p.x() + d.x(), p.y() + d.y(), 0.0f, 1.0f);
267 m_testTriangles.push_back(tri);
271 tri.p1 = tcu::Vec4(-0.202f, -0.202f, 0.0f, 1.0f);
272 tri.p2 = tcu::Vec4(-0.802f, -0.202f, 0.0f, 1.0f);
273 tri.p3 = tcu::Vec4(-0.802f, -0.802f, 0.0f, 1.0f);
274 m_testTriangles.push_back(tri);
277 // generate multisample texture (and query the sample positions in it)
278 genMultisampleTexture();
280 // verify queried samples are in a valid range
281 for (int sampleNdx = 0; sampleNdx < m_samples; ++sampleNdx)
283 if (m_samplePositions[sampleNdx].x() < 0.0f || m_samplePositions[sampleNdx].x() > 1.0f ||
284 m_samplePositions[sampleNdx].y() < 0.0f || m_samplePositions[sampleNdx].y() > 1.0f)
286 m_testCtx.getLog() << tcu::TestLog::Message << "// ERROR: Sample position of sample " << sampleNdx << " should be in range ([0, 1], [0, 1]). Got " << m_samplePositions[sampleNdx] << tcu::TestLog::EndMessage;
287 throw tcu::TestError("invalid sample position");
291 // generate sampler program
295 void SamplePosRasterizationTest::deinit (void)
299 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_vboID);
305 m_context.getRenderContext().getFunctions().deleteVertexArrays(1, &m_vaoID);
311 m_context.getRenderContext().getFunctions().deleteTextures(1, &m_texID);
315 if (m_samplerProgram)
317 delete m_samplerProgram;
318 m_samplerProgram = DE_NULL;
322 SamplePosRasterizationTest::IterateResult SamplePosRasterizationTest::iterate (void)
324 m_allIterationsOk &= testMultisampleTexture(m_iteration);
327 if (m_iteration < m_samples)
331 if (m_allIterationsOk)
332 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
334 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Pixel comparison failed");
339 void SamplePosRasterizationTest::genMultisampleTexture (void)
341 const char* const vertexShaderSource = "${GLSL_VERSION_DECL}\n"
342 "in highp vec4 a_position;\n"
345 " gl_Position = a_position;\n"
347 const char* const fragmentShaderSource = "${GLSL_VERSION_DECL}\n"
348 "layout(location = 0) out highp vec4 fragColor;\n"
351 " fragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
354 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
355 const glu::ShaderProgram program (m_context.getRenderContext(), glu::ProgramSources()
356 << glu::VertexSource(specializeShader(m_context, vertexShaderSource))
357 << glu::FragmentSource(specializeShader(m_context, fragmentShaderSource)));
358 const GLuint posLoc = gl.getAttribLocation(program.getProgram(), "a_position");
363 m_testCtx.getLog() << program;
364 throw tcu::TestError("Failed to build shader.");
367 gl.bindTexture (GL_TEXTURE_2D_MULTISAMPLE, m_texID);
368 gl.bindVertexArray (m_vaoID);
369 gl.bindBuffer (GL_ARRAY_BUFFER, m_vboID);
371 // Setup fbo for drawing and for sample position query
373 m_testCtx.getLog() << tcu::TestLog::Message << "Attaching texture to FBO" << tcu::TestLog::EndMessage;
375 gl.genFramebuffers (1, &fboID);
376 gl.bindFramebuffer (GL_FRAMEBUFFER, fboID);
377 gl.framebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, m_texID, 0);
378 GLU_EXPECT_NO_ERROR (gl.getError(), "framebufferTexture2D");
380 // Query sample positions of the multisample texture by querying the sample positions
381 // from an fbo which has the multisample texture as attachment.
383 m_testCtx.getLog() << tcu::TestLog::Message << "Sample locations:" << tcu::TestLog::EndMessage;
385 for (int sampleNdx = 0; sampleNdx < m_samples; ++sampleNdx)
387 gls::StateQueryUtil::StateQueryMemoryWriteGuard<float[2]> position;
389 gl.getMultisamplefv(GL_SAMPLE_POSITION, (deUint32)sampleNdx, position);
390 if (!position.verifyValidity(m_testCtx))
391 throw tcu::TestError("Error while querying sample positions");
393 m_testCtx.getLog() << tcu::TestLog::Message << "\t" << sampleNdx << ": (" << position[0] << ", " << position[1] << ")" << tcu::TestLog::EndMessage;
394 m_samplePositions.push_back(tcu::Vec2(position[0], position[1]));
397 // Draw test pattern to texture
399 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing test pattern to the texture" << tcu::TestLog::EndMessage;
401 gl.bufferData (GL_ARRAY_BUFFER, (glw::GLsizeiptr)(m_testTriangles.size() * sizeof(Triangle)), &m_testTriangles[0], GL_STATIC_DRAW);
402 GLU_EXPECT_NO_ERROR (gl.getError(), "bufferData");
404 gl.viewport (0, 0, m_canvasSize, m_canvasSize);
405 gl.clearColor (0, 0, 0, 1);
406 gl.clear (GL_COLOR_BUFFER_BIT);
407 gl.vertexAttribPointer (posLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
408 gl.enableVertexAttribArray (posLoc);
409 GLU_EXPECT_NO_ERROR (gl.getError(), "vertexAttribPointer");
411 gl.useProgram (program.getProgram());
412 gl.drawArrays (GL_TRIANGLES, 0, (glw::GLsizei)(m_testTriangles.size() * 3));
413 GLU_EXPECT_NO_ERROR (gl.getError(), "drawArrays");
415 gl.disableVertexAttribArray (posLoc);
417 gl.deleteFramebuffers (1, &fboID);
418 GLU_EXPECT_NO_ERROR (gl.getError(), "cleanup");
421 void SamplePosRasterizationTest::genSamplerProgram (void)
423 const char* const vertexShaderSource = "${GLSL_VERSION_DECL}\n"
424 "in highp vec4 a_position;\n"
427 " gl_Position = a_position;\n"
429 const char* const fragShaderSource = "${GLSL_VERSION_DECL}\n"
430 "layout(location = 0) out highp vec4 fragColor;\n"
431 "uniform highp sampler2DMS u_sampler;\n"
432 "uniform highp int u_sample;\n"
435 " fragColor = texelFetch(u_sampler, ivec2(int(floor(gl_FragCoord.x)), int(floor(gl_FragCoord.y))), u_sample);\n"
437 const tcu::ScopedLogSection section (m_testCtx.getLog(), "Generate sampler shader", "Generate sampler shader");
438 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
440 m_samplerProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(specializeShader(m_context, vertexShaderSource)) << glu::FragmentSource(specializeShader(m_context, fragShaderSource)));
441 m_testCtx.getLog() << *m_samplerProgram;
443 if (!m_samplerProgram->isOk())
444 throw tcu::TestError("Could not create sampler program.");
446 m_samplerProgramPosLoc = gl.getAttribLocation(m_samplerProgram->getProgram(), "a_position");
447 m_samplerProgramSamplerLoc = gl.getUniformLocation(m_samplerProgram->getProgram(), "u_sampler");
448 m_samplerProgramSampleNdxLoc = gl.getUniformLocation(m_samplerProgram->getProgram(), "u_sample");
451 bool SamplePosRasterizationTest::testMultisampleTexture (int sampleNdx)
453 tcu::Surface glSurface(m_canvasSize, m_canvasSize);
454 TriangleSceneSpec scene;
457 drawSample(glSurface, sampleNdx);
460 convertToSceneSpec(scene, m_samplePositions[sampleNdx]);
464 RasterizationArguments args;
465 args.redBits = m_context.getRenderTarget().getPixelFormat().redBits;
466 args.greenBits = m_context.getRenderTarget().getPixelFormat().greenBits;
467 args.blueBits = m_context.getRenderTarget().getPixelFormat().blueBits;
469 args.subpixelBits = m_subpixelBits;
471 return tcu::verifyTriangleGroupRasterization(glSurface, scene, args, m_testCtx.getLog(), tcu::VERIFICATIONMODE_STRICT);
475 void SamplePosRasterizationTest::drawSample (tcu::Surface& dst, int sampleNdx)
477 // Downsample using only one sample
478 static const tcu::Vec4 fullscreenQuad[] =
480 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
481 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
482 tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f),
483 tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f)
486 const tcu::ScopedLogSection section (m_testCtx.getLog(), "Test sample position " + de::toString(sampleNdx+1) + "/" + de::toString(m_samples), "Test sample position " + de::toString(sampleNdx+1) + "/" + de::toString(m_samples));
487 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
489 gl.bindTexture (GL_TEXTURE_2D_MULTISAMPLE, m_texID);
490 gl.bindVertexArray (m_vaoID);
491 gl.bindBuffer (GL_ARRAY_BUFFER, m_vboID);
493 gl.bufferData (GL_ARRAY_BUFFER, sizeof(fullscreenQuad), &fullscreenQuad[0], GL_STATIC_DRAW);
494 GLU_EXPECT_NO_ERROR (gl.getError(), "bufferData");
496 gl.viewport (0, 0, m_canvasSize, m_canvasSize);
497 gl.clearColor (0, 0, 0, 1);
498 gl.clear (GL_COLOR_BUFFER_BIT);
499 gl.vertexAttribPointer (m_samplerProgramPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
500 gl.enableVertexAttribArray (m_samplerProgramPosLoc);
501 GLU_EXPECT_NO_ERROR (gl.getError(), "vertexAttribPointer");
503 gl.useProgram (m_samplerProgram->getProgram());
504 gl.uniform1i (m_samplerProgramSamplerLoc, 0);
505 gl.uniform1i (m_samplerProgramSampleNdxLoc, (deInt32)sampleNdx);
506 GLU_EXPECT_NO_ERROR (gl.getError(), "useprogram");
508 m_testCtx.getLog() << tcu::TestLog::Message << "Reading from texture with sample index " << sampleNdx << tcu::TestLog::EndMessage;
510 gl.drawArrays (GL_TRIANGLE_STRIP, 0, 4);
511 GLU_EXPECT_NO_ERROR (gl.getError(), "drawArrays");
513 gl.disableVertexAttribArray (m_samplerProgramPosLoc);
515 GLU_EXPECT_NO_ERROR (gl.getError(), "cleanup");
518 glu::readPixels (m_context.getRenderContext(), 0, 0, dst.getAccess());
519 GLU_EXPECT_NO_ERROR (gl.getError(), "readPixels");
522 void SamplePosRasterizationTest::convertToSceneSpec (TriangleSceneSpec& scene, const tcu::Vec2& samplePos) const
524 // Triangles are offset from the pixel center by "offset". Move the triangles back to take this into account.
525 const tcu::Vec4 offset = tcu::Vec4(samplePos.x() - 0.5f, samplePos.y() - 0.5f, 0.0f, 0.0f) / tcu::Vec4((float)m_canvasSize, (float)m_canvasSize, 1.0f, 1.0f) * 2.0f;
527 for (int triangleNdx = 0; triangleNdx < (int)m_testTriangles.size(); ++triangleNdx)
529 TriangleSceneSpec::SceneTriangle triangle;
531 triangle.positions[0] = m_testTriangles[triangleNdx].p1 - offset;
532 triangle.positions[1] = m_testTriangles[triangleNdx].p2 - offset;
533 triangle.positions[2] = m_testTriangles[triangleNdx].p3 - offset;
535 triangle.sharedEdge[0] = false;
536 triangle.sharedEdge[1] = false;
537 triangle.sharedEdge[2] = false;
539 scene.triangles.push_back(triangle);
543 class SampleMaskCase : public TestCase
549 FLAGS_ALPHA_TO_COVERAGE = (1ULL << 0),
550 FLAGS_SAMPLE_COVERAGE = (1ULL << 1),
551 FLAGS_HIGH_BITS = (1ULL << 2),
554 SampleMaskCase (Context& context, const char* name, const char* desc, int samples, int flags);
555 ~SampleMaskCase (void);
560 IterateResult iterate (void);
562 void genSamplerProgram (void);
563 void genAlphaProgram (void);
564 void updateTexture (int sample);
565 bool verifyTexture (int sample);
566 void drawSample (tcu::Surface& dst, int sample);
569 const int m_canvasSize;
570 const int m_gridsize;
571 const int m_effectiveSampleMaskWordCount;
575 int m_allIterationsOk;
582 const glu::ShaderProgram* m_samplerProgram;
583 glw::GLint m_samplerProgramPosLoc;
584 glw::GLint m_samplerProgramSamplerLoc;
585 glw::GLint m_samplerProgramSampleNdxLoc;
587 const glu::ShaderProgram* m_alphaProgram;
588 glw::GLint m_alphaProgramPosLoc;
591 SampleMaskCase::SampleMaskCase (Context& context, const char* name, const char* desc, int samples, int flags)
592 : TestCase (context, name, desc)
593 , m_samples (samples)
596 , m_effectiveSampleMaskWordCount(getEffectiveSampleMaskWordCount(samples - 1))
598 , m_currentSample (-1)
599 , m_allIterationsOk (true)
604 , m_samplerProgram (DE_NULL)
605 , m_samplerProgramPosLoc (-1)
606 , m_samplerProgramSamplerLoc (-1)
607 , m_samplerProgramSampleNdxLoc (-1)
608 , m_alphaProgram (DE_NULL)
609 , m_alphaProgramPosLoc (-1)
613 SampleMaskCase::~SampleMaskCase (void)
618 void SampleMaskCase::init (void)
620 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
621 glw::GLint maxSamples = 0;
622 glw::GLint maxSampleMaskWords = 0;
626 if (m_context.getRenderTarget().getWidth() < m_canvasSize || m_context.getRenderTarget().getHeight() < m_canvasSize)
627 throw tcu::NotSupportedError("render target size must be at least " + de::toString(m_canvasSize) + "x" + de::toString(m_canvasSize));
629 gl.getIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &maxSampleMaskWords);
630 if (m_effectiveSampleMaskWordCount > maxSampleMaskWords)
631 throw tcu::NotSupportedError("Test requires larger GL_MAX_SAMPLE_MASK_WORDS");
633 gl.getIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &maxSamples);
634 if (m_samples > maxSamples)
635 throw tcu::NotSupportedError("Requested sample count is greater than GL_MAX_COLOR_TEXTURE_SAMPLES");
637 m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_COLOR_TEXTURE_SAMPLES = " << maxSamples << tcu::TestLog::EndMessage;
639 // Don't even try to test high bits if there are none
641 if ((m_flags & FLAGS_HIGH_BITS) && (m_samples % 32 == 0))
643 m_testCtx.getLog() << tcu::TestLog::Message << "Sample count is multiple of word size. No unused high bits in sample mask.\nSkipping." << tcu::TestLog::EndMessage;
644 throw tcu::NotSupportedError("Test requires unused high bits (sample count not multiple of 32)");
649 m_testCtx.getLog() << tcu::TestLog::Message << "Creating multisample texture with sample count " << m_samples << tcu::TestLog::EndMessage;
651 gl.genTextures (1, &m_texID);
652 gl.bindTexture (GL_TEXTURE_2D_MULTISAMPLE, m_texID);
653 gl.texStorage2DMultisample (GL_TEXTURE_2D_MULTISAMPLE, m_samples, GL_RGBA8, m_canvasSize, m_canvasSize, GL_FALSE);
654 GLU_EXPECT_NO_ERROR (gl.getError(), "texStorage2DMultisample");
656 // attach texture to fbo
658 m_testCtx.getLog() << tcu::TestLog::Message << "Attaching texture to FBO" << tcu::TestLog::EndMessage;
660 gl.genFramebuffers (1, &m_fboID);
661 gl.bindFramebuffer (GL_FRAMEBUFFER, m_fboID);
662 gl.framebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, m_texID, 0);
663 GLU_EXPECT_NO_ERROR (gl.getError(), "framebufferTexture2D");
667 gl.genVertexArrays (1, &m_vaoID);
668 GLU_EXPECT_NO_ERROR (gl.getError(), "genVertexArrays");
670 gl.genBuffers (1, &m_vboID);
671 gl.bindBuffer (GL_ARRAY_BUFFER, m_vboID);
672 GLU_EXPECT_NO_ERROR (gl.getError(), "genBuffers");
674 // generate grid pattern
676 std::vector<tcu::Vec4> gridData(m_gridsize*m_gridsize*6);
678 for (int y = 0; y < m_gridsize; ++y)
679 for (int x = 0; x < m_gridsize; ++x)
681 gridData[(y * m_gridsize + x)*6 + 0] = tcu::Vec4(((float)(x+0) / (float)m_gridsize) * 2.0f - 1.0f, ((float)(y+0) / (float)m_gridsize) * 2.0f - 1.0f, 0.0f, 1.0f);
682 gridData[(y * m_gridsize + x)*6 + 1] = tcu::Vec4(((float)(x+0) / (float)m_gridsize) * 2.0f - 1.0f, ((float)(y+1) / (float)m_gridsize) * 2.0f - 1.0f, 0.0f, 1.0f);
683 gridData[(y * m_gridsize + x)*6 + 2] = tcu::Vec4(((float)(x+1) / (float)m_gridsize) * 2.0f - 1.0f, ((float)(y+1) / (float)m_gridsize) * 2.0f - 1.0f, 0.0f, 1.0f);
684 gridData[(y * m_gridsize + x)*6 + 3] = tcu::Vec4(((float)(x+0) / (float)m_gridsize) * 2.0f - 1.0f, ((float)(y+0) / (float)m_gridsize) * 2.0f - 1.0f, 0.0f, 1.0f);
685 gridData[(y * m_gridsize + x)*6 + 4] = tcu::Vec4(((float)(x+1) / (float)m_gridsize) * 2.0f - 1.0f, ((float)(y+1) / (float)m_gridsize) * 2.0f - 1.0f, 0.0f, 1.0f);
686 gridData[(y * m_gridsize + x)*6 + 5] = tcu::Vec4(((float)(x+1) / (float)m_gridsize) * 2.0f - 1.0f, ((float)(y+0) / (float)m_gridsize) * 2.0f - 1.0f, 0.0f, 1.0f);
689 gl.bufferData (GL_ARRAY_BUFFER, (int)(gridData.size() * sizeof(tcu::Vec4)), gridData[0].getPtr(), GL_STATIC_DRAW);
690 GLU_EXPECT_NO_ERROR (gl.getError(), "bufferData");
699 void SampleMaskCase::deinit (void)
703 m_context.getRenderContext().getFunctions().deleteTextures(1, &m_texID);
708 m_context.getRenderContext().getFunctions().deleteVertexArrays(1, &m_vaoID);
713 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_vboID);
718 m_context.getRenderContext().getFunctions().deleteFramebuffers(1, &m_fboID);
722 if (m_samplerProgram)
724 delete m_samplerProgram;
725 m_samplerProgram = DE_NULL;
729 delete m_alphaProgram;
730 m_alphaProgram = DE_NULL;
734 SampleMaskCase::IterateResult SampleMaskCase::iterate (void)
736 const tcu::ScopedLogSection section(m_testCtx.getLog(), "Iteration", (m_currentSample == -1) ? ("Verifying with zero mask") : (std::string() + "Verifying sample " + de::toString(m_currentSample + 1) + "/" + de::toString(m_samples)));
740 // Mask only one sample, clear rest
742 updateTexture(m_currentSample);
744 // Verify only one sample set is in the texture
746 iterationOk = verifyTexture(m_currentSample);
748 m_allIterationsOk = false;
751 if (m_currentSample < m_samples)
756 if (m_allIterationsOk)
757 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
758 else if (m_flags & FLAGS_HIGH_BITS)
759 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Unused mask bits have effect");
761 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Sample test failed");
766 void SampleMaskCase::genSamplerProgram (void)
768 const char* const vertexShaderSource = "${GLSL_VERSION_DECL}\n"
769 "in highp vec4 a_position;\n"
772 " gl_Position = a_position;\n"
774 const char* const fragShaderSource = "${GLSL_VERSION_DECL}\n"
775 "layout(location = 0) out highp vec4 fragColor;\n"
776 "uniform highp sampler2DMS u_sampler;\n"
777 "uniform highp int u_sample;\n"
780 " highp float correctCoverage = 0.0;\n"
781 " highp float incorrectCoverage = 0.0;\n"
782 " highp ivec2 texelPos = ivec2(int(floor(gl_FragCoord.x)), int(floor(gl_FragCoord.y)));\n"
784 " for (int sampleNdx = 0; sampleNdx < ${NUMSAMPLES}; ++sampleNdx)\n"
786 " highp float sampleColor = texelFetch(u_sampler, texelPos, sampleNdx).r;\n"
787 " if (sampleNdx == u_sample)\n"
788 " correctCoverage += sampleColor;\n"
790 " incorrectCoverage += sampleColor;\n"
792 " fragColor = vec4(correctCoverage, incorrectCoverage, 0.0, 1.0);\n"
794 const tcu::ScopedLogSection section (m_testCtx.getLog(), "GenerateSamplerShader", "Generate sampler shader");
795 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
796 std::map<std::string, std::string> args;
797 const glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType());
799 args["GLSL_VERSION_DECL"] = glu::getGLSLVersionDeclaration(glslVersion);
800 args["NUMSAMPLES"] = de::toString(m_samples);
802 m_samplerProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(specializeShader(m_context, vertexShaderSource)) << glu::FragmentSource(tcu::StringTemplate(fragShaderSource).specialize(args)));
803 m_testCtx.getLog() << *m_samplerProgram;
805 if (!m_samplerProgram->isOk())
806 throw tcu::TestError("Could not create sampler program.");
808 m_samplerProgramPosLoc = gl.getAttribLocation(m_samplerProgram->getProgram(), "a_position");
809 m_samplerProgramSamplerLoc = gl.getUniformLocation(m_samplerProgram->getProgram(), "u_sampler");
810 m_samplerProgramSampleNdxLoc = gl.getUniformLocation(m_samplerProgram->getProgram(), "u_sample");
813 void SampleMaskCase::genAlphaProgram (void)
815 const char* const vertexShaderSource = "${GLSL_VERSION_DECL}\n"
816 "in highp vec4 a_position;\n"
817 "out highp float v_alpha;\n"
820 " gl_Position = a_position;\n"
821 " v_alpha = (a_position.x * 0.5 + 0.5)*(a_position.y * 0.5 + 0.5);\n"
823 const char* const fragShaderSource = "${GLSL_VERSION_DECL}\n"
824 "layout(location = 0) out highp vec4 fragColor;\n"
825 "in mediump float v_alpha;\n"
828 " fragColor = vec4(1.0, 1.0, 1.0, v_alpha);\n"
830 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
832 m_alphaProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(specializeShader(m_context, vertexShaderSource)) << glu::FragmentSource(specializeShader(m_context, fragShaderSource)));
834 if (!m_alphaProgram->isOk())
836 m_testCtx.getLog() << *m_alphaProgram;
837 throw tcu::TestError("Could not create aplha program.");
840 m_alphaProgramPosLoc = gl.getAttribLocation(m_alphaProgram->getProgram(), "a_position");
843 void SampleMaskCase::updateTexture (int sample)
845 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
849 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID);
850 gl.viewport(0, 0, m_canvasSize, m_canvasSize);
851 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
855 m_testCtx.getLog() << tcu::TestLog::Message << "Clearing image" << tcu::TestLog::EndMessage;
856 gl.clear(GL_COLOR_BUFFER_BIT);
860 if (m_flags & FLAGS_HIGH_BITS)
862 const std::vector<deUint32> bitmask = genSetNthBitSampleMask(sample);
863 const std::vector<deUint32> effectiveMask = genAllSetToNthBitSampleMask(m_samples);
864 std::vector<deUint32> totalBitmask (effectiveMask.size());
866 DE_ASSERT((int)totalBitmask.size() == m_effectiveSampleMaskWordCount);
868 // set some arbitrary high bits to non-effective bits
869 for (int wordNdx = 0; wordNdx < (int)effectiveMask.size(); ++wordNdx)
871 const deUint32 randomMask = (deUint32)deUint32Hash(wordNdx << 2 ^ sample);
872 const deUint32 sampleMask = (wordNdx < (int)bitmask.size()) ? (bitmask[wordNdx]) : (0);
873 const deUint32 maskMask = effectiveMask[wordNdx];
875 totalBitmask[wordNdx] = (sampleMask & maskMask) | (randomMask & ~maskMask);
878 m_testCtx.getLog() << tcu::TestLog::Message << "Setting sample mask to 0b" << sampleMaskToString(totalBitmask, (int)totalBitmask.size() * 32) << tcu::TestLog::EndMessage;
880 gl.enable(GL_SAMPLE_MASK);
881 for (int wordNdx = 0; wordNdx < m_effectiveSampleMaskWordCount; ++wordNdx)
883 const GLbitfield wordmask = (wordNdx < (int)totalBitmask.size()) ? ((GLbitfield)(totalBitmask[wordNdx])) : (0);
884 gl.sampleMaski((deUint32)wordNdx, wordmask);
889 const std::vector<deUint32> bitmask = genSetNthBitSampleMask(sample);
890 DE_ASSERT((int)bitmask.size() <= m_effectiveSampleMaskWordCount);
892 m_testCtx.getLog() << tcu::TestLog::Message << "Setting sample mask to 0b" << sampleMaskToString(bitmask, m_samples) << tcu::TestLog::EndMessage;
894 gl.enable(GL_SAMPLE_MASK);
895 for (int wordNdx = 0; wordNdx < m_effectiveSampleMaskWordCount; ++wordNdx)
897 const GLbitfield wordmask = (wordNdx < (int)bitmask.size()) ? ((GLbitfield)(bitmask[wordNdx])) : (0);
898 gl.sampleMaski((deUint32)wordNdx, wordmask);
901 if (m_flags & FLAGS_ALPHA_TO_COVERAGE)
903 m_testCtx.getLog() << tcu::TestLog::Message << "Enabling alpha to coverage." << tcu::TestLog::EndMessage;
904 gl.enable(GL_SAMPLE_ALPHA_TO_COVERAGE);
906 if (m_flags & FLAGS_SAMPLE_COVERAGE)
908 m_testCtx.getLog() << tcu::TestLog::Message << "Enabling sample coverage. Varying sample coverage for grid cells." << tcu::TestLog::EndMessage;
909 gl.enable(GL_SAMPLE_COVERAGE);
914 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing test grid" << tcu::TestLog::EndMessage;
916 gl.bindVertexArray (m_vaoID);
917 gl.bindBuffer (GL_ARRAY_BUFFER, m_vboID);
918 gl.vertexAttribPointer (m_alphaProgramPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
919 gl.enableVertexAttribArray (m_alphaProgramPosLoc);
920 GLU_EXPECT_NO_ERROR (gl.getError(), "vertexAttribPointer");
922 gl.useProgram (m_alphaProgram->getProgram());
924 for (int y = 0; y < m_gridsize; ++y)
925 for (int x = 0; x < m_gridsize; ++x)
927 if (m_flags & FLAGS_SAMPLE_COVERAGE)
928 gl.sampleCoverage((float)(y*m_gridsize + x) / float(m_gridsize*m_gridsize), GL_FALSE);
930 gl.drawArrays (GL_TRIANGLES, (y*m_gridsize + x) * 6, 6);
931 GLU_EXPECT_NO_ERROR (gl.getError(), "drawArrays");
936 gl.disableVertexAttribArray (m_alphaProgramPosLoc);
938 gl.bindFramebuffer (GL_FRAMEBUFFER, 0);
939 gl.disable (GL_SAMPLE_MASK);
940 gl.disable (GL_SAMPLE_ALPHA_TO_COVERAGE);
941 gl.disable (GL_SAMPLE_COVERAGE);
942 GLU_EXPECT_NO_ERROR (gl.getError(), "clean");
945 bool SampleMaskCase::verifyTexture (int sample)
947 tcu::Surface result (m_canvasSize, m_canvasSize);
948 tcu::Surface errorMask (m_canvasSize, m_canvasSize);
951 tcu::clear(errorMask.getAccess(), tcu::RGBA::green().toVec());
954 // Sample sampleNdx is set to red channel
955 // Other samples are set to green channel
956 drawSample(result, sample);
958 // Check surface contains only sampleNdx
959 for (int y = 0; y < m_canvasSize; ++y)
960 for (int x = 0; x < m_canvasSize; ++x)
962 const tcu::RGBA color = result.getPixel(x, y);
964 // Allow missing coverage with FLAGS_ALPHA_TO_COVERAGE and FLAGS_SAMPLE_COVERAGE, or if there are no samples enabled
965 const bool allowMissingCoverage = ((m_flags & (FLAGS_ALPHA_TO_COVERAGE | FLAGS_SAMPLE_COVERAGE)) != 0) || (sample == -1);
967 // disabled sample was written to
968 if (color.getGreen() != 0)
971 errorMask.setPixel(x, y, tcu::RGBA::red());
973 // enabled sample was not written to
974 else if (color.getRed() != 255 && !allowMissingCoverage)
977 errorMask.setPixel(x, y, tcu::RGBA::red());
984 << tcu::TestLog::Message << "Image verification failed, disabled samples found." << tcu::TestLog::EndMessage
985 << tcu::TestLog::ImageSet("VerificationResult", "Result of rendering")
986 << tcu::TestLog::Image("Result", "Result", result)
987 << tcu::TestLog::Image("ErrorMask", "Error Mask", errorMask)
988 << tcu::TestLog::EndImageSet;
993 m_testCtx.getLog() << tcu::TestLog::Message << "Image verification ok, no disabled samples found." << tcu::TestLog::EndMessage;
998 void SampleMaskCase::drawSample (tcu::Surface& dst, int sample)
1000 // Downsample using only one sample
1001 static const tcu::Vec4 fullscreenQuad[] =
1003 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
1004 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
1005 tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f),
1006 tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f)
1009 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1010 glu::Buffer vertexBuffer (m_context.getRenderContext());
1012 gl.bindTexture (GL_TEXTURE_2D_MULTISAMPLE, m_texID);
1013 gl.bindVertexArray (m_vaoID);
1015 gl.bindBuffer (GL_ARRAY_BUFFER, *vertexBuffer);
1016 gl.bufferData (GL_ARRAY_BUFFER, sizeof(fullscreenQuad), &fullscreenQuad[0], GL_STATIC_DRAW);
1017 GLU_EXPECT_NO_ERROR (gl.getError(), "bufferData");
1019 gl.viewport (0, 0, m_canvasSize, m_canvasSize);
1020 gl.clearColor (0, 0, 0, 1);
1021 gl.clear (GL_COLOR_BUFFER_BIT);
1022 gl.vertexAttribPointer (m_samplerProgramPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
1023 gl.enableVertexAttribArray (m_samplerProgramPosLoc);
1024 GLU_EXPECT_NO_ERROR (gl.getError(), "vertexAttribPointer");
1026 gl.useProgram (m_samplerProgram->getProgram());
1027 gl.uniform1i (m_samplerProgramSamplerLoc, 0);
1028 gl.uniform1i (m_samplerProgramSampleNdxLoc, (deInt32)sample);
1029 GLU_EXPECT_NO_ERROR (gl.getError(), "useprogram");
1031 m_testCtx.getLog() << tcu::TestLog::Message << "Reading from texture with sampler shader, u_sample = " << sample << tcu::TestLog::EndMessage;
1033 gl.drawArrays (GL_TRIANGLE_STRIP, 0, 4);
1034 GLU_EXPECT_NO_ERROR (gl.getError(), "drawArrays");
1036 gl.disableVertexAttribArray (m_samplerProgramPosLoc);
1038 GLU_EXPECT_NO_ERROR (gl.getError(), "cleanup");
1041 glu::readPixels (m_context.getRenderContext(), 0, 0, dst.getAccess());
1042 GLU_EXPECT_NO_ERROR (gl.getError(), "readPixels");
1045 class MultisampleTextureUsageCase : public TestCase
1051 TEXTURE_COLOR_2D = 0,
1052 TEXTURE_COLOR_2D_ARRAY,
1054 TEXTURE_INT_2D_ARRAY,
1056 TEXTURE_UINT_2D_ARRAY,
1058 TEXTURE_DEPTH_2D_ARRAY,
1063 MultisampleTextureUsageCase (Context& ctx, const char* name, const char* desc, int samples, TextureType type);
1064 ~MultisampleTextureUsageCase (void);
1069 IterateResult iterate (void);
1071 void genDrawShader (void);
1072 void genSamplerShader (void);
1074 void renderToTexture (float value);
1075 void sampleTexture (tcu::Surface& dst, float value);
1076 bool verifyImage (const tcu::Surface& dst);
1078 static const int s_textureSize = 256;
1079 static const int s_textureArraySize = 8;
1080 static const int s_textureLayer = 3;
1082 const TextureType m_type;
1083 const int m_numSamples;
1085 glw::GLuint m_fboID;
1086 glw::GLuint m_textureID;
1088 glu::ShaderProgram* m_drawShader;
1089 glu::ShaderProgram* m_samplerShader;
1091 const bool m_isColorFormat;
1092 const bool m_isSignedFormat;
1093 const bool m_isUnsignedFormat;
1094 const bool m_isDepthFormat;
1095 const bool m_isArrayType;
1098 MultisampleTextureUsageCase::MultisampleTextureUsageCase (Context& ctx, const char* name, const char* desc, int samples, TextureType type)
1099 : TestCase (ctx, name, desc)
1101 , m_numSamples (samples)
1104 , m_drawShader (DE_NULL)
1105 , m_samplerShader (DE_NULL)
1106 , m_isColorFormat (m_type == TEXTURE_COLOR_2D || m_type == TEXTURE_COLOR_2D_ARRAY)
1107 , m_isSignedFormat (m_type == TEXTURE_INT_2D || m_type == TEXTURE_INT_2D_ARRAY)
1108 , m_isUnsignedFormat(m_type == TEXTURE_UINT_2D || m_type == TEXTURE_UINT_2D_ARRAY)
1109 , m_isDepthFormat (m_type == TEXTURE_DEPTH_2D || m_type == TEXTURE_DEPTH_2D_ARRAY)
1110 , m_isArrayType (m_type == TEXTURE_COLOR_2D_ARRAY || m_type == TEXTURE_INT_2D_ARRAY || m_type == TEXTURE_UINT_2D_ARRAY || m_type == TEXTURE_DEPTH_2D_ARRAY)
1112 DE_ASSERT(m_type < TEXTURE_LAST);
1115 MultisampleTextureUsageCase::~MultisampleTextureUsageCase (void)
1120 void MultisampleTextureUsageCase::init (void)
1122 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1123 const glw::GLenum internalFormat = (m_isColorFormat) ? (GL_R8) : (m_isSignedFormat) ? (GL_R8I) : (m_isUnsignedFormat) ? (GL_R8UI) : (m_isDepthFormat) ? (GL_DEPTH_COMPONENT32F) : (0);
1124 const glw::GLenum textureTarget = (m_isArrayType) ? (GL_TEXTURE_2D_MULTISAMPLE_ARRAY) : (GL_TEXTURE_2D_MULTISAMPLE);
1125 const glw::GLenum fboAttachment = (m_isDepthFormat) ? (GL_DEPTH_ATTACHMENT) : (GL_COLOR_ATTACHMENT0);
1126 const bool supportsES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
1128 DE_ASSERT(internalFormat);
1132 if (m_isArrayType && !supportsES32 && !m_context.getContextInfo().isExtensionSupported("GL_OES_texture_storage_multisample_2d_array"))
1133 throw tcu::NotSupportedError("Test requires OES_texture_storage_multisample_2d_array extension");
1134 if (m_context.getRenderTarget().getWidth() < s_textureSize || m_context.getRenderTarget().getHeight() < s_textureSize)
1135 throw tcu::NotSupportedError("render target size must be at least " + de::toString(static_cast<int>(s_textureSize)) + "x" + de::toString(static_cast<int>(s_textureSize)));
1138 glw::GLint maxSamples = 0;
1139 gl.getInternalformativ(textureTarget, internalFormat, GL_SAMPLES, 1, &maxSamples);
1141 if (m_numSamples > maxSamples)
1142 throw tcu::NotSupportedError("Requested sample count is greater than supported");
1144 m_testCtx.getLog() << tcu::TestLog::Message << "Max sample count for " << glu::getTextureFormatStr(internalFormat) << ": " << maxSamples << tcu::TestLog::EndMessage;
1148 GLint maxTextureSize = 0;
1149 gl.getIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
1151 if (s_textureSize > maxTextureSize)
1152 throw tcu::NotSupportedError("Larger GL_MAX_TEXTURE_SIZE is required");
1157 GLint maxTextureLayers = 0;
1158 gl.getIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &maxTextureLayers);
1160 if (s_textureArraySize > maxTextureLayers)
1161 throw tcu::NotSupportedError("Larger GL_MAX_ARRAY_TEXTURE_LAYERS is required");
1166 m_testCtx.getLog() << tcu::TestLog::Message << "Creating multisample " << ((m_isDepthFormat) ? ("depth") : ("")) << " texture" << ((m_isArrayType) ? (" array") : ("")) << tcu::TestLog::EndMessage;
1168 gl.genTextures(1, &m_textureID);
1169 gl.bindTexture(textureTarget, m_textureID);
1170 GLU_EXPECT_NO_ERROR(gl.getError(), "bind texture");
1173 gl.texStorage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, m_numSamples, internalFormat, s_textureSize, s_textureSize, s_textureArraySize, GL_FALSE);
1175 gl.texStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_numSamples, internalFormat, s_textureSize, s_textureSize, GL_FALSE);
1176 GLU_EXPECT_NO_ERROR(gl.getError(), "texstorage");
1178 // create fbo for drawing
1180 gl.genFramebuffers(1, &m_fboID);
1181 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID);
1185 m_testCtx.getLog() << tcu::TestLog::Message << "Attaching multisample texture array layer " << static_cast<int>(s_textureLayer) << " to fbo" << tcu::TestLog::EndMessage;
1186 gl.framebufferTextureLayer(GL_FRAMEBUFFER, fboAttachment, m_textureID, 0, s_textureLayer);
1190 m_testCtx.getLog() << tcu::TestLog::Message << "Attaching multisample texture to fbo" << tcu::TestLog::EndMessage;
1191 gl.framebufferTexture2D(GL_FRAMEBUFFER, fboAttachment, textureTarget, m_textureID, 0);
1193 GLU_EXPECT_NO_ERROR(gl.getError(), "gen fbo");
1195 // create shader for rendering to fbo
1198 // create shader for sampling the texture rendered to
1202 void MultisampleTextureUsageCase::deinit (void)
1206 m_context.getRenderContext().getFunctions().deleteTextures(1, &m_textureID);
1212 m_context.getRenderContext().getFunctions().deleteFramebuffers(1, &m_fboID);
1218 delete m_drawShader;
1219 m_drawShader = DE_NULL;
1222 if (m_samplerShader)
1224 delete m_samplerShader;
1225 m_samplerShader = DE_NULL;
1229 MultisampleTextureUsageCase::IterateResult MultisampleTextureUsageCase::iterate (void)
1231 const tcu::ScopedLogSection section (m_testCtx.getLog(), "Sample", "Render to texture and sample texture");
1232 tcu::Surface result (s_textureSize, s_textureSize);
1233 const float minValue = (m_isColorFormat || m_isDepthFormat) ? (0.0f) : (m_isSignedFormat) ? (-100.0f) : (m_isUnsignedFormat) ? (0.0f) : ( 1.0f);
1234 const float maxValue = (m_isColorFormat || m_isDepthFormat) ? (1.0f) : (m_isSignedFormat) ? ( 100.0f) : (m_isUnsignedFormat) ? (200.0f) : (-1.0f);
1235 de::Random rnd (deUint32Hash((deUint32)m_type));
1236 const float rawValue = rnd.getFloat(minValue, maxValue);
1237 const float preparedValue = (m_isSignedFormat || m_isUnsignedFormat) ? (deFloatFloor(rawValue)) : (rawValue);
1239 // draw to fbo with a random value
1241 renderToTexture(preparedValue);
1243 // draw from texture to front buffer
1245 sampleTexture(result, preparedValue);
1249 if (verifyImage(result))
1250 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1252 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
1257 void MultisampleTextureUsageCase::genDrawShader (void)
1259 const tcu::ScopedLogSection section(m_testCtx.getLog(), "RenderShader", "Generate render-to-texture shader");
1261 static const char* const vertexShaderSource = "${GLSL_VERSION_DECL}\n"
1262 "in highp vec4 a_position;\n"
1263 "void main (void)\n"
1265 " gl_Position = a_position;\n"
1267 static const char* const fragmentShaderSourceColor = "${GLSL_VERSION_DECL}\n"
1268 "layout(location = 0) out highp ${OUTTYPE} fragColor;\n"
1269 "uniform highp float u_writeValue;\n"
1270 "void main (void)\n"
1272 " fragColor = ${OUTTYPE}(vec4(u_writeValue, 1.0, 1.0, 1.0));\n"
1274 static const char* const fragmentShaderSourceDepth = "${GLSL_VERSION_DECL}\n"
1275 "layout(location = 0) out highp vec4 fragColor;\n"
1276 "uniform highp float u_writeValue;\n"
1277 "void main (void)\n"
1279 " fragColor = vec4(0.0, 0.0, 0.0, 1.0);\n"
1280 " gl_FragDepth = u_writeValue;\n"
1282 const char* const fragmentSource = (m_isDepthFormat) ? (fragmentShaderSourceDepth) : (fragmentShaderSourceColor);
1284 std::map<std::string, std::string> fragmentArguments;
1286 const glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType());
1287 fragmentArguments["GLSL_VERSION_DECL"] = glu::getGLSLVersionDeclaration(glslVersion);
1289 if (m_isColorFormat || m_isDepthFormat)
1290 fragmentArguments["OUTTYPE"] = "vec4";
1291 else if (m_isSignedFormat)
1292 fragmentArguments["OUTTYPE"] = "ivec4";
1293 else if (m_isUnsignedFormat)
1294 fragmentArguments["OUTTYPE"] = "uvec4";
1296 DE_ASSERT(DE_FALSE);
1298 m_drawShader = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(specializeShader(m_context, vertexShaderSource)) << glu::FragmentSource(tcu::StringTemplate(fragmentSource).specialize(fragmentArguments)));
1299 m_testCtx.getLog() << *m_drawShader;
1301 if (!m_drawShader->isOk())
1302 throw tcu::TestError("could not build shader");
1305 void MultisampleTextureUsageCase::genSamplerShader (void)
1307 const tcu::ScopedLogSection section(m_testCtx.getLog(), "SamplerShader", "Generate texture sampler shader");
1309 static const char* const vertexShaderSource = "${GLSL_VERSION_DECL}\n"
1310 "in highp vec4 a_position;\n"
1311 "out highp float v_gradient;\n"
1312 "void main (void)\n"
1314 " gl_Position = a_position;\n"
1315 " v_gradient = a_position.x * 0.5 + 0.5;\n"
1317 static const char* const fragmentShaderSource = "${GLSL_VERSION_DECL}\n"
1318 "${EXTENSION_STATEMENT}"
1319 "layout(location = 0) out highp vec4 fragColor;\n"
1320 "uniform highp ${SAMPLERTYPE} u_sampler;\n"
1321 "uniform highp int u_maxSamples;\n"
1322 "uniform highp int u_layer;\n"
1323 "uniform highp float u_cmpValue;\n"
1324 "in highp float v_gradient;\n"
1325 "void main (void)\n"
1327 " const highp vec4 okColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
1328 " const highp vec4 failColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
1329 " const highp float epsilon = ${EPSILON};\n"
1331 " highp int sampleNdx = clamp(int(floor(v_gradient * float(u_maxSamples))), 0, u_maxSamples-1);\n"
1332 " highp float value = float(texelFetch(u_sampler, ${FETCHPOS}, sampleNdx).r);\n"
1333 " fragColor = (abs(u_cmpValue - value) < epsilon) ? (okColor) : (failColor);\n"
1336 std::map<std::string, std::string> fragmentArguments;
1338 const glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType());
1339 fragmentArguments["GLSL_VERSION_DECL"] = glu::getGLSLVersionDeclaration(glslVersion);
1342 fragmentArguments["FETCHPOS"] = "ivec3(floor(gl_FragCoord.xy), u_layer)";
1344 fragmentArguments["FETCHPOS"] = "ivec2(floor(gl_FragCoord.xy))";
1346 if (m_isColorFormat || m_isDepthFormat)
1347 fragmentArguments["EPSILON"] = "0.1";
1349 fragmentArguments["EPSILON"] = "1.0";
1351 if (m_isArrayType && !glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)))
1352 fragmentArguments["EXTENSION_STATEMENT"] = "#extension GL_OES_texture_storage_multisample_2d_array : require\n";
1354 fragmentArguments["EXTENSION_STATEMENT"] = "";
1358 case TEXTURE_COLOR_2D: fragmentArguments["SAMPLERTYPE"] = "sampler2DMS"; break;
1359 case TEXTURE_COLOR_2D_ARRAY: fragmentArguments["SAMPLERTYPE"] = "sampler2DMSArray"; break;
1360 case TEXTURE_INT_2D: fragmentArguments["SAMPLERTYPE"] = "isampler2DMS"; break;
1361 case TEXTURE_INT_2D_ARRAY: fragmentArguments["SAMPLERTYPE"] = "isampler2DMSArray"; break;
1362 case TEXTURE_UINT_2D: fragmentArguments["SAMPLERTYPE"] = "usampler2DMS"; break;
1363 case TEXTURE_UINT_2D_ARRAY: fragmentArguments["SAMPLERTYPE"] = "usampler2DMSArray"; break;
1364 case TEXTURE_DEPTH_2D: fragmentArguments["SAMPLERTYPE"] = "sampler2DMS"; break;
1365 case TEXTURE_DEPTH_2D_ARRAY: fragmentArguments["SAMPLERTYPE"] = "sampler2DMSArray"; break;
1368 DE_ASSERT(DE_FALSE);
1371 m_samplerShader = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(specializeShader(m_context, vertexShaderSource)) << glu::FragmentSource(tcu::StringTemplate(fragmentShaderSource).specialize(fragmentArguments)));
1372 m_testCtx.getLog() << *m_samplerShader;
1374 if (!m_samplerShader->isOk())
1375 throw tcu::TestError("could not build shader");
1378 void MultisampleTextureUsageCase::renderToTexture (float value)
1380 static const tcu::Vec4 fullscreenQuad[] =
1382 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
1383 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
1384 tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
1385 tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f),
1388 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1389 const int posLocation = gl.getAttribLocation(m_drawShader->getProgram(), "a_position");
1390 const int valueLocation = gl.getUniformLocation(m_drawShader->getProgram(), "u_writeValue");
1391 glu::Buffer vertexAttibBuffer (m_context.getRenderContext());
1393 m_testCtx.getLog() << tcu::TestLog::Message << "Filling multisample texture with value " << value << tcu::TestLog::EndMessage;
1397 gl.bindBuffer(GL_ARRAY_BUFFER, *vertexAttibBuffer);
1398 gl.bufferData(GL_ARRAY_BUFFER, sizeof(fullscreenQuad), fullscreenQuad[0].getPtr(), GL_STATIC_DRAW);
1399 GLU_EXPECT_NO_ERROR(gl.getError(), "bufferdata");
1403 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID);
1404 gl.viewport(0, 0, s_textureSize, s_textureSize);
1406 if (m_isColorFormat)
1408 const float clearColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
1409 gl.clearBufferfv(GL_COLOR, 0, clearColor);
1411 else if (m_isSignedFormat)
1413 const deInt32 clearColor[4] = { 0, 0, 0, 0 };
1414 gl.clearBufferiv(GL_COLOR, 0, clearColor);
1416 else if (m_isUnsignedFormat)
1418 const deUint32 clearColor[4] = { 0, 0, 0, 0 };
1419 gl.clearBufferuiv(GL_COLOR, 0, clearColor);
1421 else if (m_isDepthFormat)
1423 const float clearDepth = 0.5f;
1424 gl.clearBufferfv(GL_DEPTH, 0, &clearDepth);
1427 GLU_EXPECT_NO_ERROR(gl.getError(), "clear buffer");
1429 // setup shader and draw
1431 gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
1432 gl.enableVertexAttribArray(posLocation);
1434 gl.useProgram(m_drawShader->getProgram());
1435 gl.uniform1f(valueLocation, value);
1437 GLU_EXPECT_NO_ERROR(gl.getError(), "setup draw");
1439 if (m_isDepthFormat)
1441 gl.enable(GL_DEPTH_TEST);
1442 gl.depthFunc(GL_ALWAYS);
1445 gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
1446 GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
1450 if (m_isDepthFormat)
1451 gl.disable(GL_DEPTH_TEST);
1453 gl.disableVertexAttribArray(posLocation);
1455 gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
1456 GLU_EXPECT_NO_ERROR(gl.getError(), "clean");
1459 void MultisampleTextureUsageCase::sampleTexture (tcu::Surface& dst, float value)
1461 static const tcu::Vec4 fullscreenQuad[] =
1463 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
1464 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
1465 tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
1466 tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f),
1469 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1470 const int posLocation = gl.getAttribLocation(m_samplerShader->getProgram(), "a_position");
1471 const int samplerLocation = gl.getUniformLocation(m_samplerShader->getProgram(), "u_sampler");
1472 const int maxSamplesLocation = gl.getUniformLocation(m_samplerShader->getProgram(), "u_maxSamples");
1473 const int layerLocation = gl.getUniformLocation(m_samplerShader->getProgram(), "u_layer");
1474 const int valueLocation = gl.getUniformLocation(m_samplerShader->getProgram(), "u_cmpValue");
1475 const glw::GLenum textureTarget = (m_isArrayType) ? (GL_TEXTURE_2D_MULTISAMPLE_ARRAY) : (GL_TEXTURE_2D_MULTISAMPLE);
1476 glu::Buffer vertexAttibBuffer (m_context.getRenderContext());
1478 m_testCtx.getLog() << tcu::TestLog::Message << "Sampling from texture." << tcu::TestLog::EndMessage;
1482 gl.bindBuffer(GL_ARRAY_BUFFER, *vertexAttibBuffer);
1483 gl.bufferData(GL_ARRAY_BUFFER, sizeof(fullscreenQuad), fullscreenQuad[0].getPtr(), GL_STATIC_DRAW);
1484 GLU_EXPECT_NO_ERROR(gl.getError(), "bufferdata");
1488 gl.viewport(0, 0, s_textureSize, s_textureSize);
1489 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1490 gl.clear(GL_COLOR_BUFFER_BIT);
1492 // setup shader and draw
1494 gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
1495 gl.enableVertexAttribArray(posLocation);
1497 gl.useProgram(m_samplerShader->getProgram());
1498 gl.uniform1i(samplerLocation, 0);
1499 gl.uniform1i(maxSamplesLocation, m_numSamples);
1501 gl.uniform1i(layerLocation, s_textureLayer);
1502 gl.uniform1f(valueLocation, value);
1503 gl.bindTexture(textureTarget, m_textureID);
1504 GLU_EXPECT_NO_ERROR(gl.getError(), "setup draw");
1506 gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
1507 GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
1511 gl.disableVertexAttribArray(posLocation);
1513 GLU_EXPECT_NO_ERROR(gl.getError(), "clean");
1517 glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
1520 bool MultisampleTextureUsageCase::verifyImage (const tcu::Surface& dst)
1524 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying image." << tcu::TestLog::EndMessage;
1526 for (int y = 0; y < dst.getHeight(); ++y)
1527 for (int x = 0; x < dst.getWidth(); ++x)
1529 const tcu::RGBA color = dst.getPixel(x, y);
1530 const int colorThresholdRed = 1 << (8 - m_context.getRenderTarget().getPixelFormat().redBits);
1531 const int colorThresholdGreen = 1 << (8 - m_context.getRenderTarget().getPixelFormat().greenBits);
1532 const int colorThresholdBlue = 1 << (8 - m_context.getRenderTarget().getPixelFormat().blueBits);
1534 // only green is accepted
1535 if (color.getRed() > colorThresholdRed || color.getGreen() < 255 - colorThresholdGreen || color.getBlue() > colorThresholdBlue)
1541 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid pixels found." << tcu::TestLog::EndMessage;
1543 << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
1544 << tcu::TestLog::Image("Result", "Result", dst)
1545 << tcu::TestLog::EndImageSet;
1551 m_testCtx.getLog() << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
1556 class NegativeFramebufferCase : public TestCase
1561 CASE_DIFFERENT_N_SAMPLES_TEX = 0,
1562 CASE_DIFFERENT_N_SAMPLES_RBO,
1563 CASE_DIFFERENT_FIXED_TEX,
1564 CASE_DIFFERENT_FIXED_RBO,
1565 CASE_NON_ZERO_LEVEL,
1570 NegativeFramebufferCase (Context& context, const char* name, const char* desc, CaseType caseType);
1571 ~NegativeFramebufferCase (void);
1576 IterateResult iterate (void);
1578 void getFormatSamples (glw::GLenum target, std::vector<int>& samples);
1580 const CaseType m_caseType;
1581 const int m_fboSize;
1582 const glw::GLenum m_internalFormat;
1584 int m_numSamples0; // !< samples for attachment 0
1585 int m_numSamples1; // !< samples for attachment 1
1588 NegativeFramebufferCase::NegativeFramebufferCase (Context& context, const char* name, const char* desc, CaseType caseType)
1589 : TestCase (context, name, desc)
1590 , m_caseType (caseType)
1592 , m_internalFormat (GL_RGBA8)
1593 , m_numSamples0 (-1)
1594 , m_numSamples1 (-1)
1598 NegativeFramebufferCase::~NegativeFramebufferCase (void)
1603 void NegativeFramebufferCase::init (void)
1605 const bool colorAttachmentTexture = (m_caseType == CASE_DIFFERENT_N_SAMPLES_TEX) || (m_caseType == CASE_DIFFERENT_FIXED_TEX);
1606 const bool colorAttachmentRbo = (m_caseType == CASE_DIFFERENT_N_SAMPLES_RBO) || (m_caseType == CASE_DIFFERENT_FIXED_RBO);
1607 const bool useDifferentSampleCounts= (m_caseType == CASE_DIFFERENT_N_SAMPLES_TEX) || (m_caseType == CASE_DIFFERENT_N_SAMPLES_RBO);
1608 std::vector<int> textureSamples;
1609 std::vector<int> rboSamples;
1611 getFormatSamples(GL_TEXTURE_2D_MULTISAMPLE, textureSamples);
1612 getFormatSamples(GL_RENDERBUFFER, rboSamples);
1614 TCU_CHECK(!textureSamples.empty());
1615 TCU_CHECK(!rboSamples.empty());
1617 // select sample counts
1619 if (useDifferentSampleCounts)
1621 if (colorAttachmentTexture)
1623 m_numSamples0 = textureSamples[0];
1625 if (textureSamples.size() >= 2)
1626 m_numSamples1 = textureSamples[1];
1628 throw tcu::NotSupportedError("Test requires multiple supported sample counts");
1630 else if (colorAttachmentRbo)
1632 for (int texNdx = 0; texNdx < (int)textureSamples.size(); ++texNdx)
1633 for (int rboNdx = 0; rboNdx < (int)rboSamples.size(); ++rboNdx)
1635 if (textureSamples[texNdx] != rboSamples[rboNdx])
1637 m_numSamples0 = textureSamples[texNdx];
1638 m_numSamples1 = rboSamples[rboNdx];
1643 throw tcu::NotSupportedError("Test requires multiple supported sample counts");
1646 DE_ASSERT(DE_FALSE);
1650 if (colorAttachmentTexture)
1652 m_numSamples0 = textureSamples[0];
1653 m_numSamples1 = textureSamples[0];
1655 else if (colorAttachmentRbo)
1657 for (int texNdx = 0; texNdx < (int)textureSamples.size(); ++texNdx)
1658 for (int rboNdx = 0; rboNdx < (int)rboSamples.size(); ++rboNdx)
1660 if (textureSamples[texNdx] == rboSamples[rboNdx])
1662 m_numSamples0 = textureSamples[texNdx];
1663 m_numSamples1 = rboSamples[rboNdx];
1668 throw tcu::NotSupportedError("Test requires a sample count supported in both rbo and texture");
1672 m_numSamples0 = textureSamples[0];
1677 void NegativeFramebufferCase::deinit (void)
1681 NegativeFramebufferCase::IterateResult NegativeFramebufferCase::iterate (void)
1683 const bool colorAttachmentTexture = (m_caseType == CASE_DIFFERENT_N_SAMPLES_TEX) || (m_caseType == CASE_DIFFERENT_FIXED_TEX);
1684 const bool colorAttachmentRbo = (m_caseType == CASE_DIFFERENT_N_SAMPLES_RBO) || (m_caseType == CASE_DIFFERENT_FIXED_RBO);
1685 const glw::GLboolean fixedSampleLocations0 = (m_caseType == CASE_DIFFERENT_N_SAMPLES_RBO) ? (GL_TRUE) : (GL_FALSE);
1686 const glw::GLboolean fixedSampleLocations1 = ((m_caseType == CASE_DIFFERENT_FIXED_TEX) || (m_caseType == CASE_DIFFERENT_FIXED_RBO)) ? (GL_TRUE) : (GL_FALSE);
1687 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
1688 glw::GLuint fboId = 0;
1689 glw::GLuint rboId = 0;
1690 glw::GLuint tex0Id = 0;
1691 glw::GLuint tex1Id = 0;
1693 bool testFailed = false;
1695 gl.enableLogging(true);
1699 gl.glGenFramebuffers(1, &fboId);
1700 gl.glBindFramebuffer(GL_FRAMEBUFFER, fboId);
1701 GLU_EXPECT_NO_ERROR(gl.glGetError(), "gen fbo");
1703 gl.glGenTextures(1, &tex0Id);
1704 gl.glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex0Id);
1705 gl.glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_numSamples0, m_internalFormat, m_fboSize, m_fboSize, fixedSampleLocations0);
1706 GLU_EXPECT_NO_ERROR(gl.glGetError(), "gen texture 0");
1708 if (m_caseType == CASE_NON_ZERO_LEVEL)
1712 // attaching non-zero level generates invalid value
1713 gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, tex0Id, 5);
1714 error = gl.glGetError();
1716 if (error != GL_INVALID_VALUE)
1718 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Expected GL_INVALID_VALUE, got " << glu::getErrorStr(error) << tcu::TestLog::EndMessage;
1724 gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, tex0Id, 0);
1725 GLU_EXPECT_NO_ERROR(gl.glGetError(), "attach to c0");
1727 if (colorAttachmentTexture)
1729 gl.glGenTextures(1, &tex1Id);
1730 gl.glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex1Id);
1731 gl.glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_numSamples1, m_internalFormat, m_fboSize, m_fboSize, fixedSampleLocations1);
1732 GLU_EXPECT_NO_ERROR(gl.glGetError(), "gen texture 1");
1734 gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D_MULTISAMPLE, tex1Id, 0);
1735 GLU_EXPECT_NO_ERROR(gl.glGetError(), "attach to c1");
1737 else if (colorAttachmentRbo)
1739 gl.glGenRenderbuffers(1, &rboId);
1740 gl.glBindRenderbuffer(GL_RENDERBUFFER, rboId);
1741 gl.glRenderbufferStorageMultisample(GL_RENDERBUFFER, m_numSamples1, m_internalFormat, m_fboSize, m_fboSize);
1742 GLU_EXPECT_NO_ERROR(gl.glGetError(), "gen rb");
1744 gl.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER, rboId);
1745 GLU_EXPECT_NO_ERROR(gl.glGetError(), "attach to c1");
1748 DE_ASSERT(DE_FALSE);
1750 // should not be complete
1752 glw::GLenum status = gl.glCheckFramebufferStatus(GL_FRAMEBUFFER);
1754 if (status != GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE)
1756 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Expected GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE, got " << glu::getFramebufferStatusName(status) << tcu::TestLog::EndMessage;
1764 gl.glDeleteFramebuffers(1, &fboId);
1765 gl.glDeleteRenderbuffers(1, &rboId);
1766 gl.glDeleteTextures(1, &tex0Id);
1767 gl.glDeleteTextures(1, &tex1Id);
1771 gl.glDeleteFramebuffers(1, &fboId);
1772 gl.glDeleteRenderbuffers(1, &rboId);
1773 gl.glDeleteTextures(1, &tex0Id);
1774 gl.glDeleteTextures(1, &tex1Id);
1777 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong error code");
1779 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1783 void NegativeFramebufferCase::getFormatSamples (glw::GLenum target, std::vector<int>& samples)
1785 const glw::Functions gl = m_context.getRenderContext().getFunctions();
1786 int sampleCount = 0;
1788 gl.getInternalformativ(target, m_internalFormat, GL_NUM_SAMPLE_COUNTS, 1, &sampleCount);
1789 samples.resize(sampleCount);
1791 if (sampleCount > 0)
1793 gl.getInternalformativ(target, m_internalFormat, GL_SAMPLES, sampleCount, &samples[0]);
1794 GLU_EXPECT_NO_ERROR(gl.getError(), "get max samples");
1798 class NegativeTexParameterCase : public TestCase
1803 TEXTURE_MIN_FILTER = 0,
1810 TEXTURE_COMPARE_MODE,
1811 TEXTURE_COMPARE_FUNC,
1817 NegativeTexParameterCase (Context& context, const char* name, const char* desc, TexParam param);
1818 ~NegativeTexParameterCase (void);
1823 IterateResult iterate (void);
1825 glw::GLenum getParamGLEnum (void) const;
1826 glw::GLint getParamValue (void) const;
1827 glw::GLenum getExpectedError (void) const;
1829 const TexParam m_texParam;
1833 NegativeTexParameterCase::NegativeTexParameterCase (Context& context, const char* name, const char* desc, TexParam param)
1834 : TestCase (context, name, desc)
1835 , m_texParam (param)
1838 DE_ASSERT(param < TEXTURE_LAST);
1841 NegativeTexParameterCase::~NegativeTexParameterCase (void)
1846 void NegativeTexParameterCase::init (void)
1849 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1852 void NegativeTexParameterCase::deinit (void)
1856 NegativeTexParameterCase::IterateResult NegativeTexParameterCase::iterate (void)
1858 static const struct TextureType
1862 glw::GLenum internalFormat;
1866 { "color", GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, false },
1867 { "color array", GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_RGBA8, true },
1868 { "signed integer", GL_TEXTURE_2D_MULTISAMPLE, GL_R8I, false },
1869 { "signed integer array", GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_R8I, true },
1870 { "unsigned integer", GL_TEXTURE_2D_MULTISAMPLE, GL_R8UI, false },
1871 { "unsigned integer array", GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_R8UI, true },
1874 const tcu::ScopedLogSection scope(m_testCtx.getLog(), "Iteration", std::string() + "Testing parameter with " + types[m_iteration].name + " texture");
1875 const bool supportsES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
1877 if (types[m_iteration].isArrayType && !supportsES32 && !m_context.getContextInfo().isExtensionSupported("GL_OES_texture_storage_multisample_2d_array"))
1878 m_testCtx.getLog() << tcu::TestLog::Message << "GL_OES_texture_storage_multisample_2d_array not supported, skipping target" << tcu::TestLog::EndMessage;
1881 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
1882 glu::Texture texture (m_context.getRenderContext());
1885 gl.enableLogging(true);
1889 gl.glBindTexture(types[m_iteration].target, *texture);
1891 if (types[m_iteration].isArrayType)
1892 gl.glTexStorage3DMultisample(types[m_iteration].target, 1, types[m_iteration].internalFormat, 16, 16, 16, GL_FALSE);
1894 gl.glTexStorage2DMultisample(types[m_iteration].target, 1, types[m_iteration].internalFormat, 16, 16, GL_FALSE);
1895 GLU_EXPECT_NO_ERROR(gl.glGetError(), "setup texture");
1899 gl.glTexParameteri(types[m_iteration].target, getParamGLEnum(), getParamValue());
1900 error = gl.glGetError();
1904 if (error != getExpectedError())
1906 m_testCtx.getLog() << tcu::TestLog::Message << "Got unexpected error: " << glu::getErrorStr(error) << ", expected: " << glu::getErrorStr(getExpectedError()) << tcu::TestLog::EndMessage;
1907 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong error code");
1911 if (++m_iteration < DE_LENGTH_OF_ARRAY(types))
1916 glw::GLenum NegativeTexParameterCase::getParamGLEnum (void) const
1920 case TEXTURE_MIN_FILTER: return GL_TEXTURE_MIN_FILTER;
1921 case TEXTURE_MAG_FILTER: return GL_TEXTURE_MAG_FILTER;
1922 case TEXTURE_WRAP_S: return GL_TEXTURE_WRAP_S;
1923 case TEXTURE_WRAP_T: return GL_TEXTURE_WRAP_T;
1924 case TEXTURE_WRAP_R: return GL_TEXTURE_WRAP_R;
1925 case TEXTURE_MIN_LOD: return GL_TEXTURE_MIN_LOD;
1926 case TEXTURE_MAX_LOD: return GL_TEXTURE_MAX_LOD;
1927 case TEXTURE_COMPARE_MODE: return GL_TEXTURE_COMPARE_MODE;
1928 case TEXTURE_COMPARE_FUNC: return GL_TEXTURE_COMPARE_FUNC;
1929 case TEXTURE_BASE_LEVEL: return GL_TEXTURE_BASE_LEVEL;
1931 DE_ASSERT(DE_FALSE);
1936 glw::GLint NegativeTexParameterCase::getParamValue (void) const
1940 case TEXTURE_MIN_FILTER: return GL_LINEAR;
1941 case TEXTURE_MAG_FILTER: return GL_LINEAR;
1942 case TEXTURE_WRAP_S: return GL_CLAMP_TO_EDGE;
1943 case TEXTURE_WRAP_T: return GL_CLAMP_TO_EDGE;
1944 case TEXTURE_WRAP_R: return GL_CLAMP_TO_EDGE;
1945 case TEXTURE_MIN_LOD: return 1;
1946 case TEXTURE_MAX_LOD: return 5;
1947 case TEXTURE_COMPARE_MODE: return GL_NONE;
1948 case TEXTURE_COMPARE_FUNC: return GL_NOTEQUAL;
1949 case TEXTURE_BASE_LEVEL: return 2;
1951 DE_ASSERT(DE_FALSE);
1956 glw::GLenum NegativeTexParameterCase::getExpectedError (void) const
1960 case TEXTURE_MIN_FILTER: return GL_INVALID_ENUM;
1961 case TEXTURE_MAG_FILTER: return GL_INVALID_ENUM;
1962 case TEXTURE_WRAP_S: return GL_INVALID_ENUM;
1963 case TEXTURE_WRAP_T: return GL_INVALID_ENUM;
1964 case TEXTURE_WRAP_R: return GL_INVALID_ENUM;
1965 case TEXTURE_MIN_LOD: return GL_INVALID_ENUM;
1966 case TEXTURE_MAX_LOD: return GL_INVALID_ENUM;
1967 case TEXTURE_COMPARE_MODE: return GL_INVALID_ENUM;
1968 case TEXTURE_COMPARE_FUNC: return GL_INVALID_ENUM;
1969 case TEXTURE_BASE_LEVEL: return GL_INVALID_OPERATION;
1971 DE_ASSERT(DE_FALSE);
1976 class NegativeTexureSampleCase : public TestCase
1979 enum SampleCountParam
1981 SAMPLECOUNT_HIGH = 0,
1987 NegativeTexureSampleCase (Context& context, const char* name, const char* desc, SampleCountParam param);
1989 IterateResult iterate (void);
1991 const SampleCountParam m_sampleParam;
1994 NegativeTexureSampleCase::NegativeTexureSampleCase (Context& context, const char* name, const char* desc, SampleCountParam param)
1995 : TestCase (context, name, desc)
1996 , m_sampleParam (param)
1998 DE_ASSERT(param < SAMPLECOUNT_LAST);
2001 NegativeTexureSampleCase::IterateResult NegativeTexureSampleCase::iterate (void)
2003 const glw::GLenum expectedError = (m_sampleParam == SAMPLECOUNT_HIGH) ? (GL_INVALID_OPERATION) : (GL_INVALID_VALUE);
2004 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
2005 glu::Texture texture (m_context.getRenderContext());
2009 gl.enableLogging(true);
2013 if (m_sampleParam == SAMPLECOUNT_HIGH)
2017 gl.glGetInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, GL_SAMPLES, 1, &maxSamples);
2018 GLU_EXPECT_NO_ERROR(gl.glGetError(), "glGetInternalformativ");
2020 samples = maxSamples + 1;
2022 else if (m_sampleParam == SAMPLECOUNT_ZERO)
2025 DE_ASSERT(DE_FALSE);
2027 // create texture with bad values
2029 gl.glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, *texture);
2030 gl.glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGBA8, 64, 64, GL_FALSE);
2031 error = gl.glGetError();
2035 if (error == expectedError)
2036 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2039 m_testCtx.getLog() << tcu::TestLog::Message << "Got unexpected error: " << glu::getErrorStr(error) << ", expected: " << glu::getErrorStr(expectedError) << tcu::TestLog::EndMessage;
2040 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong error code");
2049 TextureMultisampleTests::TextureMultisampleTests (Context& context)
2050 : TestCaseGroup(context, "multisample", "Multisample texture tests")
2054 TextureMultisampleTests::~TextureMultisampleTests (void)
2058 void TextureMultisampleTests::init (void)
2060 static const int sampleCounts[] = { 1, 2, 3, 4, 8, 10, 12, 13, 16, 64 };
2062 static const struct TextureType
2065 MultisampleTextureUsageCase::TextureType type;
2068 { "texture_color_2d", MultisampleTextureUsageCase::TEXTURE_COLOR_2D },
2069 { "texture_color_2d_array", MultisampleTextureUsageCase::TEXTURE_COLOR_2D_ARRAY },
2070 { "texture_int_2d", MultisampleTextureUsageCase::TEXTURE_INT_2D },
2071 { "texture_int_2d_array", MultisampleTextureUsageCase::TEXTURE_INT_2D_ARRAY },
2072 { "texture_uint_2d", MultisampleTextureUsageCase::TEXTURE_UINT_2D },
2073 { "texture_uint_2d_array", MultisampleTextureUsageCase::TEXTURE_UINT_2D_ARRAY },
2074 { "texture_depth_2d", MultisampleTextureUsageCase::TEXTURE_DEPTH_2D },
2075 { "texture_depth_2d_array", MultisampleTextureUsageCase::TEXTURE_DEPTH_2D_ARRAY },
2079 for (int sampleNdx = 0; sampleNdx < DE_LENGTH_OF_ARRAY(sampleCounts); ++sampleNdx)
2081 tcu::TestCaseGroup* const sampleGroup = new tcu::TestCaseGroup(m_testCtx, (std::string("samples_") + de::toString(sampleCounts[sampleNdx])).c_str(), "Test with N samples");
2082 addChild(sampleGroup);
2084 // position query works
2085 sampleGroup->addChild(new SamplePosRasterizationTest(m_context, "sample_position", "test SAMPLE_POSITION", sampleCounts[sampleNdx]));
2087 // sample mask is ANDed properly
2088 sampleGroup->addChild(new SampleMaskCase(m_context, "sample_mask_only", "Test with SampleMask only", sampleCounts[sampleNdx], SampleMaskCase::FLAGS_NONE));
2089 sampleGroup->addChild(new SampleMaskCase(m_context, "sample_mask_and_alpha_to_coverage", "Test with SampleMask and alpha to coverage", sampleCounts[sampleNdx], SampleMaskCase::FLAGS_ALPHA_TO_COVERAGE));
2090 sampleGroup->addChild(new SampleMaskCase(m_context, "sample_mask_and_sample_coverage", "Test with SampleMask and sample coverage", sampleCounts[sampleNdx], SampleMaskCase::FLAGS_SAMPLE_COVERAGE));
2091 sampleGroup->addChild(new SampleMaskCase(m_context, "sample_mask_and_sample_coverage_and_alpha_to_coverage", "Test with SampleMask, sample coverage, and alpha to coverage", sampleCounts[sampleNdx], SampleMaskCase::FLAGS_ALPHA_TO_COVERAGE | SampleMaskCase::FLAGS_SAMPLE_COVERAGE));
2093 // high bits cause no unexpected behavior
2094 sampleGroup->addChild(new SampleMaskCase(m_context, "sample_mask_non_effective_bits", "Test with SampleMask, set higher bits than sample count", sampleCounts[sampleNdx], SampleMaskCase::FLAGS_HIGH_BITS));
2097 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(textureTypes); ++typeNdx)
2098 sampleGroup->addChild(new MultisampleTextureUsageCase(m_context, (std::string("use_") + textureTypes[typeNdx].name).c_str(), textureTypes[typeNdx].name, sampleCounts[sampleNdx], textureTypes[typeNdx].type));
2103 tcu::TestCaseGroup* const negativeGroup = new tcu::TestCaseGroup(m_testCtx, "negative", "Negative tests");
2104 addChild(negativeGroup);
2106 negativeGroup->addChild(new NegativeFramebufferCase (m_context, "fbo_attach_different_sample_count_tex_tex", "Attach different sample counts", NegativeFramebufferCase::CASE_DIFFERENT_N_SAMPLES_TEX));
2107 negativeGroup->addChild(new NegativeFramebufferCase (m_context, "fbo_attach_different_sample_count_tex_rbo", "Attach different sample counts", NegativeFramebufferCase::CASE_DIFFERENT_N_SAMPLES_RBO));
2108 negativeGroup->addChild(new NegativeFramebufferCase (m_context, "fbo_attach_different_fixed_state_tex_tex", "Attach fixed and non fixed", NegativeFramebufferCase::CASE_DIFFERENT_FIXED_TEX));
2109 negativeGroup->addChild(new NegativeFramebufferCase (m_context, "fbo_attach_different_fixed_state_tex_rbo", "Attach fixed and non fixed", NegativeFramebufferCase::CASE_DIFFERENT_FIXED_RBO));
2110 negativeGroup->addChild(new NegativeFramebufferCase (m_context, "fbo_attach_non_zero_level", "Attach non-zero level", NegativeFramebufferCase::CASE_NON_ZERO_LEVEL));
2111 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_min_filter", "set TEXTURE_MIN_FILTER", NegativeTexParameterCase::TEXTURE_MIN_FILTER));
2112 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_mag_filter", "set TEXTURE_MAG_FILTER", NegativeTexParameterCase::TEXTURE_MAG_FILTER));
2113 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_wrap_s", "set TEXTURE_WRAP_S", NegativeTexParameterCase::TEXTURE_WRAP_S));
2114 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_wrap_t", "set TEXTURE_WRAP_T", NegativeTexParameterCase::TEXTURE_WRAP_T));
2115 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_wrap_r", "set TEXTURE_WRAP_R", NegativeTexParameterCase::TEXTURE_WRAP_R));
2116 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_min_lod", "set TEXTURE_MIN_LOD", NegativeTexParameterCase::TEXTURE_MIN_LOD));
2117 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_max_lod", "set TEXTURE_MAX_LOD", NegativeTexParameterCase::TEXTURE_MAX_LOD));
2118 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_compare_mode", "set TEXTURE_COMPARE_MODE", NegativeTexParameterCase::TEXTURE_COMPARE_MODE));
2119 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_compare_func", "set TEXTURE_COMPARE_FUNC", NegativeTexParameterCase::TEXTURE_COMPARE_FUNC));
2120 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_base_level", "set TEXTURE_BASE_LEVEL", NegativeTexParameterCase::TEXTURE_BASE_LEVEL));
2121 negativeGroup->addChild(new NegativeTexureSampleCase(m_context, "texture_high_sample_count", "TexStorage with high numSamples", NegativeTexureSampleCase::SAMPLECOUNT_HIGH));
2122 negativeGroup->addChild(new NegativeTexureSampleCase(m_context, "texture_zero_sample_count", "TexStorage with zero numSamples", NegativeTexureSampleCase::SAMPLECOUNT_ZERO));