xref: /aosp_15_r20/external/angle/src/tests/perf_tests/MultisampleResolvePerf.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2024 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // MultisampleResolvePerf:
7 //   Performance tests for glBlitFramebuffer and glInvalidateFramebuffer where the framebuffer is
8 //   multisampled.
9 
10 #include "ANGLEPerfTest.h"
11 
12 #include "util/shader_utils.h"
13 
14 namespace
15 {
16 constexpr unsigned int kIterationsPerStep = 1;
17 
18 enum class Multisample
19 {
20     Yes,
21     No,
22 };
23 
24 enum class WithDepthStencil
25 {
26     Yes,
27     No,
28 };
29 
30 struct MultisampleResolveParams final : public RenderTestParams
31 {
MultisampleResolveParams__anonb4b2056f0111::MultisampleResolveParams32     MultisampleResolveParams(Multisample multisample, WithDepthStencil depthStencil)
33     {
34         iterationsPerStep = kIterationsPerStep;
35         majorVersion      = 3;
36         minorVersion      = 0;
37         windowWidth       = 256;
38         windowHeight      = 256;
39 
40         if (multisample == Multisample::No)
41         {
42             samples = 0;
43         }
44 
45         withDepthStencil = depthStencil == WithDepthStencil::Yes;
46     }
47 
story__anonb4b2056f0111::MultisampleResolveParams48     std::string story() const override
49     {
50         std::stringstream storyStr;
51         storyStr << RenderTestParams::story();
52         if (withDepthStencil)
53         {
54             storyStr << "_ds";
55         }
56         if (samples == 0)
57         {
58             storyStr << "_singlesampled_reference";
59         }
60         return storyStr.str();
61     }
62 
63     unsigned int framebufferSize = 1024;
64     unsigned int samples         = 4;
65     bool withDepthStencil        = false;
66 };
67 
operator <<(std::ostream & os,const MultisampleResolveParams & params)68 std::ostream &operator<<(std::ostream &os, const MultisampleResolveParams &params)
69 {
70     os << params.backendAndStory().substr(1);
71     return os;
72 }
73 
74 class MultisampleResolvePerf : public ANGLERenderTest,
75                                public ::testing::WithParamInterface<MultisampleResolveParams>
76 {
77   public:
MultisampleResolvePerf()78     MultisampleResolvePerf() : ANGLERenderTest("MultisampleResolvePerf", GetParam()) {}
79 
80     void initializeBenchmark() override;
81     void destroyBenchmark() override;
82     void drawBenchmark() override;
83 
84   private:
85     GLuint mMSAAFramebuffer       = 0;
86     GLuint mMSAAColor[2]          = {};
87     GLuint mMSAADepthStencil      = 0;
88     GLuint mResolveFramebuffer[2] = {};
89     GLuint mResolveColor[2]       = {};
90     GLuint mResolveDepthStencil   = 0;
91     GLuint mReferenceFramebuffer  = 0;
92     GLuint mProgram               = 0;
93 };
94 
initializeBenchmark()95 void MultisampleResolvePerf::initializeBenchmark()
96 {
97     const MultisampleResolveParams &param = GetParam();
98 
99     glGenFramebuffers(1, &mMSAAFramebuffer);
100     glGenFramebuffers(2, mResolveFramebuffer);
101     glGenFramebuffers(1, &mReferenceFramebuffer);
102 
103     // Create source and destination Renderbuffers.
104     glGenRenderbuffers(2, mMSAAColor);
105     glGenRenderbuffers(1, &mMSAADepthStencil);
106     glGenRenderbuffers(2, mResolveColor);
107     glGenRenderbuffers(1, &mResolveDepthStencil);
108 
109     ASSERT_GL_NO_ERROR();
110 
111     const GLuint size = param.framebufferSize;
112 
113     for (uint32_t i = 0; i < 2; ++i)
114     {
115         glBindRenderbuffer(GL_RENDERBUFFER, mResolveColor[i]);
116         glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, size, size);
117 
118         glBindFramebuffer(GL_FRAMEBUFFER, mResolveFramebuffer[i]);
119         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
120                                   mResolveColor[i]);
121         ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
122     }
123 
124     if (param.withDepthStencil)
125     {
126         glBindRenderbuffer(GL_RENDERBUFFER, mResolveDepthStencil);
127         glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, size, size);
128         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
129                                   mResolveDepthStencil);
130         ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
131     }
132 
133     if (param.samples > 0)
134     {
135         glBindRenderbuffer(GL_RENDERBUFFER, mMSAAColor[0]);
136         glRenderbufferStorageMultisample(GL_RENDERBUFFER, param.samples, GL_RGBA8, size, size);
137         glBindRenderbuffer(GL_RENDERBUFFER, mMSAAColor[1]);
138         glRenderbufferStorageMultisample(GL_RENDERBUFFER, param.samples, GL_RGBA8, size, size);
139 
140         glBindFramebuffer(GL_FRAMEBUFFER, mMSAAFramebuffer);
141         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
142                                   mMSAAColor[0]);
143         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_RENDERBUFFER,
144                                   mMSAAColor[1]);
145 
146         if (param.withDepthStencil)
147         {
148             glBindRenderbuffer(GL_RENDERBUFFER, mMSAADepthStencil);
149             glRenderbufferStorageMultisample(GL_RENDERBUFFER, param.samples, GL_DEPTH24_STENCIL8,
150                                              size, size);
151             glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
152                                       mMSAADepthStencil);
153         }
154 
155         ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
156     }
157     else
158     {
159         glBindFramebuffer(GL_FRAMEBUFFER, mReferenceFramebuffer);
160         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
161                                   mResolveColor[0]);
162         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_RENDERBUFFER,
163                                   mResolveColor[1]);
164 
165         if (param.withDepthStencil)
166         {
167             glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
168                                       mResolveDepthStencil);
169         }
170 
171         ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
172     }
173 
174     GLenum bufs[3] = {GL_COLOR_ATTACHMENT0, GL_NONE, GL_COLOR_ATTACHMENT2};
175     glDrawBuffers(3, bufs);
176 
177     ASSERT_GL_NO_ERROR();
178 
179     constexpr char kVS[] = R"(#version 300 es
180 precision highp float;
181 void main()
182 {
183     // gl_VertexID    x    y
184     //      0        -1   -1
185     //      1         1   -1
186     //      2        -1    1
187     //      3         1    1
188     int bit0 = gl_VertexID & 1;
189     int bit1 = gl_VertexID >> 1;
190     gl_Position = vec4(bit0 * 2 - 1, bit1 * 2 - 1, gl_VertexID % 2 == 0 ? -1 : 1, 1);
191 })";
192 
193     constexpr char kFS[] = R"(#version 300 es
194 precision highp float;
195 
196 uniform vec4 value0;
197 uniform vec4 value2;
198 
199 layout(location = 0) out vec4 color0;
200 layout(location = 2) out vec4 color2;
201 
202 void main()
203 {
204     color0 = value0;
205     color2 = value2;
206 })";
207 
208     mProgram = CompileProgram(kVS, kFS);
209     ASSERT_NE(0u, mProgram);
210     glUseProgram(mProgram);
211 
212     const GLint color0Loc = glGetUniformLocation(mProgram, "value0");
213     const GLint color1Loc = glGetUniformLocation(mProgram, "value2");
214 
215     glUniform4f(color0Loc, 1, 0, 0, 1);
216     glUniform4f(color1Loc, 0, 1, 0, 1);
217 }
218 
destroyBenchmark()219 void MultisampleResolvePerf::destroyBenchmark()
220 {
221     glDeleteFramebuffers(1, &mMSAAFramebuffer);
222     glDeleteFramebuffers(2, mResolveFramebuffer);
223     glDeleteFramebuffers(1, &mReferenceFramebuffer);
224 
225     glDeleteRenderbuffers(2, mMSAAColor);
226     glDeleteRenderbuffers(1, &mMSAADepthStencil);
227     glDeleteRenderbuffers(2, mResolveColor);
228     glDeleteRenderbuffers(1, &mResolveDepthStencil);
229 
230     glDeleteProgram(mProgram);
231 }
232 
drawBenchmark()233 void MultisampleResolvePerf::drawBenchmark()
234 {
235     const MultisampleResolveParams &param = GetParam();
236     const int size                        = param.framebufferSize;
237     const bool singleSampled              = param.samples == 0;
238 
239     glViewport(0, 0, size, size);
240     glEnable(GL_DEPTH_TEST);
241     glDepthFunc(GL_ALWAYS);
242     glEnable(GL_STENCIL_TEST);
243     glStencilFunc(GL_ALWAYS, 0x55, 0xFF);
244     glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
245     glStencilMask(0xFF);
246 
247     for (unsigned int iteration = 0; iteration < param.iterationsPerStep; ++iteration)
248     {
249         const GLenum discards[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT2,
250                                    GL_DEPTH_STENCIL_ATTACHMENT};
251 
252         glBindFramebuffer(GL_FRAMEBUFFER, singleSampled ? mReferenceFramebuffer : mMSAAFramebuffer);
253         glInvalidateFramebuffer(GL_FRAMEBUFFER, param.withDepthStencil ? 3 : 2, discards);
254 
255         // Start a render pass, then resolve each attachment + invalidate them.  Every render pass
256         // should thus start with LOAD_OP_DONT_CARE and end in STORE_OP_DONT_CARE (for the
257         // attachments) and STORE_OP_STORE (for the resolve attachments).
258         //
259         // In single-sampled mode, just draw.  This is used to compare the performance of
260         // multisampled with single sampled rendering.
261         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
262 
263         if (!singleSampled)
264         {
265             for (uint32_t i = 0; i < 2; ++i)
266             {
267                 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mResolveFramebuffer[i]);
268                 glReadBuffer(discards[i]);
269                 glBlitFramebuffer(0, 0, size, size, 0, 0, size, size, GL_COLOR_BUFFER_BIT,
270                                   GL_NEAREST);
271                 ASSERT_GL_NO_ERROR();
272 
273                 glInvalidateFramebuffer(GL_READ_FRAMEBUFFER, 1, &discards[i]);
274             }
275 
276             if (param.withDepthStencil)
277             {
278                 glBlitFramebuffer(0, 0, size, size, 0, 0, size, size,
279                                   GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
280 
281                 glInvalidateFramebuffer(GL_READ_FRAMEBUFFER, 1, &discards[2]);
282             }
283 
284             ASSERT_GL_NO_ERROR();
285         }
286     }
287 
288     ASSERT_GL_NO_ERROR();
289 }
290 
291 // Test that multisample resolve + invalidate is as efficient as single sampling on tilers.
TEST_P(MultisampleResolvePerf,Run)292 TEST_P(MultisampleResolvePerf, Run)
293 {
294     run();
295 }
296 
Vulkan(Multisample multisample,WithDepthStencil depthStencil)297 MultisampleResolveParams Vulkan(Multisample multisample, WithDepthStencil depthStencil)
298 {
299     MultisampleResolveParams params(multisample, depthStencil);
300     params.eglParameters = angle::egl_platform::VULKAN();
301     return params;
302 }
303 }  // anonymous namespace
304 
305 ANGLE_INSTANTIATE_TEST(MultisampleResolvePerf,
306                        Vulkan(Multisample::No, WithDepthStencil::No),
307                        Vulkan(Multisample::Yes, WithDepthStencil::No),
308                        Vulkan(Multisample::No, WithDepthStencil::Yes),
309                        Vulkan(Multisample::Yes, WithDepthStencil::Yes));
310 
311 // This test suite is not instantiated on some OSes.
312 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MultisampleResolvePerf);
313