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