Merge "Refactor HWUI to better handle Canvas DrawFilters."

This commit is contained in:
Derek Sollenberger
2014-10-22 15:59:25 +00:00
committed by Android (Google) Code Review
11 changed files with 76 additions and 186 deletions

View File

@@ -517,16 +517,10 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void setDrawFilter(DrawFilter filter) {
mFilter = filter;
if (filter == null) {
nResetPaintFilter(mRenderer);
} else if (filter instanceof PaintFlagsDrawFilter) {
PaintFlagsDrawFilter flagsFilter = (PaintFlagsDrawFilter) filter;
nSetupPaintFilter(mRenderer, flagsFilter.clearBits, flagsFilter.setBits);
}
nSetDrawFilter(mRenderer, (filter != null) ? filter.mNativeInt : 0);
}
private static native void nResetPaintFilter(long renderer);
private static native void nSetupPaintFilter(long renderer, int clearBits, int setBits);
private static native void nSetDrawFilter(long renderer, long nativeFilter);
@Override
public DrawFilter getDrawFilter() {

View File

@@ -587,16 +587,11 @@ static void android_view_GLES20Canvas_drawLines(JNIEnv* env, jobject clazz,
// Draw filters
// ----------------------------------------------------------------------------
static void android_view_GLES20Canvas_setupPaintFilter(JNIEnv* env, jobject clazz,
jlong rendererPtr, jint clearBits, jint setBits) {
static void android_view_GLES20Canvas_setDrawFilter(JNIEnv* env, jobject clazz,
jlong rendererPtr, jlong filterPtr) {
DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
renderer->setupPaintFilter(clearBits, setBits);
}
static void android_view_GLES20Canvas_resetPaintFilter(JNIEnv* env, jobject clazz,
jlong rendererPtr) {
DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
renderer->resetPaintFilter();
SkDrawFilter* filter = reinterpret_cast<SkDrawFilter*>(filterPtr);
renderer->setDrawFilter(filter);
}
// ----------------------------------------------------------------------------
@@ -936,8 +931,7 @@ static JNINativeMethod gMethods[] = {
{ "nDrawPath", "(JJJ)V", (void*) android_view_GLES20Canvas_drawPath },
{ "nDrawLines", "(J[FIIJ)V", (void*) android_view_GLES20Canvas_drawLines },
{ "nSetupPaintFilter", "(JII)V", (void*) android_view_GLES20Canvas_setupPaintFilter },
{ "nResetPaintFilter", "(J)V", (void*) android_view_GLES20Canvas_resetPaintFilter },
{ "nSetDrawFilter", "(JJ)V", (void*) android_view_GLES20Canvas_setDrawFilter },
{ "nDrawText", "(J[CIIFFIJJ)V", (void*) android_view_GLES20Canvas_drawTextArray },
{ "nDrawText", "(JLjava/lang/String;IIFFIJJ)V",

View File

@@ -24,8 +24,11 @@ package android.graphics;
*/
public class DrawFilter {
// this is set by subclasses, but don't make it public
/* package */ long mNativeInt; // pointer to native object
/**
* this is set by subclasses
* @hide
*/
public long mNativeInt;
protected void finalize() throws Throwable {
try {

View File

@@ -17,11 +17,6 @@
package android.graphics;
public class PaintFlagsDrawFilter extends DrawFilter {
/** @hide **/
public final int clearBits;
/** @hide **/
public final int setBits;
/**
* Subclass of DrawFilter that affects every paint by first clearing
* the specified clearBits in the paint's flags, and then setting the
@@ -31,8 +26,6 @@ public class PaintFlagsDrawFilter extends DrawFilter {
* @param setBits These bits will be set in the paint's flags
*/
public PaintFlagsDrawFilter(int clearBits, int setBits) {
this.clearBits = clearBits;
this.setBits = setBits;
// our native constructor can return 0, if the specified bits
// are effectively a no-op
mNativeInt = nativeConstructor(clearBits, setBits);

View File

@@ -235,26 +235,6 @@ public:
return false;
}
/* Draw Modifiers compatibility check
*
* Shadows are ignored, as only text uses them, and in that case they are drawn
* per-DrawTextOp, before the unified text draw. Because of this, it's always safe to merge
* text UNLESS a later draw's shadow should overlays a previous draw's text. This is covered
* above with the intersection check.
*
* OverrideLayerAlpha is also ignored, as it's only used for drawing layers, which are never
* merged.
*
* These ignore cases prevent us from simply memcmp'ing the drawModifiers
*/
const DrawModifiers& lhsMod = lhs->mDrawModifiers;
const DrawModifiers& rhsMod = rhs->mDrawModifiers;
// Draw filter testing expects bit fields to be clear if filter not set.
if (lhsMod.mHasDrawFilter != rhsMod.mHasDrawFilter) return false;
if (lhsMod.mPaintFilterClearBits != rhsMod.mPaintFilterClearBits) return false;
if (lhsMod.mPaintFilterSetBits != rhsMod.mPaintFilterSetBits) return false;
return true;
}

View File

@@ -201,10 +201,6 @@ public:
}
protected:
const SkPaint* getPaint(OpenGLRenderer& renderer) {
return renderer.filterPaint(mPaint);
}
// Helper method for determining op opaqueness. Assumes op fills its bounds in local
// coordinates, and that paint's alpha is used
inline bool isOpaqueOverBounds(const DeferredDisplayState& state) {
@@ -234,7 +230,7 @@ protected:
}
const SkPaint* mPaint; // should be accessed via getPaint() when applying
const SkPaint* mPaint;
bool mQuickRejected;
};
@@ -608,39 +604,6 @@ private:
const SkRegion* mRegion;
};
class ResetPaintFilterOp : public StateOp {
public:
virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
renderer.resetPaintFilter();
}
virtual void output(int level, uint32_t logFlags) const {
OP_LOGS("ResetPaintFilter");
}
virtual const char* name() { return "ResetPaintFilter"; }
};
class SetupPaintFilterOp : public StateOp {
public:
SetupPaintFilterOp(int clearBits, int setBits)
: mClearBits(clearBits), mSetBits(setBits) {}
virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
renderer.setupPaintFilter(mClearBits, mSetBits);
}
virtual void output(int level, uint32_t logFlags) const {
OP_LOG("SetupPaintFilter, clear %#x, set %#x", mClearBits, mSetBits);
}
virtual const char* name() { return "SetupPaintFilter"; }
private:
int mClearBits;
int mSetBits;
};
///////////////////////////////////////////////////////////////////////////////
// DRAW OPERATIONS - these are operations that can draw to the canvas's device
///////////////////////////////////////////////////////////////////////////////
@@ -659,7 +622,7 @@ public:
}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
return renderer.drawBitmap(mBitmap, getPaint(renderer));
return renderer.drawBitmap(mBitmap, mPaint);
}
AssetAtlas::Entry* getAtlasEntry() {
@@ -764,7 +727,7 @@ public:
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
return renderer.drawBitmap(mBitmap, mSrc.left, mSrc.top, mSrc.right, mSrc.bottom,
mLocalBounds.left, mLocalBounds.top, mLocalBounds.right, mLocalBounds.bottom,
getPaint(renderer));
mPaint);
}
virtual void output(int level, uint32_t logFlags) const {
@@ -790,7 +753,7 @@ public:
: DrawBitmapOp(bitmap, paint) {}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
return renderer.drawBitmapData(mBitmap, getPaint(renderer));
return renderer.drawBitmapData(mBitmap, mPaint);
}
virtual void output(int level, uint32_t logFlags) const {
@@ -815,7 +778,7 @@ public:
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
return renderer.drawBitmapMesh(mBitmap, mMeshWidth, mMeshHeight,
mVertices, mColors, getPaint(renderer));
mVertices, mColors, mPaint);
}
virtual void output(int level, uint32_t logFlags) const {
@@ -945,7 +908,7 @@ public:
}
return renderer.drawPatches(mBitmap, getAtlasEntry(),
&vertices[0], indexCount, getPaint(renderer));
&vertices[0], indexCount, mPaint);
}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
@@ -953,7 +916,7 @@ public:
// This method won't perform the quickReject() since we've already done it at this point
return renderer.drawPatch(mBitmap, getMesh(renderer), getAtlasEntry(),
mLocalBounds.left, mLocalBounds.top, mLocalBounds.right, mLocalBounds.bottom,
getPaint(renderer));
mPaint);
}
virtual void output(int level, uint32_t logFlags) const {
@@ -1037,7 +1000,7 @@ public:
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
return renderer.drawRect(mLocalBounds.left, mLocalBounds.top,
mLocalBounds.right, mLocalBounds.bottom, getPaint(renderer));
mLocalBounds.right, mLocalBounds.bottom, mPaint);
}
virtual void output(int level, uint32_t logFlags) const {
@@ -1061,7 +1024,7 @@ public:
mRects(rects), mCount(count) {}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
return renderer.drawRects(mRects, mCount, getPaint(renderer));
return renderer.drawRects(mRects, mCount, mPaint);
}
virtual void output(int level, uint32_t logFlags) const {
@@ -1088,7 +1051,7 @@ public:
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
return renderer.drawRoundRect(mLocalBounds.left, mLocalBounds.top,
mLocalBounds.right, mLocalBounds.bottom, mRx, mRy, getPaint(renderer));
mLocalBounds.right, mLocalBounds.bottom, mRx, mRy, mPaint);
}
virtual void output(int level, uint32_t logFlags) const {
@@ -1120,7 +1083,7 @@ public:
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
return renderer.drawRoundRect(*mLeft, *mTop, *mRight, *mBottom,
*mRx, *mRy, getPaint(renderer));
*mRx, *mRy, mPaint);
}
virtual void output(int level, uint32_t logFlags) const {
@@ -1146,7 +1109,7 @@ public:
mX(x), mY(y), mRadius(radius) {}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
return renderer.drawCircle(mX, mY, mRadius, getPaint(renderer));
return renderer.drawCircle(mX, mY, mRadius, mPaint);
}
virtual void output(int level, uint32_t logFlags) const {
@@ -1167,7 +1130,7 @@ public:
: DrawOp(paint), mX(x), mY(y), mRadius(radius) {}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
return renderer.drawCircle(*mX, *mY, *mRadius, getPaint(renderer));
return renderer.drawCircle(*mX, *mY, *mRadius, mPaint);
}
virtual void output(int level, uint32_t logFlags) const {
@@ -1189,7 +1152,7 @@ public:
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
return renderer.drawOval(mLocalBounds.left, mLocalBounds.top,
mLocalBounds.right, mLocalBounds.bottom, getPaint(renderer));
mLocalBounds.right, mLocalBounds.bottom, mPaint);
}
virtual void output(int level, uint32_t logFlags) const {
@@ -1209,7 +1172,7 @@ public:
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
return renderer.drawArc(mLocalBounds.left, mLocalBounds.top,
mLocalBounds.right, mLocalBounds.bottom,
mStartAngle, mSweepAngle, mUseCenter, getPaint(renderer));
mStartAngle, mSweepAngle, mUseCenter, mPaint);
}
virtual void output(int level, uint32_t logFlags) const {
@@ -1238,13 +1201,12 @@ public:
}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
return renderer.drawPath(mPath, getPaint(renderer));
return renderer.drawPath(mPath, mPaint);
}
virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
const DeferredDisplayState& state) {
const SkPaint* paint = getPaint(renderer);
renderer.getCaches().pathCache.precache(mPath, paint);
renderer.getCaches().pathCache.precache(mPath, mPaint);
deferInfo.batchId = DeferredDisplayList::kOpBatch_AlphaMaskTexture;
}
@@ -1268,7 +1230,7 @@ public:
}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
return renderer.drawLines(mPoints, mCount, getPaint(renderer));
return renderer.drawLines(mPoints, mCount, mPaint);
}
virtual void output(int level, uint32_t logFlags) const {
@@ -1295,7 +1257,7 @@ public:
: DrawLinesOp(points, count, paint) {}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
return renderer.drawPoints(mPoints, mCount, getPaint(renderer));
return renderer.drawPoints(mPoints, mCount, mPaint);
}
virtual void output(int level, uint32_t logFlags) const {
@@ -1320,9 +1282,8 @@ public:
virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
const DeferredDisplayState& state) {
const SkPaint* paint = getPaint(renderer);
FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(paint);
fontRenderer.precache(paint, mText, mCount, SkMatrix::I());
FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(mPaint);
fontRenderer.precache(mPaint, mText, mCount, SkMatrix::I());
deferInfo.batchId = mPaint->getColor() == SK_ColorBLACK ?
DeferredDisplayList::kOpBatch_Text :
@@ -1346,7 +1307,7 @@ public:
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
return renderer.drawTextOnPath(mText, mBytesCount, mCount, mPath,
mHOffset, mVOffset, getPaint(renderer));
mHOffset, mVOffset, mPaint);
}
virtual const char* name() { return "DrawTextOnPath"; }
@@ -1366,7 +1327,7 @@ public:
}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
return renderer.drawPosText(mText, mBytesCount, mCount, mPositions, getPaint(renderer));
return renderer.drawPosText(mText, mBytesCount, mCount, mPositions, mPaint);
}
virtual const char* name() { return "DrawPosText"; }
@@ -1386,12 +1347,11 @@ public:
virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
const DeferredDisplayState& state) {
const SkPaint* paint = getPaint(renderer);
FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(paint);
FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(mPaint);
SkMatrix transform;
renderer.findBestFontTransform(state.mMatrix, &transform);
if (mPrecacheTransform != transform) {
fontRenderer.precache(paint, mText, mCount, transform);
fontRenderer.precache(mPaint, mText, mCount, transform);
mPrecacheTransform = transform;
}
deferInfo.batchId = mPaint->getColor() == SK_ColorBLACK ?
@@ -1413,7 +1373,7 @@ public:
Rect bounds;
getLocalBounds(bounds);
return renderer.drawText(mText, mBytesCount, mCount, mX, mY,
mPositions, getPaint(renderer), mTotalAdvance, bounds);
mPositions, mPaint, mTotalAdvance, bounds);
}
virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
@@ -1428,7 +1388,7 @@ public:
// quickReject() will not occure in drawText() so we can use mLocalBounds
// directly, we do not need to account for shadow by calling getLocalBounds()
status |= renderer.drawText(op.mText, op.mBytesCount, op.mCount, op.mX, op.mY,
op.mPositions, op.getPaint(renderer), op.mTotalAdvance, op.mLocalBounds,
op.mPositions, op.mPaint, op.mTotalAdvance, op.mLocalBounds,
drawOpMode);
}
return status;

