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 shader render case
22 *//*--------------------------------------------------------------------*/
23
24 #include "es31fMultisampleShaderRenderCase.hpp"
25 #include "tcuRenderTarget.hpp"
26 #include "tcuSurface.hpp"
27 #include "tcuTestLog.hpp"
28 #include "tcuStringTemplate.hpp"
29 #include "gluContextInfo.hpp"
30 #include "gluShaderProgram.hpp"
31 #include "gluRenderContext.hpp"
32 #include "gluPixelTransfer.hpp"
33 #include "glwFunctions.hpp"
34 #include "glwEnums.hpp"
35 #include "deStringUtil.hpp"
36
37 namespace deqp
38 {
39 namespace gles31
40 {
41 namespace Functional
42 {
43 namespace MultisampleShaderRenderUtil
44 {
45 using std::map;
46 using std::string;
47 namespace
48 {
49
50 static const char *const s_vertexSource = "${GLSL_VERSION_DECL}\n"
51 "in highp vec4 a_position;\n"
52 "out highp vec4 v_position;\n"
53 "void main (void)\n"
54 "{\n"
55 " gl_Position = a_position;\n"
56 " v_position = a_position;\n"
57 "}";
58
59 } // namespace
60
QualityWarning(const std::string & message)61 QualityWarning::QualityWarning(const std::string &message) : tcu::Exception(message)
62 {
63 }
64
MultisampleRenderCase(Context & context,const char * name,const char * desc,int numSamples,RenderTarget target,int renderSize,int flags)65 MultisampleRenderCase::MultisampleRenderCase(Context &context, const char *name, const char *desc, int numSamples,
66 RenderTarget target, int renderSize, int flags)
67 : TestCase(context, name, desc)
68 , m_numRequestedSamples(numSamples)
69 , m_renderTarget(target)
70 , m_renderSize(renderSize)
71 , m_perIterationShader((flags & FLAG_PER_ITERATION_SHADER) != 0)
72 , m_verifyTextureSampleBuffers((flags & FLAG_VERIFY_MSAA_TEXTURE_SAMPLE_BUFFERS) != 0 && target == TARGET_TEXTURE)
73 , m_numTargetSamples(-1)
74 , m_buffer(0)
75 , m_resolveBuffer(0)
76 , m_program(DE_NULL)
77 , m_fbo(0)
78 , m_fboTexture(0)
79 , m_textureSamplerProgram(DE_NULL)
80 , m_fboRbo(0)
81 , m_resolveFbo(0)
82 , m_resolveFboTexture(0)
83 , m_iteration(0)
84 , m_numIterations(1)
85 , m_renderMode(0)
86 , m_renderCount(0)
87 , m_renderVao(0)
88 , m_resolveVao(0)
89 {
90 DE_ASSERT(target < TARGET_LAST);
91 }
92
~MultisampleRenderCase(void)93 MultisampleRenderCase::~MultisampleRenderCase(void)
94 {
95 MultisampleRenderCase::deinit();
96 }
97
init(void)98 void MultisampleRenderCase::init(void)
99 {
100 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
101 int32_t queriedSampleCount = -1;
102 const bool supportsES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
103 map<string, string> args;
104
105 args["GLSL_VERSION_DECL"] = supportsES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) :
106 getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
107
108 // requirements
109
110 switch (m_renderTarget)
111 {
112 case TARGET_DEFAULT:
113 {
114 if (m_context.getRenderTarget().getWidth() < m_renderSize ||
115 m_context.getRenderTarget().getHeight() < m_renderSize)
116 throw tcu::NotSupportedError("Test requires render target with size " + de::toString(m_renderSize) + "x" +
117 de::toString(m_renderSize) + " or greater");
118 break;
119 }
120
121 case TARGET_TEXTURE:
122 {
123 int32_t maxTextureSamples = getMaxConformantSampleCount(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8);
124 if (m_numRequestedSamples > maxTextureSamples)
125 throw tcu::NotSupportedError("Sample count not supported");
126 break;
127 }
128
129 case TARGET_RENDERBUFFER:
130 {
131 int32_t maxRboSamples = getMaxConformantSampleCount(GL_RENDERBUFFER, GL_RGBA8);
132 if (m_numRequestedSamples > maxRboSamples)
133 throw tcu::NotSupportedError("Sample count not supported");
134 break;
135 }
136
137 default:
138 DE_ASSERT(false);
139 }
140
141 // resources
142
143 {
144 gl.genBuffers(1, &m_buffer);
145 GLU_EXPECT_NO_ERROR(gl.getError(), "gen buf");
146
147 setupRenderData();
148 GLU_EXPECT_NO_ERROR(gl.getError(), "setup data");
149
150 gl.genVertexArrays(1, &m_renderVao);
151 GLU_EXPECT_NO_ERROR(gl.getError(), "gen vao");
152
153 // buffer for MSAA texture resolving
154 {
155 static const tcu::Vec4 fullscreenQuad[] = {
156 tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f),
157 tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f),
158 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
159 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
160 };
161
162 gl.genBuffers(1, &m_resolveBuffer);
163 gl.bindBuffer(GL_ARRAY_BUFFER, m_resolveBuffer);
164 gl.bufferData(GL_ARRAY_BUFFER, (int)sizeof(fullscreenQuad), fullscreenQuad, GL_STATIC_DRAW);
165 GLU_EXPECT_NO_ERROR(gl.getError(), "setup data");
166 }
167 }
168
169 // msaa targets
170
171 if (m_renderTarget == TARGET_TEXTURE)
172 {
173 const uint32_t textureTarget = (m_numRequestedSamples == 0) ? (GL_TEXTURE_2D) : (GL_TEXTURE_2D_MULTISAMPLE);
174
175 gl.genVertexArrays(1, &m_resolveVao);
176 GLU_EXPECT_NO_ERROR(gl.getError(), "gen vao");
177
178 gl.genTextures(1, &m_fboTexture);
179 gl.bindTexture(textureTarget, m_fboTexture);
180 if (m_numRequestedSamples == 0)
181 {
182 gl.texStorage2D(textureTarget, 1, GL_RGBA8, m_renderSize, m_renderSize);
183 gl.texParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
184 gl.texParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
185 }
186 else
187 gl.texStorage2DMultisample(textureTarget, m_numRequestedSamples, GL_RGBA8, m_renderSize, m_renderSize,
188 GL_FALSE);
189 GLU_EXPECT_NO_ERROR(gl.getError(), "gen tex");
190
191 gl.genFramebuffers(1, &m_fbo);
192 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
193 gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textureTarget, m_fboTexture, 0);
194 GLU_EXPECT_NO_ERROR(gl.getError(), "gen fbo");
195
196 if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
197 throw tcu::TestError("fbo not complete");
198
199 if (m_numRequestedSamples != 0)
200 {
201 // for shader
202 gl.getTexLevelParameteriv(GL_TEXTURE_2D_MULTISAMPLE, 0, GL_TEXTURE_SAMPLES, &queriedSampleCount);
203
204 // logging
205 m_testCtx.getLog() << tcu::TestLog::Message << "Asked for " << m_numRequestedSamples << " samples, got "
206 << queriedSampleCount << " samples." << tcu::TestLog::EndMessage;
207
208 // sanity
209 if (queriedSampleCount < m_numRequestedSamples)
210 throw tcu::TestError("Got less texture samples than asked for");
211 }
212
213 // texture sampler shader
214 m_textureSamplerProgram = new glu::ShaderProgram(
215 m_context.getRenderContext(), glu::ProgramSources()
216 << glu::VertexSource(tcu::StringTemplate(s_vertexSource).specialize(args))
217 << glu::FragmentSource(genMSSamplerSource(queriedSampleCount)));
218 if (!m_textureSamplerProgram->isOk())
219 {
220 m_testCtx.getLog() << tcu::TestLog::Section("SamplerShader", "Sampler shader") << *m_textureSamplerProgram
221 << tcu::TestLog::EndSection;
222 throw tcu::TestError("could not build program");
223 }
224 }
225 else if (m_renderTarget == TARGET_RENDERBUFFER)
226 {
227 gl.genRenderbuffers(1, &m_fboRbo);
228 gl.bindRenderbuffer(GL_RENDERBUFFER, m_fboRbo);
229 gl.renderbufferStorageMultisample(GL_RENDERBUFFER, m_numRequestedSamples, GL_RGBA8, m_renderSize, m_renderSize);
230 GLU_EXPECT_NO_ERROR(gl.getError(), "gen rbo");
231
232 gl.genFramebuffers(1, &m_fbo);
233 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
234 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_fboRbo);
235 GLU_EXPECT_NO_ERROR(gl.getError(), "gen fbo");
236
237 if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
238 throw tcu::TestError("fbo not complete");
239
240 // logging
241 gl.getRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &queriedSampleCount);
242 m_testCtx.getLog() << tcu::TestLog::Message << "Asked for " << m_numRequestedSamples << " samples, got "
243 << queriedSampleCount << " samples." << tcu::TestLog::EndMessage;
244
245 // sanity
246 if (queriedSampleCount < m_numRequestedSamples)
247 throw tcu::TestError("Got less renderbuffer samples samples than asked for");
248 }
249
250 // fbo for resolving the multisample fbo
251 if (m_renderTarget != TARGET_DEFAULT)
252 {
253 gl.genTextures(1, &m_resolveFboTexture);
254 gl.bindTexture(GL_TEXTURE_2D, m_resolveFboTexture);
255 gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, m_renderSize, m_renderSize);
256 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
257 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
258 GLU_EXPECT_NO_ERROR(gl.getError(), "gen tex");
259
260 gl.genFramebuffers(1, &m_resolveFbo);
261 gl.bindFramebuffer(GL_FRAMEBUFFER, m_resolveFbo);
262 gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_resolveFboTexture, 0);
263 GLU_EXPECT_NO_ERROR(gl.getError(), "gen fbo");
264
265 if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
266 throw tcu::TestError("resolve fbo not complete");
267 }
268
269 // create verifier shader and set targetSampleCount
270
271 {
272 int realSampleCount = -1;
273
274 if (m_renderTarget == TARGET_TEXTURE)
275 {
276 if (m_numRequestedSamples == 0)
277 realSampleCount = 1; // non msaa texture
278 else
279 realSampleCount = de::max(1, queriedSampleCount); // msaa texture
280 }
281 else if (m_renderTarget == TARGET_RENDERBUFFER)
282 {
283 realSampleCount = de::max(1, queriedSampleCount); // msaa rbo
284 }
285 else if (m_renderTarget == TARGET_DEFAULT)
286 {
287 realSampleCount = de::max(1, m_context.getRenderTarget().getNumSamples());
288 }
289 else
290 DE_ASSERT(false);
291
292 // is set and is valid
293 DE_ASSERT(realSampleCount != -1);
294 DE_ASSERT(realSampleCount != 0);
295 m_numTargetSamples = realSampleCount;
296 }
297
298 if (!m_perIterationShader)
299 {
300 m_program =
301 new glu::ShaderProgram(m_context.getRenderContext(),
302 glu::ProgramSources() << glu::VertexSource(genVertexSource(m_numTargetSamples))
303 << glu::FragmentSource(genFragmentSource(m_numTargetSamples)));
304 m_testCtx.getLog() << tcu::TestLog::Section("RenderShader", "Render shader") << *m_program
305 << tcu::TestLog::EndSection;
306 if (!m_program->isOk())
307 throw tcu::TestError("could not build program");
308 }
309 }
310
deinit(void)311 void MultisampleRenderCase::deinit(void)
312 {
313 if (m_buffer)
314 {
315 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_buffer);
316 m_buffer = 0;
317 }
318
319 if (m_resolveBuffer)
320 {
321 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_resolveBuffer);
322 m_resolveBuffer = 0;
323 }
324
325 delete m_program;
326 m_program = DE_NULL;
327
328 if (m_fbo)
329 {
330 m_context.getRenderContext().getFunctions().deleteFramebuffers(1, &m_fbo);
331 m_fbo = 0;
332 }
333
334 if (m_fboTexture)
335 {
336 m_context.getRenderContext().getFunctions().deleteTextures(1, &m_fboTexture);
337 m_fboTexture = 0;
338 }
339
340 delete m_textureSamplerProgram;
341 m_textureSamplerProgram = DE_NULL;
342
343 if (m_fboRbo)
344 {
345 m_context.getRenderContext().getFunctions().deleteRenderbuffers(1, &m_fboRbo);
346 m_fboRbo = 0;
347 }
348
349 if (m_resolveFbo)
350 {
351 m_context.getRenderContext().getFunctions().deleteFramebuffers(1, &m_resolveFbo);
352 m_resolveFbo = 0;
353 }
354
355 if (m_resolveFboTexture)
356 {
357 m_context.getRenderContext().getFunctions().deleteTextures(1, &m_resolveFboTexture);
358 m_resolveFboTexture = 0;
359 }
360
361 if (m_renderVao)
362 {
363 m_context.getRenderContext().getFunctions().deleteVertexArrays(1, &m_renderVao);
364 m_renderVao = 0;
365 }
366
367 if (m_resolveVao)
368 {
369 m_context.getRenderContext().getFunctions().deleteVertexArrays(1, &m_resolveVao);
370 m_resolveVao = 0;
371 }
372 }
373
iterate(void)374 MultisampleRenderCase::IterateResult MultisampleRenderCase::iterate(void)
375 {
376 // default value
377 if (m_iteration == 0)
378 {
379 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
380 preTest();
381 }
382
383 drawOneIteration();
384
385 // next iteration
386 ++m_iteration;
387 if (m_iteration < m_numIterations)
388 return CONTINUE;
389 else
390 {
391 postTest();
392 return STOP;
393 }
394 }
395
preDraw(void)396 void MultisampleRenderCase::preDraw(void)
397 {
398 }
399
postDraw(void)400 void MultisampleRenderCase::postDraw(void)
401 {
402 }
403
preTest(void)404 void MultisampleRenderCase::preTest(void)
405 {
406 }
407
postTest(void)408 void MultisampleRenderCase::postTest(void)
409 {
410 }
411
verifyResultImageAndSetResult(const tcu::Surface & resultImage)412 void MultisampleRenderCase::verifyResultImageAndSetResult(const tcu::Surface &resultImage)
413 {
414 // verify using case-specific verification
415
416 try
417 {
418 if (!verifyImage(resultImage))
419 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
420 }
421 catch (const QualityWarning &ex)
422 {
423 m_testCtx.getLog() << tcu::TestLog::Message << "Quality warning, error = " << ex.what()
424 << tcu::TestLog::EndMessage;
425
426 // Failures are more important than warnings
427 if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
428 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, ex.what());
429 }
430 }
431
verifyResultBuffersAndSetResult(const std::vector<tcu::Surface> & resultBuffers)432 void MultisampleRenderCase::verifyResultBuffersAndSetResult(const std::vector<tcu::Surface> &resultBuffers)
433 {
434 // verify using case-specific verification
435
436 try
437 {
438 if (!verifySampleBuffers(resultBuffers))
439 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
440 }
441 catch (const QualityWarning &ex)
442 {
443 m_testCtx.getLog() << tcu::TestLog::Message << "Quality warning, error = " << ex.what()
444 << tcu::TestLog::EndMessage;
445
446 // Failures are more important than warnings
447 if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
448 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, ex.what());
449 }
450 }
451
getIterationDescription(int iteration) const452 std::string MultisampleRenderCase::getIterationDescription(int iteration) const
453 {
454 DE_UNREF(iteration);
455 DE_ASSERT(false);
456 return "";
457 }
458
drawOneIteration(void)459 void MultisampleRenderCase::drawOneIteration(void)
460 {
461 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
462 const std::string sectionDescription =
463 (m_numIterations > 1) ? ("Iteration " + de::toString(m_iteration + 1) + "/" + de::toString(m_numIterations) +
464 ": " + getIterationDescription(m_iteration)) :
465 ("Test");
466 const tcu::ScopedLogSection section(m_testCtx.getLog(), "Iteration" + de::toString(m_iteration),
467 sectionDescription);
468
469 // Per iteration shader?
470 if (m_perIterationShader)
471 {
472 delete m_program;
473 m_program = DE_NULL;
474
475 m_program =
476 new glu::ShaderProgram(m_context.getRenderContext(),
477 glu::ProgramSources() << glu::VertexSource(genVertexSource(m_numTargetSamples))
478 << glu::FragmentSource(genFragmentSource(m_numTargetSamples)));
479 m_testCtx.getLog() << tcu::TestLog::Section("RenderShader", "Render shader") << *m_program
480 << tcu::TestLog::EndSection;
481 if (!m_program->isOk())
482 throw tcu::TestError("could not build program");
483 }
484
485 // render
486 {
487 if (m_renderTarget == TARGET_TEXTURE || m_renderTarget == TARGET_RENDERBUFFER)
488 {
489 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
490 GLU_EXPECT_NO_ERROR(gl.getError(), "bind fbo");
491
492 m_testCtx.getLog() << tcu::TestLog::Message << "Rendering " << m_renderSceneDescription
493 << " with render shader to fbo." << tcu::TestLog::EndMessage;
494 }
495 else
496 m_testCtx.getLog() << tcu::TestLog::Message << "Rendering " << m_renderSceneDescription
497 << " with render shader to default framebuffer." << tcu::TestLog::EndMessage;
498
499 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
500 gl.clear(GL_COLOR_BUFFER_BIT);
501 gl.viewport(0, 0, m_renderSize, m_renderSize);
502 GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
503
504 gl.bindVertexArray(m_renderVao);
505 gl.bindBuffer(GL_ARRAY_BUFFER, m_buffer);
506
507 // set attribs
508 DE_ASSERT(!m_renderAttribs.empty());
509 for (std::map<std::string, Attrib>::const_iterator it = m_renderAttribs.begin(); it != m_renderAttribs.end();
510 ++it)
511 {
512 const int32_t location = gl.getAttribLocation(m_program->getProgram(), it->first.c_str());
513
514 if (location != -1)
515 {
516 gl.vertexAttribPointer(location, 4, GL_FLOAT, GL_FALSE, it->second.stride,
517 glu::BufferOffsetAsPointer(it->second.offset));
518 gl.enableVertexAttribArray(location);
519 }
520 }
521 GLU_EXPECT_NO_ERROR(gl.getError(), "set attrib");
522
523 gl.useProgram(m_program->getProgram());
524 preDraw();
525 gl.drawArrays(m_renderMode, 0, m_renderCount);
526 postDraw();
527 gl.useProgram(0);
528 gl.bindVertexArray(0);
529 GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
530
531 if (m_renderTarget == TARGET_TEXTURE || m_renderTarget == TARGET_RENDERBUFFER)
532 gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
533 }
534
535 // read
536 {
537 if (m_renderTarget == TARGET_DEFAULT)
538 {
539 tcu::Surface resultImage(m_renderSize, m_renderSize);
540
541 m_testCtx.getLog() << tcu::TestLog::Message << "Reading pixels from default framebuffer."
542 << tcu::TestLog::EndMessage;
543
544 // default directly
545 glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
546 GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels");
547
548 // set test result
549 verifyResultImageAndSetResult(resultImage);
550 }
551 else if (m_renderTarget == TARGET_RENDERBUFFER)
552 {
553 tcu::Surface resultImage(m_renderSize, m_renderSize);
554
555 // rbo by blitting to non-multisample fbo
556
557 m_testCtx.getLog() << tcu::TestLog::Message
558 << "Blitting result from fbo to single sample fbo. (Resolve multisample)"
559 << tcu::TestLog::EndMessage;
560
561 gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo);
562 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_resolveFbo);
563 gl.blitFramebuffer(0, 0, m_renderSize, m_renderSize, 0, 0, m_renderSize, m_renderSize, GL_COLOR_BUFFER_BIT,
564 GL_NEAREST);
565 GLU_EXPECT_NO_ERROR(gl.getError(), "blit resolve");
566
567 m_testCtx.getLog() << tcu::TestLog::Message << "Reading pixels from single sample framebuffer."
568 << tcu::TestLog::EndMessage;
569
570 gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_resolveFbo);
571 glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
572 GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels");
573
574 gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
575
576 // set test result
577 verifyResultImageAndSetResult(resultImage);
578 }
579 else if (m_renderTarget == TARGET_TEXTURE && !m_verifyTextureSampleBuffers)
580 {
581 const int32_t posLocation = gl.getAttribLocation(m_textureSamplerProgram->getProgram(), "a_position");
582 const int32_t samplerLocation = gl.getUniformLocation(m_textureSamplerProgram->getProgram(), "u_sampler");
583 const uint32_t textureTarget = (m_numRequestedSamples == 0) ? (GL_TEXTURE_2D) : (GL_TEXTURE_2D_MULTISAMPLE);
584 tcu::Surface resultImage(m_renderSize, m_renderSize);
585
586 if (m_numRequestedSamples)
587 m_testCtx.getLog()
588 << tcu::TestLog::Message
589 << "Using sampler shader to sample the multisample texture to single sample framebuffer."
590 << tcu::TestLog::EndMessage;
591 else
592 m_testCtx.getLog() << tcu::TestLog::Message
593 << "Drawing texture to single sample framebuffer. Using sampler shader."
594 << tcu::TestLog::EndMessage;
595
596 if (samplerLocation == -1)
597 throw tcu::TestError("Location u_sampler was -1.");
598
599 // resolve multisample texture by averaging
600 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
601 gl.clear(GL_COLOR_BUFFER_BIT);
602 gl.viewport(0, 0, m_renderSize, m_renderSize);
603 GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
604
605 gl.bindVertexArray(m_resolveVao);
606 gl.bindBuffer(GL_ARRAY_BUFFER, m_resolveBuffer);
607 gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
608 gl.enableVertexAttribArray(posLocation);
609 GLU_EXPECT_NO_ERROR(gl.getError(), "set attrib");
610
611 gl.activeTexture(GL_TEXTURE0);
612 gl.bindTexture(textureTarget, m_fboTexture);
613 GLU_EXPECT_NO_ERROR(gl.getError(), "bind tex");
614
615 gl.useProgram(m_textureSamplerProgram->getProgram());
616 gl.uniform1i(samplerLocation, 0);
617
618 gl.bindFramebuffer(GL_FRAMEBUFFER, m_resolveFbo);
619 gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
620
621 gl.useProgram(0);
622 gl.bindVertexArray(0);
623 GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
624
625 m_testCtx.getLog() << tcu::TestLog::Message << "Reading pixels from single sample framebuffer."
626 << tcu::TestLog::EndMessage;
627
628 glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
629 GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels");
630
631 gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
632
633 // set test result
634 verifyResultImageAndSetResult(resultImage);
635 }
636 else if (m_renderTarget == TARGET_TEXTURE && m_verifyTextureSampleBuffers)
637 {
638 const int32_t posLocation = gl.getAttribLocation(m_textureSamplerProgram->getProgram(), "a_position");
639 const int32_t samplerLocation = gl.getUniformLocation(m_textureSamplerProgram->getProgram(), "u_sampler");
640 const int32_t sampleLocation = gl.getUniformLocation(m_textureSamplerProgram->getProgram(), "u_sampleNdx");
641 const uint32_t textureTarget = (m_numRequestedSamples == 0) ? (GL_TEXTURE_2D) : (GL_TEXTURE_2D_MULTISAMPLE);
642 std::vector<tcu::Surface> resultBuffers(m_numTargetSamples);
643
644 if (m_numRequestedSamples)
645 m_testCtx.getLog() << tcu::TestLog::Message << "Reading multisample texture sample buffers."
646 << tcu::TestLog::EndMessage;
647 else
648 m_testCtx.getLog() << tcu::TestLog::Message << "Reading texture." << tcu::TestLog::EndMessage;
649
650 if (samplerLocation == -1)
651 throw tcu::TestError("Location u_sampler was -1.");
652 if (sampleLocation == -1)
653 throw tcu::TestError("Location u_sampleNdx was -1.");
654
655 for (int sampleNdx = 0; sampleNdx < m_numTargetSamples; ++sampleNdx)
656 resultBuffers[sampleNdx].setSize(m_renderSize, m_renderSize);
657
658 // read sample buffers to different surfaces
659 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
660 gl.clear(GL_COLOR_BUFFER_BIT);
661 gl.viewport(0, 0, m_renderSize, m_renderSize);
662 GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
663
664 gl.bindVertexArray(m_resolveVao);
665 gl.bindBuffer(GL_ARRAY_BUFFER, m_resolveBuffer);
666 gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
667 gl.enableVertexAttribArray(posLocation);
668 GLU_EXPECT_NO_ERROR(gl.getError(), "set attrib");
669
670 gl.activeTexture(GL_TEXTURE0);
671 gl.bindTexture(textureTarget, m_fboTexture);
672 GLU_EXPECT_NO_ERROR(gl.getError(), "bind tex");
673
674 gl.bindFramebuffer(GL_FRAMEBUFFER, m_resolveFbo);
675 gl.useProgram(m_textureSamplerProgram->getProgram());
676 gl.uniform1i(samplerLocation, 0);
677
678 m_testCtx.getLog() << tcu::TestLog::Message << "Reading sample buffers" << tcu::TestLog::EndMessage;
679
680 for (int sampleNdx = 0; sampleNdx < m_numTargetSamples; ++sampleNdx)
681 {
682 gl.uniform1i(sampleLocation, sampleNdx);
683 gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
684 GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
685
686 glu::readPixels(m_context.getRenderContext(), 0, 0, resultBuffers[sampleNdx].getAccess());
687 GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels");
688 }
689
690 gl.useProgram(0);
691 gl.bindVertexArray(0);
692 gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
693
694 // verify sample buffers
695 verifyResultBuffersAndSetResult(resultBuffers);
696 }
697 else
698 DE_ASSERT(false);
699 }
700 }
701
genVertexSource(int numTargetSamples) const702 std::string MultisampleRenderCase::genVertexSource(int numTargetSamples) const
703 {
704 const bool supportsES32orGL45 =
705 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) ||
706 glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
707
708 map<string, string> args;
709
710 args["GLSL_VERSION_DECL"] = supportsES32orGL45 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) :
711 getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
712
713 DE_UNREF(numTargetSamples);
714 return std::string(tcu::StringTemplate(s_vertexSource).specialize(args));
715 }
716
genMSSamplerSource(int numTargetSamples) const717 std::string MultisampleRenderCase::genMSSamplerSource(int numTargetSamples) const
718 {
719 if (m_verifyTextureSampleBuffers)
720 return genMSTextureLayerFetchSource(numTargetSamples);
721 else
722 return genMSTextureResolverSource(numTargetSamples);
723 }
724
genMSTextureResolverSource(int numTargetSamples) const725 std::string MultisampleRenderCase::genMSTextureResolverSource(int numTargetSamples) const
726 {
727 // default behavior: average
728
729 const bool supportsES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
730 map<string, string> args;
731 const bool isSingleSampleTarget = (m_numRequestedSamples == 0);
732 std::ostringstream buf;
733
734 args["GLSL_VERSION_DECL"] = supportsES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) :
735 getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
736
737 buf << "${GLSL_VERSION_DECL}\n"
738 "in mediump vec4 v_position;\n"
739 "layout(location = 0) out mediump vec4 fragColor;\n"
740 "uniform mediump "
741 << ((isSingleSampleTarget) ? ("sampler2D") : ("sampler2DMS"))
742 << " u_sampler;\n"
743 "void main (void)\n"
744 "{\n"
745 " mediump vec2 relPosition = (v_position.xy + vec2(1.0, 1.0)) / 2.0;\n"
746 " mediump ivec2 fetchPos = ivec2(floor(relPosition * "
747 << m_renderSize
748 << ".0));\n"
749 " mediump vec4 colorSum = vec4(0.0, 0.0, 0.0, 0.0);\n"
750 "\n";
751
752 if (isSingleSampleTarget)
753 buf << " colorSum = texelFetch(u_sampler, fetchPos, 0);\n"
754 "\n";
755 else
756 buf << " for (int sampleNdx = 0; sampleNdx < " << numTargetSamples
757 << "; ++sampleNdx)\n"
758 " colorSum += texelFetch(u_sampler, fetchPos, sampleNdx);\n"
759 " colorSum /= "
760 << numTargetSamples
761 << ".0;\n"
762 "\n";
763
764 buf << " fragColor = vec4(colorSum.xyz, 1.0);\n"
765 "}\n";
766
767 return tcu::StringTemplate(buf.str()).specialize(args);
768 }
769
genMSTextureLayerFetchSource(int numTargetSamples) const770 std::string MultisampleRenderCase::genMSTextureLayerFetchSource(int numTargetSamples) const
771 {
772 DE_UNREF(numTargetSamples);
773
774 const bool supportsES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
775 map<string, string> args;
776 const bool isSingleSampleTarget = (m_numRequestedSamples == 0);
777 std::ostringstream buf;
778
779 args["GLSL_VERSION_DECL"] = supportsES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) :
780 getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
781
782 buf << "${GLSL_VERSION_DECL}\n"
783 "in mediump vec4 v_position;\n"
784 "layout(location = 0) out mediump vec4 fragColor;\n"
785 "uniform mediump "
786 << ((isSingleSampleTarget) ? ("sampler2D") : ("sampler2DMS"))
787 << " u_sampler;\n"
788 "uniform mediump int u_sampleNdx;\n"
789 "void main (void)\n"
790 "{\n"
791 " mediump vec2 relPosition = (v_position.xy + vec2(1.0, 1.0)) / 2.0;\n"
792 " mediump ivec2 fetchPos = ivec2(floor(relPosition * "
793 << m_renderSize
794 << ".0));\n"
795 "\n"
796 " mediump vec4 color = texelFetch(u_sampler, fetchPos, u_sampleNdx);\n"
797 " fragColor = vec4(color.rgb, 1.0);\n"
798 "}\n";
799
800 return tcu::StringTemplate(buf.str()).specialize(args);
801 }
802
verifySampleBuffers(const std::vector<tcu::Surface> & resultBuffers)803 bool MultisampleRenderCase::verifySampleBuffers(const std::vector<tcu::Surface> &resultBuffers)
804 {
805 DE_UNREF(resultBuffers);
806 DE_ASSERT(false);
807 return false;
808 }
809
setupRenderData(void)810 void MultisampleRenderCase::setupRenderData(void)
811 {
812 static const tcu::Vec4 fullscreenQuad[] = {
813 tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f),
814 tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f),
815 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
816 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
817 };
818
819 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
820
821 m_renderMode = GL_TRIANGLE_STRIP;
822 m_renderCount = 4;
823 m_renderSceneDescription = "quad";
824
825 m_renderAttribs["a_position"].offset = 0;
826 m_renderAttribs["a_position"].stride = sizeof(float[4]);
827
828 gl.bindBuffer(GL_ARRAY_BUFFER, m_buffer);
829 gl.bufferData(GL_ARRAY_BUFFER, (int)sizeof(fullscreenQuad), fullscreenQuad, GL_STATIC_DRAW);
830 }
831
getMaxConformantSampleCount(glw::GLenum target,glw::GLenum internalFormat)832 glw::GLint MultisampleRenderCase::getMaxConformantSampleCount(glw::GLenum target, glw::GLenum internalFormat)
833 {
834 int32_t maxTextureSamples = 0;
835 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
836
837 if (m_context.getContextInfo().isExtensionSupported("GL_NV_internalformat_sample_query"))
838 {
839 glw::GLint gl_sample_counts = 0;
840 gl.getInternalformativ(target, internalFormat, GL_NUM_SAMPLE_COUNTS, 1, &gl_sample_counts);
841 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetInternalformativ() failed for GL_NUM_SAMPLE_COUNTS pname");
842
843 /* Check and return the first conformant sample count */
844 glw::GLint *gl_supported_samples = new glw::GLint[gl_sample_counts];
845 if (gl_supported_samples)
846 {
847 gl.getInternalformativ(target, internalFormat, GL_SAMPLES, gl_sample_counts, gl_supported_samples);
848
849 for (glw::GLint i = 0; i < gl_sample_counts; i++)
850 {
851 glw::GLint isConformant = 0;
852 gl.getInternalformatSampleivNV(target, internalFormat, gl_supported_samples[i], GL_CONFORMANT_NV, 1,
853 &isConformant);
854 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetInternalformatSampleivNV() call(s) failed");
855
856 if (isConformant && gl_supported_samples[i] > maxTextureSamples)
857 {
858 maxTextureSamples = gl_supported_samples[i];
859 }
860 }
861 delete[] gl_supported_samples;
862 }
863 }
864 else
865 {
866 gl.getInternalformativ(target, internalFormat, GL_SAMPLES, 1, &maxTextureSamples);
867 }
868
869 return maxTextureSamples;
870 }
871
872 } // namespace MultisampleShaderRenderUtil
873 } // namespace Functional
874 } // namespace gles31
875 } // namespace deqp
876