1 /*
2  * Copyright (C) 2013 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 "RenderProxy.h"
18 
19 #include "DeferredLayerUpdater.h"
20 #include "DisplayList.h"
21 #include "Properties.h"
22 #include "Readback.h"
23 #include "Rect.h"
24 #include "pipeline/skia/VectorDrawableAtlas.h"
25 #include "renderstate/RenderState.h"
26 #include "renderthread/CanvasContext.h"
27 #include "renderthread/EglManager.h"
28 #include "renderthread/RenderTask.h"
29 #include "renderthread/RenderThread.h"
30 #include "utils/Macros.h"
31 #include "utils/TimeUtils.h"
32 
33 #include <ui/GraphicBuffer.h>
34 
35 namespace android {
36 namespace uirenderer {
37 namespace renderthread {
38 
RenderProxy(bool translucent,RenderNode * rootRenderNode,IContextFactory * contextFactory)39 RenderProxy::RenderProxy(bool translucent, RenderNode* rootRenderNode,
40                          IContextFactory* contextFactory)
41         : mRenderThread(RenderThread::getInstance()), mContext(nullptr) {
42     mContext = mRenderThread.queue().runSync([&]() -> CanvasContext* {
43         return CanvasContext::create(mRenderThread, translucent, rootRenderNode, contextFactory);
44     });
45     mDrawFrameTask.setContext(&mRenderThread, mContext, rootRenderNode);
46 }
47 
~RenderProxy()48 RenderProxy::~RenderProxy() {
49     destroyContext();
50 }
51 
destroyContext()52 void RenderProxy::destroyContext() {
53     if (mContext) {
54         mDrawFrameTask.setContext(nullptr, nullptr, nullptr);
55         // This is also a fence as we need to be certain that there are no
56         // outstanding mDrawFrame tasks posted before it is destroyed
57         mRenderThread.queue().runSync([this]() { delete mContext; });
58         mContext = nullptr;
59     }
60 }
61 
setSwapBehavior(SwapBehavior swapBehavior)62 void RenderProxy::setSwapBehavior(SwapBehavior swapBehavior) {
63     mRenderThread.queue().post([this, swapBehavior]() { mContext->setSwapBehavior(swapBehavior); });
64 }
65 
loadSystemProperties()66 bool RenderProxy::loadSystemProperties() {
67     return mRenderThread.queue().runSync([this]() -> bool {
68         bool needsRedraw = false;
69         if (Caches::hasInstance()) {
70             needsRedraw = Properties::load();
71         }
72         if (mContext->profiler().consumeProperties()) {
73             needsRedraw = true;
74         }
75         return needsRedraw;
76     });
77 }
78 
setName(const char * name)79 void RenderProxy::setName(const char* name) {
80     // block since name/value pointers owned by caller
81     // TODO: Support move arguments
82     mRenderThread.queue().runSync([this, name]() { mContext->setName(std::string(name)); });
83 }
84 
initialize(const sp<Surface> & surface)85 void RenderProxy::initialize(const sp<Surface>& surface) {
86     mRenderThread.queue().post(
87             [ this, surf = surface ]() mutable { mContext->setSurface(std::move(surf)); });
88 }
89 
updateSurface(const sp<Surface> & surface)90 void RenderProxy::updateSurface(const sp<Surface>& surface) {
91     mRenderThread.queue().post(
92             [ this, surf = surface ]() mutable { mContext->setSurface(std::move(surf)); });
93 }
94 
pauseSurface(const sp<Surface> & surface)95 bool RenderProxy::pauseSurface(const sp<Surface>& surface) {
96     return mRenderThread.queue().runSync([this]() -> bool { return mContext->pauseSurface(); });
97 }
98 
setStopped(bool stopped)99 void RenderProxy::setStopped(bool stopped) {
100     mRenderThread.queue().runSync([this, stopped]() { mContext->setStopped(stopped); });
101 }
102 
setup(float lightRadius,uint8_t ambientShadowAlpha,uint8_t spotShadowAlpha)103 void RenderProxy::setup(float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
104     mRenderThread.queue().post(
105             [=]() { mContext->setup(lightRadius, ambientShadowAlpha, spotShadowAlpha); });
106 }
107 
setLightCenter(const Vector3 & lightCenter)108 void RenderProxy::setLightCenter(const Vector3& lightCenter) {
109     mRenderThread.queue().post([=]() { mContext->setLightCenter(lightCenter); });
110 }
111 
setOpaque(bool opaque)112 void RenderProxy::setOpaque(bool opaque) {
113     mRenderThread.queue().post([=]() { mContext->setOpaque(opaque); });
114 }
115 
setWideGamut(bool wideGamut)116 void RenderProxy::setWideGamut(bool wideGamut) {
117     mRenderThread.queue().post([=]() { mContext->setWideGamut(wideGamut); });
118 }
119 
frameInfo()120 int64_t* RenderProxy::frameInfo() {
121     return mDrawFrameTask.frameInfo();
122 }
123 
syncAndDrawFrame()124 int RenderProxy::syncAndDrawFrame() {
125     return mDrawFrameTask.drawFrame();
126 }
127 
destroy()128 void RenderProxy::destroy() {
129     // destroyCanvasAndSurface() needs a fence as when it returns the
130     // underlying BufferQueue is going to be released from under
131     // the render thread.
132     mRenderThread.queue().runSync([=]() { mContext->destroy(); });
133 }
134 
invokeFunctor(Functor * functor,bool waitForCompletion)135 void RenderProxy::invokeFunctor(Functor* functor, bool waitForCompletion) {
136     ATRACE_CALL();
137     RenderThread& thread = RenderThread::getInstance();
138     auto invoke = [&thread, functor]() { CanvasContext::invokeFunctor(thread, functor); };
139     if (waitForCompletion) {
140         // waitForCompletion = true is expected to be fairly rare and only
141         // happen in destruction. Thus it should be fine to temporarily
142         // create a Mutex
143         thread.queue().runSync(std::move(invoke));
144     } else {
145         thread.queue().post(std::move(invoke));
146     }
147 }
148 
createTextureLayer()149 DeferredLayerUpdater* RenderProxy::createTextureLayer() {
150     return mRenderThread.queue().runSync([this]() -> auto {
151         return mContext->createTextureLayer();
152     });
153 }
154 
buildLayer(RenderNode * node)155 void RenderProxy::buildLayer(RenderNode* node) {
156     mRenderThread.queue().runSync([&]() { mContext->buildLayer(node); });
157 }
158 
copyLayerInto(DeferredLayerUpdater * layer,SkBitmap & bitmap)159 bool RenderProxy::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap& bitmap) {
160     return mRenderThread.queue().runSync(
161             [&]() -> bool { return mContext->copyLayerInto(layer, &bitmap); });
162 }
163 
pushLayerUpdate(DeferredLayerUpdater * layer)164 void RenderProxy::pushLayerUpdate(DeferredLayerUpdater* layer) {
165     mDrawFrameTask.pushLayerUpdate(layer);
166 }
167 
cancelLayerUpdate(DeferredLayerUpdater * layer)168 void RenderProxy::cancelLayerUpdate(DeferredLayerUpdater* layer) {
169     mDrawFrameTask.removeLayerUpdate(layer);
170 }
171 
detachSurfaceTexture(DeferredLayerUpdater * layer)172 void RenderProxy::detachSurfaceTexture(DeferredLayerUpdater* layer) {
173     return mRenderThread.queue().runSync([&]() { layer->detachSurfaceTexture(); });
174 }
175 
destroyHardwareResources()176 void RenderProxy::destroyHardwareResources() {
177     return mRenderThread.queue().runSync([&]() { mContext->destroyHardwareResources(); });
178 }
179 
trimMemory(int level)180 void RenderProxy::trimMemory(int level) {
181     // Avoid creating a RenderThread to do a trimMemory.
182     if (RenderThread::hasInstance()) {
183         RenderThread& thread = RenderThread::getInstance();
184         thread.queue().post([&thread, level]() { CanvasContext::trimMemory(thread, level); });
185     }
186 }
187 
overrideProperty(const char * name,const char * value)188 void RenderProxy::overrideProperty(const char* name, const char* value) {
189     // expensive, but block here since name/value pointers owned by caller
190     RenderThread::getInstance().queue().runSync(
191             [&]() { Properties::overrideProperty(name, value); });
192 }
193 
fence()194 void RenderProxy::fence() {
195     mRenderThread.queue().runSync([]() {});
196 }
197 
staticFence()198 void RenderProxy::staticFence() {
199     RenderThread::getInstance().queue().runSync([]() {});
200 }
201 
stopDrawing()202 void RenderProxy::stopDrawing() {
203     mRenderThread.queue().runSync([this]() { mContext->stopDrawing(); });
204 }
205 
notifyFramePending()206 void RenderProxy::notifyFramePending() {
207     mRenderThread.queue().post([this]() { mContext->notifyFramePending(); });
208 }
209 
dumpProfileInfo(int fd,int dumpFlags)210 void RenderProxy::dumpProfileInfo(int fd, int dumpFlags) {
211     mRenderThread.queue().runSync([&]() {
212         mContext->profiler().dumpData(fd);
213         if (dumpFlags & DumpFlags::FrameStats) {
214             mContext->dumpFrames(fd);
215         }
216         if (dumpFlags & DumpFlags::JankStats) {
217             mRenderThread.globalProfileData()->dump(fd);
218         }
219         if (dumpFlags & DumpFlags::Reset) {
220             mContext->resetFrameStats();
221         }
222     });
223 }
224 
resetProfileInfo()225 void RenderProxy::resetProfileInfo() {
226     mRenderThread.queue().runSync([=]() { mContext->resetFrameStats(); });
227 }
228 
frameTimePercentile(int percentile)229 uint32_t RenderProxy::frameTimePercentile(int percentile) {
230     return mRenderThread.queue().runSync([&]() -> auto {
231         return mRenderThread.globalProfileData()->findPercentile(percentile);
232     });
233 }
234 
dumpGraphicsMemory(int fd)235 void RenderProxy::dumpGraphicsMemory(int fd) {
236     auto& thread = RenderThread::getInstance();
237     thread.queue().runSync([&]() { thread.dumpGraphicsMemory(fd); });
238 }
239 
setProcessStatsBuffer(int fd)240 void RenderProxy::setProcessStatsBuffer(int fd) {
241     auto& rt = RenderThread::getInstance();
242     rt.queue().post([&rt, fd = dup(fd) ]() {
243         rt.globalProfileData().switchStorageToAshmem(fd);
244         close(fd);
245     });
246 }
247 
rotateProcessStatsBuffer()248 void RenderProxy::rotateProcessStatsBuffer() {
249     auto& rt = RenderThread::getInstance();
250     rt.queue().post([&rt]() { rt.globalProfileData().rotateStorage(); });
251 }
252 
getRenderThreadTid()253 int RenderProxy::getRenderThreadTid() {
254     return mRenderThread.getTid();
255 }
256 
addRenderNode(RenderNode * node,bool placeFront)257 void RenderProxy::addRenderNode(RenderNode* node, bool placeFront) {
258     mRenderThread.queue().post([=]() { mContext->addRenderNode(node, placeFront); });
259 }
260 
removeRenderNode(RenderNode * node)261 void RenderProxy::removeRenderNode(RenderNode* node) {
262     mRenderThread.queue().post([=]() { mContext->removeRenderNode(node); });
263 }
264 
drawRenderNode(RenderNode * node)265 void RenderProxy::drawRenderNode(RenderNode* node) {
266     mRenderThread.queue().runSync([=]() { mContext->prepareAndDraw(node); });
267 }
268 
setContentDrawBounds(int left,int top,int right,int bottom)269 void RenderProxy::setContentDrawBounds(int left, int top, int right, int bottom) {
270     mDrawFrameTask.setContentDrawBounds(left, top, right, bottom);
271 }
272 
setFrameCallback(std::function<void (int64_t)> && callback)273 void RenderProxy::setFrameCallback(std::function<void(int64_t)>&& callback) {
274     mDrawFrameTask.setFrameCallback(std::move(callback));
275 }
276 
setFrameCompleteCallback(std::function<void (int64_t)> && callback)277 void RenderProxy::setFrameCompleteCallback(std::function<void(int64_t)>&& callback) {
278     mDrawFrameTask.setFrameCompleteCallback(std::move(callback));
279 }
280 
serializeDisplayListTree()281 void RenderProxy::serializeDisplayListTree() {
282     mRenderThread.queue().post([=]() { mContext->serializeDisplayListTree(); });
283 }
284 
addFrameMetricsObserver(FrameMetricsObserver * observerPtr)285 void RenderProxy::addFrameMetricsObserver(FrameMetricsObserver* observerPtr) {
286     mRenderThread.queue().post([ this, observer = sp{observerPtr} ]() {
287         mContext->addFrameMetricsObserver(observer.get());
288     });
289 }
290 
removeFrameMetricsObserver(FrameMetricsObserver * observerPtr)291 void RenderProxy::removeFrameMetricsObserver(FrameMetricsObserver* observerPtr) {
292     mRenderThread.queue().post([ this, observer = sp{observerPtr} ]() {
293         mContext->removeFrameMetricsObserver(observer.get());
294     });
295 }
296 
copySurfaceInto(sp<Surface> & surface,int left,int top,int right,int bottom,SkBitmap * bitmap)297 int RenderProxy::copySurfaceInto(sp<Surface>& surface, int left, int top, int right, int bottom,
298                                  SkBitmap* bitmap) {
299     auto& thread = RenderThread::getInstance();
300     return static_cast<int>(thread.queue().runSync([&]() -> auto {
301         return thread.readback().copySurfaceInto(*surface, Rect(left, top, right, bottom), bitmap);
302     }));
303 }
304 
prepareToDraw(Bitmap & bitmap)305 void RenderProxy::prepareToDraw(Bitmap& bitmap) {
306     // If we haven't spun up a hardware accelerated window yet, there's no
307     // point in precaching these bitmaps as it can't impact jank.
308     // We also don't know if we even will spin up a hardware-accelerated
309     // window or not.
310     if (!RenderThread::hasInstance()) return;
311     RenderThread* renderThread = &RenderThread::getInstance();
312     bitmap.ref();
313     auto task = [renderThread, &bitmap]() {
314         CanvasContext::prepareToDraw(*renderThread, &bitmap);
315         bitmap.unref();
316     };
317     nsecs_t lastVsync = renderThread->timeLord().latestVsync();
318     nsecs_t estimatedNextVsync = lastVsync + renderThread->timeLord().frameIntervalNanos();
319     nsecs_t timeToNextVsync = estimatedNextVsync - systemTime(CLOCK_MONOTONIC);
320     // We expect the UI thread to take 4ms and for RT to be active from VSYNC+4ms to
321     // VSYNC+12ms or so, so aim for the gap during which RT is expected to
322     // be idle
323     // TODO: Make this concept a first-class supported thing? RT could use
324     // knowledge of pending draws to better schedule this task
325     if (timeToNextVsync > -6_ms && timeToNextVsync < 1_ms) {
326         renderThread->queue().postAt(estimatedNextVsync + 8_ms, task);
327     } else {
328         renderThread->queue().post(task);
329     }
330 }
331 
allocateHardwareBitmap(SkBitmap & bitmap)332 sk_sp<Bitmap> RenderProxy::allocateHardwareBitmap(SkBitmap& bitmap) {
333     auto& thread = RenderThread::getInstance();
334     return thread.queue().runSync([&]() -> auto { return thread.allocateHardwareBitmap(bitmap); });
335 }
336 
copyGraphicBufferInto(GraphicBuffer * buffer,SkBitmap * bitmap)337 int RenderProxy::copyGraphicBufferInto(GraphicBuffer* buffer, SkBitmap* bitmap) {
338     RenderThread& thread = RenderThread::getInstance();
339     if (Properties::isSkiaEnabled() && gettid() == thread.getTid()) {
340         // TODO: fix everything that hits this. We should never be triggering a readback ourselves.
341         return (int)thread.readback().copyGraphicBufferInto(buffer, bitmap);
342     } else {
343         return thread.queue().runSync([&]() -> int {
344             return (int)thread.readback().copyGraphicBufferInto(buffer, bitmap);
345         });
346     }
347 }
348 
onBitmapDestroyed(uint32_t pixelRefId)349 void RenderProxy::onBitmapDestroyed(uint32_t pixelRefId) {
350     if (!RenderThread::hasInstance()) return;
351     RenderThread& thread = RenderThread::getInstance();
352     thread.queue().post(
353             [&thread, pixelRefId]() { thread.renderState().onBitmapDestroyed(pixelRefId); });
354 }
355 
disableVsync()356 void RenderProxy::disableVsync() {
357     Properties::disableVsync = true;
358 }
359 
repackVectorDrawableAtlas()360 void RenderProxy::repackVectorDrawableAtlas() {
361     RenderThread& thread = RenderThread::getInstance();
362     thread.queue().post([&thread]() {
363         // The context may be null if trimMemory executed, but then the atlas was deleted too.
364         if (thread.getGrContext() != nullptr) {
365             thread.cacheManager().acquireVectorDrawableAtlas()->repackIfNeeded(
366                     thread.getGrContext());
367         }
368     });
369 }
370 
releaseVDAtlasEntries()371 void RenderProxy::releaseVDAtlasEntries() {
372     RenderThread& thread = RenderThread::getInstance();
373     thread.queue().post([&thread]() {
374         // The context may be null if trimMemory executed, but then the atlas was deleted too.
375         if (thread.getGrContext() != nullptr) {
376             thread.cacheManager().acquireVectorDrawableAtlas()->delayedReleaseEntries();
377         }
378     });
379 }
380 
381 } /* namespace renderthread */
382 } /* namespace uirenderer */
383 } /* namespace android */
384