summaryrefslogtreecommitdiffstats
path: root/libs/hwui
diff options
context:
space:
mode:
Diffstat (limited to 'libs/hwui')
-rw-r--r--libs/hwui/Android.mk1
-rw-r--r--libs/hwui/Caches.h5
-rw-r--r--libs/hwui/PathCache.cpp109
-rw-r--r--libs/hwui/PathCache.h39
-rw-r--r--libs/hwui/ShapeCache.h32
-rw-r--r--libs/hwui/thread/Future.h2
-rw-r--r--libs/hwui/thread/Task.h63
-rw-r--r--libs/hwui/thread/TaskManager.cpp118
-rw-r--r--libs/hwui/thread/TaskManager.h100
-rw-r--r--libs/hwui/thread/TaskProcessor.h72
10 files changed, 436 insertions, 105 deletions
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 85b2052..1618110 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -7,6 +7,7 @@ ifeq ($(USE_OPENGL_RENDERER),true)
LOCAL_SRC_FILES:= \
utils/Blur.cpp \
utils/SortedListImpl.cpp \
+ thread/TaskManager.cpp \
font/CacheTexture.cpp \
font/Font.cpp \
FontRenderer.cpp \
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index ca699d5..dc32a7e 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -25,6 +25,9 @@
#include <cutils/compiler.h>
+#include "thread/TaskProcessor.h"
+#include "thread/TaskManager.h"
+
#include "FontRenderer.h"
#include "GammaFontRenderer.h"
#include "TextureCache.h"
@@ -278,6 +281,8 @@ public:
GammaFontRenderer* fontRenderer;
+ TaskManager tasks;
+
Dither dither;
Stencil stencil;
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp
index 9e6ec84..afdc2c9 100644
--- a/libs/hwui/PathCache.cpp
+++ b/libs/hwui/PathCache.cpp
@@ -31,69 +31,32 @@ namespace uirenderer {
// 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;
-
- 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;
+PathCache::PathProcessor::PathProcessor(Caches& caches):
+ TaskProcessor<SkBitmap*>(&caches.tasks), mMaxTextureSize(caches.maxTextureSize) {
}
-void PathCache::PrecacheThread::addTask(PathTexture* texture, SkPath* path, SkPaint* paint) {
- if (!isRunning()) {
- run("libhwui:pathPrecache", PRIORITY_DEFAULT);
- }
-
- Task task;
- task.texture = texture;
- task.path = path;
- task.paint = paint;
-
- Mutex::Autolock l(mLock);
- mTasks.add(task);
- mSignal.signal();
-}
-
-void PathCache::PrecacheThread::exit() {
- {
- Mutex::Autolock l(mLock);
- mTasks.clear();
+void PathCache::PathProcessor::onProcess(const sp<Task<SkBitmap*> >& task) {
+ sp<PathTask> t = static_cast<PathTask* >(task.get());
+ ATRACE_NAME("pathPrecache");
+
+ float left, top, offset;
+ uint32_t width, height;
+ PathCache::computePathBounds(t->path, t->paint, left, top, offset, width, height);
+
+ PathTexture* texture = t->texture;
+ texture->left = left;
+ texture->top = top;
+ texture->offset = offset;
+ texture->width = width;
+ texture->height = height;
+
+ if (width <= mMaxTextureSize && height <= mMaxTextureSize) {
+ SkBitmap* bitmap = new SkBitmap();
+ PathCache::drawPath(t->path, t->paint, *bitmap, left, top, offset, width, height);
+ t->setResult(bitmap);
+ } else {
+ t->setResult(NULL);
}
- requestExit();
- mSignal.signal();
}
///////////////////////////////////////////////////////////////////////////////
@@ -101,11 +64,10 @@ void PathCache::PrecacheThread::exit() {
///////////////////////////////////////////////////////////////////////////////
PathCache::PathCache(): ShapeCache<PathCacheEntry>("path",
- PROPERTY_PATH_CACHE_SIZE, DEFAULT_PATH_CACHE_SIZE), mThread(new PrecacheThread()) {
+ PROPERTY_PATH_CACHE_SIZE, DEFAULT_PATH_CACHE_SIZE) {
}
PathCache::~PathCache() {
- mThread->exit();
}
void PathCache::remove(SkPath* path) {
@@ -165,17 +127,18 @@ PathTexture* PathCache::get(SkPath* path, SkPaint* paint) {
} else {
// A bitmap is attached to the texture, this means we need to
// upload it as a GL texture
- if (texture->future() != NULL) {
+ const sp<Task<SkBitmap*> >& task = texture->task();
+ if (task != 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();
+ SkBitmap* bitmap = task->getResult();
if (bitmap) {
addTexture(entry, bitmap, texture);
- texture->clearFuture();
+ texture->clearTask();
} else {
ALOGW("Path too large to be rendered into a texture (%dx%d)",
texture->width, texture->height);
- texture->clearFuture();
+ texture->clearTask();
texture = NULL;
mCache.remove(entry);
}
@@ -189,6 +152,10 @@ PathTexture* PathCache::get(SkPath* path, SkPaint* paint) {
}
void PathCache::precache(SkPath* path, SkPaint* paint) {
+ if (!Caches::getInstance().tasks.canRunTasks()) {
+ return;
+ }
+
path = getSourcePath(path);
PathCacheEntry entry(path, paint);
@@ -205,7 +172,9 @@ void PathCache::precache(SkPath* path, SkPaint* paint) {
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);
+ texture = createTexture(0.0f, 0.0f, 0.0f, 0, 0, path->getGenerationID());
+ sp<PathTask> task = new PathTask(path, paint, texture);
+ texture->setTask(task);
// During the precaching phase we insert path texture objects into
// the cache that do not point to any GL texture. They are instead
@@ -215,7 +184,11 @@ void PathCache::precache(SkPath* path, SkPaint* paint) {
// asks for a path texture. This is also when the cache limit will
// be enforced.
mCache.put(entry, texture);
- mThread->addTask(texture, path, paint);
+
+ if (mProcessor == NULL) {
+ mProcessor = new PathProcessor(Caches::getInstance());
+ }
+ mProcessor->add(task);
}
}
diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h
index 1d28ecb..27031a5 100644
--- a/libs/hwui/PathCache.h
+++ b/libs/hwui/PathCache.h
@@ -23,6 +23,8 @@
#include "Debug.h"
#include "ShapeCache.h"
#include "thread/Signal.h"
+#include "thread/Task.h"
+#include "thread/TaskProcessor.h"
class SkPaint;
class SkPath;
@@ -100,32 +102,33 @@ public:
void precache(SkPath* path, SkPaint* paint);
private:
- class PrecacheThread: public Thread {
+ class PathTask: public Task<SkBitmap*> {
public:
- PrecacheThread(): mSignal(Condition::WAKE_UP_ONE) { }
+ PathTask(SkPath* path, SkPaint* paint, PathTexture* texture):
+ path(path), paint(paint), texture(texture) {
+ }
- void addTask(PathTexture* texture, SkPath* path, SkPaint* paint);
- void exit();
+ ~PathTask() {
+ delete future()->get();
+ }
- private:
- struct Task {
- PathTexture* texture;
- SkPath* path;
- SkPaint* paint;
- };
+ SkPath* path;
+ SkPaint* paint;
+ PathTexture* texture;
+ };
- virtual bool threadLoop();
+ class PathProcessor: public TaskProcessor<SkBitmap*> {
+ public:
+ PathProcessor(Caches& caches);
+ ~PathProcessor() { }
- // Lock for the list of tasks
- Mutex mLock;
- Vector<Task> mTasks;
+ virtual void onProcess(const sp<Task<SkBitmap*> >& task);
- // Signal used to wake up the thread when a new
- // task is available in the list
- mutable Signal mSignal;
+ private:
+ uint32_t mMaxTextureSize;
};
- sp<PrecacheThread> mThread;
+ sp<PathProcessor> mProcessor;
Vector<SkPath*> mGarbage;
mutable Mutex mLock;
}; // class PathCache
diff --git a/libs/hwui/ShapeCache.h b/libs/hwui/ShapeCache.h
index 67ae85b..58fea08 100644
--- a/libs/hwui/ShapeCache.h
+++ b/libs/hwui/ShapeCache.h
@@ -30,12 +30,11 @@
#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"
+#include "thread/Task.h"
namespace android {
namespace uirenderer {
@@ -62,14 +61,8 @@ struct PathTexture: public Texture {
PathTexture(): Texture() {
}
- PathTexture(bool hasFuture): Texture() {
- if (hasFuture) {
- mFuture = new Future<SkBitmap*>();
- }
- }
-
~PathTexture() {
- clearFuture();
+ clearTask();
}
/**
@@ -85,19 +78,22 @@ struct PathTexture: public Texture {
*/
float offset;
- sp<Future<SkBitmap*> > future() const {
- return mFuture;
+ sp<Task<SkBitmap*> > task() const {
+ return mTask;
+ }
+
+ void setTask(const sp<Task<SkBitmap*> >& task) {
+ mTask = task;
}
- void clearFuture() {
- if (mFuture != NULL) {
- delete mFuture->get();
- mFuture.clear();
+ void clearTask() {
+ if (mTask != NULL) {
+ mTask.clear();
}
}
private:
- sp<Future<SkBitmap*> > mFuture;
+ sp<Task<SkBitmap*> > mTask;
}; // struct PathTexture
/**
@@ -551,8 +547,8 @@ protected:
}
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);
+ uint32_t width, uint32_t height, uint32_t id) {
+ PathTexture* texture = new PathTexture();
texture->left = left;
texture->top = top;
texture->offset = offset;
diff --git a/libs/hwui/thread/Future.h b/libs/hwui/thread/Future.h
index 340fec7..a3ff3bc 100644
--- a/libs/hwui/thread/Future.h
+++ b/libs/hwui/thread/Future.h
@@ -24,7 +24,7 @@
namespace android {
namespace uirenderer {
-template<class T>
+template<typename T>
class Future: public LightRefBase<Future<T> > {
public:
Future(Condition::WakeUpType type = Condition::WAKE_UP_ONE): mBarrier(type), mResult() { }
diff --git a/libs/hwui/thread/Task.h b/libs/hwui/thread/Task.h
new file mode 100644
index 0000000..9a211a2
--- /dev/null
+++ b/libs/hwui/thread/Task.h
@@ -0,0 +1,63 @@
+/*
+ * 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_TASK_H
+#define ANDROID_HWUI_TASK_H
+
+#define ATRACE_TAG ATRACE_TAG_VIEW
+
+#include <utils/RefBase.h>
+#include <utils/Trace.h>
+
+#include "Future.h"
+
+namespace android {
+namespace uirenderer {
+
+class TaskBase: public RefBase {
+public:
+ TaskBase() { }
+ virtual ~TaskBase() { }
+};
+
+template<typename T>
+class Task: public TaskBase {
+public:
+ Task(): mFuture(new Future<T>()) { }
+ virtual ~Task() { }
+
+ T getResult() const {
+ ATRACE_NAME("waitForTask");
+ return mFuture->get();
+ }
+
+ void setResult(T result) {
+ mFuture->produce(result);
+ }
+
+protected:
+ const sp<Future<T> >& future() const {
+ return mFuture;
+ }
+
+private:
+ sp<Future<T> > mFuture;
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_TASK_H
diff --git a/libs/hwui/thread/TaskManager.cpp b/libs/hwui/thread/TaskManager.cpp
new file mode 100644
index 0000000..ce6c8c0
--- /dev/null
+++ b/libs/hwui/thread/TaskManager.cpp
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ */
+
+#include <sys/sysinfo.h>
+
+#include "Task.h"
+#include "TaskProcessor.h"
+#include "TaskManager.h"
+
+namespace android {
+namespace uirenderer {
+
+///////////////////////////////////////////////////////////////////////////////
+// Manager
+///////////////////////////////////////////////////////////////////////////////
+
+TaskManager::TaskManager() {
+ // Get the number of available CPUs. This value does not change over time.
+ int cpuCount = sysconf(_SC_NPROCESSORS_ONLN);
+
+ for (int i = 0; i < cpuCount / 2; i++) {
+ String8 name;
+ name.appendFormat("hwuiTask%d", i + 1);
+ mThreads.add(new WorkerThread(name));
+ }
+}
+
+TaskManager::~TaskManager() {
+ for (size_t i = 0; i < mThreads.size(); i++) {
+ mThreads[i]->exit();
+ }
+}
+
+bool TaskManager::canRunTasks() const {
+ return mThreads.size() > 0;
+}
+
+bool TaskManager::addTaskBase(const sp<TaskBase>& task, const sp<TaskProcessorBase>& processor) {
+ if (mThreads.size() > 0) {
+ TaskWrapper wrapper(task, processor);
+
+ size_t minQueueSize = INT_MAX;
+ sp<WorkerThread> thread;
+
+ for (size_t i = 0; i < mThreads.size(); i++) {
+ if (mThreads[i]->getTaskCount() < minQueueSize) {
+ thread = mThreads[i];
+ minQueueSize = mThreads[i]->getTaskCount();
+ }
+ }
+
+ return thread->addTask(wrapper);
+ }
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Thread
+///////////////////////////////////////////////////////////////////////////////
+
+bool TaskManager::WorkerThread::threadLoop() {
+ mSignal.wait();
+ Vector<TaskWrapper> tasks;
+ {
+ Mutex::Autolock l(mLock);
+ tasks = mTasks;
+ mTasks.clear();
+ }
+
+ for (size_t i = 0; i < tasks.size(); i++) {
+ const TaskWrapper& task = tasks.itemAt(i);
+ task.mProcessor->process(task.mTask);
+ }
+
+ return true;
+}
+
+bool TaskManager::WorkerThread::addTask(TaskWrapper task) {
+ if (!isRunning()) {
+ run(mName.string(), PRIORITY_DEFAULT);
+ }
+
+ Mutex::Autolock l(mLock);
+ ssize_t index = mTasks.add(task);
+ mSignal.signal();
+
+ return index >= 0;
+}
+
+size_t TaskManager::WorkerThread::getTaskCount() const {
+ Mutex::Autolock l(mLock);
+ return mTasks.size();
+}
+
+void TaskManager::WorkerThread::exit() {
+ {
+ Mutex::Autolock l(mLock);
+ mTasks.clear();
+ }
+ requestExit();
+ mSignal.signal();
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/thread/TaskManager.h b/libs/hwui/thread/TaskManager.h
new file mode 100644
index 0000000..bc86062
--- /dev/null
+++ b/libs/hwui/thread/TaskManager.h
@@ -0,0 +1,100 @@
+/*
+ * 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_TASK_MANAGER_H
+#define ANDROID_HWUI_TASK_MANAGER_H
+
+#include <utils/Mutex.h>
+#include <utils/String8.h>
+#include <utils/Thread.h>
+#include <utils/Vector.h>
+
+#include "Signal.h"
+
+namespace android {
+namespace uirenderer {
+
+template <typename T>
+class Task;
+class TaskBase;
+
+template <typename T>
+class TaskProcessor;
+class TaskProcessorBase;
+
+class TaskManager {
+public:
+ TaskManager();
+ ~TaskManager();
+
+ /**
+ * Returns true if this task manager can run tasks,
+ * false otherwise. This method will typically return
+ * true on a single CPU core device.
+ */
+ bool canRunTasks() const;
+
+private:
+ template <typename T>
+ friend class TaskProcessor;
+
+ template<typename T>
+ bool addTask(const sp<Task<T> >& task, const sp<TaskProcessor<T> >& processor) {
+ return addTaskBase(sp<TaskBase>(task), sp<TaskProcessorBase>(processor));
+ }
+
+ bool addTaskBase(const sp<TaskBase>& task, const sp<TaskProcessorBase>& processor);
+
+ struct TaskWrapper {
+ TaskWrapper(): mTask(), mProcessor() { }
+
+ TaskWrapper(const sp<TaskBase>& task, const sp<TaskProcessorBase>& processor):
+ mTask(task), mProcessor(processor) {
+ }
+
+ sp<TaskBase> mTask;
+ sp<TaskProcessorBase> mProcessor;
+ };
+
+ class WorkerThread: public Thread {
+ public:
+ WorkerThread(const String8 name): mSignal(Condition::WAKE_UP_ONE), mName(name) { }
+
+ bool addTask(TaskWrapper task);
+ size_t getTaskCount() const;
+ void exit();
+
+ private:
+ virtual bool threadLoop();
+
+ // Lock for the list of tasks
+ mutable Mutex mLock;
+ Vector<TaskWrapper> mTasks;
+
+ // Signal used to wake up the thread when a new
+ // task is available in the list
+ mutable Signal mSignal;
+
+ const String8 mName;
+ };
+
+ Vector<sp<WorkerThread> > mThreads;
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_TASK_MANAGER_H
diff --git a/libs/hwui/thread/TaskProcessor.h b/libs/hwui/thread/TaskProcessor.h
new file mode 100644
index 0000000..d1269f0
--- /dev/null
+++ b/libs/hwui/thread/TaskProcessor.h
@@ -0,0 +1,72 @@
+/*
+ * 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_TASK_PROCESSOR_H
+#define ANDROID_HWUI_TASK_PROCESSOR_H
+
+#include <utils/RefBase.h>
+
+#include "Task.h"
+#include "TaskManager.h"
+
+namespace android {
+namespace uirenderer {
+
+class TaskProcessorBase: public RefBase {
+public:
+ TaskProcessorBase() { }
+ virtual ~TaskProcessorBase() { };
+
+private:
+ friend class TaskManager;
+
+ virtual void process(const sp<TaskBase>& task) = 0;
+};
+
+template<typename T>
+class TaskProcessor: public TaskProcessorBase {
+public:
+ TaskProcessor(TaskManager* manager): mManager(manager) { }
+ virtual ~TaskProcessor() { }
+
+ bool add(const sp<Task<T> >& task);
+
+ virtual void onProcess(const sp<Task<T> >& task) = 0;
+
+private:
+ virtual void process(const sp<TaskBase>& task) {
+ sp<Task<T> > realTask = static_cast<Task<T>* >(task.get());
+ // This is the right way to do it but sp<> doesn't play nice
+ // sp<Task<T> > realTask = static_cast<sp<Task<T> > >(task);
+ onProcess(realTask);
+ }
+
+ TaskManager* mManager;
+};
+
+template<typename T>
+bool TaskProcessor<T>::add(const sp<Task<T> >& task) {
+ if (mManager) {
+ sp<TaskProcessor<T> > self(this);
+ return mManager->addTask(task, self);
+ }
+ return false;
+}
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_TASK_PROCESSOR_H