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