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