CanvasContext.cpp revision 3e9999bd866fac71c72e6b484a9836c87c328a08
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 57static float sBenchMma = 0; 58static int sFrameCount = 0; 59static const float NANOS_PER_MILLIS_F = 1000000.0f; 60#endif 61 62namespace android { 63namespace uirenderer { 64namespace renderthread { 65 66CanvasContext* 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 88void 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 104void 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 123void 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 139CanvasContext::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 155CanvasContext::~CanvasContext() { 156 destroy(); 157 mRenderThread.renderState().unregisterCanvasContext(this); 158 for (auto& node : mRenderNodes) { 159 node->clearRoot(); 160 } 161 mRenderNodes.clear(); 162} 163 164void 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 170void CanvasContext::removeRenderNode(RenderNode* node) { 171 node->clearRoot(); 172 mRenderNodes.erase(std::remove(mRenderNodes.begin(), mRenderNodes.end(), node), 173 mRenderNodes.end()); 174} 175 176void CanvasContext::destroy() { 177 stopDrawing(); 178 setSurface(nullptr); 179 freePrefetchedLayers(); 180 destroyHardwareResources(); 181 mAnimationContext->destroy(); 182} 183 184void 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 201void CanvasContext::setSwapBehavior(SwapBehavior swapBehavior) { 202 mSwapBehavior = swapBehavior; 203} 204 205void CanvasContext::initialize(Surface* surface) { 206 setSurface(surface); 207} 208 209void CanvasContext::updateSurface(Surface* surface) { 210 setSurface(surface); 211} 212 213bool CanvasContext::pauseSurface(Surface* surface) { 214 return mRenderThread.removeFrameCallback(this); 215} 216 217void 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 229void 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 236void CanvasContext::setLightCenter(const Vector3& lightCenter) { 237 mLightGeometry.center = lightCenter; 238} 239 240void CanvasContext::setOpaque(bool opaque) { 241 mOpaque = opaque; 242} 243 244bool 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 266static bool wasSkipped(FrameInfo* info) { 267 return info && ((*info)[FrameInfoIndex::Flags] & FrameInfoFlags::SkippedFrame); 268} 269 270bool 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 312void 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 392void CanvasContext::stopDrawing() { 393 mRenderThread.removeFrameCallback(this); 394 mAnimationContext->pauseAnimators(); 395} 396 397void CanvasContext::notifyFramePending() { 398 ATRACE_CALL(); 399 mRenderThread.pushBackFrameCallback(this); 400} 401 402void 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 mNativeSurface->query(NATIVE_WINDOW_LAST_DEQUEUE_DURATION, &durationUs); 440 swap.dequeueDuration = us2ns(durationUs); 441 mNativeSurface->query(NATIVE_WINDOW_LAST_QUEUE_DURATION, &durationUs); 442 swap.queueDuration = us2ns(durationUs); 443 } else { 444 swap.dequeueDuration = 0; 445 swap.queueDuration = 0; 446 } 447 mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration) 448 = swap.dequeueDuration; 449 mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration) 450 = swap.queueDuration; 451 mHaveNewSurface = false; 452 mFrameNumber = -1; 453 } else { 454 mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration) = 0; 455 mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration) = 0; 456 } 457 458 // TODO: Use a fence for real completion? 459 mCurrentFrameInfo->markFrameCompleted(); 460 461#if LOG_FRAMETIME_MMA 462 float thisFrame = mCurrentFrameInfo->duration( 463 FrameInfoIndex::IssueDrawCommandsStart, 464 FrameInfoIndex::FrameCompleted) / NANOS_PER_MILLIS_F; 465 if (sFrameCount) { 466 sBenchMma = ((9 * sBenchMma) + thisFrame) / 10; 467 } else { 468 sBenchMma = thisFrame; 469 } 470 if (++sFrameCount == 10) { 471 sFrameCount = 1; 472 ALOGD("Average frame time: %.4f", sBenchMma); 473 } 474#endif 475 476 mJankTracker.addFrame(*mCurrentFrameInfo); 477 mRenderThread.jankTracker().addFrame(*mCurrentFrameInfo); 478 if (CC_UNLIKELY(mFrameMetricsReporter.get() != nullptr)) { 479 mFrameMetricsReporter->reportFrameMetrics(mCurrentFrameInfo->data()); 480 } 481 482 GpuMemoryTracker::onFrameCompleted(); 483#ifdef BUGREPORT_FONT_CACHE_USAGE 484 auto renderType = Properties::getRenderPipelineType(); 485 if (RenderPipelineType::OpenGL == renderType) { 486 Caches& caches = Caches::getInstance(); 487 caches.fontRenderer.getFontRenderer().historyTracker().frameCompleted(); 488 } 489#endif 490 491} 492 493// Called by choreographer to do an RT-driven animation 494void CanvasContext::doFrame() { 495 if (!mRenderPipeline->isSurfaceReady()) return; 496 prepareAndDraw(nullptr); 497} 498 499void CanvasContext::prepareAndDraw(RenderNode* node) { 500 ATRACE_CALL(); 501 502 nsecs_t vsync = mRenderThread.timeLord().computeFrameTimeNanos(); 503 int64_t frameInfo[UI_THREAD_FRAME_INFO_SIZE]; 504 UiFrameInfoBuilder(frameInfo) 505 .addFlag(FrameInfoFlags::RTAnimation) 506 .setVsync(vsync, vsync); 507 508 TreeInfo info(TreeInfo::MODE_RT_ONLY, *this); 509 prepareTree(info, frameInfo, systemTime(CLOCK_MONOTONIC), node); 510 if (info.out.canDrawThisFrame) { 511 draw(); 512 } else { 513 // wait on fences so tasks don't overlap next frame 514 waitOnFences(); 515 } 516} 517 518void CanvasContext::markLayerInUse(RenderNode* node) { 519 if (mPrefetchedLayers.erase(node)) { 520 node->decStrong(nullptr); 521 } 522} 523 524void CanvasContext::freePrefetchedLayers() { 525 if (mPrefetchedLayers.size()) { 526 for (auto& node : mPrefetchedLayers) { 527 ALOGW("Incorrectly called buildLayer on View: %s, destroying layer...", 528 node->getName()); 529 node->destroyLayers(); 530 node->decStrong(nullptr); 531 } 532 mPrefetchedLayers.clear(); 533 } 534} 535 536void CanvasContext::buildLayer(RenderNode* node) { 537 ATRACE_CALL(); 538 if (!mRenderPipeline->isContextReady()) return; 539 540 // buildLayer() will leave the tree in an unknown state, so we must stop drawing 541 stopDrawing(); 542 543 TreeInfo info(TreeInfo::MODE_FULL, *this); 544 info.damageAccumulator = &mDamageAccumulator; 545 info.layerUpdateQueue = &mLayerUpdateQueue; 546 info.runAnimations = false; 547 node->prepareTree(info); 548 SkRect ignore; 549 mDamageAccumulator.finish(&ignore); 550 // Tickle the GENERIC property on node to mark it as dirty for damaging 551 // purposes when the frame is actually drawn 552 node->setPropertyFieldsDirty(RenderNode::GENERIC); 553 554 mRenderPipeline->renderLayers(mLightGeometry, &mLayerUpdateQueue, mOpaque, mLightInfo); 555 556 node->incStrong(nullptr); 557 mPrefetchedLayers.insert(node); 558} 559 560bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) { 561 return mRenderPipeline->copyLayerInto(layer, bitmap); 562} 563 564void CanvasContext::destroyHardwareResources() { 565 stopDrawing(); 566 if (mRenderPipeline->isContextReady()) { 567 freePrefetchedLayers(); 568 for (const sp<RenderNode>& node : mRenderNodes) { 569 node->destroyHardwareResources(); 570 } 571 mRenderPipeline->onDestroyHardwareResources(); 572 } 573 mRenderThread.renderState().destroyLayersInUpdater(); 574} 575 576void CanvasContext::trimMemory(RenderThread& thread, int level) { 577 // No context means nothing to free 578 if (!thread.eglManager().hasEglContext()) return; 579 580 ATRACE_CALL(); 581 if (level >= TRIM_MEMORY_COMPLETE) { 582 thread.renderState().flush(Caches::FlushMode::Full); 583 thread.eglManager().destroy(); 584 } else if (level >= TRIM_MEMORY_UI_HIDDEN) { 585 thread.renderState().flush(Caches::FlushMode::Moderate); 586 } 587} 588 589DeferredLayerUpdater* CanvasContext::createTextureLayer() { 590 return mRenderPipeline->createTextureLayer(); 591} 592 593void CanvasContext::dumpFrames(int fd) { 594 FILE* file = fdopen(fd, "a"); 595 fprintf(file, "\n\n---PROFILEDATA---\n"); 596 for (size_t i = 0; i < static_cast<size_t>(FrameInfoIndex::NumIndexes); i++) { 597 fprintf(file, "%s", FrameInfoNames[i].c_str()); 598 fprintf(file, ","); 599 } 600 for (size_t i = 0; i < mFrames.size(); i++) { 601 FrameInfo& frame = mFrames[i]; 602 if (frame[FrameInfoIndex::SyncStart] == 0) { 603 continue; 604 } 605 fprintf(file, "\n"); 606 for (int i = 0; i < static_cast<int>(FrameInfoIndex::NumIndexes); i++) { 607 fprintf(file, "%" PRId64 ",", frame[i]); 608 } 609 } 610 fprintf(file, "\n---PROFILEDATA---\n\n"); 611 fflush(file); 612} 613 614void CanvasContext::resetFrameStats() { 615 mFrames.clear(); 616 mRenderThread.jankTracker().reset(); 617} 618 619void CanvasContext::serializeDisplayListTree() { 620#if ENABLE_RENDERNODE_SERIALIZATION 621 using namespace google::protobuf::io; 622 char package[128]; 623 // Check whether tracing is enabled for this process. 624 FILE * file = fopen("/proc/self/cmdline", "r"); 625 if (file) { 626 if (!fgets(package, 128, file)) { 627 ALOGE("Error reading cmdline: %s (%d)", strerror(errno), errno); 628 fclose(file); 629 return; 630 } 631 fclose(file); 632 } else { 633 ALOGE("Error opening /proc/self/cmdline: %s (%d)", strerror(errno), 634 errno); 635 return; 636 } 637 char path[1024]; 638 snprintf(path, 1024, "/data/data/%s/cache/rendertree_dump", package); 639 int fd = open(path, O_CREAT | O_WRONLY, S_IRWXU | S_IRGRP | S_IROTH); 640 if (fd == -1) { 641 ALOGD("Failed to open '%s'", path); 642 return; 643 } 644 proto::RenderNode tree; 645 // TODO: Streaming writes? 646 mRootRenderNode->copyTo(&tree); 647 std::string data = tree.SerializeAsString(); 648 write(fd, data.c_str(), data.length()); 649 close(fd); 650#endif 651} 652 653void CanvasContext::waitOnFences() { 654 if (mFrameFences.size()) { 655 ATRACE_CALL(); 656 for (auto& fence : mFrameFences) { 657 fence->getResult(); 658 } 659 mFrameFences.clear(); 660 } 661} 662 663class CanvasContext::FuncTaskProcessor : public TaskProcessor<bool> { 664public: 665 explicit FuncTaskProcessor(TaskManager* taskManager) 666 : TaskProcessor<bool>(taskManager) {} 667 668 virtual void onProcess(const sp<Task<bool> >& task) override { 669 FuncTask* t = static_cast<FuncTask*>(task.get()); 670 t->func(); 671 task->setResult(true); 672 } 673}; 674 675void CanvasContext::enqueueFrameWork(std::function<void()>&& func) { 676 if (!mFrameWorkProcessor.get()) { 677 mFrameWorkProcessor = new FuncTaskProcessor(mRenderPipeline->getTaskManager()); 678 } 679 sp<FuncTask> task(new FuncTask()); 680 task->func = func; 681 mFrameFences.push_back(task); 682 mFrameWorkProcessor->add(task); 683} 684 685int64_t CanvasContext::getFrameNumber() { 686 // mFrameNumber is reset to -1 when the surface changes or we swap buffers 687 if (mFrameNumber == -1 && mNativeSurface.get()) { 688 mFrameNumber = static_cast<int64_t>(mNativeSurface->getNextFrameNumber()); 689 } 690 return mFrameNumber; 691} 692 693SkRect CanvasContext::computeDirtyRect(const Frame& frame, SkRect* dirty) { 694 if (frame.width() != mLastFrameWidth || frame.height() != mLastFrameHeight) { 695 // can't rely on prior content of window if viewport size changes 696 dirty->setEmpty(); 697 mLastFrameWidth = frame.width(); 698 mLastFrameHeight = frame.height(); 699 } else if (mHaveNewSurface || frame.bufferAge() == 0) { 700 // New surface needs a full draw 701 dirty->setEmpty(); 702 } else { 703 if (!dirty->isEmpty() && !dirty->intersect(0, 0, frame.width(), frame.height())) { 704 ALOGW("Dirty " RECT_STRING " doesn't intersect with 0 0 %d %d ?", 705 SK_RECT_ARGS(*dirty), frame.width(), frame.height()); 706 dirty->setEmpty(); 707 } 708 profiler().unionDirty(dirty); 709 } 710 711 if (dirty->isEmpty()) { 712 dirty->set(0, 0, frame.width(), frame.height()); 713 } 714 715 // At this point dirty is the area of the window to update. However, 716 // the area of the frame we need to repaint is potentially different, so 717 // stash the screen area for later 718 SkRect windowDirty(*dirty); 719 720 // If the buffer age is 0 we do a full-screen repaint (handled above) 721 // If the buffer age is 1 the buffer contents are the same as they were 722 // last frame so there's nothing to union() against 723 // Therefore we only care about the > 1 case. 724 if (frame.bufferAge() > 1) { 725 if (frame.bufferAge() > (int) mSwapHistory.size()) { 726 // We don't have enough history to handle this old of a buffer 727 // Just do a full-draw 728 dirty->set(0, 0, frame.width(), frame.height()); 729 } else { 730 // At this point we haven't yet added the latest frame 731 // to the damage history (happens below) 732 // So we need to damage 733 for (int i = mSwapHistory.size() - 1; 734 i > ((int) mSwapHistory.size()) - frame.bufferAge(); i--) { 735 dirty->join(mSwapHistory[i].damage); 736 } 737 } 738 } 739 740 return windowDirty; 741} 742 743} /* namespace renderthread */ 744} /* namespace uirenderer */ 745} /* namespace android */ 746