1 /*
2 * Copyright 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <RenderEngineBench.h>
18 #include <android-base/file.h>
19 #include <benchmark/benchmark.h>
20 #include <gui/SurfaceComposerClient.h>
21 #include <log/log.h>
22 #include <renderengine/ExternalTexture.h>
23 #include <renderengine/LayerSettings.h>
24 #include <renderengine/RenderEngine.h>
25 #include <renderengine/impl/ExternalTexture.h>
26
27 #include <mutex>
28
29 using namespace android;
30 using namespace android::renderengine;
31
32 ///////////////////////////////////////////////////////////////////////////////
33 // Helpers for Benchmark::Apply
34 ///////////////////////////////////////////////////////////////////////////////
35
RenderEngineTypeName(RenderEngine::RenderEngineType type)36 std::string RenderEngineTypeName(RenderEngine::RenderEngineType type) {
37 switch (type) {
38 case RenderEngine::RenderEngineType::SKIA_GL_THREADED:
39 return "skiaglthreaded";
40 case RenderEngine::RenderEngineType::SKIA_GL:
41 return "skiagl";
42 case RenderEngine::RenderEngineType::SKIA_VK:
43 return "skiavk";
44 case RenderEngine::RenderEngineType::SKIA_VK_THREADED:
45 return "skiavkthreaded";
46 case RenderEngine::RenderEngineType::GLES:
47 case RenderEngine::RenderEngineType::THREADED:
48 LOG_ALWAYS_FATAL("GLESRenderEngine is deprecated - why time it?");
49 return "unused";
50 }
51 }
52
53 /**
54 * Passed (indirectly - see RunSkiaGLThreaded) to Benchmark::Apply to create a
55 * Benchmark which specifies which RenderEngineType it uses.
56 *
57 * This simplifies calling ->Arg(type)->Arg(type) and provides strings to make
58 * it obvious which version is being run.
59 *
60 * @param b The benchmark family
61 * @param type The type of RenderEngine to use.
62 */
AddRenderEngineType(benchmark::internal::Benchmark * b,RenderEngine::RenderEngineType type)63 static void AddRenderEngineType(benchmark::internal::Benchmark* b,
64 RenderEngine::RenderEngineType type) {
65 b->Arg(static_cast<int64_t>(type));
66 b->ArgName(RenderEngineTypeName(type));
67 }
68
69 /**
70 * Run a benchmark once using SKIA_GL_THREADED.
71 */
RunSkiaGLThreaded(benchmark::internal::Benchmark * b)72 static void RunSkiaGLThreaded(benchmark::internal::Benchmark* b) {
73 AddRenderEngineType(b, RenderEngine::RenderEngineType::SKIA_GL_THREADED);
74 }
75
76 ///////////////////////////////////////////////////////////////////////////////
77 // Helpers for calling drawLayers
78 ///////////////////////////////////////////////////////////////////////////////
79
getDisplaySize()80 std::pair<uint32_t, uint32_t> getDisplaySize() {
81 // These will be retrieved from a ui::Size, which stores int32_t, but they will be passed
82 // to GraphicBuffer, which wants uint32_t.
83 static uint32_t width, height;
84 std::once_flag once;
85 std::call_once(once, []() {
86 auto surfaceComposerClient = SurfaceComposerClient::getDefault();
87 auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
88 LOG_ALWAYS_FATAL_IF(ids.empty(), "Failed to get any display!");
89 ui::Size resolution = ui::kEmptySize;
90 // find the largest display resolution
91 for (auto id : ids) {
92 auto displayToken = surfaceComposerClient->getPhysicalDisplayToken(id);
93 ui::DisplayMode displayMode;
94 if (surfaceComposerClient->getActiveDisplayMode(displayToken, &displayMode) < 0) {
95 LOG_ALWAYS_FATAL("Failed to get active display mode!");
96 }
97 auto tw = displayMode.resolution.width;
98 auto th = displayMode.resolution.height;
99 LOG_ALWAYS_FATAL_IF(tw <= 0 || th <= 0, "Invalid display size!");
100 if (resolution.width * resolution.height <
101 displayMode.resolution.width * displayMode.resolution.height) {
102 resolution = displayMode.resolution;
103 }
104 }
105 width = static_cast<uint32_t>(resolution.width);
106 height = static_cast<uint32_t>(resolution.height);
107 });
108 return std::pair<uint32_t, uint32_t>(width, height);
109 }
110
111 // This value doesn't matter, as it's not read. TODO(b/199918329): Once we remove
112 // GLESRenderEngine we can remove this, too.
113 static constexpr const bool kUseFrameBufferCache = false;
114
createRenderEngine(RenderEngine::RenderEngineType type)115 static std::unique_ptr<RenderEngine> createRenderEngine(RenderEngine::RenderEngineType type) {
116 auto args = RenderEngineCreationArgs::Builder()
117 .setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
118 .setImageCacheSize(1)
119 .setEnableProtectedContext(true)
120 .setPrecacheToneMapperShaderOnly(false)
121 .setSupportsBackgroundBlur(true)
122 .setContextPriority(RenderEngine::ContextPriority::REALTIME)
123 .setRenderEngineType(type)
124 .setUseColorManagerment(true)
125 .build();
126 return RenderEngine::create(args);
127 }
128
allocateBuffer(RenderEngine & re,uint32_t width,uint32_t height,uint64_t extraUsageFlags=0,std::string name="output")129 static std::shared_ptr<ExternalTexture> allocateBuffer(RenderEngine& re, uint32_t width,
130 uint32_t height,
131 uint64_t extraUsageFlags = 0,
132 std::string name = "output") {
133 return std::make_shared<
134 impl::ExternalTexture>(sp<GraphicBuffer>::make(width, height,
135 HAL_PIXEL_FORMAT_RGBA_8888, 1u,
136 GRALLOC_USAGE_HW_RENDER |
137 GRALLOC_USAGE_HW_TEXTURE |
138 extraUsageFlags,
139 std::move(name)),
140 re,
141 impl::ExternalTexture::Usage::READABLE |
142 impl::ExternalTexture::Usage::WRITEABLE);
143 }
144
copyBuffer(RenderEngine & re,std::shared_ptr<ExternalTexture> original,uint64_t extraUsageFlags,std::string name)145 static std::shared_ptr<ExternalTexture> copyBuffer(RenderEngine& re,
146 std::shared_ptr<ExternalTexture> original,
147 uint64_t extraUsageFlags, std::string name) {
148 const uint32_t width = original->getBuffer()->getWidth();
149 const uint32_t height = original->getBuffer()->getHeight();
150 auto texture = allocateBuffer(re, width, height, extraUsageFlags, name);
151
152 const Rect displayRect(0, 0, static_cast<int32_t>(width), static_cast<int32_t>(height));
153 DisplaySettings display{
154 .physicalDisplay = displayRect,
155 .clip = displayRect,
156 .maxLuminance = 500,
157 };
158
159 const FloatRect layerRect(0, 0, width, height);
160 LayerSettings layer{
161 .geometry =
162 Geometry{
163 .boundaries = layerRect,
164 },
165 .source =
166 PixelSource{
167 .buffer =
168 Buffer{
169 .buffer = original,
170 },
171 },
172 .alpha = half(1.0f),
173 };
174 auto layers = std::vector<LayerSettings>{layer};
175
176 sp<Fence> waitFence =
177 re.drawLayers(display, layers, texture, kUseFrameBufferCache, base::unique_fd())
178 .get()
179 .value();
180 waitFence->waitForever(LOG_TAG);
181 return texture;
182 }
183
184 /**
185 * Helper for timing calls to drawLayers.
186 *
187 * Caller needs to create RenderEngine and the LayerSettings, and this takes
188 * care of setting up the display, starting and stopping the timer, calling
189 * drawLayers, and saving (if --save is used).
190 *
191 * This times both the CPU and GPU work initiated by drawLayers. All work done
192 * outside of the for loop is excluded from the timing measurements.
193 */
benchDrawLayers(RenderEngine & re,const std::vector<LayerSettings> & layers,benchmark::State & benchState,const char * saveFileName)194 static void benchDrawLayers(RenderEngine& re, const std::vector<LayerSettings>& layers,
195 benchmark::State& benchState, const char* saveFileName) {
196 auto [width, height] = getDisplaySize();
197 auto outputBuffer = allocateBuffer(re, width, height);
198
199 const Rect displayRect(0, 0, static_cast<int32_t>(width), static_cast<int32_t>(height));
200 DisplaySettings display{
201 .physicalDisplay = displayRect,
202 .clip = displayRect,
203 .maxLuminance = 500,
204 };
205
206 // This loop starts and stops the timer.
207 for (auto _ : benchState) {
208 sp<Fence> waitFence = re.drawLayers(display, layers, outputBuffer, kUseFrameBufferCache,
209 base::unique_fd())
210 .get()
211 .value();
212 waitFence->waitForever(LOG_TAG);
213 }
214
215 if (renderenginebench::save() && saveFileName) {
216 // Copy to a CPU-accessible buffer so we can encode it.
217 outputBuffer = copyBuffer(re, outputBuffer, GRALLOC_USAGE_SW_READ_OFTEN, "to_encode");
218
219 std::string outFile = base::GetExecutableDirectory();
220 outFile.append("/");
221 outFile.append(saveFileName);
222 outFile.append(".jpg");
223 renderenginebench::encodeToJpeg(outFile.c_str(), outputBuffer->getBuffer());
224 }
225 }
226
227 ///////////////////////////////////////////////////////////////////////////////
228 // Benchmarks
229 ///////////////////////////////////////////////////////////////////////////////
230
BM_blur(benchmark::State & benchState)231 void BM_blur(benchmark::State& benchState) {
232 auto re = createRenderEngine(static_cast<RenderEngine::RenderEngineType>(benchState.range()));
233
234 // Initially use cpu access so we can decode into it with AImageDecoder.
235 auto [width, height] = getDisplaySize();
236 auto srcBuffer =
237 allocateBuffer(*re, width, height, GRALLOC_USAGE_SW_WRITE_OFTEN, "decoded_source");
238 {
239 std::string srcImage = base::GetExecutableDirectory();
240 srcImage.append("/resources/homescreen.png");
241 renderenginebench::decode(srcImage.c_str(), srcBuffer->getBuffer());
242
243 // Now copy into GPU-only buffer for more realistic timing.
244 srcBuffer = copyBuffer(*re, srcBuffer, 0, "source");
245 }
246
247 const FloatRect layerRect(0, 0, width, height);
248 LayerSettings layer{
249 .geometry =
250 Geometry{
251 .boundaries = layerRect,
252 },
253 .source =
254 PixelSource{
255 .buffer =
256 Buffer{
257 .buffer = srcBuffer,
258 },
259 },
260 .alpha = half(1.0f),
261 };
262 LayerSettings blurLayer{
263 .geometry =
264 Geometry{
265 .boundaries = layerRect,
266 },
267 .alpha = half(1.0f),
268 .skipContentDraw = true,
269 .backgroundBlurRadius = 60,
270 };
271
272 auto layers = std::vector<LayerSettings>{layer, blurLayer};
273 benchDrawLayers(*re, layers, benchState, "blurred");
274 }
275
276 BENCHMARK(BM_blur)->Apply(RunSkiaGLThreaded);
277