diff options
Diffstat (limited to 'libs/hwui/renderthread')
20 files changed, 711 insertions, 1282 deletions
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp index 55694d046c2f..907f2d2d398f 100644 --- a/libs/hwui/renderthread/CacheManager.cpp +++ b/libs/hwui/renderthread/CacheManager.cpp @@ -17,11 +17,14 @@ #include "CacheManager.h" #include "Layer.h" +#include "Properties.h" #include "RenderThread.h" +#include "pipeline/skia/ShaderCache.h" #include "renderstate/RenderState.h" -#include <gui/Surface.h> #include <GrContextOptions.h> +#include <SkExecutor.h> +#include <gui/Surface.h> #include <math.h> #include <set> @@ -41,19 +44,22 @@ namespace renderthread { #define FONT_CACHE_MIN_MB (0.5f) #define FONT_CACHE_MAX_MB (4.0f) -CacheManager::CacheManager(const DisplayInfo& display) - : mMaxSurfaceArea(display.w * display.h) { - mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(mMaxSurfaceArea/2, - skiapipeline::VectorDrawableAtlas::StorageMode::allowSharedSurface); +CacheManager::CacheManager(const DisplayInfo& display) : mMaxSurfaceArea(display.w * display.h) { + mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas( + mMaxSurfaceArea / 2, + skiapipeline::VectorDrawableAtlas::StorageMode::disallowSharedSurface); + if (Properties::isSkiaEnabled()) { + skiapipeline::ShaderCache::get().initShaderDiskCache(); + } } -void CacheManager::reset(GrContext* context) { - if (context != mGrContext.get()) { +void CacheManager::reset(sk_sp<GrContext> context) { + if (context != mGrContext) { destroy(); } if (context) { - mGrContext = sk_ref_sp(context); + mGrContext = std::move(context); mGrContext->getResourceCacheLimits(&mMaxResources, nullptr); updateContextCacheSizes(); } @@ -62,7 +68,9 @@ void CacheManager::reset(GrContext* context) { void CacheManager::destroy() { // cleanup any caches here as the GrContext is about to go away... mGrContext.reset(nullptr); - mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(mMaxSurfaceArea/2); + mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas( + mMaxSurfaceArea / 2, + skiapipeline::VectorDrawableAtlas::StorageMode::disallowSharedSurface); } void CacheManager::updateContextCacheSizes() { @@ -72,6 +80,29 @@ void CacheManager::updateContextCacheSizes() { mGrContext->setResourceCacheLimits(mMaxResources, mMaxResourceBytes); } +class CacheManager::SkiaTaskProcessor : public TaskProcessor<bool>, public SkExecutor { +public: + explicit SkiaTaskProcessor(TaskManager* taskManager) : TaskProcessor<bool>(taskManager) {} + + // This is really a Task<void> but that doesn't really work when Future<> + // expects to be able to get/set a value + struct SkiaTask : public Task<bool> { + std::function<void()> func; + }; + + virtual void add(std::function<void(void)> func) override { + sp<SkiaTask> task(new SkiaTask()); + task->func = func; + TaskProcessor<bool>::add(task); + } + + virtual void onProcess(const sp<Task<bool> >& task) override { + SkiaTask* t = static_cast<SkiaTask*>(task.get()); + t->func(); + task->setResult(true); + } +}; + void CacheManager::configureContext(GrContextOptions* contextOptions) { contextOptions->fAllowPathMaskCaching = true; @@ -94,6 +125,15 @@ void CacheManager::configureContext(GrContextOptions* contextOptions) { // Skia's implementation doesn't provide a mechanism to resize the font cache due to // the potential cost of recreating the glyphs. contextOptions->fGlyphCacheTextureMaximumBytes = fontCacheMB * 1024 * 1024; + + if (mTaskManager.canRunTasks()) { + if (!mTaskProcessor.get()) { + mTaskProcessor = new SkiaTaskProcessor(&mTaskManager); + } + contextOptions->fExecutor = mTaskProcessor.get(); + } + + contextOptions->fPersistentCache = &skiapipeline::ShaderCache::get(); } void CacheManager::trimMemory(TrimMemoryMode mode) { @@ -105,7 +145,7 @@ void CacheManager::trimMemory(TrimMemoryMode mode) { switch (mode) { case TrimMemoryMode::Complete: - mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(mMaxSurfaceArea/2); + mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(mMaxSurfaceArea / 2); mGrContext->freeGpuResources(); break; case TrimMemoryMode::UiHidden: @@ -143,8 +183,8 @@ void CacheManager::dumpMemoryUsage(String8& log, const RenderState* renderState) log.appendFormat("Caches:\n"); log.appendFormat(" Current / Maximum\n"); - log.appendFormat(" VectorDrawableAtlas %6.2f kB / %6.2f kB (entries = %zu)\n", - 0.0f, 0.0f, (size_t)0); + log.appendFormat(" VectorDrawableAtlas %6.2f kB / %6.2f kB (entries = %zu)\n", 0.0f, 0.0f, + (size_t)0); if (renderState) { if (renderState->mActiveLayers.size() > 0) { @@ -153,24 +193,21 @@ void CacheManager::dumpMemoryUsage(String8& log, const RenderState* renderState) size_t layerMemoryTotal = 0; for (std::set<Layer*>::iterator it = renderState->mActiveLayers.begin(); - it != renderState->mActiveLayers.end(); it++) { + it != renderState->mActiveLayers.end(); it++) { const Layer* layer = *it; const char* layerType = layer->getApi() == Layer::Api::OpenGL ? "GlLayer" : "VkLayer"; - log.appendFormat(" %s size %dx%d\n", layerType, - layer->getWidth(), layer->getHeight()); + log.appendFormat(" %s size %dx%d\n", layerType, layer->getWidth(), + layer->getHeight()); layerMemoryTotal += layer->getWidth() * layer->getHeight() * 4; } log.appendFormat(" Layers Total %6.2f kB (numLayers = %zu)\n", layerMemoryTotal / 1024.0f, renderState->mActiveLayers.size()); } - log.appendFormat("Total memory usage:\n"); - log.appendFormat(" %zu bytes, %.2f MB (%.2f MB is purgeable)\n", - bytesCached, bytesCached / 1024.0f / 1024.0f, + log.appendFormat(" %zu bytes, %.2f MB (%.2f MB is purgeable)\n", bytesCached, + bytesCached / 1024.0f / 1024.0f, mGrContext->getResourceCachePurgeableBytes() / 1024.0f / 1024.0f); - - } } /* namespace renderthread */ diff --git a/libs/hwui/renderthread/CacheManager.h b/libs/hwui/renderthread/CacheManager.h index 90362f33358d..7d733525194f 100644 --- a/libs/hwui/renderthread/CacheManager.h +++ b/libs/hwui/renderthread/CacheManager.h @@ -22,7 +22,10 @@ #include <ui/DisplayInfo.h> #include <utils/String8.h> #include <vector> + #include "pipeline/skia/VectorDrawableAtlas.h" +#include "thread/TaskManager.h" +#include "thread/TaskProcessor.h" namespace android { @@ -39,10 +42,7 @@ class RenderThread; class CacheManager { public: - enum class TrimMemoryMode { - Complete, - UiHidden - }; + enum class TrimMemoryMode { Complete, UiHidden }; void configureContext(GrContextOptions* context); void trimMemory(TrimMemoryMode mode); @@ -54,13 +54,14 @@ public: size_t getCacheSize() const { return mMaxResourceBytes; } size_t getBackgroundCacheSize() const { return mBackgroundResourceBytes; } + TaskManager* getTaskManager() { return &mTaskManager; } + private: friend class RenderThread; CacheManager(const DisplayInfo& display); - - void reset(GrContext* grContext); + void reset(sk_sp<GrContext> grContext); void destroy(); void updateContextCacheSizes(); @@ -77,6 +78,10 @@ private: }; sp<skiapipeline::VectorDrawableAtlas> mVectorDrawableAtlas; + + class SkiaTaskProcessor; + sp<SkiaTaskProcessor> mTaskProcessor; + TaskManager mTaskManager; }; } /* namespace renderthread */ @@ -84,4 +89,3 @@ private: } /* namespace android */ #endif /* CACHEMANAGER_H */ - diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 5d7f5948b0ec..820789dd055d 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -14,35 +14,36 @@ * limitations under the License. */ -#include <GpuMemoryTracker.h> #include "CanvasContext.h" +#include <GpuMemoryTracker.h> #include "AnimationContext.h" #include "Caches.h" #include "EglManager.h" #include "Frame.h" #include "LayerUpdateQueue.h" +#include "OpenGLPipeline.h" #include "Properties.h" #include "RenderThread.h" #include "hwui/Canvas.h" -#include "renderstate/RenderState.h" -#include "renderstate/Stencil.h" -#include "protos/hwui.pb.h" -#include "OpenGLPipeline.h" #include "pipeline/skia/SkiaOpenGLPipeline.h" #include "pipeline/skia/SkiaPipeline.h" #include "pipeline/skia/SkiaVulkanPipeline.h" +#include "protos/hwui.pb.h" +#include "renderstate/RenderState.h" +#include "renderstate/Stencil.h" #include "utils/GLUtils.h" #include "utils/TimeUtils.h" +#include "../Properties.h" #include <cutils/properties.h> #include <google/protobuf/io/zero_copy_stream_impl.h> #include <private/hwui/DrawGlInfo.h> #include <strings.h> -#include <algorithm> #include <fcntl.h> #include <sys/stat.h> +#include <algorithm> #include <cstdlib> @@ -63,23 +64,22 @@ namespace android { namespace uirenderer { namespace renderthread { -CanvasContext* CanvasContext::create(RenderThread& thread, - bool translucent, RenderNode* rootRenderNode, IContextFactory* contextFactory) { - +CanvasContext* CanvasContext::create(RenderThread& thread, bool translucent, + RenderNode* rootRenderNode, IContextFactory* contextFactory) { auto renderType = Properties::getRenderPipelineType(); switch (renderType) { case RenderPipelineType::OpenGL: return new CanvasContext(thread, translucent, rootRenderNode, contextFactory, - std::make_unique<OpenGLPipeline>(thread)); + std::make_unique<OpenGLPipeline>(thread)); case RenderPipelineType::SkiaGL: return new CanvasContext(thread, translucent, rootRenderNode, contextFactory, - std::make_unique<skiapipeline::SkiaOpenGLPipeline>(thread)); + std::make_unique<skiapipeline::SkiaOpenGLPipeline>(thread)); case RenderPipelineType::SkiaVulkan: return new CanvasContext(thread, translucent, rootRenderNode, contextFactory, - std::make_unique<skiapipeline::SkiaVulkanPipeline>(thread)); + std::make_unique<skiapipeline::SkiaVulkanPipeline>(thread)); default: - LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType); + LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType); break; } return nullptr; @@ -96,7 +96,7 @@ void CanvasContext::destroyLayer(RenderNode* node) { skiapipeline::SkiaPipeline::destroyLayer(node); break; default: - LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType); + LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType); break; } } @@ -115,7 +115,7 @@ void CanvasContext::invokeFunctor(const RenderThread& thread, Functor* functor) skiapipeline::SkiaVulkanPipeline::invokeFunctor(thread, functor); break; default: - LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType); + LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType); break; } } @@ -131,14 +131,14 @@ void CanvasContext::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) { skiapipeline::SkiaPipeline::prepareToDraw(thread, bitmap); break; default: - LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType); + LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType); break; } } -CanvasContext::CanvasContext(RenderThread& thread, bool translucent, - RenderNode* rootRenderNode, IContextFactory* contextFactory, - std::unique_ptr<IRenderPipeline> renderPipeline) +CanvasContext::CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode, + IContextFactory* contextFactory, + std::unique_ptr<IRenderPipeline> renderPipeline) : mRenderThread(thread) , mOpaque(!translucent) , mAnimationContext(contextFactory->createAnimationContext(mRenderThread.timeLord())) @@ -170,7 +170,7 @@ void CanvasContext::addRenderNode(RenderNode* node, bool placeFront) { void CanvasContext::removeRenderNode(RenderNode* node) { node->clearRoot(); mRenderNodes.erase(std::remove(mRenderNodes.begin(), mRenderNodes.end(), node), - mRenderNodes.end()); + mRenderNodes.end()); } void CanvasContext::destroy() { @@ -181,21 +181,21 @@ void CanvasContext::destroy() { mAnimationContext->destroy(); } -void CanvasContext::setSurface(Surface* surface) { +void CanvasContext::setSurface(sp<Surface>&& surface) { ATRACE_CALL(); - mNativeSurface = surface; + mNativeSurface = std::move(surface); ColorMode colorMode = mWideColorGamut ? ColorMode::WideColorGamut : ColorMode::Srgb; - bool hasSurface = mRenderPipeline->setSurface(surface, mSwapBehavior, colorMode); + bool hasSurface = mRenderPipeline->setSurface(mNativeSurface.get(), mSwapBehavior, colorMode); mFrameNumber = -1; if (hasSurface) { - mHaveNewSurface = true; - mSwapHistory.clear(); + mHaveNewSurface = true; + mSwapHistory.clear(); } else { - mRenderThread.removeFrameCallback(this); + mRenderThread.removeFrameCallback(this); } } @@ -203,15 +203,7 @@ void CanvasContext::setSwapBehavior(SwapBehavior swapBehavior) { mSwapBehavior = swapBehavior; } -void CanvasContext::initialize(Surface* surface) { - setSurface(surface); -} - -void CanvasContext::updateSurface(Surface* surface) { - setSurface(surface); -} - -bool CanvasContext::pauseSurface(Surface* surface) { +bool CanvasContext::pauseSurface() { return mRenderThread.removeFrameCallback(this); } @@ -227,8 +219,7 @@ void CanvasContext::setStopped(bool stopped) { } } -void CanvasContext::setup(float lightRadius, - uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) { +void CanvasContext::setup(float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) { mLightGeometry.radius = lightRadius; mLightInfo.ambientShadowAlpha = ambientShadowAlpha; mLightInfo.spotShadowAlpha = spotShadowAlpha; @@ -262,7 +253,7 @@ bool CanvasContext::makeCurrent() { return true; default: LOG_ALWAYS_FATAL("unexpected result %d from IRenderPipeline::makeCurrent", - (int32_t) result); + (int32_t)result); } return true; @@ -285,8 +276,7 @@ bool CanvasContext::isSwapChainStuffed() { // Was there a happy queue & dequeue time? If so, don't // consider it stuffed - if (swapA.dequeueDuration < SLOW_THRESHOLD - && swapA.queueDuration < SLOW_THRESHOLD) { + if (swapA.dequeueDuration < SLOW_THRESHOLD && swapA.queueDuration < SLOW_THRESHOLD) { return false; } @@ -301,8 +291,7 @@ bool CanvasContext::isSwapChainStuffed() { // Was there a happy queue & dequeue time? If so, don't // consider it stuffed - if (swapB.dequeueDuration < SLOW_THRESHOLD - && swapB.queueDuration < SLOW_THRESHOLD) { + if (swapB.dequeueDuration < SLOW_THRESHOLD && swapB.queueDuration < SLOW_THRESHOLD) { return false; } @@ -314,8 +303,8 @@ bool CanvasContext::isSwapChainStuffed() { return true; } -void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, - int64_t syncQueued, RenderNode* target) { +void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued, + RenderNode* target) { mRenderThread.removeFrameCallback(this); // If the previous frame was dropped we don't need to hold onto it, so @@ -331,6 +320,7 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, info.layerUpdateQueue = &mLayerUpdateQueue; mAnimationContext->startFrame(info.mode); + mRenderPipeline->onPrepareTree(); for (const sp<RenderNode>& node : mRenderNodes) { // Only the primary target node will be drawn full - all other nodes would get drawn in // real time mode. In case of a window, the primary node is the window content and the other @@ -365,8 +355,8 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, // Already drew for this vsync pulse, UI draw request missed // the deadline for RT animations info.out.canDrawThisFrame = false; - } else if (vsyncDelta >= mRenderThread.timeLord().frameIntervalNanos() * 3 - || (latestVsync - mLastDropVsync) < 500_ms) { + } else if (vsyncDelta >= mRenderThread.timeLord().frameIntervalNanos() * 3 || + (latestVsync - mLastDropVsync) < 500_ms) { // It's been several frame intervals, assume the buffer queue is fine // or the last drop was too recent info.out.canDrawThisFrame = true; @@ -386,6 +376,9 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, } if (info.out.hasAnimations || !info.out.canDrawThisFrame) { + if (CC_UNLIKELY(!Properties::enableRTAnimations)) { + info.out.requiresUiRedraw = true; + } if (!info.out.requiresUiRedraw) { // If animationsNeedsRedraw is set don't bother posting for an RT anim // as we will just end up fighting the UI thread. @@ -409,10 +402,10 @@ void CanvasContext::draw() { mDamageAccumulator.finish(&dirty); // TODO: Re-enable after figuring out cause of b/22592975 -// if (dirty.isEmpty() && Properties::skipEmptyFrames) { -// mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame); -// return; -// } + // if (dirty.isEmpty() && Properties::skipEmptyFrames) { + // mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame); + // return; + // } mCurrentFrameInfo->markIssueDrawCommandsStart(); @@ -421,18 +414,19 @@ void CanvasContext::draw() { SkRect windowDirty = computeDirtyRect(frame, &dirty); bool drew = mRenderPipeline->draw(frame, windowDirty, dirty, mLightGeometry, &mLayerUpdateQueue, - mContentDrawBounds, mOpaque, mWideColorGamut, mLightInfo, mRenderNodes, &(profiler())); + mContentDrawBounds, mOpaque, mWideColorGamut, mLightInfo, + mRenderNodes, &(profiler())); waitOnFences(); bool requireSwap = false; - bool didSwap = mRenderPipeline->swapBuffers(frame, drew, windowDirty, mCurrentFrameInfo, - &requireSwap); + bool didSwap = + mRenderPipeline->swapBuffers(frame, drew, windowDirty, mCurrentFrameInfo, &requireSwap); mIsDirty = false; if (requireSwap) { - if (!didSwap) { //some error happened + if (!didSwap) { // some error happened setSurface(nullptr); } SwapHistory& swap = mSwapHistory.next(); @@ -456,10 +450,8 @@ void CanvasContext::draw() { swap.dequeueDuration = 0; swap.queueDuration = 0; } - mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration) - = swap.dequeueDuration; - mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration) - = swap.queueDuration; + mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration) = swap.dequeueDuration; + mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration) = swap.queueDuration; mHaveNewSurface = false; mFrameNumber = -1; } else { @@ -471,9 +463,9 @@ void CanvasContext::draw() { mCurrentFrameInfo->markFrameCompleted(); #if LOG_FRAMETIME_MMA - float thisFrame = mCurrentFrameInfo->duration( - FrameInfoIndex::IssueDrawCommandsStart, - FrameInfoIndex::FrameCompleted) / NANOS_PER_MILLIS_F; + float thisFrame = mCurrentFrameInfo->duration(FrameInfoIndex::IssueDrawCommandsStart, + FrameInfoIndex::FrameCompleted) / + NANOS_PER_MILLIS_F; if (sFrameCount) { sBenchMma = ((9 * sBenchMma) + thisFrame) / 10; } else { @@ -498,7 +490,6 @@ void CanvasContext::draw() { caches.fontRenderer.getFontRenderer().historyTracker().frameCompleted(); } #endif - } // Called by choreographer to do an RT-driven animation @@ -512,9 +503,7 @@ void CanvasContext::prepareAndDraw(RenderNode* node) { nsecs_t vsync = mRenderThread.timeLord().computeFrameTimeNanos(); int64_t frameInfo[UI_THREAD_FRAME_INFO_SIZE]; - UiFrameInfoBuilder(frameInfo) - .addFlag(FrameInfoFlags::RTAnimation) - .setVsync(vsync, vsync); + UiFrameInfoBuilder(frameInfo).addFlag(FrameInfoFlags::RTAnimation).setVsync(vsync, vsync); TreeInfo info(TreeInfo::MODE_RT_ONLY, *this); prepareTree(info, frameInfo, systemTime(CLOCK_MONOTONIC), node); @@ -536,7 +525,7 @@ void CanvasContext::freePrefetchedLayers() { if (mPrefetchedLayers.size()) { for (auto& node : mPrefetchedLayers) { ALOGW("Incorrectly called buildLayer on View: %s, destroying layer...", - node->getName()); + node->getName()); node->destroyLayers(); node->decStrong(nullptr); } @@ -562,8 +551,8 @@ void CanvasContext::buildLayer(RenderNode* node) { // purposes when the frame is actually drawn node->setPropertyFieldsDirty(RenderNode::GENERIC); - mRenderPipeline->renderLayers(mLightGeometry, &mLayerUpdateQueue, - mOpaque, mWideColorGamut, mLightInfo); + mRenderPipeline->renderLayers(mLightGeometry, &mLayerUpdateQueue, mOpaque, mWideColorGamut, + mLightInfo); node->incStrong(nullptr); mPrefetchedLayers.insert(node); @@ -614,7 +603,7 @@ void CanvasContext::trimMemory(RenderThread& thread, int level) { break; } default: - LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType); + LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType); break; } } @@ -641,7 +630,7 @@ void CanvasContext::serializeDisplayListTree() { using namespace google::protobuf::io; char package[128]; // Check whether tracing is enabled for this process. - FILE * file = fopen("/proc/self/cmdline", "r"); + FILE* file = fopen("/proc/self/cmdline", "r"); if (file) { if (!fgets(package, 128, file)) { ALOGE("Error reading cmdline: %s (%d)", strerror(errno), errno); @@ -650,8 +639,7 @@ void CanvasContext::serializeDisplayListTree() { } fclose(file); } else { - ALOGE("Error opening /proc/self/cmdline: %s (%d)", strerror(errno), - errno); + ALOGE("Error opening /proc/self/cmdline: %s (%d)", strerror(errno), errno); return; } char path[1024]; @@ -682,8 +670,7 @@ void CanvasContext::waitOnFences() { class CanvasContext::FuncTaskProcessor : public TaskProcessor<bool> { public: - explicit FuncTaskProcessor(TaskManager* taskManager) - : TaskProcessor<bool>(taskManager) {} + explicit FuncTaskProcessor(TaskManager* taskManager) : TaskProcessor<bool>(taskManager) {} virtual void onProcess(const sp<Task<bool> >& task) override { FuncTask* t = static_cast<FuncTask*>(task.get()); @@ -721,8 +708,8 @@ SkRect CanvasContext::computeDirtyRect(const Frame& frame, SkRect* dirty) { dirty->setEmpty(); } else { if (!dirty->isEmpty() && !dirty->intersect(0, 0, frame.width(), frame.height())) { - ALOGW("Dirty " RECT_STRING " doesn't intersect with 0 0 %d %d ?", - SK_RECT_ARGS(*dirty), frame.width(), frame.height()); + ALOGW("Dirty " RECT_STRING " doesn't intersect with 0 0 %d %d ?", SK_RECT_ARGS(*dirty), + frame.width(), frame.height()); dirty->setEmpty(); } profiler().unionDirty(dirty); @@ -742,7 +729,7 @@ SkRect CanvasContext::computeDirtyRect(const Frame& frame, SkRect* dirty) { // last frame so there's nothing to union() against // Therefore we only care about the > 1 case. if (frame.bufferAge() > 1) { - if (frame.bufferAge() > (int) mSwapHistory.size()) { + if (frame.bufferAge() > (int)mSwapHistory.size()) { // We don't have enough history to handle this old of a buffer // Just do a full-draw dirty->set(0, 0, frame.width(), frame.height()); @@ -751,7 +738,7 @@ SkRect CanvasContext::computeDirtyRect(const Frame& frame, SkRect* dirty) { // to the damage history (happens below) // So we need to damage for (int i = mSwapHistory.size() - 1; - i > ((int) mSwapHistory.size()) - frame.bufferAge(); i--) { + i > ((int)mSwapHistory.size()) - frame.bufferAge(); i--) { dirty->join(mSwapHistory[i].damage); } } diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 4a5b2c72b02a..d80a24737a7a 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -27,17 +27,17 @@ #include "IRenderPipeline.h" #include "LayerUpdateQueue.h" #include "RenderNode.h" -#include "thread/Task.h" -#include "thread/TaskProcessor.h" #include "renderthread/RenderTask.h" #include "renderthread/RenderThread.h" +#include "thread/Task.h" +#include "thread/TaskProcessor.h" -#include <cutils/compiler.h> #include <EGL/egl.h> #include <SkBitmap.h> #include <SkRect.h> -#include <utils/Functor.h> +#include <cutils/compiler.h> #include <gui/Surface.h> +#include <utils/Functor.h> #include <functional> #include <set> @@ -63,8 +63,8 @@ class Frame; // TODO: Rename to Renderer or some other per-window, top-level manager class CanvasContext : public IFrameCallback { public: - static CanvasContext* create(RenderThread& thread, bool translucent, - RenderNode* rootRenderNode, IContextFactory* contextFactory); + static CanvasContext* create(RenderThread& thread, bool translucent, RenderNode* rootRenderNode, + IContextFactory* contextFactory); virtual ~CanvasContext(); /** @@ -89,9 +89,7 @@ public: bool pinImages(std::vector<SkImage*>& mutableImages) { return mRenderPipeline->pinImages(mutableImages); } - bool pinImages(LsaVector<sk_sp<Bitmap>>& images) { - return mRenderPipeline->pinImages(images); - } + bool pinImages(LsaVector<sk_sp<Bitmap>>& images) { return mRenderPipeline->pinImages(images); } /** * Unpin any image that had be previously pinned to the GPU cache @@ -117,20 +115,17 @@ public: // Won't take effect until next EGLSurface creation void setSwapBehavior(SwapBehavior swapBehavior); - void initialize(Surface* surface); - void updateSurface(Surface* surface); - bool pauseSurface(Surface* surface); + void setSurface(sp<Surface>&& surface); + bool pauseSurface(); void setStopped(bool stopped); bool hasSurface() { return mNativeSurface.get(); } - void setup(float lightRadius, - uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha); + void setup(float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha); void setLightCenter(const Vector3& lightCenter); void setOpaque(bool opaque); void setWideGamut(bool wideGamut); bool makeCurrent(); - void prepareTree(TreeInfo& info, int64_t* uiFrameInfo, - int64_t syncQueued, RenderNode* target); + void prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued, RenderNode* target); void draw(); void destroy(); @@ -162,13 +157,9 @@ public: void addRenderNode(RenderNode* node, bool placeFront); void removeRenderNode(RenderNode* node); - void setContentDrawBounds(const Rect& bounds) { - mContentDrawBounds = bounds; - } + void setContentDrawBounds(const Rect& bounds) { mContentDrawBounds = bounds; } - RenderState& getRenderState() { - return mRenderThread.renderState(); - } + RenderState& getRenderState() { return mRenderThread.renderState(); } void addFrameMetricsObserver(FrameMetricsObserver* observer) { if (mFrameMetricsReporter.get() == nullptr) { @@ -198,15 +189,13 @@ public: private: CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode, - IContextFactory* contextFactory, std::unique_ptr<IRenderPipeline> renderPipeline); + IContextFactory* contextFactory, std::unique_ptr<IRenderPipeline> renderPipeline); friend class RegisterFrameCallbackTask; // TODO: Replace with something better for layer & other GL object // lifecycle tracking friend class android::uirenderer::RenderState; - void setSurface(Surface* window); - void freePrefetchedLayers(); bool isSwapChainStuffed(); @@ -242,14 +231,14 @@ private: bool mOpaque; bool mWideColorGamut = false; BakedOpRenderer::LightInfo mLightInfo; - FrameBuilder::LightGeometry mLightGeometry = { {0, 0, 0}, 0 }; + FrameBuilder::LightGeometry mLightGeometry = {{0, 0, 0}, 0}; bool mHaveNewSurface = false; DamageAccumulator mDamageAccumulator; LayerUpdateQueue mLayerUpdateQueue; std::unique_ptr<AnimationContext> mAnimationContext; - std::vector< sp<RenderNode> > mRenderNodes; + std::vector<sp<RenderNode>> mRenderNodes; FrameInfo* mCurrentFrameInfo = nullptr; std::string mName; @@ -269,8 +258,8 @@ private: }; class FuncTaskProcessor; - std::vector< sp<FuncTask> > mFrameFences; - sp<TaskProcessor<bool> > mFrameWorkProcessor; + std::vector<sp<FuncTask>> mFrameFences; + sp<TaskProcessor<bool>> mFrameWorkProcessor; std::unique_ptr<IRenderPipeline> mRenderPipeline; }; diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp index a097272df359..8372331c0352 100644 --- a/libs/hwui/renderthread/DrawFrameTask.cpp +++ b/libs/hwui/renderthread/DrawFrameTask.cpp @@ -33,21 +33,20 @@ DrawFrameTask::DrawFrameTask() : mRenderThread(nullptr) , mContext(nullptr) , mContentDrawBounds(0, 0, 0, 0) - , mSyncResult(SyncResult::OK) { -} + , mSyncResult(SyncResult::OK) {} -DrawFrameTask::~DrawFrameTask() { -} +DrawFrameTask::~DrawFrameTask() {} void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context, - RenderNode* targetNode) { + RenderNode* targetNode) { mRenderThread = thread; mContext = context; mTargetNode = targetNode; } void DrawFrameTask::pushLayerUpdate(DeferredLayerUpdater* layer) { - LOG_ALWAYS_FATAL_IF(!mContext, "Lifecycle violation, there's no context to pushLayerUpdate with!"); + LOG_ALWAYS_FATAL_IF(!mContext, + "Lifecycle violation, there's no context to pushLayerUpdate with!"); for (size_t i = 0; i < mLayers.size(); i++) { if (mLayers[i].get() == layer) { @@ -78,7 +77,7 @@ int DrawFrameTask::drawFrame() { void DrawFrameTask::postAndWait() { AutoMutex _lock(mLock); - mRenderThread->queue(this); + mRenderThread->queue().post([this]() { run(); }); mSignal.wait(mLock); } diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h index 83ecb98f548f..ea51ae4a42b7 100644 --- a/libs/hwui/renderthread/DrawFrameTask.h +++ b/libs/hwui/renderthread/DrawFrameTask.h @@ -24,8 +24,8 @@ #include "RenderTask.h" -#include "../Rect.h" #include "../FrameInfo.h" +#include "../Rect.h" #include "../TreeInfo.h" namespace android { @@ -55,7 +55,7 @@ enum { * tracked across many frames not just a single frame. * It is the sync-state task, and will kick off the post-sync draw */ -class DrawFrameTask : public RenderTask { +class DrawFrameTask { public: DrawFrameTask(); virtual ~DrawFrameTask(); @@ -72,7 +72,7 @@ public: int64_t* frameInfo() { return mFrameInfo; } - virtual void run() override; + void run(); private: void postAndWait(); @@ -90,7 +90,7 @@ private: /********************************************* * Single frame data *********************************************/ - std::vector< sp<DeferredLayerUpdater> > mLayers; + std::vector<sp<DeferredLayerUpdater> > mLayers; int mSyncResult; int64_t mSyncQueued; diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp index bd4708da562a..5b87e1013baf 100644 --- a/libs/hwui/renderthread/EglManager.cpp +++ b/libs/hwui/renderthread/EglManager.cpp @@ -18,17 +18,17 @@ #include <string> -#include "utils/StringUtils.h" #include <cutils/properties.h> #include <log/log.h> +#include "utils/StringUtils.h" #include "Caches.h" #include "DeviceInfo.h" #include "Frame.h" #include "Properties.h" #include "RenderThread.h" -#include "renderstate/RenderState.h" #include "Texture.h" +#include "renderstate/RenderState.h" #include <EGL/eglext.h> #include <GrContextOptions.h> @@ -47,7 +47,9 @@ namespace android { namespace uirenderer { namespace renderthread { -#define ERROR_CASE(x) case x: return #x; +#define ERROR_CASE(x) \ + case x: \ + return #x; static const char* egl_error_str(EGLint error) { switch (error) { ERROR_CASE(EGL_SUCCESS) @@ -65,8 +67,8 @@ static const char* egl_error_str(EGLint error) { ERROR_CASE(EGL_BAD_PARAMETER) ERROR_CASE(EGL_BAD_SURFACE) ERROR_CASE(EGL_CONTEXT_LOST) - default: - return "Unknown error"; + default: + return "Unknown error"; } } const char* EglManager::eglErrorString() { @@ -89,8 +91,7 @@ EglManager::EglManager(RenderThread& thread) , mEglConfigWideGamut(nullptr) , mEglContext(EGL_NO_CONTEXT) , mPBufferSurface(EGL_NO_SURFACE) - , mCurrentSurface(EGL_NO_SURFACE) { -} + , mCurrentSurface(EGL_NO_SURFACE) {} void EglManager::initialize() { if (hasEglContext()) return; @@ -98,12 +99,12 @@ void EglManager::initialize() { ATRACE_NAME("Creating EGLContext"); mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); - LOG_ALWAYS_FATAL_IF(mEglDisplay == EGL_NO_DISPLAY, - "Failed to get EGL_DEFAULT_DISPLAY! err=%s", eglErrorString()); + LOG_ALWAYS_FATAL_IF(mEglDisplay == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s", + eglErrorString()); EGLint major, minor; LOG_ALWAYS_FATAL_IF(eglInitialize(mEglDisplay, &major, &minor) == EGL_FALSE, - "Failed to initialize display %p! err=%s", mEglDisplay, eglErrorString()); + "Failed to initialize display %p! err=%s", mEglDisplay, eglErrorString()); ALOGI("Initialized EGL, version %d.%d", (int)major, (int)minor); @@ -138,26 +139,26 @@ void EglManager::initialize() { LOG_ALWAYS_FATAL_IF(!glInterface.get()); GrContextOptions options; - options.fGpuPathRenderers &= ~GrContextOptions::GpuPathRenderers::kDistanceField; + options.fDisableDistanceFieldPaths = true; mRenderThread.cacheManager().configureContext(&options); - mRenderThread.setGrContext(GrContext::Create(GrBackend::kOpenGL_GrBackend, - (GrBackendContext)glInterface.get(), options)); + sk_sp<GrContext> grContext(GrContext::MakeGL(std::move(glInterface), options)); + LOG_ALWAYS_FATAL_IF(!grContext.get()); + mRenderThread.setGrContext(grContext); } } void EglManager::initExtensions() { - auto extensions = StringUtils::split( - eglQueryString(mEglDisplay, EGL_EXTENSIONS)); + auto extensions = StringUtils::split(eglQueryString(mEglDisplay, EGL_EXTENSIONS)); // For our purposes we don't care if EGL_BUFFER_AGE is a result of // EGL_EXT_buffer_age or EGL_KHR_partial_update as our usage is covered // under EGL_KHR_partial_update and we don't need the expanded scope // that EGL_EXT_buffer_age provides. - EglExtensions.bufferAge = extensions.has("EGL_EXT_buffer_age") - || extensions.has("EGL_KHR_partial_update"); + EglExtensions.bufferAge = + extensions.has("EGL_EXT_buffer_age") || extensions.has("EGL_KHR_partial_update"); EglExtensions.setDamage = extensions.has("EGL_KHR_partial_update"); LOG_ALWAYS_FATAL_IF(!extensions.has("EGL_KHR_swap_buffers_with_damage"), - "Missing required extension EGL_KHR_swap_buffers_with_damage"); + "Missing required extension EGL_KHR_swap_buffers_with_damage"); EglExtensions.glColorSpace = extensions.has("EGL_KHR_gl_colorspace"); EglExtensions.noConfigContext = extensions.has("EGL_KHR_no_config_context"); @@ -175,30 +176,37 @@ bool EglManager::hasEglContext() { void EglManager::loadConfigs() { ALOGD("Swap behavior %d", static_cast<int>(mSwapBehavior)); - EGLint swapBehavior = (mSwapBehavior == SwapBehavior::Preserved) - ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0; - EGLint attribs[] = { - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, - EGL_RED_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_BLUE_SIZE, 8, - EGL_ALPHA_SIZE, 8, - EGL_DEPTH_SIZE, 0, - EGL_CONFIG_CAVEAT, EGL_NONE, - EGL_STENCIL_SIZE, Stencil::getStencilSize(), - EGL_SURFACE_TYPE, EGL_WINDOW_BIT | swapBehavior, - EGL_NONE - }; + EGLint swapBehavior = + (mSwapBehavior == SwapBehavior::Preserved) ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0; + EGLint attribs[] = {EGL_RENDERABLE_TYPE, + EGL_OPENGL_ES2_BIT, + EGL_RED_SIZE, + 8, + EGL_GREEN_SIZE, + 8, + EGL_BLUE_SIZE, + 8, + EGL_ALPHA_SIZE, + 8, + EGL_DEPTH_SIZE, + 0, + EGL_CONFIG_CAVEAT, + EGL_NONE, + EGL_STENCIL_SIZE, + Stencil::getStencilSize(), + EGL_SURFACE_TYPE, + EGL_WINDOW_BIT | swapBehavior, + EGL_NONE}; EGLint numConfigs = 1; - if (!eglChooseConfig(mEglDisplay, attribs, &mEglConfig, numConfigs, &numConfigs) - || numConfigs != 1) { + if (!eglChooseConfig(mEglDisplay, attribs, &mEglConfig, numConfigs, &numConfigs) || + numConfigs != 1) { if (mSwapBehavior == SwapBehavior::Preserved) { // Try again without dirty regions enabled ALOGW("Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without..."); mSwapBehavior = SwapBehavior::Discard; loadConfigs(); - return; // the call to loadConfigs() we just made picks the wide gamut config + return; // the call to loadConfigs() we just made picks the wide gamut config } else { // Failed to get a valid config LOG_ALWAYS_FATAL("Failed to choose config, error = %s", eglErrorString()); @@ -207,22 +215,30 @@ void EglManager::loadConfigs() { if (EglExtensions.pixelFormatFloat) { // If we reached this point, we have a valid swap behavior - EGLint attribs16F[] = { - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, - EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT, - EGL_RED_SIZE, 16, - EGL_GREEN_SIZE, 16, - EGL_BLUE_SIZE, 16, - EGL_ALPHA_SIZE, 16, - EGL_DEPTH_SIZE, 0, - EGL_STENCIL_SIZE, Stencil::getStencilSize(), - EGL_SURFACE_TYPE, EGL_WINDOW_BIT | swapBehavior, - EGL_NONE - }; + EGLint attribs16F[] = {EGL_RENDERABLE_TYPE, + EGL_OPENGL_ES2_BIT, + EGL_COLOR_COMPONENT_TYPE_EXT, + EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT, + EGL_RED_SIZE, + 16, + EGL_GREEN_SIZE, + 16, + EGL_BLUE_SIZE, + 16, + EGL_ALPHA_SIZE, + 16, + EGL_DEPTH_SIZE, + 0, + EGL_STENCIL_SIZE, + Stencil::getStencilSize(), + EGL_SURFACE_TYPE, + EGL_WINDOW_BIT | swapBehavior, + EGL_NONE}; numConfigs = 1; - if (!eglChooseConfig(mEglDisplay, attribs16F, &mEglConfigWideGamut, numConfigs, &numConfigs) - || numConfigs != 1) { + if (!eglChooseConfig(mEglDisplay, attribs16F, &mEglConfigWideGamut, numConfigs, + &numConfigs) || + numConfigs != 1) { ALOGE("Device claims wide gamut support, cannot find matching config, error = %s", eglErrorString()); EglExtensions.pixelFormatFloat = false; @@ -231,23 +247,20 @@ void EglManager::loadConfigs() { } void EglManager::createContext() { - EGLint attribs[] = { - EGL_CONTEXT_CLIENT_VERSION, GLES_VERSION, - EGL_NONE - }; - mEglContext = eglCreateContext(mEglDisplay, - EglExtensions.noConfigContext ? ((EGLConfig) nullptr) : mEglConfig, + EGLint attribs[] = {EGL_CONTEXT_CLIENT_VERSION, GLES_VERSION, EGL_NONE}; + mEglContext = eglCreateContext( + mEglDisplay, EglExtensions.noConfigContext ? ((EGLConfig) nullptr) : mEglConfig, EGL_NO_CONTEXT, attribs); - LOG_ALWAYS_FATAL_IF(mEglContext == EGL_NO_CONTEXT, - "Failed to create context, error = %s", eglErrorString()); + LOG_ALWAYS_FATAL_IF(mEglContext == EGL_NO_CONTEXT, "Failed to create context, error = %s", + eglErrorString()); } void EglManager::createPBufferSurface() { LOG_ALWAYS_FATAL_IF(mEglDisplay == EGL_NO_DISPLAY, - "usePBufferSurface() called on uninitialized GlobalContext!"); + "usePBufferSurface() called on uninitialized GlobalContext!"); if (mPBufferSurface == EGL_NO_SURFACE) { - EGLint attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE }; + EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE}; mPBufferSurface = eglCreatePbufferSurface(mEglDisplay, mEglConfig, attribs); } } @@ -255,8 +268,8 @@ void EglManager::createPBufferSurface() { EGLSurface EglManager::createSurface(EGLNativeWindowType window, bool wideColorGamut) { initialize(); - wideColorGamut = wideColorGamut && EglExtensions.glColorSpace && EglExtensions.scRGB - && EglExtensions.pixelFormatFloat && EglExtensions.noConfigContext; + wideColorGamut = wideColorGamut && EglExtensions.glColorSpace && EglExtensions.scRGB && + EglExtensions.pixelFormatFloat && EglExtensions.noConfigContext; // The color space we want to use depends on whether linear blending is turned // on and whether the app has requested wide color gamut rendering. When wide @@ -280,10 +293,7 @@ EGLSurface EglManager::createSurface(EGLNativeWindowType window, bool wideColorG // We insert to placeholders to set EGL_GL_COLORSPACE_KHR and its value. // According to section 3.4.1 of the EGL specification, the attributes // list is considered empty if the first entry is EGL_NONE - EGLint attribs[] = { - EGL_NONE, EGL_NONE, - EGL_NONE - }; + EGLint attribs[] = {EGL_NONE, EGL_NONE, EGL_NONE}; if (EglExtensions.glColorSpace) { attribs[0] = EGL_GL_COLORSPACE_KHR; @@ -302,16 +312,17 @@ EGLSurface EglManager::createSurface(EGLNativeWindowType window, bool wideColorG #endif } - EGLSurface surface = eglCreateWindowSurface(mEglDisplay, - wideColorGamut ? mEglConfigWideGamut : mEglConfig, window, attribs); + EGLSurface surface = eglCreateWindowSurface( + mEglDisplay, wideColorGamut ? mEglConfigWideGamut : mEglConfig, window, attribs); LOG_ALWAYS_FATAL_IF(surface == EGL_NO_SURFACE, - "Failed to create EGLSurface for window %p, eglErr = %s", - (void*) window, eglErrorString()); + "Failed to create EGLSurface for window %p, eglErr = %s", (void*)window, + eglErrorString()); if (mSwapBehavior != SwapBehavior::Preserved) { - LOG_ALWAYS_FATAL_IF(eglSurfaceAttrib(mEglDisplay, surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED) == EGL_FALSE, + LOG_ALWAYS_FATAL_IF(eglSurfaceAttrib(mEglDisplay, surface, EGL_SWAP_BEHAVIOR, + EGL_BUFFER_DESTROYED) == EGL_FALSE, "Failed to set swap behavior to destroyed for window %p, eglErr = %s", - (void*) window, eglErrorString()); + (void*)window, eglErrorString()); } return surface; @@ -353,11 +364,11 @@ bool EglManager::makeCurrent(EGLSurface surface, EGLint* errOut) { if (!eglMakeCurrent(mEglDisplay, surface, surface, mEglContext)) { if (errOut) { *errOut = eglGetError(); - ALOGW("Failed to make current on surface %p, error=%s", - (void*)surface, egl_error_str(*errOut)); + ALOGW("Failed to make current on surface %p, error=%s", (void*)surface, + egl_error_str(*errOut)); } else { - LOG_ALWAYS_FATAL("Failed to make current on surface %p, error=%s", - (void*)surface, eglErrorString()); + LOG_ALWAYS_FATAL("Failed to make current on surface %p, error=%s", (void*)surface, + eglErrorString()); } } mCurrentSurface = surface; @@ -369,21 +380,20 @@ bool EglManager::makeCurrent(EGLSurface surface, EGLint* errOut) { EGLint EglManager::queryBufferAge(EGLSurface surface) { switch (mSwapBehavior) { - case SwapBehavior::Discard: - return 0; - case SwapBehavior::Preserved: - return 1; - case SwapBehavior::BufferAge: - EGLint bufferAge; - eglQuerySurface(mEglDisplay, surface, EGL_BUFFER_AGE_EXT, &bufferAge); - return bufferAge; + case SwapBehavior::Discard: + return 0; + case SwapBehavior::Preserved: + return 1; + case SwapBehavior::BufferAge: + EGLint bufferAge; + eglQuerySurface(mEglDisplay, surface, EGL_BUFFER_AGE_EXT, &bufferAge); + return bufferAge; } return 0; } Frame EglManager::beginFrame(EGLSurface surface) { - LOG_ALWAYS_FATAL_IF(surface == EGL_NO_SURFACE, - "Tried to beginFrame on EGL_NO_SURFACE!"); + LOG_ALWAYS_FATAL_IF(surface == EGL_NO_SURFACE, "Tried to beginFrame on EGL_NO_SURFACE!"); makeCurrent(surface); Frame frame; frame.mSurface = surface; @@ -401,7 +411,7 @@ void EglManager::damageFrame(const Frame& frame, const SkRect& dirty) { frame.map(dirty, rects); if (!eglSetDamageRegionKHR(mEglDisplay, frame.mSurface, rects, 1)) { LOG_ALWAYS_FATAL("Failed to set damage region on surface %p, error=%s", - (void*)frame.mSurface, eglErrorString()); + (void*)frame.mSurface, eglErrorString()); } } #endif @@ -412,7 +422,6 @@ bool EglManager::damageRequiresSwap() { } bool EglManager::swapBuffers(const Frame& frame, const SkRect& screenDirty) { - if (CC_UNLIKELY(Properties::waitForGpuCompletion)) { ATRACE_NAME("Finishing GPU work"); fence(); @@ -420,8 +429,7 @@ bool EglManager::swapBuffers(const Frame& frame, const SkRect& screenDirty) { EGLint rects[4]; frame.map(screenDirty, rects); - eglSwapBuffersWithDamageKHR(mEglDisplay, frame.mSurface, rects, - screenDirty.isEmpty() ? 0 : 1); + eglSwapBuffersWithDamageKHR(mEglDisplay, frame.mSurface, rects, screenDirty.isEmpty() ? 0 : 1); EGLint err = eglGetError(); if (CC_LIKELY(err == EGL_SUCCESS)) { @@ -431,20 +439,18 @@ bool EglManager::swapBuffers(const Frame& frame, const SkRect& screenDirty) { // For some reason our surface was destroyed out from under us // This really shouldn't happen, but if it does we can recover easily // by just not trying to use the surface anymore - ALOGW("swapBuffers encountered EGL error %d on %p, halting rendering...", - err, frame.mSurface); + ALOGW("swapBuffers encountered EGL error %d on %p, halting rendering...", err, + frame.mSurface); return false; } - LOG_ALWAYS_FATAL("Encountered EGL error %d %s during rendering", - err, egl_error_str(err)); + LOG_ALWAYS_FATAL("Encountered EGL error %d %s during rendering", err, egl_error_str(err)); // Impossible to hit this, but the compiler doesn't know that return false; } void EglManager::fence() { EGLSyncKHR fence = eglCreateSyncKHR(mEglDisplay, EGL_SYNC_FENCE_KHR, NULL); - eglClientWaitSyncKHR(mEglDisplay, fence, - EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, EGL_FOREVER_KHR); + eglClientWaitSyncKHR(mEglDisplay, fence, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, EGL_FOREVER_KHR); eglDestroySyncKHR(mEglDisplay, fence); } @@ -452,17 +458,17 @@ bool EglManager::setPreserveBuffer(EGLSurface surface, bool preserve) { if (mSwapBehavior != SwapBehavior::Preserved) return false; bool preserved = eglSurfaceAttrib(mEglDisplay, surface, EGL_SWAP_BEHAVIOR, - preserve ? EGL_BUFFER_PRESERVED : EGL_BUFFER_DESTROYED); + preserve ? EGL_BUFFER_PRESERVED : EGL_BUFFER_DESTROYED); if (!preserved) { - ALOGW("Failed to set EGL_SWAP_BEHAVIOR on surface %p, error=%s", - (void*) surface, eglErrorString()); + ALOGW("Failed to set EGL_SWAP_BEHAVIOR on surface %p, error=%s", (void*)surface, + eglErrorString()); // Maybe it's already set? EGLint swapBehavior; if (eglQuerySurface(mEglDisplay, surface, EGL_SWAP_BEHAVIOR, &swapBehavior)) { preserved = (swapBehavior == EGL_BUFFER_PRESERVED); } else { - ALOGW("Failed to query EGL_SWAP_BEHAVIOR on surface %p, error=%p", - (void*) surface, eglErrorString()); + ALOGW("Failed to query EGL_SWAP_BEHAVIOR on surface %p, error=%p", (void*)surface, + eglErrorString()); } } diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h index 2982c23552c9..ef9effbf9953 100644 --- a/libs/hwui/renderthread/EglManager.h +++ b/libs/hwui/renderthread/EglManager.h @@ -16,9 +16,9 @@ #ifndef EGLMANAGER_H #define EGLMANAGER_H -#include <cutils/compiler.h> #include <EGL/egl.h> #include <SkRect.h> +#include <cutils/compiler.h> #include <ui/GraphicBuffer.h> #include <utils/StrongPointer.h> diff --git a/libs/hwui/renderthread/Frame.h b/libs/hwui/renderthread/Frame.h index 99996fe40626..d266faa4f7c9 100644 --- a/libs/hwui/renderthread/Frame.h +++ b/libs/hwui/renderthread/Frame.h @@ -19,7 +19,7 @@ #include <stdint.h> struct SkRect; -typedef void *EGLSurface; +typedef void* EGLSurface; namespace android { namespace uirenderer { @@ -28,9 +28,7 @@ namespace renderthread { class Frame { public: Frame(int32_t width, int32_t height, int32_t bufferAge) - : mWidth(width) - , mHeight(height) - , mBufferAge(bufferAge) { } + : mWidth(width), mHeight(height), mBufferAge(bufferAge) {} int32_t width() const { return mWidth; } int32_t height() const { return mHeight; } @@ -57,4 +55,3 @@ private: } /* namespace renderthread */ } /* namespace uirenderer */ } /* namespace android */ - diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h index f9b6e384d211..246ab269b838 100644 --- a/libs/hwui/renderthread/IRenderPipeline.h +++ b/libs/hwui/renderthread/IRenderPipeline.h @@ -17,6 +17,7 @@ #pragma once #include "FrameInfoVisualizer.h" +#include "SwapBehavior.h" #include <SkRect.h> #include <utils/RefBase.h> @@ -33,16 +34,7 @@ class DeferredLayerUpdater; namespace renderthread { -enum class SwapBehavior { - kSwap_default, - kSwap_discardBuffer, -}; - -enum class MakeCurrentResult { - AlreadyCurrent, - Failed, - Succeeded -}; +enum class MakeCurrentResult { AlreadyCurrent, Failed, Succeeded }; enum class ColorMode { Srgb, @@ -57,14 +49,13 @@ public: virtual MakeCurrentResult makeCurrent() = 0; virtual Frame getFrame() = 0; virtual bool draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty, - const FrameBuilder::LightGeometry& lightGeometry, - LayerUpdateQueue* layerUpdateQueue, - const Rect& contentDrawBounds, bool opaque, bool wideColorGamut, - const BakedOpRenderer::LightInfo& lightInfo, - const std::vector< sp<RenderNode> >& renderNodes, - FrameInfoVisualizer* profiler) = 0; + const FrameBuilder::LightGeometry& lightGeometry, + LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds, + bool opaque, bool wideColorGamut, const BakedOpRenderer::LightInfo& lightInfo, + const std::vector<sp<RenderNode>>& renderNodes, + FrameInfoVisualizer* profiler) = 0; virtual bool swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty, - FrameInfo* currentFrameInfo, bool* requireSwap) = 0; + FrameInfo* currentFrameInfo, bool* requireSwap) = 0; virtual bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) = 0; virtual DeferredLayerUpdater* createTextureLayer() = 0; virtual bool setSurface(Surface* window, SwapBehavior swapBehavior, ColorMode colorMode) = 0; @@ -73,14 +64,15 @@ public: virtual bool isContextReady() = 0; virtual void onDestroyHardwareResources() = 0; virtual void renderLayers(const FrameBuilder::LightGeometry& lightGeometry, - LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut, - const BakedOpRenderer::LightInfo& lightInfo) = 0; + LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut, + const BakedOpRenderer::LightInfo& lightInfo) = 0; virtual TaskManager* getTaskManager() = 0; - virtual bool createOrUpdateLayer(RenderNode* node, - const DamageAccumulator& damageAccumulator, bool wideColorGamut) = 0; + virtual bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator, + bool wideColorGamut) = 0; virtual bool pinImages(std::vector<SkImage*>& mutableImages) = 0; virtual bool pinImages(LsaVector<sk_sp<Bitmap>>& images) = 0; virtual void unpinImages() = 0; + virtual void onPrepareTree() = 0; virtual ~IRenderPipeline() {} }; diff --git a/libs/hwui/renderthread/OpenGLPipeline.cpp b/libs/hwui/renderthread/OpenGLPipeline.cpp index 7283eb123d6a..f3103fd0cbb4 100644 --- a/libs/hwui/renderthread/OpenGLPipeline.cpp +++ b/libs/hwui/renderthread/OpenGLPipeline.cpp @@ -20,9 +20,9 @@ #include "EglManager.h" #include "Frame.h" #include "GlLayer.h" +#include "OpenGLReadback.h" #include "ProfileRenderer.h" #include "renderstate/RenderState.h" -#include "OpenGLReadback.h" #include <cutils/properties.h> #include <strings.h> @@ -32,9 +32,7 @@ namespace uirenderer { namespace renderthread { OpenGLPipeline::OpenGLPipeline(RenderThread& thread) - : mEglManager(thread.eglManager()) - , mRenderThread(thread) { -} + : mEglManager(thread.eglManager()), mRenderThread(thread) {} MakeCurrentResult OpenGLPipeline::makeCurrent() { // TODO: Figure out why this workaround is needed, see b/13913604 @@ -51,23 +49,21 @@ MakeCurrentResult OpenGLPipeline::makeCurrent() { Frame OpenGLPipeline::getFrame() { LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE, - "drawRenderNode called on a context with no surface!"); + "drawRenderNode called on a context with no surface!"); return mEglManager.beginFrame(mEglSurface); } bool OpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty, - const FrameBuilder::LightGeometry& lightGeometry, - LayerUpdateQueue* layerUpdateQueue, - const Rect& contentDrawBounds, bool opaque, bool wideColorGamut, - const BakedOpRenderer::LightInfo& lightInfo, - const std::vector< sp<RenderNode> >& renderNodes, - FrameInfoVisualizer* profiler) { - + const FrameBuilder::LightGeometry& lightGeometry, + LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds, + bool opaque, bool wideColorGamut, + const BakedOpRenderer::LightInfo& lightInfo, + const std::vector<sp<RenderNode>>& renderNodes, + FrameInfoVisualizer* profiler) { mEglManager.damageFrame(frame, dirty); bool drew = false; - auto& caches = Caches::getInstance(); FrameBuilder frameBuilder(dirty, frame.width(), frame.height(), lightGeometry, caches); @@ -76,8 +72,8 @@ bool OpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, const S frameBuilder.deferRenderNodeScene(renderNodes, contentDrawBounds); - BakedOpRenderer renderer(caches, mRenderThread.renderState(), - opaque, wideColorGamut, lightInfo); + BakedOpRenderer renderer(caches, mRenderThread.renderState(), opaque, wideColorGamut, + lightInfo); frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer); ProfileRenderer profileRenderer(renderer); profiler->draw(profileRenderer); @@ -100,8 +96,7 @@ bool OpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, const S } bool OpenGLPipeline::swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty, - FrameInfo* currentFrameInfo, bool* requireSwap) { - + FrameInfo* currentFrameInfo, bool* requireSwap) { GL_CHECKPOINT(LOW); // Even if we decided to cancel the frame, from the perspective of jank @@ -123,13 +118,13 @@ bool OpenGLPipeline::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap layer->updateTexImage(); layer->apply(); return OpenGLReadbackImpl::copyLayerInto(mRenderThread, - static_cast<GlLayer&>(*layer->backingLayer()), bitmap); + static_cast<GlLayer&>(*layer->backingLayer()), bitmap); } static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight, - SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) { - GlLayer* layer = new GlLayer(renderState, layerWidth, layerHeight, colorFilter, alpha, - mode, blend); + SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) { + GlLayer* layer = + new GlLayer(renderState, layerWidth, layerHeight, colorFilter, alpha, mode, blend); Caches::getInstance().textureState().activateTexture(0); layer->generateTexture(); return layer; @@ -147,7 +142,6 @@ void OpenGLPipeline::onStop() { } bool OpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior, ColorMode colorMode) { - if (mEglSurface != EGL_NO_SURFACE) { mEglManager.destroySurface(mEglSurface); mEglSurface = EGL_NO_SURFACE; @@ -184,14 +178,16 @@ void OpenGLPipeline::onDestroyHardwareResources() { } void OpenGLPipeline::renderLayers(const FrameBuilder::LightGeometry& lightGeometry, - LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut, - const BakedOpRenderer::LightInfo& lightInfo) { - static const std::vector< sp<RenderNode> > emptyNodeList; + LayerUpdateQueue* layerUpdateQueue, bool opaque, + bool wideColorGamut, + const BakedOpRenderer::LightInfo& lightInfo) { + static const std::vector<sp<RenderNode>> emptyNodeList; auto& caches = Caches::getInstance(); FrameBuilder frameBuilder(*layerUpdateQueue, lightGeometry, caches); layerUpdateQueue->clear(); // TODO: Handle wide color gamut contexts - BakedOpRenderer renderer(caches, mRenderThread.renderState(), opaque, wideColorGamut, lightInfo); + BakedOpRenderer renderer(caches, mRenderThread.renderState(), opaque, wideColorGamut, + lightInfo); LOG_ALWAYS_FATAL_IF(renderer.didDraw(), "shouldn't draw in buildlayer case"); frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer); } @@ -205,13 +201,14 @@ static bool layerMatchesWH(OffscreenBuffer* layer, int width, int height) { } bool OpenGLPipeline::createOrUpdateLayer(RenderNode* node, - const DamageAccumulator& damageAccumulator, bool wideColorGamut) { + const DamageAccumulator& damageAccumulator, + bool wideColorGamut) { RenderState& renderState = mRenderThread.renderState(); OffscreenBufferPool& layerPool = renderState.layerPool(); bool transformUpdateNeeded = false; if (node->getLayer() == nullptr) { - node->setLayer(layerPool.get(renderState, - node->getWidth(), node->getHeight(), wideColorGamut)); + node->setLayer( + layerPool.get(renderState, node->getWidth(), node->getHeight(), wideColorGamut)); transformUpdateNeeded = true; } else if (!layerMatchesWH(node->getLayer(), node->getWidth(), node->getHeight())) { // TODO: remove now irrelevant, currently enqueued damage (respecting damage ordering) @@ -273,8 +270,7 @@ void OpenGLPipeline::invokeFunctor(const RenderThread& thread, Functor* functor) class AutoEglFence { public: - AutoEglFence(EGLDisplay display) - : mDisplay(display) { + AutoEglFence(EGLDisplay display) : mDisplay(display) { fence = eglCreateSyncKHR(mDisplay, EGL_SYNC_FENCE_KHR, NULL); } @@ -285,17 +281,17 @@ public: } EGLSyncKHR fence = EGL_NO_SYNC_KHR; + private: EGLDisplay mDisplay = EGL_NO_DISPLAY; }; class AutoEglImage { public: - AutoEglImage(EGLDisplay display, EGLClientBuffer clientBuffer) - : mDisplay(display) { - EGLint imageAttrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE }; - image = eglCreateImageKHR(display, EGL_NO_CONTEXT, - EGL_NATIVE_BUFFER_ANDROID, clientBuffer, imageAttrs); + AutoEglImage(EGLDisplay display, EGLClientBuffer clientBuffer) : mDisplay(display) { + EGLint imageAttrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE}; + image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuffer, + imageAttrs); } ~AutoEglImage() { @@ -305,21 +301,19 @@ public: } EGLImageKHR image = EGL_NO_IMAGE_KHR; + private: EGLDisplay mDisplay = EGL_NO_DISPLAY; }; class AutoGlTexture { public: - AutoGlTexture(uirenderer::Caches& caches) - : mCaches(caches) { + AutoGlTexture(uirenderer::Caches& caches) : mCaches(caches) { glGenTextures(1, &mTexture); caches.textureState().bindTexture(mTexture); } - ~AutoGlTexture() { - mCaches.textureState().deleteTexture(mTexture); - } + ~AutoGlTexture() { mCaches.textureState().deleteTexture(mTexture); } private: uirenderer::Caches& mCaches; @@ -327,18 +321,17 @@ private: }; static bool uploadBitmapToGraphicBuffer(uirenderer::Caches& caches, SkBitmap& bitmap, - GraphicBuffer& buffer, GLint format, GLint type) { + GraphicBuffer& buffer, GLint format, GLint type) { EGLDisplay display = eglGetCurrentDisplay(); - LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, - "Failed to get EGL_DEFAULT_DISPLAY! err=%s", - uirenderer::renderthread::EglManager::eglErrorString()); + LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s", + uirenderer::renderthread::EglManager::eglErrorString()); // We use an EGLImage to access the content of the GraphicBuffer // The EGL image is later bound to a 2D texture - EGLClientBuffer clientBuffer = (EGLClientBuffer) buffer.getNativeBuffer(); + EGLClientBuffer clientBuffer = (EGLClientBuffer)buffer.getNativeBuffer(); AutoEglImage autoImage(display, clientBuffer); if (autoImage.image == EGL_NO_IMAGE_KHR) { ALOGW("Could not create EGL image, err =%s", - uirenderer::renderthread::EglManager::eglErrorString()); + uirenderer::renderthread::EglManager::eglErrorString()); return false; } AutoGlTexture glTexture(caches); @@ -346,8 +339,8 @@ static bool uploadBitmapToGraphicBuffer(uirenderer::Caches& caches, SkBitmap& bi GL_CHECKPOINT(MODERATE); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(), - format, type, bitmap.getPixels()); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(), format, type, + bitmap.getPixels()); GL_CHECKPOINT(MODERATE); @@ -362,7 +355,7 @@ static bool uploadBitmapToGraphicBuffer(uirenderer::Caches& caches, SkBitmap& bi // The flag EGL_SYNC_FLUSH_COMMANDS_BIT_KHR will trigger a // pipeline flush (similar to what a glFlush() would do.) EGLint waitStatus = eglClientWaitSyncKHR(display, autoFence.fence, - EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, FENCE_TIMEOUT); + EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, FENCE_TIMEOUT); if (waitStatus != EGL_CONDITION_SATISFIED_KHR) { LOG_ALWAYS_FATAL("Failed to wait for the fence %#x", eglGetError()); return false; @@ -373,24 +366,24 @@ static bool uploadBitmapToGraphicBuffer(uirenderer::Caches& caches, SkBitmap& bi // TODO: handle SRGB sanely static PixelFormat internalFormatToPixelFormat(GLint internalFormat) { switch (internalFormat) { - case GL_LUMINANCE: - return PIXEL_FORMAT_RGBA_8888; - case GL_SRGB8_ALPHA8: - return PIXEL_FORMAT_RGBA_8888; - case GL_RGBA: - return PIXEL_FORMAT_RGBA_8888; - case GL_RGB: - return PIXEL_FORMAT_RGB_565; - case GL_RGBA16F: - return PIXEL_FORMAT_RGBA_FP16; - default: - LOG_ALWAYS_FATAL("Unsupported bitmap colorType: %d", internalFormat); - return PIXEL_FORMAT_UNKNOWN; + case GL_LUMINANCE: + return PIXEL_FORMAT_RGBA_8888; + case GL_SRGB8_ALPHA8: + return PIXEL_FORMAT_RGBA_8888; + case GL_RGBA: + return PIXEL_FORMAT_RGBA_8888; + case GL_RGB: + return PIXEL_FORMAT_RGB_565; + case GL_RGBA16F: + return PIXEL_FORMAT_RGBA_FP16; + default: + LOG_ALWAYS_FATAL("Unsupported bitmap colorType: %d", internalFormat); + return PIXEL_FORMAT_UNKNOWN; } } sk_sp<Bitmap> OpenGLPipeline::allocateHardwareBitmap(RenderThread& renderThread, - SkBitmap& skBitmap) { + SkBitmap& skBitmap) { renderThread.eglManager().initialize(); uirenderer::Caches& caches = uirenderer::Caches::getInstance(); @@ -404,13 +397,14 @@ sk_sp<Bitmap> OpenGLPipeline::allocateHardwareBitmap(RenderThread& renderThread, bool hasLinearBlending = caches.extensions().hasLinearBlending(); GLint format, type, internalFormat; uirenderer::Texture::colorTypeToGlFormatAndType(caches, skBitmap.colorType(), - needSRGB && hasLinearBlending, &internalFormat, &format, &type); + needSRGB && hasLinearBlending, &internalFormat, + &format, &type); PixelFormat pixelFormat = internalFormatToPixelFormat(internalFormat); - sp<GraphicBuffer> buffer = new GraphicBuffer(info.width(), info.height(), pixelFormat, - GraphicBuffer::USAGE_HW_TEXTURE | - GraphicBuffer::USAGE_SW_WRITE_NEVER | - GraphicBuffer::USAGE_SW_READ_NEVER, + sp<GraphicBuffer> buffer = new GraphicBuffer( + info.width(), info.height(), pixelFormat, + GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER | + GraphicBuffer::USAGE_SW_READ_NEVER, std::string("Bitmap::allocateHardwareBitmap pid [") + std::to_string(getpid()) + "]"); status_t error = buffer->initCheck(); @@ -420,8 +414,8 @@ sk_sp<Bitmap> OpenGLPipeline::allocateHardwareBitmap(RenderThread& renderThread, } SkBitmap bitmap; - if (CC_UNLIKELY(uirenderer::Texture::hasUnsupportedColorType(skBitmap.info(), - hasLinearBlending))) { + if (CC_UNLIKELY( + uirenderer::Texture::hasUnsupportedColorType(skBitmap.info(), hasLinearBlending))) { sk_sp<SkColorSpace> sRGB = SkColorSpace::MakeSRGB(); bitmap = uirenderer::Texture::uploadToN32(skBitmap, hasLinearBlending, std::move(sRGB)); } else { diff --git a/libs/hwui/renderthread/OpenGLPipeline.h b/libs/hwui/renderthread/OpenGLPipeline.h index 4ca19fb6245c..118007c6a46c 100644 --- a/libs/hwui/renderthread/OpenGLPipeline.h +++ b/libs/hwui/renderthread/OpenGLPipeline.h @@ -16,9 +16,9 @@ #pragma once -#include "CanvasContext.h" #include "BakedOpDispatcher.h" #include "BakedOpRenderer.h" +#include "CanvasContext.h" #include "FrameBuilder.h" #include "IRenderPipeline.h" @@ -34,14 +34,13 @@ public: MakeCurrentResult makeCurrent() override; Frame getFrame() override; bool draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty, - const FrameBuilder::LightGeometry& lightGeometry, - LayerUpdateQueue* layerUpdateQueue, - const Rect& contentDrawBounds, bool opaque, bool wideColorGamut, - const BakedOpRenderer::LightInfo& lightInfo, - const std::vector< sp<RenderNode> >& renderNodes, - FrameInfoVisualizer* profiler) override; + const FrameBuilder::LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, + const Rect& contentDrawBounds, bool opaque, bool wideColorGamut, + const BakedOpRenderer::LightInfo& lightInfo, + const std::vector<sp<RenderNode>>& renderNodes, + FrameInfoVisualizer* profiler) override; bool swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty, - FrameInfo* currentFrameInfo, bool* requireSwap) override; + FrameInfo* currentFrameInfo, bool* requireSwap) override; bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) override; DeferredLayerUpdater* createTextureLayer() override; bool setSurface(Surface* window, SwapBehavior swapBehavior, ColorMode colorMode) override; @@ -50,19 +49,19 @@ public: bool isContextReady() override; void onDestroyHardwareResources() override; void renderLayers(const FrameBuilder::LightGeometry& lightGeometry, - LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut, - const BakedOpRenderer::LightInfo& lightInfo) override; + LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut, + const BakedOpRenderer::LightInfo& lightInfo) override; TaskManager* getTaskManager() override; - bool createOrUpdateLayer(RenderNode* node, - const DamageAccumulator& damageAccumulator, bool wideColorGamut) override; + bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator, + bool wideColorGamut) override; bool pinImages(std::vector<SkImage*>& mutableImages) override { return false; } bool pinImages(LsaVector<sk_sp<Bitmap>>& images) override; void unpinImages() override; + void onPrepareTree() override {} static void destroyLayer(RenderNode* node); static void prepareToDraw(const RenderThread& thread, Bitmap* bitmap); static void invokeFunctor(const RenderThread& thread, Functor* functor); - static sk_sp<Bitmap> allocateHardwareBitmap(RenderThread& thread, - SkBitmap& skBitmap); + static sk_sp<Bitmap> allocateHardwareBitmap(RenderThread& thread, SkBitmap& skBitmap); private: EglManager& mEglManager; diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 9048bd14b35c..79e46ed9e65f 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -22,11 +22,11 @@ #include "Readback.h" #include "Rect.h" #include "pipeline/skia/VectorDrawableAtlas.h" +#include "renderstate/RenderState.h" #include "renderthread/CanvasContext.h" #include "renderthread/EglManager.h" #include "renderthread/RenderTask.h" #include "renderthread/RenderThread.h" -#include "renderstate/RenderState.h" #include "utils/Macros.h" #include "utils/TimeUtils.h" @@ -36,46 +36,12 @@ namespace android { namespace uirenderer { namespace renderthread { -#define ARGS(method) method ## Args - -#define CREATE_BRIDGE0(name) CREATE_BRIDGE(name,,,,,,,,) -#define CREATE_BRIDGE1(name, a1) CREATE_BRIDGE(name, a1,,,,,,,) -#define CREATE_BRIDGE2(name, a1, a2) CREATE_BRIDGE(name, a1,a2,,,,,,) -#define CREATE_BRIDGE3(name, a1, a2, a3) CREATE_BRIDGE(name, a1,a2,a3,,,,,) -#define CREATE_BRIDGE4(name, a1, a2, a3, a4) CREATE_BRIDGE(name, a1,a2,a3,a4,,,,) -#define CREATE_BRIDGE5(name, a1, a2, a3, a4, a5) CREATE_BRIDGE(name, a1,a2,a3,a4,a5,,,) -#define CREATE_BRIDGE6(name, a1, a2, a3, a4, a5, a6) CREATE_BRIDGE(name, a1,a2,a3,a4,a5,a6,,) -#define CREATE_BRIDGE7(name, a1, a2, a3, a4, a5, a6, a7) CREATE_BRIDGE(name, a1,a2,a3,a4,a5,a6,a7,) -#define CREATE_BRIDGE(name, a1, a2, a3, a4, a5, a6, a7, a8) \ - typedef struct { \ - a1; a2; a3; a4; a5; a6; a7; a8; \ - } ARGS(name); \ - static_assert(std::is_trivially_destructible<ARGS(name)>::value, \ - "Error, ARGS must be trivially destructible!"); \ - static void* Bridge_ ## name(ARGS(name)* args) - -#define SETUP_TASK(method) \ - LOG_ALWAYS_FATAL_IF( METHOD_INVOKE_PAYLOAD_SIZE < sizeof(ARGS(method)), \ - "METHOD_INVOKE_PAYLOAD_SIZE %zu is smaller than sizeof(" #method "Args) %zu", \ - METHOD_INVOKE_PAYLOAD_SIZE, sizeof(ARGS(method))); \ - MethodInvokeRenderTask* task = new MethodInvokeRenderTask((RunnableMethod) Bridge_ ## method); \ - ARGS(method) *args = (ARGS(method) *) task->payload() - -CREATE_BRIDGE4(createContext, RenderThread* thread, bool translucent, - RenderNode* rootRenderNode, IContextFactory* contextFactory) { - return CanvasContext::create(*args->thread, args->translucent, - args->rootRenderNode, args->contextFactory); -} - -RenderProxy::RenderProxy(bool translucent, RenderNode* rootRenderNode, IContextFactory* contextFactory) - : mRenderThread(RenderThread::getInstance()) - , mContext(nullptr) { - SETUP_TASK(createContext); - args->translucent = translucent; - args->rootRenderNode = rootRenderNode; - args->thread = &mRenderThread; - args->contextFactory = contextFactory; - mContext = (CanvasContext*) postAndWait(task); +RenderProxy::RenderProxy(bool translucent, RenderNode* rootRenderNode, + IContextFactory* contextFactory) + : mRenderThread(RenderThread::getInstance()), mContext(nullptr) { + mContext = mRenderThread.queue().runSync([&]() -> CanvasContext* { + return CanvasContext::create(mRenderThread, translucent, rootRenderNode, contextFactory); + }); mDrawFrameTask.setContext(&mRenderThread, mContext, rootRenderNode); } @@ -83,162 +49,72 @@ RenderProxy::~RenderProxy() { destroyContext(); } -CREATE_BRIDGE1(destroyContext, CanvasContext* context) { - delete args->context; - return nullptr; -} - void RenderProxy::destroyContext() { if (mContext) { - SETUP_TASK(destroyContext); - args->context = mContext; - mContext = nullptr; mDrawFrameTask.setContext(nullptr, nullptr, nullptr); // This is also a fence as we need to be certain that there are no // outstanding mDrawFrame tasks posted before it is destroyed - postAndWait(task); + mRenderThread.queue().runSync([this]() { delete mContext; }); + mContext = nullptr; } } -CREATE_BRIDGE2(setSwapBehavior, CanvasContext* context, SwapBehavior swapBehavior) { - args->context->setSwapBehavior(args->swapBehavior); - return nullptr; -} - void RenderProxy::setSwapBehavior(SwapBehavior swapBehavior) { - SETUP_TASK(setSwapBehavior); - args->context = mContext; - args->swapBehavior = swapBehavior; - post(task); -} - -CREATE_BRIDGE1(loadSystemProperties, CanvasContext* context) { - bool needsRedraw = false; - if (Caches::hasInstance()) { - needsRedraw = Properties::load(); - } - if (args->context->profiler().consumeProperties()) { - needsRedraw = true; - } - return (void*) needsRedraw; + mRenderThread.queue().post([this, swapBehavior]() { mContext->setSwapBehavior(swapBehavior); }); } bool RenderProxy::loadSystemProperties() { - SETUP_TASK(loadSystemProperties); - args->context = mContext; - return (bool) postAndWait(task); -} - -CREATE_BRIDGE2(setName, CanvasContext* context, const char* name) { - args->context->setName(std::string(args->name)); - return nullptr; + return mRenderThread.queue().runSync([this]() -> bool { + bool needsRedraw = false; + if (Caches::hasInstance()) { + needsRedraw = Properties::load(); + } + if (mContext->profiler().consumeProperties()) { + needsRedraw = true; + } + return needsRedraw; + }); } void RenderProxy::setName(const char* name) { - SETUP_TASK(setName); - args->context = mContext; - args->name = name; - postAndWait(task); // block since name/value pointers owned by caller -} - -CREATE_BRIDGE2(initialize, CanvasContext* context, Surface* surface) { - args->context->initialize(args->surface); - return nullptr; + // block since name/value pointers owned by caller + // TODO: Support move arguments + mRenderThread.queue().runSync([this, name]() { mContext->setName(std::string(name)); }); } void RenderProxy::initialize(const sp<Surface>& surface) { - SETUP_TASK(initialize); - args->context = mContext; - args->surface = surface.get(); - post(task); -} - -CREATE_BRIDGE2(updateSurface, CanvasContext* context, Surface* surface) { - args->context->updateSurface(args->surface); - return nullptr; + mRenderThread.queue().post( + [ this, surf = surface ]() mutable { mContext->setSurface(std::move(surf)); }); } void RenderProxy::updateSurface(const sp<Surface>& surface) { - SETUP_TASK(updateSurface); - args->context = mContext; - args->surface = surface.get(); - post(task); -} - -CREATE_BRIDGE2(pauseSurface, CanvasContext* context, Surface* surface) { - return (void*) args->context->pauseSurface(args->surface); + mRenderThread.queue().post( + [ this, surf = surface ]() mutable { mContext->setSurface(std::move(surf)); }); } bool RenderProxy::pauseSurface(const sp<Surface>& surface) { - SETUP_TASK(pauseSurface); - args->context = mContext; - args->surface = surface.get(); - return (bool) postAndWait(task); -} - -CREATE_BRIDGE2(setStopped, CanvasContext* context, bool stopped) { - args->context->setStopped(args->stopped); - return nullptr; + return mRenderThread.queue().runSync([this]() -> bool { return mContext->pauseSurface(); }); } void RenderProxy::setStopped(bool stopped) { - SETUP_TASK(setStopped); - args->context = mContext; - args->stopped = stopped; - postAndWait(task); -} - -CREATE_BRIDGE4(setup, CanvasContext* context, - float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) { - args->context->setup(args->lightRadius, - args->ambientShadowAlpha, args->spotShadowAlpha); - return nullptr; + mRenderThread.queue().runSync([this, stopped]() { mContext->setStopped(stopped); }); } -void RenderProxy::setup(float lightRadius, - uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) { - SETUP_TASK(setup); - args->context = mContext; - args->lightRadius = lightRadius; - args->ambientShadowAlpha = ambientShadowAlpha; - args->spotShadowAlpha = spotShadowAlpha; - post(task); -} - -CREATE_BRIDGE2(setLightCenter, CanvasContext* context, Vector3 lightCenter) { - args->context->setLightCenter(args->lightCenter); - return nullptr; +void RenderProxy::setup(float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) { + mRenderThread.queue().post( + [=]() { mContext->setup(lightRadius, ambientShadowAlpha, spotShadowAlpha); }); } void RenderProxy::setLightCenter(const Vector3& lightCenter) { - SETUP_TASK(setLightCenter); - args->context = mContext; - args->lightCenter = lightCenter; - post(task); -} - -CREATE_BRIDGE2(setOpaque, CanvasContext* context, bool opaque) { - args->context->setOpaque(args->opaque); - return nullptr; + mRenderThread.queue().post([=]() { mContext->setLightCenter(lightCenter); }); } void RenderProxy::setOpaque(bool opaque) { - SETUP_TASK(setOpaque); - args->context = mContext; - args->opaque = opaque; - post(task); -} - -CREATE_BRIDGE2(setWideGamut, CanvasContext* context, bool wideGamut) { - args->context->setWideGamut(args->wideGamut); - return nullptr; + mRenderThread.queue().post([=]() { mContext->setOpaque(opaque); }); } void RenderProxy::setWideGamut(bool wideGamut) { - SETUP_TASK(setWideGamut); - args->context = mContext; - args->wideGamut = wideGamut; - post(task); + mRenderThread.queue().post([=]() { mContext->setWideGamut(wideGamut); }); } int64_t* RenderProxy::frameInfo() { @@ -249,77 +125,40 @@ int RenderProxy::syncAndDrawFrame() { return mDrawFrameTask.drawFrame(); } -CREATE_BRIDGE1(destroy, CanvasContext* context) { - args->context->destroy(); - return nullptr; -} - void RenderProxy::destroy() { - SETUP_TASK(destroy); - args->context = mContext; // destroyCanvasAndSurface() needs a fence as when it returns the // underlying BufferQueue is going to be released from under // the render thread. - postAndWait(task); -} - -CREATE_BRIDGE2(invokeFunctor, RenderThread* thread, Functor* functor) { - CanvasContext::invokeFunctor(*args->thread, args->functor); - return nullptr; + mRenderThread.queue().runSync([=]() { mContext->destroy(); }); } void RenderProxy::invokeFunctor(Functor* functor, bool waitForCompletion) { ATRACE_CALL(); RenderThread& thread = RenderThread::getInstance(); - SETUP_TASK(invokeFunctor); - args->thread = &thread; - args->functor = functor; + auto invoke = [&thread, functor]() { CanvasContext::invokeFunctor(thread, functor); }; if (waitForCompletion) { // waitForCompletion = true is expected to be fairly rare and only // happen in destruction. Thus it should be fine to temporarily // create a Mutex - staticPostAndWait(task); + thread.queue().runSync(std::move(invoke)); } else { - thread.queue(task); + thread.queue().post(std::move(invoke)); } } -CREATE_BRIDGE1(createTextureLayer, CanvasContext* context) { - return args->context->createTextureLayer(); -} - DeferredLayerUpdater* RenderProxy::createTextureLayer() { - SETUP_TASK(createTextureLayer); - args->context = mContext; - void* retval = postAndWait(task); - DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(retval); - return layer; -} - -CREATE_BRIDGE2(buildLayer, CanvasContext* context, RenderNode* node) { - args->context->buildLayer(args->node); - return nullptr; + return mRenderThread.queue().runSync([this]() -> auto { + return mContext->createTextureLayer(); + }); } void RenderProxy::buildLayer(RenderNode* node) { - SETUP_TASK(buildLayer); - args->context = mContext; - args->node = node; - postAndWait(task); -} - -CREATE_BRIDGE3(copyLayerInto, CanvasContext* context, DeferredLayerUpdater* layer, - SkBitmap* bitmap) { - bool success = args->context->copyLayerInto(args->layer, args->bitmap); - return (void*) success; + mRenderThread.queue().runSync([&]() { mContext->buildLayer(node); }); } bool RenderProxy::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap& bitmap) { - SETUP_TASK(copyLayerInto); - args->context = mContext; - args->layer = layer; - args->bitmap = &bitmap; - return (bool) postAndWait(task); + return mRenderThread.queue().runSync( + [&]() -> bool { return mContext->copyLayerInto(layer, &bitmap); }); } void RenderProxy::pushLayerUpdate(DeferredLayerUpdater* layer) { @@ -330,302 +169,129 @@ void RenderProxy::cancelLayerUpdate(DeferredLayerUpdater* layer) { mDrawFrameTask.removeLayerUpdate(layer); } -CREATE_BRIDGE1(detachSurfaceTexture, DeferredLayerUpdater* layer) { - args->layer->detachSurfaceTexture(); - return nullptr; -} - void RenderProxy::detachSurfaceTexture(DeferredLayerUpdater* layer) { - SETUP_TASK(detachSurfaceTexture); - args->layer = layer; - postAndWait(task); -} - -CREATE_BRIDGE1(destroyHardwareResources, CanvasContext* context) { - args->context->destroyHardwareResources(); - return nullptr; + return mRenderThread.queue().runSync([&]() { layer->detachSurfaceTexture(); }); } void RenderProxy::destroyHardwareResources() { - SETUP_TASK(destroyHardwareResources); - args->context = mContext; - postAndWait(task); -} - -CREATE_BRIDGE2(trimMemory, RenderThread* thread, int level) { - CanvasContext::trimMemory(*args->thread, args->level); - return nullptr; + return mRenderThread.queue().runSync([&]() { mContext->destroyHardwareResources(); }); } void RenderProxy::trimMemory(int level) { // Avoid creating a RenderThread to do a trimMemory. if (RenderThread::hasInstance()) { RenderThread& thread = RenderThread::getInstance(); - SETUP_TASK(trimMemory); - args->thread = &thread; - args->level = level; - thread.queue(task); + thread.queue().post([&thread, level]() { CanvasContext::trimMemory(thread, level); }); } } -CREATE_BRIDGE2(overrideProperty, const char* name, const char* value) { - Properties::overrideProperty(args->name, args->value); - return nullptr; -} - void RenderProxy::overrideProperty(const char* name, const char* value) { - SETUP_TASK(overrideProperty); - args->name = name; - args->value = value; - staticPostAndWait(task); // expensive, but block here since name/value pointers owned by caller + // expensive, but block here since name/value pointers owned by caller + RenderThread::getInstance().queue().runSync( + [&]() { Properties::overrideProperty(name, value); }); } -CREATE_BRIDGE0(fence) { - // Intentionally empty - return nullptr; -} - -template <typename T> -void UNUSED(T t) {} - void RenderProxy::fence() { - SETUP_TASK(fence); - UNUSED(args); - postAndWait(task); + mRenderThread.queue().runSync([]() {}); } void RenderProxy::staticFence() { - SETUP_TASK(fence); - UNUSED(args); - staticPostAndWait(task); -} - -CREATE_BRIDGE1(stopDrawing, CanvasContext* context) { - args->context->stopDrawing(); - return nullptr; + RenderThread::getInstance().queue().runSync([]() {}); } void RenderProxy::stopDrawing() { - SETUP_TASK(stopDrawing); - args->context = mContext; - postAndWait(task); -} - -CREATE_BRIDGE1(notifyFramePending, CanvasContext* context) { - args->context->notifyFramePending(); - return nullptr; + mRenderThread.queue().runSync([this]() { mContext->stopDrawing(); }); } void RenderProxy::notifyFramePending() { - SETUP_TASK(notifyFramePending); - args->context = mContext; - mRenderThread.queueAtFront(task); -} - -CREATE_BRIDGE4(dumpProfileInfo, CanvasContext* context, RenderThread* thread, - int fd, int dumpFlags) { - args->context->profiler().dumpData(args->fd); - if (args->dumpFlags & DumpFlags::FrameStats) { - args->context->dumpFrames(args->fd); - } - if (args->dumpFlags & DumpFlags::JankStats) { - args->thread->globalProfileData()->dump(args->fd); - } - if (args->dumpFlags & DumpFlags::Reset) { - args->context->resetFrameStats(); - } - return nullptr; + mRenderThread.queue().post([this]() { mContext->notifyFramePending(); }); } void RenderProxy::dumpProfileInfo(int fd, int dumpFlags) { - SETUP_TASK(dumpProfileInfo); - args->context = mContext; - args->thread = &mRenderThread; - args->fd = fd; - args->dumpFlags = dumpFlags; - postAndWait(task); -} - -CREATE_BRIDGE1(resetProfileInfo, CanvasContext* context) { - args->context->resetFrameStats(); - return nullptr; + mRenderThread.queue().runSync([&]() { + mContext->profiler().dumpData(fd); + if (dumpFlags & DumpFlags::FrameStats) { + mContext->dumpFrames(fd); + } + if (dumpFlags & DumpFlags::JankStats) { + mRenderThread.globalProfileData()->dump(fd); + } + if (dumpFlags & DumpFlags::Reset) { + mContext->resetFrameStats(); + } + }); } void RenderProxy::resetProfileInfo() { - SETUP_TASK(resetProfileInfo); - args->context = mContext; - postAndWait(task); -} - -CREATE_BRIDGE2(frameTimePercentile, RenderThread* thread, int percentile) { - return reinterpret_cast<void*>(static_cast<uintptr_t>( - args->thread->globalProfileData()->findPercentile(args->percentile))); -} - -uint32_t RenderProxy::frameTimePercentile(int p) { - SETUP_TASK(frameTimePercentile); - args->thread = &mRenderThread; - args->percentile = p; - return static_cast<uint32_t>(reinterpret_cast<uintptr_t>( - postAndWait(task))); + mRenderThread.queue().runSync([=]() { mContext->resetFrameStats(); }); } -CREATE_BRIDGE2(dumpGraphicsMemory, int fd, RenderThread* thread) { - args->thread->dumpGraphicsMemory(args->fd); - return nullptr; +uint32_t RenderProxy::frameTimePercentile(int percentile) { + return mRenderThread.queue().runSync([&]() -> auto { + return mRenderThread.globalProfileData()->findPercentile(percentile); + }); } void RenderProxy::dumpGraphicsMemory(int fd) { - if (!RenderThread::hasInstance()) return; - SETUP_TASK(dumpGraphicsMemory); - args->fd = fd; - args->thread = &RenderThread::getInstance(); - staticPostAndWait(task); -} - -CREATE_BRIDGE2(setProcessStatsBuffer, RenderThread* thread, int fd) { - args->thread->globalProfileData().switchStorageToAshmem(args->fd); - close(args->fd); - return nullptr; + auto& thread = RenderThread::getInstance(); + thread.queue().runSync([&]() { thread.dumpGraphicsMemory(fd); }); } void RenderProxy::setProcessStatsBuffer(int fd) { - SETUP_TASK(setProcessStatsBuffer); auto& rt = RenderThread::getInstance(); - args->thread = &rt; - args->fd = dup(fd); - rt.queue(task); -} - -CREATE_BRIDGE1(rotateProcessStatsBuffer, RenderThread* thread) { - args->thread->globalProfileData().rotateStorage(); - return nullptr; + rt.queue().post([&rt, fd = dup(fd) ]() { + rt.globalProfileData().switchStorageToAshmem(fd); + close(fd); + }); } void RenderProxy::rotateProcessStatsBuffer() { - SETUP_TASK(rotateProcessStatsBuffer); auto& rt = RenderThread::getInstance(); - args->thread = &rt; - rt.queue(task); + rt.queue().post([&rt]() { rt.globalProfileData().rotateStorage(); }); } int RenderProxy::getRenderThreadTid() { return mRenderThread.getTid(); } -CREATE_BRIDGE3(addRenderNode, CanvasContext* context, RenderNode* node, bool placeFront) { - args->context->addRenderNode(args->node, args->placeFront); - return nullptr; -} - void RenderProxy::addRenderNode(RenderNode* node, bool placeFront) { - SETUP_TASK(addRenderNode); - args->context = mContext; - args->node = node; - args->placeFront = placeFront; - post(task); -} - -CREATE_BRIDGE2(removeRenderNode, CanvasContext* context, RenderNode* node) { - args->context->removeRenderNode(args->node); - return nullptr; + mRenderThread.queue().post([=]() { mContext->addRenderNode(node, placeFront); }); } void RenderProxy::removeRenderNode(RenderNode* node) { - SETUP_TASK(removeRenderNode); - args->context = mContext; - args->node = node; - post(task); -} - -CREATE_BRIDGE2(drawRenderNode, CanvasContext* context, RenderNode* node) { - args->context->prepareAndDraw(args->node); - return nullptr; + mRenderThread.queue().post([=]() { mContext->removeRenderNode(node); }); } void RenderProxy::drawRenderNode(RenderNode* node) { - SETUP_TASK(drawRenderNode); - args->context = mContext; - args->node = node; - // Be pseudo-thread-safe and don't use any member variables - staticPostAndWait(task); + mRenderThread.queue().runSync([=]() { mContext->prepareAndDraw(node); }); } void RenderProxy::setContentDrawBounds(int left, int top, int right, int bottom) { mDrawFrameTask.setContentDrawBounds(left, top, right, bottom); } -CREATE_BRIDGE1(serializeDisplayListTree, CanvasContext* context) { - args->context->serializeDisplayListTree(); - return nullptr; -} - void RenderProxy::serializeDisplayListTree() { - SETUP_TASK(serializeDisplayListTree); - args->context = mContext; - post(task); -} - -CREATE_BRIDGE2(addFrameMetricsObserver, CanvasContext* context, - FrameMetricsObserver* frameStatsObserver) { - args->context->addFrameMetricsObserver(args->frameStatsObserver); - if (args->frameStatsObserver != nullptr) { - args->frameStatsObserver->decStrong(args->context); - } - return nullptr; -} - -void RenderProxy::addFrameMetricsObserver(FrameMetricsObserver* observer) { - SETUP_TASK(addFrameMetricsObserver); - args->context = mContext; - args->frameStatsObserver = observer; - if (observer != nullptr) { - observer->incStrong(mContext); - } - post(task); -} - -CREATE_BRIDGE2(removeFrameMetricsObserver, CanvasContext* context, - FrameMetricsObserver* frameStatsObserver) { - args->context->removeFrameMetricsObserver(args->frameStatsObserver); - if (args->frameStatsObserver != nullptr) { - args->frameStatsObserver->decStrong(args->context); - } - return nullptr; -} - -void RenderProxy::removeFrameMetricsObserver(FrameMetricsObserver* observer) { - SETUP_TASK(removeFrameMetricsObserver); - args->context = mContext; - args->frameStatsObserver = observer; - if (observer != nullptr) { - observer->incStrong(mContext); - } - post(task); + mRenderThread.queue().post([=]() { mContext->serializeDisplayListTree(); }); } -CREATE_BRIDGE4(copySurfaceInto, RenderThread* thread, - Surface* surface, Rect srcRect, SkBitmap* bitmap) { - return (void*)args->thread->readback().copySurfaceInto(*args->surface, - args->srcRect, args->bitmap); +void RenderProxy::addFrameMetricsObserver(FrameMetricsObserver* observerPtr) { + mRenderThread.queue().post([ this, observer = sp{observerPtr} ]() { + mContext->addFrameMetricsObserver(observer.get()); + }); } -int RenderProxy::copySurfaceInto(sp<Surface>& surface, int left, int top, - int right, int bottom, SkBitmap* bitmap) { - SETUP_TASK(copySurfaceInto); - args->bitmap = bitmap; - args->surface = surface.get(); - args->thread = &RenderThread::getInstance(); - args->srcRect.set(left, top, right, bottom); - return static_cast<int>( - reinterpret_cast<intptr_t>( staticPostAndWait(task) )); +void RenderProxy::removeFrameMetricsObserver(FrameMetricsObserver* observerPtr) { + mRenderThread.queue().post([ this, observer = sp{observerPtr} ]() { + mContext->removeFrameMetricsObserver(observer.get()); + }); } -CREATE_BRIDGE2(prepareToDraw, RenderThread* thread, Bitmap* bitmap) { - CanvasContext::prepareToDraw(*args->thread, args->bitmap); - args->bitmap->unref(); - args->bitmap = nullptr; - return nullptr; +int RenderProxy::copySurfaceInto(sp<Surface>& surface, int left, int top, int right, int bottom, + SkBitmap* bitmap) { + auto& thread = RenderThread::getInstance(); + return static_cast<int>(thread.queue().runSync([&]() -> auto { + return thread.readback().copySurfaceInto(*surface, Rect(left, top, right, bottom), bitmap); + })); } void RenderProxy::prepareToDraw(Bitmap& bitmap) { @@ -635,10 +301,11 @@ void RenderProxy::prepareToDraw(Bitmap& bitmap) { // window or not. if (!RenderThread::hasInstance()) return; RenderThread* renderThread = &RenderThread::getInstance(); - SETUP_TASK(prepareToDraw); - args->thread = renderThread; bitmap.ref(); - args->bitmap = &bitmap; + auto task = [renderThread, &bitmap]() { + CanvasContext::prepareToDraw(*renderThread, &bitmap); + bitmap.unref(); + }; nsecs_t lastVsync = renderThread->timeLord().latestVsync(); nsecs_t estimatedNextVsync = lastVsync + renderThread->timeLord().frameIntervalNanos(); nsecs_t timeToNextVsync = estimatedNextVsync - systemTime(CLOCK_MONOTONIC); @@ -648,97 +315,52 @@ void RenderProxy::prepareToDraw(Bitmap& bitmap) { // TODO: Make this concept a first-class supported thing? RT could use // knowledge of pending draws to better schedule this task if (timeToNextVsync > -6_ms && timeToNextVsync < 1_ms) { - renderThread->queueAt(task, estimatedNextVsync + 8_ms); + renderThread->queue().postAt(estimatedNextVsync + 8_ms, task); } else { - renderThread->queue(task); + renderThread->queue().post(task); } } -CREATE_BRIDGE2(allocateHardwareBitmap, RenderThread* thread, SkBitmap* bitmap) { - sk_sp<Bitmap> hardwareBitmap = args->thread->allocateHardwareBitmap(*args->bitmap); - return hardwareBitmap.release(); -} - sk_sp<Bitmap> RenderProxy::allocateHardwareBitmap(SkBitmap& bitmap) { - SETUP_TASK(allocateHardwareBitmap); - args->bitmap = &bitmap; - args->thread = &RenderThread::getInstance(); - sk_sp<Bitmap> hardwareBitmap(reinterpret_cast<Bitmap*>(staticPostAndWait(task))); - return hardwareBitmap; -} - -CREATE_BRIDGE3(copyGraphicBufferInto, RenderThread* thread, GraphicBuffer* buffer, SkBitmap* bitmap) { - return (void*) args->thread->readback().copyGraphicBufferInto(args->buffer, args->bitmap); + auto& thread = RenderThread::getInstance(); + return thread.queue().runSync([&]() -> auto { return thread.allocateHardwareBitmap(bitmap); }); } int RenderProxy::copyGraphicBufferInto(GraphicBuffer* buffer, SkBitmap* bitmap) { RenderThread& thread = RenderThread::getInstance(); if (Properties::isSkiaEnabled() && gettid() == thread.getTid()) { - //TODO: fix everything that hits this. We should never be triggering a readback ourselves. - return (int) thread.readback().copyGraphicBufferInto(buffer, bitmap); + // TODO: fix everything that hits this. We should never be triggering a readback ourselves. + return (int)thread.readback().copyGraphicBufferInto(buffer, bitmap); } else { - SETUP_TASK(copyGraphicBufferInto); - args->thread = &thread; - args->bitmap = bitmap; - args->buffer = buffer; - return static_cast<int>(reinterpret_cast<intptr_t>(staticPostAndWait(task))); + return thread.queue().runSync([&]() -> int { + return (int)thread.readback().copyGraphicBufferInto(buffer, bitmap); + }); } } -CREATE_BRIDGE2(onBitmapDestroyed, RenderThread* thread, uint32_t pixelRefId) { - args->thread->renderState().onBitmapDestroyed(args->pixelRefId); - return nullptr; -} - void RenderProxy::onBitmapDestroyed(uint32_t pixelRefId) { if (!RenderThread::hasInstance()) return; - SETUP_TASK(onBitmapDestroyed); RenderThread& thread = RenderThread::getInstance(); - args->thread = &thread; - args->pixelRefId = pixelRefId; - thread.queue(task); + thread.queue().post( + [&thread, pixelRefId]() { thread.renderState().onBitmapDestroyed(pixelRefId); }); } void RenderProxy::disableVsync() { Properties::disableVsync = true; } -void RenderProxy::post(RenderTask* task) { - mRenderThread.queue(task); -} - -CREATE_BRIDGE1(repackVectorDrawableAtlas, RenderThread* thread) { - args->thread->cacheManager().acquireVectorDrawableAtlas()->repackIfNeeded( - args->thread->getGrContext()); - return nullptr; -} - void RenderProxy::repackVectorDrawableAtlas() { RenderThread& thread = RenderThread::getInstance(); - SETUP_TASK(repackVectorDrawableAtlas); - args->thread = &thread; - thread.queue(task); -} - -void* RenderProxy::postAndWait(MethodInvokeRenderTask* task) { - void* retval; - task->setReturnPtr(&retval); - SignalingRenderTask syncTask(task, &mSyncMutex, &mSyncCondition); - AutoMutex _lock(mSyncMutex); - mRenderThread.queue(&syncTask); - while (!syncTask.hasRun()) { - mSyncCondition.wait(mSyncMutex); - } - return retval; + thread.queue().post([&thread]() { + thread.cacheManager().acquireVectorDrawableAtlas()->repackIfNeeded(thread.getGrContext()); + }); } -void* RenderProxy::staticPostAndWait(MethodInvokeRenderTask* task) { +void RenderProxy::releaseVDAtlasEntries() { RenderThread& thread = RenderThread::getInstance(); - LOG_ALWAYS_FATAL_IF(gettid() == thread.getTid()); - void* retval; - task->setReturnPtr(&retval); - thread.queueAndWait(task); - return retval; + thread.queue().post([&thread]() { + thread.cacheManager().acquireVectorDrawableAtlas()->delayedReleaseEntries(); + }); } } /* namespace renderthread */ diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index 06eaebd066ee..bc57d9255ad5 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -17,22 +17,16 @@ #ifndef RENDERPROXY_H_ #define RENDERPROXY_H_ -#include "RenderTask.h" - -#include <cutils/compiler.h> -#include <EGL/egl.h> #include <SkBitmap.h> -#include <utils/Condition.h> +#include <cutils/compiler.h> +#include <gui/Surface.h> #include <utils/Functor.h> -#include <utils/Mutex.h> -#include <utils/Timers.h> -#include <utils/StrongPointer.h> -#include "../Caches.h" #include "../FrameMetricsObserver.h" #include "../IContextFactory.h" -#include "CanvasContext.h" #include "DrawFrameTask.h" +#include "SwapBehavior.h" +#include "hwui/Bitmap.h" namespace android { class GraphicBuffer; @@ -41,22 +35,20 @@ namespace uirenderer { class DeferredLayerUpdater; class RenderNode; -class DisplayList; -class Layer; class Rect; namespace renderthread { -class ErrorChannel; +class CanvasContext; class RenderThread; class RenderProxyBridge; namespace DumpFlags { - enum { - FrameStats = 1 << 0, - Reset = 1 << 1, - JankStats = 1 << 2, - }; +enum { + FrameStats = 1 << 0, + Reset = 1 << 1, + JankStats = 1 << 2, +}; }; /* @@ -81,8 +73,7 @@ public: ANDROID_API void updateSurface(const sp<Surface>& surface); ANDROID_API bool pauseSurface(const sp<Surface>& surface); ANDROID_API void setStopped(bool stopped); - ANDROID_API void setup(float lightRadius, - uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha); + ANDROID_API void setup(float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha); ANDROID_API void setLightCenter(const Vector3& lightCenter); ANDROID_API void setOpaque(bool opaque); ANDROID_API void setWideGamut(bool wideGamut); @@ -129,8 +120,8 @@ public: ANDROID_API void removeFrameMetricsObserver(FrameMetricsObserver* observer); ANDROID_API long getDroppedFrameReportCount(); - ANDROID_API static int copySurfaceInto(sp<Surface>& surface, - int left, int top, int right, int bottom, SkBitmap* bitmap); + ANDROID_API static int copySurfaceInto(sp<Surface>& surface, int left, int top, int right, + int bottom, SkBitmap* bitmap); ANDROID_API static void prepareToDraw(Bitmap& bitmap); static sk_sp<Bitmap> allocateHardwareBitmap(SkBitmap& bitmap); @@ -143,22 +134,16 @@ public: static void repackVectorDrawableAtlas(); + static void releaseVDAtlasEntries(); + private: RenderThread& mRenderThread; CanvasContext* mContext; DrawFrameTask mDrawFrameTask; - Mutex mSyncMutex; - Condition mSyncCondition; - void destroyContext(); - void post(RenderTask* task); - void* postAndWait(MethodInvokeRenderTask* task); - - static void* staticPostAndWait(MethodInvokeRenderTask* task); - // Friend class to help with bridging friend class RenderProxyBridge; }; diff --git a/libs/hwui/renderthread/RenderTask.h b/libs/hwui/renderthread/RenderTask.h index a7acf91cbdb1..c56a3578ad58 100644 --- a/libs/hwui/renderthread/RenderTask.h +++ b/libs/hwui/renderthread/RenderTask.h @@ -53,7 +53,7 @@ public: ANDROID_API virtual void run() = 0; RenderTask* mNext; - nsecs_t mRunAt; // nano-seconds on the SYSTEM_TIME_MONOTONIC clock + nsecs_t mRunAt; // nano-seconds on the SYSTEM_TIME_MONOTONIC clock }; class SignalingRenderTask : public RenderTask { @@ -75,8 +75,7 @@ typedef void* (*RunnableMethod)(void* data); class MethodInvokeRenderTask : public RenderTask { public: - explicit MethodInvokeRenderTask(RunnableMethod method) - : mMethod(method), mReturnPtr(nullptr) {} + explicit MethodInvokeRenderTask(RunnableMethod method) : mMethod(method), mReturnPtr(nullptr) {} void* payload() { return mData; } void setReturnPtr(void** retptr) { mReturnPtr = retptr; } @@ -89,6 +88,7 @@ public: // Commit suicide delete this; } + private: RunnableMethod mMethod; char mData[METHOD_INVOKE_PAYLOAD_SIZE]; diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp index 72a428f1c70c..8e0546b529af 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -16,17 +16,18 @@ #include "RenderThread.h" -#include "hwui/Bitmap.h" -#include "renderstate/RenderState.h" -#include "renderthread/OpenGLPipeline.h" -#include "pipeline/skia/SkiaOpenGLReadback.h" -#include "pipeline/skia/SkiaOpenGLPipeline.h" -#include "pipeline/skia/SkiaVulkanPipeline.h" #include "CanvasContext.h" #include "EglManager.h" #include "OpenGLReadback.h" #include "RenderProxy.h" #include "VulkanManager.h" +#include "hwui/Bitmap.h" +#include "pipeline/skia/SkiaOpenGLPipeline.h" +#include "pipeline/skia/SkiaOpenGLReadback.h" +#include "pipeline/skia/SkiaVulkanReadback.h" +#include "pipeline/skia/SkiaVulkanPipeline.h" +#include "renderstate/RenderState.h" +#include "renderthread/OpenGLPipeline.h" #include "utils/FatVector.h" #include <gui/DisplayEventReceiver.h> @@ -49,107 +50,19 @@ static const size_t EVENT_BUFFER_SIZE = 100; // Slight delay to give the UI time to push us a new frame before we replay static const nsecs_t DISPATCH_FRAME_CALLBACKS_DELAY = milliseconds_to_nanoseconds(4); -TaskQueue::TaskQueue() : mHead(nullptr), mTail(nullptr) {} - -RenderTask* TaskQueue::next() { - RenderTask* ret = mHead; - if (ret) { - mHead = ret->mNext; - if (!mHead) { - mTail = nullptr; - } - ret->mNext = nullptr; - } - return ret; -} - -RenderTask* TaskQueue::peek() { - return mHead; -} - -void TaskQueue::queue(RenderTask* task) { - // Since the RenderTask itself forms the linked list it is not allowed - // to have the same task queued twice - LOG_ALWAYS_FATAL_IF(task->mNext || mTail == task, "Task is already in the queue!"); - if (mTail) { - // Fast path if we can just append - if (mTail->mRunAt <= task->mRunAt) { - mTail->mNext = task; - mTail = task; - } else { - // Need to find the proper insertion point - RenderTask* previous = nullptr; - RenderTask* next = mHead; - while (next && next->mRunAt <= task->mRunAt) { - previous = next; - next = next->mNext; - } - if (!previous) { - task->mNext = mHead; - mHead = task; - } else { - previous->mNext = task; - if (next) { - task->mNext = next; - } else { - mTail = task; - } - } - } - } else { - mTail = mHead = task; - } -} - -void TaskQueue::queueAtFront(RenderTask* task) { - LOG_ALWAYS_FATAL_IF(task->mNext || mHead == task, "Task is already in the queue!"); - if (mTail) { - task->mNext = mHead; - mHead = task; - } else { - mTail = mHead = task; - } -} - -void TaskQueue::remove(RenderTask* task) { - // TaskQueue is strict here to enforce that users are keeping track of - // their RenderTasks due to how their memory is managed - LOG_ALWAYS_FATAL_IF(!task->mNext && mTail != task, - "Cannot remove a task that isn't in the queue!"); - - // If task is the head we can just call next() to pop it off - // Otherwise we need to scan through to find the task before it - if (peek() == task) { - next(); - } else { - RenderTask* previous = mHead; - while (previous->mNext != task) { - previous = previous->mNext; - } - previous->mNext = task->mNext; - if (mTail == task) { - mTail = previous; - } - } -} - -class DispatchFrameCallbacks : public RenderTask { -private: - RenderThread* mRenderThread; -public: - explicit DispatchFrameCallbacks(RenderThread* rt) : mRenderThread(rt) {} - - virtual void run() override { - mRenderThread->dispatchFrameCallbacks(); - } -}; - static bool gHasRenderThreadInstance = false; +static void (*gOnStartHook)() = nullptr; + bool RenderThread::hasInstance() { return gHasRenderThreadInstance; } +void RenderThread::setOnStartHook(void (*onStartHook)()) { + LOG_ALWAYS_FATAL_IF(hasInstance(), "can't set an onStartHook after we've started..."); + gOnStartHook = onStartHook; +} + RenderThread& RenderThread::getInstance() { // This is a pointer because otherwise __cxa_finalize // will try to delete it like a Good Citizen but that causes us to crash @@ -159,19 +72,16 @@ RenderThread& RenderThread::getInstance() { return *sInstance; } -RenderThread::RenderThread() : Thread(true) - , mNextWakeup(LLONG_MAX) +RenderThread::RenderThread() + : ThreadBase() , mDisplayEventReceiver(nullptr) , mVsyncRequested(false) , mFrameCallbackTaskPending(false) - , mFrameCallbackTask(nullptr) , mRenderState(nullptr) , mEglManager(nullptr) , mVkManager(nullptr) { Properties::load(); - mFrameCallbackTask = new DispatchFrameCallbacks(this); - mLooper = new Looper(false); - run("RenderThread"); + start("RenderThread"); } RenderThread::~RenderThread() { @@ -182,17 +92,18 @@ void RenderThread::initializeDisplayEventReceiver() { LOG_ALWAYS_FATAL_IF(mDisplayEventReceiver, "Initializing a second DisplayEventReceiver?"); mDisplayEventReceiver = new DisplayEventReceiver(); status_t status = mDisplayEventReceiver->initCheck(); - LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "Initialization of DisplayEventReceiver " - "failed with status: %d", status); + LOG_ALWAYS_FATAL_IF(status != NO_ERROR, + "Initialization of DisplayEventReceiver " + "failed with status: %d", + status); // Register the FD - mLooper->addFd(mDisplayEventReceiver->getFd(), 0, - Looper::EVENT_INPUT, RenderThread::displayEventReceiverCallback, this); + mLooper->addFd(mDisplayEventReceiver->getFd(), 0, Looper::EVENT_INPUT, + RenderThread::displayEventReceiverCallback, this); } void RenderThread::initThreadLocals() { - sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay( - ISurfaceComposer::eDisplayIdMain)); + sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &mDisplayInfo); LOG_ALWAYS_FATAL_IF(status, "Failed to get display info\n"); nsecs_t frameIntervalNanos = static_cast<nsecs_t>(1000000000 / mDisplayInfo.fps); @@ -232,18 +143,15 @@ void RenderThread::dumpGraphicsMemory(int fd) { break; } default: - LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType); + LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType); break; } - FILE *file = fdopen(fd, "a"); - fprintf(file, "\n%s\n", cachesOutput.string()); - fprintf(file, "\nPipeline=%s\n", pipeline.string()); - fflush(file); + dprintf(fd, "\n%s\n", cachesOutput.string()); + dprintf(fd, "\nPipeline=%s\n", pipeline.string()); } Readback& RenderThread::readback() { - if (!mReadback) { auto renderType = Properties::getRenderPipelineType(); switch (renderType) { @@ -251,14 +159,13 @@ Readback& RenderThread::readback() { mReadback = new OpenGLReadbackImpl(*this); break; case RenderPipelineType::SkiaGL: - case RenderPipelineType::SkiaVulkan: - // It works to use the OpenGL pipeline for Vulkan but this is not - // ideal as it causes us to create an OpenGL context in addition - // to the Vulkan one. mReadback = new skiapipeline::SkiaOpenGLReadback(*this); break; + case RenderPipelineType::SkiaVulkan: + mReadback = new skiapipeline::SkiaVulkanReadback(*this); + break; default: - LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType); + LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType); break; } } @@ -266,30 +173,32 @@ Readback& RenderThread::readback() { return *mReadback; } -void RenderThread::setGrContext(GrContext* context) { +void RenderThread::setGrContext(sk_sp<GrContext> context) { mCacheManager->reset(context); - if (mGrContext.get()) { + if (mGrContext) { mGrContext->releaseResourcesAndAbandonContext(); } - mGrContext.reset(context); + mGrContext = std::move(context); } int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) { if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) { ALOGE("Display event receiver pipe was closed or an error occurred. " - "events=0x%x", events); - return 0; // remove the callback + "events=0x%x", + events); + return 0; // remove the callback } if (!(events & Looper::EVENT_INPUT)) { ALOGW("Received spurious callback for unhandled poll event. " - "events=0x%x", events); - return 1; // keep the callback + "events=0x%x", + events); + return 1; // keep the callback } reinterpret_cast<RenderThread*>(data)->drainDisplayEventQueue(); - return 1; // keep the callback + return 1; // keep the callback } static nsecs_t latestVsyncEvent(DisplayEventReceiver* receiver) { @@ -300,9 +209,9 @@ static nsecs_t latestVsyncEvent(DisplayEventReceiver* receiver) { for (ssize_t i = 0; i < n; i++) { const DisplayEventReceiver::Event& ev = buf[i]; switch (ev.header.type) { - case DisplayEventReceiver::DISPLAY_EVENT_VSYNC: - latest = ev.header.timestamp; - break; + case DisplayEventReceiver::DISPLAY_EVENT_VSYNC: + latest = ev.header.timestamp; + break; } } } @@ -321,7 +230,7 @@ void RenderThread::drainDisplayEventQueue() { ATRACE_NAME("queue mFrameCallbackTask"); mFrameCallbackTaskPending = true; nsecs_t runAt = (vsyncEvent + DISPATCH_FRAME_CALLBACKS_DELAY); - queueAt(mFrameCallbackTask, runAt); + queue().postAt(runAt, [this]() { dispatchFrameCallbacks(); }); } } } @@ -337,7 +246,8 @@ void RenderThread::dispatchFrameCallbacks() { // Assume one of them will probably animate again so preemptively // request the next vsync in case it occurs mid-frame requestVsync(); - for (std::set<IFrameCallback*>::iterator it = callbacks.begin(); it != callbacks.end(); it++) { + for (std::set<IFrameCallback*>::iterator it = callbacks.begin(); it != callbacks.end(); + it++) { (*it)->doFrame(); } } @@ -347,49 +257,25 @@ void RenderThread::requestVsync() { if (!mVsyncRequested) { mVsyncRequested = true; status_t status = mDisplayEventReceiver->requestNextVsync(); - LOG_ALWAYS_FATAL_IF(status != NO_ERROR, - "requestNextVsync failed with status: %d", status); + LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "requestNextVsync failed with status: %d", status); } } bool RenderThread::threadLoop() { setpriority(PRIO_PROCESS, 0, PRIORITY_DISPLAY); + if (gOnStartHook) { + gOnStartHook(); + } initThreadLocals(); - int timeoutMillis = -1; - for (;;) { - int result = mLooper->pollOnce(timeoutMillis); - LOG_ALWAYS_FATAL_IF(result == Looper::POLL_ERROR, - "RenderThread Looper POLL_ERROR!"); - - nsecs_t nextWakeup; - { - FatVector<RenderTask*, 10> workQueue; - // Process our queue, if we have anything. By first acquiring - // all the pending events then processing them we avoid vsync - // starvation if more tasks are queued while we are processing tasks. - while (RenderTask* task = nextTask(&nextWakeup)) { - workQueue.push_back(task); - } - for (auto task : workQueue) { - task->run(); - // task may have deleted itself, do not reference it again - } - } - if (nextWakeup == LLONG_MAX) { - timeoutMillis = -1; - } else { - nsecs_t timeoutNanos = nextWakeup - systemTime(SYSTEM_TIME_MONOTONIC); - timeoutMillis = nanoseconds_to_milliseconds(timeoutNanos); - if (timeoutMillis < 0) { - timeoutMillis = 0; - } - } + while (true) { + waitForWork(); + processQueue(); if (mPendingRegistrationFrameCallbacks.size() && !mFrameCallbackTaskPending) { drainDisplayEventQueue(); - mFrameCallbacks.insert( - mPendingRegistrationFrameCallbacks.begin(), mPendingRegistrationFrameCallbacks.end()); + mFrameCallbacks.insert(mPendingRegistrationFrameCallbacks.begin(), + mPendingRegistrationFrameCallbacks.end()); mPendingRegistrationFrameCallbacks.clear(); requestVsync(); } @@ -406,46 +292,6 @@ bool RenderThread::threadLoop() { return false; } -void RenderThread::queue(RenderTask* task) { - AutoMutex _lock(mLock); - mQueue.queue(task); - if (mNextWakeup && task->mRunAt < mNextWakeup) { - mNextWakeup = 0; - mLooper->wake(); - } -} - -void RenderThread::queueAndWait(RenderTask* task) { - // These need to be local to the thread to avoid the Condition - // signaling the wrong thread. The easiest way to achieve that is to just - // make this on the stack, although that has a slight cost to it - Mutex mutex; - Condition condition; - SignalingRenderTask syncTask(task, &mutex, &condition); - - AutoMutex _lock(mutex); - queue(&syncTask); - while (!syncTask.hasRun()) { - condition.wait(mutex); - } -} - -void RenderThread::queueAtFront(RenderTask* task) { - AutoMutex _lock(mLock); - mQueue.queueAtFront(task); - mLooper->wake(); -} - -void RenderThread::queueAt(RenderTask* task, nsecs_t runAtNs) { - task->mRunAt = runAtNs; - queue(task); -} - -void RenderThread::remove(RenderTask* task) { - AutoMutex _lock(mLock); - mQueue.remove(task); -} - void RenderThread::postFrameCallback(IFrameCallback* callback) { mPendingRegistrationFrameCallbacks.insert(callback); } @@ -463,26 +309,6 @@ void RenderThread::pushBackFrameCallback(IFrameCallback* callback) { } } -RenderTask* RenderThread::nextTask(nsecs_t* nextWakeup) { - AutoMutex _lock(mLock); - RenderTask* next = mQueue.peek(); - if (!next) { - mNextWakeup = LLONG_MAX; - } else { - mNextWakeup = next->mRunAt; - // Most tasks won't be delayed, so avoid unnecessary systemTime() calls - if (next->mRunAt <= 0 || next->mRunAt <= systemTime(SYSTEM_TIME_MONOTONIC)) { - next = mQueue.next(); - } else { - next = nullptr; - } - } - if (nextWakeup) { - *nextWakeup = mNextWakeup; - } - return next; -} - sk_sp<Bitmap> RenderThread::allocateHardwareBitmap(SkBitmap& skBitmap) { auto renderType = Properties::getRenderPipelineType(); switch (renderType) { @@ -493,12 +319,16 @@ sk_sp<Bitmap> RenderThread::allocateHardwareBitmap(SkBitmap& skBitmap) { case RenderPipelineType::SkiaVulkan: return skiapipeline::SkiaVulkanPipeline::allocateHardwareBitmap(*this, skBitmap); default: - LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType); + LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType); break; } return nullptr; } +bool RenderThread::isCurrent() { + return gettid() == getInstance().getTid(); +} + } /* namespace renderthread */ } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h index bef47b3e27c5..3aa548773b3b 100644 --- a/libs/hwui/renderthread/RenderThread.h +++ b/libs/hwui/renderthread/RenderThread.h @@ -22,15 +22,18 @@ #include "../JankTracker.h" #include "CacheManager.h" #include "TimeLord.h" +#include "thread/ThreadBase.h" #include <GrContext.h> -#include <cutils/compiler.h> #include <SkBitmap.h> +#include <cutils/compiler.h> #include <ui/DisplayInfo.h> #include <utils/Looper.h> #include <utils/Thread.h> +#include <thread/ThreadBase.h> #include <memory> +#include <mutex> #include <set> namespace android { @@ -47,26 +50,10 @@ class TestUtils; namespace renderthread { class CanvasContext; -class DispatchFrameCallbacks; class EglManager; class RenderProxy; class VulkanManager; -class TaskQueue { -public: - TaskQueue(); - - RenderTask* next(); - void queue(RenderTask* task); - void queueAtFront(RenderTask* task); - RenderTask* peek(); - void remove(RenderTask* task); - -private: - RenderTask* mHead; - RenderTask* mTail; -}; - // Mimics android.view.Choreographer.FrameCallback class IFrameCallback { public: @@ -76,16 +63,14 @@ protected: ~IFrameCallback() {} }; -class ANDROID_API RenderThread : public Thread { +class RenderThread : private ThreadBase { PREVENT_COPY_AND_ASSIGN(RenderThread); + public: - // RenderThread takes complete ownership of tasks that are queued - // and will delete them after they are run - ANDROID_API void queue(RenderTask* task); - ANDROID_API void queueAndWait(RenderTask* task); - ANDROID_API void queueAtFront(RenderTask* task); - void queueAt(RenderTask* task, nsecs_t runAtNs); - void remove(RenderTask* task); + // Sets a callback that fires before any RenderThread setup has occured. + ANDROID_API static void setOnStartHook(void (*onStartHook)()); + + WorkQueue& queue() { return ThreadBase::queue(); } // Mimics android.view.Choreographer void postFrameCallback(IFrameCallback* callback); @@ -103,7 +88,7 @@ public: const DisplayInfo& mainDisplayInfo() { return mDisplayInfo; } GrContext* getGrContext() const { return mGrContext.get(); } - void setGrContext(GrContext* cxt); + void setGrContext(sk_sp<GrContext> cxt); CacheManager& cacheManager() { return *mCacheManager; } VulkanManager& vulkanManager() { return *mVkManager; } @@ -111,6 +96,14 @@ public: sk_sp<Bitmap> allocateHardwareBitmap(SkBitmap& skBitmap); void dumpGraphicsMemory(int fd); + /** + * isCurrent provides a way to query, if the caller is running on + * the render thread. + * + * @return true only if isCurrent is invoked from the render thread. + */ + static bool isCurrent(); + protected: virtual bool threadLoop() override; @@ -132,17 +125,6 @@ private: void dispatchFrameCallbacks(); void requestVsync(); - // Returns the next task to be run. If this returns NULL nextWakeup is set - // to the time to requery for the nextTask to run. mNextWakeup is also - // set to this time - RenderTask* nextTask(nsecs_t* nextWakeup); - - sp<Looper> mLooper; - Mutex mLock; - - nsecs_t mNextWakeup; - TaskQueue mQueue; - DisplayInfo mDisplayInfo; DisplayEventReceiver* mDisplayEventReceiver; @@ -154,7 +136,6 @@ private: // the previous one std::set<IFrameCallback*> mPendingRegistrationFrameCallbacks; bool mFrameCallbackTaskPending; - DispatchFrameCallbacks* mFrameCallbackTask; TimeLord mTimeLord; RenderState* mRenderState; diff --git a/libs/hwui/renderthread/TimeLord.cpp b/libs/hwui/renderthread/TimeLord.cpp index 6c2575f699bb..b82c5d159756 100644 --- a/libs/hwui/renderthread/TimeLord.cpp +++ b/libs/hwui/renderthread/TimeLord.cpp @@ -19,10 +19,7 @@ namespace android { namespace uirenderer { namespace renderthread { -TimeLord::TimeLord() - : mFrameIntervalNanos(milliseconds_to_nanoseconds(16)) - , mFrameTimeNanos(0) { -} +TimeLord::TimeLord() : mFrameIntervalNanos(milliseconds_to_nanoseconds(16)), mFrameTimeNanos(0) {} bool TimeLord::vsyncReceived(nsecs_t vsync) { if (vsync > mFrameTimeNanos) { diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp index 2195143658d2..9d246ffc9a4a 100644 --- a/libs/hwui/renderthread/VulkanManager.cpp +++ b/libs/hwui/renderthread/VulkanManager.cpp @@ -31,11 +31,10 @@ namespace android { namespace uirenderer { namespace renderthread { -#define GET_PROC(F) m ## F = (PFN_vk ## F) vkGetInstanceProcAddr(instance, "vk" #F) -#define GET_DEV_PROC(F) m ## F = (PFN_vk ## F) vkGetDeviceProcAddr(device, "vk" #F) +#define GET_PROC(F) m##F = (PFN_vk##F)vkGetInstanceProcAddr(instance, "vk" #F) +#define GET_DEV_PROC(F) m##F = (PFN_vk##F)vkGetDeviceProcAddr(device, "vk" #F) -VulkanManager::VulkanManager(RenderThread& thread) : mRenderThread(thread) { -} +VulkanManager::VulkanManager(RenderThread& thread) : mRenderThread(thread) {} void VulkanManager::destroy() { if (!hasVkContext()) return; @@ -51,12 +50,15 @@ void VulkanManager::destroy() { } void VulkanManager::initialize() { - if (hasVkContext()) { return; } + if (hasVkContext()) { + return; + } auto canPresent = [](VkInstance, VkPhysicalDevice, uint32_t) { return true; }; mBackendContext.reset(GrVkBackendContext::Create(vkGetInstanceProcAddr, vkGetDeviceProcAddr, - &mPresentQueueIndex, canPresent)); + &mPresentQueueIndex, canPresent)); + LOG_ALWAYS_FATAL_IF(!mBackendContext.get()); // Get all the addresses of needed vulkan functions VkInstance instance = mBackendContext->fInstance; @@ -99,15 +101,19 @@ void VulkanManager::initialize() { // this needs to be on the render queue commandPoolInfo.queueFamilyIndex = mBackendContext->fGraphicsQueueIndex; commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - SkDEBUGCODE(VkResult res =) mCreateCommandPool(mBackendContext->fDevice, - &commandPoolInfo, nullptr, &mCommandPool); + SkDEBUGCODE(VkResult res =) mCreateCommandPool(mBackendContext->fDevice, &commandPoolInfo, + nullptr, &mCommandPool); SkASSERT(VK_SUCCESS == res); } mGetDeviceQueue(mBackendContext->fDevice, mPresentQueueIndex, 0, &mPresentQueue); - mRenderThread.setGrContext(GrContext::Create(kVulkan_GrBackend, - (GrBackendContext) mBackendContext.get())); + GrContextOptions options; + options.fDisableDistanceFieldPaths = true; + mRenderThread.cacheManager().configureContext(&options); + sk_sp<GrContext> grContext(GrContext::MakeVulkan(mBackendContext, options)); + LOG_ALWAYS_FATAL_IF(!grContext.get()); + mRenderThread.setGrContext(grContext); DeviceInfo::initialize(mRenderThread.getGrContext()->caps()->maxRenderTargetSize()); if (Properties::enablePartialUpdates && Properties::useBufferAge) { @@ -127,13 +133,13 @@ VulkanSurface::BackbufferInfo* VulkanManager::getAvailableBackbuffer(VulkanSurfa surface->mCurrentBackbufferIndex = 0; } - VulkanSurface::BackbufferInfo* backbuffer = surface->mBackbuffers + - surface->mCurrentBackbufferIndex; + VulkanSurface::BackbufferInfo* backbuffer = + surface->mBackbuffers + surface->mCurrentBackbufferIndex; // Before we reuse a backbuffer, make sure its fences have all signaled so that we can safely // reuse its commands buffers. - VkResult res = mWaitForFences(mBackendContext->fDevice, 2, backbuffer->mUsageFences, - true, UINT64_MAX); + VkResult res = + mWaitForFences(mBackendContext->fDevice, 2, backbuffer->mUsageFences, true, UINT64_MAX); if (res != VK_SUCCESS) { return nullptr; } @@ -141,7 +147,6 @@ VulkanSurface::BackbufferInfo* VulkanManager::getAvailableBackbuffer(VulkanSurfa return backbuffer; } - SkSurface* VulkanManager::getBackbufferSurface(VulkanSurface* surface) { VulkanSurface::BackbufferInfo* backbuffer = getAvailableBackbuffer(surface); SkASSERT(backbuffer); @@ -154,7 +159,8 @@ SkSurface* VulkanManager::getBackbufferSurface(VulkanSurface* surface) { // The acquire will signal the attached mAcquireSemaphore. We use this to know the image has // finished presenting and that it is safe to begin sending new commands to the returned image. res = mAcquireNextImageKHR(mBackendContext->fDevice, surface->mSwapchain, UINT64_MAX, - backbuffer->mAcquireSemaphore, VK_NULL_HANDLE, &backbuffer->mImageIndex); + backbuffer->mAcquireSemaphore, VK_NULL_HANDLE, + &backbuffer->mImageIndex); if (VK_ERROR_SURFACE_LOST_KHR == res) { // need to figure out how to create a new vkSurface without the platformData* @@ -172,7 +178,8 @@ SkSurface* VulkanManager::getBackbufferSurface(VulkanSurface* surface) { // acquire the image res = mAcquireNextImageKHR(mBackendContext->fDevice, surface->mSwapchain, UINT64_MAX, - backbuffer->mAcquireSemaphore, VK_NULL_HANDLE, &backbuffer->mImageIndex); + backbuffer->mAcquireSemaphore, VK_NULL_HANDLE, + &backbuffer->mImageIndex); if (VK_SUCCESS != res) { return nullptr; @@ -182,25 +189,25 @@ SkSurface* VulkanManager::getBackbufferSurface(VulkanSurface* surface) { // set up layout transfer from initial to color attachment VkImageLayout layout = surface->mImageInfos[backbuffer->mImageIndex].mImageLayout; SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout || VK_IMAGE_LAYOUT_PRESENT_SRC_KHR == layout); - VkPipelineStageFlags srcStageMask = (VK_IMAGE_LAYOUT_UNDEFINED == layout) ? - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT : - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + VkPipelineStageFlags srcStageMask = (VK_IMAGE_LAYOUT_UNDEFINED == layout) + ? VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT + : VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - VkAccessFlags srcAccessMask = (VK_IMAGE_LAYOUT_UNDEFINED == layout) ? - 0 : VK_ACCESS_MEMORY_READ_BIT; + VkAccessFlags srcAccessMask = + (VK_IMAGE_LAYOUT_UNDEFINED == layout) ? 0 : VK_ACCESS_MEMORY_READ_BIT; VkAccessFlags dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; VkImageMemoryBarrier imageMemoryBarrier = { - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType - NULL, // pNext - srcAccessMask, // outputMask - dstAccessMask, // inputMask - layout, // oldLayout - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // newLayout - mPresentQueueIndex, // srcQueueFamilyIndex - mBackendContext->fGraphicsQueueIndex, // dstQueueFamilyIndex - surface->mImages[backbuffer->mImageIndex], // image - { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } // subresourceRange + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType + NULL, // pNext + srcAccessMask, // outputMask + dstAccessMask, // inputMask + layout, // oldLayout + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // newLayout + mPresentQueueIndex, // srcQueueFamilyIndex + mBackendContext->fGraphicsQueueIndex, // dstQueueFamilyIndex + surface->mImages[backbuffer->mImageIndex], // image + {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1} // subresourceRange }; mResetCommandBuffer(backbuffer->mTransitionCmdBuffers[0], 0); @@ -210,8 +217,8 @@ SkSurface* VulkanManager::getBackbufferSurface(VulkanSurface* surface) { info.flags = 0; mBeginCommandBuffer(backbuffer->mTransitionCmdBuffers[0], &info); - mCmdPipelineBarrier(backbuffer->mTransitionCmdBuffers[0], srcStageMask, dstStageMask, 0, - 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); + mCmdPipelineBarrier(backbuffer->mTransitionCmdBuffers[0], srcStageMask, dstStageMask, 0, 0, + nullptr, 0, nullptr, 1, &imageMemoryBarrier); mEndCommandBuffer(backbuffer->mTransitionCmdBuffers[0]); @@ -235,7 +242,7 @@ SkSurface* VulkanManager::getBackbufferSurface(VulkanSurface* surface) { GrVkImageInfo* imageInfo; sk_sp<SkSurface> skSurface = surface->mImageInfos[backbuffer->mImageIndex].mSurface; skSurface->getRenderTargetHandle((GrBackendObject*)&imageInfo, - SkSurface::kFlushRead_BackendHandleAccess); + SkSurface::kFlushRead_BackendHandleAccess); imageInfo->updateImageLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); surface->mBackbuffer = std::move(skSurface); @@ -246,14 +253,14 @@ void VulkanManager::destroyBuffers(VulkanSurface* surface) { if (surface->mBackbuffers) { for (uint32_t i = 0; i < surface->mImageCount + 1; ++i) { mWaitForFences(mBackendContext->fDevice, 2, surface->mBackbuffers[i].mUsageFences, true, - UINT64_MAX); + UINT64_MAX); surface->mBackbuffers[i].mImageIndex = -1; mDestroySemaphore(mBackendContext->fDevice, surface->mBackbuffers[i].mAcquireSemaphore, - nullptr); + nullptr); mDestroySemaphore(mBackendContext->fDevice, surface->mBackbuffers[i].mRenderSemaphore, - nullptr); + nullptr); mFreeCommandBuffers(mBackendContext->fDevice, mCommandPool, 2, - surface->mBackbuffers[i].mTransitionCmdBuffers); + surface->mBackbuffers[i].mTransitionCmdBuffers); mDestroyFence(mBackendContext->fDevice, surface->mBackbuffers[i].mUsageFences[0], 0); mDestroyFence(mBackendContext->fDevice, surface->mBackbuffers[i].mUsageFences[1], 0); } @@ -290,11 +297,11 @@ void VulkanManager::destroySurface(VulkanSurface* surface) { void VulkanManager::createBuffers(VulkanSurface* surface, VkFormat format, VkExtent2D extent) { mGetSwapchainImagesKHR(mBackendContext->fDevice, surface->mSwapchain, &surface->mImageCount, - nullptr); + nullptr); SkASSERT(surface->mImageCount); surface->mImages = new VkImage[surface->mImageCount]; - mGetSwapchainImagesKHR(mBackendContext->fDevice, surface->mSwapchain, - &surface->mImageCount, surface->mImages); + mGetSwapchainImagesKHR(mBackendContext->fDevice, surface->mSwapchain, &surface->mImageCount, + surface->mImages); SkSurfaceProps props(0, kUnknown_SkPixelGeometry); @@ -303,7 +310,7 @@ void VulkanManager::createBuffers(VulkanSurface* surface, VkFormat format, VkExt for (uint32_t i = 0; i < surface->mImageCount; ++i) { GrVkImageInfo info; info.fImage = surface->mImages[i]; - info.fAlloc = { VK_NULL_HANDLE, 0, 0, 0 }; + info.fAlloc = {VK_NULL_HANDLE, 0, 0, 0}; info.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED; info.fImageTiling = VK_IMAGE_TILING_OPTIMAL; info.fFormat = format; @@ -312,8 +319,8 @@ void VulkanManager::createBuffers(VulkanSurface* surface, VkFormat format, VkExt GrBackendRenderTarget backendRT(extent.width, extent.height, 0, 0, info); VulkanSurface::ImageInfo& imageInfo = surface->mImageInfos[i]; - imageInfo.mSurface = SkSurface::MakeFromBackendRenderTarget(mRenderThread.getGrContext(), - backendRT, kTopLeft_GrSurfaceOrigin, nullptr, &props); + imageInfo.mSurface = SkSurface::MakeFromBackendRenderTarget( + mRenderThread.getGrContext(), backendRT, kTopLeft_GrSurfaceOrigin, nullptr, &props); } SkASSERT(mCommandPool != VK_NULL_HANDLE); @@ -343,16 +350,16 @@ void VulkanManager::createBuffers(VulkanSurface* surface, VkFormat format, VkExt for (uint32_t i = 0; i < surface->mImageCount + 1; ++i) { SkDEBUGCODE(VkResult res); surface->mBackbuffers[i].mImageIndex = -1; - SkDEBUGCODE(res = ) mCreateSemaphore(mBackendContext->fDevice, &semaphoreInfo, nullptr, - &surface->mBackbuffers[i].mAcquireSemaphore); - SkDEBUGCODE(res = ) mCreateSemaphore(mBackendContext->fDevice, &semaphoreInfo, nullptr, - &surface->mBackbuffers[i].mRenderSemaphore); - SkDEBUGCODE(res = ) mAllocateCommandBuffers(mBackendContext->fDevice, &commandBuffersInfo, - surface->mBackbuffers[i].mTransitionCmdBuffers); - SkDEBUGCODE(res = ) mCreateFence(mBackendContext->fDevice, &fenceInfo, nullptr, - &surface->mBackbuffers[i].mUsageFences[0]); - SkDEBUGCODE(res = ) mCreateFence(mBackendContext->fDevice, &fenceInfo, nullptr, - &surface->mBackbuffers[i].mUsageFences[1]); + SkDEBUGCODE(res =) mCreateSemaphore(mBackendContext->fDevice, &semaphoreInfo, nullptr, + &surface->mBackbuffers[i].mAcquireSemaphore); + SkDEBUGCODE(res =) mCreateSemaphore(mBackendContext->fDevice, &semaphoreInfo, nullptr, + &surface->mBackbuffers[i].mRenderSemaphore); + SkDEBUGCODE(res =) mAllocateCommandBuffers(mBackendContext->fDevice, &commandBuffersInfo, + surface->mBackbuffers[i].mTransitionCmdBuffers); + SkDEBUGCODE(res =) mCreateFence(mBackendContext->fDevice, &fenceInfo, nullptr, + &surface->mBackbuffers[i].mUsageFences[0]); + SkDEBUGCODE(res =) mCreateFence(mBackendContext->fDevice, &fenceInfo, nullptr, + &surface->mBackbuffers[i].mUsageFences[1]); SkASSERT(VK_SUCCESS == res); } surface->mCurrentBackbufferIndex = surface->mImageCount; @@ -362,35 +369,36 @@ bool VulkanManager::createSwapchain(VulkanSurface* surface) { // check for capabilities VkSurfaceCapabilitiesKHR caps; VkResult res = mGetPhysicalDeviceSurfaceCapabilitiesKHR(mBackendContext->fPhysicalDevice, - surface->mVkSurface, &caps); + surface->mVkSurface, &caps); if (VK_SUCCESS != res) { return false; } uint32_t surfaceFormatCount; res = mGetPhysicalDeviceSurfaceFormatsKHR(mBackendContext->fPhysicalDevice, surface->mVkSurface, - &surfaceFormatCount, nullptr); + &surfaceFormatCount, nullptr); if (VK_SUCCESS != res) { return false; } FatVector<VkSurfaceFormatKHR, 4> surfaceFormats(surfaceFormatCount); res = mGetPhysicalDeviceSurfaceFormatsKHR(mBackendContext->fPhysicalDevice, surface->mVkSurface, - &surfaceFormatCount, surfaceFormats.data()); + &surfaceFormatCount, surfaceFormats.data()); if (VK_SUCCESS != res) { return false; } uint32_t presentModeCount; res = mGetPhysicalDeviceSurfacePresentModesKHR(mBackendContext->fPhysicalDevice, - surface->mVkSurface, &presentModeCount, nullptr); + surface->mVkSurface, &presentModeCount, nullptr); if (VK_SUCCESS != res) { return false; } FatVector<VkPresentModeKHR, VK_PRESENT_MODE_RANGE_SIZE_KHR> presentModes(presentModeCount); res = mGetPhysicalDeviceSurfacePresentModesKHR(mBackendContext->fPhysicalDevice, - surface->mVkSurface, &presentModeCount, presentModes.data()); + surface->mVkSurface, &presentModeCount, + presentModes.data()); if (VK_SUCCESS != res) { return false; } @@ -420,12 +428,12 @@ bool VulkanManager::createSwapchain(VulkanSurface* surface) { VK_IMAGE_USAGE_TRANSFER_DST_BIT; SkASSERT((caps.supportedUsageFlags & usageFlags) == usageFlags); SkASSERT(caps.supportedTransforms & caps.currentTransform); - SkASSERT(caps.supportedCompositeAlpha & (VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR | - VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)); + SkASSERT(caps.supportedCompositeAlpha & + (VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR | VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)); VkCompositeAlphaFlagBitsKHR composite_alpha = - (caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) ? - VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR : - VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + (caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) + ? VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR + : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; // Pick our surface format. For now, just make sure it matches our sRGB request: VkFormat surfaceFormat = VK_FORMAT_UNDEFINED; @@ -470,7 +478,7 @@ bool VulkanManager::createSwapchain(VulkanSurface* surface) { swapchainCreateInfo.imageArrayLayers = 1; swapchainCreateInfo.imageUsage = usageFlags; - uint32_t queueFamilies[] = { mBackendContext->fGraphicsQueueIndex, mPresentQueueIndex }; + uint32_t queueFamilies[] = {mBackendContext->fGraphicsQueueIndex, mPresentQueueIndex}; if (mBackendContext->fGraphicsQueueIndex != mPresentQueueIndex) { swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; swapchainCreateInfo.queueFamilyIndexCount = 2; @@ -488,7 +496,7 @@ bool VulkanManager::createSwapchain(VulkanSurface* surface) { swapchainCreateInfo.oldSwapchain = surface->mSwapchain; res = mCreateSwapchainKHR(mBackendContext->fDevice, &swapchainCreateInfo, nullptr, - &surface->mSwapchain); + &surface->mSwapchain); if (VK_SUCCESS != res) { return false; } @@ -507,7 +515,6 @@ bool VulkanManager::createSwapchain(VulkanSurface* surface) { return true; } - VulkanSurface* VulkanManager::createSurface(ANativeWindow* window) { initialize(); @@ -524,21 +531,20 @@ VulkanSurface* VulkanManager::createSurface(ANativeWindow* window) { surfaceCreateInfo.flags = 0; surfaceCreateInfo.window = window; - VkResult res = mCreateAndroidSurfaceKHR(mBackendContext->fInstance, &surfaceCreateInfo, - nullptr, &surface->mVkSurface); + VkResult res = mCreateAndroidSurfaceKHR(mBackendContext->fInstance, &surfaceCreateInfo, nullptr, + &surface->mVkSurface); if (VK_SUCCESS != res) { delete surface; return nullptr; } -SkDEBUGCODE( - VkBool32 supported; - res = mGetPhysicalDeviceSurfaceSupportKHR(mBackendContext->fPhysicalDevice, - mPresentQueueIndex, surface->mVkSurface, &supported); - // All physical devices and queue families on Android must be capable of presentation with any - // native window. - SkASSERT(VK_SUCCESS == res && supported); -); + SkDEBUGCODE(VkBool32 supported; res = mGetPhysicalDeviceSurfaceSupportKHR( + mBackendContext->fPhysicalDevice, mPresentQueueIndex, + surface->mVkSurface, &supported); + // All physical devices and queue families on Android must be capable of + // presentation with any + // native window. + SkASSERT(VK_SUCCESS == res && supported);); if (!createSwapchain(surface)) { destroySurface(surface); @@ -573,11 +579,9 @@ static VkAccessFlags layoutToSrcAccessMask(const VkImageLayout layout) { VkAccessFlags flags = 0; if (VK_IMAGE_LAYOUT_GENERAL == layout) { flags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | - VK_ACCESS_TRANSFER_WRITE_BIT | - VK_ACCESS_TRANSFER_READ_BIT | - VK_ACCESS_SHADER_READ_BIT | - VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_HOST_READ_BIT; + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT | + VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_HOST_WRITE_BIT | + VK_ACCESS_HOST_READ_BIT; } else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) { flags = VK_ACCESS_HOST_WRITE_BIT; } else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout) { @@ -600,12 +604,13 @@ void VulkanManager::swapBuffers(VulkanSurface* surface) { mDeviceWaitIdle(mBackendContext->fDevice); } - VulkanSurface::BackbufferInfo* backbuffer = surface->mBackbuffers + - surface->mCurrentBackbufferIndex; + SkASSERT(surface->mBackbuffers); + VulkanSurface::BackbufferInfo* backbuffer = + surface->mBackbuffers + surface->mCurrentBackbufferIndex; GrVkImageInfo* imageInfo; SkSurface* skSurface = surface->mImageInfos[backbuffer->mImageIndex].mSurface.get(); skSurface->getRenderTargetHandle((GrBackendObject*)&imageInfo, - SkSurface::kFlushRead_BackendHandleAccess); + SkSurface::kFlushRead_BackendHandleAccess); // Check to make sure we never change the actually wrapped image SkASSERT(imageInfo->fImage == surface->mImages[backbuffer->mImageIndex]); @@ -618,16 +623,16 @@ void VulkanManager::swapBuffers(VulkanSurface* surface) { VkAccessFlags dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; VkImageMemoryBarrier imageMemoryBarrier = { - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType - NULL, // pNext - srcAccessMask, // outputMask - dstAccessMask, // inputMask - layout, // oldLayout - VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // newLayout - mBackendContext->fGraphicsQueueIndex, // srcQueueFamilyIndex - mPresentQueueIndex, // dstQueueFamilyIndex - surface->mImages[backbuffer->mImageIndex], // image - { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } // subresourceRange + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType + NULL, // pNext + srcAccessMask, // outputMask + dstAccessMask, // inputMask + layout, // oldLayout + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // newLayout + mBackendContext->fGraphicsQueueIndex, // srcQueueFamilyIndex + mPresentQueueIndex, // dstQueueFamilyIndex + surface->mImages[backbuffer->mImageIndex], // image + {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1} // subresourceRange }; mResetCommandBuffer(backbuffer->mTransitionCmdBuffers[1], 0); @@ -636,8 +641,8 @@ void VulkanManager::swapBuffers(VulkanSurface* surface) { info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; info.flags = 0; mBeginCommandBuffer(backbuffer->mTransitionCmdBuffers[1], &info); - mCmdPipelineBarrier(backbuffer->mTransitionCmdBuffers[1], srcStageMask, dstStageMask, 0, - 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); + mCmdPipelineBarrier(backbuffer->mTransitionCmdBuffers[1], srcStageMask, dstStageMask, 0, 0, + nullptr, 0, nullptr, 1, &imageMemoryBarrier); mEndCommandBuffer(backbuffer->mTransitionCmdBuffers[1]); surface->mImageInfos[backbuffer->mImageIndex].mImageLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; @@ -661,16 +666,15 @@ void VulkanManager::swapBuffers(VulkanSurface* surface) { // Submit present operation to present queue. We use a semaphore here to make sure all rendering // to the image is complete and that the layout has been change to present on the graphics // queue. - const VkPresentInfoKHR presentInfo = - { - VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, // sType - NULL, // pNext - 1, // waitSemaphoreCount - &backbuffer->mRenderSemaphore, // pWaitSemaphores - 1, // swapchainCount - &surface->mSwapchain, // pSwapchains - &backbuffer->mImageIndex, // pImageIndices - NULL // pResults + const VkPresentInfoKHR presentInfo = { + VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, // sType + NULL, // pNext + 1, // waitSemaphoreCount + &backbuffer->mRenderSemaphore, // pWaitSemaphores + 1, // swapchainCount + &surface->mSwapchain, // pSwapchains + &backbuffer->mImageIndex, // pImageIndices + NULL // pResults }; mQueuePresentKHR(mPresentQueue, &presentInfo); @@ -682,10 +686,11 @@ void VulkanManager::swapBuffers(VulkanSurface* surface) { } int VulkanManager::getAge(VulkanSurface* surface) { - VulkanSurface::BackbufferInfo* backbuffer = surface->mBackbuffers + - surface->mCurrentBackbufferIndex; - if (mSwapBehavior == SwapBehavior::Discard - || surface->mImageInfos[backbuffer->mImageIndex].mInvalid) { + SkASSERT(surface->mBackbuffers); + VulkanSurface::BackbufferInfo* backbuffer = + surface->mBackbuffers + surface->mCurrentBackbufferIndex; + if (mSwapBehavior == SwapBehavior::Discard || + surface->mImageInfos[backbuffer->mImageIndex].mInvalid) { return 0; } uint16_t lastUsed = surface->mImageInfos[backbuffer->mImageIndex].mLastUsed; diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h index d225b3fc4ec0..c319c9ec209f 100644 --- a/libs/hwui/renderthread/VulkanManager.h +++ b/libs/hwui/renderthread/VulkanManager.h @@ -37,13 +37,14 @@ public: private: friend class VulkanManager; struct BackbufferInfo { - uint32_t mImageIndex; // image this is associated with - VkSemaphore mAcquireSemaphore; // we signal on this for acquisition of image - VkSemaphore mRenderSemaphore; // we wait on this for rendering to be done - VkCommandBuffer mTransitionCmdBuffers[2]; // to transition layout between present and render + uint32_t mImageIndex; // image this is associated with + VkSemaphore mAcquireSemaphore; // we signal on this for acquisition of image + VkSemaphore mRenderSemaphore; // we wait on this for rendering to be done + VkCommandBuffer + mTransitionCmdBuffers[2]; // to transition layout between present and render // We use these fences to make sure the above Command buffers have finished their work // before attempting to reuse them or destroy them. - VkFence mUsageFences[2]; + VkFence mUsageFences[2]; }; struct ImageInfo { @@ -58,11 +59,11 @@ private: VkSurfaceKHR mVkSurface = VK_NULL_HANDLE; VkSwapchainKHR mSwapchain = VK_NULL_HANDLE; - BackbufferInfo* mBackbuffers; + BackbufferInfo* mBackbuffers = nullptr; uint32_t mCurrentBackbufferIndex; uint32_t mImageCount; - VkImage* mImages; + VkImage* mImages = nullptr; ImageInfo* mImageInfos; uint16_t mCurrentTime = 0; }; @@ -118,11 +119,16 @@ private: VulkanSurface::BackbufferInfo* getAvailableBackbuffer(VulkanSurface* surface); // simple wrapper class that exists only to initialize a pointer to NULL - template <typename FNPTR_TYPE> class VkPtr { + template <typename FNPTR_TYPE> + class VkPtr { public: VkPtr() : fPtr(NULL) {} - VkPtr operator=(FNPTR_TYPE ptr) { fPtr = ptr; return *this; } + VkPtr operator=(FNPTR_TYPE ptr) { + fPtr = ptr; + return *this; + } operator FNPTR_TYPE() const { return fPtr; } + private: FNPTR_TYPE fPtr; }; @@ -183,4 +189,3 @@ private: } /* namespace android */ #endif /* VULKANMANAGER_H */ - |