1 /* 2 * Copyright (C) 2014 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 <GpuMemoryTracker.h> 18 #include "CanvasContext.h" 19 20 #include "AnimationContext.h" 21 #include "Caches.h" 22 #include "EglManager.h" 23 #include "Frame.h" 24 #include "LayerUpdateQueue.h" 25 #include "Properties.h" 26 #include "RenderThread.h" 27 #include "hwui/Canvas.h" 28 #include "renderstate/RenderState.h" 29 #include "renderstate/Stencil.h" 30 #include "protos/hwui.pb.h" 31 #include "OpenGLPipeline.h" 32 #include "pipeline/skia/SkiaOpenGLPipeline.h" 33 #include "pipeline/skia/SkiaPipeline.h" 34 #include "pipeline/skia/SkiaVulkanPipeline.h" 35 #include "utils/GLUtils.h" 36 #include "utils/TimeUtils.h" 37 38 #include <cutils/properties.h> 39 #include <google/protobuf/io/zero_copy_stream_impl.h> 40 #include <private/hwui/DrawGlInfo.h> 41 #include <strings.h> 42 43 #include <algorithm> 44 #include <fcntl.h> 45 #include <sys/stat.h> 46 47 #include <cstdlib> 48 49 #define TRIM_MEMORY_COMPLETE 80 50 #define TRIM_MEMORY_UI_HIDDEN 20 51 52 #define ENABLE_RENDERNODE_SERIALIZATION false 53 54 #define LOG_FRAMETIME_MMA 0 55 56 #if LOG_FRAMETIME_MMA 57 static float sBenchMma = 0; 58 static int sFrameCount = 0; 59 static const float NANOS_PER_MILLIS_F = 1000000.0f; 60 #endif 61 62 namespace android { 63 namespace uirenderer { 64 namespace renderthread { 65 66 CanvasContext* CanvasContext::create(RenderThread& thread, 67 bool translucent, RenderNode* rootRenderNode, IContextFactory* contextFactory) { 68 69 auto renderType = Properties::getRenderPipelineType(); 70 71 switch (renderType) { 72 case RenderPipelineType::OpenGL: 73 return new CanvasContext(thread, translucent, rootRenderNode, contextFactory, 74 std::make_unique<OpenGLPipeline>(thread)); 75 case RenderPipelineType::SkiaGL: 76 return new CanvasContext(thread, translucent, rootRenderNode, contextFactory, 77 std::make_unique<skiapipeline::SkiaOpenGLPipeline>(thread)); 78 case RenderPipelineType::SkiaVulkan: 79 return new CanvasContext(thread, translucent, rootRenderNode, contextFactory, 80 std::make_unique<skiapipeline::SkiaVulkanPipeline>(thread)); 81 default: 82 LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType); 83 break; 84 } 85 return nullptr; 86 } 87 88 void CanvasContext::destroyLayer(RenderNode* node) { 89 auto renderType = Properties::getRenderPipelineType(); 90 switch (renderType) { 91 case RenderPipelineType::OpenGL: 92 OpenGLPipeline::destroyLayer(node); 93 break; 94 case RenderPipelineType::SkiaGL: 95 case RenderPipelineType::SkiaVulkan: 96 skiapipeline::SkiaPipeline::destroyLayer(node); 97 break; 98 default: 99 LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType); 100 break; 101 } 102 } 103 104 void CanvasContext::invokeFunctor(const RenderThread& thread, Functor* functor) { 105 ATRACE_CALL(); 106 auto renderType = Properties::getRenderPipelineType(); 107 switch (renderType) { 108 case RenderPipelineType::OpenGL: 109 OpenGLPipeline::invokeFunctor(thread, functor); 110 break; 111 case RenderPipelineType::SkiaGL: 112 skiapipeline::SkiaOpenGLPipeline::invokeFunctor(thread, functor); 113 break; 114 case RenderPipelineType::SkiaVulkan: 115 skiapipeline::SkiaVulkanPipeline::invokeFunctor(thread, functor); 116 break; 117 default: 118 LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType); 119 break; 120 } 121 } 122 123 void CanvasContext::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) { 124 auto renderType = Properties::getRenderPipelineType(); 125 switch (renderType) { 126 case RenderPipelineType::OpenGL: 127 OpenGLPipeline::prepareToDraw(thread, bitmap); 128 break; 129 case RenderPipelineType::SkiaGL: 130 case RenderPipelineType::SkiaVulkan: 131 skiapipeline::SkiaPipeline::prepareToDraw(thread, bitmap); 132 break; 133 default: 134 LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType); 135 break; 136 } 137 } 138 139 CanvasContext::CanvasContext(RenderThread& thread, bool translucent, 140 RenderNode* rootRenderNode, IContextFactory* contextFactory, 141 std::unique_ptr<IRenderPipeline> renderPipeline) 142 : mRenderThread(thread) 143 , mOpaque(!translucent) 144 , mAnimationContext(contextFactory->createAnimationContext(mRenderThread.timeLord())) 145 , mJankTracker(thread.mainDisplayInfo()) 146 , mProfiler(mFrames) 147 , mContentDrawBounds(0, 0, 0, 0) 148 , mRenderPipeline(std::move(renderPipeline)) { 149 rootRenderNode->makeRoot(); 150 mRenderNodes.emplace_back(rootRenderNode); 151 mRenderThread.renderState().registerCanvasContext(this); 152 mProfiler.setDensity(mRenderThread.mainDisplayInfo().density); 153 } 154 155 CanvasContext::~CanvasContext() { 156 destroy(); 157 mRenderThread.renderState().unregisterCanvasContext(this); 158 for (auto& node : mRenderNodes) { 159 node->clearRoot(); 160 } 161 mRenderNodes.clear(); 162 } 163 164 void CanvasContext::addRenderNode(RenderNode* node, bool placeFront) { 165 int pos = placeFront ? 0 : static_cast<int>(mRenderNodes.size()); 166 node->makeRoot(); 167 mRenderNodes.emplace(mRenderNodes.begin() + pos, node); 168 } 169 170 void CanvasContext::removeRenderNode(RenderNode* node) { 171 node->clearRoot(); 172 mRenderNodes.erase(std::remove(mRenderNodes.begin(), mRenderNodes.end(), node), 173 mRenderNodes.end()); 174 } 175 176 void CanvasContext::destroy() { 177 stopDrawing(); 178 setSurface(nullptr); 179 freePrefetchedLayers(); 180 destroyHardwareResources(); 181 mAnimationContext->destroy(); 182 } 183 184 void CanvasContext::setSurface(Surface* surface) { 185 ATRACE_CALL(); 186 187 mNativeSurface = surface; 188 189 bool hasSurface = mRenderPipeline->setSurface(surface, mSwapBehavior); 190 191 mFrameNumber = -1; 192 193 if (hasSurface) { 194 mHaveNewSurface = true; 195 mSwapHistory.clear(); 196 } else { 197 mRenderThread.removeFrameCallback(this); 198 } 199 } 200 201 void CanvasContext::setSwapBehavior(SwapBehavior swapBehavior) { 202 mSwapBehavior = swapBehavior; 203 } 204 205 void CanvasContext::initialize(Surface* surface) { 206 setSurface(surface); 207 } 208 209 void CanvasContext::updateSurface(Surface* surface) { 210 setSurface(surface); 211 } 212 213 bool CanvasContext::pauseSurface(Surface* surface) { 214 return mRenderThread.removeFrameCallback(this); 215 } 216 217 void CanvasContext::setStopped(bool stopped) { 218 if (mStopped != stopped) { 219 mStopped = stopped; 220 if (mStopped) { 221 mRenderThread.removeFrameCallback(this); 222 mRenderPipeline->onStop(); 223 } else if (mIsDirty && hasSurface()) { 224 mRenderThread.postFrameCallback(this); 225 } 226 } 227 } 228 229 void CanvasContext::setup(float lightRadius, 230 uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) { 231 mLightGeometry.radius = lightRadius; 232 mLightInfo.ambientShadowAlpha = ambientShadowAlpha; 233 mLightInfo.spotShadowAlpha = spotShadowAlpha; 234 } 235 236 void CanvasContext::setLightCenter(const Vector3& lightCenter) { 237 mLightGeometry.center = lightCenter; 238 } 239 240 void CanvasContext::setOpaque(bool opaque) { 241 mOpaque = opaque; 242 } 243 244 bool CanvasContext::makeCurrent() { 245 if (mStopped) return false; 246 247 auto result = mRenderPipeline->makeCurrent(); 248 switch (result) { 249 case MakeCurrentResult::AlreadyCurrent: 250 return true; 251 case MakeCurrentResult::Failed: 252 mHaveNewSurface = true; 253 setSurface(nullptr); 254 return false; 255 case MakeCurrentResult::Succeeded: 256 mHaveNewSurface = true; 257 return true; 258 default: 259 LOG_ALWAYS_FATAL("unexpected result %d from IRenderPipeline::makeCurrent", 260 (int32_t) result); 261 } 262 263 return true; 264 } 265 266 static bool wasSkipped(FrameInfo* info) { 267 return info && ((*info)[FrameInfoIndex::Flags] & FrameInfoFlags::SkippedFrame); 268 } 269 270 bool CanvasContext::isSwapChainStuffed() { 271 static const auto SLOW_THRESHOLD = 6_ms; 272 273 if (mSwapHistory.size() != mSwapHistory.capacity()) { 274 // We want at least 3 frames of history before attempting to 275 // guess if the queue is stuffed 276 return false; 277 } 278 nsecs_t frameInterval = mRenderThread.timeLord().frameIntervalNanos(); 279 auto& swapA = mSwapHistory[0]; 280 281 // Was there a happy queue & dequeue time? If so, don't 282 // consider it stuffed 283 if (swapA.dequeueDuration < SLOW_THRESHOLD 284 && swapA.queueDuration < SLOW_THRESHOLD) { 285 return false; 286 } 287 288 for (size_t i = 1; i < mSwapHistory.size(); i++) { 289 auto& swapB = mSwapHistory[i]; 290 291 // If there's a multi-frameInterval gap we effectively already dropped a frame, 292 // so consider the queue healthy. 293 if (swapA.swapCompletedTime - swapB.swapCompletedTime > frameInterval * 3) { 294 return false; 295 } 296 297 // Was there a happy queue & dequeue time? If so, don't 298 // consider it stuffed 299 if (swapB.dequeueDuration < SLOW_THRESHOLD 300 && swapB.queueDuration < SLOW_THRESHOLD) { 301 return false; 302 } 303 304 swapA = swapB; 305 } 306 307 // All signs point to a stuffed swap chain 308 ATRACE_NAME("swap chain stuffed"); 309 return true; 310 } 311 312 void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, 313 int64_t syncQueued, RenderNode* target) { 314 mRenderThread.removeFrameCallback(this); 315 316 // If the previous frame was dropped we don't need to hold onto it, so 317 // just keep using the previous frame's structure instead 318 if (!wasSkipped(mCurrentFrameInfo)) { 319 mCurrentFrameInfo = &mFrames.next(); 320 } 321 mCurrentFrameInfo->importUiThreadInfo(uiFrameInfo); 322 mCurrentFrameInfo->set(FrameInfoIndex::SyncQueued) = syncQueued; 323 mCurrentFrameInfo->markSyncStart(); 324 325 info.damageAccumulator = &mDamageAccumulator; 326 info.layerUpdateQueue = &mLayerUpdateQueue; 327 328 mAnimationContext->startFrame(info.mode); 329 for (const sp<RenderNode>& node : mRenderNodes) { 330 // Only the primary target node will be drawn full - all other nodes would get drawn in 331 // real time mode. In case of a window, the primary node is the window content and the other 332 // node(s) are non client / filler nodes. 333 info.mode = (node.get() == target ? TreeInfo::MODE_FULL : TreeInfo::MODE_RT_ONLY); 334 node->prepareTree(info); 335 GL_CHECKPOINT(MODERATE); 336 } 337 mAnimationContext->runRemainingAnimations(info); 338 GL_CHECKPOINT(MODERATE); 339 340 freePrefetchedLayers(); 341 GL_CHECKPOINT(MODERATE); 342 343 mIsDirty = true; 344 345 if (CC_UNLIKELY(!mNativeSurface.get())) { 346 mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame); 347 info.out.canDrawThisFrame = false; 348 return; 349 } 350 351 if (CC_LIKELY(mSwapHistory.size() && !Properties::forceDrawFrame)) { 352 nsecs_t latestVsync = mRenderThread.timeLord().latestVsync(); 353 SwapHistory& lastSwap = mSwapHistory.back(); 354 nsecs_t vsyncDelta = std::abs(lastSwap.vsyncTime - latestVsync); 355 // The slight fudge-factor is to deal with cases where 356 // the vsync was estimated due to being slow handling the signal. 357 // See the logic in TimeLord#computeFrameTimeNanos or in 358 // Choreographer.java for details on when this happens 359 if (vsyncDelta < 2_ms) { 360 // Already drew for this vsync pulse, UI draw request missed 361 // the deadline for RT animations 362 info.out.canDrawThisFrame = false; 363 } else if (vsyncDelta >= mRenderThread.timeLord().frameIntervalNanos() * 3 364 || (latestVsync - mLastDropVsync) < 500_ms) { 365 // It's been several frame intervals, assume the buffer queue is fine 366 // or the last drop was too recent 367 info.out.canDrawThisFrame = true; 368 } else { 369 info.out.canDrawThisFrame = !isSwapChainStuffed(); 370 if (!info.out.canDrawThisFrame) { 371 // dropping frame 372 mLastDropVsync = mRenderThread.timeLord().latestVsync(); 373 } 374 } 375 } else { 376 info.out.canDrawThisFrame = true; 377 } 378 379 if (!info.out.canDrawThisFrame) { 380 mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame); 381 } 382 383 if (info.out.hasAnimations || !info.out.canDrawThisFrame) { 384 if (!info.out.requiresUiRedraw) { 385 // If animationsNeedsRedraw is set don't bother posting for an RT anim 386 // as we will just end up fighting the UI thread. 387 mRenderThread.postFrameCallback(this); 388 } 389 } 390 } 391 392 void CanvasContext::stopDrawing() { 393 mRenderThread.removeFrameCallback(this); 394 mAnimationContext->pauseAnimators(); 395 } 396 397 void CanvasContext::notifyFramePending() { 398 ATRACE_CALL(); 399 mRenderThread.pushBackFrameCallback(this); 400 } 401 402 void CanvasContext::draw() { 403 SkRect dirty; 404 mDamageAccumulator.finish(&dirty); 405 406 // TODO: Re-enable after figuring out cause of b/22592975 407 // if (dirty.isEmpty() && Properties::skipEmptyFrames) { 408 // mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame); 409 // return; 410 // } 411 412 mCurrentFrameInfo->markIssueDrawCommandsStart(); 413 414 Frame frame = mRenderPipeline->getFrame(); 415 416 SkRect windowDirty = computeDirtyRect(frame, &dirty); 417 418 bool drew = mRenderPipeline->draw(frame, windowDirty, dirty, mLightGeometry, &mLayerUpdateQueue, 419 mContentDrawBounds, mOpaque, mLightInfo, mRenderNodes, &(profiler())); 420 421 waitOnFences(); 422 423 bool requireSwap = false; 424 bool didSwap = mRenderPipeline->swapBuffers(frame, drew, windowDirty, mCurrentFrameInfo, 425 &requireSwap); 426 427 mIsDirty = false; 428 429 if (requireSwap) { 430 if (!didSwap) { //some error happened 431 setSurface(nullptr); 432 } 433 SwapHistory& swap = mSwapHistory.next(); 434 swap.damage = windowDirty; 435 swap.swapCompletedTime = systemTime(CLOCK_MONOTONIC); 436 swap.vsyncTime = mRenderThread.timeLord().latestVsync(); 437 if (mNativeSurface.get()) { 438 int durationUs; 439 nsecs_t dequeueStart = mNativeSurface->getLastDequeueStartTime(); 440 if (dequeueStart < mCurrentFrameInfo->get(FrameInfoIndex::SyncStart)) { 441 // Ignoring dequeue duration as it happened prior to frame render start 442 // and thus is not part of the frame. 443 swap.dequeueDuration = 0; 444 } else { 445 mNativeSurface->query(NATIVE_WINDOW_LAST_DEQUEUE_DURATION, &durationUs); 446 swap.dequeueDuration = us2ns(durationUs); 447 } 448 mNativeSurface->query(NATIVE_WINDOW_LAST_QUEUE_DURATION, &durationUs); 449 swap.queueDuration = us2ns(durationUs); 450 } else { 451 swap.dequeueDuration = 0; 452 swap.queueDuration = 0; 453 } 454 mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration) 455 = swap.dequeueDuration; 456 mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration) 457 = swap.queueDuration; 458 mHaveNewSurface = false; 459 mFrameNumber = -1; 460 } else { 461 mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration) = 0; 462 mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration) = 0; 463 } 464 465 // TODO: Use a fence for real completion? 466 mCurrentFrameInfo->markFrameCompleted(); 467 468 #if LOG_FRAMETIME_MMA 469 float thisFrame = mCurrentFrameInfo->duration( 470 FrameInfoIndex::IssueDrawCommandsStart, 471 FrameInfoIndex::FrameCompleted) / NANOS_PER_MILLIS_F; 472 if (sFrameCount) { 473 sBenchMma = ((9 * sBenchMma) + thisFrame) / 10; 474 } else { 475 sBenchMma = thisFrame; 476 } 477 if (++sFrameCount == 10) { 478 sFrameCount = 1; 479 ALOGD("Average frame time: %.4f", sBenchMma); 480 } 481 #endif 482 483 mJankTracker.addFrame(*mCurrentFrameInfo); 484 mRenderThread.jankTracker().addFrame(*mCurrentFrameInfo); 485 if (CC_UNLIKELY(mFrameMetricsReporter.get() != nullptr)) { 486 mFrameMetricsReporter->reportFrameMetrics(mCurrentFrameInfo->data()); 487 } 488 489 GpuMemoryTracker::onFrameCompleted(); 490 #ifdef BUGREPORT_FONT_CACHE_USAGE 491 auto renderType = Properties::getRenderPipelineType(); 492 if (RenderPipelineType::OpenGL == renderType) { 493 Caches& caches = Caches::getInstance(); 494 caches.fontRenderer.getFontRenderer().historyTracker().frameCompleted(); 495 } 496 #endif 497 498 } 499 500 // Called by choreographer to do an RT-driven animation 501 void CanvasContext::doFrame() { 502 if (!mRenderPipeline->isSurfaceReady()) return; 503 prepareAndDraw(nullptr); 504 } 505 506 void CanvasContext::prepareAndDraw(RenderNode* node) { 507 ATRACE_CALL(); 508 509 nsecs_t vsync = mRenderThread.timeLord().computeFrameTimeNanos(); 510 int64_t frameInfo[UI_THREAD_FRAME_INFO_SIZE]; 511 UiFrameInfoBuilder(frameInfo) 512 .addFlag(FrameInfoFlags::RTAnimation) 513 .setVsync(vsync, vsync); 514 515 TreeInfo info(TreeInfo::MODE_RT_ONLY, *this); 516 prepareTree(info, frameInfo, systemTime(CLOCK_MONOTONIC), node); 517 if (info.out.canDrawThisFrame) { 518 draw(); 519 } else { 520 // wait on fences so tasks don't overlap next frame 521 waitOnFences(); 522 } 523 } 524 525 void CanvasContext::markLayerInUse(RenderNode* node) { 526 if (mPrefetchedLayers.erase(node)) { 527 node->decStrong(nullptr); 528 } 529 } 530 531 void CanvasContext::freePrefetchedLayers() { 532 if (mPrefetchedLayers.size()) { 533 for (auto& node : mPrefetchedLayers) { 534 ALOGW("Incorrectly called buildLayer on View: %s, destroying layer...", 535 node->getName()); 536 node->destroyLayers(); 537 node->decStrong(nullptr); 538 } 539 mPrefetchedLayers.clear(); 540 } 541 } 542 543 void CanvasContext::buildLayer(RenderNode* node) { 544 ATRACE_CALL(); 545 if (!mRenderPipeline->isContextReady()) return; 546 547 // buildLayer() will leave the tree in an unknown state, so we must stop drawing 548 stopDrawing(); 549 550 TreeInfo info(TreeInfo::MODE_FULL, *this); 551 info.damageAccumulator = &mDamageAccumulator; 552 info.layerUpdateQueue = &mLayerUpdateQueue; 553 info.runAnimations = false; 554 node->prepareTree(info); 555 SkRect ignore; 556 mDamageAccumulator.finish(&ignore); 557 // Tickle the GENERIC property on node to mark it as dirty for damaging 558 // purposes when the frame is actually drawn 559 node->setPropertyFieldsDirty(RenderNode::GENERIC); 560 561 mRenderPipeline->renderLayers(mLightGeometry, &mLayerUpdateQueue, mOpaque, mLightInfo); 562 563 node->incStrong(nullptr); 564 mPrefetchedLayers.insert(node); 565 } 566 567 bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) { 568 return mRenderPipeline->copyLayerInto(layer, bitmap); 569 } 570 571 void CanvasContext::destroyHardwareResources() { 572 stopDrawing(); 573 if (mRenderPipeline->isContextReady()) { 574 freePrefetchedLayers(); 575 for (const sp<RenderNode>& node : mRenderNodes) { 576 node->destroyHardwareResources(); 577 } 578 mRenderPipeline->onDestroyHardwareResources(); 579 } 580 } 581 582 void CanvasContext::trimMemory(RenderThread& thread, int level) { 583 // No context means nothing to free 584 if (!thread.eglManager().hasEglContext()) return; 585 586 ATRACE_CALL(); 587 if (level >= TRIM_MEMORY_COMPLETE) { 588 thread.renderState().flush(Caches::FlushMode::Full); 589 thread.eglManager().destroy(); 590 } else if (level >= TRIM_MEMORY_UI_HIDDEN) { 591 thread.renderState().flush(Caches::FlushMode::Moderate); 592 } 593 } 594 595 DeferredLayerUpdater* CanvasContext::createTextureLayer() { 596 return mRenderPipeline->createTextureLayer(); 597 } 598 599 void CanvasContext::dumpFrames(int fd) { 600 mJankTracker.dump(fd); 601 FILE* file = fdopen(fd, "a"); 602 fprintf(file, "\n\n---PROFILEDATA---\n"); 603 for (size_t i = 0; i < static_cast<size_t>(FrameInfoIndex::NumIndexes); i++) { 604 fprintf(file, "%s", FrameInfoNames[i].c_str()); 605 fprintf(file, ","); 606 } 607 for (size_t i = 0; i < mFrames.size(); i++) { 608 FrameInfo& frame = mFrames[i]; 609 if (frame[FrameInfoIndex::SyncStart] == 0) { 610 continue; 611 } 612 fprintf(file, "\n"); 613 for (int i = 0; i < static_cast<int>(FrameInfoIndex::NumIndexes); i++) { 614 fprintf(file, "%" PRId64 ",", frame[i]); 615 } 616 } 617 fprintf(file, "\n---PROFILEDATA---\n\n"); 618 fflush(file); 619 } 620 621 void CanvasContext::resetFrameStats() { 622 mFrames.clear(); 623 mRenderThread.jankTracker().reset(); 624 } 625 626 void CanvasContext::setName(const std::string&& name) { 627 mJankTracker.setDescription(JankTrackerType::Window, std::move(name)); 628 } 629 630 void CanvasContext::serializeDisplayListTree() { 631 #if ENABLE_RENDERNODE_SERIALIZATION 632 using namespace google::protobuf::io; 633 char package[128]; 634 // Check whether tracing is enabled for this process. 635 FILE * file = fopen("/proc/self/cmdline", "r"); 636 if (file) { 637 if (!fgets(package, 128, file)) { 638 ALOGE("Error reading cmdline: %s (%d)", strerror(errno), errno); 639 fclose(file); 640 return; 641 } 642 fclose(file); 643 } else { 644 ALOGE("Error opening /proc/self/cmdline: %s (%d)", strerror(errno), 645 errno); 646 return; 647 } 648 char path[1024]; 649 snprintf(path, 1024, "/data/data/%s/cache/rendertree_dump", package); 650 int fd = open(path, O_CREAT | O_WRONLY, S_IRWXU | S_IRGRP | S_IROTH); 651 if (fd == -1) { 652 ALOGD("Failed to open '%s'", path); 653 return; 654 } 655 proto::RenderNode tree; 656 // TODO: Streaming writes? 657 mRootRenderNode->copyTo(&tree); 658 std::string data = tree.SerializeAsString(); 659 write(fd, data.c_str(), data.length()); 660 close(fd); 661 #endif 662 } 663 664 void CanvasContext::waitOnFences() { 665 if (mFrameFences.size()) { 666 ATRACE_CALL(); 667 for (auto& fence : mFrameFences) { 668 fence->getResult(); 669 } 670 mFrameFences.clear(); 671 } 672 } 673 674 class CanvasContext::FuncTaskProcessor : public TaskProcessor<bool> { 675 public: 676 explicit FuncTaskProcessor(TaskManager* taskManager) 677 : TaskProcessor<bool>(taskManager) {} 678 679 virtual void onProcess(const sp<Task<bool> >& task) override { 680 FuncTask* t = static_cast<FuncTask*>(task.get()); 681 t->func(); 682 task->setResult(true); 683 } 684 }; 685 686 void CanvasContext::enqueueFrameWork(std::function<void()>&& func) { 687 if (!mFrameWorkProcessor.get()) { 688 mFrameWorkProcessor = new FuncTaskProcessor(mRenderPipeline->getTaskManager()); 689 } 690 sp<FuncTask> task(new FuncTask()); 691 task->func = func; 692 mFrameFences.push_back(task); 693 mFrameWorkProcessor->add(task); 694 } 695 696 int64_t CanvasContext::getFrameNumber() { 697 // mFrameNumber is reset to -1 when the surface changes or we swap buffers 698 if (mFrameNumber == -1 && mNativeSurface.get()) { 699 mFrameNumber = static_cast<int64_t>(mNativeSurface->getNextFrameNumber()); 700 } 701 return mFrameNumber; 702 } 703 704 SkRect CanvasContext::computeDirtyRect(const Frame& frame, SkRect* dirty) { 705 if (frame.width() != mLastFrameWidth || frame.height() != mLastFrameHeight) { 706 // can't rely on prior content of window if viewport size changes 707 dirty->setEmpty(); 708 mLastFrameWidth = frame.width(); 709 mLastFrameHeight = frame.height(); 710 } else if (mHaveNewSurface || frame.bufferAge() == 0) { 711 // New surface needs a full draw 712 dirty->setEmpty(); 713 } else { 714 if (!dirty->isEmpty() && !dirty->intersect(0, 0, frame.width(), frame.height())) { 715 ALOGW("Dirty " RECT_STRING " doesn't intersect with 0 0 %d %d ?", 716 SK_RECT_ARGS(*dirty), frame.width(), frame.height()); 717 dirty->setEmpty(); 718 } 719 profiler().unionDirty(dirty); 720 } 721 722 if (dirty->isEmpty()) { 723 dirty->set(0, 0, frame.width(), frame.height()); 724 } 725 726 // At this point dirty is the area of the window to update. However, 727 // the area of the frame we need to repaint is potentially different, so 728 // stash the screen area for later 729 SkRect windowDirty(*dirty); 730 731 // If the buffer age is 0 we do a full-screen repaint (handled above) 732 // If the buffer age is 1 the buffer contents are the same as they were 733 // last frame so there's nothing to union() against 734 // Therefore we only care about the > 1 case. 735 if (frame.bufferAge() > 1) { 736 if (frame.bufferAge() > (int) mSwapHistory.size()) { 737 // We don't have enough history to handle this old of a buffer 738 // Just do a full-draw 739 dirty->set(0, 0, frame.width(), frame.height()); 740 } else { 741 // At this point we haven't yet added the latest frame 742 // to the damage history (happens below) 743 // So we need to damage 744 for (int i = mSwapHistory.size() - 1; 745 i > ((int) mSwapHistory.size()) - frame.bufferAge(); i--) { 746 dirty->join(mSwapHistory[i].damage); 747 } 748 } 749 } 750 751 return windowDirty; 752 } 753 754 } /* namespace renderthread */ 755 } /* namespace uirenderer */ 756 } /* namespace android */ 757