summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/hwui/Android.mk1
-rw-r--r--libs/hwui/DisplayListRenderer.cpp29
-rw-r--r--libs/hwui/DisplayListRenderer.h69
-rw-r--r--libs/hwui/FontRenderer.h2
-rw-r--r--libs/hwui/LayerRenderer.cpp2
-rw-r--r--libs/hwui/LayerRenderer.h2
-rw-r--r--libs/hwui/OpenGLRenderer.cpp285
-rw-r--r--libs/hwui/OpenGLRenderer.h78
-rw-r--r--libs/hwui/Renderer.h21
-rw-r--r--libs/hwui/StatefulBaseRenderer.cpp206
-rw-r--r--libs/hwui/StatefulBaseRenderer.h137
11 files changed, 492 insertions, 340 deletions
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 962d726..9d31232 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -42,6 +42,7 @@ ifeq ($(USE_OPENGL_RENDERER),true)
SkiaColorFilter.cpp \
SkiaShader.cpp \
Snapshot.cpp \
+ StatefulBaseRenderer.cpp \
Stencil.cpp \
Texture.cpp \
TextureCache.cpp \
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 31a7db6..9c5db6e 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -120,19 +120,14 @@ void DisplayListRenderer::setViewport(int width, int height) {
// TODO: DisplayListRenderer shouldn't have a projection matrix, as it should never be used
mViewProjMatrix.loadOrtho(0, width, height, 0, -1, 1);
- mWidth = width;
- mHeight = height;
+ initializeViewport(width, height);
}
status_t DisplayListRenderer::prepareDirty(float left, float top,
float right, float bottom, bool opaque) {
- mSnapshot = new Snapshot(mFirstSnapshot,
- SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
- mSaveCount = 1;
+ initializeSaveStack(0, 0, getWidth(), getHeight());
- mSnapshot->setClip(0.0f, 0.0f, mWidth, mHeight);
mDirtyClip = opaque;
-
mRestoreSaveCount = -1;
return DrawGlInfo::kStatusDone; // No invalidate needed at record-time
@@ -158,7 +153,7 @@ status_t DisplayListRenderer::callDrawGLFunction(Functor *functor, Rect& dirty)
int DisplayListRenderer::save(int flags) {
addStateOp(new (alloc()) SaveOp(flags));
- return OpenGLRenderer::save(flags);
+ return StatefulBaseRenderer::save(flags);
}
void DisplayListRenderer::restore() {
@@ -169,19 +164,19 @@ void DisplayListRenderer::restore() {
mRestoreSaveCount--;
insertTranslate();
- OpenGLRenderer::restore();
+ StatefulBaseRenderer::restore();
}
void DisplayListRenderer::restoreToCount(int saveCount) {
mRestoreSaveCount = saveCount;
insertTranslate();
- OpenGLRenderer::restoreToCount(saveCount);
+ StatefulBaseRenderer::restoreToCount(saveCount);
}
int DisplayListRenderer::saveLayer(float left, float top, float right, float bottom,
int alpha, SkXfermode::Mode mode, int flags) {
addStateOp(new (alloc()) SaveLayerOp(left, top, right, bottom, alpha, mode, flags));
- return OpenGLRenderer::save(flags);
+ return StatefulBaseRenderer::save(flags);
}
void DisplayListRenderer::translate(float dx, float dy, float dz) {
@@ -190,34 +185,34 @@ void DisplayListRenderer::translate(float dx, float dy, float dz) {
mTranslateX += dx;
mTranslateY += dy;
insertRestoreToCount();
- OpenGLRenderer::translate(dx, dy, dz);
+ StatefulBaseRenderer::translate(dx, dy, dz);
}
void DisplayListRenderer::rotate(float degrees) {
addStateOp(new (alloc()) RotateOp(degrees));
- OpenGLRenderer::rotate(degrees);
+ StatefulBaseRenderer::rotate(degrees);
}
void DisplayListRenderer::scale(float sx, float sy) {
addStateOp(new (alloc()) ScaleOp(sx, sy));
- OpenGLRenderer::scale(sx, sy);
+ StatefulBaseRenderer::scale(sx, sy);
}
void DisplayListRenderer::skew(float sx, float sy) {
addStateOp(new (alloc()) SkewOp(sx, sy));
- OpenGLRenderer::skew(sx, sy);
+ StatefulBaseRenderer::skew(sx, sy);
}
void DisplayListRenderer::setMatrix(SkMatrix* matrix) {
matrix = refMatrix(matrix);
addStateOp(new (alloc()) SetMatrixOp(matrix));
- OpenGLRenderer::setMatrix(matrix);
+ StatefulBaseRenderer::setMatrix(matrix);
}
void DisplayListRenderer::concatMatrix(SkMatrix* matrix) {
matrix = refMatrix(matrix);
addStateOp(new (alloc()) ConcatMatrixOp(matrix));
- OpenGLRenderer::concatMatrix(matrix);
+ StatefulBaseRenderer::concatMatrix(matrix);
}
bool DisplayListRenderer::clipRect(float left, float top, float right, float bottom,
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index b6244e4..b5d9924 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -65,22 +65,26 @@ public:
virtual bool isRecording() { return true; }
+// ----------------------------------------------------------------------------
+// Frame state operations
+// ----------------------------------------------------------------------------
virtual void setViewport(int width, int height);
virtual status_t prepareDirty(float left, float top, float right, float bottom, bool opaque);
virtual void finish();
-
- virtual status_t callDrawGLFunction(Functor *functor, Rect& dirty);
-
virtual void interrupt();
virtual void resume();
+// ----------------------------------------------------------------------------
+// Canvas state operations
+// ----------------------------------------------------------------------------
+ // Save (layer)
virtual int save(int flags);
virtual void restore();
virtual void restoreToCount(int saveCount);
-
virtual int saveLayer(float left, float top, float right, float bottom,
int alpha, SkXfermode::Mode mode, int flags);
+ // Matrix
virtual void translate(float dx, float dy, float dz);
virtual void rotate(float degrees);
virtual void scale(float sx, float sy);
@@ -89,12 +93,30 @@ public:
virtual void setMatrix(SkMatrix* matrix);
virtual void concatMatrix(SkMatrix* matrix);
+ // Clip
virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
virtual bool clipPath(SkPath* path, SkRegion::Op op);
virtual bool clipRegion(SkRegion* region, SkRegion::Op op);
- virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t flags);
- virtual status_t drawLayer(Layer* layer, float x, float y);
+ // Misc - should be implemented with SkPaint inspection
+ virtual void resetShader();
+ virtual void setupShader(SkiaShader* shader);
+
+ virtual void resetColorFilter();
+ virtual void setupColorFilter(SkiaColorFilter* filter);
+
+ virtual void resetShadow();
+ virtual void setupShadow(float radius, float dx, float dy, int color);
+
+ virtual void resetPaintFilter();
+ virtual void setupPaintFilter(int clearBits, int setBits);
+
+// ----------------------------------------------------------------------------
+// Canvas draw operations
+// ----------------------------------------------------------------------------
+ virtual status_t drawColor(int color, SkXfermode::Mode mode);
+
+ // Bitmap-based
virtual status_t drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
virtual status_t drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
virtual status_t drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
@@ -105,8 +127,10 @@ public:
float* vertices, int* colors, SkPaint* paint);
virtual status_t drawPatch(SkBitmap* bitmap, Res_png_9patch* patch,
float left, float top, float right, float bottom, SkPaint* paint);
- virtual status_t drawColor(int color, SkXfermode::Mode mode);
+
+ // Shapes
virtual status_t drawRect(float left, float top, float right, float bottom, SkPaint* paint);
+ virtual status_t drawRects(const float* rects, int count, SkPaint* paint);
virtual status_t drawRoundRect(float left, float top, float right, float bottom,
float rx, float ry, SkPaint* paint);
virtual status_t drawCircle(float x, float y, float radius, SkPaint* paint);
@@ -116,28 +140,29 @@ public:
virtual status_t drawPath(SkPath* path, SkPaint* paint);
virtual status_t drawLines(float* points, int count, SkPaint* paint);
virtual status_t drawPoints(float* points, int count, SkPaint* paint);
+
+ // Text
+ virtual status_t drawText(const char* text, int bytesCount, int count, float x, float y,
+ const float* positions, SkPaint* paint, float totalAdvance, const Rect& bounds,
+ DrawOpMode drawOpMode = kDrawOpMode_Immediate);
virtual status_t drawTextOnPath(const char* text, int bytesCount, int count, SkPath* path,
float hOffset, float vOffset, SkPaint* paint);
virtual status_t drawPosText(const char* text, int bytesCount, int count,
const float* positions, SkPaint* paint);
- virtual status_t drawText(const char* text, int bytesCount, int count, float x, float y,
- const float* positions, SkPaint* paint, float totalAdvance, const Rect& bounds,
- DrawOpMode drawOpMode);
-
- virtual status_t drawRects(const float* rects, int count, SkPaint* paint);
- virtual void resetShader();
- virtual void setupShader(SkiaShader* shader);
-
- virtual void resetColorFilter();
- virtual void setupColorFilter(SkiaColorFilter* filter);
-
- virtual void resetShadow();
- virtual void setupShadow(float radius, float dx, float dy, int color);
+// ----------------------------------------------------------------------------
+// Canvas draw operations - special
+// ----------------------------------------------------------------------------
+ virtual status_t drawLayer(Layer* layer, float x, float y);
+ virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty,
+ int32_t replayFlags);
- virtual void resetPaintFilter();
- virtual void setupPaintFilter(int clearBits, int setBits);
+ // TODO: rename for consistency
+ virtual status_t callDrawGLFunction(Functor* functor, Rect& dirty);
+// ----------------------------------------------------------------------------
+// DisplayList / resource management
+// ----------------------------------------------------------------------------
ANDROID_API void reset();
sp<DisplayListData> getDisplayListData() const {
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index aa7e776..db4e020 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -44,8 +44,6 @@ namespace RSC {
}
#endif
-class Functor;
-
namespace android {
namespace uirenderer {
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index f8076cc..35fd46e 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -92,7 +92,7 @@ void LayerRenderer::finish() {
// who will invoke OpenGLRenderer::resume()
}
-GLint LayerRenderer::getTargetFbo() const {
+GLuint LayerRenderer::getTargetFbo() const {
return mLayer->getFbo();
}
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index 5f86731..f24c8d4 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -67,7 +67,7 @@ protected:
virtual void ensureStencilBuffer();
virtual bool hasLayer() const;
virtual Region* getRegion() const;
- virtual GLint getTargetFbo() const;
+ virtual GLuint getTargetFbo() const;
virtual bool suppressErrorChecks() const;
private:
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index c30d86f..a3a4432 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -129,7 +129,6 @@ OpenGLRenderer::OpenGLRenderer():
memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices));
- mFirstSnapshot = new Snapshot;
mFrameStarted = false;
mCountOverdraw = false;
@@ -182,24 +181,15 @@ void OpenGLRenderer::initViewport(int width, int height) {
mViewProjMatrix.loadOrtho(0, width, height, 0, -1, 1);
}
- mWidth = width;
- mHeight = height;
-
- mFirstSnapshot->height = height;
- mFirstSnapshot->viewport.set(0, 0, width, height);
+ initializeViewport(width, height);
}
void OpenGLRenderer::setupFrameState(float left, float top,
float right, float bottom, bool opaque) {
mCaches.clearGarbage();
+ initializeSaveStack(left, top, right, bottom);
mOpaque = opaque;
- mSnapshot = new Snapshot(mFirstSnapshot,
- SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
- mSnapshot->fbo = getTargetFbo();
- mSaveCount = 1;
-
- mSnapshot->setClip(left, top, right, bottom);
mTilingClip.set(left, top, right, bottom);
}
@@ -211,14 +201,14 @@ status_t OpenGLRenderer::startFrame() {
discardFramebuffer(mTilingClip.left, mTilingClip.top, mTilingClip.right, mTilingClip.bottom);
- glViewport(0, 0, mWidth, mHeight);
+ glViewport(0, 0, getWidth(), getHeight());
// Functors break the tiling extension in pretty spectacular ways
// This ensures we don't use tiling when a functor is going to be
// invoked during the frame
mSuppressTiling = mCaches.hasRegisteredFunctors();
- startTiling(mSnapshot, true);
+ startTiling(*mSnapshot, true);
debugOverdraw(true, true);
@@ -226,10 +216,6 @@ status_t OpenGLRenderer::startFrame() {
mTilingClip.right, mTilingClip.bottom, mOpaque);
}
-status_t OpenGLRenderer::prepare(bool opaque) {
- return prepareDirty(0.0f, 0.0f, mWidth, mHeight, opaque);
-}
-
status_t OpenGLRenderer::prepareDirty(float left, float top,
float right, float bottom, bool opaque) {
@@ -239,7 +225,7 @@ status_t OpenGLRenderer::prepareDirty(float left, float top,
// The framebuffer renderer will first defer the display list
// for each layer and wait until the first drawing command
// to start the frame
- if (mSnapshot->fbo == 0) {
+ if (currentSnapshot().fbo == 0) {
syncState();
updateLayers();
} else {
@@ -254,7 +240,7 @@ void OpenGLRenderer::discardFramebuffer(float left, float top, float right, floa
// perform a discard to let the driver know we don't need to preserve
// the back buffer for this frame.
if (mExtensions.hasDiscardFramebuffer() &&
- left <= 0.0f && top <= 0.0f && right >= mWidth && bottom >= mHeight) {
+ left <= 0.0f && top <= 0.0f && right >= getWidth() && bottom >= getHeight()) {
const bool isFbo = getTargetFbo() == 0;
const GLenum attachments[] = {
isFbo ? (const GLenum) GL_COLOR_EXT : (const GLenum) GL_COLOR_ATTACHMENT0,
@@ -266,7 +252,7 @@ void OpenGLRenderer::discardFramebuffer(float left, float top, float right, floa
status_t OpenGLRenderer::clear(float left, float top, float right, float bottom, bool opaque) {
if (!opaque || mCountOverdraw) {
mCaches.enableScissor();
- mCaches.setScissor(left, mSnapshot->height - bottom, right - left, bottom - top);
+ mCaches.setScissor(left, currentSnapshot().height - bottom, right - left, bottom - top);
glClear(GL_COLOR_BUFFER_BIT);
return DrawGlInfo::kStatusDrew;
}
@@ -283,14 +269,14 @@ void OpenGLRenderer::syncState() {
}
}
-void OpenGLRenderer::startTiling(const sp<Snapshot>& s, bool opaque) {
+void OpenGLRenderer::startTiling(const Snapshot& s, bool opaque) {
if (!mSuppressTiling) {
- Rect* clip = &mTilingClip;
- if (s->flags & Snapshot::kFlagFboTarget) {
- clip = &(s->layer->clipRect);
+ const Rect* clip = &mTilingClip;
+ if (s.flags & Snapshot::kFlagFboTarget) {
+ clip = &(s.layer->clipRect);
}
- startTiling(*clip, s->height, opaque);
+ startTiling(*clip, s.height, opaque);
}
}
@@ -369,9 +355,9 @@ void OpenGLRenderer::interrupt() {
}
void OpenGLRenderer::resume() {
- sp<Snapshot> snapshot = (mSnapshot != NULL) ? mSnapshot : mFirstSnapshot;
- glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight());
- glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo);
+ const Snapshot& snapshot = currentSnapshot();
+ glViewport(0, 0, snapshot.viewport.getWidth(), snapshot.viewport.getHeight());
+ glBindFramebuffer(GL_FRAMEBUFFER, snapshot.fbo);
debugOverdraw(true, false);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
@@ -391,9 +377,9 @@ void OpenGLRenderer::resume() {
}
void OpenGLRenderer::resumeAfterLayer() {
- sp<Snapshot> snapshot = (mSnapshot != NULL) ? mSnapshot : mFirstSnapshot;
- glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight());
- glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo);
+ const Snapshot& snapshot = currentSnapshot();
+ glViewport(0, 0, snapshot.viewport.getWidth(), snapshot.viewport.getHeight());
+ glBindFramebuffer(GL_FRAMEBUFFER, snapshot.fbo);
debugOverdraw(true, false);
mCaches.resetScissor();
@@ -447,12 +433,12 @@ status_t OpenGLRenderer::invokeFunctors(Rect& dirty) {
}
status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
- if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
+ if (currentSnapshot().isIgnored()) return DrawGlInfo::kStatusDone;
detachFunctor(functor);
- Rect clip(*mSnapshot->clipRect);
+ Rect clip(currentClipRect());
clip.snapToPixelBoundaries();
// Since we don't know what the functor will draw, let's dirty
@@ -556,9 +542,9 @@ void OpenGLRenderer::renderOverdraw() {
}
void OpenGLRenderer::countOverdraw() {
- size_t count = mWidth * mHeight;
+ size_t count = getWidth() * getHeight();
uint32_t* buffer = new uint32_t[count];
- glReadPixels(0, 0, mWidth, mHeight, GL_RGBA, GL_UNSIGNED_BYTE, &buffer[0]);
+ glReadPixels(0, 0, getWidth(), getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, &buffer[0]);
size_t total = 0;
for (size_t i = 0; i < count; i++) {
@@ -594,7 +580,7 @@ bool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) {
if (inFrame) {
resumeAfterLayer();
- startTiling(mSnapshot);
+ startTiling(*mSnapshot);
}
layer->debugDrawUpdate = mCaches.debugLayersUpdates;
@@ -715,50 +701,17 @@ void OpenGLRenderer::flushLayerUpdates() {
// State management
///////////////////////////////////////////////////////////////////////////////
-int OpenGLRenderer::getSaveCount() const {
- return mSaveCount;
-}
-
-int OpenGLRenderer::save(int flags) {
- return saveSnapshot(flags);
-}
-
-void OpenGLRenderer::restore() {
- if (mSaveCount > 1) {
- restoreSnapshot();
- }
-}
-
-void OpenGLRenderer::restoreToCount(int saveCount) {
- if (saveCount < 1) saveCount = 1;
-
- while (mSaveCount > saveCount) {
- restoreSnapshot();
- }
-}
-
-int OpenGLRenderer::saveSnapshot(int flags) {
- mSnapshot = new Snapshot(mSnapshot, flags);
- return mSaveCount++;
-}
-
-bool OpenGLRenderer::restoreSnapshot() {
- bool restoreClip = mSnapshot->flags & Snapshot::kFlagClipSet;
- bool restoreLayer = mSnapshot->flags & Snapshot::kFlagIsLayer;
- bool restoreOrtho = mSnapshot->flags & Snapshot::kFlagDirtyOrtho;
-
- sp<Snapshot> current = mSnapshot;
- sp<Snapshot> previous = mSnapshot->previous;
+void OpenGLRenderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {
+ bool restoreOrtho = removed.flags & Snapshot::kFlagDirtyOrtho;
+ bool restoreClip = removed.flags & Snapshot::kFlagClipSet;
+ bool restoreLayer = removed.flags & Snapshot::kFlagIsLayer;
if (restoreOrtho) {
- Rect& r = previous->viewport;
+ const Rect& r = restored.viewport;
glViewport(r.left, r.top, r.right, r.bottom);
- mViewProjMatrix.load(current->orthoMatrix);
+ mViewProjMatrix.load(removed.orthoMatrix); // todo: should ortho be stored in 'restored'?
}
- mSaveCount--;
- mSnapshot = previous;
-
if (restoreClip) {
dirtyClip();
}
@@ -766,11 +719,9 @@ bool OpenGLRenderer::restoreSnapshot() {
if (restoreLayer) {
endMark(); // Savelayer
startMark("ComposeLayer");
- composeLayer(current, previous);
+ composeLayer(removed, restored);
endMark();
}
-
- return restoreClip;
}
///////////////////////////////////////////////////////////////////////////////
@@ -781,7 +732,7 @@ int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,
int alpha, SkXfermode::Mode mode, int flags) {
const int count = saveSnapshot(flags);
- if (!mSnapshot->isIgnored()) {
+ if (!currentSnapshot().isIgnored()) {
createLayer(left, top, right, bottom, alpha, mode, flags);
}
@@ -794,14 +745,14 @@ void OpenGLRenderer::calculateLayerBoundsAndClip(Rect& bounds, Rect& clip, bool
currentTransform().mapRect(bounds);
// Layers only make sense if they are in the framebuffer's bounds
- if (bounds.intersect(*mSnapshot->clipRect)) {
+ if (bounds.intersect(currentClipRect())) {
// We cannot work with sub-pixels in this case
bounds.snapToPixelBoundaries();
// When the layer is not an FBO, we may use glCopyTexImage so we
// need to make sure the layer does not extend outside the bounds
// of the framebuffer
- if (!bounds.intersect(mSnapshot->previous->viewport)) {
+ if (!bounds.intersect(currentSnapshot().previous->viewport)) {
bounds.setEmpty();
} else if (fboLayer) {
clip.set(bounds);
@@ -836,7 +787,7 @@ int OpenGLRenderer::saveLayerDeferred(float left, float top, float right, float
int alpha, SkXfermode::Mode mode, int flags) {
const int count = saveSnapshot(flags);
- if (!mSnapshot->isIgnored() && (flags & SkCanvas::kClipToLayer_SaveFlag)) {
+ if (!currentSnapshot().isIgnored() && (flags & SkCanvas::kClipToLayer_SaveFlag)) {
// initialize the snapshot as though it almost represents an FBO layer so deferred draw
// operations will be able to store and restore the current clip and transform info, and
// quick rejection will be correct (for display lists)
@@ -846,7 +797,7 @@ int OpenGLRenderer::saveLayerDeferred(float left, float top, float right, float
calculateLayerBoundsAndClip(bounds, clip, true);
updateSnapshotIgnoreForLayer(bounds, clip, true, alpha);
- if (!mSnapshot->isIgnored()) {
+ if (!currentSnapshot().isIgnored()) {
mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
mSnapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
@@ -922,7 +873,7 @@ bool OpenGLRenderer::createLayer(float left, float top, float right, float botto
updateSnapshotIgnoreForLayer(bounds, clip, fboLayer, alpha);
// Bail out if we won't draw in this snapshot
- if (mSnapshot->isIgnored()) {
+ if (currentSnapshot().isIgnored()) {
return false;
}
@@ -1001,7 +952,7 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip) {
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
layer->getTexture(), 0);
- startTiling(mSnapshot, true);
+ startTiling(*mSnapshot, true);
// Clear the FBO, expand the clear region by 1 to get nice bilinear filtering
mCaches.enableScissor();
@@ -1023,15 +974,15 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip) {
/**
* Read the documentation of createLayer() before doing anything in this method.
*/
-void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
- if (!current->layer) {
+void OpenGLRenderer::composeLayer(const Snapshot& removed, const Snapshot& restored) {
+ if (!removed.layer) {
ALOGE("Attempting to compose a layer that does not exist");
return;
}
- Layer* layer = current->layer;
+ Layer* layer = removed.layer;
const Rect& rect = layer->layer;
- const bool fboLayer = current->flags & Snapshot::kFlagIsFboLayer;
+ const bool fboLayer = removed.flags & Snapshot::kFlagIsFboLayer;
bool clipRequired = false;
calculateQuickRejectForScissor(rect.left, rect.top, rect.right, rect.bottom,
@@ -1047,10 +998,10 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
layer->removeFbo(false);
// Unbind current FBO and restore previous one
- glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, restored.fbo);
debugOverdraw(true, false);
- startTiling(previous);
+ startTiling(restored);
}
if (!fboLayer && layer->getAlpha() < 255) {
@@ -1067,7 +1018,7 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
// When the layer is stored in an FBO, we can save a bit of fillrate by
// drawing only the dirty region
if (fboLayer) {
- dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *previous->transform);
+ dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *restored.transform);
if (layer->getColorFilter()) {
setupColorFilter(layer->getColorFilter());
}
@@ -1347,7 +1298,7 @@ void OpenGLRenderer::dirtyLayer(const float left, const float top,
}
void OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) {
- if (bounds.intersect(*mSnapshot->clipRect)) {
+ if (bounds.intersect(currentClipRect())) {
bounds.snapToPixelBoundaries();
android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom);
if (!dirty.isEmpty()) {
@@ -1375,7 +1326,7 @@ void OpenGLRenderer::clearLayerRegions() {
const size_t count = mLayers.size();
if (count == 0) return;
- if (!mSnapshot->isIgnored()) {
+ if (!currentSnapshot().isIgnored()) {
// Doing several glScissor/glClear here can negatively impact
// GPUs with a tiler architecture, instead we draw quads with
// the Clear blending mode
@@ -1427,8 +1378,8 @@ void OpenGLRenderer::clearLayerRegions() {
///////////////////////////////////////////////////////////////////////////////
bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDeferFlags) {
- const Rect& currentClip = *(mSnapshot->clipRect);
- const mat4& currentMatrix = *(mSnapshot->transform);
+ const Rect& currentClip = currentClipRect();
+ const mat4& currentMatrix = currentTransform();
if (stateDeferFlags & kStateDeferFlag_Draw) {
// state has bounds initialized in local coordinates
@@ -1471,14 +1422,14 @@ bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDef
// (Note: saveLayer/restore use colorFilter and alpha, so we just save restore everything)
state.mMatrix.load(currentMatrix);
state.mDrawModifiers = mDrawModifiers;
- state.mAlpha = mSnapshot->alpha;
+ state.mAlpha = currentSnapshot().alpha;
return false;
}
void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore) {
- currentTransform().load(state.mMatrix);
- mDrawModifiers = state.mDrawModifiers;
+ setMatrix(state.mMatrix);
mSnapshot->alpha = state.mAlpha;
+ mDrawModifiers = state.mDrawModifiers;
if (state.mClipValid && !skipClipRestore) {
mSnapshot->setClip(state.mClip.left, state.mClip.top,
@@ -1498,62 +1449,21 @@ void OpenGLRenderer::setupMergedMultiDraw(const Rect* clipRect) {
if (clipRect != NULL) {
mSnapshot->setClip(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
} else {
- mSnapshot->setClip(0, 0, mWidth, mHeight);
+ mSnapshot->setClip(0, 0, getWidth(), getHeight());
}
dirtyClip();
mCaches.setScissorEnabled(clipRect != NULL || mScissorOptimizationDisabled);
}
///////////////////////////////////////////////////////////////////////////////
-// Transforms
-///////////////////////////////////////////////////////////////////////////////
-
-void OpenGLRenderer::translate(float dx, float dy, float dz) {
- currentTransform().translate(dx, dy, dz);
-}
-
-void OpenGLRenderer::rotate(float degrees) {
- currentTransform().rotate(degrees, 0.0f, 0.0f, 1.0f);
-}
-
-void OpenGLRenderer::scale(float sx, float sy) {
- currentTransform().scale(sx, sy, 1.0f);
-}
-
-void OpenGLRenderer::skew(float sx, float sy) {
- currentTransform().skew(sx, sy);
-}
-
-void OpenGLRenderer::setMatrix(SkMatrix* matrix) {
- if (matrix) {
- currentTransform().load(*matrix);
- } else {
- currentTransform().loadIdentity();
- }
-}
-
-bool OpenGLRenderer::hasRectToRectTransform() {
- return CC_LIKELY(currentTransform().rectToRect());
-}
-
-void OpenGLRenderer::getMatrix(SkMatrix* matrix) const {
- currentTransform().copyTo(*matrix);
-}
-
-void OpenGLRenderer::concatMatrix(SkMatrix* matrix) {
- mat4 transform(*matrix);
- currentTransform().multiply(transform);
-}
-
-///////////////////////////////////////////////////////////////////////////////
// Clipping
///////////////////////////////////////////////////////////////////////////////
void OpenGLRenderer::setScissorFromClip() {
- Rect clip(*mSnapshot->clipRect);
+ Rect clip(currentClipRect());
clip.snapToPixelBoundaries();
- if (mCaches.setScissor(clip.left, mSnapshot->height - clip.bottom,
+ if (mCaches.setScissor(clip.left, currentSnapshot().height - clip.bottom,
clip.getWidth(), clip.getHeight())) {
mDirtyClip = false;
}
@@ -1564,7 +1474,7 @@ void OpenGLRenderer::ensureStencilBuffer() {
// cannot attach a stencil buffer to fbo0 dynamically. Let's
// just hope we have one when hasLayer() returns false.
if (hasLayer()) {
- attachStencilBufferToLayer(mSnapshot->layer);
+ attachStencilBufferToLayer(currentSnapshot().layer);
}
}
@@ -1586,7 +1496,7 @@ void OpenGLRenderer::attachStencilBufferToLayer(Layer* layer) {
void OpenGLRenderer::setStencilFromClip() {
if (!mCaches.debugOverdraw) {
- if (!mSnapshot->clipRegion->isEmpty()) {
+ if (!currentSnapshot().clipRegion->isEmpty()) {
// NOTE: The order here is important, we must set dirtyClip to false
// before any draw call to avoid calling back into this method
mDirtyClip = false;
@@ -1611,14 +1521,16 @@ void OpenGLRenderer::setStencilFromClip() {
// The last parameter is important: we are not drawing in the color buffer
// so we don't want to dirty the current layer, if any
- drawRegionRects(*mSnapshot->clipRegion, 0xff000000, SkXfermode::kSrc_Mode, false);
+ drawRegionRects(*(currentSnapshot().clipRegion),
+ 0xff000000, SkXfermode::kSrc_Mode, false);
mCaches.stencil.enableTest();
// Draw the region used to generate the stencil if the appropriate debug
// mode is enabled
if (mCaches.debugStencilClip == Caches::kStencilShowRegion) {
- drawRegionRects(*mSnapshot->clipRegion, 0x7f0000ff, SkXfermode::kSrcOver_Mode);
+ drawRegionRects(*(currentSnapshot().clipRegion),
+ 0x7f0000ff, SkXfermode::kSrcOver_Mode);
}
} else {
mCaches.stencil.disable();
@@ -1626,69 +1538,6 @@ void OpenGLRenderer::setStencilFromClip() {
}
}
-const Rect& OpenGLRenderer::getClipBounds() const {
- return mSnapshot->getLocalClip();
-}
-
-/**
- * Calculates whether content drawn within the passed bounds would be outside of, or intersect with
- * the clipRect. Does not modify the scissor.
- *
- * @param clipRequired if not null, will be set to true if element intersects clip
- * (and wasn't rejected)
- *
- * @param snapOut if set, the geometry will be treated as having an AA ramp.
- * See Rect::snapGeometryToPixelBoundaries()
- */
-bool OpenGLRenderer::calculateQuickRejectForScissor(float left, float top,
- float right, float bottom, bool* clipRequired, bool snapOut) const {
- if (mSnapshot->isIgnored() || bottom <= top || right <= left) {
- return true;
- }
-
- Rect r(left, top, right, bottom);
- currentTransform().mapRect(r);
- r.snapGeometryToPixelBoundaries(snapOut);
-
- Rect clipRect(*mSnapshot->clipRect);
- clipRect.snapToPixelBoundaries();
-
- if (!clipRect.intersects(r)) return true;
-
- // clip is required if geometry intersects clip rect
- if (clipRequired) *clipRequired = !clipRect.contains(r);
- return false;
-}
-
-/**
- * Returns false if drawing won't be clipped out.
- *
- * Makes the decision conservatively, by rounding out the mapped rect before comparing with the
- * clipRect. To be used when perfect, pixel accuracy is not possible (esp. with tessellation) but
- * rejection is still desired.
- *
- * This function, unlike quickRejectSetupScissor, should be used where precise geometry information
- * isn't known (esp. when geometry adjusts based on scale). Generally, this will be first pass
- * rejection where precise rejection isn't important, or precise information isn't available.
- */
-bool OpenGLRenderer::quickRejectConservative(float left, float top,
- float right, float bottom) const {
- if (mSnapshot->isIgnored() || bottom <= top || right <= left) {
- return true;
- }
-
- Rect r(left, top, right, bottom);
- currentTransform().mapRect(r);
- r.roundOut(); // rounded out to be conservative
-
- Rect clipRect(*mSnapshot->clipRect);
- clipRect.snapToPixelBoundaries();
-
- if (!clipRect.intersects(r)) return true;
-
- return false;
-}
-
/**
* Returns false and sets scissor enable based upon bounds if drawing won't be clipped out.
*
@@ -1721,8 +1570,8 @@ bool OpenGLRenderer::quickRejectSetupScissor(float left, float top, float right,
void OpenGLRenderer::debugClip() {
#if DEBUG_CLIP_REGIONS
- if (!isRecording() && !mSnapshot->clipRegion->isEmpty()) {
- drawRegionRects(*mSnapshot->clipRegion, 0x7f00ff00, SkXfermode::kSrcOver_Mode);
+ if (!isRecording() && !currentSnapshot().clipRegion->isEmpty()) {
+ drawRegionRects(*(currentSnapshot().clipRegion), 0x7f00ff00, SkXfermode::kSrcOver_Mode);
}
#endif
}
@@ -1754,7 +1603,7 @@ bool OpenGLRenderer::clipPath(SkPath* path, SkRegion::Op op) {
clip.setRegion(*mSnapshot->previous->clipRegion);
} else {
if (mSnapshot->previous == mFirstSnapshot) {
- clip.setRect(0, 0, mWidth, mHeight);
+ clip.setRect(0, 0, getWidth(), getHeight());
} else {
Rect* bounds = mSnapshot->previous->clipRect;
clip.setRect(bounds->left, bounds->top, bounds->right, bounds->bottom);
@@ -1779,10 +1628,6 @@ bool OpenGLRenderer::clipRegion(SkRegion* region, SkRegion::Op op) {
return !mSnapshot->clipRect->isEmpty();
}
-Rect* OpenGLRenderer::getClipRect() {
- return mSnapshot->clipRect;
-}
-
///////////////////////////////////////////////////////////////////////////////
// Drawing commands
///////////////////////////////////////////////////////////////////////////////
@@ -2067,7 +1912,7 @@ status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty,
if (mCaches.propertyDirtyViewport) {
// force recalc of view/proj matrices
- setViewport(mWidth, mHeight);
+ setViewport(getWidth(), getHeight());
mCaches.propertyDirtyViewport = false;
}
@@ -3107,7 +2952,7 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
transform = &layer->getTransform();
if (!transform->isIdentity()) {
save(0);
- currentTransform().multiply(*transform);
+ concatMatrix(*transform);
}
}
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 2d6a7e9..1325bf7 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -42,6 +42,7 @@
#include "Program.h"
#include "Rect.h"
#include "Renderer.h"
+#include "StatefulBaseRenderer.h"
#include "SkiaColorFilter.h"
#include "Snapshot.h"
#include "UvMapper.h"
@@ -120,10 +121,9 @@ enum ModelViewMode {
// Renderer
///////////////////////////////////////////////////////////////////////////////
/**
- * OpenGL renderer used to draw accelerated 2D graphics. The API is a
- * simplified version of Skia's Canvas API.
+ * OpenGL Renderer implementation.
*/
-class OpenGLRenderer : public Renderer {
+class OpenGLRenderer : public StatefulBaseRenderer {
public:
ANDROID_API OpenGLRenderer();
virtual ~OpenGLRenderer();
@@ -131,10 +131,7 @@ public:
ANDROID_API void initProperties();
virtual void setViewport(int width, int height);
-
- virtual status_t prepare(bool opaque);
virtual status_t prepareDirty(float left, float top, float right, float bottom, bool opaque);
-
virtual void finish();
virtual void interrupt();
virtual void resume();
@@ -157,11 +154,6 @@ public:
ANDROID_API void clearLayerUpdates();
ANDROID_API void flushLayerUpdates();
- ANDROID_API int getSaveCount() const;
- virtual int save(int flags);
- virtual void restore();
- virtual void restoreToCount(int saveCount);
-
ANDROID_API int saveLayer(float left, float top, float right, float bottom,
SkPaint* paint, int flags) {
SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode;
@@ -178,28 +170,9 @@ public:
int saveLayerDeferred(float left, float top, float right, float bottom,
int alpha, SkXfermode::Mode mode, int flags);
- virtual void translate(float dx, float dy, float dz = 0);
- virtual void rotate(float degrees);
- virtual void scale(float sx, float sy);
- virtual void skew(float sx, float sy);
-
- bool hasRectToRectTransform();
- ANDROID_API void getMatrix(SkMatrix* matrix) const;
- virtual void setMatrix(SkMatrix* matrix);
- virtual void concatMatrix(SkMatrix* matrix);
- virtual void concatMatrix(Matrix4& matrix) {
- currentTransform().multiply(matrix);
- }
-
- ANDROID_API const Rect& getClipBounds() const;
-
- ANDROID_API bool quickRejectConservative(float left, float top,
- float right, float bottom) const;
-
virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
virtual bool clipPath(SkPath* path, SkRegion::Op op);
virtual bool clipRegion(SkRegion* region, SkRegion::Op op);
- virtual Rect* getClipRect();
virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t replayFlags);
virtual status_t drawLayer(Layer* layer, float x, float y);
@@ -273,7 +246,7 @@ public:
void setDrawModifiers(const DrawModifiers& drawModifiers) { mDrawModifiers = drawModifiers; }
ANDROID_API bool isCurrentTransformSimple() {
- return mSnapshot->transform->isSimple();
+ return currentTransform().isSimple();
}
Caches& getCaches() {
@@ -400,9 +373,6 @@ protected:
*/
void attachStencilBufferToLayer(Layer* layer);
- bool calculateQuickRejectForScissor(float left, float top, float right, float bottom,
- bool* clipRequired, bool snapOut) const;
-
bool quickRejectSetupScissor(float left, float top, float right, float bottom,
SkPaint* paint = NULL);
bool quickRejectSetupScissor(const Rect& bounds, SkPaint* paint = NULL) {
@@ -419,16 +389,13 @@ protected:
* @param curent The current snapshot containing the layer to compose
* @param previous The previous snapshot to compose the current layer with
*/
- virtual void composeLayer(sp<Snapshot> current, sp<Snapshot> previous);
+ virtual void composeLayer(const Snapshot& current, const Snapshot& previous);
/**
* Marks the specified region as dirty at the specified bounds.
*/
void dirtyLayerUnchecked(Rect& bounds, Region* region);
- /**
- * Returns the current snapshot.
- */
sp<Snapshot> getSnapshot() const {
return mSnapshot;
}
@@ -450,7 +417,7 @@ protected:
/**
* Returns the name of the FBO this renderer is rendering into.
*/
- virtual GLint getTargetFbo() const {
+ virtual GLuint getTargetFbo() const {
return 0;
}
@@ -520,7 +487,7 @@ private:
* This method needs to be invoked every time getTargetFbo() is
* bound again.
*/
- void startTiling(const sp<Snapshot>& snapshot, bool opaque = false);
+ void startTiling(const Snapshot& snapshot, bool opaque = false);
/**
* Tells the GPU what part of the screen is about to be redrawn.
@@ -535,23 +502,7 @@ private:
*/
void endTiling();
- /**
- * Saves the current state of the renderer as a new snapshot.
- * The new snapshot is saved in mSnapshot and the previous snapshot
- * is linked from mSnapshot->previous.
- *
- * @param flags The save flags; see SkCanvas for more information
- *
- * @return The new save count. This value can be passed to #restoreToCount()
- */
- int saveSnapshot(int flags);
-
- /**
- * Restores the current snapshot; mSnapshot becomes mSnapshot->previous.
- *
- * @return True if the clip was modified.
- */
- bool restoreSnapshot();
+ void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored);
/**
* Sets the clipping rectangle using glScissor. The clip is defined by
@@ -979,10 +930,6 @@ private:
mDirtyClip = true;
}
- inline mat4& currentTransform() const {
- return *mSnapshot->transform;
- }
-
inline const UvMapper& getMapper(const Texture* texture) {
return texture && texture->uvMapper ? *texture->uvMapper : mUvMapper;
}
@@ -994,9 +941,6 @@ private:
*/
Texture* getTexture(SkBitmap* bitmap);
- // Dimensions of the drawing surface
- int mWidth, mHeight;
-
// Matrix used for view/projection in shaders
mat4 mViewProjMatrix;
@@ -1016,12 +960,6 @@ private:
*/
mat4 mModelView;
- // Number of saved states
- int mSaveCount;
- // Base state
- sp<Snapshot> mFirstSnapshot;
- // Current state
- sp<Snapshot> mSnapshot;
// State used to define the clipping region
Rect mTilingClip;
// Is the target render surface opaque
diff --git a/libs/hwui/Renderer.h b/libs/hwui/Renderer.h
index ac216fe..faf663a 100644
--- a/libs/hwui/Renderer.h
+++ b/libs/hwui/Renderer.h
@@ -17,10 +17,18 @@
#ifndef ANDROID_HWUI_RENDERER_H
#define ANDROID_HWUI_RENDERER_H
+#include <SkRegion.h>
+
+#include <utils/String8.h>
+
#include "AssetAtlas.h"
#include "SkPaint.h"
namespace android {
+
+class Functor;
+class Res_png_9patch;
+
namespace uirenderer {
class DisplayList;
@@ -152,12 +160,8 @@ public:
// ----------------------------------------------------------------------------
// Canvas state operations
// ----------------------------------------------------------------------------
- // getters
+ // Save (layer)
virtual int getSaveCount() const = 0;
- virtual void getMatrix(SkMatrix* outMatrix) const = 0;
- virtual const Rect& getClipBounds() const = 0;
-
- // save (layer)
virtual int save(int flags) = 0;
virtual void restore() = 0;
virtual void restoreToCount(int saveCount) = 0;
@@ -180,6 +184,7 @@ public:
int alpha, SkXfermode::Mode mode, int flags) = 0;
// Matrix
+ virtual void getMatrix(SkMatrix* outMatrix) const = 0;
virtual void translate(float dx, float dy, float dz = 0.0f) = 0;
virtual void rotate(float degrees) = 0;
virtual void scale(float sx, float sy) = 0;
@@ -187,9 +192,11 @@ public:
virtual void setMatrix(SkMatrix* matrix) = 0;
virtual void concatMatrix(SkMatrix* matrix) = 0;
- virtual void concatMatrix(Matrix4& matrix) = 0;
- // Clip
+ // clip
+ virtual const Rect& getClipBounds() const = 0;
+ virtual bool quickRejectConservative(float left, float top,
+ float right, float bottom) const = 0;
virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op) = 0;
virtual bool clipPath(SkPath* path, SkRegion::Op op) = 0;
virtual bool clipRegion(SkRegion* region, SkRegion::Op op) = 0;
diff --git a/libs/hwui/StatefulBaseRenderer.cpp b/libs/hwui/StatefulBaseRenderer.cpp
new file mode 100644
index 0000000..cc8b14f
--- /dev/null
+++ b/libs/hwui/StatefulBaseRenderer.cpp
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2014 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 <SkCanvas.h>
+
+#include "StatefulBaseRenderer.h"
+
+namespace android {
+namespace uirenderer {
+
+StatefulBaseRenderer::StatefulBaseRenderer() :
+ mSaveCount(1), mFirstSnapshot(new Snapshot), mSnapshot(mFirstSnapshot) {
+}
+
+void StatefulBaseRenderer::initializeSaveStack(float clipLeft, float clipTop,
+ float clipRight, float clipBottom) {
+ mSnapshot = new Snapshot(mFirstSnapshot,
+ SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+ mSnapshot->setClip(clipLeft, clipTop, clipRight, clipBottom);
+ mSnapshot->fbo = getTargetFbo();
+ mSaveCount = 1;
+}
+
+void StatefulBaseRenderer::initializeViewport(int width, int height) {
+ mWidth = width;
+ mHeight = height;
+
+ mFirstSnapshot->height = height;
+ mFirstSnapshot->viewport.set(0, 0, width, height);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Save (layer)
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Non-virtual implementation of save, guaranteed to save without side-effects
+ *
+ * The approach here and in restoreSnapshot(), allows subclasses to directly manipulate the save
+ * stack, and ensures restoreToCount() doesn't call back into subclass overrides.
+ */
+int StatefulBaseRenderer::saveSnapshot(int flags) {
+ mSnapshot = new Snapshot(mSnapshot, flags);
+ return mSaveCount++;
+}
+
+int StatefulBaseRenderer::save(int flags) {
+ return saveSnapshot(flags);
+}
+
+/**
+ * Non-virtual implementation of restore, guaranteed to restore without side-effects.
+ */
+void StatefulBaseRenderer::restoreSnapshot() {
+ sp<Snapshot> toRemove = mSnapshot;
+ sp<Snapshot> toRestore = mSnapshot->previous;
+
+ mSaveCount--;
+ mSnapshot = toRestore;
+
+ // subclass handles restore implementation
+ onSnapshotRestored(*toRemove, *toRestore);
+}
+
+void StatefulBaseRenderer::restore() {
+ if (mSaveCount > 1) {
+ restoreSnapshot();
+ }
+}
+
+void StatefulBaseRenderer::restoreToCount(int saveCount) {
+ if (saveCount < 1) saveCount = 1;
+
+ while (mSaveCount > saveCount) {
+ restoreSnapshot();
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Matrix
+///////////////////////////////////////////////////////////////////////////////
+
+void StatefulBaseRenderer::getMatrix(SkMatrix* matrix) const {
+ mSnapshot->transform->copyTo(*matrix);
+}
+
+void StatefulBaseRenderer::translate(float dx, float dy, float dz) {
+ mSnapshot->transform->translate(dx, dy, dz);
+}
+
+void StatefulBaseRenderer::rotate(float degrees) {
+ mSnapshot->transform->rotate(degrees, 0.0f, 0.0f, 1.0f);
+}
+
+void StatefulBaseRenderer::scale(float sx, float sy) {
+ mSnapshot->transform->scale(sx, sy, 1.0f);
+}
+
+void StatefulBaseRenderer::skew(float sx, float sy) {
+ mSnapshot->transform->skew(sx, sy);
+}
+
+void StatefulBaseRenderer::setMatrix(SkMatrix* matrix) {
+ if (matrix) {
+ mSnapshot->transform->load(*matrix);
+ } else {
+ mSnapshot->transform->loadIdentity();
+ }
+}
+
+void StatefulBaseRenderer::setMatrix(const Matrix4& matrix) {
+ mSnapshot->transform->load(matrix);
+}
+
+void StatefulBaseRenderer::concatMatrix(SkMatrix* matrix) {
+ mat4 transform(*matrix);
+ mSnapshot->transform->multiply(transform);
+}
+
+void StatefulBaseRenderer::concatMatrix(const Matrix4& matrix) {
+ mSnapshot->transform->multiply(matrix);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Clip
+///////////////////////////////////////////////////////////////////////////////
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Quick Rejection
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Calculates whether content drawn within the passed bounds would be outside of, or intersect with
+ * the clipRect. Does not modify the scissor.
+ *
+ * @param clipRequired if not null, will be set to true if element intersects clip
+ * (and wasn't rejected)
+ *
+ * @param snapOut if set, the geometry will be treated as having an AA ramp.
+ * See Rect::snapGeometryToPixelBoundaries()
+ */
+bool StatefulBaseRenderer::calculateQuickRejectForScissor(float left, float top,
+ float right, float bottom, bool* clipRequired, bool snapOut) const {
+ if (mSnapshot->isIgnored() || bottom <= top || right <= left) {
+ return true;
+ }
+
+ Rect r(left, top, right, bottom);
+ currentTransform().mapRect(r);
+ r.snapGeometryToPixelBoundaries(snapOut);
+
+ Rect clipRect(currentClipRect());
+ clipRect.snapToPixelBoundaries();
+
+ if (!clipRect.intersects(r)) return true;
+
+ // clip is required if geometry intersects clip rect
+ if (clipRequired) *clipRequired = !clipRect.contains(r);
+ return false;
+}
+
+/**
+ * Returns false if drawing won't be clipped out.
+ *
+ * Makes the decision conservatively, by rounding out the mapped rect before comparing with the
+ * clipRect. To be used when perfect, pixel accuracy is not possible (esp. with tessellation) but
+ * rejection is still desired.
+ *
+ * This function, unlike quickRejectSetupScissor, should be used where precise geometry information
+ * isn't known (esp. when geometry adjusts based on scale). Generally, this will be first pass
+ * rejection where precise rejection isn't important, or precise information isn't available.
+ */
+bool StatefulBaseRenderer::quickRejectConservative(float left, float top,
+ float right, float bottom) const {
+ if (mSnapshot->isIgnored() || bottom <= top || right <= left) {
+ return true;
+ }
+
+ Rect r(left, top, right, bottom);
+ currentTransform().mapRect(r);
+ r.roundOut(); // rounded out to be conservative
+
+ Rect clipRect(currentClipRect());
+ clipRect.snapToPixelBoundaries();
+
+ if (!clipRect.intersects(r)) return true;
+
+ return false;
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/StatefulBaseRenderer.h b/libs/hwui/StatefulBaseRenderer.h
new file mode 100644
index 0000000..2bd196e
--- /dev/null
+++ b/libs/hwui/StatefulBaseRenderer.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2014 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_STATEFUL_BASE_RENDERER_H
+#define ANDROID_HWUI_STATEFUL_BASE_RENDERER_H
+
+#include <utils/RefBase.h>
+
+#include "Renderer.h"
+#include "Snapshot.h"
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * Implementation for Renderer state methods
+ *
+ * Eventually, this class should have abstract protected methods
+ * for allowing subclasses to hook into save/saveLayer and restore
+ */
+class StatefulBaseRenderer : public Renderer {
+public:
+ StatefulBaseRenderer();
+
+ virtual status_t prepare(bool opaque) {
+ return prepareDirty(0.0f, 0.0f, mWidth, mHeight, opaque);
+ }
+ void initializeViewport(int width, int height);
+ void initializeSaveStack(float clipLeft, float clipTop, float clipRight, float clipBottom);
+
+ // getters
+ bool hasRectToRectTransform() const {
+ return CC_LIKELY(currentTransform().rectToRect());
+ }
+
+ // Save (layer)
+ virtual int getSaveCount() const { return mSaveCount; }
+ virtual int save(int flags);
+ virtual void restore();
+ virtual void restoreToCount(int saveCount);
+ //virtual int saveLayer(float left, float top, float right, float bottom,
+ // int alpha, SkXfermode::Mode mode, int flags);
+
+ // Matrix
+ virtual void getMatrix(SkMatrix* outMatrix) const;
+ virtual void translate(float dx, float dy, float dz = 0.0f);
+ virtual void rotate(float degrees);
+ virtual void scale(float sx, float sy);
+ virtual void skew(float sx, float sy);
+
+ virtual void setMatrix(SkMatrix* matrix);
+ void setMatrix(const Matrix4& matrix); // internal only convenience method
+ virtual void concatMatrix(SkMatrix* matrix);
+ void concatMatrix(const Matrix4& matrix); // internal only convenience method
+
+ // Clip
+ const Rect& getClipBounds() const { return mSnapshot->getLocalClip(); }
+ virtual bool quickRejectConservative(float left, float top, float right, float bottom) const;
+
+ // TODO: implement these with hooks to enable scissor/stencil usage in OpenGLRenderer
+ // virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
+ // virtual bool clipPath(SkPath* path, SkRegion::Op op);
+ // virtual bool clipRegion(SkRegion* region, SkRegion::Op op);
+
+protected:
+ int getWidth() { return mWidth; }
+ int getHeight() { return mHeight; }
+
+ // Save
+ int saveSnapshot(int flags);
+ void restoreSnapshot();
+
+ // allows subclasses to control what value is stored in snapshot's fbo field in
+ // initializeSaveStack
+ virtual GLuint getTargetFbo() const {
+ return -1;
+ }
+
+ // Clip
+ bool calculateQuickRejectForScissor(float left, float top, float right, float bottom,
+ bool* clipRequired, bool snapOut) const;
+
+ /**
+ * Called just after a restore has occurred. The 'removed' snapshot popped from the stack,
+ * 'restored' snapshot has become the top/current.
+ *
+ * Subclasses can override this method to handle layer restoration
+ */
+ virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {};
+
+ inline const Rect& currentClipRect() const {
+ return *(mSnapshot->clipRect);
+ }
+
+ inline const mat4& currentTransform() const {
+ return *(mSnapshot->transform);
+ }
+
+ inline const Snapshot& currentSnapshot() const {
+ return mSnapshot != NULL ? *mSnapshot : *mFirstSnapshot;
+ }
+
+ // TODO: below should be private so that snapshot stack manipulation
+ // goes though (mostly) public methods
+
+ // Number of saved states
+ int mSaveCount;
+
+ // Base state
+ sp<Snapshot> mFirstSnapshot;
+
+ // Current state
+ sp<Snapshot> mSnapshot;
+
+private:
+ // Dimensions of the drawing surface
+ int mWidth, mHeight;
+
+}; // class StatefulBaseRenderer
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_STATEFUL_BASE_RENDERER_H