diff options
author | Romain Guy <romainguy@google.com> | 2013-03-08 17:44:20 -0800 |
---|---|---|
committer | Romain Guy <romainguy@google.com> | 2013-03-11 17:05:28 -0700 |
commit | ca89e2a68703bd428e8b66547d033a6ed35b3595 (patch) | |
tree | 5661de81848f7d26559531a1ea650ed7fea2decd | |
parent | 6e2004089305cf2cd958b52b234459a49a4e5c83 (diff) | |
download | frameworks_base-ca89e2a68703bd428e8b66547d033a6ed35b3595.zip frameworks_base-ca89e2a68703bd428e8b66547d033a6ed35b3595.tar.gz frameworks_base-ca89e2a68703bd428e8b66547d033a6ed35b3595.tar.bz2 |
Precache paths from a worker thread
Change-Id: I3e7b53d67e0e03e403beaf55c39350ead7f1e309
-rw-r--r-- | libs/hwui/DisplayListOp.h | 7 | ||||
-rw-r--r-- | libs/hwui/GradientCache.cpp | 1 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 6 | ||||
-rw-r--r-- | libs/hwui/PathCache.cpp | 162 | ||||
-rw-r--r-- | libs/hwui/PathCache.h | 36 | ||||
-rw-r--r-- | libs/hwui/ShapeCache.h | 178 | ||||
-rw-r--r-- | libs/hwui/TextureCache.cpp | 2 | ||||
-rw-r--r-- | libs/hwui/thread/Barrier.h | 58 | ||||
-rw-r--r-- | libs/hwui/thread/Future.h | 58 | ||||
-rw-r--r-- | libs/hwui/thread/Signal.h | 56 | ||||
-rw-r--r-- | tests/HwAccelerationTest/src/com/android/test/hwui/PathsCacheActivity.java | 4 |
11 files changed, 483 insertions, 85 deletions
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h index d231907..105f45f 100644 --- a/libs/hwui/DisplayListOp.h +++ b/libs/hwui/DisplayListOp.h @@ -1005,7 +1005,7 @@ public: : DrawBoundedOp(paint), mPath(path) { float left, top, offset; uint32_t width, height; - computePathBounds(path, paint, left, top, offset, width, height); + PathCache::computePathBounds(path, paint, left, top, offset, width, height); left -= offset; top -= offset; mLocalBounds.set(left, top, left + width, top + height); @@ -1016,6 +1016,11 @@ public: return renderer.drawPath(mPath, getPaint(renderer)); } + virtual void onDrawOpDeferred(OpenGLRenderer& renderer) { + SkPaint* paint = getPaint(renderer); + renderer.getCaches().pathCache.precache(mPath, paint); + } + virtual void output(int level, uint32_t flags) { OP_LOG("Draw Path %p in "RECT_STRING, mPath, RECT_ARGS(mLocalBounds)); } diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp index 78f9cf5..d681609 100644 --- a/libs/hwui/GradientCache.cpp +++ b/libs/hwui/GradientCache.cpp @@ -17,7 +17,6 @@ #define LOG_TAG "OpenGLRenderer" #include <utils/JenkinsHash.h> -#include <utils/threads.h> #include "Caches.h" #include "Debug.h" diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 11fdd6c..7fe0a69 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -276,6 +276,12 @@ void OpenGLRenderer::finish() { renderOverdraw(); endTiling(); + // When finish() is invoked on FBO 0 we've reached the end + // of the current frame + if (getTargetFbo() == 0) { + mCaches.pathCache.trim(); + } + if (!suppressErrorChecks()) { #if DEBUG_OPENGL GLenum status = GL_NO_ERROR; diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp index 4f682ed..9e6ec84 100644 --- a/libs/hwui/PathCache.cpp +++ b/libs/hwui/PathCache.cpp @@ -16,34 +16,84 @@ #define LOG_TAG "OpenGLRenderer" -#include <utils/threads.h> +#include <utils/Mutex.h> +#include <sys/sysinfo.h> + +#include "Caches.h" #include "PathCache.h" #include "Properties.h" namespace android { namespace uirenderer { -// Defined in ShapeCache.h +/////////////////////////////////////////////////////////////////////////////// +// Path precaching +/////////////////////////////////////////////////////////////////////////////// + +bool PathCache::PrecacheThread::threadLoop() { + mSignal.wait(); + Vector<Task> tasks; + { + Mutex::Autolock l(mLock); + tasks = mTasks; + mTasks.clear(); + } + + Caches& caches = Caches::getInstance(); + uint32_t maxSize = caches.maxTextureSize; + + ATRACE_BEGIN("pathPrecache"); + for (size_t i = 0; i < tasks.size(); i++) { + const Task& task = tasks.itemAt(i); + + float left, top, offset; + uint32_t width, height; + PathCache::computePathBounds(task.path, task.paint, left, top, offset, width, height); + + if (width <= maxSize && height <= maxSize) { + SkBitmap* bitmap = new SkBitmap(); + + PathTexture* texture = task.texture; + texture->left = left; + texture->top = top; + texture->offset = offset; + texture->width = width; + texture->height = height; -void computePathBounds(const SkPath* path, const SkPaint* paint, - float& left, float& top, float& offset, uint32_t& width, uint32_t& height) { - const SkRect& bounds = path->getBounds(); - computeBounds(bounds, paint, left, top, offset, width, height); + PathCache::drawPath(task.path, task.paint, *bitmap, left, top, offset, width, height); + + texture->future()->produce(bitmap); + } else { + task.texture->future()->produce(NULL); + } + } + ATRACE_END(); + return true; } -void computeBounds(const SkRect& bounds, const SkPaint* paint, - float& left, float& top, float& offset, uint32_t& width, uint32_t& height) { - const float pathWidth = fmax(bounds.width(), 1.0f); - const float pathHeight = fmax(bounds.height(), 1.0f); +void PathCache::PrecacheThread::addTask(PathTexture* texture, SkPath* path, SkPaint* paint) { + if (!isRunning()) { + run("libhwui:pathPrecache", PRIORITY_DEFAULT); + } - left = bounds.fLeft; - top = bounds.fTop; + Task task; + task.texture = texture; + task.path = path; + task.paint = paint; - offset = (int) floorf(fmax(paint->getStrokeWidth(), 1.0f) * 1.5f + 0.5f); + Mutex::Autolock l(mLock); + mTasks.add(task); + mSignal.signal(); +} - width = uint32_t(pathWidth + offset * 2.0 + 0.5); - height = uint32_t(pathHeight + offset * 2.0 + 0.5); +void PathCache::PrecacheThread::exit() { + { + Mutex::Autolock l(mLock); + mTasks.clear(); + } + requestExit(); + mSignal.signal(); } /////////////////////////////////////////////////////////////////////////////// @@ -51,7 +101,11 @@ void computeBounds(const SkRect& bounds, const SkPaint* paint, /////////////////////////////////////////////////////////////////////////////// PathCache::PathCache(): ShapeCache<PathCacheEntry>("path", - PROPERTY_PATH_CACHE_SIZE, DEFAULT_PATH_CACHE_SIZE) { + PROPERTY_PATH_CACHE_SIZE, DEFAULT_PATH_CACHE_SIZE), mThread(new PrecacheThread()) { +} + +PathCache::~PathCache() { + mThread->exit(); } void PathCache::remove(SkPath* path) { @@ -60,7 +114,7 @@ void PathCache::remove(SkPath* path) { while (i.next()) { const PathCacheEntry& key = i.key(); - if (key.path == path) { + if (key.path == path || key.path == path->getSourcePath()) { pathsToRemove.push(key); } } @@ -71,12 +125,12 @@ void PathCache::remove(SkPath* path) { } void PathCache::removeDeferred(SkPath* path) { - Mutex::Autolock _l(mLock); + Mutex::Autolock l(mLock); mGarbage.push(path); } void PathCache::clearGarbage() { - Mutex::Autolock _l(mLock); + Mutex::Autolock l(mLock); size_t count = mGarbage.size(); for (size_t i = 0; i < count; i++) { remove(mGarbage.itemAt(i)); @@ -84,23 +138,85 @@ void PathCache::clearGarbage() { mGarbage.clear(); } -PathTexture* PathCache::get(SkPath* path, SkPaint* paint) { +/** + * To properly handle path mutations at draw time we always make a copy + * of paths objects when recording display lists. The source path points + * to the path we originally copied the path from. This ensures we use + * the original path as a cache key the first time a path is inserted + * in the cache. The source path is also used to reclaim garbage when a + * Dalvik Path object is collected. + */ +static SkPath* getSourcePath(SkPath* path) { const SkPath* sourcePath = path->getSourcePath(); if (sourcePath && sourcePath->getGenerationID() == path->getGenerationID()) { - path = const_cast<SkPath*>(sourcePath); + return const_cast<SkPath*>(sourcePath); } + return path; +} + +PathTexture* PathCache::get(SkPath* path, SkPaint* paint) { + path = getSourcePath(path); PathCacheEntry entry(path, paint); PathTexture* texture = mCache.get(entry); if (!texture) { texture = addTexture(entry, path, paint); + } else { + // A bitmap is attached to the texture, this means we need to + // upload it as a GL texture + if (texture->future() != NULL) { + // But we must first wait for the worker thread to be done + // producing the bitmap, so let's wait + SkBitmap* bitmap = texture->future()->get(); + if (bitmap) { + addTexture(entry, bitmap, texture); + texture->clearFuture(); + } else { + ALOGW("Path too large to be rendered into a texture (%dx%d)", + texture->width, texture->height); + texture->clearFuture(); + texture = NULL; + mCache.remove(entry); + } + } else if (path->getGenerationID() != texture->generation) { + mCache.remove(entry); + texture = addTexture(entry, path, paint); + } + } + + return texture; +} + +void PathCache::precache(SkPath* path, SkPaint* paint) { + path = getSourcePath(path); + + PathCacheEntry entry(path, paint); + PathTexture* texture = mCache.get(entry); + + bool generate = false; + if (!texture) { + generate = true; } else if (path->getGenerationID() != texture->generation) { mCache.remove(entry); - texture = addTexture(entry, path, paint); + generate = true; } - return texture; + if (generate) { + // It is important to specify the generation ID so we do not + // attempt to precache the same path several times + texture = createTexture(0.0f, 0.0f, 0.0f, 0, 0, path->getGenerationID(), true); + + // During the precaching phase we insert path texture objects into + // the cache that do not point to any GL texture. They are instead + // treated as a task for the precaching worker thread. This is why + // we do not check the cache limit when inserting these objects. + // The conversion into GL texture will happen in get(), when a client + // asks for a path texture. This is also when the cache limit will + // be enforced. + mCache.put(entry, texture); + mThread->addTask(texture, path, paint); + } } }; // namespace uirenderer diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h index 8a0235b..1d28ecb 100644 --- a/libs/hwui/PathCache.h +++ b/libs/hwui/PathCache.h @@ -17,14 +17,21 @@ #ifndef ANDROID_HWUI_PATH_CACHE_H #define ANDROID_HWUI_PATH_CACHE_H +#include <utils/Thread.h> #include <utils/Vector.h> #include "Debug.h" #include "ShapeCache.h" +#include "thread/Signal.h" + +class SkPaint; +class SkPath; namespace android { namespace uirenderer { +class Caches; + /////////////////////////////////////////////////////////////////////////////// // Classes /////////////////////////////////////////////////////////////////////////////// @@ -69,6 +76,7 @@ inline hash_t hash_type(const PathCacheEntry& entry) { class PathCache: public ShapeCache<PathCacheEntry> { public: PathCache(); + ~PathCache(); /** * Returns the texture associated with the specified path. If the texture @@ -89,7 +97,35 @@ public: */ void clearGarbage(); + void precache(SkPath* path, SkPaint* paint); + private: + class PrecacheThread: public Thread { + public: + PrecacheThread(): mSignal(Condition::WAKE_UP_ONE) { } + + void addTask(PathTexture* texture, SkPath* path, SkPaint* paint); + void exit(); + + private: + struct Task { + PathTexture* texture; + SkPath* path; + SkPaint* paint; + }; + + virtual bool threadLoop(); + + // Lock for the list of tasks + Mutex mLock; + Vector<Task> mTasks; + + // Signal used to wake up the thread when a new + // task is available in the list + mutable Signal mSignal; + }; + + sp<PrecacheThread> mThread; Vector<SkPath*> mGarbage; mutable Mutex mLock; }; // class PathCache diff --git a/libs/hwui/ShapeCache.h b/libs/hwui/ShapeCache.h index 47cab83..67ae85b 100644 --- a/libs/hwui/ShapeCache.h +++ b/libs/hwui/ShapeCache.h @@ -17,6 +17,8 @@ #ifndef ANDROID_HWUI_SHAPE_CACHE_H #define ANDROID_HWUI_SHAPE_CACHE_H +#define ATRACE_TAG ATRACE_TAG_VIEW + #include <GLES2/gl2.h> #include <SkBitmap.h> @@ -27,10 +29,13 @@ #include <utils/JenkinsHash.h> #include <utils/LruCache.h> +#include <utils/Trace.h> +#include <utils/CallStack.h> #include "Debug.h" #include "Properties.h" #include "Texture.h" +#include "thread/Future.h" namespace android { namespace uirenderer { @@ -57,6 +62,16 @@ struct PathTexture: public Texture { PathTexture(): Texture() { } + PathTexture(bool hasFuture): Texture() { + if (hasFuture) { + mFuture = new Future<SkBitmap*>(); + } + } + + ~PathTexture() { + clearFuture(); + } + /** * Left coordinate of the path bounds. */ @@ -69,6 +84,20 @@ struct PathTexture: public Texture { * Offset to draw the path at the correct origin. */ float offset; + + sp<Future<SkBitmap*> > future() const { + return mFuture; + } + + void clearFuture() { + if (mFuture != NULL) { + delete mFuture->get(); + mFuture.clear(); + } + } + +private: + sp<Future<SkBitmap*> > mFuture; }; // struct PathTexture /** @@ -449,6 +478,52 @@ public: */ uint32_t getSize(); + /** + * Trims the contents of the cache, removing items until it's under its + * specified limit. + * + * Trimming is used for caches that support pre-caching from a worker + * thread. During pre-caching the maximum limit of the cache can be + * exceeded for the duration of the frame. It is therefore required to + * trim the cache at the end of the frame to keep the total amount of + * memory used under control. + * + * Only the PathCache currently supports pre-caching. + */ + void trim(); + + static void computePathBounds(const SkPath* path, const SkPaint* paint, + float& left, float& top, float& offset, uint32_t& width, uint32_t& height) { + const SkRect& bounds = path->getBounds(); + computeBounds(bounds, paint, left, top, offset, width, height); + } + + static void computeBounds(const SkRect& bounds, const SkPaint* paint, + float& left, float& top, float& offset, uint32_t& width, uint32_t& height) { + const float pathWidth = fmax(bounds.width(), 1.0f); + const float pathHeight = fmax(bounds.height(), 1.0f); + + left = bounds.fLeft; + top = bounds.fTop; + + offset = (int) floorf(fmax(paint->getStrokeWidth(), 1.0f) * 1.5f + 0.5f); + + width = uint32_t(pathWidth + offset * 2.0 + 0.5); + height = uint32_t(pathHeight + offset * 2.0 + 0.5); + } + + static void drawPath(const SkPath *path, const SkPaint* paint, SkBitmap& bitmap, + float left, float top, float offset, uint32_t width, uint32_t height) { + initBitmap(bitmap, width, height); + + SkPaint pathPaint(*paint); + initPaint(pathPaint); + + SkCanvas canvas(bitmap); + canvas.translate(-left + offset, -top + offset); + canvas.drawPath(*path, pathPaint); + } + protected: PathTexture* addTexture(const Entry& entry, const SkPath *path, const SkPaint* paint); PathTexture* addTexture(const Entry& entry, SkBitmap* bitmap); @@ -460,17 +535,51 @@ protected: */ void purgeCache(uint32_t width, uint32_t height); - void initBitmap(SkBitmap& bitmap, uint32_t width, uint32_t height); - void initPaint(SkPaint& paint); - - bool checkTextureSize(uint32_t width, uint32_t height); - PathTexture* get(Entry entry) { return mCache.get(entry); } void removeTexture(PathTexture* texture); + bool checkTextureSize(uint32_t width, uint32_t height) { + if (width > mMaxTextureSize || height > mMaxTextureSize) { + ALOGW("Shape %s too large to be rendered into a texture (%dx%d, max=%dx%d)", + mName, width, height, mMaxTextureSize, mMaxTextureSize); + return false; + } + return true; + } + + static PathTexture* createTexture(float left, float top, float offset, + uint32_t width, uint32_t height, uint32_t id, bool hasFuture = false) { + PathTexture* texture = new PathTexture(hasFuture); + texture->left = left; + texture->top = top; + texture->offset = offset; + texture->width = width; + texture->height = height; + texture->generation = id; + return texture; + } + + static void initBitmap(SkBitmap& bitmap, uint32_t width, uint32_t height) { + bitmap.setConfig(SkBitmap::kA8_Config, width, height); + bitmap.allocPixels(); + bitmap.eraseColor(0); + } + + static void initPaint(SkPaint& paint) { + // Make sure the paint is opaque, color, alpha, filter, etc. + // will be applied later when compositing the alpha8 texture + paint.setColor(0xff000000); + paint.setAlpha(255); + paint.setColorFilter(NULL); + paint.setMaskFilter(NULL); + paint.setShader(NULL); + SkXfermode* mode = SkXfermode::Create(SkXfermode::kSrc_Mode); + SkSafeUnref(paint.setXfermode(mode)); + } + LruCache<Entry, PathTexture*> mCache; uint32_t mSize; uint32_t mMaxSize; @@ -617,23 +726,6 @@ void ShapeCache<Entry>::removeTexture(PathTexture* texture) { } } -void computePathBounds(const SkPath* path, const SkPaint* paint, - float& left, float& top, float& offset, uint32_t& width, uint32_t& height); -void computeBounds(const SkRect& bounds, const SkPaint* paint, - float& left, float& top, float& offset, uint32_t& width, uint32_t& height); - -static PathTexture* createTexture(float left, float top, float offset, - uint32_t width, uint32_t height, uint32_t id) { - PathTexture* texture = new PathTexture; - texture->left = left; - texture->top = top; - texture->offset = offset; - texture->width = width; - texture->height = height; - texture->generation = id; - return texture; -} - template<class Entry> void ShapeCache<Entry>::purgeCache(uint32_t width, uint32_t height) { const uint32_t size = width * height; @@ -646,38 +738,16 @@ void ShapeCache<Entry>::purgeCache(uint32_t width, uint32_t height) { } template<class Entry> -void ShapeCache<Entry>::initBitmap(SkBitmap& bitmap, uint32_t width, uint32_t height) { - bitmap.setConfig(SkBitmap::kA8_Config, width, height); - bitmap.allocPixels(); - bitmap.eraseColor(0); -} - -template<class Entry> -void ShapeCache<Entry>::initPaint(SkPaint& paint) { - // Make sure the paint is opaque, color, alpha, filter, etc. - // will be applied later when compositing the alpha8 texture - paint.setColor(0xff000000); - paint.setAlpha(255); - paint.setColorFilter(NULL); - paint.setMaskFilter(NULL); - paint.setShader(NULL); - SkXfermode* mode = SkXfermode::Create(SkXfermode::kSrc_Mode); - SkSafeUnref(paint.setXfermode(mode)); -} - -template<class Entry> -bool ShapeCache<Entry>::checkTextureSize(uint32_t width, uint32_t height) { - if (width > mMaxTextureSize || height > mMaxTextureSize) { - ALOGW("Shape %s too large to be rendered into a texture (%dx%d, max=%dx%d)", - mName, width, height, mMaxTextureSize, mMaxTextureSize); - return false; +void ShapeCache<Entry>::trim() { + while (mSize > mMaxSize) { + mCache.removeOldest(); } - return true; } template<class Entry> PathTexture* ShapeCache<Entry>::addTexture(const Entry& entry, const SkPath *path, const SkPaint* paint) { + ATRACE_CALL(); float left, top, offset; uint32_t width, height; @@ -688,16 +758,10 @@ PathTexture* ShapeCache<Entry>::addTexture(const Entry& entry, const SkPath *pat purgeCache(width, height); SkBitmap bitmap; - initBitmap(bitmap, width, height); - - SkPaint pathPaint(*paint); - initPaint(pathPaint); - - SkCanvas canvas(bitmap); - canvas.translate(-left + offset, -top + offset); - canvas.drawPath(*path, pathPaint); + drawPath(path, paint, bitmap, left, top, offset, width, height); - PathTexture* texture = createTexture(left, top, offset, width, height, path->getGenerationID()); + PathTexture* texture = createTexture(left, top, offset, width, height, + path->getGenerationID()); addTexture(entry, &bitmap, texture); return texture; diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp index 5cff5a5..2378eb5 100644 --- a/libs/hwui/TextureCache.cpp +++ b/libs/hwui/TextureCache.cpp @@ -20,7 +20,7 @@ #include <SkCanvas.h> -#include <utils/threads.h> +#include <utils/Mutex.h> #include "Caches.h" #include "TextureCache.h" diff --git a/libs/hwui/thread/Barrier.h b/libs/hwui/thread/Barrier.h new file mode 100644 index 0000000..6cb23e5 --- /dev/null +++ b/libs/hwui/thread/Barrier.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2013 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. + */ + +#ifndef ANDROID_HWUI_BARRIER_H +#define ANDROID_HWUI_BARRIER_H + +#include <utils/Condition.h> + +namespace android { +namespace uirenderer { + +class Barrier { +public: + Barrier(Condition::WakeUpType type = Condition::WAKE_UP_ALL) : mType(type), mOpened(false) { } + ~Barrier() { } + + void open() { + Mutex::Autolock l(mLock); + mOpened = true; + mCondition.signal(mType); + } + + void close() { + Mutex::Autolock l(mLock); + mOpened = false; + } + + void wait() const { + Mutex::Autolock l(mLock); + while (!mOpened) { + mCondition.wait(mLock); + } + } + +private: + Condition::WakeUpType mType; + volatile bool mOpened; + mutable Mutex mLock; + mutable Condition mCondition; +}; + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_HWUI_BARRIER_H diff --git a/libs/hwui/thread/Future.h b/libs/hwui/thread/Future.h new file mode 100644 index 0000000..340fec7 --- /dev/null +++ b/libs/hwui/thread/Future.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2013 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. + */ + +#ifndef ANDROID_HWUI_FUTURE_H +#define ANDROID_HWUI_FUTURE_H + +#include <utils/RefBase.h> + +#include "Barrier.h" + +namespace android { +namespace uirenderer { + +template<class T> +class Future: public LightRefBase<Future<T> > { +public: + Future(Condition::WakeUpType type = Condition::WAKE_UP_ONE): mBarrier(type), mResult() { } + ~Future() { } + + /** + * Returns the result of this future, blocking if + * the result is not available yet. + */ + T get() const { + mBarrier.wait(); + return mResult; + } + + /** + * This method must be called only once. + */ + void produce(T result) { + mResult = result; + mBarrier.open(); + } + +private: + Barrier mBarrier; + T mResult; +}; + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_HWUI_FUTURE_H diff --git a/libs/hwui/thread/Signal.h b/libs/hwui/thread/Signal.h new file mode 100644 index 0000000..dcf5449 --- /dev/null +++ b/libs/hwui/thread/Signal.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2013 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. + */ + +#ifndef ANDROID_HWUI_SIGNAL_H +#define ANDROID_HWUI_SIGNAL_H + +#include <stdint.h> +#include <sys/types.h> +#include <utils/threads.h> + +namespace android { +namespace uirenderer { + +class Signal { +public: + Signal(Condition::WakeUpType type = Condition::WAKE_UP_ALL) : mType(type), mSignaled(false) { } + ~Signal() { } + + void signal() { + Mutex::Autolock l(mLock); + mSignaled = true; + mCondition.signal(mType); + } + + void wait() { + Mutex::Autolock l(mLock); + while (!mSignaled) { + mCondition.wait(mLock); + } + mSignaled = false; + } + +private: + Condition::WakeUpType mType; + volatile bool mSignaled; + mutable Mutex mLock; + mutable Condition mCondition; +}; + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_HWUI_SIGNAL_H diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PathsCacheActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/PathsCacheActivity.java index 9ab2a86..ac8ab1f 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/PathsCacheActivity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/PathsCacheActivity.java @@ -45,13 +45,13 @@ public class PathsCacheActivity extends Activity { setContentView(view); } - private Path makePath() { + private static Path makePath() { Path path = new Path(); buildPath(path); return path; } - private void buildPath(Path path) { + private static void buildPath(Path path) { path.moveTo(0.0f, 0.0f); path.cubicTo(0.0f, 0.0f, 100.0f, 150.0f, 100.0f, 200.0f); path.cubicTo(100.0f, 200.0f, 50.0f, 300.0f, -80.0f, 200.0f); |