• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2020 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 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
18 
19 #include "RenderEngineThreaded.h"
20 
21 #include <sched.h>
22 #include <chrono>
23 #include <future>
24 
25 #include <android-base/stringprintf.h>
26 #include <private/gui/SyncFeatures.h>
27 #include <processgroup/processgroup.h>
28 #include <utils/Trace.h>
29 
30 #include "gl/GLESRenderEngine.h"
31 
32 using namespace std::chrono_literals;
33 
34 namespace android {
35 namespace renderengine {
36 namespace threaded {
37 
create(CreateInstanceFactory factory,RenderEngineType type)38 std::unique_ptr<RenderEngineThreaded> RenderEngineThreaded::create(CreateInstanceFactory factory,
39                                                                    RenderEngineType type) {
40     return std::make_unique<RenderEngineThreaded>(std::move(factory), type);
41 }
42 
RenderEngineThreaded(CreateInstanceFactory factory,RenderEngineType type)43 RenderEngineThreaded::RenderEngineThreaded(CreateInstanceFactory factory, RenderEngineType type)
44       : RenderEngine(type) {
45     ATRACE_CALL();
46 
47     std::lock_guard lockThread(mThreadMutex);
48     mThread = std::thread(&RenderEngineThreaded::threadMain, this, factory);
49 }
50 
~RenderEngineThreaded()51 RenderEngineThreaded::~RenderEngineThreaded() {
52     mRunning = false;
53     mCondition.notify_one();
54 
55     if (mThread.joinable()) {
56         mThread.join();
57     }
58 }
59 
setSchedFifo(bool enabled)60 status_t RenderEngineThreaded::setSchedFifo(bool enabled) {
61     static constexpr int kFifoPriority = 2;
62     static constexpr int kOtherPriority = 0;
63 
64     struct sched_param param = {0};
65     int sched_policy;
66     if (enabled) {
67         sched_policy = SCHED_FIFO;
68         param.sched_priority = kFifoPriority;
69     } else {
70         sched_policy = SCHED_OTHER;
71         param.sched_priority = kOtherPriority;
72     }
73 
74     if (sched_setscheduler(0, sched_policy, &param) != 0) {
75         return -errno;
76     }
77     return NO_ERROR;
78 }
79 
80 // NO_THREAD_SAFETY_ANALYSIS is because std::unique_lock presently lacks thread safety annotations.
threadMain(CreateInstanceFactory factory)81 void RenderEngineThreaded::threadMain(CreateInstanceFactory factory) NO_THREAD_SAFETY_ANALYSIS {
82     ATRACE_CALL();
83 
84     if (!SetTaskProfiles(0, {"SFRenderEnginePolicy"})) {
85         ALOGW("Failed to set render-engine task profile!");
86     }
87 
88     if (setSchedFifo(true) != NO_ERROR) {
89         ALOGW("Couldn't set SCHED_FIFO");
90     }
91 
92     mRenderEngine = factory();
93 
94     pthread_setname_np(pthread_self(), mThreadName);
95 
96     {
97         std::scoped_lock lock(mInitializedMutex);
98         mIsInitialized = true;
99     }
100     mInitializedCondition.notify_all();
101 
102     while (mRunning) {
103         const auto getNextTask = [this]() -> std::optional<Work> {
104             std::scoped_lock lock(mThreadMutex);
105             if (!mFunctionCalls.empty()) {
106                 Work task = mFunctionCalls.front();
107                 mFunctionCalls.pop();
108                 return std::make_optional<Work>(task);
109             }
110             return std::nullopt;
111         };
112 
113         const auto task = getNextTask();
114 
115         if (task) {
116             (*task)(*mRenderEngine);
117         }
118 
119         std::unique_lock<std::mutex> lock(mThreadMutex);
120         mCondition.wait(lock, [this]() REQUIRES(mThreadMutex) {
121             return !mRunning || !mFunctionCalls.empty();
122         });
123     }
124 
125     // we must release the RenderEngine on the thread that created it
126     mRenderEngine.reset();
127 }
128 
waitUntilInitialized() const129 void RenderEngineThreaded::waitUntilInitialized() const {
130     std::unique_lock<std::mutex> lock(mInitializedMutex);
131     mInitializedCondition.wait(lock, [=] { return mIsInitialized; });
132 }
133 
primeCache()134 std::future<void> RenderEngineThreaded::primeCache() {
135     const auto resultPromise = std::make_shared<std::promise<void>>();
136     std::future<void> resultFuture = resultPromise->get_future();
137     ATRACE_CALL();
138     // This function is designed so it can run asynchronously, so we do not need to wait
139     // for the futures.
140     {
141         std::lock_guard lock(mThreadMutex);
142         mFunctionCalls.push([resultPromise](renderengine::RenderEngine& instance) {
143             ATRACE_NAME("REThreaded::primeCache");
144             if (setSchedFifo(false) != NO_ERROR) {
145                 ALOGW("Couldn't set SCHED_OTHER for primeCache");
146             }
147 
148             instance.primeCache();
149             resultPromise->set_value();
150 
151             if (setSchedFifo(true) != NO_ERROR) {
152                 ALOGW("Couldn't set SCHED_FIFO for primeCache");
153             }
154         });
155     }
156     mCondition.notify_one();
157 
158     return resultFuture;
159 }
160 
dump(std::string & result)161 void RenderEngineThreaded::dump(std::string& result) {
162     std::promise<std::string> resultPromise;
163     std::future<std::string> resultFuture = resultPromise.get_future();
164     {
165         std::lock_guard lock(mThreadMutex);
166         mFunctionCalls.push([&resultPromise, &result](renderengine::RenderEngine& instance) {
167             ATRACE_NAME("REThreaded::dump");
168             std::string localResult = result;
169             instance.dump(localResult);
170             resultPromise.set_value(std::move(localResult));
171         });
172     }
173     mCondition.notify_one();
174     // Note: This is an rvalue.
175     result.assign(resultFuture.get());
176 }
177 
genTextures(size_t count,uint32_t * names)178 void RenderEngineThreaded::genTextures(size_t count, uint32_t* names) {
179     ATRACE_CALL();
180     // This is a no-op in SkiaRenderEngine.
181     if (getRenderEngineType() != RenderEngineType::THREADED) {
182         return;
183     }
184     std::promise<void> resultPromise;
185     std::future<void> resultFuture = resultPromise.get_future();
186     {
187         std::lock_guard lock(mThreadMutex);
188         mFunctionCalls.push([&resultPromise, count, names](renderengine::RenderEngine& instance) {
189             ATRACE_NAME("REThreaded::genTextures");
190             instance.genTextures(count, names);
191             resultPromise.set_value();
192         });
193     }
194     mCondition.notify_one();
195     resultFuture.wait();
196 }
197 
deleteTextures(size_t count,uint32_t const * names)198 void RenderEngineThreaded::deleteTextures(size_t count, uint32_t const* names) {
199     ATRACE_CALL();
200     // This is a no-op in SkiaRenderEngine.
201     if (getRenderEngineType() != RenderEngineType::THREADED) {
202         return;
203     }
204     std::promise<void> resultPromise;
205     std::future<void> resultFuture = resultPromise.get_future();
206     {
207         std::lock_guard lock(mThreadMutex);
208         mFunctionCalls.push([&resultPromise, count, &names](renderengine::RenderEngine& instance) {
209             ATRACE_NAME("REThreaded::deleteTextures");
210             instance.deleteTextures(count, names);
211             resultPromise.set_value();
212         });
213     }
214     mCondition.notify_one();
215     resultFuture.wait();
216 }
217 
mapExternalTextureBuffer(const sp<GraphicBuffer> & buffer,bool isRenderable)218 void RenderEngineThreaded::mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer,
219                                                     bool isRenderable) {
220     ATRACE_CALL();
221     // This function is designed so it can run asynchronously, so we do not need to wait
222     // for the futures.
223     {
224         std::lock_guard lock(mThreadMutex);
225         mFunctionCalls.push([=](renderengine::RenderEngine& instance) {
226             ATRACE_NAME("REThreaded::mapExternalTextureBuffer");
227             instance.mapExternalTextureBuffer(buffer, isRenderable);
228         });
229     }
230     mCondition.notify_one();
231 }
232 
unmapExternalTextureBuffer(sp<GraphicBuffer> && buffer)233 void RenderEngineThreaded::unmapExternalTextureBuffer(sp<GraphicBuffer>&& buffer) {
234     ATRACE_CALL();
235     // This function is designed so it can run asynchronously, so we do not need to wait
236     // for the futures.
237     {
238         std::lock_guard lock(mThreadMutex);
239         mFunctionCalls.push(
240                 [=, buffer = std::move(buffer)](renderengine::RenderEngine& instance) mutable {
241                     ATRACE_NAME("REThreaded::unmapExternalTextureBuffer");
242                     instance.unmapExternalTextureBuffer(std::move(buffer));
243                 });
244     }
245     mCondition.notify_one();
246 }
247 
getMaxTextureSize() const248 size_t RenderEngineThreaded::getMaxTextureSize() const {
249     waitUntilInitialized();
250     return mRenderEngine->getMaxTextureSize();
251 }
252 
getMaxViewportDims() const253 size_t RenderEngineThreaded::getMaxViewportDims() const {
254     waitUntilInitialized();
255     return mRenderEngine->getMaxViewportDims();
256 }
257 
supportsProtectedContent() const258 bool RenderEngineThreaded::supportsProtectedContent() const {
259     waitUntilInitialized();
260     return mRenderEngine->supportsProtectedContent();
261 }
262 
cleanupPostRender()263 void RenderEngineThreaded::cleanupPostRender() {
264     if (canSkipPostRenderCleanup()) {
265         return;
266     }
267 
268     // This function is designed so it can run asynchronously, so we do not need to wait
269     // for the futures.
270     {
271         std::lock_guard lock(mThreadMutex);
272         mFunctionCalls.push([=](renderengine::RenderEngine& instance) {
273             ATRACE_NAME("REThreaded::cleanupPostRender");
274             instance.cleanupPostRender();
275         });
276     }
277     mCondition.notify_one();
278 }
279 
canSkipPostRenderCleanup() const280 bool RenderEngineThreaded::canSkipPostRenderCleanup() const {
281     waitUntilInitialized();
282     return mRenderEngine->canSkipPostRenderCleanup();
283 }
284 
drawLayersInternal(const std::shared_ptr<std::promise<FenceResult>> && resultPromise,const DisplaySettings & display,const std::vector<LayerSettings> & layers,const std::shared_ptr<ExternalTexture> & buffer,const bool useFramebufferCache,base::unique_fd && bufferFence)285 void RenderEngineThreaded::drawLayersInternal(
286         const std::shared_ptr<std::promise<FenceResult>>&& resultPromise,
287         const DisplaySettings& display, const std::vector<LayerSettings>& layers,
288         const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
289         base::unique_fd&& bufferFence) {
290     resultPromise->set_value(Fence::NO_FENCE);
291     return;
292 }
293 
drawLayers(const DisplaySettings & display,const std::vector<LayerSettings> & layers,const std::shared_ptr<ExternalTexture> & buffer,const bool useFramebufferCache,base::unique_fd && bufferFence)294 ftl::Future<FenceResult> RenderEngineThreaded::drawLayers(
295         const DisplaySettings& display, const std::vector<LayerSettings>& layers,
296         const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
297         base::unique_fd&& bufferFence) {
298     ATRACE_CALL();
299     const auto resultPromise = std::make_shared<std::promise<FenceResult>>();
300     std::future<FenceResult> resultFuture = resultPromise->get_future();
301     int fd = bufferFence.release();
302     {
303         std::lock_guard lock(mThreadMutex);
304         mFunctionCalls.push([resultPromise, display, layers, buffer, useFramebufferCache,
305                              fd](renderengine::RenderEngine& instance) {
306             ATRACE_NAME("REThreaded::drawLayers");
307             instance.updateProtectedContext(layers, buffer);
308             instance.drawLayersInternal(std::move(resultPromise), display, layers, buffer,
309                                         useFramebufferCache, base::unique_fd(fd));
310         });
311     }
312     mCondition.notify_one();
313     return resultFuture;
314 }
315 
cleanFramebufferCache()316 void RenderEngineThreaded::cleanFramebufferCache() {
317     ATRACE_CALL();
318     // This function is designed so it can run asynchronously, so we do not need to wait
319     // for the futures.
320     {
321         std::lock_guard lock(mThreadMutex);
322         mFunctionCalls.push([](renderengine::RenderEngine& instance) {
323             ATRACE_NAME("REThreaded::cleanFramebufferCache");
324             instance.cleanFramebufferCache();
325         });
326     }
327     mCondition.notify_one();
328 }
329 
getContextPriority()330 int RenderEngineThreaded::getContextPriority() {
331     std::promise<int> resultPromise;
332     std::future<int> resultFuture = resultPromise.get_future();
333     {
334         std::lock_guard lock(mThreadMutex);
335         mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& instance) {
336             ATRACE_NAME("REThreaded::getContextPriority");
337             int priority = instance.getContextPriority();
338             resultPromise.set_value(priority);
339         });
340     }
341     mCondition.notify_one();
342     return resultFuture.get();
343 }
344 
supportsBackgroundBlur()345 bool RenderEngineThreaded::supportsBackgroundBlur() {
346     waitUntilInitialized();
347     return mRenderEngine->supportsBackgroundBlur();
348 }
349 
onActiveDisplaySizeChanged(ui::Size size)350 void RenderEngineThreaded::onActiveDisplaySizeChanged(ui::Size size) {
351     // This function is designed so it can run asynchronously, so we do not need to wait
352     // for the futures.
353     {
354         std::lock_guard lock(mThreadMutex);
355         mFunctionCalls.push([size](renderengine::RenderEngine& instance) {
356             ATRACE_NAME("REThreaded::onActiveDisplaySizeChanged");
357             instance.onActiveDisplaySizeChanged(size);
358         });
359     }
360     mCondition.notify_one();
361 }
362 
getRenderEngineTid() const363 std::optional<pid_t> RenderEngineThreaded::getRenderEngineTid() const {
364     std::promise<pid_t> tidPromise;
365     std::future<pid_t> tidFuture = tidPromise.get_future();
366     {
367         std::lock_guard lock(mThreadMutex);
368         mFunctionCalls.push([&tidPromise](renderengine::RenderEngine& instance) {
369             tidPromise.set_value(gettid());
370         });
371     }
372 
373     mCondition.notify_one();
374     return std::make_optional(tidFuture.get());
375 }
376 
setEnableTracing(bool tracingEnabled)377 void RenderEngineThreaded::setEnableTracing(bool tracingEnabled) {
378     // This function is designed so it can run asynchronously, so we do not need to wait
379     // for the futures.
380     {
381         std::lock_guard lock(mThreadMutex);
382         mFunctionCalls.push([tracingEnabled](renderengine::RenderEngine& instance) {
383             ATRACE_NAME("REThreaded::setEnableTracing");
384             instance.setEnableTracing(tracingEnabled);
385         });
386     }
387     mCondition.notify_one();
388 }
389 } // namespace threaded
390 } // namespace renderengine
391 } // namespace android
392