1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.1 Module
3 * -------------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
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 Multisample texture test
22 *//*--------------------------------------------------------------------*/
23
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"
43
44 using namespace glw;
45
46 namespace deqp
47 {
48 namespace gles31
49 {
50 namespace Functional
51 {
52 namespace
53 {
54
55 using tcu::RasterizationArguments;
56 using tcu::TriangleSceneSpec;
57
sampleMaskToString(const std::vector<uint32_t> & bitfield,int numBits)58 static std::string sampleMaskToString(const std::vector<uint32_t> &bitfield, int numBits)
59 {
60 std::string result(numBits, '0');
61
62 // move from back to front and set chars to 1
63 for (int wordNdx = 0; wordNdx < (int)bitfield.size(); ++wordNdx)
64 {
65 for (int bit = 0; bit < 32; ++bit)
66 {
67 const int targetCharNdx = numBits - (wordNdx * 32 + bit) - 1;
68
69 // beginning of the string reached
70 if (targetCharNdx < 0)
71 return result;
72
73 if ((bitfield[wordNdx] >> bit) & 0x01)
74 result[targetCharNdx] = '1';
75 }
76 }
77
78 return result;
79 }
80
81 /*--------------------------------------------------------------------*//*!
82 * \brief Returns the number of words needed to represent mask of given length
83 *//*--------------------------------------------------------------------*/
getEffectiveSampleMaskWordCount(int highestBitNdx)84 static int getEffectiveSampleMaskWordCount(int highestBitNdx)
85 {
86 const int wordSize = 32;
87 const int maskLen = highestBitNdx + 1;
88
89 return ((maskLen - 1) / wordSize) + 1; // round_up(mask_len / wordSize)
90 }
91
92 /*--------------------------------------------------------------------*//*!
93 * \brief Creates sample mask with all less significant bits than nthBit set
94 *//*--------------------------------------------------------------------*/
genAllSetToNthBitSampleMask(int nthBit)95 static std::vector<uint32_t> genAllSetToNthBitSampleMask(int nthBit)
96 {
97 const int wordSize = 32;
98 const int numWords = getEffectiveSampleMaskWordCount(nthBit - 1);
99 const uint32_t topWordBits = (uint32_t)(nthBit - (numWords - 1) * wordSize);
100 std::vector<uint32_t> mask(numWords);
101
102 for (int ndx = 0; ndx < numWords - 1; ++ndx)
103 mask[ndx] = 0xFFFFFFFF;
104
105 mask[numWords - 1] = (uint32_t)((1ULL << topWordBits) - (uint32_t)1);
106 return mask;
107 }
108
109 /*--------------------------------------------------------------------*//*!
110 * \brief Creates sample mask with nthBit set
111 *//*--------------------------------------------------------------------*/
genSetNthBitSampleMask(int nthBit)112 static std::vector<uint32_t> genSetNthBitSampleMask(int nthBit)
113 {
114 const int wordSize = 32;
115 const int numWords = getEffectiveSampleMaskWordCount(nthBit);
116 const uint32_t topWordBits = (uint32_t)(nthBit - (numWords - 1) * wordSize);
117 std::vector<uint32_t> mask(numWords);
118
119 for (int ndx = 0; ndx < numWords - 1; ++ndx)
120 mask[ndx] = 0;
121
122 mask[numWords - 1] = (uint32_t)(1ULL << topWordBits);
123 return mask;
124 }
125
specializeShader(Context & context,const char * code)126 std::string specializeShader(Context &context, const char *code)
127 {
128 const glu::ContextType contextType = context.getRenderContext().getType();
129 const glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(contextType);
130 std::map<std::string, std::string> specializationMap;
131
132 specializationMap["GLSL_VERSION_DECL"] = glu::getGLSLVersionDeclaration(glslVersion);
133
134 return tcu::StringTemplate(code).specialize(specializationMap);
135 }
136
137 class SamplePosRasterizationTest : public TestCase
138 {
139 public:
140 SamplePosRasterizationTest(Context &context, const char *name, const char *desc, int samples);
141 ~SamplePosRasterizationTest(void);
142
143 private:
144 void init(void);
145 void deinit(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;
152
153 struct Triangle
154 {
155 tcu::Vec4 p1;
156 tcu::Vec4 p2;
157 tcu::Vec4 p3;
158 };
159
160 const int m_samples;
161 const int m_canvasSize;
162 std::vector<Triangle> m_testTriangles;
163
164 int m_iteration;
165 bool m_allIterationsOk;
166
167 GLuint m_texID;
168 GLuint m_vaoID;
169 GLuint m_vboID;
170 std::vector<tcu::Vec2> m_samplePositions;
171 int m_subpixelBits;
172
173 const glu::ShaderProgram *m_samplerProgram;
174 GLint m_samplerProgramPosLoc;
175 GLint m_samplerProgramSamplerLoc;
176 GLint m_samplerProgramSampleNdxLoc;
177 };
178
SamplePosRasterizationTest(Context & context,const char * name,const char * desc,int samples)179 SamplePosRasterizationTest::SamplePosRasterizationTest(Context &context, const char *name, const char *desc,
180 int samples)
181 : TestCase(context, name, desc)
182 , m_samples(samples)
183 , m_canvasSize(256)
184 , m_iteration(0)
185 , m_allIterationsOk(true)
186 , m_texID(0)
187 , m_vaoID(0)
188 , m_vboID(0)
189 , m_subpixelBits(0)
190 , m_samplerProgram(DE_NULL)
191 , m_samplerProgramPosLoc(-1)
192 , m_samplerProgramSamplerLoc(-1)
193 , m_samplerProgramSampleNdxLoc(-1)
194 {
195 }
196
~SamplePosRasterizationTest(void)197 SamplePosRasterizationTest::~SamplePosRasterizationTest(void)
198 {
199 deinit();
200 }
201
init(void)202 void SamplePosRasterizationTest::init(void)
203 {
204 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
205 GLint maxSamples = 0;
206
207 // requirements
208
209 if (m_context.getRenderTarget().getWidth() < m_canvasSize || m_context.getRenderTarget().getHeight() < m_canvasSize)
210 throw tcu::NotSupportedError("render target size must be at least " + de::toString(m_canvasSize) + "x" +
211 de::toString(m_canvasSize));
212
213 gl.getIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &maxSamples);
214 if (m_samples > maxSamples)
215 throw tcu::NotSupportedError("Requested sample count is greater than GL_MAX_COLOR_TEXTURE_SAMPLES");
216
217 m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_COLOR_TEXTURE_SAMPLES = " << maxSamples
218 << tcu::TestLog::EndMessage;
219
220 gl.getIntegerv(GL_SUBPIXEL_BITS, &m_subpixelBits);
221 m_testCtx.getLog() << tcu::TestLog::Message << "GL_SUBPIXEL_BITS = " << m_subpixelBits << tcu::TestLog::EndMessage;
222
223 // generate textures & other gl stuff
224
225 m_testCtx.getLog() << tcu::TestLog::Message << "Creating multisample texture" << tcu::TestLog::EndMessage;
226
227 gl.genTextures(1, &m_texID);
228 gl.bindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_texID);
229 gl.texStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_samples, GL_RGBA8, m_canvasSize, m_canvasSize, GL_TRUE);
230 GLU_EXPECT_NO_ERROR(gl.getError(), "texStorage2DMultisample");
231
232 gl.genVertexArrays(1, &m_vaoID);
233 gl.bindVertexArray(m_vaoID);
234 GLU_EXPECT_NO_ERROR(gl.getError(), "bindVertexArray");
235
236 gl.genBuffers(1, &m_vboID);
237 gl.bindBuffer(GL_ARRAY_BUFFER, m_vboID);
238 GLU_EXPECT_NO_ERROR(gl.getError(), "bindBuffer");
239
240 // generate test scene
241 for (int i = 0; i < 20; ++i)
242 {
243 // vertical spikes
244 Triangle tri;
245 tri.p1 = tcu::Vec4(((float)i + 1.0f / (float)(i + 1)) / 20.0f, 0.0f, 0.0f, 1.0f);
246 tri.p2 = tcu::Vec4(((float)i + 0.3f + 1.0f / (float)(i + 1)) / 20.0f, 0.0f, 0.0f, 1.0f);
247 tri.p3 = tcu::Vec4(((float)i + 1.0f / (float)(i + 1)) / 20.0f, -1.0f, 0.0f, 1.0f);
248 m_testTriangles.push_back(tri);
249 }
250 for (int i = 0; i < 20; ++i)
251 {
252 // horisontal spikes
253 Triangle tri;
254 tri.p1 = tcu::Vec4(-1.0f, ((float)i + 1.0f / (float)(i + 1)) / 20.0f, 0.0f, 1.0f);
255 tri.p2 = tcu::Vec4(-1.0f, ((float)i + 0.3f + 1.0f / (float)(i + 1)) / 20.0f, 0.0f, 1.0f);
256 tri.p3 = tcu::Vec4(0.0f, ((float)i + 1.0f / (float)(i + 1)) / 20.0f, 0.0f, 1.0f);
257 m_testTriangles.push_back(tri);
258 }
259
260 for (int i = 0; i < 20; ++i)
261 {
262 // fan
263 const tcu::Vec2 p = tcu::Vec2(deFloatCos(((float)i) / 20.0f * DE_PI * 2) * 0.5f + 0.5f,
264 deFloatSin(((float)i) / 20.0f * DE_PI * 2) * 0.5f + 0.5f);
265 const tcu::Vec2 d = tcu::Vec2(0.1f, 0.02f);
266
267 Triangle tri;
268 tri.p1 = tcu::Vec4(0.4f, 0.4f, 0.0f, 1.0f);
269 tri.p2 = tcu::Vec4(p.x(), p.y(), 0.0f, 1.0f);
270 tri.p3 = tcu::Vec4(p.x() + d.x(), p.y() + d.y(), 0.0f, 1.0f);
271 m_testTriangles.push_back(tri);
272 }
273 {
274 Triangle tri;
275 tri.p1 = tcu::Vec4(-0.202f, -0.202f, 0.0f, 1.0f);
276 tri.p2 = tcu::Vec4(-0.802f, -0.202f, 0.0f, 1.0f);
277 tri.p3 = tcu::Vec4(-0.802f, -0.802f, 0.0f, 1.0f);
278 m_testTriangles.push_back(tri);
279 }
280
281 // generate multisample texture (and query the sample positions in it)
282 genMultisampleTexture();
283
284 // verify queried samples are in a valid range
285 for (int sampleNdx = 0; sampleNdx < m_samples; ++sampleNdx)
286 {
287 if (m_samplePositions[sampleNdx].x() < 0.0f || m_samplePositions[sampleNdx].x() > 1.0f ||
288 m_samplePositions[sampleNdx].y() < 0.0f || m_samplePositions[sampleNdx].y() > 1.0f)
289 {
290 m_testCtx.getLog() << tcu::TestLog::Message << "// ERROR: Sample position of sample " << sampleNdx
291 << " should be in range ([0, 1], [0, 1]). Got " << m_samplePositions[sampleNdx]
292 << tcu::TestLog::EndMessage;
293 throw tcu::TestError("invalid sample position");
294 }
295 }
296
297 // generate sampler program
298 genSamplerProgram();
299 }
300
deinit(void)301 void SamplePosRasterizationTest::deinit(void)
302 {
303 if (m_vboID)
304 {
305 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_vboID);
306 m_vboID = 0;
307 }
308
309 if (m_vaoID)
310 {
311 m_context.getRenderContext().getFunctions().deleteVertexArrays(1, &m_vaoID);
312 m_vaoID = 0;
313 }
314
315 if (m_texID)
316 {
317 m_context.getRenderContext().getFunctions().deleteTextures(1, &m_texID);
318 m_texID = 0;
319 }
320
321 if (m_samplerProgram)
322 {
323 delete m_samplerProgram;
324 m_samplerProgram = DE_NULL;
325 }
326 }
327
iterate(void)328 SamplePosRasterizationTest::IterateResult SamplePosRasterizationTest::iterate(void)
329 {
330 m_allIterationsOk &= testMultisampleTexture(m_iteration);
331 m_iteration++;
332
333 if (m_iteration < m_samples)
334 return CONTINUE;
335
336 // End result
337 if (m_allIterationsOk)
338 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
339 else
340 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Pixel comparison failed");
341
342 return STOP;
343 }
344
genMultisampleTexture(void)345 void SamplePosRasterizationTest::genMultisampleTexture(void)
346 {
347 const char *const vertexShaderSource = "${GLSL_VERSION_DECL}\n"
348 "in highp vec4 a_position;\n"
349 "void main (void)\n"
350 "{\n"
351 " gl_Position = a_position;\n"
352 "}\n";
353 const char *const fragmentShaderSource = "${GLSL_VERSION_DECL}\n"
354 "layout(location = 0) out highp vec4 fragColor;\n"
355 "void main (void)\n"
356 "{\n"
357 " fragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
358 "}\n";
359
360 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
361 const glu::ShaderProgram program(m_context.getRenderContext(),
362 glu::ProgramSources()
363 << glu::VertexSource(specializeShader(m_context, vertexShaderSource))
364 << glu::FragmentSource(specializeShader(m_context, fragmentShaderSource)));
365 const GLuint posLoc = gl.getAttribLocation(program.getProgram(), "a_position");
366 GLuint fboID = 0;
367
368 if (!program.isOk())
369 {
370 m_testCtx.getLog() << program;
371 throw tcu::TestError("Failed to build shader.");
372 }
373
374 gl.bindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_texID);
375 gl.bindVertexArray(m_vaoID);
376 gl.bindBuffer(GL_ARRAY_BUFFER, m_vboID);
377
378 // Setup fbo for drawing and for sample position query
379
380 m_testCtx.getLog() << tcu::TestLog::Message << "Attaching texture to FBO" << tcu::TestLog::EndMessage;
381
382 gl.genFramebuffers(1, &fboID);
383 gl.bindFramebuffer(GL_FRAMEBUFFER, fboID);
384 gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, m_texID, 0);
385 GLU_EXPECT_NO_ERROR(gl.getError(), "framebufferTexture2D");
386
387 // Query sample positions of the multisample texture by querying the sample positions
388 // from an fbo which has the multisample texture as attachment.
389
390 m_testCtx.getLog() << tcu::TestLog::Message << "Sample locations:" << tcu::TestLog::EndMessage;
391
392 for (int sampleNdx = 0; sampleNdx < m_samples; ++sampleNdx)
393 {
394 gls::StateQueryUtil::StateQueryMemoryWriteGuard<float[2]> position;
395
396 gl.getMultisamplefv(GL_SAMPLE_POSITION, (uint32_t)sampleNdx, position);
397 if (!position.verifyValidity(m_testCtx))
398 throw tcu::TestError("Error while querying sample positions");
399
400 m_testCtx.getLog() << tcu::TestLog::Message << "\t" << sampleNdx << ": (" << position[0] << ", " << position[1]
401 << ")" << tcu::TestLog::EndMessage;
402 m_samplePositions.push_back(tcu::Vec2(position[0], position[1]));
403 }
404
405 // Draw test pattern to texture
406
407 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing test pattern to the texture" << tcu::TestLog::EndMessage;
408
409 gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(m_testTriangles.size() * sizeof(Triangle)), &m_testTriangles[0],
410 GL_STATIC_DRAW);
411 GLU_EXPECT_NO_ERROR(gl.getError(), "bufferData");
412
413 gl.viewport(0, 0, m_canvasSize, m_canvasSize);
414 gl.clearColor(0, 0, 0, 1);
415 gl.clear(GL_COLOR_BUFFER_BIT);
416 gl.vertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
417 gl.enableVertexAttribArray(posLoc);
418 GLU_EXPECT_NO_ERROR(gl.getError(), "vertexAttribPointer");
419
420 gl.useProgram(program.getProgram());
421 gl.drawArrays(GL_TRIANGLES, 0, (glw::GLsizei)(m_testTriangles.size() * 3));
422 GLU_EXPECT_NO_ERROR(gl.getError(), "drawArrays");
423
424 gl.disableVertexAttribArray(posLoc);
425 gl.useProgram(0);
426 gl.deleteFramebuffers(1, &fboID);
427 GLU_EXPECT_NO_ERROR(gl.getError(), "cleanup");
428 }
429
genSamplerProgram(void)430 void SamplePosRasterizationTest::genSamplerProgram(void)
431 {
432 const char *const vertexShaderSource = "${GLSL_VERSION_DECL}\n"
433 "in highp vec4 a_position;\n"
434 "void main (void)\n"
435 "{\n"
436 " gl_Position = a_position;\n"
437 "}\n";
438 const char *const fragShaderSource = "${GLSL_VERSION_DECL}\n"
439 "layout(location = 0) out highp vec4 fragColor;\n"
440 "uniform highp sampler2DMS u_sampler;\n"
441 "uniform highp int u_sample;\n"
442 "void main (void)\n"
443 "{\n"
444 " fragColor = texelFetch(u_sampler, ivec2(int(floor(gl_FragCoord.x)), "
445 "int(floor(gl_FragCoord.y))), u_sample);\n"
446 "}\n";
447 const tcu::ScopedLogSection section(m_testCtx.getLog(), "Generate sampler shader", "Generate sampler shader");
448 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
449
450 m_samplerProgram = new glu::ShaderProgram(
451 m_context.getRenderContext(), glu::ProgramSources()
452 << glu::VertexSource(specializeShader(m_context, vertexShaderSource))
453 << glu::FragmentSource(specializeShader(m_context, fragShaderSource)));
454 m_testCtx.getLog() << *m_samplerProgram;
455
456 if (!m_samplerProgram->isOk())
457 throw tcu::TestError("Could not create sampler program.");
458
459 m_samplerProgramPosLoc = gl.getAttribLocation(m_samplerProgram->getProgram(), "a_position");
460 m_samplerProgramSamplerLoc = gl.getUniformLocation(m_samplerProgram->getProgram(), "u_sampler");
461 m_samplerProgramSampleNdxLoc = gl.getUniformLocation(m_samplerProgram->getProgram(), "u_sample");
462 }
463
testMultisampleTexture(int sampleNdx)464 bool SamplePosRasterizationTest::testMultisampleTexture(int sampleNdx)
465 {
466 tcu::Surface glSurface(m_canvasSize, m_canvasSize);
467 TriangleSceneSpec scene;
468
469 // Draw sample
470 drawSample(glSurface, sampleNdx);
471
472 // Draw reference(s)
473 convertToSceneSpec(scene, m_samplePositions[sampleNdx]);
474
475 // Compare
476 {
477 RasterizationArguments args;
478 args.redBits = m_context.getRenderTarget().getPixelFormat().redBits;
479 args.greenBits = m_context.getRenderTarget().getPixelFormat().greenBits;
480 args.blueBits = m_context.getRenderTarget().getPixelFormat().blueBits;
481 args.numSamples = 0;
482 args.subpixelBits = m_subpixelBits;
483
484 return tcu::verifyTriangleGroupRasterization(glSurface, scene, args, m_testCtx.getLog(),
485 tcu::VERIFICATIONMODE_STRICT);
486 }
487 }
488
drawSample(tcu::Surface & dst,int sampleNdx)489 void SamplePosRasterizationTest::drawSample(tcu::Surface &dst, int sampleNdx)
490 {
491 // Downsample using only one sample
492 static const tcu::Vec4 fullscreenQuad[] = {tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f), tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
493 tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f)};
494
495 const tcu::ScopedLogSection section(
496 m_testCtx.getLog(), "Test sample position " + de::toString(sampleNdx + 1) + "/" + de::toString(m_samples),
497 "Test sample position " + de::toString(sampleNdx + 1) + "/" + de::toString(m_samples));
498 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
499
500 gl.bindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_texID);
501 gl.bindVertexArray(m_vaoID);
502 gl.bindBuffer(GL_ARRAY_BUFFER, m_vboID);
503
504 gl.bufferData(GL_ARRAY_BUFFER, sizeof(fullscreenQuad), &fullscreenQuad[0], GL_STATIC_DRAW);
505 GLU_EXPECT_NO_ERROR(gl.getError(), "bufferData");
506
507 gl.viewport(0, 0, m_canvasSize, m_canvasSize);
508 gl.clearColor(0, 0, 0, 1);
509 gl.clear(GL_COLOR_BUFFER_BIT);
510 gl.vertexAttribPointer(m_samplerProgramPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
511 gl.enableVertexAttribArray(m_samplerProgramPosLoc);
512 GLU_EXPECT_NO_ERROR(gl.getError(), "vertexAttribPointer");
513
514 gl.useProgram(m_samplerProgram->getProgram());
515 gl.uniform1i(m_samplerProgramSamplerLoc, 0);
516 gl.uniform1i(m_samplerProgramSampleNdxLoc, (int32_t)sampleNdx);
517 GLU_EXPECT_NO_ERROR(gl.getError(), "useprogram");
518
519 m_testCtx.getLog() << tcu::TestLog::Message << "Reading from texture with sample index " << sampleNdx
520 << tcu::TestLog::EndMessage;
521
522 gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
523 GLU_EXPECT_NO_ERROR(gl.getError(), "drawArrays");
524
525 gl.disableVertexAttribArray(m_samplerProgramPosLoc);
526 gl.useProgram(0);
527 GLU_EXPECT_NO_ERROR(gl.getError(), "cleanup");
528
529 gl.finish();
530 glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
531 GLU_EXPECT_NO_ERROR(gl.getError(), "readPixels");
532 }
533
convertToSceneSpec(TriangleSceneSpec & scene,const tcu::Vec2 & samplePos) const534 void SamplePosRasterizationTest::convertToSceneSpec(TriangleSceneSpec &scene, const tcu::Vec2 &samplePos) const
535 {
536 // Triangles are offset from the pixel center by "offset". Move the triangles back to take this into account.
537 const tcu::Vec4 offset = tcu::Vec4(samplePos.x() - 0.5f, samplePos.y() - 0.5f, 0.0f, 0.0f) /
538 tcu::Vec4((float)m_canvasSize, (float)m_canvasSize, 1.0f, 1.0f) * 2.0f;
539
540 for (int triangleNdx = 0; triangleNdx < (int)m_testTriangles.size(); ++triangleNdx)
541 {
542 TriangleSceneSpec::SceneTriangle triangle;
543
544 triangle.positions[0] = m_testTriangles[triangleNdx].p1 - offset;
545 triangle.positions[1] = m_testTriangles[triangleNdx].p2 - offset;
546 triangle.positions[2] = m_testTriangles[triangleNdx].p3 - offset;
547
548 triangle.sharedEdge[0] = false;
549 triangle.sharedEdge[1] = false;
550 triangle.sharedEdge[2] = false;
551
552 scene.triangles.push_back(triangle);
553 }
554 }
555
556 class SampleMaskCase : public TestCase
557 {
558 public:
559 enum CaseFlags
560 {
561 FLAGS_NONE = 0,
562 FLAGS_ALPHA_TO_COVERAGE = (1ULL << 0),
563 FLAGS_SAMPLE_COVERAGE = (1ULL << 1),
564 FLAGS_HIGH_BITS = (1ULL << 2),
565 };
566
567 SampleMaskCase(Context &context, const char *name, const char *desc, int samples, int flags);
568 ~SampleMaskCase(void);
569
570 private:
571 void init(void);
572 void deinit(void);
573 IterateResult iterate(void);
574
575 void genSamplerProgram(void);
576 void genAlphaProgram(void);
577 void updateTexture(int sample);
578 bool verifyTexture(int sample);
579 void drawSample(tcu::Surface &dst, int sample);
580
581 glw::GLint getMaxConformantSampleCount(glw::GLenum target, glw::GLenum internalFormat);
582
583 const int m_samples;
584 const int m_canvasSize;
585 const int m_gridsize;
586 const int m_effectiveSampleMaskWordCount;
587
588 int m_flags;
589 int m_currentSample;
590 int m_allIterationsOk;
591
592 glw::GLuint m_texID;
593 glw::GLuint m_vaoID;
594 glw::GLuint m_vboID;
595 glw::GLuint m_fboID;
596
597 const glu::ShaderProgram *m_samplerProgram;
598 glw::GLint m_samplerProgramPosLoc;
599 glw::GLint m_samplerProgramSamplerLoc;
600 glw::GLint m_samplerProgramSampleNdxLoc;
601
602 const glu::ShaderProgram *m_alphaProgram;
603 glw::GLint m_alphaProgramPosLoc;
604 };
605
SampleMaskCase(Context & context,const char * name,const char * desc,int samples,int flags)606 SampleMaskCase::SampleMaskCase(Context &context, const char *name, const char *desc, int samples, int flags)
607 : TestCase(context, name, desc)
608 , m_samples(samples)
609 , m_canvasSize(256)
610 , m_gridsize(16)
611 , m_effectiveSampleMaskWordCount(getEffectiveSampleMaskWordCount(samples - 1))
612 , m_flags(flags)
613 , m_currentSample(-1)
614 , m_allIterationsOk(true)
615 , m_texID(0)
616 , m_vaoID(0)
617 , m_vboID(0)
618 , m_fboID(0)
619 , m_samplerProgram(DE_NULL)
620 , m_samplerProgramPosLoc(-1)
621 , m_samplerProgramSamplerLoc(-1)
622 , m_samplerProgramSampleNdxLoc(-1)
623 , m_alphaProgram(DE_NULL)
624 , m_alphaProgramPosLoc(-1)
625 {
626 }
627
~SampleMaskCase(void)628 SampleMaskCase::~SampleMaskCase(void)
629 {
630 deinit();
631 }
632
init(void)633 void SampleMaskCase::init(void)
634 {
635 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
636 glw::GLint maxSamples = 0;
637 glw::GLint maxSampleMaskWords = 0;
638
639 // requirements
640
641 if (m_context.getRenderTarget().getWidth() < m_canvasSize || m_context.getRenderTarget().getHeight() < m_canvasSize)
642 throw tcu::NotSupportedError("render target size must be at least " + de::toString(m_canvasSize) + "x" +
643 de::toString(m_canvasSize));
644
645 gl.getIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &maxSampleMaskWords);
646 if (m_effectiveSampleMaskWordCount > maxSampleMaskWords)
647 throw tcu::NotSupportedError("Test requires larger GL_MAX_SAMPLE_MASK_WORDS");
648
649 maxSamples = getMaxConformantSampleCount(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8);
650 if (m_samples > maxSamples)
651 throw tcu::NotSupportedError(
652 "Requested sample count is greater than glGetInternalformativ(GL_SAMPLES) for this target/format");
653
654 m_testCtx.getLog() << tcu::TestLog::Message << "glGetInternalformativ(GL_SAMPLES) = " << maxSamples
655 << tcu::TestLog::EndMessage;
656
657 // Don't even try to test high bits if there are none
658
659 if ((m_flags & FLAGS_HIGH_BITS) && (m_samples % 32 == 0))
660 {
661 m_testCtx.getLog() << tcu::TestLog::Message
662 << "Sample count is multiple of word size. No unused high bits in sample mask.\nSkipping."
663 << tcu::TestLog::EndMessage;
664 throw tcu::NotSupportedError("Test requires unused high bits (sample count not multiple of 32)");
665 }
666
667 // generate textures
668
669 m_testCtx.getLog() << tcu::TestLog::Message << "Creating multisample texture with sample count " << m_samples
670 << tcu::TestLog::EndMessage;
671
672 gl.genTextures(1, &m_texID);
673 gl.bindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_texID);
674 gl.texStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_samples, GL_RGBA8, m_canvasSize, m_canvasSize, GL_FALSE);
675 GLU_EXPECT_NO_ERROR(gl.getError(), "texStorage2DMultisample");
676
677 // attach texture to fbo
678
679 m_testCtx.getLog() << tcu::TestLog::Message << "Attaching texture to FBO" << tcu::TestLog::EndMessage;
680
681 gl.genFramebuffers(1, &m_fboID);
682 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID);
683 gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, m_texID, 0);
684 GLU_EXPECT_NO_ERROR(gl.getError(), "framebufferTexture2D");
685
686 // buffers
687
688 gl.genVertexArrays(1, &m_vaoID);
689 GLU_EXPECT_NO_ERROR(gl.getError(), "genVertexArrays");
690
691 gl.genBuffers(1, &m_vboID);
692 gl.bindBuffer(GL_ARRAY_BUFFER, m_vboID);
693 GLU_EXPECT_NO_ERROR(gl.getError(), "genBuffers");
694
695 // generate grid pattern
696 {
697 std::vector<tcu::Vec4> gridData(m_gridsize * m_gridsize * 6);
698
699 for (int y = 0; y < m_gridsize; ++y)
700 for (int x = 0; x < m_gridsize; ++x)
701 {
702 gridData[(y * m_gridsize + x) * 6 + 0] =
703 tcu::Vec4(((float)(x + 0) / (float)m_gridsize) * 2.0f - 1.0f,
704 ((float)(y + 0) / (float)m_gridsize) * 2.0f - 1.0f, 0.0f, 1.0f);
705 gridData[(y * m_gridsize + x) * 6 + 1] =
706 tcu::Vec4(((float)(x + 0) / (float)m_gridsize) * 2.0f - 1.0f,
707 ((float)(y + 1) / (float)m_gridsize) * 2.0f - 1.0f, 0.0f, 1.0f);
708 gridData[(y * m_gridsize + x) * 6 + 2] =
709 tcu::Vec4(((float)(x + 1) / (float)m_gridsize) * 2.0f - 1.0f,
710 ((float)(y + 1) / (float)m_gridsize) * 2.0f - 1.0f, 0.0f, 1.0f);
711 gridData[(y * m_gridsize + x) * 6 + 3] =
712 tcu::Vec4(((float)(x + 0) / (float)m_gridsize) * 2.0f - 1.0f,
713 ((float)(y + 0) / (float)m_gridsize) * 2.0f - 1.0f, 0.0f, 1.0f);
714 gridData[(y * m_gridsize + x) * 6 + 4] =
715 tcu::Vec4(((float)(x + 1) / (float)m_gridsize) * 2.0f - 1.0f,
716 ((float)(y + 1) / (float)m_gridsize) * 2.0f - 1.0f, 0.0f, 1.0f);
717 gridData[(y * m_gridsize + x) * 6 + 5] =
718 tcu::Vec4(((float)(x + 1) / (float)m_gridsize) * 2.0f - 1.0f,
719 ((float)(y + 0) / (float)m_gridsize) * 2.0f - 1.0f, 0.0f, 1.0f);
720 }
721
722 gl.bufferData(GL_ARRAY_BUFFER, (int)(gridData.size() * sizeof(tcu::Vec4)), gridData[0].getPtr(),
723 GL_STATIC_DRAW);
724 GLU_EXPECT_NO_ERROR(gl.getError(), "bufferData");
725 }
726
727 // generate programs
728
729 genSamplerProgram();
730 genAlphaProgram();
731 }
732
deinit(void)733 void SampleMaskCase::deinit(void)
734 {
735 if (m_texID)
736 {
737 m_context.getRenderContext().getFunctions().deleteTextures(1, &m_texID);
738 m_texID = 0;
739 }
740 if (m_vaoID)
741 {
742 m_context.getRenderContext().getFunctions().deleteVertexArrays(1, &m_vaoID);
743 m_vaoID = 0;
744 }
745 if (m_vboID)
746 {
747 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_vboID);
748 m_vboID = 0;
749 }
750 if (m_fboID)
751 {
752 m_context.getRenderContext().getFunctions().deleteFramebuffers(1, &m_fboID);
753 m_fboID = 0;
754 }
755
756 if (m_samplerProgram)
757 {
758 delete m_samplerProgram;
759 m_samplerProgram = DE_NULL;
760 }
761 if (m_alphaProgram)
762 {
763 delete m_alphaProgram;
764 m_alphaProgram = DE_NULL;
765 }
766 }
767
iterate(void)768 SampleMaskCase::IterateResult SampleMaskCase::iterate(void)
769 {
770 const tcu::ScopedLogSection section(
771 m_testCtx.getLog(), "Iteration",
772 (m_currentSample == -1) ?
773 ("Verifying with zero mask") :
774 (std::string() + "Verifying sample " + de::toString(m_currentSample + 1) + "/" + de::toString(m_samples)));
775
776 bool iterationOk;
777
778 // Mask only one sample, clear rest
779
780 updateTexture(m_currentSample);
781
782 // Verify only one sample set is in the texture
783
784 iterationOk = verifyTexture(m_currentSample);
785 if (!iterationOk)
786 m_allIterationsOk = false;
787
788 m_currentSample++;
789 if (m_currentSample < m_samples)
790 return CONTINUE;
791
792 // End result
793
794 if (m_allIterationsOk)
795 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
796 else if (m_flags & FLAGS_HIGH_BITS)
797 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Unused mask bits have effect");
798 else
799 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Sample test failed");
800
801 return STOP;
802 }
803
genSamplerProgram(void)804 void SampleMaskCase::genSamplerProgram(void)
805 {
806 const char *const vertexShaderSource = "${GLSL_VERSION_DECL}\n"
807 "in highp vec4 a_position;\n"
808 "void main (void)\n"
809 "{\n"
810 " gl_Position = a_position;\n"
811 "}\n";
812 const char *const fragShaderSource =
813 "${GLSL_VERSION_DECL}\n"
814 "layout(location = 0) out highp vec4 fragColor;\n"
815 "uniform highp sampler2DMS u_sampler;\n"
816 "uniform highp int u_sample;\n"
817 "void main (void)\n"
818 "{\n"
819 " highp float correctCoverage = 0.0;\n"
820 " highp float incorrectCoverage = 0.0;\n"
821 " highp ivec2 texelPos = ivec2(int(floor(gl_FragCoord.x)), int(floor(gl_FragCoord.y)));\n"
822 "\n"
823 " for (int sampleNdx = 0; sampleNdx < ${NUMSAMPLES}; ++sampleNdx)\n"
824 " {\n"
825 " highp float sampleColor = texelFetch(u_sampler, texelPos, sampleNdx).r;\n"
826 " if (sampleNdx == u_sample)\n"
827 " correctCoverage += sampleColor;\n"
828 " else\n"
829 " incorrectCoverage += sampleColor;\n"
830 " }\n"
831 " fragColor = vec4(correctCoverage, incorrectCoverage, 0.0, 1.0);\n"
832 "}\n";
833 const tcu::ScopedLogSection section(m_testCtx.getLog(), "GenerateSamplerShader", "Generate sampler shader");
834 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
835 std::map<std::string, std::string> args;
836 const glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType());
837
838 args["GLSL_VERSION_DECL"] = glu::getGLSLVersionDeclaration(glslVersion);
839 args["NUMSAMPLES"] = de::toString(m_samples);
840
841 m_samplerProgram = new glu::ShaderProgram(
842 m_context.getRenderContext(),
843 glu::ProgramSources() << glu::VertexSource(specializeShader(m_context, vertexShaderSource))
844 << glu::FragmentSource(tcu::StringTemplate(fragShaderSource).specialize(args)));
845 m_testCtx.getLog() << *m_samplerProgram;
846
847 if (!m_samplerProgram->isOk())
848 throw tcu::TestError("Could not create sampler program.");
849
850 m_samplerProgramPosLoc = gl.getAttribLocation(m_samplerProgram->getProgram(), "a_position");
851 m_samplerProgramSamplerLoc = gl.getUniformLocation(m_samplerProgram->getProgram(), "u_sampler");
852 m_samplerProgramSampleNdxLoc = gl.getUniformLocation(m_samplerProgram->getProgram(), "u_sample");
853 }
854
genAlphaProgram(void)855 void SampleMaskCase::genAlphaProgram(void)
856 {
857 const char *const vertexShaderSource = "${GLSL_VERSION_DECL}\n"
858 "in highp vec4 a_position;\n"
859 "out highp float v_alpha;\n"
860 "void main (void)\n"
861 "{\n"
862 " gl_Position = a_position;\n"
863 " v_alpha = (a_position.x * 0.5 + 0.5)*(a_position.y * 0.5 + 0.5);\n"
864 "}\n";
865 const char *const fragShaderSource = "${GLSL_VERSION_DECL}\n"
866 "layout(location = 0) out highp vec4 fragColor;\n"
867 "in mediump float v_alpha;\n"
868 "void main (void)\n"
869 "{\n"
870 " fragColor = vec4(1.0, 1.0, 1.0, v_alpha);\n"
871 "}\n";
872 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
873
874 m_alphaProgram = new glu::ShaderProgram(m_context.getRenderContext(),
875 glu::ProgramSources()
876 << glu::VertexSource(specializeShader(m_context, vertexShaderSource))
877 << glu::FragmentSource(specializeShader(m_context, fragShaderSource)));
878
879 if (!m_alphaProgram->isOk())
880 {
881 m_testCtx.getLog() << *m_alphaProgram;
882 throw tcu::TestError("Could not create aplha program.");
883 }
884
885 m_alphaProgramPosLoc = gl.getAttribLocation(m_alphaProgram->getProgram(), "a_position");
886 }
887
updateTexture(int sample)888 void SampleMaskCase::updateTexture(int sample)
889 {
890 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
891
892 // prepare draw
893
894 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID);
895 gl.viewport(0, 0, m_canvasSize, m_canvasSize);
896 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
897
898 // clear all samples
899
900 m_testCtx.getLog() << tcu::TestLog::Message << "Clearing image" << tcu::TestLog::EndMessage;
901 gl.clear(GL_COLOR_BUFFER_BIT);
902
903 // set mask state
904
905 if (m_flags & FLAGS_HIGH_BITS)
906 {
907 const std::vector<uint32_t> bitmask = genSetNthBitSampleMask(sample);
908 const std::vector<uint32_t> effectiveMask = genAllSetToNthBitSampleMask(m_samples);
909 std::vector<uint32_t> totalBitmask(effectiveMask.size());
910
911 DE_ASSERT((int)totalBitmask.size() == m_effectiveSampleMaskWordCount);
912
913 // set some arbitrary high bits to non-effective bits
914 for (int wordNdx = 0; wordNdx < (int)effectiveMask.size(); ++wordNdx)
915 {
916 const uint32_t randomMask = (uint32_t)deUint32Hash(wordNdx << 2 ^ sample);
917 const uint32_t sampleMask = (wordNdx < (int)bitmask.size()) ? (bitmask[wordNdx]) : (0);
918 const uint32_t maskMask = effectiveMask[wordNdx];
919
920 totalBitmask[wordNdx] = (sampleMask & maskMask) | (randomMask & ~maskMask);
921 }
922
923 m_testCtx.getLog() << tcu::TestLog::Message << "Setting sample mask to 0b"
924 << sampleMaskToString(totalBitmask, (int)totalBitmask.size() * 32)
925 << tcu::TestLog::EndMessage;
926
927 gl.enable(GL_SAMPLE_MASK);
928 for (int wordNdx = 0; wordNdx < m_effectiveSampleMaskWordCount; ++wordNdx)
929 {
930 const GLbitfield wordmask =
931 (wordNdx < (int)totalBitmask.size()) ? ((GLbitfield)(totalBitmask[wordNdx])) : (0);
932 gl.sampleMaski((uint32_t)wordNdx, wordmask);
933 }
934 }
935 else
936 {
937 const std::vector<uint32_t> bitmask =
938 sample < 0 ? std::vector<uint32_t>(m_effectiveSampleMaskWordCount, 0) : genSetNthBitSampleMask(sample);
939 DE_ASSERT((int)bitmask.size() <= m_effectiveSampleMaskWordCount);
940
941 m_testCtx.getLog() << tcu::TestLog::Message << "Setting sample mask to 0b"
942 << sampleMaskToString(bitmask, m_samples) << tcu::TestLog::EndMessage;
943
944 gl.enable(GL_SAMPLE_MASK);
945 for (int wordNdx = 0; wordNdx < m_effectiveSampleMaskWordCount; ++wordNdx)
946 {
947 const GLbitfield wordmask = (wordNdx < (int)bitmask.size()) ? ((GLbitfield)(bitmask[wordNdx])) : (0);
948 gl.sampleMaski((uint32_t)wordNdx, wordmask);
949 }
950 }
951 if (m_flags & FLAGS_ALPHA_TO_COVERAGE)
952 {
953 m_testCtx.getLog() << tcu::TestLog::Message << "Enabling alpha to coverage." << tcu::TestLog::EndMessage;
954 gl.enable(GL_SAMPLE_ALPHA_TO_COVERAGE);
955 }
956 if (m_flags & FLAGS_SAMPLE_COVERAGE)
957 {
958 m_testCtx.getLog() << tcu::TestLog::Message
959 << "Enabling sample coverage. Varying sample coverage for grid cells."
960 << tcu::TestLog::EndMessage;
961 gl.enable(GL_SAMPLE_COVERAGE);
962 }
963
964 // draw test pattern
965
966 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing test grid" << tcu::TestLog::EndMessage;
967
968 gl.bindVertexArray(m_vaoID);
969 gl.bindBuffer(GL_ARRAY_BUFFER, m_vboID);
970 gl.vertexAttribPointer(m_alphaProgramPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
971 gl.enableVertexAttribArray(m_alphaProgramPosLoc);
972 GLU_EXPECT_NO_ERROR(gl.getError(), "vertexAttribPointer");
973
974 gl.useProgram(m_alphaProgram->getProgram());
975
976 for (int y = 0; y < m_gridsize; ++y)
977 for (int x = 0; x < m_gridsize; ++x)
978 {
979 if (m_flags & FLAGS_SAMPLE_COVERAGE)
980 gl.sampleCoverage((float)(y * m_gridsize + x) / float(m_gridsize * m_gridsize), GL_FALSE);
981
982 gl.drawArrays(GL_TRIANGLES, (y * m_gridsize + x) * 6, 6);
983 GLU_EXPECT_NO_ERROR(gl.getError(), "drawArrays");
984 }
985
986 // clean state
987
988 gl.disableVertexAttribArray(m_alphaProgramPosLoc);
989 gl.useProgram(0);
990 gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
991 gl.disable(GL_SAMPLE_MASK);
992 gl.disable(GL_SAMPLE_ALPHA_TO_COVERAGE);
993 gl.disable(GL_SAMPLE_COVERAGE);
994 GLU_EXPECT_NO_ERROR(gl.getError(), "clean");
995 }
996
verifyTexture(int sample)997 bool SampleMaskCase::verifyTexture(int sample)
998 {
999 tcu::Surface result(m_canvasSize, m_canvasSize);
1000 tcu::Surface errorMask(m_canvasSize, m_canvasSize);
1001 bool error = false;
1002
1003 tcu::clear(errorMask.getAccess(), tcu::RGBA::green().toVec());
1004
1005 // Draw sample:
1006 // Sample sampleNdx is set to red channel
1007 // Other samples are set to green channel
1008 drawSample(result, sample);
1009
1010 // Check surface contains only sampleNdx
1011 for (int y = 0; y < m_canvasSize; ++y)
1012 for (int x = 0; x < m_canvasSize; ++x)
1013 {
1014 const tcu::RGBA color = result.getPixel(x, y);
1015
1016 // Allow missing coverage with FLAGS_ALPHA_TO_COVERAGE and FLAGS_SAMPLE_COVERAGE, or if there are no samples enabled
1017 const bool allowMissingCoverage =
1018 ((m_flags & (FLAGS_ALPHA_TO_COVERAGE | FLAGS_SAMPLE_COVERAGE)) != 0) || (sample == -1);
1019
1020 // disabled sample was written to
1021 if (color.getGreen() != 0)
1022 {
1023 error = true;
1024 errorMask.setPixel(x, y, tcu::RGBA::red());
1025 }
1026 // enabled sample was not written to
1027 else if (color.getRed() != 255 && !allowMissingCoverage)
1028 {
1029 error = true;
1030 errorMask.setPixel(x, y, tcu::RGBA::red());
1031 }
1032 }
1033
1034 if (error)
1035 {
1036 m_testCtx.getLog() << tcu::TestLog::Message << "Image verification failed, disabled samples found."
1037 << tcu::TestLog::EndMessage
1038 << tcu::TestLog::ImageSet("VerificationResult", "Result of rendering")
1039 << tcu::TestLog::Image("Result", "Result", result)
1040 << tcu::TestLog::Image("ErrorMask", "Error Mask", errorMask) << tcu::TestLog::EndImageSet;
1041 return false;
1042 }
1043 else
1044 {
1045 m_testCtx.getLog() << tcu::TestLog::Message << "Image verification ok, no disabled samples found."
1046 << tcu::TestLog::EndMessage;
1047 return true;
1048 }
1049 }
1050
drawSample(tcu::Surface & dst,int sample)1051 void SampleMaskCase::drawSample(tcu::Surface &dst, int sample)
1052 {
1053 // Downsample using only one sample
1054 static const tcu::Vec4 fullscreenQuad[] = {tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f), tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
1055 tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f)};
1056
1057 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1058 glu::Buffer vertexBuffer(m_context.getRenderContext());
1059
1060 gl.bindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_texID);
1061 gl.bindVertexArray(m_vaoID);
1062
1063 gl.bindBuffer(GL_ARRAY_BUFFER, *vertexBuffer);
1064 gl.bufferData(GL_ARRAY_BUFFER, sizeof(fullscreenQuad), &fullscreenQuad[0], GL_STATIC_DRAW);
1065 GLU_EXPECT_NO_ERROR(gl.getError(), "bufferData");
1066
1067 gl.viewport(0, 0, m_canvasSize, m_canvasSize);
1068 gl.clearColor(0, 0, 0, 1);
1069 gl.clear(GL_COLOR_BUFFER_BIT);
1070 gl.vertexAttribPointer(m_samplerProgramPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
1071 gl.enableVertexAttribArray(m_samplerProgramPosLoc);
1072 GLU_EXPECT_NO_ERROR(gl.getError(), "vertexAttribPointer");
1073
1074 gl.useProgram(m_samplerProgram->getProgram());
1075 gl.uniform1i(m_samplerProgramSamplerLoc, 0);
1076 gl.uniform1i(m_samplerProgramSampleNdxLoc, (int32_t)sample);
1077 GLU_EXPECT_NO_ERROR(gl.getError(), "useprogram");
1078
1079 m_testCtx.getLog() << tcu::TestLog::Message << "Reading from texture with sampler shader, u_sample = " << sample
1080 << tcu::TestLog::EndMessage;
1081
1082 gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
1083 GLU_EXPECT_NO_ERROR(gl.getError(), "drawArrays");
1084
1085 gl.disableVertexAttribArray(m_samplerProgramPosLoc);
1086 gl.useProgram(0);
1087 GLU_EXPECT_NO_ERROR(gl.getError(), "cleanup");
1088
1089 gl.finish();
1090 glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
1091 GLU_EXPECT_NO_ERROR(gl.getError(), "readPixels");
1092 }
1093
getMaxConformantSampleCount(glw::GLenum target,glw::GLenum internalFormat)1094 glw::GLint SampleMaskCase::getMaxConformantSampleCount(glw::GLenum target, glw::GLenum internalFormat)
1095 {
1096 int32_t maxTextureSamples = 0;
1097 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1098 if (m_context.getContextInfo().isExtensionSupported("GL_NV_internalformat_sample_query"))
1099 {
1100 glw::GLint gl_sample_counts = 0;
1101 gl.getInternalformativ(target, internalFormat, GL_NUM_SAMPLE_COUNTS, 1, &gl_sample_counts);
1102 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetInternalformativ() failed for GL_NUM_SAMPLE_COUNTS pname");
1103 /* Check and return the first conformant sample count */
1104 glw::GLint *gl_supported_samples = new glw::GLint[gl_sample_counts];
1105 if (gl_supported_samples)
1106 {
1107 gl.getInternalformativ(target, internalFormat, GL_SAMPLES, gl_sample_counts, gl_supported_samples);
1108 for (glw::GLint i = 0; i < gl_sample_counts; i++)
1109 {
1110 glw::GLint isConformant = 0;
1111 gl.getInternalformatSampleivNV(target, internalFormat, gl_supported_samples[i], GL_CONFORMANT_NV, 1,
1112 &isConformant);
1113 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetInternalformatSampleivNV() call(s) failed");
1114 if (isConformant && gl_supported_samples[i] > maxTextureSamples)
1115 {
1116 maxTextureSamples = gl_supported_samples[i];
1117 }
1118 }
1119 delete[] gl_supported_samples;
1120 }
1121 }
1122 else
1123 {
1124 gl.getInternalformativ(target, internalFormat, GL_SAMPLES, 1, &maxTextureSamples);
1125 }
1126 return maxTextureSamples;
1127 }
1128
1129 class MultisampleTextureUsageCase : public TestCase
1130 {
1131 public:
1132 enum TextureType
1133 {
1134 TEXTURE_COLOR_2D = 0,
1135 TEXTURE_COLOR_2D_ARRAY,
1136 TEXTURE_INT_2D,
1137 TEXTURE_INT_2D_ARRAY,
1138 TEXTURE_UINT_2D,
1139 TEXTURE_UINT_2D_ARRAY,
1140 TEXTURE_DEPTH_2D,
1141 TEXTURE_DEPTH_2D_ARRAY,
1142
1143 TEXTURE_LAST
1144 };
1145
1146 MultisampleTextureUsageCase(Context &ctx, const char *name, const char *desc, int samples, TextureType type);
1147 ~MultisampleTextureUsageCase(void);
1148
1149 private:
1150 void init(void);
1151 void deinit(void);
1152 IterateResult iterate(void);
1153
1154 void genDrawShader(void);
1155 void genSamplerShader(void);
1156
1157 void renderToTexture(float value);
1158 void sampleTexture(tcu::Surface &dst, float value);
1159 bool verifyImage(const tcu::Surface &dst);
1160
1161 static const int s_textureSize = 256;
1162 static const int s_textureArraySize = 8;
1163 static const int s_textureLayer = 3;
1164
1165 const TextureType m_type;
1166 const int m_numSamples;
1167
1168 glw::GLuint m_fboID;
1169 glw::GLuint m_vaoID;
1170 glw::GLuint m_textureID;
1171
1172 glu::ShaderProgram *m_drawShader;
1173 glu::ShaderProgram *m_samplerShader;
1174
1175 const bool m_isColorFormat;
1176 const bool m_isSignedFormat;
1177 const bool m_isUnsignedFormat;
1178 const bool m_isDepthFormat;
1179 const bool m_isArrayType;
1180 };
1181
MultisampleTextureUsageCase(Context & ctx,const char * name,const char * desc,int samples,TextureType type)1182 MultisampleTextureUsageCase::MultisampleTextureUsageCase(Context &ctx, const char *name, const char *desc, int samples,
1183 TextureType type)
1184 : TestCase(ctx, name, desc)
1185 , m_type(type)
1186 , m_numSamples(samples)
1187 , m_fboID(0)
1188 , m_vaoID(0)
1189 , m_textureID(0)
1190 , m_drawShader(DE_NULL)
1191 , m_samplerShader(DE_NULL)
1192 , m_isColorFormat(m_type == TEXTURE_COLOR_2D || m_type == TEXTURE_COLOR_2D_ARRAY)
1193 , m_isSignedFormat(m_type == TEXTURE_INT_2D || m_type == TEXTURE_INT_2D_ARRAY)
1194 , m_isUnsignedFormat(m_type == TEXTURE_UINT_2D || m_type == TEXTURE_UINT_2D_ARRAY)
1195 , m_isDepthFormat(m_type == TEXTURE_DEPTH_2D || m_type == TEXTURE_DEPTH_2D_ARRAY)
1196 , m_isArrayType(m_type == TEXTURE_COLOR_2D_ARRAY || m_type == TEXTURE_INT_2D_ARRAY ||
1197 m_type == TEXTURE_UINT_2D_ARRAY || m_type == TEXTURE_DEPTH_2D_ARRAY)
1198 {
1199 DE_ASSERT(m_type < TEXTURE_LAST);
1200 }
1201
~MultisampleTextureUsageCase(void)1202 MultisampleTextureUsageCase::~MultisampleTextureUsageCase(void)
1203 {
1204 deinit();
1205 }
1206
init(void)1207 void MultisampleTextureUsageCase::init(void)
1208 {
1209 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1210 const glw::GLenum internalFormat = (m_isColorFormat) ? (GL_R8) :
1211 (m_isSignedFormat) ? (GL_R8I) :
1212 (m_isUnsignedFormat) ? (GL_R8UI) :
1213 (m_isDepthFormat) ? (GL_DEPTH_COMPONENT32F) :
1214 (0);
1215 const glw::GLenum textureTarget = (m_isArrayType) ? (GL_TEXTURE_2D_MULTISAMPLE_ARRAY) : (GL_TEXTURE_2D_MULTISAMPLE);
1216 const glw::GLenum fboAttachment = (m_isDepthFormat) ? (GL_DEPTH_ATTACHMENT) : (GL_COLOR_ATTACHMENT0);
1217 const bool supportsES32orGL45 =
1218 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) ||
1219 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
1220
1221 DE_ASSERT(internalFormat);
1222
1223 // requirements
1224
1225 if (m_isArrayType && !supportsES32orGL45 &&
1226 !m_context.getContextInfo().isExtensionSupported("GL_OES_texture_storage_multisample_2d_array"))
1227 throw tcu::NotSupportedError("Test requires OES_texture_storage_multisample_2d_array extension");
1228 if (m_context.getRenderTarget().getWidth() < s_textureSize ||
1229 m_context.getRenderTarget().getHeight() < s_textureSize)
1230 throw tcu::NotSupportedError("render target size must be at least " +
1231 de::toString(static_cast<int>(s_textureSize)) + "x" +
1232 de::toString(static_cast<int>(s_textureSize)));
1233
1234 {
1235 glw::GLint maxSamples = 0;
1236 gl.getInternalformativ(textureTarget, internalFormat, GL_SAMPLES, 1, &maxSamples);
1237
1238 if (m_numSamples > maxSamples)
1239 throw tcu::NotSupportedError("Requested sample count is greater than supported");
1240
1241 m_testCtx.getLog() << tcu::TestLog::Message << "Max sample count for "
1242 << glu::getTextureFormatStr(internalFormat) << ": " << maxSamples
1243 << tcu::TestLog::EndMessage;
1244 }
1245
1246 {
1247 GLint maxTextureSize = 0;
1248 gl.getIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
1249
1250 if (s_textureSize > maxTextureSize)
1251 throw tcu::NotSupportedError("Larger GL_MAX_TEXTURE_SIZE is required");
1252 }
1253
1254 if (m_isArrayType)
1255 {
1256 GLint maxTextureLayers = 0;
1257 gl.getIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &maxTextureLayers);
1258
1259 if (s_textureArraySize > maxTextureLayers)
1260 throw tcu::NotSupportedError("Larger GL_MAX_ARRAY_TEXTURE_LAYERS is required");
1261 }
1262
1263 // create texture
1264
1265 m_testCtx.getLog() << tcu::TestLog::Message << "Creating multisample " << ((m_isDepthFormat) ? ("depth") : (""))
1266 << " texture" << ((m_isArrayType) ? (" array") : ("")) << tcu::TestLog::EndMessage;
1267
1268 gl.genTextures(1, &m_textureID);
1269 gl.bindTexture(textureTarget, m_textureID);
1270 GLU_EXPECT_NO_ERROR(gl.getError(), "bind texture");
1271
1272 if (m_isArrayType)
1273 gl.texStorage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, m_numSamples, internalFormat, s_textureSize,
1274 s_textureSize, s_textureArraySize, GL_FALSE);
1275 else
1276 gl.texStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_numSamples, internalFormat, s_textureSize,
1277 s_textureSize, GL_FALSE);
1278 GLU_EXPECT_NO_ERROR(gl.getError(), "texstorage");
1279
1280 // create fbo for drawing
1281
1282 gl.genFramebuffers(1, &m_fboID);
1283 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID);
1284
1285 if (m_isArrayType)
1286 {
1287 m_testCtx.getLog() << tcu::TestLog::Message << "Attaching multisample texture array layer "
1288 << static_cast<int>(s_textureLayer) << " to fbo" << tcu::TestLog::EndMessage;
1289 gl.framebufferTextureLayer(GL_FRAMEBUFFER, fboAttachment, m_textureID, 0, s_textureLayer);
1290 }
1291 else
1292 {
1293 m_testCtx.getLog() << tcu::TestLog::Message << "Attaching multisample texture to fbo"
1294 << tcu::TestLog::EndMessage;
1295 gl.framebufferTexture2D(GL_FRAMEBUFFER, fboAttachment, textureTarget, m_textureID, 0);
1296 }
1297 GLU_EXPECT_NO_ERROR(gl.getError(), "gen fbo");
1298
1299 // create vao if context is GL4.5
1300 if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
1301 gl.genVertexArrays(1, &m_vaoID);
1302
1303 // create shader for rendering to fbo
1304 genDrawShader();
1305
1306 // create shader for sampling the texture rendered to
1307 genSamplerShader();
1308 }
1309
deinit(void)1310 void MultisampleTextureUsageCase::deinit(void)
1311 {
1312 if (m_textureID)
1313 {
1314 m_context.getRenderContext().getFunctions().deleteTextures(1, &m_textureID);
1315 m_textureID = 0;
1316 }
1317
1318 if (m_fboID)
1319 {
1320 m_context.getRenderContext().getFunctions().deleteFramebuffers(1, &m_fboID);
1321 m_fboID = 0;
1322 }
1323
1324 if (m_vaoID)
1325 {
1326 m_context.getRenderContext().getFunctions().deleteVertexArrays(1, &m_vaoID);
1327 m_vaoID = 0;
1328 }
1329
1330 if (m_drawShader)
1331 {
1332 delete m_drawShader;
1333 m_drawShader = DE_NULL;
1334 }
1335
1336 if (m_samplerShader)
1337 {
1338 delete m_samplerShader;
1339 m_samplerShader = DE_NULL;
1340 }
1341 }
1342
iterate(void)1343 MultisampleTextureUsageCase::IterateResult MultisampleTextureUsageCase::iterate(void)
1344 {
1345 const tcu::ScopedLogSection section(m_testCtx.getLog(), "Sample", "Render to texture and sample texture");
1346 tcu::Surface result(s_textureSize, s_textureSize);
1347 const float minValue = (m_isColorFormat || m_isDepthFormat) ? (0.0f) :
1348 (m_isSignedFormat) ? (-100.0f) :
1349 (m_isUnsignedFormat) ? (0.0f) :
1350 (1.0f);
1351 const float maxValue = (m_isColorFormat || m_isDepthFormat) ? (1.0f) :
1352 (m_isSignedFormat) ? (100.0f) :
1353 (m_isUnsignedFormat) ? (200.0f) :
1354 (-1.0f);
1355 de::Random rnd(deUint32Hash((uint32_t)m_type));
1356 const float rawValue = rnd.getFloat(minValue, maxValue);
1357 const float preparedValue = (m_isSignedFormat || m_isUnsignedFormat) ? (deFloatFloor(rawValue)) : (rawValue);
1358
1359 // draw to fbo with a random value
1360
1361 renderToTexture(preparedValue);
1362
1363 // draw from texture to front buffer
1364
1365 sampleTexture(result, preparedValue);
1366
1367 // result is ok?
1368
1369 if (verifyImage(result))
1370 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1371 else
1372 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
1373
1374 return STOP;
1375 }
1376
genDrawShader(void)1377 void MultisampleTextureUsageCase::genDrawShader(void)
1378 {
1379 const tcu::ScopedLogSection section(m_testCtx.getLog(), "RenderShader", "Generate render-to-texture shader");
1380
1381 static const char *const vertexShaderSource = "${GLSL_VERSION_DECL}\n"
1382 "in highp vec4 a_position;\n"
1383 "void main (void)\n"
1384 "{\n"
1385 " gl_Position = a_position;\n"
1386 "}\n";
1387 static const char *const fragmentShaderSourceColor =
1388 "${GLSL_VERSION_DECL}\n"
1389 "layout(location = 0) out highp ${OUTTYPE} fragColor;\n"
1390 "uniform highp float u_writeValue;\n"
1391 "void main (void)\n"
1392 "{\n"
1393 " fragColor = ${OUTTYPE}(vec4(u_writeValue, 1.0, 1.0, 1.0));\n"
1394 "}\n";
1395 static const char *const fragmentShaderSourceDepth = "${GLSL_VERSION_DECL}\n"
1396 "layout(location = 0) out highp vec4 fragColor;\n"
1397 "uniform highp float u_writeValue;\n"
1398 "void main (void)\n"
1399 "{\n"
1400 " fragColor = vec4(0.0, 0.0, 0.0, 1.0);\n"
1401 " gl_FragDepth = u_writeValue;\n"
1402 "}\n";
1403 const char *const fragmentSource = (m_isDepthFormat) ? (fragmentShaderSourceDepth) : (fragmentShaderSourceColor);
1404
1405 std::map<std::string, std::string> fragmentArguments;
1406
1407 const glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType());
1408 fragmentArguments["GLSL_VERSION_DECL"] = glu::getGLSLVersionDeclaration(glslVersion);
1409
1410 if (m_isColorFormat || m_isDepthFormat)
1411 fragmentArguments["OUTTYPE"] = "vec4";
1412 else if (m_isSignedFormat)
1413 fragmentArguments["OUTTYPE"] = "ivec4";
1414 else if (m_isUnsignedFormat)
1415 fragmentArguments["OUTTYPE"] = "uvec4";
1416 else
1417 DE_ASSERT(false);
1418
1419 m_drawShader = new glu::ShaderProgram(
1420 m_context.getRenderContext(), glu::ProgramSources()
1421 << glu::VertexSource(specializeShader(m_context, vertexShaderSource))
1422 << glu::FragmentSource(
1423 tcu::StringTemplate(fragmentSource).specialize(fragmentArguments)));
1424 m_testCtx.getLog() << *m_drawShader;
1425
1426 if (!m_drawShader->isOk())
1427 throw tcu::TestError("could not build shader");
1428 }
1429
genSamplerShader(void)1430 void MultisampleTextureUsageCase::genSamplerShader(void)
1431 {
1432 const tcu::ScopedLogSection section(m_testCtx.getLog(), "SamplerShader", "Generate texture sampler shader");
1433
1434 static const char *const vertexShaderSource = "${GLSL_VERSION_DECL}\n"
1435 "in highp vec4 a_position;\n"
1436 "out highp float v_gradient;\n"
1437 "void main (void)\n"
1438 "{\n"
1439 " gl_Position = a_position;\n"
1440 " v_gradient = a_position.x * 0.5 + 0.5;\n"
1441 "}\n";
1442 static const char *const fragmentShaderSource =
1443 "${GLSL_VERSION_DECL}\n"
1444 "${EXTENSION_STATEMENT}"
1445 "layout(location = 0) out highp vec4 fragColor;\n"
1446 "uniform highp ${SAMPLERTYPE} u_sampler;\n"
1447 "uniform highp int u_maxSamples;\n"
1448 "uniform highp int u_layer;\n"
1449 "uniform highp float u_cmpValue;\n"
1450 "in highp float v_gradient;\n"
1451 "void main (void)\n"
1452 "{\n"
1453 " const highp vec4 okColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
1454 " const highp vec4 failColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
1455 " const highp float epsilon = ${EPSILON};\n"
1456 "\n"
1457 " highp int sampleNdx = clamp(int(floor(v_gradient * float(u_maxSamples))), 0, u_maxSamples-1);\n"
1458 " highp float value = float(texelFetch(u_sampler, ${FETCHPOS}, sampleNdx).r);\n"
1459 " fragColor = (abs(u_cmpValue - value) < epsilon) ? (okColor) : (failColor);\n"
1460 "}\n";
1461
1462 std::map<std::string, std::string> fragmentArguments;
1463
1464 const glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType());
1465 fragmentArguments["GLSL_VERSION_DECL"] = glu::getGLSLVersionDeclaration(glslVersion);
1466
1467 const bool supportsES32orGL45 =
1468 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) ||
1469 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
1470
1471 if (m_isArrayType)
1472 fragmentArguments["FETCHPOS"] = "ivec3(floor(gl_FragCoord.xy), u_layer)";
1473 else
1474 fragmentArguments["FETCHPOS"] = "ivec2(floor(gl_FragCoord.xy))";
1475
1476 if (m_isColorFormat || m_isDepthFormat)
1477 fragmentArguments["EPSILON"] = "0.1";
1478 else
1479 fragmentArguments["EPSILON"] = "1.0";
1480
1481 if (m_isArrayType && !supportsES32orGL45)
1482 fragmentArguments["EXTENSION_STATEMENT"] = "#extension GL_OES_texture_storage_multisample_2d_array : require\n";
1483 else
1484 fragmentArguments["EXTENSION_STATEMENT"] = "";
1485
1486 switch (m_type)
1487 {
1488 case TEXTURE_COLOR_2D:
1489 fragmentArguments["SAMPLERTYPE"] = "sampler2DMS";
1490 break;
1491 case TEXTURE_COLOR_2D_ARRAY:
1492 fragmentArguments["SAMPLERTYPE"] = "sampler2DMSArray";
1493 break;
1494 case TEXTURE_INT_2D:
1495 fragmentArguments["SAMPLERTYPE"] = "isampler2DMS";
1496 break;
1497 case TEXTURE_INT_2D_ARRAY:
1498 fragmentArguments["SAMPLERTYPE"] = "isampler2DMSArray";
1499 break;
1500 case TEXTURE_UINT_2D:
1501 fragmentArguments["SAMPLERTYPE"] = "usampler2DMS";
1502 break;
1503 case TEXTURE_UINT_2D_ARRAY:
1504 fragmentArguments["SAMPLERTYPE"] = "usampler2DMSArray";
1505 break;
1506 case TEXTURE_DEPTH_2D:
1507 fragmentArguments["SAMPLERTYPE"] = "sampler2DMS";
1508 break;
1509 case TEXTURE_DEPTH_2D_ARRAY:
1510 fragmentArguments["SAMPLERTYPE"] = "sampler2DMSArray";
1511 break;
1512
1513 default:
1514 DE_ASSERT(false);
1515 }
1516
1517 m_samplerShader = new glu::ShaderProgram(
1518 m_context.getRenderContext(),
1519 glu::ProgramSources() << glu::VertexSource(specializeShader(m_context, vertexShaderSource))
1520 << glu::FragmentSource(
1521 tcu::StringTemplate(fragmentShaderSource).specialize(fragmentArguments)));
1522 m_testCtx.getLog() << *m_samplerShader;
1523
1524 if (!m_samplerShader->isOk())
1525 throw tcu::TestError("could not build shader");
1526 }
1527
renderToTexture(float value)1528 void MultisampleTextureUsageCase::renderToTexture(float value)
1529 {
1530 static const tcu::Vec4 fullscreenQuad[] = {
1531 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
1532 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
1533 tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f),
1534 tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f),
1535 };
1536
1537 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1538 const int posLocation = gl.getAttribLocation(m_drawShader->getProgram(), "a_position");
1539 const int valueLocation = gl.getUniformLocation(m_drawShader->getProgram(), "u_writeValue");
1540 glu::Buffer vertexAttibBuffer(m_context.getRenderContext());
1541
1542 m_testCtx.getLog() << tcu::TestLog::Message << "Filling multisample texture with value " << value
1543 << tcu::TestLog::EndMessage;
1544
1545 // upload data
1546
1547 gl.bindBuffer(GL_ARRAY_BUFFER, *vertexAttibBuffer);
1548 gl.bufferData(GL_ARRAY_BUFFER, sizeof(fullscreenQuad), fullscreenQuad[0].getPtr(), GL_STATIC_DRAW);
1549 GLU_EXPECT_NO_ERROR(gl.getError(), "bufferdata");
1550
1551 // clear buffer
1552
1553 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID);
1554 gl.viewport(0, 0, s_textureSize, s_textureSize);
1555
1556 if (m_isColorFormat)
1557 {
1558 const float clearColor[4] = {0.0f, 0.0f, 0.0f, 0.0f};
1559 gl.clearBufferfv(GL_COLOR, 0, clearColor);
1560 }
1561 else if (m_isSignedFormat)
1562 {
1563 const int32_t clearColor[4] = {0, 0, 0, 0};
1564 gl.clearBufferiv(GL_COLOR, 0, clearColor);
1565 }
1566 else if (m_isUnsignedFormat)
1567 {
1568 const uint32_t clearColor[4] = {0, 0, 0, 0};
1569 gl.clearBufferuiv(GL_COLOR, 0, clearColor);
1570 }
1571 else if (m_isDepthFormat)
1572 {
1573 const float clearDepth = 0.5f;
1574 gl.clearBufferfv(GL_DEPTH, 0, &clearDepth);
1575 }
1576
1577 GLU_EXPECT_NO_ERROR(gl.getError(), "clear buffer");
1578
1579 // setup shader and draw
1580 if (m_vaoID)
1581 gl.bindVertexArray(m_vaoID);
1582
1583 gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
1584 gl.enableVertexAttribArray(posLocation);
1585
1586 gl.useProgram(m_drawShader->getProgram());
1587 gl.uniform1f(valueLocation, value);
1588
1589 GLU_EXPECT_NO_ERROR(gl.getError(), "setup draw");
1590
1591 if (m_isDepthFormat)
1592 {
1593 gl.enable(GL_DEPTH_TEST);
1594 gl.depthFunc(GL_ALWAYS);
1595 }
1596
1597 gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
1598 GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
1599
1600 // clean state
1601
1602 if (m_isDepthFormat)
1603 gl.disable(GL_DEPTH_TEST);
1604
1605 gl.disableVertexAttribArray(posLocation);
1606 gl.useProgram(0);
1607 gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
1608 GLU_EXPECT_NO_ERROR(gl.getError(), "clean");
1609 }
1610
sampleTexture(tcu::Surface & dst,float value)1611 void MultisampleTextureUsageCase::sampleTexture(tcu::Surface &dst, float value)
1612 {
1613 static const tcu::Vec4 fullscreenQuad[] = {
1614 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
1615 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
1616 tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f),
1617 tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f),
1618 };
1619
1620 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1621 const int posLocation = gl.getAttribLocation(m_samplerShader->getProgram(), "a_position");
1622 const int samplerLocation = gl.getUniformLocation(m_samplerShader->getProgram(), "u_sampler");
1623 const int maxSamplesLocation = gl.getUniformLocation(m_samplerShader->getProgram(), "u_maxSamples");
1624 const int layerLocation = gl.getUniformLocation(m_samplerShader->getProgram(), "u_layer");
1625 const int valueLocation = gl.getUniformLocation(m_samplerShader->getProgram(), "u_cmpValue");
1626 const glw::GLenum textureTarget = (m_isArrayType) ? (GL_TEXTURE_2D_MULTISAMPLE_ARRAY) : (GL_TEXTURE_2D_MULTISAMPLE);
1627 glu::Buffer vertexAttibBuffer(m_context.getRenderContext());
1628
1629 m_testCtx.getLog() << tcu::TestLog::Message << "Sampling from texture." << tcu::TestLog::EndMessage;
1630
1631 // upload data
1632
1633 gl.bindBuffer(GL_ARRAY_BUFFER, *vertexAttibBuffer);
1634 gl.bufferData(GL_ARRAY_BUFFER, sizeof(fullscreenQuad), fullscreenQuad[0].getPtr(), GL_STATIC_DRAW);
1635 GLU_EXPECT_NO_ERROR(gl.getError(), "bufferdata");
1636
1637 // clear
1638
1639 gl.viewport(0, 0, s_textureSize, s_textureSize);
1640 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1641 gl.clear(GL_COLOR_BUFFER_BIT);
1642
1643 // setup shader and draw
1644
1645 gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
1646 gl.enableVertexAttribArray(posLocation);
1647
1648 gl.useProgram(m_samplerShader->getProgram());
1649 gl.uniform1i(samplerLocation, 0);
1650 gl.uniform1i(maxSamplesLocation, m_numSamples);
1651 if (m_isArrayType)
1652 gl.uniform1i(layerLocation, s_textureLayer);
1653 gl.uniform1f(valueLocation, value);
1654 gl.bindTexture(textureTarget, m_textureID);
1655 GLU_EXPECT_NO_ERROR(gl.getError(), "setup draw");
1656
1657 gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
1658 GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
1659
1660 // clean state
1661
1662 gl.disableVertexAttribArray(posLocation);
1663 gl.useProgram(0);
1664 GLU_EXPECT_NO_ERROR(gl.getError(), "clean");
1665
1666 // read results
1667 gl.finish();
1668 glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
1669 }
1670
verifyImage(const tcu::Surface & dst)1671 bool MultisampleTextureUsageCase::verifyImage(const tcu::Surface &dst)
1672 {
1673 bool error = false;
1674
1675 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying image." << tcu::TestLog::EndMessage;
1676
1677 for (int y = 0; y < dst.getHeight(); ++y)
1678 for (int x = 0; x < dst.getWidth(); ++x)
1679 {
1680 const tcu::RGBA color = dst.getPixel(x, y);
1681 const int colorThresholdRed = 1 << (8 - m_context.getRenderTarget().getPixelFormat().redBits);
1682 const int colorThresholdGreen = 1 << (8 - m_context.getRenderTarget().getPixelFormat().greenBits);
1683 const int colorThresholdBlue = 1 << (8 - m_context.getRenderTarget().getPixelFormat().blueBits);
1684
1685 // only green is accepted
1686 if (color.getRed() > colorThresholdRed || color.getGreen() < 255 - colorThresholdGreen ||
1687 color.getBlue() > colorThresholdBlue)
1688 error = true;
1689 }
1690
1691 if (error)
1692 {
1693 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid pixels found." << tcu::TestLog::EndMessage;
1694 m_testCtx.getLog() << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
1695 << tcu::TestLog::Image("Result", "Result", dst) << tcu::TestLog::EndImageSet;
1696
1697 return false;
1698 }
1699 else
1700 {
1701 m_testCtx.getLog() << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
1702 return true;
1703 }
1704 }
1705
1706 class NegativeFramebufferCase : public TestCase
1707 {
1708 public:
1709 enum CaseType
1710 {
1711 CASE_DIFFERENT_N_SAMPLES_TEX = 0,
1712 CASE_DIFFERENT_N_SAMPLES_RBO,
1713 CASE_DIFFERENT_FIXED_TEX,
1714 CASE_DIFFERENT_FIXED_RBO,
1715 CASE_NON_ZERO_LEVEL,
1716
1717 CASE_LAST
1718 };
1719
1720 NegativeFramebufferCase(Context &context, const char *name, const char *desc, CaseType caseType);
1721 ~NegativeFramebufferCase(void);
1722
1723 private:
1724 void init(void);
1725 void deinit(void);
1726 IterateResult iterate(void);
1727
1728 void getFormatSamples(glw::GLenum target, std::vector<int> &samples);
1729
1730 const CaseType m_caseType;
1731 const int m_fboSize;
1732 const glw::GLenum m_internalFormat;
1733
1734 int m_numSamples0; // !< samples for attachment 0
1735 int m_numSamples1; // !< samples for attachment 1
1736 };
1737
NegativeFramebufferCase(Context & context,const char * name,const char * desc,CaseType caseType)1738 NegativeFramebufferCase::NegativeFramebufferCase(Context &context, const char *name, const char *desc,
1739 CaseType caseType)
1740 : TestCase(context, name, desc)
1741 , m_caseType(caseType)
1742 , m_fboSize(64)
1743 , m_internalFormat(GL_RGBA8)
1744 , m_numSamples0(-1)
1745 , m_numSamples1(-1)
1746 {
1747 }
1748
~NegativeFramebufferCase(void)1749 NegativeFramebufferCase::~NegativeFramebufferCase(void)
1750 {
1751 deinit();
1752 }
1753
init(void)1754 void NegativeFramebufferCase::init(void)
1755 {
1756 const bool colorAttachmentTexture =
1757 (m_caseType == CASE_DIFFERENT_N_SAMPLES_TEX) || (m_caseType == CASE_DIFFERENT_FIXED_TEX);
1758 const bool colorAttachmentRbo =
1759 (m_caseType == CASE_DIFFERENT_N_SAMPLES_RBO) || (m_caseType == CASE_DIFFERENT_FIXED_RBO);
1760 const bool useDifferentSampleCounts =
1761 (m_caseType == CASE_DIFFERENT_N_SAMPLES_TEX) || (m_caseType == CASE_DIFFERENT_N_SAMPLES_RBO);
1762 std::vector<int> textureSamples;
1763 std::vector<int> rboSamples;
1764
1765 getFormatSamples(GL_TEXTURE_2D_MULTISAMPLE, textureSamples);
1766 getFormatSamples(GL_RENDERBUFFER, rboSamples);
1767
1768 TCU_CHECK(!textureSamples.empty());
1769 TCU_CHECK(!rboSamples.empty());
1770
1771 // select sample counts
1772
1773 if (useDifferentSampleCounts)
1774 {
1775 if (colorAttachmentTexture)
1776 {
1777 m_numSamples0 = textureSamples[0];
1778
1779 if (textureSamples.size() >= 2)
1780 m_numSamples1 = textureSamples[1];
1781 else
1782 throw tcu::NotSupportedError("Test requires multiple supported sample counts");
1783 }
1784 else if (colorAttachmentRbo)
1785 {
1786 for (int texNdx = 0; texNdx < (int)textureSamples.size(); ++texNdx)
1787 for (int rboNdx = 0; rboNdx < (int)rboSamples.size(); ++rboNdx)
1788 {
1789 if (textureSamples[texNdx] != rboSamples[rboNdx])
1790 {
1791 m_numSamples0 = textureSamples[texNdx];
1792 m_numSamples1 = rboSamples[rboNdx];
1793 return;
1794 }
1795 }
1796
1797 throw tcu::NotSupportedError("Test requires multiple supported sample counts");
1798 }
1799 else
1800 DE_ASSERT(false);
1801 }
1802 else
1803 {
1804 if (colorAttachmentTexture)
1805 {
1806 m_numSamples0 = textureSamples[0];
1807 m_numSamples1 = textureSamples[0];
1808 }
1809 else if (colorAttachmentRbo)
1810 {
1811 for (int texNdx = 0; texNdx < (int)textureSamples.size(); ++texNdx)
1812 for (int rboNdx = 0; rboNdx < (int)rboSamples.size(); ++rboNdx)
1813 {
1814 if (textureSamples[texNdx] == rboSamples[rboNdx])
1815 {
1816 m_numSamples0 = textureSamples[texNdx];
1817 m_numSamples1 = rboSamples[rboNdx];
1818 return;
1819 }
1820 }
1821
1822 throw tcu::NotSupportedError("Test requires a sample count supported in both rbo and texture");
1823 }
1824 else
1825 {
1826 m_numSamples0 = textureSamples[0];
1827 }
1828 }
1829 }
1830
deinit(void)1831 void NegativeFramebufferCase::deinit(void)
1832 {
1833 }
1834
iterate(void)1835 NegativeFramebufferCase::IterateResult NegativeFramebufferCase::iterate(void)
1836 {
1837 const bool colorAttachmentTexture =
1838 (m_caseType == CASE_DIFFERENT_N_SAMPLES_TEX) || (m_caseType == CASE_DIFFERENT_FIXED_TEX);
1839 const bool colorAttachmentRbo =
1840 (m_caseType == CASE_DIFFERENT_N_SAMPLES_RBO) || (m_caseType == CASE_DIFFERENT_FIXED_RBO);
1841 const glw::GLboolean fixedSampleLocations0 = (m_caseType == CASE_DIFFERENT_N_SAMPLES_RBO) ? (GL_TRUE) : (GL_FALSE);
1842 const glw::GLboolean fixedSampleLocations1 =
1843 ((m_caseType == CASE_DIFFERENT_FIXED_TEX) || (m_caseType == CASE_DIFFERENT_FIXED_RBO)) ? (GL_TRUE) : (GL_FALSE);
1844 glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
1845 glw::GLuint fboId = 0;
1846 glw::GLuint rboId = 0;
1847 glw::GLuint tex0Id = 0;
1848 glw::GLuint tex1Id = 0;
1849
1850 bool testFailed = false;
1851
1852 gl.enableLogging(true);
1853
1854 try
1855 {
1856 gl.glGenFramebuffers(1, &fboId);
1857 gl.glBindFramebuffer(GL_FRAMEBUFFER, fboId);
1858 GLU_EXPECT_NO_ERROR(gl.glGetError(), "gen fbo");
1859
1860 gl.glGenTextures(1, &tex0Id);
1861 gl.glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex0Id);
1862 gl.glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_numSamples0, m_internalFormat, m_fboSize, m_fboSize,
1863 fixedSampleLocations0);
1864 GLU_EXPECT_NO_ERROR(gl.glGetError(), "gen texture 0");
1865
1866 int textureSamples;
1867 gl.glGetTexLevelParameteriv(GL_TEXTURE_2D_MULTISAMPLE, 0, GL_TEXTURE_SAMPLES, &textureSamples);
1868
1869 if (m_caseType == CASE_NON_ZERO_LEVEL)
1870 {
1871 glw::GLenum error;
1872
1873 // attaching non-zero level generates invalid value
1874 gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, tex0Id, 5);
1875 error = gl.glGetError();
1876
1877 if (error != GL_INVALID_VALUE)
1878 {
1879 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Expected GL_INVALID_VALUE, got "
1880 << glu::getErrorStr(error) << tcu::TestLog::EndMessage;
1881 testFailed = true;
1882 }
1883 }
1884 else
1885 {
1886 gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, tex0Id, 0);
1887 GLU_EXPECT_NO_ERROR(gl.glGetError(), "attach to c0");
1888
1889 int fbSamples = 0;
1890
1891 if (colorAttachmentTexture)
1892 {
1893 gl.glGenTextures(1, &tex1Id);
1894 gl.glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex1Id);
1895 gl.glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_numSamples1, m_internalFormat, m_fboSize,
1896 m_fboSize, fixedSampleLocations1);
1897 GLU_EXPECT_NO_ERROR(gl.glGetError(), "gen texture 1");
1898 gl.glGetTexLevelParameteriv(GL_TEXTURE_2D_MULTISAMPLE, 0, GL_TEXTURE_SAMPLES, &fbSamples);
1899
1900 gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D_MULTISAMPLE, tex1Id, 0);
1901 GLU_EXPECT_NO_ERROR(gl.glGetError(), "attach to c1");
1902 }
1903 else if (colorAttachmentRbo)
1904 {
1905 gl.glGenRenderbuffers(1, &rboId);
1906 gl.glBindRenderbuffer(GL_RENDERBUFFER, rboId);
1907 gl.glRenderbufferStorageMultisample(GL_RENDERBUFFER, m_numSamples1, m_internalFormat, m_fboSize,
1908 m_fboSize);
1909 GLU_EXPECT_NO_ERROR(gl.glGetError(), "gen rb");
1910 gl.glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &fbSamples);
1911
1912 gl.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER, rboId);
1913 GLU_EXPECT_NO_ERROR(gl.glGetError(), "attach to c1");
1914 }
1915 else
1916 DE_ASSERT(false);
1917
1918 {
1919 glw::GLenum status = gl.glCheckFramebufferStatus(GL_FRAMEBUFFER);
1920
1921 if ((textureSamples != fbSamples) || (fixedSampleLocations0 != fixedSampleLocations1))
1922 {
1923 if (status != GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE) // should not be complete
1924 {
1925 m_testCtx.getLog()
1926 << tcu::TestLog::Message << "ERROR! Expected GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE, got "
1927 << glu::getFramebufferStatusName(status) << tcu::TestLog::EndMessage;
1928 testFailed = true;
1929 }
1930 }
1931 else
1932 {
1933 if (status != GL_FRAMEBUFFER_COMPLETE) // should be complete
1934 {
1935 m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Expected GL_FRAMEBUFFER_COMPLETE, got "
1936 << glu::getFramebufferStatusName(status) << tcu::TestLog::EndMessage;
1937 testFailed = true;
1938 }
1939 }
1940 }
1941 }
1942 }
1943 catch (...)
1944 {
1945 gl.glDeleteFramebuffers(1, &fboId);
1946 gl.glDeleteRenderbuffers(1, &rboId);
1947 gl.glDeleteTextures(1, &tex0Id);
1948 gl.glDeleteTextures(1, &tex1Id);
1949 throw;
1950 }
1951
1952 gl.glDeleteFramebuffers(1, &fboId);
1953 gl.glDeleteRenderbuffers(1, &rboId);
1954 gl.glDeleteTextures(1, &tex0Id);
1955 gl.glDeleteTextures(1, &tex1Id);
1956
1957 if (testFailed)
1958 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong error code");
1959 else
1960 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1961 return STOP;
1962 }
1963
getFormatSamples(glw::GLenum target,std::vector<int> & samples)1964 void NegativeFramebufferCase::getFormatSamples(glw::GLenum target, std::vector<int> &samples)
1965 {
1966 const glw::Functions gl = m_context.getRenderContext().getFunctions();
1967 int sampleCount = 0;
1968
1969 gl.getInternalformativ(target, m_internalFormat, GL_NUM_SAMPLE_COUNTS, 1, &sampleCount);
1970 samples.resize(sampleCount);
1971
1972 if (sampleCount > 0)
1973 {
1974 gl.getInternalformativ(target, m_internalFormat, GL_SAMPLES, sampleCount, &samples[0]);
1975 GLU_EXPECT_NO_ERROR(gl.getError(), "get max samples");
1976 }
1977 }
1978
1979 class NegativeTexParameterCase : public TestCase
1980 {
1981 public:
1982 enum TexParam
1983 {
1984 TEXTURE_MIN_FILTER = 0,
1985 TEXTURE_MAG_FILTER,
1986 TEXTURE_WRAP_S,
1987 TEXTURE_WRAP_T,
1988 TEXTURE_WRAP_R,
1989 TEXTURE_MIN_LOD,
1990 TEXTURE_MAX_LOD,
1991 TEXTURE_COMPARE_MODE,
1992 TEXTURE_COMPARE_FUNC,
1993 TEXTURE_BASE_LEVEL,
1994
1995 TEXTURE_LAST
1996 };
1997
1998 NegativeTexParameterCase(Context &context, const char *name, const char *desc, TexParam param);
1999 ~NegativeTexParameterCase(void);
2000
2001 private:
2002 void init(void);
2003 void deinit(void);
2004 IterateResult iterate(void);
2005
2006 glw::GLenum getParamGLEnum(void) const;
2007 glw::GLint getParamValue(void) const;
2008 glw::GLenum getExpectedError(void) const;
2009
2010 const TexParam m_texParam;
2011 int m_iteration;
2012 };
2013
NegativeTexParameterCase(Context & context,const char * name,const char * desc,TexParam param)2014 NegativeTexParameterCase::NegativeTexParameterCase(Context &context, const char *name, const char *desc, TexParam param)
2015 : TestCase(context, name, desc)
2016 , m_texParam(param)
2017 , m_iteration(0)
2018 {
2019 DE_ASSERT(param < TEXTURE_LAST);
2020 }
2021
~NegativeTexParameterCase(void)2022 NegativeTexParameterCase::~NegativeTexParameterCase(void)
2023 {
2024 deinit();
2025 }
2026
init(void)2027 void NegativeTexParameterCase::init(void)
2028 {
2029 // default value
2030 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2031 }
2032
deinit(void)2033 void NegativeTexParameterCase::deinit(void)
2034 {
2035 }
2036
iterate(void)2037 NegativeTexParameterCase::IterateResult NegativeTexParameterCase::iterate(void)
2038 {
2039 static const struct TextureType
2040 {
2041 const char *name;
2042 glw::GLenum target;
2043 glw::GLenum internalFormat;
2044 bool isArrayType;
2045 } types[] = {
2046 {"color", GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, false},
2047 {"color array", GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_RGBA8, true},
2048 {"signed integer", GL_TEXTURE_2D_MULTISAMPLE, GL_R8I, false},
2049 {"signed integer array", GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_R8I, true},
2050 {"unsigned integer", GL_TEXTURE_2D_MULTISAMPLE, GL_R8UI, false},
2051 {"unsigned integer array", GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_R8UI, true},
2052 };
2053
2054 const tcu::ScopedLogSection scope(m_testCtx.getLog(), "Iteration",
2055 std::string() + "Testing parameter with " + types[m_iteration].name + " texture");
2056 const bool supportsES32orGL45 =
2057 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) ||
2058 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
2059
2060 if (types[m_iteration].isArrayType && !supportsES32orGL45 &&
2061 !m_context.getContextInfo().isExtensionSupported("GL_OES_texture_storage_multisample_2d_array"))
2062 m_testCtx.getLog() << tcu::TestLog::Message
2063 << "GL_OES_texture_storage_multisample_2d_array not supported, skipping target"
2064 << tcu::TestLog::EndMessage;
2065 else
2066 {
2067 glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
2068 glu::Texture texture(m_context.getRenderContext());
2069 glw::GLenum error;
2070
2071 gl.enableLogging(true);
2072
2073 // gen texture
2074
2075 gl.glBindTexture(types[m_iteration].target, *texture);
2076
2077 if (types[m_iteration].isArrayType)
2078 gl.glTexStorage3DMultisample(types[m_iteration].target, 1, types[m_iteration].internalFormat, 16, 16, 16,
2079 GL_FALSE);
2080 else
2081 gl.glTexStorage2DMultisample(types[m_iteration].target, 1, types[m_iteration].internalFormat, 16, 16,
2082 GL_FALSE);
2083 GLU_EXPECT_NO_ERROR(gl.glGetError(), "setup texture");
2084
2085 // set param
2086
2087 gl.glTexParameteri(types[m_iteration].target, getParamGLEnum(), getParamValue());
2088 error = gl.glGetError();
2089
2090 // expect failure
2091
2092 if (error != getExpectedError())
2093 {
2094 m_testCtx.getLog() << tcu::TestLog::Message << "Got unexpected error: " << glu::getErrorStr(error)
2095 << ", expected: " << glu::getErrorStr(getExpectedError()) << tcu::TestLog::EndMessage;
2096 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong error code");
2097 }
2098 }
2099
2100 if (++m_iteration < DE_LENGTH_OF_ARRAY(types))
2101 return CONTINUE;
2102 return STOP;
2103 }
2104
getParamGLEnum(void) const2105 glw::GLenum NegativeTexParameterCase::getParamGLEnum(void) const
2106 {
2107 switch (m_texParam)
2108 {
2109 case TEXTURE_MIN_FILTER:
2110 return GL_TEXTURE_MIN_FILTER;
2111 case TEXTURE_MAG_FILTER:
2112 return GL_TEXTURE_MAG_FILTER;
2113 case TEXTURE_WRAP_S:
2114 return GL_TEXTURE_WRAP_S;
2115 case TEXTURE_WRAP_T:
2116 return GL_TEXTURE_WRAP_T;
2117 case TEXTURE_WRAP_R:
2118 return GL_TEXTURE_WRAP_R;
2119 case TEXTURE_MIN_LOD:
2120 return GL_TEXTURE_MIN_LOD;
2121 case TEXTURE_MAX_LOD:
2122 return GL_TEXTURE_MAX_LOD;
2123 case TEXTURE_COMPARE_MODE:
2124 return GL_TEXTURE_COMPARE_MODE;
2125 case TEXTURE_COMPARE_FUNC:
2126 return GL_TEXTURE_COMPARE_FUNC;
2127 case TEXTURE_BASE_LEVEL:
2128 return GL_TEXTURE_BASE_LEVEL;
2129 default:
2130 DE_ASSERT(false);
2131 return 0;
2132 }
2133 }
2134
getParamValue(void) const2135 glw::GLint NegativeTexParameterCase::getParamValue(void) const
2136 {
2137 switch (m_texParam)
2138 {
2139 case TEXTURE_MIN_FILTER:
2140 return GL_LINEAR;
2141 case TEXTURE_MAG_FILTER:
2142 return GL_LINEAR;
2143 case TEXTURE_WRAP_S:
2144 return GL_CLAMP_TO_EDGE;
2145 case TEXTURE_WRAP_T:
2146 return GL_CLAMP_TO_EDGE;
2147 case TEXTURE_WRAP_R:
2148 return GL_CLAMP_TO_EDGE;
2149 case TEXTURE_MIN_LOD:
2150 return 1;
2151 case TEXTURE_MAX_LOD:
2152 return 5;
2153 case TEXTURE_COMPARE_MODE:
2154 return GL_NONE;
2155 case TEXTURE_COMPARE_FUNC:
2156 return GL_NOTEQUAL;
2157 case TEXTURE_BASE_LEVEL:
2158 return 2;
2159 default:
2160 DE_ASSERT(false);
2161 return 0;
2162 }
2163 }
2164
getExpectedError(void) const2165 glw::GLenum NegativeTexParameterCase::getExpectedError(void) const
2166 {
2167 switch (m_texParam)
2168 {
2169 case TEXTURE_MIN_FILTER:
2170 return GL_INVALID_ENUM;
2171 case TEXTURE_MAG_FILTER:
2172 return GL_INVALID_ENUM;
2173 case TEXTURE_WRAP_S:
2174 return GL_INVALID_ENUM;
2175 case TEXTURE_WRAP_T:
2176 return GL_INVALID_ENUM;
2177 case TEXTURE_WRAP_R:
2178 return GL_INVALID_ENUM;
2179 case TEXTURE_MIN_LOD:
2180 return GL_INVALID_ENUM;
2181 case TEXTURE_MAX_LOD:
2182 return GL_INVALID_ENUM;
2183 case TEXTURE_COMPARE_MODE:
2184 return GL_INVALID_ENUM;
2185 case TEXTURE_COMPARE_FUNC:
2186 return GL_INVALID_ENUM;
2187 case TEXTURE_BASE_LEVEL:
2188 return GL_INVALID_OPERATION;
2189 default:
2190 DE_ASSERT(false);
2191 return 0;
2192 }
2193 }
2194
2195 class NegativeTexureSampleCase : public TestCase
2196 {
2197 public:
2198 enum SampleCountParam
2199 {
2200 SAMPLECOUNT_HIGH = 0,
2201 SAMPLECOUNT_ZERO,
2202
2203 SAMPLECOUNT_LAST
2204 };
2205
2206 NegativeTexureSampleCase(Context &context, const char *name, const char *desc, SampleCountParam param);
2207
2208 private:
2209 IterateResult iterate(void);
2210
2211 const SampleCountParam m_sampleParam;
2212 };
2213
NegativeTexureSampleCase(Context & context,const char * name,const char * desc,SampleCountParam param)2214 NegativeTexureSampleCase::NegativeTexureSampleCase(Context &context, const char *name, const char *desc,
2215 SampleCountParam param)
2216 : TestCase(context, name, desc)
2217 , m_sampleParam(param)
2218 {
2219 DE_ASSERT(param < SAMPLECOUNT_LAST);
2220 }
2221
iterate(void)2222 NegativeTexureSampleCase::IterateResult NegativeTexureSampleCase::iterate(void)
2223 {
2224 const glw::GLenum expectedError = (m_sampleParam == SAMPLECOUNT_HIGH) ? (GL_INVALID_OPERATION) : (GL_INVALID_VALUE);
2225 glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
2226 glu::Texture texture(m_context.getRenderContext());
2227 glw::GLenum error;
2228 int samples = -1;
2229
2230 gl.enableLogging(true);
2231
2232 // calc samples
2233
2234 if (m_sampleParam == SAMPLECOUNT_HIGH)
2235 {
2236 int maxSamples = 0;
2237
2238 gl.glGetInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, GL_SAMPLES, 1, &maxSamples);
2239 GLU_EXPECT_NO_ERROR(gl.glGetError(), "glGetInternalformativ");
2240
2241 samples = maxSamples + 1;
2242 }
2243 else if (m_sampleParam == SAMPLECOUNT_ZERO)
2244 samples = 0;
2245 else
2246 DE_ASSERT(false);
2247
2248 // create texture with bad values
2249
2250 gl.glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, *texture);
2251 gl.glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGBA8, 64, 64, GL_FALSE);
2252 error = gl.glGetError();
2253
2254 // expect failure
2255
2256 if (error == expectedError)
2257 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2258 else
2259 {
2260 m_testCtx.getLog() << tcu::TestLog::Message << "Got unexpected error: " << glu::getErrorStr(error)
2261 << ", expected: " << glu::getErrorStr(expectedError) << tcu::TestLog::EndMessage;
2262 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong error code");
2263 }
2264
2265 return STOP;
2266 }
2267
2268 } // namespace
2269
TextureMultisampleTests(Context & context)2270 TextureMultisampleTests::TextureMultisampleTests(Context &context)
2271 : TestCaseGroup(context, "multisample", "Multisample texture tests")
2272 {
2273 }
2274
~TextureMultisampleTests(void)2275 TextureMultisampleTests::~TextureMultisampleTests(void)
2276 {
2277 }
2278
init(void)2279 void TextureMultisampleTests::init(void)
2280 {
2281 static const int sampleCounts[] = {1, 2, 3, 4, 8, 10, 12, 13, 16, 64};
2282
2283 static const struct TextureType
2284 {
2285 const char *name;
2286 MultisampleTextureUsageCase::TextureType type;
2287 } textureTypes[] = {
2288 {"texture_color_2d", MultisampleTextureUsageCase::TEXTURE_COLOR_2D},
2289 {"texture_color_2d_array", MultisampleTextureUsageCase::TEXTURE_COLOR_2D_ARRAY},
2290 {"texture_int_2d", MultisampleTextureUsageCase::TEXTURE_INT_2D},
2291 {"texture_int_2d_array", MultisampleTextureUsageCase::TEXTURE_INT_2D_ARRAY},
2292 {"texture_uint_2d", MultisampleTextureUsageCase::TEXTURE_UINT_2D},
2293 {"texture_uint_2d_array", MultisampleTextureUsageCase::TEXTURE_UINT_2D_ARRAY},
2294 {"texture_depth_2d", MultisampleTextureUsageCase::TEXTURE_DEPTH_2D},
2295 {"texture_depth_2d_array", MultisampleTextureUsageCase::TEXTURE_DEPTH_2D_ARRAY},
2296 };
2297
2298 // .samples_x
2299 for (int sampleNdx = 0; sampleNdx < DE_LENGTH_OF_ARRAY(sampleCounts); ++sampleNdx)
2300 {
2301 tcu::TestCaseGroup *const sampleGroup =
2302 new tcu::TestCaseGroup(m_testCtx, (std::string("samples_") + de::toString(sampleCounts[sampleNdx])).c_str(),
2303 "Test with N samples");
2304 addChild(sampleGroup);
2305
2306 // position query works
2307 sampleGroup->addChild(new SamplePosRasterizationTest(m_context, "sample_position", "test SAMPLE_POSITION",
2308 sampleCounts[sampleNdx]));
2309
2310 // sample mask is ANDed properly
2311 sampleGroup->addChild(new SampleMaskCase(m_context, "sample_mask_only", "Test with SampleMask only",
2312 sampleCounts[sampleNdx], SampleMaskCase::FLAGS_NONE));
2313 sampleGroup->addChild(new SampleMaskCase(m_context, "sample_mask_and_alpha_to_coverage",
2314 "Test with SampleMask and alpha to coverage", sampleCounts[sampleNdx],
2315 SampleMaskCase::FLAGS_ALPHA_TO_COVERAGE));
2316 sampleGroup->addChild(new SampleMaskCase(m_context, "sample_mask_and_sample_coverage",
2317 "Test with SampleMask and sample coverage", sampleCounts[sampleNdx],
2318 SampleMaskCase::FLAGS_SAMPLE_COVERAGE));
2319 sampleGroup->addChild(
2320 new SampleMaskCase(m_context, "sample_mask_and_sample_coverage_and_alpha_to_coverage",
2321 "Test with SampleMask, sample coverage, and alpha to coverage", sampleCounts[sampleNdx],
2322 SampleMaskCase::FLAGS_ALPHA_TO_COVERAGE | SampleMaskCase::FLAGS_SAMPLE_COVERAGE));
2323
2324 // high bits cause no unexpected behavior
2325 sampleGroup->addChild(new SampleMaskCase(m_context, "sample_mask_non_effective_bits",
2326 "Test with SampleMask, set higher bits than sample count",
2327 sampleCounts[sampleNdx], SampleMaskCase::FLAGS_HIGH_BITS));
2328
2329 // usage
2330 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(textureTypes); ++typeNdx)
2331 sampleGroup->addChild(new MultisampleTextureUsageCase(
2332 m_context, (std::string("use_") + textureTypes[typeNdx].name).c_str(), textureTypes[typeNdx].name,
2333 sampleCounts[sampleNdx], textureTypes[typeNdx].type));
2334 }
2335
2336 // .negative
2337 {
2338 tcu::TestCaseGroup *const negativeGroup = new tcu::TestCaseGroup(m_testCtx, "negative", "Negative tests");
2339 addChild(negativeGroup);
2340
2341 negativeGroup->addChild(new NegativeFramebufferCase(m_context, "fbo_attach_different_sample_count_tex_tex",
2342 "Attach different sample counts",
2343 NegativeFramebufferCase::CASE_DIFFERENT_N_SAMPLES_TEX));
2344 negativeGroup->addChild(new NegativeFramebufferCase(m_context, "fbo_attach_different_sample_count_tex_rbo",
2345 "Attach different sample counts",
2346 NegativeFramebufferCase::CASE_DIFFERENT_N_SAMPLES_RBO));
2347 negativeGroup->addChild(new NegativeFramebufferCase(m_context, "fbo_attach_different_fixed_state_tex_tex",
2348 "Attach fixed and non fixed",
2349 NegativeFramebufferCase::CASE_DIFFERENT_FIXED_TEX));
2350 negativeGroup->addChild(new NegativeFramebufferCase(m_context, "fbo_attach_different_fixed_state_tex_rbo",
2351 "Attach fixed and non fixed",
2352 NegativeFramebufferCase::CASE_DIFFERENT_FIXED_RBO));
2353 negativeGroup->addChild(new NegativeFramebufferCase(m_context, "fbo_attach_non_zero_level",
2354 "Attach non-zero level",
2355 NegativeFramebufferCase::CASE_NON_ZERO_LEVEL));
2356 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_min_filter", "set TEXTURE_MIN_FILTER",
2357 NegativeTexParameterCase::TEXTURE_MIN_FILTER));
2358 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_mag_filter", "set TEXTURE_MAG_FILTER",
2359 NegativeTexParameterCase::TEXTURE_MAG_FILTER));
2360 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_wrap_s", "set TEXTURE_WRAP_S",
2361 NegativeTexParameterCase::TEXTURE_WRAP_S));
2362 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_wrap_t", "set TEXTURE_WRAP_T",
2363 NegativeTexParameterCase::TEXTURE_WRAP_T));
2364 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_wrap_r", "set TEXTURE_WRAP_R",
2365 NegativeTexParameterCase::TEXTURE_WRAP_R));
2366 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_min_lod", "set TEXTURE_MIN_LOD",
2367 NegativeTexParameterCase::TEXTURE_MIN_LOD));
2368 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_max_lod", "set TEXTURE_MAX_LOD",
2369 NegativeTexParameterCase::TEXTURE_MAX_LOD));
2370 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_compare_mode",
2371 "set TEXTURE_COMPARE_MODE",
2372 NegativeTexParameterCase::TEXTURE_COMPARE_MODE));
2373 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_compare_func",
2374 "set TEXTURE_COMPARE_FUNC",
2375 NegativeTexParameterCase::TEXTURE_COMPARE_FUNC));
2376 negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_base_level", "set TEXTURE_BASE_LEVEL",
2377 NegativeTexParameterCase::TEXTURE_BASE_LEVEL));
2378 negativeGroup->addChild(new NegativeTexureSampleCase(m_context, "texture_high_sample_count",
2379 "TexStorage with high numSamples",
2380 NegativeTexureSampleCase::SAMPLECOUNT_HIGH));
2381 negativeGroup->addChild(new NegativeTexureSampleCase(m_context, "texture_zero_sample_count",
2382 "TexStorage with zero numSamples",
2383 NegativeTexureSampleCase::SAMPLECOUNT_ZERO));
2384 }
2385 }
2386
2387 } // namespace Functional
2388 } // namespace gles31
2389 } // namespace deqp
2390