xref: /aosp_15_r20/external/deqp/modules/gles31/functional/es31fMultisampleShaderRenderCase.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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