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