From 76d3a1b8d035d27bc80b0f2fc480a903bd001514 Mon Sep 17 00:00:00 2001 From: Derek Sollenberger Date: Tue, 10 Dec 2013 12:28:58 -0500 Subject: Removing SkiaColorFilter and inspecting the native object directly. bug: 10650594 Change-Id: I4fcf66d008765afa0e35d011f58bc792183cb74f --- libs/hwui/ProgramCache.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'libs/hwui/ProgramCache.cpp') diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp index a5ce6f603663..6d504100c0fa 100644 --- a/libs/hwui/ProgramCache.cpp +++ b/libs/hwui/ProgramCache.cpp @@ -148,15 +148,12 @@ const char* gFS_Uniforms_GradientSampler[2] = { }; const char* gFS_Uniforms_BitmapSampler = "uniform sampler2D bitmapSampler;\n"; -const char* gFS_Uniforms_ColorOp[4] = { +const char* gFS_Uniforms_ColorOp[3] = { // None "", // Matrix "uniform mat4 colorMatrix;\n" "uniform vec4 colorMatrixVector;\n", - // Lighting - "uniform vec4 lightingMul;\n" - "uniform vec4 lightingAdd;\n", // PorterDuff "uniform vec4 colorBlend;\n" }; @@ -311,17 +308,13 @@ const char* gFS_Main_FragColor_Blend = " gl_FragColor = blendFramebuffer(fragColor, gl_LastFragColor);\n"; const char* gFS_Main_FragColor_Blend_Swap = " gl_FragColor = blendFramebuffer(gl_LastFragColor, fragColor);\n"; -const char* gFS_Main_ApplyColorOp[4] = { +const char* gFS_Main_ApplyColorOp[3] = { // None "", // Matrix " fragColor *= colorMatrix;\n" " fragColor += colorMatrixVector;\n" " fragColor.rgb *= fragColor.a;\n", - // Lighting - " float lightingAlpha = fragColor.a;\n" - " fragColor = min(fragColor * lightingMul + (lightingAdd * lightingAlpha), lightingAlpha);\n" - " fragColor.a = lightingAlpha;\n", // PorterDuff " fragColor = blendColors(colorBlend, fragColor);\n" }; -- cgit v1.2.3-59-g8ed1b From deeda3d337aed1eee218b89a7aba5992ced371f0 Mon Sep 17 00:00:00 2001 From: Chris Craik Date: Mon, 5 May 2014 19:09:33 -0700 Subject: Round rect outline clipping Change-Id: Iee9cf4f719f6f1917507b69189ad114fa365917b --- api/current.txt | 2 + core/java/android/view/RenderNode.java | 5 ++ core/java/android/view/View.java | 15 +++- core/jni/android_view_RenderNode.cpp | 7 ++ graphics/java/android/graphics/Outline.java | 50 ++++++++----- libs/hwui/DeferredDisplayList.cpp | 11 +-- libs/hwui/DeferredDisplayList.h | 1 + libs/hwui/OpenGLRenderer.cpp | 47 ++++++++++-- libs/hwui/OpenGLRenderer.h | 2 + libs/hwui/Outline.h | 13 ++++ libs/hwui/Program.h | 28 ++++--- libs/hwui/ProgramCache.cpp | 50 ++++++++++++- libs/hwui/Rect.h | 2 +- libs/hwui/RenderNode.cpp | 4 + libs/hwui/Snapshot.cpp | 50 ++++++++++++- libs/hwui/Snapshot.h | 42 +++++++++++ libs/hwui/StatefulBaseRenderer.cpp | 20 ++++- libs/hwui/StatefulBaseRenderer.h | 10 ++- libs/hwui/utils/MathUtils.h | 4 + tests/HwAccelerationTest/AndroidManifest.xml | 9 +++ .../com/android/test/hwui/ClipOutlineActivity.java | 87 ++++++++++++++++++++++ 21 files changed, 401 insertions(+), 58 deletions(-) create mode 100644 tests/HwAccelerationTest/src/com/android/test/hwui/ClipOutlineActivity.java (limited to 'libs/hwui/ProgramCache.cpp') diff --git a/api/current.txt b/api/current.txt index 22892d88882f..809a5d3be1d5 100644 --- a/api/current.txt +++ b/api/current.txt @@ -10214,7 +10214,9 @@ package android.graphics { public final class Outline { ctor public Outline(); ctor public Outline(android.graphics.Outline); + method public boolean canClip(); method public boolean isValid(); + method public void reset(); method public void set(android.graphics.Outline); method public void setConvexPath(android.graphics.Path); method public void setOval(int, int, int, int); diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java index 0cfde94f2413..b2839cbcee6c 100644 --- a/core/java/android/view/RenderNode.java +++ b/core/java/android/view/RenderNode.java @@ -387,6 +387,10 @@ public class RenderNode { nSetClipToOutline(mNativeRenderNode, clipToOutline); } + public boolean getClipToOutline() { + return nGetClipToOutline(mNativeRenderNode); + } + /** * Controls the RenderNode's circular reveal clip. */ @@ -919,6 +923,7 @@ public class RenderNode { private static native void nSetAnimationMatrix(long renderNode, long animationMatrix); private static native boolean nHasOverlappingRendering(long renderNode); + private static native boolean nGetClipToOutline(long renderNode); private static native float nGetAlpha(long renderNode); private static native float nGetLeft(long renderNode); private static native float nGetTop(long renderNode); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index e829141ad18e..83bb59781575 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -10696,9 +10696,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mRenderNode.setOutline(mOutline); } - // TODO: remove - public final boolean getClipToOutline() { return false; } - public void setClipToOutline(boolean clipToOutline) {} + public final boolean getClipToOutline() { + return mRenderNode.getClipToOutline(); + } + + public void setClipToOutline(boolean clipToOutline) { + // TODO: add a fast invalidation here + if (getClipToOutline() != clipToOutline) { + mRenderNode.setClipToOutline(clipToOutline); + } + } private void queryOutlineFromBackgroundIfUndefined() { if ((mPrivateFlags3 & PFLAG3_OUTLINE_DEFINED) == 0) { @@ -10707,7 +10714,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mOutline = new Outline(); } else { //invalidate outline, to ensure background calculates it - mOutline.set(null); + mOutline.reset(); } if (mBackground.getOutline(mOutline)) { if (!mOutline.isValid()) { diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp index e45a901bc73c..cbd806873108 100644 --- a/core/jni/android_view_RenderNode.cpp +++ b/core/jni/android_view_RenderNode.cpp @@ -285,6 +285,12 @@ static jboolean android_view_RenderNode_hasOverlappingRendering(JNIEnv* env, return renderNode->stagingProperties().hasOverlappingRendering(); } +static jboolean android_view_RenderNode_getClipToOutline(JNIEnv* env, + jobject clazz, jlong renderNodePtr) { + RenderNode* renderNode = reinterpret_cast(renderNodePtr); + return renderNode->stagingProperties().getOutline().getShouldClip(); +} + static jfloat android_view_RenderNode_getAlpha(JNIEnv* env, jobject clazz, jlong renderNodePtr) { RenderNode* renderNode = reinterpret_cast(renderNodePtr); @@ -505,6 +511,7 @@ static JNINativeMethod gMethods[] = { { "nOffsetTopAndBottom", "(JF)V", (void*) android_view_RenderNode_offsetTopAndBottom }, { "nHasOverlappingRendering", "(J)Z", (void*) android_view_RenderNode_hasOverlappingRendering }, + { "nGetClipToOutline", "(J)Z", (void*) android_view_RenderNode_getClipToOutline }, { "nGetAlpha", "(J)F", (void*) android_view_RenderNode_getAlpha }, { "nGetLeft", "(J)F", (void*) android_view_RenderNode_getLeft }, { "nGetTop", "(J)F", (void*) android_view_RenderNode_getTop }, diff --git a/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java index b5c0801af5b9..c6ba75c520e2 100644 --- a/graphics/java/android/graphics/Outline.java +++ b/graphics/java/android/graphics/Outline.java @@ -53,8 +53,7 @@ public final class Outline { set(src); } - /** @hide */ - public void markInvalid() { + public void reset() { mRadius = 0; mRect = null; mPath = null; @@ -74,27 +73,21 @@ public final class Outline { * * @param src Source outline to copy from. */ - public void set(@Nullable Outline src) { - if (src == null) { - mRadius = 0; - mRect = null; - mPath = null; - } else { - if (src.mPath != null) { - if (mPath == null) { - mPath = new Path(); - } - mPath.set(src.mPath); - mRect = null; + public void set(@NonNull Outline src) { + if (src.mPath != null) { + if (mPath == null) { + mPath = new Path(); } - if (src.mRect != null) { - if (mRect == null) { - mRect = new Rect(); - } - mRect.set(src.mRect); + mPath.set(src.mPath); + mRect = null; + } + if (src.mRect != null) { + if (mRect == null) { + mRect = new Rect(); } - mRadius = src.mRadius; + mRect.set(src.mRect); } + mRadius = src.mRadius; } /** @@ -134,6 +127,11 @@ public final class Outline { * Sets the outline to the oval defined by input rect. */ public void setOval(int left, int top, int right, int bottom) { + if ((bottom - top) == (right - left)) { + // represent circle as round rect, for efficiency, and to enable clipping + setRoundRect(left, top, right, bottom, (bottom - top) / 2.0f); + return; + } mRect = null; if (mPath == null) mPath = new Path(); mPath.reset(); @@ -160,4 +158,16 @@ public final class Outline { mRadius = -1.0f; mPath.set(convexPath); } + + /** + * Returns whether the outline can be used to clip a View. + * + * Currently, only outlines that can be represented as a rectangle, circle, or round rect + * support clipping. + * + * @see {@link View#setClipToOutline(boolean)} + */ + public boolean canClip() { + return mRect != null; + } } diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp index 45b6624029c0..3016814deafc 100644 --- a/libs/hwui/DeferredDisplayList.cpp +++ b/libs/hwui/DeferredDisplayList.cpp @@ -28,6 +28,7 @@ #include "DeferredDisplayList.h" #include "DisplayListOp.h" #include "OpenGLRenderer.h" +#include "utils/MathUtils.h" #if DEBUG_DEFER #define DEFER_LOGD(...) ALOGD(__VA_ARGS__) @@ -146,10 +147,6 @@ private: mergeid_t mMergeId; }; -// compare alphas approximately, with a small margin -#define NEQ_FALPHA(lhs, rhs) \ - fabs((float)lhs - (float)rhs) > 0.001f - class MergingDrawBatch : public DrawBatch { public: MergingDrawBatch(DeferInfo& deferInfo, int width, int height) : @@ -196,7 +193,11 @@ public: const DeferredDisplayState* lhs = state; const DeferredDisplayState* rhs = mOps[0].state; - if (NEQ_FALPHA(lhs->mAlpha, rhs->mAlpha)) return false; + if (!MathUtils::areEqual(lhs->mAlpha, rhs->mAlpha)) return false; + + // Identical round rect clip state means both ops will clip in the same way, or not at all. + // As the state objects are const, we can compare their pointers to determine mergeability + if (lhs->mRoundRectClipState != rhs->mRoundRectClipState) return false; /* Clipping compatibility check * diff --git a/libs/hwui/DeferredDisplayList.h b/libs/hwui/DeferredDisplayList.h index fca3588aa344..48489c2b4bfb 100644 --- a/libs/hwui/DeferredDisplayList.h +++ b/libs/hwui/DeferredDisplayList.h @@ -64,6 +64,7 @@ public: mat4 mMatrix; DrawModifiers mDrawModifiers; float mAlpha; + const RoundRectClipState* mRoundRectClipState; }; class OpStatePair { diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 4df97e672c5b..7993c0fc8491 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -711,6 +711,7 @@ int OpenGLRenderer::saveLayerDeferred(float left, float top, float right, float mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f); mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom); mSnapshot->initializeViewport(bounds.getWidth(), bounds.getHeight()); + mSnapshot->roundRectClipState = NULL; } } @@ -844,6 +845,7 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip) { mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f); mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom); mSnapshot->initializeViewport(bounds.getWidth(), bounds.getHeight()); + mSnapshot->roundRectClipState = NULL; endTiling(); debugOverdraw(false, false); @@ -872,8 +874,6 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip) { // Change the ortho projection glViewport(0, 0, bounds.getWidth(), bounds.getHeight()); - - return true; } @@ -892,7 +892,7 @@ void OpenGLRenderer::composeLayer(const Snapshot& removed, const Snapshot& resto bool clipRequired = false; calculateQuickRejectForScissor(rect.left, rect.top, rect.right, rect.bottom, - &clipRequired, false); // safely ignore return, should never be rejected + &clipRequired, NULL, false); // safely ignore return, should never be rejected mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired); if (fboLayer) { @@ -1367,6 +1367,9 @@ bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDef state.mMatrix.load(*currentMatrix); state.mDrawModifiers = mDrawModifiers; state.mAlpha = currentSnapshot()->alpha; + + // always store/restore, since it's just a pointer + state.mRoundRectClipState = currentSnapshot()->roundRectClipState; return false; } @@ -1374,6 +1377,7 @@ void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool setMatrix(state.mMatrix); mSnapshot->alpha = state.mAlpha; mDrawModifiers = state.mDrawModifiers; + mSnapshot->roundRectClipState = state.mRoundRectClipState; if (state.mClipValid && !skipClipRestore) { mSnapshot->setClip(state.mClip.left, state.mClip.top, @@ -1449,7 +1453,7 @@ void OpenGLRenderer::setStencilFromClip() { mCaches.stencil.enableWrite(); - // Clear the stencil but first make sure we restrict drawing + // Clear and update the stencil, but first make sure we restrict drawing // to the region's bounds bool resetScissor = mCaches.enableScissor(); if (resetScissor) { @@ -1457,7 +1461,10 @@ void OpenGLRenderer::setStencilFromClip() { setScissorFromClip(); } mCaches.stencil.clear(); - if (resetScissor) mCaches.disableScissor(); + + // stash and disable the outline clip state, since stencil doesn't account for outline + bool storedSkipOutlineClip = mSkipOutlineClip; + mSkipOutlineClip = true; SkPaint paint; paint.setColor(0xff000000); @@ -1470,6 +1477,8 @@ 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(*(currentSnapshot()->clipRegion), paint, false); + if (resetScissor) mCaches.disableScissor(); + mSkipOutlineClip = storedSkipOutlineClip; mCaches.stencil.enableTest(); @@ -1494,7 +1503,6 @@ void OpenGLRenderer::setStencilFromClip() { */ bool OpenGLRenderer::quickRejectSetupScissor(float left, float top, float right, float bottom, const SkPaint* paint) { - bool clipRequired = false; bool snapOut = paint && paint->isAntiAlias(); if (paint && paint->getStyle() != SkPaint::kFill_Style) { @@ -1505,13 +1513,17 @@ bool OpenGLRenderer::quickRejectSetupScissor(float left, float top, float right, bottom += outset; } - if (calculateQuickRejectForScissor(left, top, right, bottom, &clipRequired, snapOut)) { + bool clipRequired = false; + bool roundRectClipRequired = false; + if (calculateQuickRejectForScissor(left, top, right, bottom, + &clipRequired, &roundRectClipRequired, snapOut)) { return true; } if (!isRecording()) { // not quick rejected, so enable the scissor if clipRequired mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired); + mSkipOutlineClip = !roundRectClipRequired; } return false; } @@ -1668,6 +1680,18 @@ void OpenGLRenderer::setupDrawBlending(const SkPaint* paint, bool blend, bool sw void OpenGLRenderer::setupDrawProgram() { useProgram(mCaches.programCache.get(mDescription)); + if (mDescription.hasRoundRectClip) { + // TODO: avoid doing this repeatedly, stashing state pointer in program + const RoundRectClipState* state = mSnapshot->roundRectClipState; + const Rect& innerRect = state->outlineInnerRect; + glUniform4f(mCaches.currentProgram->getUniform("roundRectInnerRectLTRB"), + innerRect.left, innerRect.top, + innerRect.right, innerRect.bottom); + glUniform1f(mCaches.currentProgram->getUniform("roundRectRadius"), + state->outlineRadius); + glUniformMatrix4fv(mCaches.currentProgram->getUniform("roundRectInvTransform"), + 1, GL_FALSE, &state->matrix.data[0]); + } } void OpenGLRenderer::setupDrawDirtyRegionsDisabled() { @@ -2902,7 +2926,7 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) { bool clipRequired = false; const bool rejected = calculateQuickRejectForScissor(x, y, - x + layer->layer.getWidth(), y + layer->layer.getHeight(), &clipRequired, false); + x + layer->layer.getWidth(), y + layer->layer.getHeight(), &clipRequired, NULL, false); if (rejected) { if (transform && !transform->isIdentity()) { @@ -3433,6 +3457,13 @@ void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, f void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, ProgramDescription& description, bool swapSrcDst) { + + if (mSnapshot->roundRectClipState != NULL /*&& !mSkipOutlineClip*/) { + blend = true; + mDescription.hasRoundRectClip = true; + } + mSkipOutlineClip = true; + if (mCountOverdraw) { if (!mCaches.blend) glEnable(GL_BLEND); if (mCaches.lastSrcMode != GL_ONE || mCaches.lastDstMode != GL_ONE) { diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index b58b817c213a..f70ae5838b4a 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -993,6 +993,8 @@ private: bool mCountOverdraw; float mOverdraw; + bool mSkipOutlineClip; + friend class DisplayListRenderer; friend class Layer; friend class TextSetupFunctor; diff --git a/libs/hwui/Outline.h b/libs/hwui/Outline.h index 530be3023b10..5c24335bc41a 100644 --- a/libs/hwui/Outline.h +++ b/libs/hwui/Outline.h @@ -58,11 +58,24 @@ public: mShouldClip = clip; } + bool getShouldClip() const { + return mShouldClip; + } + bool willClip() const { // only round rect outlines can be used for clipping return mShouldClip && (mType == kOutlineType_RoundRect); } + bool getAsRoundRect(Rect* outRect, float* outRadius) const { + if (mType == kOutlineType_RoundRect) { + outRect->set(mBounds); + *outRadius = mRadius; + return true; + } + return false; + } + const SkPath* getPath() const { if (mType == kOutlineType_None) return NULL; diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h index 33c91b3a68fe..3e191d0a0186 100644 --- a/libs/hwui/Program.h +++ b/libs/hwui/Program.h @@ -45,17 +45,18 @@ namespace uirenderer { #define COLOR_COMPONENT_THRESHOLD 1.0f #define COLOR_COMPONENT_INV_THRESHOLD 0.0f -#define PROGRAM_KEY_TEXTURE 0x1 -#define PROGRAM_KEY_A8_TEXTURE 0x2 -#define PROGRAM_KEY_BITMAP 0x4 -#define PROGRAM_KEY_GRADIENT 0x8 -#define PROGRAM_KEY_BITMAP_FIRST 0x10 -#define PROGRAM_KEY_COLOR_MATRIX 0x20 -#define PROGRAM_KEY_COLOR_BLEND 0x40 -#define PROGRAM_KEY_BITMAP_NPOT 0x80 -#define PROGRAM_KEY_SWAP_SRC_DST 0x2000 - -#define PROGRAM_KEY_BITMAP_WRAPS_MASK 0x600 +#define PROGRAM_KEY_TEXTURE 0x01 +#define PROGRAM_KEY_A8_TEXTURE 0x02 +#define PROGRAM_KEY_BITMAP 0x04 +#define PROGRAM_KEY_GRADIENT 0x08 +#define PROGRAM_KEY_BITMAP_FIRST 0x10 +#define PROGRAM_KEY_COLOR_MATRIX 0x20 +#define PROGRAM_KEY_COLOR_BLEND 0x40 +#define PROGRAM_KEY_BITMAP_NPOT 0x80 + +#define PROGRAM_KEY_SWAP_SRC_DST 0x2000 + +#define PROGRAM_KEY_BITMAP_WRAPS_MASK 0x600 #define PROGRAM_KEY_BITMAP_WRAPT_MASK 0x1800 // Encode the xfermodes on 6 bits @@ -83,6 +84,7 @@ namespace uirenderer { #define PROGRAM_HAS_DEBUG_HIGHLIGHT 42 #define PROGRAM_EMULATE_STENCIL 43 +#define PROGRAM_HAS_ROUND_RECT_CLIP 44 /////////////////////////////////////////////////////////////////////////////// // Types @@ -158,6 +160,7 @@ struct ProgramDescription { bool hasDebugHighlight; bool emulateStencil; + bool hasRoundRectClip; /** * Resets this description. All fields are reset back to the default @@ -198,6 +201,8 @@ struct ProgramDescription { gamma = 2.2f; hasDebugHighlight = false; + emulateStencil = false; + hasRoundRectClip = false; } /** @@ -264,6 +269,7 @@ struct ProgramDescription { if (hasColors) key |= programid(0x1) << PROGRAM_HAS_COLORS; if (hasDebugHighlight) key |= programid(0x1) << PROGRAM_HAS_DEBUG_HIGHLIGHT; if (emulateStencil) key |= programid(0x1) << PROGRAM_EMULATE_STENCIL; + if (hasRoundRectClip) key |= programid(0x1) << PROGRAM_HAS_ROUND_RECT_CLIP; return key; } diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp index 6d504100c0fa..f451690709f9 100644 --- a/libs/hwui/ProgramCache.cpp +++ b/libs/hwui/ProgramCache.cpp @@ -58,6 +58,8 @@ const char* gVS_Header_Uniforms_HasGradient = const char* gVS_Header_Uniforms_HasBitmap = "uniform mat4 textureTransform;\n" "uniform mediump vec2 textureDimension;\n"; +const char* gVS_Header_Uniforms_HasRoundRectClip = + "uniform mat4 roundRectInvTransform;\n"; const char* gVS_Header_Varyings_HasTexture = "varying vec2 outTexCoords;\n"; const char* gVS_Header_Varyings_HasColors = @@ -85,6 +87,8 @@ const char* gVS_Header_Varyings_HasGradient[6] = { "varying highp vec2 sweep;\n" "varying vec2 ditherTexCoords;\n", }; +const char* gVS_Header_Varyings_HasRoundRectClip = + "varying vec2 roundRectPos;\n"; const char* gVS_Main = "\nvoid main(void) {\n"; const char* gVS_Main_OutTexCoords = @@ -115,9 +119,12 @@ const char* gVS_Main_OutGradient[6] = { const char* gVS_Main_OutBitmapTexCoords = " outBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n"; const char* gVS_Main_Position = - " gl_Position = projection * transform * position;\n"; + " vec4 transformedPosition = projection * transform * position;\n" + " gl_Position = transformedPosition;\n"; const char* gVS_Main_AAVertexShape = " alpha = vtxAlpha;\n"; +const char* gVS_Main_HasRoundRectClip = + " roundRectPos = (roundRectInvTransform * transformedPosition).xy;\n"; const char* gVS_Footer = "}\n\n"; @@ -160,6 +167,10 @@ const char* gFS_Uniforms_ColorOp[3] = { const char* gFS_Uniforms_Gamma = "uniform float gamma;\n"; +const char* gFS_Uniforms_HasRoundRectClip = + "uniform vec4 roundRectInnerRectLTRB;\n" + "uniform float roundRectRadius;\n"; + const char* gFS_Main = "\nvoid main(void) {\n" " lowp vec4 fragColor;\n"; @@ -318,6 +329,15 @@ const char* gFS_Main_ApplyColorOp[3] = { // PorterDuff " fragColor = blendColors(colorBlend, fragColor);\n" }; + +// Note: LTRB -> xyzw +const char* gFS_Main_FragColor_HasRoundRectClip = + " mediump vec2 fragToLT = roundRectInnerRectLTRB.xy - roundRectPos;\n" + " mediump vec2 fragFromRB = roundRectPos - roundRectInnerRectLTRB.zw;\n" + " mediump vec2 dist = max(max(fragToLT, fragFromRB), vec2(0.0, 0.0));\n" + " mediump float linearDist = roundRectRadius - length(dist);\n" + " gl_FragColor *= clamp(linearDist, 0.0, 1.0);\n"; + const char* gFS_Main_DebugHighlight = " gl_FragColor.rgb = vec3(0.0, gl_FragColor.a, 0.0);\n"; const char* gFS_Main_EmulateStencil = @@ -462,6 +482,9 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description if (description.hasBitmap) { shader.append(gVS_Header_Uniforms_HasBitmap); } + if (description.hasRoundRectClip) { + shader.append(gVS_Header_Uniforms_HasRoundRectClip); + } // Varyings if (description.hasTexture || description.hasExternalTexture) { shader.append(gVS_Header_Varyings_HasTexture); @@ -478,6 +501,9 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description if (description.hasBitmap) { shader.append(gVS_Header_Varyings_HasBitmap); } + if (description.hasRoundRectClip) { + shader.append(gVS_Header_Varyings_HasRoundRectClip); + } // Begin the shader shader.append(gVS_Main); { @@ -500,6 +526,9 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description if (description.hasGradient) { shader.append(gVS_Main_OutGradient[gradientIndex(description)]); } + if (description.hasRoundRectClip) { + shader.append(gVS_Main_HasRoundRectClip); + } } // End the shader shader.append(gVS_Footer); @@ -546,6 +575,9 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti if (description.hasBitmap) { shader.append(gVS_Header_Varyings_HasBitmap); } + if (description.hasRoundRectClip) { + shader.append(gVS_Header_Varyings_HasRoundRectClip); + } // Uniforms int modulateOp = MODULATE_OP_NO_MODULATE; @@ -568,11 +600,18 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti if (description.hasGammaCorrection) { shader.append(gFS_Uniforms_Gamma); } + if (description.hasRoundRectClip) { + shader.append(gFS_Uniforms_HasRoundRectClip); + } // Optimization for common cases - if (!description.isAA && !blendFramebuffer && !description.hasColors && - description.colorOp == ProgramDescription::kColorNone && - !description.hasDebugHighlight && !description.emulateStencil) { + if (!description.isAA + && !blendFramebuffer + && !description.hasColors + && description.colorOp == ProgramDescription::kColorNone + && !description.hasDebugHighlight + && !description.emulateStencil + && !description.hasRoundRectClip) { bool fast = false; const bool noShader = !description.hasGradient && !description.hasBitmap; @@ -722,6 +761,9 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti if (description.hasColors) { shader.append(gFS_Main_FragColor_HasColors); } + if (description.hasRoundRectClip) { + shader.append(gFS_Main_FragColor_HasRoundRectClip); + } if (description.hasDebugHighlight) { shader.append(gFS_Main_DebugHighlight); } diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h index f38d8b7d0ef6..2ddbbd71709f 100644 --- a/libs/hwui/Rect.h +++ b/libs/hwui/Rect.h @@ -234,7 +234,7 @@ public: bottom = ceilf(bottom); } - void dump(const char* label) const { + void dump(const char* label = NULL) const { ALOGD("%s[l=%f t=%f r=%f b=%f]", label ? label : "Rect", left, top, right, bottom); } diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index fba482d0f483..ad48f44429a3 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -653,6 +653,10 @@ void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) { bool quickRejected = properties().getClipToBounds() && renderer.quickRejectConservative(0, 0, properties().getWidth(), properties().getHeight()); if (!quickRejected) { + if (mProperties.getOutline().willClip()) { + renderer.setClippingOutline(alloc, &(mProperties.getOutline())); + } + Vector zTranslatedNodes; buildZSortedChildList(zTranslatedNodes); diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp index 029b56d6ae00..80f7eca2cb9f 100644 --- a/libs/hwui/Snapshot.cpp +++ b/libs/hwui/Snapshot.cpp @@ -20,6 +20,8 @@ #include +#include "utils/MathUtils.h" + namespace android { namespace uirenderer { @@ -34,7 +36,8 @@ Snapshot::Snapshot() , fbo(0) , invisible(false) , empty(false) - , alpha(1.0f) { + , alpha(1.0f) + , roundRectClipState(NULL) { transform = &mTransformRoot; clipRect = &mClipRectRoot; region = NULL; @@ -53,8 +56,8 @@ Snapshot::Snapshot(const sp& s, int saveFlags) , invisible(s->invisible) , empty(false) , alpha(s->alpha) + , roundRectClipState(s->roundRectClipState) , mViewportData(s->mViewportData) { - if (saveFlags & SkCanvas::kMatrix_SaveFlag) { mTransformRoot.load(*s->transform); transform = &mTransformRoot; @@ -203,6 +206,49 @@ void Snapshot::resetTransform(float x, float y, float z) { transform->loadTranslate(x, y, z); } +/////////////////////////////////////////////////////////////////////////////// +// Clipping outline +/////////////////////////////////////////////////////////////////////////////// + +void Snapshot::setClippingOutline(LinearAllocator& allocator, const Outline* outline) { + Rect bounds; + float radius; + if (!outline->getAsRoundRect(&bounds, &radius)) return; // only RR supported + + if (!MathUtils::isPositive(radius)) return; // leave clipping up to rect clipping + + RoundRectClipState* state = new (allocator) RoundRectClipState; + + // store the inverse drawing matrix + Matrix4 outlineDrawingMatrix; + outlineDrawingMatrix.load(getOrthoMatrix()); + outlineDrawingMatrix.multiply(*transform); + state->matrix.loadInverse(outlineDrawingMatrix); + + // compute area under rounded corners - only draws overlapping these rects need to be clipped + for (int i = 0 ; i < 4; i++) { + state->dangerRects[i] = bounds; + } + state->dangerRects[0].bottom = state->dangerRects[1].bottom = bounds.top + radius; + state->dangerRects[0].right = state->dangerRects[2].right = bounds.left + radius; + state->dangerRects[1].left = state->dangerRects[3].left = bounds.right - radius; + state->dangerRects[2].top = state->dangerRects[3].top = bounds.bottom - radius; + for (int i = 0; i < 4; i++) { + transform->mapRect(state->dangerRects[i]); + + // round danger rects out as though they are AA geometry (since they essentially are) + state->dangerRects[i].snapGeometryToPixelBoundaries(true); + } + + // store RR area + bounds.inset(radius); + state->outlineInnerRect = bounds; + state->outlineRadius = radius; + + // store as immutable so, for this frame, pointer uniquely identifies this bundle of shader info + roundRectClipState = state; +} + /////////////////////////////////////////////////////////////////////////////// // Queries /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h index e9ab1ff147e6..435736c5a4e0 100644 --- a/libs/hwui/Snapshot.h +++ b/libs/hwui/Snapshot.h @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -27,11 +28,39 @@ #include "Layer.h" #include "Matrix.h" +#include "Outline.h" #include "Rect.h" +#include "utils/Macros.h" namespace android { namespace uirenderer { +/** + * Temporary structure holding information for a single outline clip. + * + * These structures are treated as immutable once created, and only exist for a single frame, which + * is why they may only be allocated with a LinearAllocator. + */ +class RoundRectClipState { +public: + /** static void* operator new(size_t size); PURPOSELY OMITTED, allocator only **/ + static void* operator new(size_t size, LinearAllocator& allocator) { + return allocator.alloc(size); + } + + bool areaRequiresRoundRectClip(const Rect& rect) const { + return rect.intersects(dangerRects[0]) + || rect.intersects(dangerRects[1]) + || rect.intersects(dangerRects[2]) + || rect.intersects(dangerRects[3]); + } + + Matrix4 matrix; + Rect dangerRects[4]; + Rect outlineInnerRect; + float outlineRadius; +}; + /** * A snapshot holds information about the current state of the rendering * surface. A snapshot is usually created whenever the user calls save() @@ -132,6 +161,11 @@ public: int getViewportHeight() const { return mViewportData.mHeight; } const Matrix4& getOrthoMatrix() const { return mViewportData.mOrthoMatrix; } + /** + * Sets (and replaces) the current clipping outline + */ + void setClippingOutline(LinearAllocator& allocator, const Outline* outline); + /** * Indicates whether this snapshot should be ignored. A snapshot * is typicalled ignored if its layer is invisible or empty. @@ -225,6 +259,14 @@ public: */ float alpha; + /** + * Current clipping round rect. + * + * Points to data not owned by the snapshot, and may only be replaced by subsequent RR clips, + * never modified. + */ + const RoundRectClipState* roundRectClipState; + void dump() const; private: diff --git a/libs/hwui/StatefulBaseRenderer.cpp b/libs/hwui/StatefulBaseRenderer.cpp index aa83e20cd8a5..7d299f09b131 100644 --- a/libs/hwui/StatefulBaseRenderer.cpp +++ b/libs/hwui/StatefulBaseRenderer.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#define LOG_TAG "OpenGLRenderer" + #include #include "StatefulBaseRenderer.h" @@ -180,6 +182,10 @@ bool StatefulBaseRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) { return !mSnapshot->clipRect->isEmpty(); } +void StatefulBaseRenderer::setClippingOutline(LinearAllocator& allocator, const Outline* outline) { + mSnapshot->setClippingOutline(allocator, outline); +} + /////////////////////////////////////////////////////////////////////////////// // Quick Rejection /////////////////////////////////////////////////////////////////////////////// @@ -195,7 +201,9 @@ bool StatefulBaseRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) { * See Rect::snapGeometryToPixelBoundaries() */ bool StatefulBaseRenderer::calculateQuickRejectForScissor(float left, float top, - float right, float bottom, bool* clipRequired, bool snapOut) const { + float right, float bottom, + bool* clipRequired, bool* roundRectClipRequired, + bool snapOut) const { if (mSnapshot->isIgnored() || bottom <= top || right <= left) { return true; } @@ -210,7 +218,15 @@ bool StatefulBaseRenderer::calculateQuickRejectForScissor(float left, float top, if (!clipRect.intersects(r)) return true; // clip is required if geometry intersects clip rect - if (clipRequired) *clipRequired = !clipRect.contains(r); + if (clipRequired) { + *clipRequired = !clipRect.contains(r); + } + + // round rect clip is required if RR clip exists, and geometry intersects its corners + if (roundRectClipRequired) { + *roundRectClipRequired = mSnapshot->roundRectClipState != NULL + && mSnapshot->roundRectClipState->areaRequiresRoundRectClip(r); + } return false; } diff --git a/libs/hwui/StatefulBaseRenderer.h b/libs/hwui/StatefulBaseRenderer.h index 9fbf2ca821b7..2e7f279bedc8 100644 --- a/libs/hwui/StatefulBaseRenderer.h +++ b/libs/hwui/StatefulBaseRenderer.h @@ -88,6 +88,14 @@ public: virtual bool clipPath(const SkPath* path, SkRegion::Op op); virtual bool clipRegion(const SkRegion* region, SkRegion::Op op); + /** + * Does not support different clipping Ops (that is, every call to setClippingOutline is + * effectively using SkRegion::kReplaceOp) + * + * The clipping outline is independent from the regular clip. + */ + void setClippingOutline(LinearAllocator& allocator, const Outline* outline); + protected: const Rect& getRenderTargetClipBounds() const { return mSnapshot->getRenderTargetClip(); } @@ -106,7 +114,7 @@ protected: // Clip bool calculateQuickRejectForScissor(float left, float top, float right, float bottom, - bool* clipRequired, bool snapOut) const; + bool* clipRequired, bool* roundRectClipRequired, bool snapOut) const; /** * Called just after a restore has occurred. The 'removed' snapshot popped from the stack, diff --git a/libs/hwui/utils/MathUtils.h b/libs/hwui/utils/MathUtils.h index 1a7082bda660..997acde2e606 100644 --- a/libs/hwui/utils/MathUtils.h +++ b/libs/hwui/utils/MathUtils.h @@ -34,6 +34,10 @@ public: return value >= gNonZeroEpsilon; } + inline static bool areEqual(float valueA, float valueB) { + return isZero(valueA - valueB); + } + inline static int min(int a, int b) { return a < b ? a : b; } diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml index 3e9cf43cf6aa..db802c56a03b 100644 --- a/tests/HwAccelerationTest/AndroidManifest.xml +++ b/tests/HwAccelerationTest/AndroidManifest.xml @@ -215,6 +215,15 @@ + + + + + + + diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ClipOutlineActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ClipOutlineActivity.java new file mode 100644 index 000000000000..af448e8e6ffc --- /dev/null +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ClipOutlineActivity.java @@ -0,0 +1,87 @@ +/* + * 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. + */ + +package com.android.test.hwui; + +import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; +import android.app.Activity; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Outline; +import android.graphics.Path; +import android.graphics.Rect; +import android.os.Bundle; +import android.widget.FrameLayout; +import android.widget.TextView; + +public class ClipOutlineActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + final RegionView group = new RegionView(this); + + final TextView text = new TextView(this); + text.setText(buildText()); + group.addView(text); + + setContentView(group); + + ObjectAnimator animator = ObjectAnimator.ofFloat(group, "clipPosition", 0.0f, 1.0f); + animator.setDuration(3000); + animator.setRepeatCount(ValueAnimator.INFINITE); + animator.setRepeatMode(ValueAnimator.REVERSE); + animator.start(); + } + + private static CharSequence buildText() { + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < 10; i++) { + buffer.append(LOREM_IPSUM); + } + return buffer; + } + + public static class RegionView extends FrameLayout { + private float mClipPosition = 0.0f; + private Outline mOutline = new Outline(); + private Rect mRect = new Rect(); + + public RegionView(Context c) { + super(c); + setClipToOutline(true); + } + + public float getClipPosition() { + return mClipPosition; + } + + public void setClipPosition(float clipPosition) { + mClipPosition = clipPosition; + int w = getWidth() / 2; + int h = getHeight() / 2; + + mRect.set(0, 0, w, h); + mRect.offset((int) (clipPosition * w), getHeight() / 4); + mOutline.setRoundRect(mRect, w / 2); + setOutline(mOutline); + invalidate(); + } + } + + private static final String LOREM_IPSUM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed sagittis molestie aliquam. Donec metus metus, laoreet nec sagittis vitae, ultricies sit amet eros. Suspendisse sed massa sit amet felis consectetur gravida. In vitae erat mi, in egestas nisl. Phasellus quis ipsum massa, at scelerisque arcu. Nam lectus est, pellentesque eget lacinia non, congue vitae augue. Aliquam erat volutpat. Pellentesque bibendum tincidunt viverra. Aliquam erat volutpat. Maecenas pretium vulputate placerat. Nulla varius elementum rutrum. Aenean mollis blandit imperdiet. Pellentesque interdum fringilla ligula."; +} -- cgit v1.2.3-59-g8ed1b From f99f320dc79e290a89d668243b6d77c3442b36ab Mon Sep 17 00:00:00 2001 From: Chris Craik Date: Tue, 5 Aug 2014 15:31:52 -0700 Subject: Fix large radius RR clipping issue on certain devices bug:16804363 Since dist can be in the 1000s of pixels, and length() may square it in its current precision, scale the value down significantly first, since final precision isn't very important. Change-Id: Id20f7a49d6171355c8e242442c2b5083f746dca3 --- libs/hwui/ProgramCache.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'libs/hwui/ProgramCache.cpp') diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp index f451690709f9..3ef2a716905d 100644 --- a/libs/hwui/ProgramCache.cpp +++ b/libs/hwui/ProgramCache.cpp @@ -334,8 +334,10 @@ const char* gFS_Main_ApplyColorOp[3] = { const char* gFS_Main_FragColor_HasRoundRectClip = " mediump vec2 fragToLT = roundRectInnerRectLTRB.xy - roundRectPos;\n" " mediump vec2 fragFromRB = roundRectPos - roundRectInnerRectLTRB.zw;\n" - " mediump vec2 dist = max(max(fragToLT, fragFromRB), vec2(0.0, 0.0));\n" - " mediump float linearDist = roundRectRadius - length(dist);\n" + + // divide + multiply by 128 to avoid falling out of range in length() function + " mediump vec2 dist = max(max(fragToLT, fragFromRB), vec2(0.0, 0.0)) / 128.0;\n" + " mediump float linearDist = roundRectRadius - (length(dist) * 128.0);\n" " gl_FragColor *= clamp(linearDist, 0.0, 1.0);\n"; const char* gFS_Main_DebugHighlight = -- cgit v1.2.3-59-g8ed1b From bf75945e7a1ae7c1000682716643c942c1e19ba6 Mon Sep 17 00:00:00 2001 From: Chris Craik Date: Mon, 11 Aug 2014 16:00:44 -0700 Subject: Rework shadow interpolation bug:16852257 Use pow(alpha, 1.5) to avoid harsh edges on shadow alpha ramps. Also adjusts shadow constants to compensate. Change-Id: I5869956d7d292db2a8e496bc320084b6d64c3fb7 --- core/res/res/values/styles.xml | 4 ++-- libs/hwui/OpenGLRenderer.cpp | 23 ++++++++++++----------- libs/hwui/OpenGLRenderer.h | 15 ++++++++++----- libs/hwui/Program.h | 20 ++++++++++++-------- libs/hwui/ProgramCache.cpp | 18 ++++++++++++++++-- 5 files changed, 52 insertions(+), 28 deletions(-) (limited to 'libs/hwui/ProgramCache.cpp') diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index e693d91c1469..35baf9c7eeb8 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -1359,8 +1359,8 @@ please see styles_device_defaults.xml. -200dp 800dp 800dp - 0.0471 - 0.1765 + 0.06 + 0.22 diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 636f218929cc..7123bfe76216 100755 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -1641,8 +1641,9 @@ void OpenGLRenderer::setupDrawNoTexture() { mCaches.disableTexCoordsVertexArray(); } -void OpenGLRenderer::setupDrawAA() { +void OpenGLRenderer::setupDrawAA(bool useShadowInterp) { mDescription.isAA = true; + mDescription.isShadowAA = useShadowInterp; } void OpenGLRenderer::setupDrawColor(int color, int alpha) { @@ -2365,7 +2366,7 @@ status_t OpenGLRenderer::drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* } status_t OpenGLRenderer::drawVertexBuffer(float translateX, float translateY, - const VertexBuffer& vertexBuffer, const SkPaint* paint, bool useOffset) { + const VertexBuffer& vertexBuffer, const SkPaint* paint, int displayFlags) { // not missing call to quickReject/dirtyLayer, always done at a higher level if (!vertexBuffer.getVertexCount()) { // no vertices to draw @@ -2381,13 +2382,14 @@ status_t OpenGLRenderer::drawVertexBuffer(float translateX, float translateY, setupDraw(); setupDrawNoTexture(); - if (isAA) setupDrawAA(); + if (isAA) setupDrawAA((displayFlags & kVertexBuffer_ShadowAA)); setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha); setupDrawColorFilter(getColorFilter(paint)); setupDrawShader(getShader(paint)); setupDrawBlending(paint, isAA); setupDrawProgram(); - setupDrawModelView(kModelViewMode_Translate, useOffset, translateX, translateY, 0, 0); + setupDrawModelView(kModelViewMode_Translate, (displayFlags & kVertexBuffer_Offset), + translateX, translateY, 0, 0); setupDrawColorUniforms(getShader(paint)); setupDrawColorFilterUniforms(getColorFilter(paint)); setupDrawShaderUniforms(getShader(paint)); @@ -2397,7 +2399,6 @@ status_t OpenGLRenderer::drawVertexBuffer(float translateX, float translateY, mCaches.bindPositionVertexPointer(true, vertices, isAA ? gAlphaVertexStride : gVertexStride); mCaches.resetTexCoordsVertexPointer(); - int alphaSlot = -1; if (isAA) { void* alphaCoords = ((GLbyte*) vertices) + gVertexAlphaOffset; @@ -2466,8 +2467,8 @@ status_t OpenGLRenderer::drawLines(const float* points, int count, const SkPaint return DrawGlInfo::kStatusDone; } - bool useOffset = !paint->isAntiAlias(); - return drawVertexBuffer(buffer, paint, useOffset); + int displayFlags = paint->isAntiAlias() ? 0 : kVertexBuffer_Offset; + return drawVertexBuffer(buffer, paint, displayFlags); } status_t OpenGLRenderer::drawPoints(const float* points, int count, const SkPaint* paint) { @@ -2483,8 +2484,8 @@ status_t OpenGLRenderer::drawPoints(const float* points, int count, const SkPain return DrawGlInfo::kStatusDone; } - bool useOffset = !paint->isAntiAlias(); - return drawVertexBuffer(buffer, paint, useOffset); + int displayFlags = paint->isAntiAlias() ? 0 : kVertexBuffer_Offset; + return drawVertexBuffer(buffer, paint, displayFlags); } status_t OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) { @@ -3167,12 +3168,12 @@ status_t OpenGLRenderer::drawShadow(float casterAlpha, if (ambientShadowVertexBuffer && mAmbientShadowAlpha > 0) { paint.setARGB(casterAlpha * mAmbientShadowAlpha, 0, 0, 0); - drawVertexBuffer(*ambientShadowVertexBuffer, &paint); + drawVertexBuffer(*ambientShadowVertexBuffer, &paint, kVertexBuffer_ShadowAA); } if (spotShadowVertexBuffer && mSpotShadowAlpha > 0) { paint.setARGB(casterAlpha * mSpotShadowAlpha, 0, 0, 0); - drawVertexBuffer(*spotShadowVertexBuffer, &paint); + drawVertexBuffer(*spotShadowVertexBuffer, &paint, kVertexBuffer_ShadowAA); } return DrawGlInfo::kStatusDrew; diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index fd228db58541..2a9badda7783 100755 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -94,6 +94,11 @@ enum ClipSideFlags { kClipSide_ConservativeFull = 0x1F }; +enum VertexBufferDisplayFlags { + kVertexBuffer_Offset = 0x1, + kVertexBuffer_ShadowAA = 0x2, +}; + /** * Defines additional transformation that should be applied by the model view matrix, beyond that of * the currentTransform() @@ -656,17 +661,17 @@ private: * * @param vertexBuffer The VertexBuffer to be drawn * @param paint The paint to render with - * @param useOffset Offset the vertexBuffer (used in drawing non-AA lines) + * @param flags flags with which to draw */ status_t drawVertexBuffer(float translateX, float translateY, const VertexBuffer& vertexBuffer, - const SkPaint* paint, bool useOffset = false); + const SkPaint* paint, int flags = 0); /** * Convenience for translating method */ status_t drawVertexBuffer(const VertexBuffer& vertexBuffer, - const SkPaint* paint, bool useOffset = false) { - return drawVertexBuffer(0.0f, 0.0f, vertexBuffer, paint, useOffset); + const SkPaint* paint, int flags = 0) { + return drawVertexBuffer(0.0f, 0.0f, vertexBuffer, paint, flags); } /** @@ -842,7 +847,7 @@ private: void setupDrawWithTextureAndColor(bool isAlpha8 = false); void setupDrawWithExternalTexture(); void setupDrawNoTexture(); - void setupDrawAA(); + void setupDrawAA(bool useShadowInterp); void setupDrawColor(int color, int alpha); void setupDrawColor(float r, float g, float b, float a); void setupDrawAlpha8Color(int color, int alpha); diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h index 3e191d0a0186..1d95c40b6233 100644 --- a/libs/hwui/Program.h +++ b/libs/hwui/Program.h @@ -72,19 +72,20 @@ namespace uirenderer { #define PROGRAM_MODULATE_SHIFT 35 #define PROGRAM_HAS_AA_SHIFT 36 +#define PROGRAM_HAS_SHADOW_AA_SHIFT 37 -#define PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT 37 -#define PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT 38 +#define PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT 38 +#define PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT 39 -#define PROGRAM_HAS_GAMMA_CORRECTION 39 +#define PROGRAM_HAS_GAMMA_CORRECTION 40 -#define PROGRAM_IS_SIMPLE_GRADIENT 40 +#define PROGRAM_IS_SIMPLE_GRADIENT 41 -#define PROGRAM_HAS_COLORS 41 +#define PROGRAM_HAS_COLORS 42 -#define PROGRAM_HAS_DEBUG_HIGHLIGHT 42 -#define PROGRAM_EMULATE_STENCIL 43 -#define PROGRAM_HAS_ROUND_RECT_CLIP 44 +#define PROGRAM_HAS_DEBUG_HIGHLIGHT 43 +#define PROGRAM_EMULATE_STENCIL 44 +#define PROGRAM_HAS_ROUND_RECT_CLIP 45 /////////////////////////////////////////////////////////////////////////////// // Types @@ -135,6 +136,7 @@ struct ProgramDescription { bool isBitmapNpot; bool isAA; // drawing with a per-vertex alpha + bool isShadowAA; // drawing per vertex alpha with shadow interpolation bool hasGradient; Gradient gradientType; @@ -175,6 +177,7 @@ struct ProgramDescription { hasColors = false; isAA = false; + isShadowAA = false; modulate = false; @@ -262,6 +265,7 @@ struct ProgramDescription { if (swapSrcDst) key |= PROGRAM_KEY_SWAP_SRC_DST; if (modulate) key |= programid(0x1) << PROGRAM_MODULATE_SHIFT; if (isAA) key |= programid(0x1) << PROGRAM_HAS_AA_SHIFT; + if (isShadowAA) key |= programid(0x1) << PROGRAM_HAS_SHADOW_AA_SHIFT; if (hasExternalTexture) key |= programid(0x1) << PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT; if (hasTextureTransform) key |= programid(0x1) << PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT; if (hasGammaCorrection) key |= programid(0x1) << PROGRAM_HAS_GAMMA_CORRECTION; diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp index 3ef2a716905d..2dd89b857107 100644 --- a/libs/hwui/ProgramCache.cpp +++ b/libs/hwui/ProgramCache.cpp @@ -121,8 +121,12 @@ const char* gVS_Main_OutBitmapTexCoords = const char* gVS_Main_Position = " vec4 transformedPosition = projection * transform * position;\n" " gl_Position = transformedPosition;\n"; + +const char* gVS_Main_ShadowAAVertexShape = + " alpha = pow(vtxAlpha, 0.667);\n"; const char* gVS_Main_AAVertexShape = " alpha = vtxAlpha;\n"; + const char* gVS_Main_HasRoundRectClip = " roundRectPos = (roundRectInvTransform * transformedPosition).xy;\n"; const char* gVS_Footer = @@ -237,6 +241,8 @@ const char* gFS_Main_ModulateColor = " fragColor *= color.a;\n"; const char* gFS_Main_AccountForAAVertexShape = " fragColor *= alpha;\n"; +const char* gFS_Main_AccountForShadowAAVertexShape = + " fragColor *= pow(alpha, 1.5);\n"; const char* gFS_Main_FetchTexture[2] = { // Don't modulate @@ -515,7 +521,11 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description shader.append(gVS_Main_OutTexCoords); } if (description.isAA) { - shader.append(gVS_Main_AAVertexShape); + if (description.isShadowAA) { + shader.append(gVS_Main_ShadowAAVertexShape); + } else { + shader.append(gVS_Main_AAVertexShape); + } } if (description.hasColors) { shader.append(gVS_Main_OutColors); @@ -750,7 +760,11 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti shader.append(gFS_Main_ApplyColorOp[description.colorOp]); if (description.isAA) { - shader.append(gFS_Main_AccountForAAVertexShape); + if (description.isShadowAA) { + shader.append(gFS_Main_AccountForShadowAAVertexShape); + } else { + shader.append(gFS_Main_AccountForAAVertexShape); + } } // Output the fragment -- cgit v1.2.3-59-g8ed1b From 91a8c7c62913c2597e3bf5a6d59d2ed5fc7ba4e0 Mon Sep 17 00:00:00 2001 From: Chris Craik Date: Tue, 12 Aug 2014 14:31:35 -0700 Subject: Switch to cos interpolation of shadow alpha bug:16852257 Updates default shadow opacities to compensate. Also, update variable/constant naming related to vertex alpha. Change-Id: I9055b4ac3c9ac305ca9d515f21b52d6aa6dc9c5c --- core/res/res/values/styles.xml | 2 +- libs/hwui/AmbientShadow.cpp | 5 ++++- libs/hwui/OpenGLRenderer.cpp | 12 ++++++------ libs/hwui/OpenGLRenderer.h | 4 ++-- libs/hwui/Program.h | 16 +++++++-------- libs/hwui/ProgramCache.cpp | 44 ++++++++++++++++++------------------------ libs/hwui/SpotShadow.cpp | 12 +++++++++--- 7 files changed, 49 insertions(+), 46 deletions(-) (limited to 'libs/hwui/ProgramCache.cpp') diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index 35baf9c7eeb8..8fc9bacdf111 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -1360,7 +1360,7 @@ please see styles_device_defaults.xml. 800dp 800dp 0.06 - 0.22 + 0.16 diff --git a/libs/hwui/AmbientShadow.cpp b/libs/hwui/AmbientShadow.cpp index 181230ad7547..9cc83ed68755 100644 --- a/libs/hwui/AmbientShadow.cpp +++ b/libs/hwui/AmbientShadow.cpp @@ -117,10 +117,13 @@ void AmbientShadow::createAmbientShadow(bool isCasterOpaque, // inner ring of points float opacity = 1.0 / (1 + rayHeight[rayIndex] * heightFactor); + // NOTE: Shadow alpha values are transformed when stored in alphavertices, + // so that they can be consumed directly by gFS_Main_ApplyVertexAlphaShadowInterp + float transformedOpacity = acos(1.0f - 2.0f * opacity); AlphaVertex::set(&shadowVertices[rays + rayIndex], intersection.x, intersection.y, - opacity); + transformedOpacity); } if (isCasterOpaque) { diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 7123bfe76216..d1522b640d46 100755 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -1641,9 +1641,9 @@ void OpenGLRenderer::setupDrawNoTexture() { mCaches.disableTexCoordsVertexArray(); } -void OpenGLRenderer::setupDrawAA(bool useShadowInterp) { - mDescription.isAA = true; - mDescription.isShadowAA = useShadowInterp; +void OpenGLRenderer::setupDrawVertexAlpha(bool useShadowAlphaInterp) { + mDescription.hasVertexAlpha = true; + mDescription.useShadowAlphaInterp = useShadowAlphaInterp; } void OpenGLRenderer::setupDrawColor(int color, int alpha) { @@ -2382,7 +2382,7 @@ status_t OpenGLRenderer::drawVertexBuffer(float translateX, float translateY, setupDraw(); setupDrawNoTexture(); - if (isAA) setupDrawAA((displayFlags & kVertexBuffer_ShadowAA)); + if (isAA) setupDrawVertexAlpha((displayFlags & kVertexBuffer_ShadowInterp)); setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha); setupDrawColorFilter(getColorFilter(paint)); setupDrawShader(getShader(paint)); @@ -3168,12 +3168,12 @@ status_t OpenGLRenderer::drawShadow(float casterAlpha, if (ambientShadowVertexBuffer && mAmbientShadowAlpha > 0) { paint.setARGB(casterAlpha * mAmbientShadowAlpha, 0, 0, 0); - drawVertexBuffer(*ambientShadowVertexBuffer, &paint, kVertexBuffer_ShadowAA); + drawVertexBuffer(*ambientShadowVertexBuffer, &paint, kVertexBuffer_ShadowInterp); } if (spotShadowVertexBuffer && mSpotShadowAlpha > 0) { paint.setARGB(casterAlpha * mSpotShadowAlpha, 0, 0, 0); - drawVertexBuffer(*spotShadowVertexBuffer, &paint, kVertexBuffer_ShadowAA); + drawVertexBuffer(*spotShadowVertexBuffer, &paint, kVertexBuffer_ShadowInterp); } return DrawGlInfo::kStatusDrew; diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 2a9badda7783..fc95c18e81b8 100755 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -96,7 +96,7 @@ enum ClipSideFlags { enum VertexBufferDisplayFlags { kVertexBuffer_Offset = 0x1, - kVertexBuffer_ShadowAA = 0x2, + kVertexBuffer_ShadowInterp = 0x2, }; /** @@ -847,7 +847,7 @@ private: void setupDrawWithTextureAndColor(bool isAlpha8 = false); void setupDrawWithExternalTexture(); void setupDrawNoTexture(); - void setupDrawAA(bool useShadowInterp); + void setupDrawVertexAlpha(bool useShadowAlphaInterp); void setupDrawColor(int color, int alpha); void setupDrawColor(float r, float g, float b, float a); void setupDrawAlpha8Color(int color, int alpha); diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h index 1d95c40b6233..56773f44f9b5 100644 --- a/libs/hwui/Program.h +++ b/libs/hwui/Program.h @@ -71,8 +71,8 @@ namespace uirenderer { #define PROGRAM_GRADIENT_TYPE_SHIFT 33 // 2 bits for gradient type #define PROGRAM_MODULATE_SHIFT 35 -#define PROGRAM_HAS_AA_SHIFT 36 -#define PROGRAM_HAS_SHADOW_AA_SHIFT 37 +#define PROGRAM_HAS_VERTEX_ALPHA_SHIFT 36 +#define PROGRAM_USE_SHADOW_ALPHA_INTERP_SHIFT 37 #define PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT 38 #define PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT 39 @@ -135,8 +135,8 @@ struct ProgramDescription { bool hasBitmap; bool isBitmapNpot; - bool isAA; // drawing with a per-vertex alpha - bool isShadowAA; // drawing per vertex alpha with shadow interpolation + bool hasVertexAlpha; + bool useShadowAlphaInterp; bool hasGradient; Gradient gradientType; @@ -176,8 +176,8 @@ struct ProgramDescription { hasColors = false; - isAA = false; - isShadowAA = false; + hasVertexAlpha = false; + useShadowAlphaInterp = false; modulate = false; @@ -264,8 +264,8 @@ struct ProgramDescription { key |= (framebufferMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT; if (swapSrcDst) key |= PROGRAM_KEY_SWAP_SRC_DST; if (modulate) key |= programid(0x1) << PROGRAM_MODULATE_SHIFT; - if (isAA) key |= programid(0x1) << PROGRAM_HAS_AA_SHIFT; - if (isShadowAA) key |= programid(0x1) << PROGRAM_HAS_SHADOW_AA_SHIFT; + if (hasVertexAlpha) key |= programid(0x1) << PROGRAM_HAS_VERTEX_ALPHA_SHIFT; + if (useShadowAlphaInterp) key |= programid(0x1) << PROGRAM_USE_SHADOW_ALPHA_INTERP_SHIFT; if (hasExternalTexture) key |= programid(0x1) << PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT; if (hasTextureTransform) key |= programid(0x1) << PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT; if (hasGammaCorrection) key |= programid(0x1) << PROGRAM_HAS_GAMMA_CORRECTION; diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp index 2dd89b857107..c802b183d41c 100644 --- a/libs/hwui/ProgramCache.cpp +++ b/libs/hwui/ProgramCache.cpp @@ -46,7 +46,7 @@ const char* gVS_Header_Attributes_TexCoords = "attribute vec2 texCoords;\n"; const char* gVS_Header_Attributes_Colors = "attribute vec4 colors;\n"; -const char* gVS_Header_Attributes_AAVertexShapeParameters = +const char* gVS_Header_Attributes_VertexAlphaParameters = "attribute float vtxAlpha;\n"; const char* gVS_Header_Uniforms_TextureTransform = "uniform mat4 mainTextureTransform;\n"; @@ -64,7 +64,7 @@ const char* gVS_Header_Varyings_HasTexture = "varying vec2 outTexCoords;\n"; const char* gVS_Header_Varyings_HasColors = "varying vec4 outColors;\n"; -const char* gVS_Header_Varyings_IsAAVertexShape = +const char* gVS_Header_Varyings_HasVertexAlpha = "varying float alpha;\n"; const char* gVS_Header_Varyings_HasBitmap = "varying highp vec2 outBitmapTexCoords;\n"; @@ -122,9 +122,7 @@ const char* gVS_Main_Position = " vec4 transformedPosition = projection * transform * position;\n" " gl_Position = transformedPosition;\n"; -const char* gVS_Main_ShadowAAVertexShape = - " alpha = pow(vtxAlpha, 0.667);\n"; -const char* gVS_Main_AAVertexShape = +const char* gVS_Main_VertexAlpha = " alpha = vtxAlpha;\n"; const char* gVS_Main_HasRoundRectClip = @@ -239,10 +237,10 @@ const char* gFS_Main_FetchColor = " fragColor = color;\n"; const char* gFS_Main_ModulateColor = " fragColor *= color.a;\n"; -const char* gFS_Main_AccountForAAVertexShape = +const char* gFS_Main_ApplyVertexAlphaLinearInterp = " fragColor *= alpha;\n"; -const char* gFS_Main_AccountForShadowAAVertexShape = - " fragColor *= pow(alpha, 1.5);\n"; +const char* gFS_Main_ApplyVertexAlphaShadowInterp = + " fragColor *= (1.0 - cos(alpha)) / 2.0;\n"; const char* gFS_Main_FetchTexture[2] = { // Don't modulate @@ -473,8 +471,8 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description if (description.hasTexture || description.hasExternalTexture) { shader.append(gVS_Header_Attributes_TexCoords); } - if (description.isAA) { - shader.append(gVS_Header_Attributes_AAVertexShapeParameters); + if (description.hasVertexAlpha) { + shader.append(gVS_Header_Attributes_VertexAlphaParameters); } if (description.hasColors) { shader.append(gVS_Header_Attributes_Colors); @@ -497,8 +495,8 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description if (description.hasTexture || description.hasExternalTexture) { shader.append(gVS_Header_Varyings_HasTexture); } - if (description.isAA) { - shader.append(gVS_Header_Varyings_IsAAVertexShape); + if (description.hasVertexAlpha) { + shader.append(gVS_Header_Varyings_HasVertexAlpha); } if (description.hasColors) { shader.append(gVS_Header_Varyings_HasColors); @@ -520,12 +518,8 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description } else if (description.hasTexture || description.hasExternalTexture) { shader.append(gVS_Main_OutTexCoords); } - if (description.isAA) { - if (description.isShadowAA) { - shader.append(gVS_Main_ShadowAAVertexShape); - } else { - shader.append(gVS_Main_AAVertexShape); - } + if (description.hasVertexAlpha) { + shader.append(gVS_Main_VertexAlpha); } if (description.hasColors) { shader.append(gVS_Main_OutColors); @@ -575,8 +569,8 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti if (description.hasTexture || description.hasExternalTexture) { shader.append(gVS_Header_Varyings_HasTexture); } - if (description.isAA) { - shader.append(gVS_Header_Varyings_IsAAVertexShape); + if (description.hasVertexAlpha) { + shader.append(gVS_Header_Varyings_HasVertexAlpha); } if (description.hasColors) { shader.append(gVS_Header_Varyings_HasColors); @@ -617,7 +611,7 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti } // Optimization for common cases - if (!description.isAA + if (!description.hasVertexAlpha && !blendFramebuffer && !description.hasColors && description.colorOp == ProgramDescription::kColorNone @@ -759,11 +753,11 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti // Apply the color op if needed shader.append(gFS_Main_ApplyColorOp[description.colorOp]); - if (description.isAA) { - if (description.isShadowAA) { - shader.append(gFS_Main_AccountForShadowAAVertexShape); + if (description.hasVertexAlpha) { + if (description.useShadowAlphaInterp) { + shader.append(gFS_Main_ApplyVertexAlphaShadowInterp); } else { - shader.append(gFS_Main_AccountForAAVertexShape); + shader.append(gFS_Main_ApplyVertexAlphaLinearInterp); } } diff --git a/libs/hwui/SpotShadow.cpp b/libs/hwui/SpotShadow.cpp index 8c3077b682be..d72653864d7b 100644 --- a/libs/hwui/SpotShadow.cpp +++ b/libs/hwui/SpotShadow.cpp @@ -754,9 +754,13 @@ void SpotShadow::generateTriangleStrip(bool isCasterOpaque, const Vector2* penum AlphaVertex* shadowVertices = shadowTriangleStrip.alloc(SHADOW_VERTEX_COUNT); + // NOTE: Shadow alpha values are transformed when stored in alphavertices, + // so that they can be consumed directly by gFS_Main_ApplyVertexAlphaShadowInterp + float transformedMaxAlpha = M_PI; + // Calculate the vertices (x, y, alpha) in the shadow area. AlphaVertex centroidXYA; - AlphaVertex::set(¢roidXYA, centroid.x, centroid.y, 1.0f); + AlphaVertex::set(¢roidXYA, centroid.x, centroid.y, transformedMaxAlpha); for (int rayIndex = 0; rayIndex < rays; rayIndex++) { float dx = cosf(step * rayIndex); float dy = sinf(step * rayIndex); @@ -770,14 +774,16 @@ void SpotShadow::generateTriangleStrip(bool isCasterOpaque, const Vector2* penum // umbra ring float umbraDistance = umbraDistPerRay[rayIndex]; AlphaVertex::set(&shadowVertices[rays + rayIndex], - dx * umbraDistance + centroid.x, dy * umbraDistance + centroid.y, 1.0f); + dx * umbraDistance + centroid.x, + dy * umbraDistance + centroid.y, + transformedMaxAlpha); // occluded umbra ring if (hasOccludedUmbraArea) { float occludedUmbraDistance = occludedUmbraDistPerRay[rayIndex]; AlphaVertex::set(&shadowVertices[2 * rays + rayIndex], dx * occludedUmbraDistance + centroid.x, - dy * occludedUmbraDistance + centroid.y, 1.0f); + dy * occludedUmbraDistance + centroid.y, transformedMaxAlpha); } else { // Put all vertices of the occluded umbra ring at the centroid. shadowVertices[2 * rays + rayIndex] = centroidXYA; -- cgit v1.2.3-59-g8ed1b From 79c9f9168919b0fbb26f8ecd5704875dbc6a539b Mon Sep 17 00:00:00 2001 From: Derek Sollenberger Date: Mon, 18 Aug 2014 15:54:13 -0400 Subject: Remove invalid premul step from HWUI's matrix color filter. bug: 16186699 Change-Id: Ia0b828e76ce4831ee9e3b4f54c697e6017f1604d --- libs/hwui/ProgramCache.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'libs/hwui/ProgramCache.cpp') diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp index c802b183d41c..c38f136879ea 100644 --- a/libs/hwui/ProgramCache.cpp +++ b/libs/hwui/ProgramCache.cpp @@ -328,8 +328,7 @@ const char* gFS_Main_ApplyColorOp[3] = { "", // Matrix " fragColor *= colorMatrix;\n" - " fragColor += colorMatrixVector;\n" - " fragColor.rgb *= fragColor.a;\n", + " fragColor += colorMatrixVector;\n", // PorterDuff " fragColor = blendColors(colorBlend, fragColor);\n" }; -- cgit v1.2.3-59-g8ed1b From 68a73e8700c3bb30395e4ebf1b6e5a9b81699a5a Mon Sep 17 00:00:00 2001 From: Chris Craik Date: Fri, 29 Aug 2014 17:06:27 -0700 Subject: Fix precision issues for roundrect clipping bug:16984008 Change-Id: I941232d569293717f6bcd249d9e01f72a7409d2e --- libs/hwui/ProgramCache.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libs/hwui/ProgramCache.cpp') diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp index c802b183d41c..23fe1b990df5 100644 --- a/libs/hwui/ProgramCache.cpp +++ b/libs/hwui/ProgramCache.cpp @@ -88,7 +88,7 @@ const char* gVS_Header_Varyings_HasGradient[6] = { "varying vec2 ditherTexCoords;\n", }; const char* gVS_Header_Varyings_HasRoundRectClip = - "varying vec2 roundRectPos;\n"; + "varying highp vec2 roundRectPos;\n"; const char* gVS_Main = "\nvoid main(void) {\n"; const char* gVS_Main_OutTexCoords = -- cgit v1.2.3-59-g8ed1b From 73821c8d2bd453de6bf3f516e1f1cdb9a132f4a7 Mon Sep 17 00:00:00 2001 From: Chris Craik Date: Tue, 16 Sep 2014 17:32:13 -0700 Subject: Handle premultiplication correctly for ColorMatrixColorFilters bug:17405627 Previously, the input content to the color matrix computation was left premultiplied. Since the color matrix could reduce the alpha channel, the alpha was re-multiplied, but this was incomplete, and incorrect. Instead, apply the color matrix in unpremultiplied space. Change-Id: I87b8e03d2e228e6ded81f7bbfea952605d7a095c --- libs/hwui/ProgramCache.cpp | 4 +++- libs/hwui/Renderer.h | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'libs/hwui/ProgramCache.cpp') diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp index a8b8b16826a3..06353c096adc 100644 --- a/libs/hwui/ProgramCache.cpp +++ b/libs/hwui/ProgramCache.cpp @@ -327,8 +327,10 @@ const char* gFS_Main_ApplyColorOp[3] = { // None "", // Matrix + " fragColor.rgb /= (fragColor.a + 0.0019);\n" // un-premultiply " fragColor *= colorMatrix;\n" - " fragColor += colorMatrixVector;\n", + " fragColor += colorMatrixVector;\n" + " fragColor.rgb *= (fragColor.a + 0.0019);\n", // re-premultiply // PorterDuff " fragColor = blendColors(colorBlend, fragColor);\n" }; diff --git a/libs/hwui/Renderer.h b/libs/hwui/Renderer.h index 6d4bb4ab50f2..3681637a962e 100644 --- a/libs/hwui/Renderer.h +++ b/libs/hwui/Renderer.h @@ -70,6 +70,7 @@ public: // TODO: move to a method on android:Paint static inline bool paintWillNotDraw(const SkPaint& paint) { return paint.getAlpha() == 0 + && !paint.getColorFilter() && getXfermode(paint.getXfermode()) != SkXfermode::kClear_Mode; } @@ -77,6 +78,7 @@ public: static inline bool paintWillNotDrawText(const SkPaint& paint) { return paint.getAlpha() == 0 && paint.getLooper() == NULL + && !paint.getColorFilter() && getXfermode(paint.getXfermode()) == SkXfermode::kSrcOver_Mode; } // ---------------------------------------------------------------------------- -- cgit v1.2.3-59-g8ed1b