xref: /aosp_15_r20/external/deqp/modules/gles3/functional/es3fFboMultisampleTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.0 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 FBO multisample tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es3fApiCase.hpp"
25 #include "es3fFboMultisampleTests.hpp"
26 #include "es3fFboTestCase.hpp"
27 #include "es3fFboTestUtil.hpp"
28 #include "gluTextureUtil.hpp"
29 #include "tcuImageCompare.hpp"
30 #include "tcuTextureUtil.hpp"
31 #include "tcuTestLog.hpp"
32 #include "deStringUtil.hpp"
33 #include "deRandom.hpp"
34 #include "sglrContextUtil.hpp"
35 #include "glwEnums.hpp"
36 
37 namespace deqp
38 {
39 namespace gles3
40 {
41 namespace Functional
42 {
43 
44 using std::string;
45 using tcu::IVec2;
46 using tcu::IVec3;
47 using tcu::IVec4;
48 using tcu::TestLog;
49 using tcu::UVec4;
50 using tcu::Vec2;
51 using tcu::Vec3;
52 using tcu::Vec4;
53 using namespace FboTestUtil;
54 
55 class BasicFboMultisampleCase : public FboTestCase
56 {
57 public:
BasicFboMultisampleCase(Context & context,const char * name,const char * desc,uint32_t colorFormat,uint32_t depthStencilFormat,const IVec2 & size,int numSamples)58     BasicFboMultisampleCase(Context &context, const char *name, const char *desc, uint32_t colorFormat,
59                             uint32_t depthStencilFormat, const IVec2 &size, int numSamples)
60         : FboTestCase(context, name, desc)
61         , m_colorFormat(colorFormat)
62         , m_depthStencilFormat(depthStencilFormat)
63         , m_size(size)
64         , m_numSamples(numSamples)
65     {
66     }
67 
68 protected:
preCheck(void)69     void preCheck(void)
70     {
71         checkFormatSupport(m_colorFormat);
72         checkSampleCount(m_colorFormat, m_numSamples);
73 
74         if (m_depthStencilFormat != GL_NONE)
75         {
76             checkFormatSupport(m_depthStencilFormat);
77             checkSampleCount(m_depthStencilFormat, m_numSamples);
78         }
79     }
80 
render(tcu::Surface & dst)81     void render(tcu::Surface &dst)
82     {
83         tcu::TextureFormat colorFmt = glu::mapGLInternalFormat(m_colorFormat);
84         tcu::TextureFormat depthStencilFmt =
85             m_depthStencilFormat != GL_NONE ? glu::mapGLInternalFormat(m_depthStencilFormat) : tcu::TextureFormat();
86         tcu::TextureFormatInfo colorFmtInfo = tcu::getTextureFormatInfo(colorFmt);
87         bool depth = depthStencilFmt.order == tcu::TextureFormat::D || depthStencilFmt.order == tcu::TextureFormat::DS;
88         bool stencil =
89             depthStencilFmt.order == tcu::TextureFormat::S || depthStencilFmt.order == tcu::TextureFormat::DS;
90         GradientShader gradShader(getFragmentOutputType(colorFmt));
91         FlatColorShader flatShader(getFragmentOutputType(colorFmt));
92         uint32_t gradShaderID           = getCurrentContext()->createProgram(&gradShader);
93         uint32_t flatShaderID           = getCurrentContext()->createProgram(&flatShader);
94         uint32_t msaaFbo                = 0;
95         uint32_t resolveFbo             = 0;
96         uint32_t msaaColorRbo           = 0;
97         uint32_t resolveColorRbo        = 0;
98         uint32_t msaaDepthStencilRbo    = 0;
99         uint32_t resolveDepthStencilRbo = 0;
100 
101         // Create framebuffers.
102         for (int ndx = 0; ndx < 2; ndx++)
103         {
104             uint32_t &fbo             = ndx ? resolveFbo : msaaFbo;
105             uint32_t &colorRbo        = ndx ? resolveColorRbo : msaaColorRbo;
106             uint32_t &depthStencilRbo = ndx ? resolveDepthStencilRbo : msaaDepthStencilRbo;
107             int samples               = ndx ? 0 : m_numSamples;
108 
109             glGenRenderbuffers(1, &colorRbo);
110             glBindRenderbuffer(GL_RENDERBUFFER, colorRbo);
111             glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, m_colorFormat, m_size.x(), m_size.y());
112 
113             if (depth || stencil)
114             {
115                 glGenRenderbuffers(1, &depthStencilRbo);
116                 glBindRenderbuffer(GL_RENDERBUFFER, depthStencilRbo);
117                 glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, m_depthStencilFormat, m_size.x(),
118                                                  m_size.y());
119             }
120 
121             glGenFramebuffers(1, &fbo);
122             glBindFramebuffer(GL_FRAMEBUFFER, fbo);
123             glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRbo);
124             if (depth)
125                 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthStencilRbo);
126             if (stencil)
127                 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthStencilRbo);
128 
129             checkError();
130             checkFramebufferStatus(GL_FRAMEBUFFER);
131         }
132 
133         glBindFramebuffer(GL_FRAMEBUFFER, msaaFbo);
134         glViewport(0, 0, m_size.x(), m_size.y());
135 
136         // Clear depth and stencil buffers.
137         glClearBufferfi(GL_DEPTH_STENCIL, 0, 1.0f, 0);
138 
139         // Fill MSAA fbo with gradient, depth = [-1..1]
140         glEnable(GL_DEPTH_TEST);
141         gradShader.setGradient(*getCurrentContext(), gradShaderID, colorFmtInfo.valueMin, colorFmtInfo.valueMax);
142         sglr::drawQuad(*getCurrentContext(), gradShaderID, Vec3(-1.0f, -1.0f, -1.0f), Vec3(1.0f, 1.0f, 1.0f));
143 
144         // Render random-colored quads.
145         {
146             const int numQuads = 8;
147             de::Random rnd(9);
148 
149             glDepthFunc(GL_ALWAYS);
150             glEnable(GL_STENCIL_TEST);
151             glStencilFunc(GL_ALWAYS, 0, 0xffu);
152             glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
153 
154             for (int ndx = 0; ndx < numQuads; ndx++)
155             {
156                 float r  = rnd.getFloat();
157                 float g  = rnd.getFloat();
158                 float b  = rnd.getFloat();
159                 float a  = rnd.getFloat();
160                 float x0 = rnd.getFloat(-1.0f, 1.0f);
161                 float y0 = rnd.getFloat(-1.0f, 1.0f);
162                 float z0 = rnd.getFloat(-1.0f, 1.0f);
163                 float x1 = rnd.getFloat(-1.0f, 1.0f);
164                 float y1 = rnd.getFloat(-1.0f, 1.0f);
165                 float z1 = rnd.getFloat(-1.0f, 1.0f);
166 
167                 flatShader.setColor(*getCurrentContext(), flatShaderID,
168                                     Vec4(r, g, b, a) * (colorFmtInfo.valueMax - colorFmtInfo.valueMin) +
169                                         colorFmtInfo.valueMin);
170                 sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(x0, y0, z0), Vec3(x1, y1, z1));
171             }
172         }
173 
174         glDisable(GL_DEPTH_TEST);
175         glDisable(GL_STENCIL_TEST);
176         checkError();
177 
178         // Resolve using glBlitFramebuffer().
179         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFbo);
180         glBlitFramebuffer(0, 0, m_size.x(), m_size.y(), 0, 0, m_size.x(), m_size.y(),
181                           GL_COLOR_BUFFER_BIT | (depth ? GL_DEPTH_BUFFER_BIT : 0) |
182                               (stencil ? GL_STENCIL_BUFFER_BIT : 0),
183                           GL_NEAREST);
184 
185         glBindFramebuffer(GL_READ_FRAMEBUFFER, resolveFbo);
186 
187         if (depth)
188         {
189             // Visualize depth.
190             const int numSteps = 8;
191             const float step   = 2.0f / (float)numSteps;
192 
193             glEnable(GL_DEPTH_TEST);
194             glDepthFunc(GL_LESS);
195             glDepthMask(GL_FALSE);
196             glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_FALSE);
197 
198             for (int ndx = 0; ndx < numSteps; ndx++)
199             {
200                 float d = -1.0f + step * (float)ndx;
201                 float c = (float)ndx / (float)(numSteps - 1);
202 
203                 flatShader.setColor(*getCurrentContext(), flatShaderID,
204                                     Vec4(0.0f, 0.0f, c, 1.0f) * (colorFmtInfo.valueMax - colorFmtInfo.valueMin) +
205                                         colorFmtInfo.valueMin);
206                 sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(-1.0f, -1.0f, d), Vec3(1.0f, 1.0f, d));
207             }
208 
209             glDisable(GL_DEPTH_TEST);
210         }
211 
212         if (stencil)
213         {
214             // Visualize stencil.
215             const int numSteps = 4;
216             const int step     = 1;
217 
218             glEnable(GL_STENCIL_TEST);
219             glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
220             glColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_FALSE);
221 
222             for (int ndx = 0; ndx < numSteps; ndx++)
223             {
224                 int s   = step * ndx;
225                 float c = (float)ndx / (float)(numSteps - 1);
226 
227                 glStencilFunc(GL_EQUAL, s, 0xffu);
228 
229                 flatShader.setColor(*getCurrentContext(), flatShaderID,
230                                     Vec4(0.0f, c, 0.0f, 1.0f) * (colorFmtInfo.valueMax - colorFmtInfo.valueMin) +
231                                         colorFmtInfo.valueMin);
232                 sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
233             }
234 
235             glDisable(GL_STENCIL_TEST);
236         }
237 
238         readPixels(dst, 0, 0, m_size.x(), m_size.y(), colorFmt, colorFmtInfo.lookupScale, colorFmtInfo.lookupBias);
239     }
240 
colorCompare(const tcu::Surface & reference,const tcu::Surface & result)241     bool colorCompare(const tcu::Surface &reference, const tcu::Surface &result)
242     {
243         const tcu::RGBA threshold(tcu::max(getFormatThreshold(m_colorFormat), tcu::RGBA(12, 12, 12, 12)));
244 
245         return tcu::bilinearCompare(m_testCtx.getLog(), "Result", "Image comparison result", reference.getAccess(),
246                                     result.getAccess(), threshold, tcu::COMPARE_LOG_RESULT);
247     }
248 
compare(const tcu::Surface & reference,const tcu::Surface & result)249     bool compare(const tcu::Surface &reference, const tcu::Surface &result)
250     {
251         if (m_depthStencilFormat != GL_NONE)
252             return FboTestCase::compare(reference, result);
253         else
254             return colorCompare(reference, result);
255     }
256 
257 private:
258     uint32_t m_colorFormat;
259     uint32_t m_depthStencilFormat;
260     IVec2 m_size;
261     int m_numSamples;
262 };
263 
264 // Ported from WebGL [1], originally written to test a Qualcomm driver bug [2].
265 // [1] https://github.com/KhronosGroup/WebGL/blob/main/sdk/tests/conformance2/renderbuffers/multisampled-renderbuffer-initialization.html
266 // [2] http://crbug.com/696126
267 class RenderbufferResizeCase : public ApiCase
268 {
269 public:
RenderbufferResizeCase(Context & context,const char * name,const char * desc,bool multisampled1,bool multisampled2)270     RenderbufferResizeCase(Context &context, const char *name, const char *desc, bool multisampled1, bool multisampled2)
271         : ApiCase(context, name, desc)
272         , m_multisampled1(multisampled1)
273         , m_multisampled2(multisampled2)
274     {
275     }
276 
277 protected:
test()278     void test()
279     {
280         glDisable(GL_DEPTH_TEST);
281 
282         int maxSamples = 0;
283         glGetInternalformativ(GL_RENDERBUFFER, GL_RGBA8, GL_SAMPLES, 1, &maxSamples);
284         uint32_t samp1 = m_multisampled1 ? maxSamples : 0;
285         uint32_t samp2 = m_multisampled2 ? maxSamples : 0;
286 
287         static const uint32_t W1 = 10, H1 = 10;
288         static const uint32_t W2 = 40, H2 = 40;
289 
290         // Set up non-multisampled buffer to blit to and read back from.
291         uint32_t fboResolve = 0;
292         uint32_t rboResolve = 0;
293         {
294             glGenFramebuffers(1, &fboResolve);
295             glBindFramebuffer(GL_FRAMEBUFFER, fboResolve);
296             glGenRenderbuffers(1, &rboResolve);
297             glBindRenderbuffer(GL_RENDERBUFFER, rboResolve);
298             glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, W2, H2);
299             glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rboResolve);
300             TCU_CHECK(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
301             glClearBufferfv(GL_COLOR, 0, Vec4(1.0f, 0.0f, 0.0f, 1.0f).getPtr());
302         }
303         expectError(GL_NO_ERROR);
304 
305         // Set up multisampled buffer to test.
306         uint32_t fboMultisampled = 0;
307         uint32_t rboMultisampled = 0;
308         {
309             glGenFramebuffers(1, &fboMultisampled);
310             glBindFramebuffer(GL_FRAMEBUFFER, fboMultisampled);
311             glGenRenderbuffers(1, &rboMultisampled);
312             glBindRenderbuffer(GL_RENDERBUFFER, rboMultisampled);
313             // Allocate,
314             glRenderbufferStorageMultisample(GL_RENDERBUFFER, samp1, GL_RGBA8, W1, H1);
315             // attach,
316             glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rboMultisampled);
317             TCU_CHECK(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
318             glClearBufferfv(GL_COLOR, 0, Vec4(0.0f, 0.0f, 1.0f, 1.0f).getPtr());
319             // and allocate again with different parameters.
320             glRenderbufferStorageMultisample(GL_RENDERBUFFER, samp2, GL_RGBA8, W2, H2);
321             TCU_CHECK(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
322             glClearBufferfv(GL_COLOR, 0, Vec4(0.0f, 1.0f, 0.0f, 1.0f).getPtr());
323         }
324         expectError(GL_NO_ERROR);
325 
326         // This is a blit from the multisampled buffer to the non-multisampled buffer.
327         glBindFramebuffer(GL_READ_FRAMEBUFFER, fboMultisampled);
328         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboResolve);
329         // Blit color from fboMultisampled (should be green) to fboResolve (should currently be red).
330         glBlitFramebuffer(0, 0, W2, H2, 0, 0, W2, H2, GL_COLOR_BUFFER_BIT, GL_NEAREST);
331         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
332         expectError(GL_NO_ERROR);
333 
334         // fboResolve should now be green.
335         glBindFramebuffer(GL_READ_FRAMEBUFFER, fboResolve);
336         uint32_t pixels[W2 * H2] = {};
337         glReadPixels(0, 0, W2, H2, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
338         expectError(GL_NO_ERROR);
339 
340         const tcu::RGBA threshold(tcu::max(getFormatThreshold(GL_RGBA8), tcu::RGBA(12, 12, 12, 12)));
341         for (uint32_t y = 0; y < H2; ++y)
342         {
343             for (uint32_t x = 0; x < W2; ++x)
344             {
345                 tcu::RGBA color(pixels[y * W2 + x]);
346                 TCU_CHECK(compareThreshold(color, tcu::RGBA::green(), threshold));
347             }
348         }
349     }
350 
351 private:
352     bool m_multisampled1;
353     bool m_multisampled2;
354 };
355 
FboMultisampleTests(Context & context)356 FboMultisampleTests::FboMultisampleTests(Context &context) : TestCaseGroup(context, "msaa", "Multisample FBO tests")
357 {
358 }
359 
~FboMultisampleTests(void)360 FboMultisampleTests::~FboMultisampleTests(void)
361 {
362 }
363 
init(void)364 void FboMultisampleTests::init(void)
365 {
366     static const uint32_t colorFormats[] = {// RGBA formats
367                                             GL_RGBA8, GL_SRGB8_ALPHA8, GL_RGB10_A2, GL_RGBA4, GL_RGB5_A1,
368 
369                                             // RGB formats
370                                             GL_RGB8, GL_RGB565,
371 
372                                             // RG formats
373                                             GL_RG8,
374 
375                                             // R formats
376                                             GL_R8,
377 
378                                             // GL_EXT_color_buffer_float
379                                             GL_RGBA32F, GL_RGBA16F, GL_R11F_G11F_B10F, GL_RG32F, GL_RG16F, GL_R32F,
380                                             GL_R16F};
381 
382     static const uint32_t depthStencilFormats[] = {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT16,
383                                                    GL_DEPTH32F_STENCIL8,  GL_DEPTH24_STENCIL8,  GL_STENCIL_INDEX8};
384 
385     static const int sampleCounts[] = {2, 4, 8};
386 
387     for (int sampleCntNdx = 0; sampleCntNdx < DE_LENGTH_OF_ARRAY(sampleCounts); sampleCntNdx++)
388     {
389         int samples = sampleCounts[sampleCntNdx];
390         tcu::TestCaseGroup *sampleCountGroup =
391             new tcu::TestCaseGroup(m_testCtx, (de::toString(samples) + "_samples").c_str(), "");
392         addChild(sampleCountGroup);
393 
394         // Color formats.
395         for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++)
396             sampleCountGroup->addChild(new BasicFboMultisampleCase(m_context, getFormatName(colorFormats[fmtNdx]), "",
397                                                                    colorFormats[fmtNdx], GL_NONE, IVec2(119, 131),
398                                                                    samples));
399 
400         // Depth/stencil formats.
401         for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(depthStencilFormats); fmtNdx++)
402             sampleCountGroup->addChild(
403                 new BasicFboMultisampleCase(m_context, getFormatName(depthStencilFormats[fmtNdx]), "", GL_RGBA8,
404                                             depthStencilFormats[fmtNdx], IVec2(119, 131), samples));
405     }
406 
407     // .renderbuffer_resize
408     {
409         tcu::TestCaseGroup *group =
410             new tcu::TestCaseGroup(m_testCtx, "renderbuffer_resize", "Multisample renderbuffer resize");
411         addChild(group);
412 
413         {
414             group->addChild(new RenderbufferResizeCase(m_context, "nonms_to_nonms", "", false, false));
415             group->addChild(new RenderbufferResizeCase(m_context, "nonms_to_ms", "", false, true));
416             group->addChild(new RenderbufferResizeCase(m_context, "ms_to_nonms", "", true, false));
417             group->addChild(new RenderbufferResizeCase(m_context, "ms_to_ms", "", true, true));
418         }
419     }
420 }
421 
422 } // namespace Functional
423 } // namespace gles3
424 } // namespace deqp
425