From 5a4690bf26932c0d6940e4af8516d920e09ae81a Mon Sep 17 00:00:00 2001 From: Chris Craik Date: Tue, 14 Jul 2015 12:13:03 -0700 Subject: Clean up unncessary defines LOG_TAG and TRACE_TAG are already defined in the makefile Change-Id: I9e53e3dacbe018441edd74cb7c8c90846defee74 --- libs/hwui/GradientCache.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'libs/hwui/GradientCache.cpp') diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp index ea93e7f9716b..aa105f9fec0a 100644 --- a/libs/hwui/GradientCache.cpp +++ b/libs/hwui/GradientCache.cpp @@ -14,8 +14,6 @@ * limitations under the License. */ -#define LOG_TAG "OpenGLRenderer" - #include #include "Caches.h" -- cgit v1.2.3-59-g8ed1b From 6b50780363d3bb8db600c770183fa07677509ae8 Mon Sep 17 00:00:00 2001 From: John Reck Date: Tue, 3 Nov 2015 10:09:59 -0800 Subject: Remove almost-all android::Singleton users Bug: 25426213 Change-Id: I88e6206e8915cce95c3a8a8a82a4bb8fbf668141 --- libs/hwui/Caches.cpp | 1 + libs/hwui/Caches.h | 1 - libs/hwui/Extensions.cpp | 1 + libs/hwui/Extensions.h | 6 ------ libs/hwui/GradientCache.cpp | 2 ++ libs/hwui/PathCache.cpp | 2 ++ libs/hwui/Properties.cpp | 6 +++++- libs/hwui/Properties.h | 2 -- libs/hwui/RenderBufferCache.cpp | 6 ++++-- libs/hwui/renderthread/RenderProxy.cpp | 5 +---- libs/hwui/renderthread/RenderProxy.h | 3 --- libs/hwui/renderthread/RenderThread.cpp | 29 +++++++++++++++++++---------- libs/hwui/renderthread/RenderThread.h | 12 ++++++++---- 13 files changed, 43 insertions(+), 33 deletions(-) (limited to 'libs/hwui/GradientCache.cpp') diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp index 7c63e316ba38..94a11f131229 100644 --- a/libs/hwui/Caches.cpp +++ b/libs/hwui/Caches.cpp @@ -23,6 +23,7 @@ #include "ShadowTessellator.h" #include "utils/GLUtils.h" +#include #include #include diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h index 61e958d42148..330dc2951ec9 100644 --- a/libs/hwui/Caches.h +++ b/libs/hwui/Caches.h @@ -43,7 +43,6 @@ #include #include -#include #include diff --git a/libs/hwui/Extensions.cpp b/libs/hwui/Extensions.cpp index 06c8a21b019b..6dd29ad8c703 100644 --- a/libs/hwui/Extensions.cpp +++ b/libs/hwui/Extensions.cpp @@ -20,6 +20,7 @@ #include "Properties.h" #include "utils/StringUtils.h" +#include #include #include diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h index 0a30d162f2e8..6689b88f17e3 100644 --- a/libs/hwui/Extensions.h +++ b/libs/hwui/Extensions.h @@ -19,12 +19,6 @@ #include -#include -#include -#include - -#include - namespace android { namespace uirenderer { diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp index aa105f9fec0a..8c4645092c97 100644 --- a/libs/hwui/GradientCache.cpp +++ b/libs/hwui/GradientCache.cpp @@ -21,6 +21,8 @@ #include "GradientCache.h" #include "Properties.h" +#include + namespace android { namespace uirenderer { diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp index 4031f2e13f39..fd9ab1847f0d 100644 --- a/libs/hwui/PathCache.cpp +++ b/libs/hwui/PathCache.cpp @@ -30,6 +30,8 @@ #include "thread/Signal.h" #include "thread/TaskProcessor.h" +#include + namespace android { namespace uirenderer { diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp index c0c61db0f5d1..e81818679f3e 100644 --- a/libs/hwui/Properties.cpp +++ b/libs/hwui/Properties.cpp @@ -17,8 +17,12 @@ #include "Debug.h" -#include +#include #include +#include + +#include +#include namespace android { namespace uirenderer { diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index 74cd74bde176..1293c786a0bd 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -18,8 +18,6 @@ #define ANDROID_HWUI_PROPERTIES_H #include -#include -#include /** * This file contains the list of system properties used to configure diff --git a/libs/hwui/RenderBufferCache.cpp b/libs/hwui/RenderBufferCache.cpp index 8beed2540e1c..11d7a6af3a6a 100644 --- a/libs/hwui/RenderBufferCache.cpp +++ b/libs/hwui/RenderBufferCache.cpp @@ -14,12 +14,14 @@ * limitations under the License. */ -#include - #include "Debug.h" #include "Properties.h" #include "RenderBufferCache.h" +#include + +#include + namespace android { namespace uirenderer { diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 15ccd6ac5b6b..a1107f029691 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -563,10 +563,7 @@ void RenderProxy::post(RenderTask* task) { void* RenderProxy::postAndWait(MethodInvokeRenderTask* task) { void* retval; task->setReturnPtr(&retval); - SignalingRenderTask syncTask(task, &mSyncMutex, &mSyncCondition); - AutoMutex _lock(mSyncMutex); - mRenderThread.queue(&syncTask); - mSyncCondition.wait(mSyncMutex); + mRenderThread.queueAndWait(task); return retval; } diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index 338fab650876..d0e601e09be6 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -117,9 +117,6 @@ private: DrawFrameTask mDrawFrameTask; - Mutex mSyncMutex; - Condition mSyncCondition; - void destroyContext(); void post(RenderTask* task); diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp index 8fcd10967e17..526a84861d98 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -28,9 +28,6 @@ #include namespace android { -using namespace uirenderer::renderthread; -ANDROID_SINGLETON_STATIC_INSTANCE(RenderThread); - namespace uirenderer { namespace renderthread { @@ -136,7 +133,22 @@ public: } }; -RenderThread::RenderThread() : Thread(true), Singleton() +static bool gHasRenderThreadInstance = false; + +bool RenderThread::hasInstance() { + return gHasRenderThreadInstance; +} + +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 + // because we don't want to delete the RenderThread normally. + static RenderThread* sInstance = new RenderThread(); + gHasRenderThreadInstance = true; + return *sInstance; +} + +RenderThread::RenderThread() : Thread(true) , mNextWakeup(LLONG_MAX) , mDisplayEventReceiver(nullptr) , mVsyncRequested(false) @@ -313,13 +325,10 @@ void RenderThread::queue(RenderTask* task) { } void RenderThread::queueAndWait(RenderTask* task) { - Mutex mutex; - Condition condition; - SignalingRenderTask syncTask(task, &mutex, &condition); - - AutoMutex _lock(mutex); + SignalingRenderTask syncTask(task, &mSyncMutex, &mSyncCondition); + AutoMutex _lock(mSyncMutex); queue(&syncTask); - condition.wait(mutex); + mSyncCondition.wait(mSyncMutex); } void RenderThread::queueAtFront(RenderTask* task) { diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h index f3444a85a336..d8c7e61f34eb 100644 --- a/libs/hwui/renderthread/RenderThread.h +++ b/libs/hwui/renderthread/RenderThread.h @@ -25,11 +25,11 @@ #include #include #include -#include -#include #include +#include #include +#include #include namespace android { @@ -72,7 +72,7 @@ protected: ~IFrameCallback() {} }; -class ANDROID_API RenderThread : public Thread, protected Singleton { +class ANDROID_API RenderThread : public Thread { public: // RenderThread takes complete ownership of tasks that are queued // and will delete them after they are run @@ -100,7 +100,6 @@ protected: virtual bool threadLoop() override; private: - friend class Singleton; friend class DispatchFrameCallbacks; friend class RenderProxy; friend class android::uirenderer::TestUtils; @@ -108,6 +107,9 @@ private: RenderThread(); virtual ~RenderThread(); + static bool hasInstance(); + static RenderThread& getInstance(); + void initThreadLocals(); void initializeDisplayEventReceiver(); static int displayEventReceiverCallback(int fd, int events, void* data); @@ -125,6 +127,8 @@ private: nsecs_t mNextWakeup; TaskQueue mQueue; + Mutex mSyncMutex; + Condition mSyncCondition; DisplayInfo mDisplayInfo; -- cgit v1.2.3-59-g8ed1b From 38e0c32852e3b9d8ca4a9d3791577f52536419cb Mon Sep 17 00:00:00 2001 From: John Reck Date: Tue, 10 Nov 2015 12:19:17 -0800 Subject: Track texture memory globally Also mostly consolidates texture creation Change-Id: Ifea01303afda531dcec99b8fe2a0f64cf2f24420 --- libs/hwui/Android.mk | 2 + libs/hwui/AssetAtlas.cpp | 57 +++--- libs/hwui/AssetAtlas.h | 31 ++-- libs/hwui/BakedOpDispatcher.cpp | 14 +- libs/hwui/BakedOpRenderer.cpp | 6 +- libs/hwui/GpuMemoryTracker.cpp | 140 +++++++++++++++ libs/hwui/GpuMemoryTracker.h | 76 ++++++++ libs/hwui/GradientCache.cpp | 24 +-- libs/hwui/GradientCache.h | 3 +- libs/hwui/Layer.cpp | 35 ++-- libs/hwui/Layer.h | 17 +- libs/hwui/LayerCache.cpp | 1 - libs/hwui/OpenGLRenderer.cpp | 18 +- libs/hwui/PathCache.cpp | 33 +--- libs/hwui/PathCache.h | 4 +- libs/hwui/SkiaShader.cpp | 6 +- libs/hwui/TextDropShadowCache.cpp | 9 +- libs/hwui/Texture.cpp | 208 +++++++++++++++++++++- libs/hwui/Texture.h | 85 +++++++-- libs/hwui/TextureCache.cpp | 9 +- libs/hwui/TextureCache.h | 1 + libs/hwui/font/CacheTexture.cpp | 28 +-- libs/hwui/font/CacheTexture.h | 7 +- libs/hwui/renderstate/OffscreenBufferPool.cpp | 31 ++-- libs/hwui/renderstate/OffscreenBufferPool.h | 10 +- libs/hwui/renderstate/RenderState.cpp | 8 +- libs/hwui/renderstate/TextureState.cpp | 128 ------------- libs/hwui/renderstate/TextureState.h | 7 - libs/hwui/renderthread/CanvasContext.cpp | 3 + libs/hwui/tests/common/TestUtils.h | 4 + libs/hwui/tests/macrobench/main.cpp | 1 + libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp | 70 ++++++++ libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp | 12 +- libs/hwui/tests/unit/StringUtilsTests.cpp | 15 ++ libs/hwui/utils/StringUtils.h | 17 ++ 35 files changed, 743 insertions(+), 377 deletions(-) create mode 100644 libs/hwui/GpuMemoryTracker.cpp create mode 100644 libs/hwui/GpuMemoryTracker.h create mode 100644 libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp (limited to 'libs/hwui/GradientCache.cpp') diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index bbfc0221666c..cdd891fa5644 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -53,6 +53,7 @@ hwui_src_files := \ FrameInfoVisualizer.cpp \ GammaFontRenderer.cpp \ GlopBuilder.cpp \ + GpuMemoryTracker.cpp \ GradientCache.cpp \ Image.cpp \ Interpolator.cpp \ @@ -228,6 +229,7 @@ LOCAL_SRC_FILES += \ tests/unit/DamageAccumulatorTests.cpp \ tests/unit/DeviceInfoTests.cpp \ tests/unit/FatVectorTests.cpp \ + tests/unit/GpuMemoryTrackerTests.cpp \ tests/unit/LayerUpdateQueueTests.cpp \ tests/unit/LinearAllocatorTests.cpp \ tests/unit/VectorDrawableTests.cpp \ diff --git a/libs/hwui/AssetAtlas.cpp b/libs/hwui/AssetAtlas.cpp index 41411a98a4bf..6afff1b7158e 100644 --- a/libs/hwui/AssetAtlas.cpp +++ b/libs/hwui/AssetAtlas.cpp @@ -39,40 +39,22 @@ void AssetAtlas::init(sp buffer, int64_t* map, int count) { if (!mTexture) { Caches& caches = Caches::getInstance(); mTexture = new Texture(caches); - mTexture->width = buffer->getWidth(); - mTexture->height = buffer->getHeight(); + mTexture->wrap(mImage->getTexture(), + buffer->getWidth(), buffer->getHeight(), GL_RGBA); createEntries(caches, map, count); } } else { ALOGW("Could not create atlas image"); - delete mImage; - mImage = nullptr; + terminate(); } - - updateTextureId(); } void AssetAtlas::terminate() { - if (mImage) { - delete mImage; - mImage = nullptr; - updateTextureId(); - } -} - - -void AssetAtlas::updateTextureId() { - mTexture->id = mImage ? mImage->getTexture() : 0; - if (mTexture->id) { - // Texture ID changed, force-set to defaults to sync the wrapper & GL - // state objects - mTexture->setWrap(GL_CLAMP_TO_EDGE, false, true); - mTexture->setFilter(GL_NEAREST, false, true); - } - for (size_t i = 0; i < mEntries.size(); i++) { - AssetAtlas::Entry* entry = mEntries.valueAt(i); - entry->texture->id = mTexture->id; - } + delete mImage; + mImage = nullptr; + delete mTexture; + mTexture = nullptr; + mEntries.clear(); } /////////////////////////////////////////////////////////////////////////////// @@ -80,13 +62,13 @@ void AssetAtlas::updateTextureId() { /////////////////////////////////////////////////////////////////////////////// AssetAtlas::Entry* AssetAtlas::getEntry(const SkPixelRef* pixelRef) const { - ssize_t index = mEntries.indexOfKey(pixelRef); - return index >= 0 ? mEntries.valueAt(index) : nullptr; + auto result = mEntries.find(pixelRef); + return result != mEntries.end() ? result->second.get() : nullptr; } Texture* AssetAtlas::getEntryTexture(const SkPixelRef* pixelRef) const { - ssize_t index = mEntries.indexOfKey(pixelRef); - return index >= 0 ? mEntries.valueAt(index)->texture : nullptr; + auto result = mEntries.find(pixelRef); + return result != mEntries.end() ? result->second->texture : nullptr; } /** @@ -94,7 +76,8 @@ Texture* AssetAtlas::getEntryTexture(const SkPixelRef* pixelRef) const { * instead of applying the changes to the virtual textures. */ struct DelegateTexture: public Texture { - DelegateTexture(Caches& caches, Texture* delegate): Texture(caches), mDelegate(delegate) { } + DelegateTexture(Caches& caches, Texture* delegate) + : Texture(caches), mDelegate(delegate) { } virtual void setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture = false, bool force = false, GLenum renderTarget = GL_TEXTURE_2D) override { @@ -111,8 +94,8 @@ private: }; // struct DelegateTexture void AssetAtlas::createEntries(Caches& caches, int64_t* map, int count) { - const float width = float(mTexture->width); - const float height = float(mTexture->height); + const float width = float(mTexture->width()); + const float height = float(mTexture->height()); for (int i = 0; i < count; ) { SkPixelRef* pixelRef = reinterpret_cast(map[i++]); @@ -133,13 +116,13 @@ void AssetAtlas::createEntries(Caches& caches, int64_t* map, int count) { Texture* texture = new DelegateTexture(caches, mTexture); texture->blend = !SkAlphaTypeIsOpaque(pixelRef->info().alphaType()); - texture->width = pixelRef->info().width(); - texture->height = pixelRef->info().height(); + texture->wrap(mTexture->id(), pixelRef->info().width(), + pixelRef->info().height(), mTexture->format()); - Entry* entry = new Entry(pixelRef, texture, mapper, *this); + std::unique_ptr entry(new Entry(pixelRef, texture, mapper, *this)); texture->uvMapper = &entry->uvMapper; - mEntries.add(entry->pixelRef, entry); + mEntries.emplace(entry->pixelRef, std::move(entry)); } } diff --git a/libs/hwui/AssetAtlas.h b/libs/hwui/AssetAtlas.h index a037725b1c6c..75400ff494c3 100644 --- a/libs/hwui/AssetAtlas.h +++ b/libs/hwui/AssetAtlas.h @@ -17,18 +17,16 @@ #ifndef ANDROID_HWUI_ASSET_ATLAS_H #define ANDROID_HWUI_ASSET_ATLAS_H -#include - -#include - -#include +#include "Texture.h" +#include "UvMapper.h" #include - +#include +#include #include -#include "Texture.h" -#include "UvMapper.h" +#include +#include namespace android { namespace uirenderer { @@ -71,6 +69,10 @@ public: return texture->blend ? &atlas.mBlendKey : &atlas.mOpaqueKey; } + ~Entry() { + delete texture; + } + private: /** * The pixel ref that generated this atlas entry. @@ -90,10 +92,6 @@ public: , atlas(atlas) { } - ~Entry() { - delete texture; - } - friend class AssetAtlas; }; @@ -127,7 +125,7 @@ public: * Can return 0 if the atlas is not initialized. */ uint32_t getWidth() const { - return mTexture ? mTexture->width : 0; + return mTexture ? mTexture->width() : 0; } /** @@ -135,7 +133,7 @@ public: * Can return 0 if the atlas is not initialized. */ uint32_t getHeight() const { - return mTexture ? mTexture->height : 0; + return mTexture ? mTexture->height() : 0; } /** @@ -143,7 +141,7 @@ public: * Can return 0 if the atlas is not initialized. */ GLuint getTexture() const { - return mTexture ? mTexture->id : 0; + return mTexture ? mTexture->id() : 0; } /** @@ -160,7 +158,6 @@ public: private: void createEntries(Caches& caches, int64_t* map, int count); - void updateTextureId(); Texture* mTexture; Image* mImage; @@ -168,7 +165,7 @@ private: const bool mBlendKey; const bool mOpaqueKey; - KeyedVector mEntries; + std::unordered_map> mEntries; }; // class AssetAtlas }; // namespace uirenderer diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp index 5b34f6b79199..6b0c1499336f 100644 --- a/libs/hwui/BakedOpDispatcher.cpp +++ b/libs/hwui/BakedOpDispatcher.cpp @@ -217,7 +217,7 @@ static void renderTextShadow(BakedOpRenderer& renderer, FontRenderer& fontRender .setMeshTexturedUnitQuad(nullptr) .setFillShadowTexturePaint(*texture, textShadow.color, *op.paint, state.alpha) .setTransform(state.computedState.transform, TransformFlags::None) - .setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width, sy + texture->height)) + .setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width(), sy + texture->height())) .build(); renderer.renderGlop(state, glop); } @@ -337,7 +337,7 @@ static void renderConvexPath(BakedOpRenderer& renderer, const BakedOpState& stat static void renderPathTexture(BakedOpRenderer& renderer, const BakedOpState& state, PathTexture& texture, const RecordedOp& op) { - Rect dest(texture.width, texture.height); + Rect dest(texture.width(), texture.height()); dest.translate(texture.left - texture.offset, texture.top - texture.offset); Glop glop; @@ -399,7 +399,7 @@ void BakedOpDispatcher::onBitmapOp(BakedOpRenderer& renderer, const BitmapOp& op .setMeshTexturedUnitQuad(texture->uvMapper) .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha) .setTransform(state.computedState.transform, TransformFlags::None) - .setModelViewMapUnitToRectSnap(Rect(texture->width, texture->height)) + .setModelViewMapUnitToRectSnap(Rect(texture->width(), texture->height())) .build(); renderer.renderGlop(state, glop); } @@ -483,10 +483,10 @@ void BakedOpDispatcher::onBitmapRectOp(BakedOpRenderer& renderer, const BitmapRe if (!texture) return; const AutoTexture autoCleanup(texture); - Rect uv(std::max(0.0f, op.src.left / texture->width), - std::max(0.0f, op.src.top / texture->height), - std::min(1.0f, op.src.right / texture->width), - std::min(1.0f, op.src.bottom / texture->height)); + Rect uv(std::max(0.0f, op.src.left / texture->width()), + std::max(0.0f, op.src.top / texture->height()), + std::min(1.0f, op.src.right / texture->width()), + std::min(1.0f, op.src.bottom / texture->height())); const int textureFillFlags = (op.bitmap->colorType() == kAlpha_8_SkColorType) ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None; diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp index 42fb66fe9845..4fbff0d107ba 100644 --- a/libs/hwui/BakedOpRenderer.cpp +++ b/libs/hwui/BakedOpRenderer.cpp @@ -48,7 +48,7 @@ void BakedOpRenderer::startRepaintLayer(OffscreenBuffer* offscreenBuffer, const // attach the texture to the FBO glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - offscreenBuffer->texture.id, 0); + offscreenBuffer->texture.id(), 0); LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "startLayer FAILED"); LOG_ALWAYS_FATAL_IF(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE, "framebuffer incomplete!"); @@ -84,7 +84,7 @@ OffscreenBuffer* BakedOpRenderer::copyToLayer(const Rect& area) { area.getWidth(), area.getHeight()); if (!area.isEmpty()) { mCaches.textureState().activateTexture(0); - mCaches.textureState().bindTexture(buffer->texture.id); + mCaches.textureState().bindTexture(buffer->texture.id()); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, area.left, mRenderTarget.viewportHeight - area.bottom, @@ -272,7 +272,7 @@ void BakedOpRenderer::prepareRender(const Rect* dirtyBounds, const ClipBase* cli OffscreenBuffer* layer = mRenderTarget.offscreenBuffer; mRenderTarget.stencil = mCaches.renderBufferCache.get( Stencil::getLayerStencilFormat(), - layer->texture.width, layer->texture.height); + layer->texture.width(), layer->texture.height()); // stencil is bound + allocated - associate it with current FBO glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, mRenderTarget.stencil->getName()); diff --git a/libs/hwui/GpuMemoryTracker.cpp b/libs/hwui/GpuMemoryTracker.cpp new file mode 100644 index 000000000000..4fb57019264d --- /dev/null +++ b/libs/hwui/GpuMemoryTracker.cpp @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "utils/StringUtils.h" +#include "Texture.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace android { +namespace uirenderer { + +pthread_t gGpuThread = 0; + +#define NUM_TYPES static_cast(GpuObjectType::TypeCount) + +const char* TYPE_NAMES[] = { + "Texture", + "OffscreenBuffer", + "Layer", +}; + +struct TypeStats { + int totalSize = 0; + int count = 0; +}; + +static std::array gObjectStats; +static std::unordered_set gObjectSet; + +void GpuMemoryTracker::notifySizeChanged(int newSize) { + int delta = newSize - mSize; + mSize = newSize; + gObjectStats[static_cast(mType)].totalSize += delta; +} + +void GpuMemoryTracker::startTrackingObject() { + auto result = gObjectSet.insert(this); + LOG_ALWAYS_FATAL_IF(!result.second, + "startTrackingObject() on %p failed, already being tracked!", this); + gObjectStats[static_cast(mType)].count++; +} + +void GpuMemoryTracker::stopTrackingObject() { + size_t removed = gObjectSet.erase(this); + LOG_ALWAYS_FATAL_IF(removed != 1, + "stopTrackingObject removed %zd, is %p not being tracked?", + removed, this); + gObjectStats[static_cast(mType)].count--; +} + +void GpuMemoryTracker::onGLContextCreated() { + LOG_ALWAYS_FATAL_IF(gGpuThread != 0, "We already have a GL thread? " + "current = %lu, gl thread = %lu", pthread_self(), gGpuThread); + gGpuThread = pthread_self(); +} + +void GpuMemoryTracker::onGLContextDestroyed() { + gGpuThread = 0; + if (CC_UNLIKELY(gObjectSet.size() > 0)) { + std::stringstream os; + dump(os); + ALOGE("%s", os.str().c_str()); + LOG_ALWAYS_FATAL("Leaked %zd GPU objects!", gObjectSet.size()); + } +} + +void GpuMemoryTracker::dump() { + std::stringstream strout; + dump(strout); + ALOGD("%s", strout.str().c_str()); +} + +void GpuMemoryTracker::dump(std::ostream& stream) { + for (int type = 0; type < NUM_TYPES; type++) { + const TypeStats& stats = gObjectStats[type]; + stream << TYPE_NAMES[type]; + stream << " is using " << SizePrinter{stats.totalSize}; + stream << ", count = " << stats.count; + stream << std::endl; + } +} + +int GpuMemoryTracker::getInstanceCount(GpuObjectType type) { + return gObjectStats[static_cast(type)].count; +} + +int GpuMemoryTracker::getTotalSize(GpuObjectType type) { + return gObjectStats[static_cast(type)].totalSize; +} + +void GpuMemoryTracker::onFrameCompleted() { + if (ATRACE_ENABLED()) { + char buf[128]; + for (int type = 0; type < NUM_TYPES; type++) { + snprintf(buf, 128, "hwui_%s", TYPE_NAMES[type]); + const TypeStats& stats = gObjectStats[type]; + ATRACE_INT(buf, stats.totalSize); + snprintf(buf, 128, "hwui_%s_count", TYPE_NAMES[type]); + ATRACE_INT(buf, stats.count); + } + } + + std::vector freeList; + for (const auto& obj : gObjectSet) { + if (obj->objectType() == GpuObjectType::Texture) { + const Texture* texture = static_cast(obj); + if (texture->cleanup) { + ALOGE("Leaked texture marked for cleanup! id=%u, size %ux%u", + texture->id(), texture->width(), texture->height()); + freeList.push_back(texture); + } + } + } + for (auto& texture : freeList) { + const_cast(texture)->deleteTexture(); + delete texture; + } +} + +} // namespace uirenderer +} // namespace android; diff --git a/libs/hwui/GpuMemoryTracker.h b/libs/hwui/GpuMemoryTracker.h new file mode 100644 index 000000000000..851aeae8352c --- /dev/null +++ b/libs/hwui/GpuMemoryTracker.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include +#include +#include + +namespace android { +namespace uirenderer { + +extern pthread_t gGpuThread; + +#define ASSERT_GPU_THREAD() LOG_ALWAYS_FATAL_IF( \ + !pthread_equal(gGpuThread, pthread_self()), \ + "Error, %p of type %d (size=%d) used on wrong thread! cur thread %lu " \ + "!= gpu thread %lu", this, static_cast(mType), mSize, \ + pthread_self(), gGpuThread) + +enum class GpuObjectType { + Texture = 0, + OffscreenBuffer, + Layer, + + TypeCount, +}; + +class GpuMemoryTracker { +public: + GpuObjectType objectType() { return mType; } + int objectSize() { return mSize; } + + static void onGLContextCreated(); + static void onGLContextDestroyed(); + static void dump(); + static void dump(std::ostream& stream); + static int getInstanceCount(GpuObjectType type); + static int getTotalSize(GpuObjectType type); + static void onFrameCompleted(); + +protected: + GpuMemoryTracker(GpuObjectType type) : mType(type) { + ASSERT_GPU_THREAD(); + startTrackingObject(); + } + + ~GpuMemoryTracker() { + notifySizeChanged(0); + stopTrackingObject(); + } + + void notifySizeChanged(int newSize); + +private: + void startTrackingObject(); + void stopTrackingObject(); + + int mSize = 0; + GpuObjectType mType; +}; + +} // namespace uirenderer +} // namespace android; diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp index 8c4645092c97..522aa96132dd 100644 --- a/libs/hwui/GradientCache.cpp +++ b/libs/hwui/GradientCache.cpp @@ -110,9 +110,7 @@ void GradientCache::setMaxSize(uint32_t maxSize) { void GradientCache::operator()(GradientCacheEntry&, Texture*& texture) { if (texture) { - const uint32_t size = texture->width * texture->height * bytesPerPixel(); - mSize -= size; - + mSize -= texture->objectSize(); texture->deleteTexture(); delete texture; } @@ -167,18 +165,16 @@ Texture* GradientCache::addLinearGradient(GradientCacheEntry& gradient, getGradientInfo(colors, count, info); Texture* texture = new Texture(Caches::getInstance()); - texture->width = info.width; - texture->height = 2; texture->blend = info.hasAlpha; texture->generation = 1; // Asume the cache is always big enough - const uint32_t size = texture->width * texture->height * bytesPerPixel(); + const uint32_t size = info.width * 2 * bytesPerPixel(); while (getSize() + size > mMaxSize) { mCache.removeOldest(); } - generateTexture(colors, positions, texture); + generateTexture(colors, positions, info.width, 2, texture); mSize += size; mCache.put(gradient, texture); @@ -231,10 +227,10 @@ void GradientCache::mixFloats(GradientColor& start, GradientColor& end, float am dst += 4 * sizeof(float); } -void GradientCache::generateTexture(uint32_t* colors, float* positions, Texture* texture) { - const uint32_t width = texture->width; +void GradientCache::generateTexture(uint32_t* colors, float* positions, + const uint32_t width, const uint32_t height, Texture* texture) { const GLsizei rowBytes = width * bytesPerPixel(); - uint8_t pixels[rowBytes * texture->height]; + uint8_t pixels[rowBytes * height]; static ChannelSplitter gSplitters[] = { &android::uirenderer::GradientCache::splitToBytes, @@ -277,17 +273,13 @@ void GradientCache::generateTexture(uint32_t* colors, float* positions, Texture* memcpy(pixels + rowBytes, pixels, rowBytes); - glGenTextures(1, &texture->id); - Caches::getInstance().textureState().bindTexture(texture->id); glPixelStorei(GL_UNPACK_ALIGNMENT, 4); if (mUseFloatTexture) { // We have to use GL_RGBA16F because GL_RGBA32F does not support filtering - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, texture->height, 0, - GL_RGBA, GL_FLOAT, pixels); + texture->upload(width, height, GL_RGBA16F, GL_RGBA, GL_FLOAT, pixels); } else { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, texture->height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, pixels); + texture->upload(width, height, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, pixels); } texture->setFilter(GL_LINEAR); diff --git a/libs/hwui/GradientCache.h b/libs/hwui/GradientCache.h index 7534c5d11164..b762ca7d5e5c 100644 --- a/libs/hwui/GradientCache.h +++ b/libs/hwui/GradientCache.h @@ -143,7 +143,8 @@ private: Texture* addLinearGradient(GradientCacheEntry& gradient, uint32_t* colors, float* positions, int count); - void generateTexture(uint32_t* colors, float* positions, Texture* texture); + void generateTexture(uint32_t* colors, float* positions, + const uint32_t width, const uint32_t height, Texture* texture); struct GradientInfo { uint32_t width; diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp index 0fe20ad1b662..7a74b9825d80 100644 --- a/libs/hwui/Layer.cpp +++ b/libs/hwui/Layer.cpp @@ -36,7 +36,8 @@ namespace android { namespace uirenderer { Layer::Layer(Type layerType, RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight) - : state(State::Uncached) + : GpuMemoryTracker(GpuObjectType::Layer) + , state(State::Uncached) , caches(Caches::getInstance()) , renderState(renderState) , texture(caches) @@ -45,8 +46,8 @@ Layer::Layer(Type layerType, RenderState& renderState, uint32_t layerWidth, uint // preserves the old inc/dec ref locations. This should be changed... incStrong(nullptr); renderTarget = GL_TEXTURE_2D; - texture.width = layerWidth; - texture.height = layerHeight; + texture.mWidth = layerWidth; + texture.mHeight = layerHeight; renderState.registerLayer(this); } @@ -54,10 +55,10 @@ Layer::~Layer() { renderState.unregisterLayer(this); SkSafeUnref(colorFilter); - if (stencil || fbo || texture.id) { + if (stencil || fbo || texture.mId) { renderState.requireGLContext(); removeFbo(); - deleteTexture(); + texture.deleteTexture(); } delete[] mesh; @@ -65,7 +66,7 @@ Layer::~Layer() { void Layer::onGlContextLost() { removeFbo(); - deleteTexture(); + texture.deleteTexture(); } uint32_t Layer::computeIdealWidth(uint32_t layerWidth) { @@ -179,8 +180,8 @@ void Layer::setColorFilter(SkColorFilter* filter) { } void Layer::bindTexture() const { - if (texture.id) { - caches.textureState().bindTexture(renderTarget, texture.id); + if (texture.mId) { + caches.textureState().bindTexture(renderTarget, texture.mId); } } @@ -191,28 +192,22 @@ void Layer::bindStencilRenderBuffer() const { } void Layer::generateTexture() { - if (!texture.id) { - glGenTextures(1, &texture.id); - } -} - -void Layer::deleteTexture() { - if (texture.id) { - texture.deleteTexture(); - texture.id = 0; + if (!texture.mId) { + glGenTextures(1, &texture.mId); } } void Layer::clearTexture() { - caches.textureState().unbindTexture(texture.id); - texture.id = 0; + caches.textureState().unbindTexture(texture.mId); + texture.mId = 0; } void Layer::allocateTexture() { #if DEBUG_LAYERS ALOGD(" Allocate layer: %dx%d", getWidth(), getHeight()); #endif - if (texture.id) { + if (texture.mId) { + texture.updateSize(getWidth(), getHeight(), GL_RGBA); glPixelStorei(GL_UNPACK_ALIGNMENT, 4); glTexImage2D(renderTarget, 0, GL_RGBA, getWidth(), getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index e90f055b667b..e00ae66997a5 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -24,6 +24,7 @@ #include #include +#include #include @@ -54,7 +55,7 @@ struct DeferStateStruct; /** * A layer has dimensions and is backed by an OpenGL texture or FBO. */ -class Layer : public VirtualLightRefBase { +class Layer : public VirtualLightRefBase, GpuMemoryTracker { public: enum class Type { Texture, @@ -94,8 +95,8 @@ public: regionRect.set(bounds.leftTop().x, bounds.leftTop().y, bounds.rightBottom().x, bounds.rightBottom().y); - const float texX = 1.0f / float(texture.width); - const float texY = 1.0f / float(texture.height); + const float texX = 1.0f / float(texture.mWidth); + const float texY = 1.0f / float(texture.mHeight); const float height = layer.getHeight(); texCoords.set( regionRect.left * texX, (height - regionRect.top) * texY, @@ -112,11 +113,11 @@ public: void updateDeferred(RenderNode* renderNode, int left, int top, int right, int bottom); inline uint32_t getWidth() const { - return texture.width; + return texture.mWidth; } inline uint32_t getHeight() const { - return texture.height; + return texture.mHeight; } /** @@ -131,8 +132,7 @@ public: bool resize(const uint32_t width, const uint32_t height); void setSize(uint32_t width, uint32_t height) { - texture.width = width; - texture.height = height; + texture.updateSize(width, height, texture.format()); } ANDROID_API void setPaint(const SkPaint* paint); @@ -201,7 +201,7 @@ public: } inline GLuint getTextureId() const { - return texture.id; + return texture.id(); } inline Texture& getTexture() { @@ -263,7 +263,6 @@ public: void bindTexture() const; void generateTexture(); void allocateTexture(); - void deleteTexture(); /** * When the caller frees the texture itself, the caller diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp index b117754347ed..f5681ce712d5 100644 --- a/libs/hwui/LayerCache.cpp +++ b/libs/hwui/LayerCache.cpp @@ -112,7 +112,6 @@ Layer* LayerCache::get(RenderState& renderState, const uint32_t width, const uin layer->bindTexture(); layer->setFilter(GL_NEAREST); layer->setWrap(GL_CLAMP_TO_EDGE, false); - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); #if DEBUG_LAYERS dump(); diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 92b758de8200..0cd763df78d1 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include #include "OpenGLRenderer.h" #include "DeferredDisplayList.h" @@ -200,6 +201,7 @@ bool OpenGLRenderer::finish() { #if DEBUG_MEMORY_USAGE mCaches.dumpMemoryUsage(); + GPUMemoryTracker::dump(); #else if (Properties::debugLevel & kDebugMemory) { mCaches.dumpMemoryUsage(); @@ -1497,7 +1499,7 @@ void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) { .setMeshTexturedUnitQuad(texture->uvMapper) .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha) .setTransform(*currentSnapshot(), TransformFlags::None) - .setModelViewMapUnitToRectSnap(Rect(texture->width, texture->height)) + .setModelViewMapUnitToRectSnap(Rect(texture->width(), texture->height())) .build(); renderGlop(glop); } @@ -1601,10 +1603,10 @@ void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, Rect src, Rect dst, cons if (!texture) return; const AutoTexture autoCleanup(texture); - Rect uv(std::max(0.0f, src.left / texture->width), - std::max(0.0f, src.top / texture->height), - std::min(1.0f, src.right / texture->width), - std::min(1.0f, src.bottom / texture->height)); + Rect uv(std::max(0.0f, src.left / texture->width()), + std::max(0.0f, src.top / texture->height()), + std::min(1.0f, src.right / texture->width()), + std::min(1.0f, src.bottom / texture->height())); const int textureFillFlags = (bitmap->colorType() == kAlpha_8_SkColorType) ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None; @@ -1977,7 +1979,7 @@ void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text, .setMeshTexturedUnitQuad(nullptr) .setFillShadowTexturePaint(*texture, textShadow.color, *paint, currentSnapshot()->alpha) .setTransform(*currentSnapshot(), TransformFlags::None) - .setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width, sy + texture->height)) + .setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width(), sy + texture->height())) .build(); renderGlop(glop); } @@ -2316,7 +2318,7 @@ Texture* OpenGLRenderer::getTexture(const SkBitmap* bitmap) { void OpenGLRenderer::drawPathTexture(PathTexture* texture, float x, float y, const SkPaint* paint) { - if (quickRejectSetupScissor(x, y, x + texture->width, y + texture->height)) { + if (quickRejectSetupScissor(x, y, x + texture->width(), y + texture->height())) { return; } @@ -2326,7 +2328,7 @@ void OpenGLRenderer::drawPathTexture(PathTexture* texture, float x, float y, .setMeshTexturedUnitQuad(nullptr) .setFillPathTexturePaint(*texture, *paint, currentSnapshot()->alpha) .setTransform(*currentSnapshot(), TransformFlags::None) - .setModelViewMapUnitToRect(Rect(x, y, x + texture->width, y + texture->height)) + .setModelViewMapUnitToRect(Rect(x, y, x + texture->width(), y + texture->height())) .build(); renderGlop(glop); } diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp index 06ea55ad2eac..bfabc1d4d94c 100644 --- a/libs/hwui/PathCache.cpp +++ b/libs/hwui/PathCache.cpp @@ -185,7 +185,7 @@ void PathCache::operator()(PathDescription& entry, PathTexture*& texture) { void PathCache::removeTexture(PathTexture* texture) { if (texture) { - const uint32_t size = texture->width * texture->height; + const uint32_t size = texture->width() * texture->height(); // If there is a pending task we must wait for it to return // before attempting our cleanup @@ -209,9 +209,7 @@ void PathCache::removeTexture(PathTexture* texture) { ALOGD("Shape deleted, size = %d", size); } - if (texture->id) { - Caches::getInstance().textureState().deleteTexture(texture->id); - } + texture->deleteTexture(); delete texture; } } @@ -248,8 +246,7 @@ PathTexture* PathCache::addTexture(const PathDescription& entry, const SkPath *p drawPath(path, paint, bitmap, left, top, offset, width, height); PathTexture* texture = new PathTexture(Caches::getInstance(), - left, top, offset, width, height, - path->getGenerationID()); + left, top, offset, path->getGenerationID()); generateTexture(entry, &bitmap, texture); return texture; @@ -262,7 +259,7 @@ void PathCache::generateTexture(const PathDescription& entry, SkBitmap* bitmap, // Note here that we upload to a texture even if it's bigger than mMaxSize. // Such an entry in mCache will only be temporary, since it will be evicted // immediately on trim, or on any other Path entering the cache. - uint32_t size = texture->width * texture->height; + uint32_t size = texture->width() * texture->height(); mSize += size; PATH_LOGD("PathCache::get/create: name, size, mSize = %d, %d, %d", texture->id, size, mSize); @@ -280,24 +277,8 @@ void PathCache::clear() { void PathCache::generateTexture(SkBitmap& bitmap, Texture* texture) { ATRACE_NAME("Upload Path Texture"); - SkAutoLockPixels alp(bitmap); - if (!bitmap.readyToDraw()) { - ALOGE("Cannot generate texture from bitmap"); - return; - } - - glGenTextures(1, &texture->id); - - Caches::getInstance().textureState().bindTexture(texture->id); - // Textures are Alpha8 - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - texture->blend = true; - glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, texture->width, texture->height, 0, - GL_ALPHA, GL_UNSIGNED_BYTE, bitmap.getPixels()); - + texture->upload(bitmap); texture->setFilter(GL_LINEAR); - texture->setWrap(GL_CLAMP_TO_EDGE); } /////////////////////////////////////////////////////////////////////////////// @@ -320,16 +301,12 @@ void PathCache::PathProcessor::onProcess(const sp >& task) { texture->left = left; texture->top = top; texture->offset = offset; - texture->width = width; - texture->height = height; if (width <= mMaxTextureSize && height <= mMaxTextureSize) { SkBitmap* bitmap = new SkBitmap(); drawPath(&t->path, &t->paint, *bitmap, left, top, offset, width, height); t->setResult(bitmap); } else { - texture->width = 0; - texture->height = 0; t->setResult(nullptr); } } diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h index 302e9f856904..18f380fe3f7a 100644 --- a/libs/hwui/PathCache.h +++ b/libs/hwui/PathCache.h @@ -61,13 +61,11 @@ class Caches; */ struct PathTexture: public Texture { PathTexture(Caches& caches, float left, float top, - float offset, int width, int height, int generation) + float offset, int generation) : Texture(caches) , left(left) , top(top) , offset(offset) { - this->width = width; - this->height = height; this->generation = generation; } PathTexture(Caches& caches, int generation) diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp index 83652c6de21f..6f4a6839be4e 100644 --- a/libs/hwui/SkiaShader.cpp +++ b/libs/hwui/SkiaShader.cpp @@ -57,7 +57,7 @@ static inline void bindUniformColor(int slot, FloatColor color) { } static inline void bindTexture(Caches* caches, Texture* texture, GLenum wrapS, GLenum wrapT) { - caches->textureState().bindTexture(texture->id); + caches->textureState().bindTexture(texture->id()); texture->setWrapST(wrapS, wrapT); } @@ -219,8 +219,8 @@ bool tryStoreBitmap(Caches& caches, const SkShader& shader, const Matrix4& model outData->bitmapSampler = (*textureUnit)++; - const float width = outData->bitmapTexture->width; - const float height = outData->bitmapTexture->height; + const float width = outData->bitmapTexture->width(); + const float height = outData->bitmapTexture->height(); description->hasBitmap = true; if (!caches.extensions().hasNPot() diff --git a/libs/hwui/TextDropShadowCache.cpp b/libs/hwui/TextDropShadowCache.cpp index 51f16523966b..f1e28b7dfa40 100644 --- a/libs/hwui/TextDropShadowCache.cpp +++ b/libs/hwui/TextDropShadowCache.cpp @@ -187,13 +187,10 @@ ShadowTexture* TextDropShadowCache::get(const SkPaint* paint, const char* glyphs texture = new ShadowTexture(caches); texture->left = shadow.penX; texture->top = shadow.penY; - texture->width = shadow.width; - texture->height = shadow.height; texture->generation = 0; texture->blend = true; const uint32_t size = shadow.width * shadow.height; - texture->bitmapSize = size; // Don't even try to cache a bitmap that's bigger than the cache if (size < mMaxSize) { @@ -202,15 +199,11 @@ ShadowTexture* TextDropShadowCache::get(const SkPaint* paint, const char* glyphs } } - glGenTextures(1, &texture->id); - - caches.textureState().bindTexture(texture->id); // Textures are Alpha8 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, texture->width, texture->height, 0, + texture->upload(GL_ALPHA, shadow.width, shadow.height, GL_ALPHA, GL_UNSIGNED_BYTE, shadow.image); - texture->setFilter(GL_LINEAR); texture->setWrap(GL_CLAMP_TO_EDGE); diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp index 5195b457af2b..8a6b28d86f27 100644 --- a/libs/hwui/Texture.cpp +++ b/libs/hwui/Texture.cpp @@ -14,14 +14,29 @@ * limitations under the License. */ -#include - #include "Caches.h" #include "Texture.h" +#include "utils/TraceUtils.h" + +#include + +#include namespace android { namespace uirenderer { +static int bytesPerPixel(GLint glFormat) { + switch (glFormat) { + case GL_ALPHA: + return 1; + case GL_RGB: + return 3; + case GL_RGBA: + default: + return 4; + } +} + void Texture::setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture, bool force, GLenum renderTarget) { @@ -32,7 +47,7 @@ void Texture::setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture, bool force mWrapT = wrapT; if (bindTexture) { - mCaches.textureState().bindTexture(renderTarget, id); + mCaches.textureState().bindTexture(renderTarget, mId); } glTexParameteri(renderTarget, GL_TEXTURE_WRAP_S, wrapS); @@ -50,7 +65,7 @@ void Texture::setFilterMinMag(GLenum min, GLenum mag, bool bindTexture, bool for mMagFilter = mag; if (bindTexture) { - mCaches.textureState().bindTexture(renderTarget, id); + mCaches.textureState().bindTexture(renderTarget, mId); } if (mipMap && min == GL_LINEAR) min = GL_LINEAR_MIPMAP_LINEAR; @@ -60,8 +75,189 @@ void Texture::setFilterMinMag(GLenum min, GLenum mag, bool bindTexture, bool for } } -void Texture::deleteTexture() const { - mCaches.textureState().deleteTexture(id); +void Texture::deleteTexture() { + mCaches.textureState().deleteTexture(mId); + mId = 0; +} + +bool Texture::updateSize(uint32_t width, uint32_t height, GLint format) { + if (mWidth == width && mHeight == height && mFormat == format) { + return false; + } + mWidth = width; + mHeight = height; + mFormat = format; + notifySizeChanged(mWidth * mHeight * bytesPerPixel(mFormat)); + return true; +} + +void Texture::upload(GLint internalformat, uint32_t width, uint32_t height, + GLenum format, GLenum type, const void* pixels) { + bool needsAlloc = updateSize(width, height, internalformat); + if (!needsAlloc && !pixels) { + return; + } + mCaches.textureState().activateTexture(0); + if (!mId) { + glGenTextures(1, &mId); + needsAlloc = true; + } + mCaches.textureState().bindTexture(GL_TEXTURE_2D, mId); + if (needsAlloc) { + glTexImage2D(GL_TEXTURE_2D, 0, mFormat, mWidth, mHeight, 0, + format, type, pixels); + } else { + glTexSubImage2D(GL_TEXTURE_2D, 0, mFormat, mWidth, mHeight, 0, + format, type, pixels); + } +} + +static void uploadToTexture(bool resize, GLenum format, GLenum type, GLsizei stride, GLsizei bpp, + GLsizei width, GLsizei height, const GLvoid * data) { + + glPixelStorei(GL_UNPACK_ALIGNMENT, bpp); + const bool useStride = stride != width + && Caches::getInstance().extensions().hasUnpackRowLength(); + if ((stride == width) || useStride) { + if (useStride) { + glPixelStorei(GL_UNPACK_ROW_LENGTH, stride); + } + + if (resize) { + glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, data); + } else { + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, data); + } + + if (useStride) { + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + } + } else { + // With OpenGL ES 2.0 we need to copy the bitmap in a temporary buffer + // if the stride doesn't match the width + + GLvoid * temp = (GLvoid *) malloc(width * height * bpp); + if (!temp) return; + + uint8_t * pDst = (uint8_t *)temp; + uint8_t * pSrc = (uint8_t *)data; + for (GLsizei i = 0; i < height; i++) { + memcpy(pDst, pSrc, width * bpp); + pDst += width * bpp; + pSrc += stride * bpp; + } + + if (resize) { + glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, temp); + } else { + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, temp); + } + + free(temp); + } +} + +static void uploadSkBitmapToTexture(const SkBitmap& bitmap, + bool resize, GLenum format, GLenum type) { + uploadToTexture(resize, format, type, bitmap.rowBytesAsPixels(), bitmap.bytesPerPixel(), + bitmap.width(), bitmap.height(), bitmap.getPixels()); +} + +static void colorTypeToGlFormatAndType(SkColorType colorType, + GLint* outFormat, GLint* outType) { + switch (colorType) { + case kAlpha_8_SkColorType: + *outFormat = GL_ALPHA; + *outType = GL_UNSIGNED_BYTE; + break; + case kRGB_565_SkColorType: + *outFormat = GL_RGB; + *outType = GL_UNSIGNED_SHORT_5_6_5; + break; + // ARGB_4444 and Index_8 are both upconverted to RGBA_8888 + case kARGB_4444_SkColorType: + case kIndex_8_SkColorType: + case kN32_SkColorType: + *outFormat = GL_RGBA; + *outType = GL_UNSIGNED_BYTE; + break; + default: + LOG_ALWAYS_FATAL("Unsupported bitmap colorType: %d", colorType); + break; + } +} + +void Texture::upload(const SkBitmap& bitmap) { + SkAutoLockPixels alp(bitmap); + + if (!bitmap.readyToDraw()) { + ALOGE("Cannot generate texture from bitmap"); + return; + } + + ATRACE_FORMAT("Upload %ux%u Texture", bitmap.width(), bitmap.height()); + + // We could also enable mipmapping if both bitmap dimensions are powers + // of 2 but we'd have to deal with size changes. Let's keep this simple + const bool canMipMap = mCaches.extensions().hasNPot(); + + // If the texture had mipmap enabled but not anymore, + // force a glTexImage2D to discard the mipmap levels + bool needsAlloc = canMipMap && mipMap && !bitmap.hasHardwareMipMap(); + + if (!mId) { + glGenTextures(1, &mId); + needsAlloc = true; + } + + GLint format, type; + colorTypeToGlFormatAndType(bitmap.colorType(), &format, &type); + + if (updateSize(bitmap.width(), bitmap.height(), format)) { + needsAlloc = true; + } + + blend = !bitmap.isOpaque(); + mCaches.textureState().bindTexture(mId); + + if (CC_UNLIKELY(bitmap.colorType() == kARGB_4444_SkColorType + || bitmap.colorType() == kIndex_8_SkColorType)) { + SkBitmap rgbaBitmap; + rgbaBitmap.allocPixels(SkImageInfo::MakeN32(mWidth, mHeight, + bitmap.alphaType())); + rgbaBitmap.eraseColor(0); + + SkCanvas canvas(rgbaBitmap); + canvas.drawBitmap(bitmap, 0.0f, 0.0f, nullptr); + + uploadSkBitmapToTexture(rgbaBitmap, needsAlloc, format, type); + } else { + uploadSkBitmapToTexture(bitmap, needsAlloc, format, type); + } + + if (canMipMap) { + mipMap = bitmap.hasHardwareMipMap(); + if (mipMap) { + glGenerateMipmap(GL_TEXTURE_2D); + } + } + + if (mFirstFilter) { + setFilter(GL_NEAREST); + } + + if (mFirstWrap) { + setWrap(GL_CLAMP_TO_EDGE); + } +} + +void Texture::wrap(GLuint id, uint32_t width, uint32_t height, GLint format) { + mId = id; + mWidth = width; + mHeight = height; + mFormat = format; + // We're wrapping an existing texture, so don't double count this memory + notifySizeChanged(0); } }; // namespace uirenderer diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h index 1c544b929e64..4e8e6dcf1a77 100644 --- a/libs/hwui/Texture.h +++ b/libs/hwui/Texture.h @@ -17,20 +17,27 @@ #ifndef ANDROID_HWUI_TEXTURE_H #define ANDROID_HWUI_TEXTURE_H +#include "GpuMemoryTracker.h" + #include +#include namespace android { namespace uirenderer { class Caches; class UvMapper; +class Layer; /** * Represents an OpenGL texture. */ -class Texture { +class Texture : public GpuMemoryTracker { public: - Texture(Caches& caches) : mCaches(caches) { } + Texture(Caches& caches) + : GpuMemoryTracker(GpuObjectType::Texture) + , mCaches(caches) + { } virtual ~Texture() { } @@ -53,28 +60,63 @@ public: /** * Convenience method to call glDeleteTextures() on this texture's id. */ - void deleteTexture() const; + void deleteTexture(); /** - * Name of the texture. + * Sets the width, height, and format of the texture along with allocating + * the texture ID. Does nothing if the width, height, and format are already + * the requested values. + * + * The image data is undefined after calling this. */ - GLuint id = 0; + void resize(uint32_t width, uint32_t height, GLint format) { + upload(format, width, height, format, GL_UNSIGNED_BYTE, nullptr); + } + /** - * Generation of the backing bitmap, + * Updates this Texture with the contents of the provided SkBitmap, + * also setting the appropriate width, height, and format. It is not necessary + * to call resize() prior to this. + * + * Note this does not set the generation from the SkBitmap. */ - uint32_t generation = 0; + void upload(const SkBitmap& source); + /** - * Indicates whether the texture requires blending. + * Basically glTexImage2D/glTexSubImage2D. */ - bool blend = false; + void upload(GLint internalformat, uint32_t width, uint32_t height, + GLenum format, GLenum type, const void* pixels); + /** - * Width of the backing bitmap. + * Wraps an existing texture. */ - uint32_t width = 0; + void wrap(GLuint id, uint32_t width, uint32_t height, GLint format); + + GLuint id() const { + return mId; + } + + uint32_t width() const { + return mWidth; + } + + uint32_t height() const { + return mHeight; + } + + GLint format() const { + return mFormat; + } + /** - * Height of the backing bitmap. + * Generation of the backing bitmap, */ - uint32_t height = 0; + uint32_t generation = 0; + /** + * Indicates whether the texture requires blending. + */ + bool blend = false; /** * Indicates whether this texture should be cleaned up after use. */ @@ -100,6 +142,19 @@ public: void* isInUse = nullptr; private: + // TODO: Temporarily grant private access to Layer, remove once + // Layer can be de-tangled from being a dual-purpose render target + // and external texture wrapper + friend class Layer; + + // Returns true if the size changed, false if it was the same + bool updateSize(uint32_t width, uint32_t height, GLint format); + + GLuint mId = 0; + uint32_t mWidth = 0; + uint32_t mHeight = 0; + GLint mFormat = 0; + /** * Last wrap modes set on this texture. */ @@ -120,7 +175,7 @@ private: class AutoTexture { public: - AutoTexture(const Texture* texture) + AutoTexture(Texture* texture) : texture(texture) {} ~AutoTexture() { if (texture && texture->cleanup) { @@ -129,7 +184,7 @@ public: } } - const Texture *const texture; + Texture* const texture; }; // class AutoTexture }; // namespace uirenderer diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp index 21901cf4414b..31bfa3a1ada4 100644 --- a/libs/hwui/TextureCache.cpp +++ b/libs/hwui/TextureCache.cpp @@ -166,7 +166,8 @@ Texture* TextureCache::getCachedTexture(const SkBitmap* bitmap, AtlasUsageType a if (canCache) { texture = new Texture(Caches::getInstance()); texture->bitmapSize = size; - Caches::getInstance().textureState().generateTexture(bitmap, texture, false); + texture->generation = bitmap->getGenerationID(); + texture->upload(*bitmap); mSize += size; TEXTURE_LOGD("TextureCache::get: create texture(%p): name, size, mSize = %d, %d, %d", @@ -179,7 +180,8 @@ Texture* TextureCache::getCachedTexture(const SkBitmap* bitmap, AtlasUsageType a } else if (!texture->isInUse && bitmap->getGenerationID() != texture->generation) { // Texture was in the cache but is dirty, re-upload // TODO: Re-adjust the cache size if the bitmap's dimensions have changed - Caches::getInstance().textureState().generateTexture(bitmap, texture, true); + texture->upload(*bitmap); + texture->generation = bitmap->getGenerationID(); } return texture; @@ -204,7 +206,8 @@ Texture* TextureCache::get(const SkBitmap* bitmap, AtlasUsageType atlasUsageType const uint32_t size = bitmap->rowBytes() * bitmap->height(); texture = new Texture(Caches::getInstance()); texture->bitmapSize = size; - Caches::getInstance().textureState().generateTexture(bitmap, texture, false); + texture->upload(*bitmap); + texture->generation = bitmap->getGenerationID(); texture->cleanup = true; } diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h index 191c8a81fec6..463450c81714 100644 --- a/libs/hwui/TextureCache.h +++ b/libs/hwui/TextureCache.h @@ -25,6 +25,7 @@ #include "Debug.h" #include +#include namespace android { namespace uirenderer { diff --git a/libs/hwui/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp index d2685daa1711..8ba4761c1b2e 100644 --- a/libs/hwui/font/CacheTexture.cpp +++ b/libs/hwui/font/CacheTexture.cpp @@ -111,11 +111,11 @@ CacheBlock* CacheBlock::removeBlock(CacheBlock* head, CacheBlock* blockToRemove) CacheTexture::CacheTexture(uint16_t width, uint16_t height, GLenum format, uint32_t maxQuadCount) : mTexture(Caches::getInstance()) + , mWidth(width) + , mHeight(height) , mFormat(format) , mMaxQuadCount(maxQuadCount) , mCaches(Caches::getInstance()) { - mTexture.width = width; - mTexture.height = height; mTexture.blend = true; mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE, @@ -160,10 +160,7 @@ void CacheTexture::releasePixelBuffer() { delete mPixelBuffer; mPixelBuffer = nullptr; } - if (mTexture.id) { - mCaches.textureState().deleteTexture(mTexture.id); - mTexture.id = 0; - } + mTexture.deleteTexture(); mDirty = false; mCurrentQuad = 0; } @@ -183,22 +180,9 @@ void CacheTexture::allocatePixelBuffer() { mPixelBuffer = PixelBuffer::create(mFormat, getWidth(), getHeight()); } - if (!mTexture.id) { - glGenTextures(1, &mTexture.id); - - mCaches.textureState().bindTexture(mTexture.id); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - // Initialize texture dimensions - glTexImage2D(GL_TEXTURE_2D, 0, mFormat, getWidth(), getHeight(), 0, - mFormat, GL_UNSIGNED_BYTE, nullptr); - - const GLenum filtering = getLinearFiltering() ? GL_LINEAR : GL_NEAREST; - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } + mTexture.resize(mWidth, mHeight, mFormat); + mTexture.setFilter(getLinearFiltering() ? GL_LINEAR : GL_NEAREST); + mTexture.setWrap(GL_CLAMP_TO_EDGE); } bool CacheTexture::upload() { diff --git a/libs/hwui/font/CacheTexture.h b/libs/hwui/font/CacheTexture.h index 6dabc768ce6b..5510666eef86 100644 --- a/libs/hwui/font/CacheTexture.h +++ b/libs/hwui/font/CacheTexture.h @@ -92,11 +92,11 @@ public: bool fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY); inline uint16_t getWidth() const { - return mTexture.width; + return mWidth; } inline uint16_t getHeight() const { - return mTexture.height; + return mHeight; } inline GLenum getFormat() const { @@ -122,7 +122,7 @@ public: GLuint getTextureId() { allocatePixelBuffer(); - return mTexture.id; + return mTexture.id(); } inline bool isDirty() const { @@ -183,6 +183,7 @@ private: PixelBuffer* mPixelBuffer = nullptr; Texture mTexture; + uint32_t mWidth, mHeight; GLenum mFormat; bool mLinearFiltering = false; bool mDirty = false; diff --git a/libs/hwui/renderstate/OffscreenBufferPool.cpp b/libs/hwui/renderstate/OffscreenBufferPool.cpp index 227b6409b893..98c94dfab1c5 100644 --- a/libs/hwui/renderstate/OffscreenBufferPool.cpp +++ b/libs/hwui/renderstate/OffscreenBufferPool.cpp @@ -34,29 +34,22 @@ namespace uirenderer { OffscreenBuffer::OffscreenBuffer(RenderState& renderState, Caches& caches, uint32_t viewportWidth, uint32_t viewportHeight) - : renderState(renderState) + : GpuMemoryTracker(GpuObjectType::OffscreenBuffer) + , renderState(renderState) , viewportWidth(viewportWidth) , viewportHeight(viewportHeight) , texture(caches) { - texture.width = computeIdealDimension(viewportWidth); - texture.height = computeIdealDimension(viewportHeight); + uint32_t width = computeIdealDimension(viewportWidth); + uint32_t height = computeIdealDimension(viewportHeight); + texture.resize(width, height, GL_RGBA); texture.blend = true; - - caches.textureState().activateTexture(0); - glGenTextures(1, &texture.id); - caches.textureState().bindTexture(GL_TEXTURE_2D, texture.id); - - texture.setWrap(GL_CLAMP_TO_EDGE, false, false, GL_TEXTURE_2D); + texture.setWrap(GL_CLAMP_TO_EDGE); // not setting filter on texture, since it's set when drawing, based on transform - - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture.width, texture.height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, nullptr); } Rect OffscreenBuffer::getTextureCoordinates() { - const float texX = 1.0f / float(texture.width); - const float texY = 1.0f / float(texture.height); + const float texX = 1.0f / static_cast(texture.width()); + const float texY = 1.0f / static_cast(texture.height()); return Rect(0, viewportHeight * texY, viewportWidth * texX, 0); } @@ -69,8 +62,8 @@ void OffscreenBuffer::updateMeshFromRegion() { size_t count; const android::Rect* rects = safeRegion.getArray(&count); - const float texX = 1.0f / float(texture.width); - const float texY = 1.0f / float(texture.height); + const float texX = 1.0f / float(texture.width()); + const float texY = 1.0f / float(texture.height()); FatVector meshVector(count * 4); // uses heap if more than 64 vertices needed TextureVertex* mesh = &meshVector[0]; @@ -157,8 +150,8 @@ OffscreenBuffer* OffscreenBufferPool::get(RenderState& renderState, OffscreenBuffer* OffscreenBufferPool::resize(OffscreenBuffer* layer, const uint32_t width, const uint32_t height) { RenderState& renderState = layer->renderState; - if (layer->texture.width == OffscreenBuffer::computeIdealDimension(width) - && layer->texture.height == OffscreenBuffer::computeIdealDimension(height)) { + if (layer->texture.width() == OffscreenBuffer::computeIdealDimension(width) + && layer->texture.height() == OffscreenBuffer::computeIdealDimension(height)) { // resize in place layer->viewportWidth = width; layer->viewportHeight = height; diff --git a/libs/hwui/renderstate/OffscreenBufferPool.h b/libs/hwui/renderstate/OffscreenBufferPool.h index 2d8d5295e1f8..94155efcbb0a 100644 --- a/libs/hwui/renderstate/OffscreenBufferPool.h +++ b/libs/hwui/renderstate/OffscreenBufferPool.h @@ -17,10 +17,10 @@ #ifndef ANDROID_HWUI_OFFSCREEN_BUFFER_POOL_H #define ANDROID_HWUI_OFFSCREEN_BUFFER_POOL_H +#include #include "Caches.h" #include "Texture.h" #include "utils/Macros.h" - #include #include @@ -40,7 +40,7 @@ class RenderState; * viewport bounds, since textures are always allocated with width / height as a multiple of 64, for * the purpose of improving reuse. */ -class OffscreenBuffer { +class OffscreenBuffer : GpuMemoryTracker { public: OffscreenBuffer(RenderState& renderState, Caches& caches, uint32_t viewportWidth, uint32_t viewportHeight); @@ -58,7 +58,7 @@ public: static uint32_t computeIdealDimension(uint32_t dimension); - uint32_t getSizeInBytes() { return texture.width * texture.height * 4; } + uint32_t getSizeInBytes() { return texture.objectSize(); } RenderState& renderState; @@ -124,8 +124,8 @@ private: Entry(OffscreenBuffer* layer) : layer(layer) - , width(layer->texture.width) - , height(layer->texture.height) { + , width(layer->texture.width()) + , height(layer->texture.height()) { } static int compare(const Entry& lhs, const Entry& rhs); diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp index 4fa820058fb2..4a1e8fcfedf2 100644 --- a/libs/hwui/renderstate/RenderState.cpp +++ b/libs/hwui/renderstate/RenderState.cpp @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include #include "renderstate/RenderState.h" #include "renderthread/CanvasContext.h" #include "renderthread/EglManager.h" #include "utils/GLUtils.h" - #include namespace android { @@ -40,6 +40,8 @@ RenderState::~RenderState() { void RenderState::onGLContextCreated() { LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil, "State object lifecycle not managed correctly"); + GpuMemoryTracker::onGLContextCreated(); + mBlend = new Blend(); mMeshState = new MeshState(); mScissor = new Scissor(); @@ -106,6 +108,8 @@ void RenderState::onGLContextDestroyed() { mScissor = nullptr; delete mStencil; mStencil = nullptr; + + GpuMemoryTracker::onGLContextDestroyed(); } void RenderState::flush(Caches::FlushMode mode) { @@ -310,7 +314,7 @@ void RenderState::render(const Glop& glop, const Matrix4& orthoMatrix) { texture.texture->setFilter(texture.filter, true, false, texture.target); } - mCaches->textureState().bindTexture(texture.target, texture.texture->id); + mCaches->textureState().bindTexture(texture.target, texture.texture->id()); meshState().enableTexCoordsVertexArray(); meshState().bindTexCoordsVertexPointer(force, vertices.texCoord, vertices.stride); diff --git a/libs/hwui/renderstate/TextureState.cpp b/libs/hwui/renderstate/TextureState.cpp index 1f50f712c267..26ebdee06c08 100644 --- a/libs/hwui/renderstate/TextureState.cpp +++ b/libs/hwui/renderstate/TextureState.cpp @@ -34,134 +34,6 @@ const GLenum kTextureUnits[] = { GL_TEXTURE3 }; -static void uploadToTexture(bool resize, GLenum format, GLenum type, GLsizei stride, GLsizei bpp, - GLsizei width, GLsizei height, const GLvoid * data) { - - glPixelStorei(GL_UNPACK_ALIGNMENT, bpp); - const bool useStride = stride != width - && Caches::getInstance().extensions().hasUnpackRowLength(); - if ((stride == width) || useStride) { - if (useStride) { - glPixelStorei(GL_UNPACK_ROW_LENGTH, stride); - } - - if (resize) { - glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, data); - } else { - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, data); - } - - if (useStride) { - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - } - } else { - // With OpenGL ES 2.0 we need to copy the bitmap in a temporary buffer - // if the stride doesn't match the width - - GLvoid * temp = (GLvoid *) malloc(width * height * bpp); - if (!temp) return; - - uint8_t * pDst = (uint8_t *)temp; - uint8_t * pSrc = (uint8_t *)data; - for (GLsizei i = 0; i < height; i++) { - memcpy(pDst, pSrc, width * bpp); - pDst += width * bpp; - pSrc += stride * bpp; - } - - if (resize) { - glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, temp); - } else { - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, temp); - } - - free(temp); - } -} - -static void uploadSkBitmapToTexture(const SkBitmap& bitmap, - bool resize, GLenum format, GLenum type) { - uploadToTexture(resize, format, type, bitmap.rowBytesAsPixels(), bitmap.bytesPerPixel(), - bitmap.width(), bitmap.height(), bitmap.getPixels()); -} - -void TextureState::generateTexture(const SkBitmap* bitmap, Texture* texture, bool regenerate) { - SkAutoLockPixels alp(*bitmap); - - if (!bitmap->readyToDraw()) { - ALOGE("Cannot generate texture from bitmap"); - return; - } - - ATRACE_FORMAT("Upload %ux%u Texture", bitmap->width(), bitmap->height()); - - // We could also enable mipmapping if both bitmap dimensions are powers - // of 2 but we'd have to deal with size changes. Let's keep this simple - const bool canMipMap = Caches::getInstance().extensions().hasNPot(); - - // If the texture had mipmap enabled but not anymore, - // force a glTexImage2D to discard the mipmap levels - const bool resize = !regenerate || bitmap->width() != int(texture->width) || - bitmap->height() != int(texture->height) || - (regenerate && canMipMap && texture->mipMap && !bitmap->hasHardwareMipMap()); - - if (!regenerate) { - glGenTextures(1, &texture->id); - } - - texture->generation = bitmap->getGenerationID(); - texture->width = bitmap->width(); - texture->height = bitmap->height(); - - bindTexture(texture->id); - - switch (bitmap->colorType()) { - case kAlpha_8_SkColorType: - uploadSkBitmapToTexture(*bitmap, resize, GL_ALPHA, GL_UNSIGNED_BYTE); - texture->blend = true; - break; - case kRGB_565_SkColorType: - uploadSkBitmapToTexture(*bitmap, resize, GL_RGB, GL_UNSIGNED_SHORT_5_6_5); - texture->blend = false; - break; - case kN32_SkColorType: - uploadSkBitmapToTexture(*bitmap, resize, GL_RGBA, GL_UNSIGNED_BYTE); - // Do this after calling getPixels() to make sure Skia's deferred - // decoding happened - texture->blend = !bitmap->isOpaque(); - break; - case kARGB_4444_SkColorType: - case kIndex_8_SkColorType: { - SkBitmap rgbaBitmap; - rgbaBitmap.allocPixels(SkImageInfo::MakeN32(texture->width, texture->height, - bitmap->alphaType())); - rgbaBitmap.eraseColor(0); - - SkCanvas canvas(rgbaBitmap); - canvas.drawBitmap(*bitmap, 0.0f, 0.0f, nullptr); - - uploadSkBitmapToTexture(rgbaBitmap, resize, GL_RGBA, GL_UNSIGNED_BYTE); - texture->blend = !bitmap->isOpaque(); - break; - } - default: - ALOGW("Unsupported bitmap colorType: %d", bitmap->colorType()); - break; - } - - if (canMipMap) { - texture->mipMap = bitmap->hasHardwareMipMap(); - if (texture->mipMap) { - glGenerateMipmap(GL_TEXTURE_2D); - } - } - - if (!regenerate) { - texture->setFilter(GL_NEAREST); - texture->setWrap(GL_CLAMP_TO_EDGE); - } -} - TextureState::TextureState() : mTextureUnit(0) { glActiveTexture(kTextureUnits[0]); diff --git a/libs/hwui/renderstate/TextureState.h b/libs/hwui/renderstate/TextureState.h index 3a2b85ae2886..ec94d7e9e267 100644 --- a/libs/hwui/renderstate/TextureState.h +++ b/libs/hwui/renderstate/TextureState.h @@ -76,13 +76,6 @@ public: */ void unbindTexture(GLuint texture); - /** - * Generates the texture from a bitmap into the specified texture structure. - * - * @param regenerate If true, the bitmap data is reuploaded into the texture, but - * no new texture is generated. - */ - void generateTexture(const SkBitmap* bitmap, Texture* texture, bool regenerate); private: // total number of texture units available for use static const int kTextureUnitsCount = 4; diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 644f3565216b..968135b4fd6c 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include #include "CanvasContext.h" #include "AnimationContext.h" @@ -497,6 +498,8 @@ void CanvasContext::draw() { mJankTracker.addFrame(*mCurrentFrameInfo); mRenderThread.jankTracker().addFrame(*mCurrentFrameInfo); + + GpuMemoryTracker::onFrameCompleted(); } // Called by choreographer to do an RT-driven animation diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h index edde31e502e0..42cd0ced0cac 100644 --- a/libs/hwui/tests/common/TestUtils.h +++ b/libs/hwui/tests/common/TestUtils.h @@ -197,6 +197,10 @@ public: renderthread::RenderThread::getInstance().queueAndWait(&task); } + static bool isRenderThreadRunning() { + return renderthread::RenderThread::hasInstance(); + } + static SkColor interpolateColor(float fraction, SkColor start, SkColor end); static void drawTextToCanvas(TestCanvas* canvas, const char* text, diff --git a/libs/hwui/tests/macrobench/main.cpp b/libs/hwui/tests/macrobench/main.cpp index 1616a95857d8..02a39501e647 100644 --- a/libs/hwui/tests/macrobench/main.cpp +++ b/libs/hwui/tests/macrobench/main.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include diff --git a/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp b/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp new file mode 100644 index 000000000000..aa1dcb2ea51b --- /dev/null +++ b/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include + +#include "renderthread/EglManager.h" +#include "renderthread/RenderThread.h" +#include "tests/common/TestUtils.h" + +#include + +using namespace android; +using namespace android::uirenderer; +using namespace android::uirenderer::renderthread; + +class TestGPUObject : public GpuMemoryTracker { +public: + TestGPUObject() : GpuMemoryTracker(GpuObjectType::Texture) {} + + void changeSize(int newSize) { + notifySizeChanged(newSize); + } +}; + +// Other tests may have created a renderthread and EGL context. +// This will destroy the EGLContext on RenderThread if it exists so that the +// current thread can spoof being a GPU thread +static void destroyEglContext() { + if (TestUtils::isRenderThreadRunning()) { + TestUtils::runOnRenderThread([](RenderThread& thread) { + thread.eglManager().destroy(); + }); + } +} + +TEST(GpuMemoryTracker, sizeCheck) { + destroyEglContext(); + + GpuMemoryTracker::onGLContextCreated(); + ASSERT_EQ(0, GpuMemoryTracker::getTotalSize(GpuObjectType::Texture)); + ASSERT_EQ(0, GpuMemoryTracker::getInstanceCount(GpuObjectType::Texture)); + { + TestGPUObject myObj; + ASSERT_EQ(1, GpuMemoryTracker::getInstanceCount(GpuObjectType::Texture)); + myObj.changeSize(500); + ASSERT_EQ(500, GpuMemoryTracker::getTotalSize(GpuObjectType::Texture)); + myObj.changeSize(1000); + ASSERT_EQ(1000, GpuMemoryTracker::getTotalSize(GpuObjectType::Texture)); + myObj.changeSize(300); + ASSERT_EQ(300, GpuMemoryTracker::getTotalSize(GpuObjectType::Texture)); + } + ASSERT_EQ(0, GpuMemoryTracker::getTotalSize(GpuObjectType::Texture)); + ASSERT_EQ(0, GpuMemoryTracker::getInstanceCount(GpuObjectType::Texture)); + GpuMemoryTracker::onGLContextDestroyed(); +} diff --git a/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp b/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp index e96e9ba55361..5278730a3c9e 100644 --- a/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp +++ b/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp @@ -36,8 +36,8 @@ TEST(OffscreenBuffer, construct) { EXPECT_EQ(49u, layer.viewportWidth); EXPECT_EQ(149u, layer.viewportHeight); - EXPECT_EQ(64u, layer.texture.width); - EXPECT_EQ(192u, layer.texture.height); + EXPECT_EQ(64u, layer.texture.width()); + EXPECT_EQ(192u, layer.texture.height()); EXPECT_EQ(64u * 192u * 4u, layer.getSizeInBytes()); }); @@ -100,8 +100,8 @@ TEST(OffscreenBufferPool, resize) { ASSERT_EQ(layer, pool.resize(layer, 60u, 55u)); EXPECT_EQ(60u, layer->viewportWidth); EXPECT_EQ(55u, layer->viewportHeight); - EXPECT_EQ(64u, layer->texture.width); - EXPECT_EQ(64u, layer->texture.height); + EXPECT_EQ(64u, layer->texture.width()); + EXPECT_EQ(64u, layer->texture.height()); // resized to use different object in pool auto layer2 = pool.get(thread.renderState(), 128u, 128u); @@ -110,8 +110,8 @@ TEST(OffscreenBufferPool, resize) { ASSERT_EQ(layer2, pool.resize(layer, 120u, 125u)); EXPECT_EQ(120u, layer2->viewportWidth); EXPECT_EQ(125u, layer2->viewportHeight); - EXPECT_EQ(128u, layer2->texture.width); - EXPECT_EQ(128u, layer2->texture.height); + EXPECT_EQ(128u, layer2->texture.width()); + EXPECT_EQ(128u, layer2->texture.height()); // original allocation now only thing in pool EXPECT_EQ(1u, pool.getCount()); diff --git a/libs/hwui/tests/unit/StringUtilsTests.cpp b/libs/hwui/tests/unit/StringUtilsTests.cpp index 6b2e265a61ff..b60e96c756ec 100644 --- a/libs/hwui/tests/unit/StringUtilsTests.cpp +++ b/libs/hwui/tests/unit/StringUtilsTests.cpp @@ -36,3 +36,18 @@ TEST(StringUtils, advancedBuildSet) { EXPECT_TRUE(collection.has("GL_ext1")); EXPECT_FALSE(collection.has("GL_ext")); // string present, but not in list } + +TEST(StringUtils, sizePrinter) { + std::stringstream os; + os << SizePrinter{500}; + EXPECT_EQ("500.00B", os.str()); + os.str(""); + os << SizePrinter{46080}; + EXPECT_EQ("45.00KiB", os.str()); + os.str(""); + os << SizePrinter{5 * 1024 * 1024 + 520 * 1024}; + EXPECT_EQ("5.51MiB", os.str()); + os.str(""); + os << SizePrinter{2147483647}; + EXPECT_EQ("2048.00MiB", os.str()); +} diff --git a/libs/hwui/utils/StringUtils.h b/libs/hwui/utils/StringUtils.h index 055869f73c26..05a3d5931e5d 100644 --- a/libs/hwui/utils/StringUtils.h +++ b/libs/hwui/utils/StringUtils.h @@ -18,6 +18,8 @@ #include #include +#include +#include namespace android { namespace uirenderer { @@ -34,6 +36,21 @@ public: static unordered_string_set split(const char* spacedList); }; +struct SizePrinter { + int bytes; + friend std::ostream& operator<<(std::ostream& stream, const SizePrinter& d) { + static const char* SUFFIXES[] = {"B", "KiB", "MiB"}; + size_t suffix = 0; + double temp = d.bytes; + while (temp > 1000 && suffix < 2) { + temp /= 1024.0; + suffix++; + } + stream << std::fixed << std::setprecision(2) << temp << SUFFIXES[suffix]; + return stream; + } +}; + } /* namespace uirenderer */ } /* namespace android */ -- cgit v1.2.3-59-g8ed1b From 9372ac3621848085e77b867f220c0b5ffce4010d Mon Sep 17 00:00:00 2001 From: John Reck Date: Tue, 19 Jan 2016 11:46:52 -0800 Subject: Fix ordering of texture->upload arguments Caught by scatter-shotting GL_CHECKPOINTS which seem generally useful to have Bug: 26609444 Change-Id: Ie31d9297d8dae56405126720f338b4256c8bae77 --- libs/hwui/BakedOpDispatcher.cpp | 2 ++ libs/hwui/BakedOpRenderer.cpp | 3 ++- libs/hwui/FrameBuilder.h | 9 +++++++++ libs/hwui/GradientCache.cpp | 4 ++-- libs/hwui/Texture.cpp | 7 +++++++ libs/hwui/renderstate/RenderState.cpp | 12 ++++++++++++ libs/hwui/renderthread/CanvasContext.cpp | 7 +++++++ libs/hwui/utils/GLUtils.h | 9 +++++++++ 8 files changed, 50 insertions(+), 3 deletions(-) (limited to 'libs/hwui/GradientCache.cpp') diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp index 7ecc743b700c..00381eea4147 100644 --- a/libs/hwui/BakedOpDispatcher.cpp +++ b/libs/hwui/BakedOpDispatcher.cpp @@ -784,7 +784,9 @@ void BakedOpDispatcher::onCopyFromLayerOp(BakedOpRenderer& renderer, const CopyF .build(); renderer.renderGlop(state, glop); } + GL_CHECKPOINT(); renderer.renderState().layerPool().putOrDelete(*op.layerHandle); + GL_CHECKPOINT(); } } // namespace uirenderer diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp index 4fbff0d107ba..09312825234e 100644 --- a/libs/hwui/BakedOpRenderer.cpp +++ b/libs/hwui/BakedOpRenderer.cpp @@ -74,7 +74,8 @@ void BakedOpRenderer::endLayer() { // Detach the texture from the FBO glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); - LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "endLayer FAILED"); + LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "endLayer FAILED, bound fbo = %u", + mRenderState.getFramebuffer()); mRenderState.deleteFramebuffer(mRenderTarget.frameBufferId); mRenderTarget.frameBufferId = 0; } diff --git a/libs/hwui/FrameBuilder.h b/libs/hwui/FrameBuilder.h index 3ba73f00f61d..bd0185017f52 100644 --- a/libs/hwui/FrameBuilder.h +++ b/libs/hwui/FrameBuilder.h @@ -21,6 +21,7 @@ #include "DisplayList.h" #include "LayerBuilder.h" #include "RecordedOp.h" +#include "utils/GLUtils.h" #include #include @@ -99,22 +100,30 @@ public: // Relay through layers in reverse order, since layers // later in the list will be drawn by earlier ones for (int i = mLayerBuilders.size() - 1; i >= 1; i--) { + GL_CHECKPOINT(); LayerBuilder& layer = *(mLayerBuilders[i]); if (layer.renderNode) { // cached HW layer - can't skip layer if empty renderer.startRepaintLayer(layer.offscreenBuffer, layer.repaintRect); + GL_CHECKPOINT(); layer.replayBakedOpsImpl((void*)&renderer, unmergedReceivers, mergedReceivers); + GL_CHECKPOINT(); renderer.endLayer(); } else if (!layer.empty()) { // save layer - skip entire layer if empty layer.offscreenBuffer = renderer.startTemporaryLayer(layer.width, layer.height); + GL_CHECKPOINT(); layer.replayBakedOpsImpl((void*)&renderer, unmergedReceivers, mergedReceivers); + GL_CHECKPOINT(); renderer.endLayer(); } } + GL_CHECKPOINT(); const LayerBuilder& fbo0 = *(mLayerBuilders[0]); renderer.startFrame(fbo0.width, fbo0.height, fbo0.repaintRect); + GL_CHECKPOINT(); fbo0.replayBakedOpsImpl((void*)&renderer, unmergedReceivers, mergedReceivers); + GL_CHECKPOINT(); renderer.endFrame(fbo0.repaintRect); } diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp index 522aa96132dd..1473bc88c060 100644 --- a/libs/hwui/GradientCache.cpp +++ b/libs/hwui/GradientCache.cpp @@ -277,9 +277,9 @@ void GradientCache::generateTexture(uint32_t* colors, float* positions, if (mUseFloatTexture) { // We have to use GL_RGBA16F because GL_RGBA32F does not support filtering - texture->upload(width, height, GL_RGBA16F, GL_RGBA, GL_FLOAT, pixels); + texture->upload(GL_RGBA16F, width, height, GL_RGBA, GL_FLOAT, pixels); } else { - texture->upload(width, height, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + texture->upload(GL_RGBA, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); } texture->setFilter(GL_LINEAR); diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp index 8a6b28d86f27..771d004cb91d 100644 --- a/libs/hwui/Texture.cpp +++ b/libs/hwui/Texture.cpp @@ -16,6 +16,7 @@ #include "Caches.h" #include "Texture.h" +#include "utils/GLUtils.h" #include "utils/TraceUtils.h" #include @@ -93,22 +94,28 @@ bool Texture::updateSize(uint32_t width, uint32_t height, GLint format) { void Texture::upload(GLint internalformat, uint32_t width, uint32_t height, GLenum format, GLenum type, const void* pixels) { + GL_CHECKPOINT(); bool needsAlloc = updateSize(width, height, internalformat); if (!needsAlloc && !pixels) { return; } mCaches.textureState().activateTexture(0); + GL_CHECKPOINT(); if (!mId) { glGenTextures(1, &mId); needsAlloc = true; } + GL_CHECKPOINT(); mCaches.textureState().bindTexture(GL_TEXTURE_2D, mId); + GL_CHECKPOINT(); if (needsAlloc) { glTexImage2D(GL_TEXTURE_2D, 0, mFormat, mWidth, mHeight, 0, format, type, pixels); + GL_CHECKPOINT(); } else { glTexSubImage2D(GL_TEXTURE_2D, 0, mFormat, mWidth, mHeight, 0, format, type, pixels); + GL_CHECKPOINT(); } } diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp index b6dba02cb01d..e71d6eed2197 100644 --- a/libs/hwui/renderstate/RenderState.cpp +++ b/libs/hwui/renderstate/RenderState.cpp @@ -241,6 +241,8 @@ void RenderState::render(const Glop& glop, const Matrix4& orthoMatrix) { const Glop::Mesh::Indices& indices = mesh.indices; const Glop::Fill& fill = glop.fill; + GL_CHECKPOINT(); + // --------------------------------------------- // ---------- Program + uniform setup ---------- // --------------------------------------------- @@ -284,6 +286,8 @@ void RenderState::render(const Glop& glop, const Matrix4& orthoMatrix) { roundedOutRadius); } + GL_CHECKPOINT(); + // -------------------------------- // ---------- Mesh setup ---------- // -------------------------------- @@ -335,11 +339,15 @@ void RenderState::render(const Glop& glop, const Matrix4& orthoMatrix) { // Shader uniforms SkiaShader::apply(*mCaches, fill.skiaShaderData); + GL_CHECKPOINT(); + // ------------------------------------ // ---------- GL state setup ---------- // ------------------------------------ blend().setFactors(glop.blend.src, glop.blend.dst); + GL_CHECKPOINT(); + // ------------------------------------ // ---------- Actual drawing ---------- // ------------------------------------ @@ -368,6 +376,8 @@ void RenderState::render(const Glop& glop, const Matrix4& orthoMatrix) { glDrawArrays(mesh.primitiveMode, 0, mesh.elementCount); } + GL_CHECKPOINT(); + // ----------------------------------- // ---------- Mesh teardown ---------- // ----------------------------------- @@ -377,6 +387,8 @@ void RenderState::render(const Glop& glop, const Matrix4& orthoMatrix) { if (vertices.attribFlags & VertexAttribFlags::Color) { glDisableVertexAttribArray(colorLocation); } + + GL_CHECKPOINT(); } void RenderState::dump() { diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index dd48a836f858..6f8d62757437 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -29,6 +29,7 @@ #include "renderstate/RenderState.h" #include "renderstate/Stencil.h" #include "protos/hwui.pb.h" +#include "utils/GLUtils.h" #include "utils/TimeUtils.h" #if HWUI_NEW_OPS @@ -213,10 +214,13 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, // node(s) are non client / filler nodes. info.mode = (node.get() == target ? TreeInfo::MODE_FULL : TreeInfo::MODE_RT_ONLY); node->prepareTree(info); + GL_CHECKPOINT(); } mAnimationContext->runRemainingAnimations(info); + GL_CHECKPOINT(); freePrefetechedLayers(); + GL_CHECKPOINT(); if (CC_UNLIKELY(!mNativeWindow.get())) { mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame); @@ -463,6 +467,9 @@ void CanvasContext::draw() { bool drew = mCanvas->finish(); #endif + + GL_CHECKPOINT(); + // Even if we decided to cancel the frame, from the perspective of jank // metrics the frame was swapped at this point mCurrentFrameInfo->markSwapBuffers(); diff --git a/libs/hwui/utils/GLUtils.h b/libs/hwui/utils/GLUtils.h index 702046148ad8..6c521e4955a0 100644 --- a/libs/hwui/utils/GLUtils.h +++ b/libs/hwui/utils/GLUtils.h @@ -16,9 +16,18 @@ #ifndef GLUTILS_H #define GLUTILS_H +#include + namespace android { namespace uirenderer { +#if 0 +#define GL_CHECKPOINT() LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(),\ + "GL errors! %s:%d", __FILE__, __LINE__) +#else +#define GL_CHECKPOINT() +#endif + class GLUtils { public: /** -- cgit v1.2.3-59-g8ed1b From 2de7771740ee08fcaff638ec6b2e460bb72fff04 Mon Sep 17 00:00:00 2001 From: John Reck Date: Wed, 20 Jan 2016 11:09:53 -0800 Subject: Normalize GL_UNPACK_ALIGNMENT Several places were setting GL_UNPACK_ALIGNMENT unneccessarily, whereas other places were assuming an unpack alignment of 1. Since we never actually do explicit row-alignment, set GL_UNPACK_ALIGNMENT to 1 at context creation time and never change it Bug: 26584230 Also turns on aggressive glGetError checking to better catch potential problem zones Change-Id: I190c8f0f0494a7f046d5ed769405c75d363be59a --- libs/hwui/BakedOpRenderer.cpp | 4 +--- libs/hwui/Dither.cpp | 2 -- libs/hwui/FontRenderer.cpp | 1 - libs/hwui/GradientCache.cpp | 2 -- libs/hwui/Layer.cpp | 1 - libs/hwui/LayerRenderer.cpp | 18 +++++------------- libs/hwui/OpenGLRenderer.cpp | 4 +--- libs/hwui/PixelBuffer.cpp | 11 ++++------- libs/hwui/TextDropShadowCache.cpp | 2 -- libs/hwui/Texture.cpp | 1 - libs/hwui/renderstate/TextureState.cpp | 1 + libs/hwui/utils/GLUtils.h | 4 +++- 12 files changed, 15 insertions(+), 36 deletions(-) (limited to 'libs/hwui/GradientCache.cpp') diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp index 09312825234e..e65746eea98a 100644 --- a/libs/hwui/BakedOpRenderer.cpp +++ b/libs/hwui/BakedOpRenderer.cpp @@ -139,9 +139,7 @@ void BakedOpRenderer::endFrame(const Rect& repaintRect) { mCaches.pathCache.trim(); mCaches.tessellationCache.trim(); -#if DEBUG_OPENGL - GLUtils::dumpGLErrors(); -#endif + GL_CHECKPOINT(); #if DEBUG_MEMORY_USAGE mCaches.dumpMemoryUsage(); diff --git a/libs/hwui/Dither.cpp b/libs/hwui/Dither.cpp index 1ba651174c8a..ec2013e27401 100644 --- a/libs/hwui/Dither.cpp +++ b/libs/hwui/Dither.cpp @@ -54,7 +54,6 @@ void Dither::bindDitherTexture() { 15 * dither, 7 * dither, 13 * dither, 5 * dither }; - glPixelStorei(GL_UNPACK_ALIGNMENT, sizeof(GLfloat)); glTexImage2D(GL_TEXTURE_2D, 0, GL_R16F, DITHER_KERNEL_SIZE, DITHER_KERNEL_SIZE, 0, GL_RED, GL_FLOAT, &pattern); } else { @@ -65,7 +64,6 @@ void Dither::bindDitherTexture() { 15, 7, 13, 5 }; - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, DITHER_KERNEL_SIZE, DITHER_KERNEL_SIZE, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &pattern); } diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp index ed31a2c27121..68bae6dc47f6 100644 --- a/libs/hwui/FontRenderer.cpp +++ b/libs/hwui/FontRenderer.cpp @@ -458,7 +458,6 @@ void FontRenderer::checkTextureUpdate() { GLuint lastTextureId = 0; bool resetPixelStore = false; - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // Iterate over all the cache textures and see which ones need to be updated checkTextureUpdateForCache(caches, mACacheTextures, resetPixelStore, lastTextureId); diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp index 1473bc88c060..e899ac71ff36 100644 --- a/libs/hwui/GradientCache.cpp +++ b/libs/hwui/GradientCache.cpp @@ -273,8 +273,6 @@ void GradientCache::generateTexture(uint32_t* colors, float* positions, memcpy(pixels + rowBytes, pixels, rowBytes); - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - if (mUseFloatTexture) { // We have to use GL_RGBA16F because GL_RGBA32F does not support filtering texture->upload(GL_RGBA16F, width, height, GL_RGBA, GL_FLOAT, pixels); diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp index 83692664d76f..114347d94357 100644 --- a/libs/hwui/Layer.cpp +++ b/libs/hwui/Layer.cpp @@ -207,7 +207,6 @@ void Layer::allocateTexture() { #endif if (texture.mId) { texture.updateSize(getWidth(), getHeight(), GL_RGBA); - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); glTexImage2D(renderTarget, 0, GL_RGBA, getWidth(), getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); } diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp index 0cf643fb686e..0f219e4792f6 100644 --- a/libs/hwui/LayerRenderer.cpp +++ b/libs/hwui/LayerRenderer.cpp @@ -373,7 +373,6 @@ bool LayerRenderer::copyLayer(RenderState& renderState, Layer* layer, SkBitmap* GLenum format; GLenum type; - GLenum error = GL_NO_ERROR; bool status = false; switch (bitmap->colorType()) { @@ -408,7 +407,7 @@ bool LayerRenderer::copyLayer(RenderState& renderState, Layer* layer, SkBitmap* renderState.bindFramebuffer(fbo); glGenTextures(1, &texture); - if ((error = glGetError()) != GL_NO_ERROR) goto error; + GL_CHECKPOINT(); caches.textureState().activateTexture(0); caches.textureState().bindTexture(texture); @@ -423,11 +422,11 @@ bool LayerRenderer::copyLayer(RenderState& renderState, Layer* layer, SkBitmap* glTexImage2D(GL_TEXTURE_2D, 0, format, bitmap->width(), bitmap->height(), 0, format, type, nullptr); - if ((error = glGetError()) != GL_NO_ERROR) goto error; + GL_CHECKPOINT(); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); - if ((error = glGetError()) != GL_NO_ERROR) goto error; + GL_CHECKPOINT(); { LayerRenderer renderer(renderState, layer); @@ -438,7 +437,7 @@ bool LayerRenderer::copyLayer(RenderState& renderState, Layer* layer, SkBitmap* renderer.translate(0.0f, bitmap->height()); renderer.scale(1.0f, -1.0f); - if ((error = glGetError()) != GL_NO_ERROR) goto error; + GL_CHECKPOINT(); { Rect bounds; @@ -448,19 +447,12 @@ bool LayerRenderer::copyLayer(RenderState& renderState, Layer* layer, SkBitmap* glReadPixels(0, 0, bitmap->width(), bitmap->height(), format, type, bitmap->getPixels()); - if ((error = glGetError()) != GL_NO_ERROR) goto error; + GL_CHECKPOINT(); } status = true; } -error: -#if DEBUG_OPENGL - if (error != GL_NO_ERROR) { - ALOGD("GL error while copying layer into bitmap = 0x%x", error); - } -#endif - renderState.bindFramebuffer(previousFbo); layer->setAlpha(alpha, mode); layer->setFbo(previousLayerFbo); diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 0cd763df78d1..1bfa3084d266 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -195,9 +195,7 @@ bool OpenGLRenderer::finish() { } if (!suppressErrorChecks()) { -#if DEBUG_OPENGL - GLUtils::dumpGLErrors(); -#endif + GL_CHECKPOINT(); #if DEBUG_MEMORY_USAGE mCaches.dumpMemoryUsage(); diff --git a/libs/hwui/PixelBuffer.cpp b/libs/hwui/PixelBuffer.cpp index 96247260f0f4..6df994c623f2 100644 --- a/libs/hwui/PixelBuffer.cpp +++ b/libs/hwui/PixelBuffer.cpp @@ -20,6 +20,7 @@ #include "Extensions.h" #include "Properties.h" #include "renderstate/RenderState.h" +#include "utils/GLUtils.h" #include @@ -112,14 +113,10 @@ uint8_t* GpuPixelBuffer::map(AccessMode mode) { if (mAccessMode == kAccessMode_None) { mCaches.pixelBufferState().bind(mBuffer); mMappedPointer = (uint8_t*) glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, getSize(), mode); -#if DEBUG_OPENGL - if (!mMappedPointer) { - GLenum status = GL_NO_ERROR; - while ((status = glGetError()) != GL_NO_ERROR) { - ALOGE("Could not map GPU pixel buffer: 0x%x", status); - } + if (CC_UNLIKELY(!mMappedPointer)) { + GLUtils::dumpGLErrors(); + LOG_ALWAYS_FATAL("Failed to map PBO"); } -#endif mAccessMode = mode; } diff --git a/libs/hwui/TextDropShadowCache.cpp b/libs/hwui/TextDropShadowCache.cpp index f1e28b7dfa40..62a20fcfa699 100644 --- a/libs/hwui/TextDropShadowCache.cpp +++ b/libs/hwui/TextDropShadowCache.cpp @@ -200,8 +200,6 @@ ShadowTexture* TextDropShadowCache::get(const SkPaint* paint, const char* glyphs } // Textures are Alpha8 - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - texture->upload(GL_ALPHA, shadow.width, shadow.height, GL_ALPHA, GL_UNSIGNED_BYTE, shadow.image); texture->setFilter(GL_LINEAR); diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp index 771d004cb91d..9fc0c199815d 100644 --- a/libs/hwui/Texture.cpp +++ b/libs/hwui/Texture.cpp @@ -122,7 +122,6 @@ void Texture::upload(GLint internalformat, uint32_t width, uint32_t height, static void uploadToTexture(bool resize, GLenum format, GLenum type, GLsizei stride, GLsizei bpp, GLsizei width, GLsizei height, const GLvoid * data) { - glPixelStorei(GL_UNPACK_ALIGNMENT, bpp); const bool useStride = stride != width && Caches::getInstance().extensions().hasUnpackRowLength(); if ((stride == width) || useStride) { diff --git a/libs/hwui/renderstate/TextureState.cpp b/libs/hwui/renderstate/TextureState.cpp index 26ebdee06c08..78b8edae2eed 100644 --- a/libs/hwui/renderstate/TextureState.cpp +++ b/libs/hwui/renderstate/TextureState.cpp @@ -43,6 +43,7 @@ TextureState::TextureState() glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits); LOG_ALWAYS_FATAL_IF(maxTextureUnits < kTextureUnitsCount, "At least %d texture units are required!", kTextureUnitsCount); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); } void TextureState::activateTexture(GLuint textureUnit) { diff --git a/libs/hwui/utils/GLUtils.h b/libs/hwui/utils/GLUtils.h index 6c521e4955a0..85a10f94dc4c 100644 --- a/libs/hwui/utils/GLUtils.h +++ b/libs/hwui/utils/GLUtils.h @@ -16,12 +16,14 @@ #ifndef GLUTILS_H #define GLUTILS_H +#include "Debug.h" + #include namespace android { namespace uirenderer { -#if 0 +#if DEBUG_OPENGL #define GL_CHECKPOINT() LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(),\ "GL errors! %s:%d", __FILE__, __LINE__) #else -- cgit v1.2.3-59-g8ed1b From 83c9b5bf638d75a3395f57c2c57c31c959632f9d Mon Sep 17 00:00:00 2001 From: John Reck Date: Fri, 5 Feb 2016 13:03:47 -0800 Subject: Add a debug assert to track down infinite loop Bug: 26980851 Change-Id: I326983ab367782048311b6cf06d800f72837e38e --- libs/hwui/Android.mk | 3 ++- libs/hwui/GradientCache.cpp | 7 +++-- libs/hwui/tests/unit/GradientCacheTests.cpp | 40 +++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 libs/hwui/tests/unit/GradientCacheTests.cpp (limited to 'libs/hwui/GradientCache.cpp') diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index 1fb9ac515f03..939b9f6c3578 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -250,7 +250,8 @@ LOCAL_SRC_FILES += \ tests/unit/SkiaBehaviorTests.cpp \ tests/unit/StringUtilsTests.cpp \ tests/unit/TextDropShadowCacheTests.cpp \ - tests/unit/VectorDrawableTests.cpp + tests/unit/VectorDrawableTests.cpp \ + tests/unit/GradientCacheTests.cpp ifeq (true, $(HWUI_NEW_OPS)) LOCAL_SRC_FILES += \ diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp index e899ac71ff36..eec9ed16939e 100644 --- a/libs/hwui/GradientCache.cpp +++ b/libs/hwui/GradientCache.cpp @@ -168,10 +168,13 @@ Texture* GradientCache::addLinearGradient(GradientCacheEntry& gradient, texture->blend = info.hasAlpha; texture->generation = 1; - // Asume the cache is always big enough + // Assume the cache is always big enough const uint32_t size = info.width * 2 * bytesPerPixel(); while (getSize() + size > mMaxSize) { - mCache.removeOldest(); + LOG_ALWAYS_FATAL_IF(!mCache.removeOldest(), + "Ran out of things to remove from the cache? getSize() = %" PRIu32 + ", size = %" PRIu32 ", mMaxSize = %" PRIu32 ", width = %" PRIu32, + getSize(), size, mMaxSize, info.width); } generateTexture(colors, positions, info.width, 2, texture); diff --git a/libs/hwui/tests/unit/GradientCacheTests.cpp b/libs/hwui/tests/unit/GradientCacheTests.cpp new file mode 100644 index 000000000000..5ee17054183c --- /dev/null +++ b/libs/hwui/tests/unit/GradientCacheTests.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "Extensions.h" +#include "GradientCache.h" +#include "tests/common/TestUtils.h" + +using namespace android; +using namespace android::uirenderer; + +RENDERTHREAD_TEST(GradientCache, addRemove) { + Extensions extensions; + GradientCache cache(extensions); + cache.setMaxSize(5000); + + SkColor colors[] = { 0xFF00FF00, 0xFFFF0000, 0xFF0000FF }; + float positions[] = { 1, 2, 3 }; + Texture* texture = cache.get(colors, positions, 3); + ASSERT_TRUE(texture); + ASSERT_FALSE(texture->cleanup); + ASSERT_EQ((uint32_t) texture->objectSize(), cache.getSize()); + ASSERT_TRUE(cache.getSize()); + cache.clear(); + ASSERT_EQ(cache.getSize(), 0u); +} -- cgit v1.2.3-59-g8ed1b From 48a8f431fa52ae2ee25ffba9d20676f03bb710ff Mon Sep 17 00:00:00 2001 From: Chris Craik Date: Fri, 5 Feb 2016 15:59:29 -0800 Subject: Move several property queries to Properties class bug:17478770 This removes a lot of redundant property query code, and puts the queries all in one place, so defining them automatically will be simpler in the future. Change-Id: I0428550e6081f07bc6554ffdf73b22284325abb8 --- libs/hwui/FboCache.cpp | 11 ++--------- libs/hwui/GradientCache.cpp | 17 +---------------- libs/hwui/GradientCache.h | 6 +----- libs/hwui/PatchCache.cpp | 12 ++---------- libs/hwui/PatchCache.h | 2 +- libs/hwui/PathCache.cpp | 15 ++++----------- libs/hwui/PathCache.h | 2 +- libs/hwui/Properties.cpp | 25 +++++++++++++++++++++++-- libs/hwui/Properties.h | 9 +++++++++ libs/hwui/RenderBufferCache.cpp | 18 +++--------------- libs/hwui/RenderBufferCache.h | 4 ---- libs/hwui/TessellationCache.cpp | 18 +----------------- libs/hwui/TessellationCache.h | 8 +------- libs/hwui/TextDropShadowCache.cpp | 38 ++++++++------------------------------ libs/hwui/TextDropShadowCache.h | 10 ++-------- libs/hwui/TextureCache.cpp | 32 ++------------------------------ libs/hwui/TextureCache.h | 13 ++----------- 17 files changed, 63 insertions(+), 177 deletions(-) (limited to 'libs/hwui/GradientCache.cpp') diff --git a/libs/hwui/FboCache.cpp b/libs/hwui/FboCache.cpp index cca3cb7a98f1..b2181b60054f 100644 --- a/libs/hwui/FboCache.cpp +++ b/libs/hwui/FboCache.cpp @@ -27,15 +27,8 @@ namespace uirenderer { // Constructors/destructor /////////////////////////////////////////////////////////////////////////////// -FboCache::FboCache(): mMaxSize(DEFAULT_FBO_CACHE_SIZE) { - char property[PROPERTY_VALUE_MAX]; - if (property_get(PROPERTY_FBO_CACHE_SIZE, property, nullptr) > 0) { - INIT_LOGD(" Setting fbo cache size to %s", property); - mMaxSize = atoi(property); - } else { - INIT_LOGD(" Using default fbo cache size of %d", DEFAULT_FBO_CACHE_SIZE); - } -} +FboCache::FboCache() + : mMaxSize(Properties::fboCacheSize) {} FboCache::~FboCache() { clear(); diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp index e899ac71ff36..044c7cb65718 100644 --- a/libs/hwui/GradientCache.cpp +++ b/libs/hwui/GradientCache.cpp @@ -65,17 +65,9 @@ int GradientCacheEntry::compare(const GradientCacheEntry& lhs, const GradientCac GradientCache::GradientCache(Extensions& extensions) : mCache(LruCache::kUnlimitedCapacity) , mSize(0) - , mMaxSize(MB(DEFAULT_GRADIENT_CACHE_SIZE)) + , mMaxSize(Properties::gradientCacheSize) , mUseFloatTexture(extensions.hasFloatTextures()) , mHasNpot(extensions.hasNPot()){ - char property[PROPERTY_VALUE_MAX]; - if (property_get(PROPERTY_GRADIENT_CACHE_SIZE, property, nullptr) > 0) { - INIT_LOGD(" Setting gradient cache size to %sMB", property); - setMaxSize(MB(atof(property))); - } else { - INIT_LOGD(" Using default gradient cache size of %.2fMB", DEFAULT_GRADIENT_CACHE_SIZE); - } - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); mCache.setOnEntryRemovedListener(this); @@ -97,13 +89,6 @@ uint32_t GradientCache::getMaxSize() { return mMaxSize; } -void GradientCache::setMaxSize(uint32_t maxSize) { - mMaxSize = maxSize; - while (mSize > mMaxSize) { - mCache.removeOldest(); - } -} - /////////////////////////////////////////////////////////////////////////////// // Callbacks /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/GradientCache.h b/libs/hwui/GradientCache.h index b762ca7d5e5c..dccd45072522 100644 --- a/libs/hwui/GradientCache.h +++ b/libs/hwui/GradientCache.h @@ -122,10 +122,6 @@ public: */ void clear(); - /** - * Sets the maximum size of the cache in bytes. - */ - void setMaxSize(uint32_t maxSize); /** * Returns the maximum size of the cache in bytes. */ @@ -177,7 +173,7 @@ private: LruCache mCache; uint32_t mSize; - uint32_t mMaxSize; + const uint32_t mMaxSize; GLint mMaxTextureSize; bool mUseFloatTexture; diff --git a/libs/hwui/PatchCache.cpp b/libs/hwui/PatchCache.cpp index 98812805259e..bd6feb9fc762 100644 --- a/libs/hwui/PatchCache.cpp +++ b/libs/hwui/PatchCache.cpp @@ -32,20 +32,12 @@ namespace uirenderer { PatchCache::PatchCache(RenderState& renderState) : mRenderState(renderState) + , mMaxSize(Properties::patchCacheSize) , mSize(0) , mCache(LruCache::kUnlimitedCapacity) , mMeshBuffer(0) , mFreeBlocks(nullptr) - , mGenerationId(0) { - char property[PROPERTY_VALUE_MAX]; - if (property_get(PROPERTY_PATCH_CACHE_SIZE, property, nullptr) > 0) { - INIT_LOGD(" Setting patch cache size to %skB", property); - mMaxSize = KB(atoi(property)); - } else { - INIT_LOGD(" Using default patch cache size of %.2fkB", DEFAULT_PATCH_CACHE_SIZE); - mMaxSize = KB(DEFAULT_PATCH_CACHE_SIZE); - } -} + , mGenerationId(0) {} PatchCache::~PatchCache() { clear(); diff --git a/libs/hwui/PatchCache.h b/libs/hwui/PatchCache.h index 387f79acf0ec..66ef6a0279ba 100644 --- a/libs/hwui/PatchCache.h +++ b/libs/hwui/PatchCache.h @@ -169,7 +169,7 @@ private: #endif RenderState& mRenderState; - uint32_t mMaxSize; + const uint32_t mMaxSize; uint32_t mSize; LruCache mCache; diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp index bfabc1d4d94c..8f914acc5c76 100644 --- a/libs/hwui/PathCache.cpp +++ b/libs/hwui/PathCache.cpp @@ -135,17 +135,10 @@ static void drawPath(const SkPath *path, const SkPaint* paint, SkBitmap& bitmap, // Cache constructor/destructor /////////////////////////////////////////////////////////////////////////////// -PathCache::PathCache(): - mCache(LruCache::kUnlimitedCapacity), - mSize(0), mMaxSize(MB(DEFAULT_PATH_CACHE_SIZE)) { - char property[PROPERTY_VALUE_MAX]; - if (property_get(PROPERTY_PATH_CACHE_SIZE, property, nullptr) > 0) { - INIT_LOGD(" Setting path cache size to %sMB", property); - mMaxSize = MB(atof(property)); - } else { - INIT_LOGD(" Using default path cache size of %.2fMB", DEFAULT_PATH_CACHE_SIZE); - } - +PathCache::PathCache() + : mCache(LruCache::kUnlimitedCapacity) + , mSize(0) + , mMaxSize(Properties::pathCacheSize) { mCache.setOnEntryRemovedListener(this); GLint maxTextureSize; diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h index 18f380fe3f7a..d2633aa427c5 100644 --- a/libs/hwui/PathCache.h +++ b/libs/hwui/PathCache.h @@ -300,7 +300,7 @@ private: LruCache mCache; uint32_t mSize; - uint32_t mMaxSize; + const uint32_t mMaxSize; GLuint mMaxTextureSize; bool mDebugEnabled; diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp index 083aeb7ed585..bbd8c7226ab2 100644 --- a/libs/hwui/Properties.cpp +++ b/libs/hwui/Properties.cpp @@ -37,7 +37,18 @@ bool Properties::useBufferAge = true; bool Properties::enablePartialUpdates = true; float Properties::textGamma = DEFAULT_TEXT_GAMMA; -int Properties::layerPoolSize = DEFAULT_LAYER_CACHE_SIZE; + +int Properties::fboCacheSize = DEFAULT_FBO_CACHE_SIZE; +int Properties::gradientCacheSize = MB(DEFAULT_GRADIENT_CACHE_SIZE); +int Properties::layerPoolSize = MB(DEFAULT_LAYER_CACHE_SIZE); +int Properties::patchCacheSize = KB(DEFAULT_PATCH_CACHE_SIZE); +int Properties::pathCacheSize = MB(DEFAULT_PATH_CACHE_SIZE); +int Properties::renderBufferCacheSize = MB(DEFAULT_RENDER_BUFFER_CACHE_SIZE); +int Properties::tessellationCacheSize = MB(DEFAULT_VERTEX_CACHE_SIZE); +int Properties::textDropShadowCacheSize = MB(DEFAULT_DROP_SHADOW_CACHE_SIZE); +int Properties::textureCacheSize = MB(DEFAULT_TEXTURE_CACHE_SIZE); + +float Properties::textureCacheFlushRate = DEFAULT_TEXTURE_CACHE_FLUSH_RATE; DebugLevel Properties::debugLevel = kDebugDisabled; OverdrawColorSet Properties::overdrawColorSet = OverdrawColorSet::Default; @@ -79,7 +90,6 @@ bool Properties::load() { bool prevDebugOverdraw = debugOverdraw; StencilClipDebug prevDebugStencilClip = debugStencilClip; - debugOverdraw = false; if (property_get(PROPERTY_DEBUG_OVERDRAW, property, nullptr) > 0) { INIT_LOGD(" Overdraw debug enabled: %s", property); @@ -133,7 +143,18 @@ bool Properties::load() { enablePartialUpdates = property_get_bool(PROPERTY_ENABLE_PARTIAL_UPDATES, true); textGamma = property_get_float(PROPERTY_TEXT_GAMMA, DEFAULT_TEXT_GAMMA); + + fboCacheSize = property_get_int(PROPERTY_FBO_CACHE_SIZE, DEFAULT_FBO_CACHE_SIZE); + gradientCacheSize = MB(property_get_float(PROPERTY_GRADIENT_CACHE_SIZE, DEFAULT_GRADIENT_CACHE_SIZE)); layerPoolSize = MB(property_get_float(PROPERTY_LAYER_CACHE_SIZE, DEFAULT_LAYER_CACHE_SIZE)); + patchCacheSize = KB(property_get_float(PROPERTY_PATCH_CACHE_SIZE, DEFAULT_PATCH_CACHE_SIZE)); + pathCacheSize = MB(property_get_float(PROPERTY_PATH_CACHE_SIZE, DEFAULT_PATH_CACHE_SIZE)); + renderBufferCacheSize = MB(property_get_float(PROPERTY_RENDER_BUFFER_CACHE_SIZE, DEFAULT_RENDER_BUFFER_CACHE_SIZE)); + tessellationCacheSize = MB(property_get_float(PROPERTY_VERTEX_CACHE_SIZE, DEFAULT_VERTEX_CACHE_SIZE)); + textDropShadowCacheSize = MB(property_get_float(PROPERTY_DROP_SHADOW_CACHE_SIZE, DEFAULT_DROP_SHADOW_CACHE_SIZE)); + textureCacheSize = MB(property_get_float(PROPERTY_TEXTURE_CACHE_SIZE, DEFAULT_TEXTURE_CACHE_SIZE)); + textureCacheFlushRate = std::max(0.0f, std::min(1.0f, + property_get_float(PROPERTY_TEXTURE_CACHE_FLUSH_RATE, DEFAULT_TEXTURE_CACHE_FLUSH_RATE))); return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw) diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index 88f1dbc98926..3e111516ac63 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -267,7 +267,16 @@ public: static float textGamma; + static int fboCacheSize; + static int gradientCacheSize; static int layerPoolSize; + static int patchCacheSize; + static int pathCacheSize; + static int renderBufferCacheSize; + static int tessellationCacheSize; + static int textDropShadowCacheSize; + static int textureCacheSize; + static float textureCacheFlushRate; static DebugLevel debugLevel; static OverdrawColorSet overdrawColorSet; diff --git a/libs/hwui/RenderBufferCache.cpp b/libs/hwui/RenderBufferCache.cpp index 11d7a6af3a6a..1ac57cdbac0c 100644 --- a/libs/hwui/RenderBufferCache.cpp +++ b/libs/hwui/RenderBufferCache.cpp @@ -40,16 +40,9 @@ namespace uirenderer { // Constructors/destructor /////////////////////////////////////////////////////////////////////////////// -RenderBufferCache::RenderBufferCache(): mSize(0), mMaxSize(MB(DEFAULT_RENDER_BUFFER_CACHE_SIZE)) { - char property[PROPERTY_VALUE_MAX]; - if (property_get(PROPERTY_RENDER_BUFFER_CACHE_SIZE, property, nullptr) > 0) { - INIT_LOGD(" Setting render buffer cache size to %sMB", property); - setMaxSize(MB(atof(property))); - } else { - INIT_LOGD(" Using default render buffer cache size of %.2fMB", - DEFAULT_RENDER_BUFFER_CACHE_SIZE); - } -} +RenderBufferCache::RenderBufferCache() + : mSize(0) + , mMaxSize(Properties::renderBufferCacheSize) {} RenderBufferCache::~RenderBufferCache() { clear(); @@ -67,11 +60,6 @@ uint32_t RenderBufferCache::getMaxSize() { return mMaxSize; } -void RenderBufferCache::setMaxSize(uint32_t maxSize) { - clear(); - mMaxSize = maxSize; -} - /////////////////////////////////////////////////////////////////////////////// // Caching /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/RenderBufferCache.h b/libs/hwui/RenderBufferCache.h index 7f59ec1c48b1..f77f4c95b5ba 100644 --- a/libs/hwui/RenderBufferCache.h +++ b/libs/hwui/RenderBufferCache.h @@ -63,10 +63,6 @@ public: */ void clear(); - /** - * Sets the maximum size of the cache in bytes. - */ - void setMaxSize(uint32_t maxSize); /** * Returns the maximum size of the cache in bytes. */ diff --git a/libs/hwui/TessellationCache.cpp b/libs/hwui/TessellationCache.cpp index fd9fb852171c..14c8f3926e31 100644 --- a/libs/hwui/TessellationCache.cpp +++ b/libs/hwui/TessellationCache.cpp @@ -265,18 +265,9 @@ public: /////////////////////////////////////////////////////////////////////////////// TessellationCache::TessellationCache() - : mSize(0) - , mMaxSize(MB(DEFAULT_VERTEX_CACHE_SIZE)) + : mMaxSize(Properties::tessellationCacheSize) , mCache(LruCache::kUnlimitedCapacity) , mShadowCache(LruCache*>::kUnlimitedCapacity) { - char property[PROPERTY_VALUE_MAX]; - if (property_get(PROPERTY_VERTEX_CACHE_SIZE, property, nullptr) > 0) { - INIT_LOGD(" Setting tessellation cache size to %sMB", property); - setMaxSize(MB(atof(property))); - } else { - INIT_LOGD(" Using default tessellation cache size of %.2fMB", DEFAULT_VERTEX_CACHE_SIZE); - } - mCache.setOnEntryRemovedListener(&mBufferRemovedListener); mShadowCache.setOnEntryRemovedListener(&mBufferPairRemovedListener); mDebugEnabled = Properties::debugLevel & kDebugCaches; @@ -303,13 +294,6 @@ uint32_t TessellationCache::getMaxSize() { return mMaxSize; } -void TessellationCache::setMaxSize(uint32_t maxSize) { - mMaxSize = maxSize; - while (mSize > mMaxSize) { - mCache.removeOldest(); - } -} - /////////////////////////////////////////////////////////////////////////////// // Caching /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/TessellationCache.h b/libs/hwui/TessellationCache.h index 6dcc8120cf48..0bd6365db60f 100644 --- a/libs/hwui/TessellationCache.h +++ b/libs/hwui/TessellationCache.h @@ -131,11 +131,6 @@ public: * Clears the cache. This causes all TessellationBuffers to be deleted. */ void clear(); - - /** - * Sets the maximum size of the cache in bytes. - */ - void setMaxSize(uint32_t maxSize); /** * Returns the maximum size of the cache in bytes. */ @@ -198,8 +193,7 @@ private: Buffer* getOrCreateBuffer(const Description& entry, Tessellator tessellator); - uint32_t mSize; - uint32_t mMaxSize; + const uint32_t mMaxSize; bool mDebugEnabled; diff --git a/libs/hwui/TextDropShadowCache.cpp b/libs/hwui/TextDropShadowCache.cpp index 1707468f169d..fe4b3d7507b2 100644 --- a/libs/hwui/TextDropShadowCache.cpp +++ b/libs/hwui/TextDropShadowCache.cpp @@ -93,36 +93,21 @@ int ShadowText::compare(const ShadowText& lhs, const ShadowText& rhs) { // Constructors/destructor /////////////////////////////////////////////////////////////////////////////// -TextDropShadowCache::TextDropShadowCache(): - mCache(LruCache::kUnlimitedCapacity), - mSize(0), mMaxSize(MB(DEFAULT_DROP_SHADOW_CACHE_SIZE)) { - char property[PROPERTY_VALUE_MAX]; - if (property_get(PROPERTY_DROP_SHADOW_CACHE_SIZE, property, nullptr) > 0) { - INIT_LOGD(" Setting drop shadow cache size to %sMB", property); - setMaxSize(MB(atof(property))); - } else { - INIT_LOGD(" Using default drop shadow cache size of %.2fMB", - DEFAULT_DROP_SHADOW_CACHE_SIZE); - } - - init(); -} +TextDropShadowCache::TextDropShadowCache() + : TextDropShadowCache(Properties::textDropShadowCacheSize) {} -TextDropShadowCache::TextDropShadowCache(uint32_t maxByteSize): - mCache(LruCache::kUnlimitedCapacity), - mSize(0), mMaxSize(maxByteSize) { - init(); +TextDropShadowCache::TextDropShadowCache(uint32_t maxByteSize) + : mCache(LruCache::kUnlimitedCapacity) + , mSize(0) + , mMaxSize(maxByteSize) { + mCache.setOnEntryRemovedListener(this); + mDebugEnabled = Properties::debugLevel & kDebugMoreCaches; } TextDropShadowCache::~TextDropShadowCache() { mCache.clear(); } -void TextDropShadowCache::init() { - mCache.setOnEntryRemovedListener(this); - mDebugEnabled = Properties::debugLevel & kDebugMoreCaches; -} - /////////////////////////////////////////////////////////////////////////////// // Size management /////////////////////////////////////////////////////////////////////////////// @@ -135,13 +120,6 @@ uint32_t TextDropShadowCache::getMaxSize() { return mMaxSize; } -void TextDropShadowCache::setMaxSize(uint32_t maxSize) { - mMaxSize = maxSize; - while (mSize > mMaxSize) { - mCache.removeOldest(); - } -} - /////////////////////////////////////////////////////////////////////////////// // Callbacks /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/TextDropShadowCache.h b/libs/hwui/TextDropShadowCache.h index c4f3c5d96786..cf647882e5a7 100644 --- a/libs/hwui/TextDropShadowCache.h +++ b/libs/hwui/TextDropShadowCache.h @@ -147,10 +147,6 @@ public: mRenderer = &fontRenderer; } - /** - * Sets the maximum size of the cache in bytes. - */ - void setMaxSize(uint32_t maxSize); /** * Returns the maximum size of the cache in bytes. */ @@ -161,13 +157,11 @@ public: uint32_t getSize(); private: - void init(); - LruCache mCache; uint32_t mSize; - uint32_t mMaxSize; - FontRenderer* mRenderer; + const uint32_t mMaxSize; + FontRenderer* mRenderer = nullptr; bool mDebugEnabled; }; // class TextDropShadowCache diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp index 31bfa3a1ada4..ade8600ab78b 100644 --- a/libs/hwui/TextureCache.cpp +++ b/libs/hwui/TextureCache.cpp @@ -35,26 +35,9 @@ namespace uirenderer { TextureCache::TextureCache() : mCache(LruCache::kUnlimitedCapacity) , mSize(0) - , mMaxSize(MB(DEFAULT_TEXTURE_CACHE_SIZE)) - , mFlushRate(DEFAULT_TEXTURE_CACHE_FLUSH_RATE) + , mMaxSize(Properties::textureCacheSize) + , mFlushRate(Properties::textureCacheFlushRate) , mAssetAtlas(nullptr) { - char property[PROPERTY_VALUE_MAX]; - if (property_get(PROPERTY_TEXTURE_CACHE_SIZE, property, nullptr) > 0) { - INIT_LOGD(" Setting texture cache size to %sMB", property); - setMaxSize(MB(atof(property))); - } else { - INIT_LOGD(" Using default texture cache size of %.2fMB", DEFAULT_TEXTURE_CACHE_SIZE); - } - - if (property_get(PROPERTY_TEXTURE_CACHE_FLUSH_RATE, property, nullptr) > 0) { - float flushRate = atof(property); - INIT_LOGD(" Setting texture cache flush rate to %.2f%%", flushRate * 100.0f); - setFlushRate(flushRate); - } else { - INIT_LOGD(" Using default texture cache flush rate of %.2f%%", - DEFAULT_TEXTURE_CACHE_FLUSH_RATE * 100.0f); - } - mCache.setOnEntryRemovedListener(this); glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); @@ -79,17 +62,6 @@ uint32_t TextureCache::getMaxSize() { return mMaxSize; } -void TextureCache::setMaxSize(uint32_t maxSize) { - mMaxSize = maxSize; - while (mSize > mMaxSize) { - mCache.removeOldest(); - } -} - -void TextureCache::setFlushRate(float flushRate) { - mFlushRate = std::max(0.0f, std::min(1.0f, flushRate)); -} - /////////////////////////////////////////////////////////////////////////////// // Callbacks /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h index 463450c81714..a4317cee73fd 100644 --- a/libs/hwui/TextureCache.h +++ b/libs/hwui/TextureCache.h @@ -108,10 +108,6 @@ public: */ void clear(); - /** - * Sets the maximum size of the cache in bytes. - */ - void setMaxSize(uint32_t maxSize); /** * Returns the maximum size of the cache in bytes. */ @@ -126,11 +122,6 @@ public: * is defined by the flush rate. */ void flush(); - /** - * Indicates the percentage of the cache to retain when a - * memory trim is requested (see Caches::flush). - */ - void setFlushRate(float flushRate); void setAssetAtlas(AssetAtlas* assetAtlas); @@ -148,10 +139,10 @@ private: LruCache mCache; uint32_t mSize; - uint32_t mMaxSize; + const uint32_t mMaxSize; GLint mMaxTextureSize; - float mFlushRate; + const float mFlushRate; bool mDebugEnabled; -- cgit v1.2.3-59-g8ed1b From 1d4e6a0901e5d26f4319ed173b4aa7b907350d93 Mon Sep 17 00:00:00 2001 From: John Reck Date: Thu, 11 Feb 2016 13:22:25 -0800 Subject: Fix bpp mismatch Bug: 26980851 GL_RGBA16F was being incorrectly calculated as 4 bpp instead of 16 in Texture's objectSize(), leading to a mismatch in cache size tracking in GradientCache Change-Id: I533c52fcdf9910d7a7d14bbd80965b8cbef8e147 --- libs/hwui/GradientCache.cpp | 4 ++++ libs/hwui/Texture.cpp | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'libs/hwui/GradientCache.cpp') diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp index 11293d61211b..88ae02b5524d 100644 --- a/libs/hwui/GradientCache.cpp +++ b/libs/hwui/GradientCache.cpp @@ -165,6 +165,10 @@ Texture* GradientCache::addLinearGradient(GradientCacheEntry& gradient, generateTexture(colors, positions, info.width, 2, texture); mSize += size; + LOG_ALWAYS_FATAL_IF((int)size != texture->objectSize(), + "size != texture->objectSize(), size %" PRIu32 ", objectSize %" PRIu32 + " width = %" PRIu32 " bytesPerPixel() = %" PRIu32, + size, texture->objectSize(), info.width, bytesPerPixel()); mCache.put(gradient, texture); return texture; diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp index c09b6dd89e4e..49a103c01108 100644 --- a/libs/hwui/Texture.cpp +++ b/libs/hwui/Texture.cpp @@ -33,8 +33,11 @@ static int bytesPerPixel(GLint glFormat) { case GL_RGB: return 3; case GL_RGBA: - default: return 4; + case GL_RGBA16F: + return 16; + default: + LOG_ALWAYS_FATAL("UNKNOWN FORMAT %d", glFormat); } } -- cgit v1.2.3-59-g8ed1b From d61fd4ede537695d6f7c340aae365095e5bade4d Mon Sep 17 00:00:00 2001 From: John Reck Date: Thu, 11 Feb 2016 14:35:08 -0800 Subject: Fix build Change-Id: Id793d3a824902ab794b5d5a4cdf4c77a72c52add --- libs/hwui/GradientCache.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'libs/hwui/GradientCache.cpp') diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp index 88ae02b5524d..c8f5e9435594 100644 --- a/libs/hwui/GradientCache.cpp +++ b/libs/hwui/GradientCache.cpp @@ -166,8 +166,8 @@ Texture* GradientCache::addLinearGradient(GradientCacheEntry& gradient, mSize += size; LOG_ALWAYS_FATAL_IF((int)size != texture->objectSize(), - "size != texture->objectSize(), size %" PRIu32 ", objectSize %" PRIu32 - " width = %" PRIu32 " bytesPerPixel() = %" PRIu32, + "size != texture->objectSize(), size %" PRIu32 ", objectSize %d" + " width = %" PRIu32 " bytesPerPixel() = %zu", size, texture->objectSize(), info.width, bytesPerPixel()); mCache.put(gradient, texture); -- cgit v1.2.3-59-g8ed1b