Refactor HWUI to better handle Canvas DrawFilters.
First, this CL removes the need to decompose the DrawFilters in Java and instead passes the SkDrawFilter to HWUI directly. This also allows the removal of duplicated logic between HWUI and other Canvas implementations regarding Paint filter levels. Second, the DrawFilter is now stored in the DisplayListRenderer where we apply it to every paint BEFORE it is stored in the DisplayList. This eliminates the need to filter all Paints on playback and removes additional complexity at playback. Finally, as a result of storing the filtered paint we can now do a better job caching the paints. This takes advantage of recent changes in Skia to quickly enable quick hashing and comparison of paint objects. Change-Id: Iec507a2d894827975cc4f1d22241542bb0534b4e
This commit is contained in:
@@ -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() {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user