summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRomain Guy <romainguy@google.com>2013-03-08 17:44:20 -0800
committerRomain Guy <romainguy@google.com>2013-03-11 17:05:28 -0700
commitca89e2a68703bd428e8b66547d033a6ed35b3595 (patch)
tree5661de81848f7d26559531a1ea650ed7fea2decd
parent6e2004089305cf2cd958b52b234459a49a4e5c83 (diff)
downloadframeworks_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.h7
-rw-r--r--libs/hwui/GradientCache.cpp1
-rw-r--r--libs/hwui/OpenGLRenderer.cpp6
-rw-r--r--libs/hwui/PathCache.cpp162
-rw-r--r--libs/hwui/PathCache.h36
-rw-r--r--libs/hwui/ShapeCache.h178
-rw-r--r--libs/hwui/TextureCache.cpp2
-rw-r--r--libs/hwui/thread/Barrier.h58
-rw-r--r--libs/hwui/thread/Future.h58
-rw-r--r--libs/hwui/thread/Signal.h56
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/PathsCacheActivity.java4
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);