• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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