View File

@@ -437,12 +437,8 @@ status_t DisplayListRenderer::drawRects(const float* rects, int count, const SkP
return DrawGlInfo::kStatusDone;
}
void DisplayListRenderer::resetPaintFilter() {
addStateOp(new (alloc()) ResetPaintFilterOp());
}
void DisplayListRenderer::setupPaintFilter(int clearBits, int setBits) {
addStateOp(new (alloc()) SetupPaintFilterOp(clearBits, setBits));
void DisplayListRenderer::setDrawFilter(SkDrawFilter* filter) {
mDrawFilter.reset(filter);
}
void DisplayListRenderer::insertReorderBarrier(bool enableReorder) {

View File

@@ -17,10 +17,12 @@
#ifndef ANDROID_HWUI_DISPLAY_LIST_RENDERER_H
#define ANDROID_HWUI_DISPLAY_LIST_RENDERER_H
#include <SkDrawFilter.h>
#include <SkMatrix.h>
#include <SkPaint.h>
#include <SkPath.h>
#include <SkRegion.h>
#include <SkTLazy.h>
#include <cutils/compiler.h>
#include "DisplayList.h"
@@ -96,9 +98,8 @@ public:
virtual bool clipPath(const SkPath* path, SkRegion::Op op);
virtual bool clipRegion(const SkRegion* region, SkRegion::Op op);
// Misc - should be implemented with SkPaint inspection
virtual void resetPaintFilter();
virtual void setupPaintFilter(int clearBits, int setBits);
// Misc
virtual void setDrawFilter(SkDrawFilter* filter);
bool isCurrentTransformSimple() {
return currentTransform()->isSimple();
@@ -221,15 +222,27 @@ private:
inline const SkPaint* refPaint(const SkPaint* paint) {
if (!paint) return NULL;
const SkPaint* paintCopy = mPaintMap.valueFor(paint);
if (paintCopy == NULL || paintCopy->getGenerationID() != paint->getGenerationID()) {
paintCopy = new SkPaint(*paint);
// replaceValueFor() performs an add if the entry doesn't exist
mPaintMap.replaceValueFor(paint, paintCopy);
mDisplayListData->paints.add(paintCopy);
// If there is a draw filter apply it here and store the modified paint
// so that we don't need to modify the paint every time we access it.
SkTLazy<SkPaint> filteredPaint;
if (mDrawFilter.get()) {
paint = filteredPaint.init();
mDrawFilter->filter(filteredPaint.get(), SkDrawFilter::kPaint_Type);
}
return paintCopy;
// compute the hash key for the paint and check the cache.
const uint32_t key = paint->getHash();
const SkPaint* cachedPaint = mPaintMap.valueFor(key);
// In the unlikely event that 2 unique paints have the same hash we do a
// object equality check to ensure we don't erroneously dedup them.
if (cachedPaint == NULL || *cachedPaint != *paint) {
cachedPaint = new SkPaint(*paint);
// replaceValueFor() performs an add if the entry doesn't exist
mPaintMap.replaceValueFor(key, cachedPaint);
mDisplayListData->paints.add(cachedPaint);
}
return cachedPaint;
}
inline SkPaint* copyPaint(const SkPaint* paint) {
@@ -285,7 +298,7 @@ private:
return patch;
}
DefaultKeyedVector<const SkPaint*, const SkPaint*> mPaintMap;
DefaultKeyedVector<uint32_t, const SkPaint*> mPaintMap;
DefaultKeyedVector<const SkPath*, const SkPath*> mPathMap;
DefaultKeyedVector<const SkRegion*, const SkRegion*> mRegionMap;
@@ -300,6 +313,8 @@ private:
int mRestoreSaveCount;
SkAutoTUnref<SkDrawFilter> mDrawFilter;
friend class RenderNode;
}; // class DisplayListRenderer

View File

@@ -3057,47 +3057,10 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
///////////////////////////////////////////////////////////////////////////////
// Draw filters
///////////////////////////////////////////////////////////////////////////////
void OpenGLRenderer::resetPaintFilter() {
// when clearing the PaintFilter, the masks should also be cleared for simple DrawModifier
// comparison, see MergingDrawBatch::canMergeWith
mDrawModifiers.mHasDrawFilter = false;
mDrawModifiers.mPaintFilterClearBits = 0;
mDrawModifiers.mPaintFilterSetBits = 0;
}
void OpenGLRenderer::setupPaintFilter(int clearBits, int setBits) {
// TODO: don't bother with boolean, it's redundant with clear/set bits
mDrawModifiers.mHasDrawFilter = true;
mDrawModifiers.mPaintFilterClearBits = clearBits & SkPaint::kAllFlags;
mDrawModifiers.mPaintFilterSetBits = setBits & SkPaint::kAllFlags;
}
const SkPaint* OpenGLRenderer::filterPaint(const SkPaint* paint) {
// TODO: use CompatFlagsDrawFilter here, and combine logic with android/graphics/DrawFilter.cpp
// to avoid clobbering 0x02 paint flag
// Equivalent to the Java Paint's FILTER_BITMAP_FLAG.
static const uint32_t sFilterBitmapFlag = 0x02;
if (CC_LIKELY(!mDrawModifiers.mHasDrawFilter || !paint)) {
return paint;
}
const uint32_t clearBits = mDrawModifiers.mPaintFilterClearBits;
const uint32_t setBits = mDrawModifiers.mPaintFilterSetBits;
const uint32_t flags = (paint->getFlags() & ~clearBits) | setBits;
mFilteredPaint = *paint;
mFilteredPaint.setFlags(flags);
// check if paint filter trying to override bitmap filter
if ((clearBits | setBits) & sFilterBitmapFlag) {
mFilteredPaint.setFilterLevel(flags & sFilterBitmapFlag
? SkPaint::kLow_FilterLevel : SkPaint::kNone_FilterLevel);
}
return &mFilteredPaint;
void OpenGLRenderer::setDrawFilter(SkDrawFilter* filter) {
// We should never get here since we apply the draw filter when stashing
// the paints in the DisplayList.
LOG_ALWAYS_FATAL("OpenGLRenderer does not directly support DrawFilters");
}
///////////////////////////////////////////////////////////////////////////////

View File

@@ -70,11 +70,6 @@ struct DrawModifiers {
}
float mOverrideLayerAlpha;
// Draw filters
bool mHasDrawFilter;
int mPaintFilterClearBits;
int mPaintFilterSetBits;
};
enum StateDeferFlags {
@@ -205,14 +200,11 @@ public:
status_t drawShadow(float casterAlpha,
const VertexBuffer* ambientShadowVertexBuffer, const VertexBuffer* spotShadowVertexBuffer);
virtual void resetPaintFilter();
virtual void setupPaintFilter(int clearBits, int setBits);
virtual void setDrawFilter(SkDrawFilter* filter);
// If this value is set to < 1.0, it overrides alpha set on layer (see drawBitmap, drawLayer)
void setOverrideLayerAlpha(float alpha) { mDrawModifiers.mOverrideLayerAlpha = alpha; }
const SkPaint* filterPaint(const SkPaint* paint);
/**
* Store the current display state (most importantly, the current clip and transform), and
* additionally map the state's bounds from local to window coordinates.

View File

@@ -20,11 +20,12 @@
#include <SkColorFilter.h>
#include <SkPaint.h>
#include <SkRegion.h>
#include <utils/String8.h>
#include "AssetAtlas.h"
class SkDrawFilter;
namespace android {
class Functor;
@@ -173,9 +174,8 @@ public:
virtual bool clipPath(const SkPath* path, SkRegion::Op op) = 0;
virtual bool clipRegion(const SkRegion* region, SkRegion::Op op) = 0;
// Misc - should be implemented with SkPaint inspection
virtual void resetPaintFilter() = 0;
virtual void setupPaintFilter(int clearBits, int setBits) = 0;
// Misc
virtual void setDrawFilter(SkDrawFilter* filter) = 0;
// ----------------------------------------------------------------------------
// Canvas draw operations