1 //
2 // Copyright 2021 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 // FramebufferAttachPerfTest:
7 // Performance test for attaching and detaching resources to a Framebuffer.
8 //
9
10 #include "ANGLEPerfTest.h"
11 #include "test_utils/gl_raii.h"
12
13 #include <iostream>
14 #include <random>
15 #include <sstream>
16
17 namespace angle
18 {
19 constexpr unsigned int kIterationsPerStep = 256;
20 constexpr unsigned int kTextureSize = 256;
21 constexpr std::size_t kTextureCount = 4;
22 constexpr std::size_t kFboCount = kTextureCount;
23 constexpr std::size_t kAdditionalFboCount = kFboCount * kFboCount;
24
25 struct FramebufferAttachmentParams final : public RenderTestParams
26 {
FramebufferAttachmentParamsangle::FramebufferAttachmentParams27 FramebufferAttachmentParams()
28 {
29 iterationsPerStep = kIterationsPerStep;
30
31 // Common default params
32 majorVersion = 3;
33 minorVersion = 0;
34 windowWidth = kTextureSize;
35 windowHeight = kTextureSize;
36 }
37
38 std::string story() const override;
39 };
40
operator <<(std::ostream & os,const FramebufferAttachmentParams & params)41 std::ostream &operator<<(std::ostream &os, const FramebufferAttachmentParams ¶ms)
42 {
43 os << params.backendAndStory().substr(1);
44 return os;
45 }
46
story() const47 std::string FramebufferAttachmentParams::story() const
48 {
49 std::stringstream strstr;
50
51 strstr << RenderTestParams::story();
52
53 return strstr.str();
54 }
55
56 class FramebufferAttachmentBenchmark
57 : public ANGLERenderTest,
58 public ::testing::WithParamInterface<FramebufferAttachmentParams>
59 {
60 public:
FramebufferAttachmentBenchmark()61 FramebufferAttachmentBenchmark() : ANGLERenderTest("Framebuffers", GetParam()) {}
62 void initializeBenchmark() override;
63 void drawBenchmark() override;
64
65 protected:
66 void initTextures();
67
68 std::array<GLTexture, kTextureCount> mTextures;
69 std::array<GLFramebuffer, kFboCount> mFbo;
70 };
71
initializeBenchmark()72 void FramebufferAttachmentBenchmark::initializeBenchmark()
73 {
74 initTextures();
75
76 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
77 glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight());
78
79 ASSERT_GL_NO_ERROR();
80
81 GLint maxAttachmentCount;
82 glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &maxAttachmentCount);
83 if (mTextures.size() > static_cast<size_t>(maxAttachmentCount))
84 {
85 skipTest("Texture count exceeds maximum attachment unit count");
86 }
87 }
88
initTextures()89 void FramebufferAttachmentBenchmark::initTextures()
90 {
91 std::vector<GLubyte> textureData(kTextureSize * kTextureSize * 4);
92 for (auto &byte : textureData)
93 {
94 byte = rand() % 255u;
95 }
96
97 for (GLTexture &texture : mTextures)
98 {
99 glBindTexture(GL_TEXTURE_2D, texture);
100 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kTextureSize, kTextureSize, 0, GL_RGBA,
101 GL_UNSIGNED_BYTE, textureData.data());
102 glBindTexture(GL_TEXTURE_2D, 0);
103 }
104 }
105
drawBenchmark()106 void FramebufferAttachmentBenchmark::drawBenchmark()
107 {
108 const auto ¶ms = GetParam();
109
110 size_t fboCount = mFbo.size();
111 size_t textureCount = mTextures.size();
112
113 for (size_t it = 0; it < params.iterationsPerStep; ++it)
114 {
115 // Attach
116 for (size_t fboIndex = 0; fboIndex < fboCount; fboIndex++)
117 {
118 glBindFramebuffer(GL_FRAMEBUFFER, mFbo[fboIndex]);
119 for (size_t textureIndex = 0; textureIndex < textureCount; textureIndex++)
120 {
121 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + textureIndex,
122 GL_TEXTURE_2D, mTextures[textureIndex], 0);
123 }
124 glBindFramebuffer(GL_FRAMEBUFFER, 0);
125 }
126
127 // Detach
128 for (size_t fboIndex = 0; fboIndex < fboCount; fboIndex++)
129 {
130 glBindFramebuffer(GL_FRAMEBUFFER, mFbo[fboIndex]);
131 for (size_t index = 0; index < textureCount; index++)
132 {
133 size_t textureIndex = mTextures.size() - (index + 1);
134 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + textureIndex,
135 GL_TEXTURE_2D, 0, 0);
136 }
137 glBindFramebuffer(GL_FRAMEBUFFER, 0);
138 }
139 }
140
141 ASSERT_GL_NO_ERROR();
142 }
143
144 class FramebufferAttachmentStateUpdateBenchmark : public FramebufferAttachmentBenchmark
145 {
146 public:
FramebufferAttachmentStateUpdateBenchmark()147 FramebufferAttachmentStateUpdateBenchmark() : FramebufferAttachmentBenchmark() {}
148 void initializeBenchmark() override;
149 void destroyBenchmark() override;
150 void drawBenchmark() override;
151
152 private:
153 std::array<GLFramebuffer, kAdditionalFboCount> mAdditionalFbo;
154 };
155
initializeBenchmark()156 void FramebufferAttachmentStateUpdateBenchmark::initializeBenchmark()
157 {
158 FramebufferAttachmentBenchmark::initializeBenchmark();
159
160 // Attach
161 for (size_t fboIndex = 0; fboIndex < mAdditionalFbo.size(); fboIndex++)
162 {
163 glBindFramebuffer(GL_FRAMEBUFFER, mAdditionalFbo[fboIndex]);
164 for (size_t textureIndex = 0; textureIndex < mTextures.size(); textureIndex++)
165 {
166 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + textureIndex,
167 GL_TEXTURE_2D, mTextures[textureIndex], 0);
168 }
169 glBindFramebuffer(GL_FRAMEBUFFER, 0);
170 }
171 }
172
destroyBenchmark()173 void FramebufferAttachmentStateUpdateBenchmark::destroyBenchmark()
174 {
175 // Detach
176 for (size_t fboIndex = 0; fboIndex < mAdditionalFbo.size(); fboIndex++)
177 {
178 glBindFramebuffer(GL_FRAMEBUFFER, mAdditionalFbo[fboIndex]);
179 for (size_t index = 0; index < mTextures.size(); index++)
180 {
181 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + index, GL_TEXTURE_2D, 0,
182 0);
183 }
184 glBindFramebuffer(GL_FRAMEBUFFER, 0);
185 }
186
187 FramebufferAttachmentBenchmark::destroyBenchmark();
188 }
189
drawBenchmark()190 void FramebufferAttachmentStateUpdateBenchmark::drawBenchmark()
191 {
192 const auto ¶ms = GetParam();
193
194 size_t textureCount = mTextures.size();
195 GLenum nearestFilter = GL_NEAREST;
196 GLenum linearFilter = GL_LINEAR;
197 for (size_t it = 0; it < params.iterationsPerStep; ++it)
198 {
199 for (size_t textureIndex = 0; textureIndex < textureCount; textureIndex++)
200 {
201 glBindTexture(GL_TEXTURE_2D, mTextures[textureIndex]);
202 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
203 (it % 2) ? linearFilter : nearestFilter);
204 glBindTexture(GL_TEXTURE_2D, 0);
205 }
206 }
207
208 ASSERT_GL_NO_ERROR();
209 }
210
VulkanParams()211 FramebufferAttachmentParams VulkanParams()
212 {
213 FramebufferAttachmentParams params;
214 params.eglParameters = egl_platform::VULKAN_NULL();
215
216 return params;
217 }
218
TEST_P(FramebufferAttachmentBenchmark,Run)219 TEST_P(FramebufferAttachmentBenchmark, Run)
220 {
221 run();
222 }
223
TEST_P(FramebufferAttachmentStateUpdateBenchmark,Run)224 TEST_P(FramebufferAttachmentStateUpdateBenchmark, Run)
225 {
226 run();
227 }
228
229 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(FramebufferAttachmentBenchmark);
230 ANGLE_INSTANTIATE_TEST(FramebufferAttachmentBenchmark, VulkanParams());
231
232 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(FramebufferAttachmentStateUpdateBenchmark);
233 ANGLE_INSTANTIATE_TEST(FramebufferAttachmentStateUpdateBenchmark, VulkanParams());
234 } // namespace angle
235