Gradient shaders: make fPtsToUnit const, pre-cache getType().
authormtklein <mtklein@chromium.org>
Wed, 10 Dec 2014 18:29:19 +0000 (10:29 -0800)
committerCommit bot <commit-bot@chromium.org>
Wed, 10 Dec 2014 18:29:19 +0000 (10:29 -0800)
This prevents races when calling fPtsToUnit.getType() from multiple threads.

This introduces a small amount of redundant code in SkTwoPointRadialGradient,
but it's probably optimized together into no extra run-time work.

BUG=437511

Review URL: https://codereview.chromium.org/793763003

src/effects/gradients/SkGradientShader.cpp
src/effects/gradients/SkGradientShaderPriv.h
src/effects/gradients/SkLinearGradient.cpp
src/effects/gradients/SkRadialGradient.cpp
src/effects/gradients/SkSweepGradient.cpp
src/effects/gradients/SkTwoPointConicalGradient.cpp
src/effects/gradients/SkTwoPointConicalGradient.h
src/effects/gradients/SkTwoPointRadialGradient.cpp
src/effects/gradients/SkTwoPointRadialGradient.h

index dce079e9aebf29d564574414e11d0b36f736ee25..0c147946f33c5ac75d67abd32b828df306de7747 100644 (file)
@@ -67,9 +67,11 @@ bool SkGradientShaderBase::DescriptorScope::unflatten(SkReadBuffer& buffer) {
 
 ////////////////////////////////////////////////////////////////////////////////////////////
 
-SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc)
+SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc, const SkMatrix& ptsToUnit)
     : INHERITED(desc.fLocalMatrix)
+    , fPtsToUnit(ptsToUnit)
 {
+    fPtsToUnit.getType();  // Precache so reads are threadsafe.
     SkASSERT(desc.fCount > 1);
 
     fGradFlags = SkToU8(desc.fGradFlags);
index 72014d330e5e5503035f95fb2d2f95bbf5bf17dd..125c7b056d681a8782b1029037dc5ea4504abaf6 100644 (file)
@@ -121,7 +121,7 @@ public:
     };
 
 public:
-    SkGradientShaderBase(const Descriptor& desc);
+    SkGradientShaderBase(const Descriptor& desc, const SkMatrix& ptsToUnit);
     virtual ~SkGradientShaderBase();
 
     // The cache is initialized on-demand when getCache16/32 is called.
@@ -223,7 +223,7 @@ protected:
     virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE;
     SK_TO_STRING_OVERRIDE()
 
-    SkMatrix    fPtsToUnit;     // set by subclass
+    const SkMatrix fPtsToUnit;
     TileMode    fTileMode;
     TileProc    fTileProc;
     int         fColorCount;
index 958862fb2e10e42829b08c8551801e717e6d9631..6bd5d83e32dfb1ab37bc1202af8e58fcd3bc02b3 100644 (file)
@@ -39,25 +39,25 @@ static inline int mirror_8bits(int x) {
 #pragma optimize("", on)
 #endif
 
-static void pts_to_unit_matrix(const SkPoint pts[2], SkMatrix* matrix) {
+static SkMatrix pts_to_unit_matrix(const SkPoint pts[2]) {
     SkVector    vec = pts[1] - pts[0];
     SkScalar    mag = vec.length();
     SkScalar    inv = mag ? SkScalarInvert(mag) : 0;
 
     vec.scale(inv);
-    matrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY);
-    matrix->postTranslate(-pts[0].fX, -pts[0].fY);
-    matrix->postScale(inv, inv);
+    SkMatrix matrix;
+    matrix.setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY);
+    matrix.postTranslate(-pts[0].fX, -pts[0].fY);
+    matrix.postScale(inv, inv);
+    return matrix;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
 SkLinearGradient::SkLinearGradient(const SkPoint pts[2], const Descriptor& desc)
-    : SkGradientShaderBase(desc)
+    : SkGradientShaderBase(desc, pts_to_unit_matrix(pts))
     , fStart(pts[0])
-    , fEnd(pts[1])
-{
-    pts_to_unit_matrix(pts, &fPtsToUnit);
+    , fEnd(pts[1]) {
 }
 
 SkFlattenable* SkLinearGradient::CreateProc(SkReadBuffer& buffer) {
index e880df25cbbe59aa8d665467a26a995624b601b4..c10c555147fa4ee11dcf491c41d0ca722eddd191 100644 (file)
@@ -12,6 +12,8 @@
 #define kSQRT_TABLE_BITS    11
 #define kSQRT_TABLE_SIZE    (1 << kSQRT_TABLE_BITS)
 
+SK_COMPILE_ASSERT(sizeof(gSqrt8Table) == kSQRT_TABLE_SIZE, SqrtTableSizesMatch);
+
 #if 0
 
 #include <stdio.h>
@@ -55,12 +57,13 @@ inline SkFixed repeat_tileproc_nonstatic(SkFixed x) {
     return repeat_tileproc(x);
 }
 
-void rad_to_unit_matrix(const SkPoint& center, SkScalar radius,
-                               SkMatrix* matrix) {
+SkMatrix rad_to_unit_matrix(const SkPoint& center, SkScalar radius) {
     SkScalar    inv = SkScalarInvert(radius);
 
-    matrix->setTranslate(-center.fX, -center.fY);
-    matrix->postScale(inv, inv);
+    SkMatrix matrix;
+    matrix.setTranslate(-center.fX, -center.fY);
+    matrix.postScale(inv, inv);
+    return matrix;
 }
 
 typedef void (* RadialShade16Proc)(SkScalar sfx, SkScalar sdx,
@@ -146,14 +149,9 @@ void shadeSpan16_radial_repeat(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar d
 /////////////////////////////////////////////////////////////////////
 
 SkRadialGradient::SkRadialGradient(const SkPoint& center, SkScalar radius, const Descriptor& desc)
-    : SkGradientShaderBase(desc)
+    : SkGradientShaderBase(desc, rad_to_unit_matrix(center, radius))
     , fCenter(center)
-    , fRadius(radius)
-{
-    // make sure our table is insync with our current #define for kSQRT_TABLE_SIZE
-    SkASSERT(sizeof(gSqrt8Table) == kSQRT_TABLE_SIZE);
-
-    rad_to_unit_matrix(center, radius, &fPtsToUnit);
+    , fRadius(radius) {
 }
 
 size_t SkRadialGradient::contextSize() const {
index 2493060e99e739171ca9cece8e399e9db8f10a56..6e91e2ba257c229fdda83f7fb2f9d1b2eacd3b1c 100644 (file)
@@ -8,12 +8,16 @@
 
 #include "SkSweepGradient.h"
 
+static SkMatrix translate(SkScalar dx, SkScalar dy) {
+    SkMatrix matrix;
+    matrix.setTranslate(dx, dy);
+    return matrix;
+}
+
 SkSweepGradient::SkSweepGradient(SkScalar cx, SkScalar cy, const Descriptor& desc)
-    : SkGradientShaderBase(desc)
+    : SkGradientShaderBase(desc, translate(-cx, -cy))
     , fCenter(SkPoint::Make(cx, cy))
 {
-    fPtsToUnit.setTranslate(-cx, -cy);
-
     // overwrite the tilemode to a canonical value (since sweep ignores it)
     fTileMode = SkShader::kClamp_TileMode;
 }
index 2fc848e10962a86a4bd7dbd2a7644b9308306f4a..94751a89c63a30c3cf8373ecc2af307557075879 100644 (file)
@@ -186,18 +186,13 @@ static void twopoint_mirror(TwoPtRadialContext* rec, SkPMColor* SK_RESTRICT dstC
     }
 }
 
-void SkTwoPointConicalGradient::init() {
-    fRec.init(fCenter1, fRadius1, fCenter2, fRadius2, fFlippedGrad);
-    fPtsToUnit.reset();
-}
-
 /////////////////////////////////////////////////////////////////////
 
 SkTwoPointConicalGradient::SkTwoPointConicalGradient(
         const SkPoint& start, SkScalar startRadius,
         const SkPoint& end, SkScalar endRadius,
         bool flippedGrad, const Descriptor& desc)
-    : SkGradientShaderBase(desc)
+    : SkGradientShaderBase(desc, SkMatrix::I())
     , fCenter1(start)
     , fCenter2(end)
     , fRadius1(startRadius)
@@ -206,7 +201,7 @@ SkTwoPointConicalGradient::SkTwoPointConicalGradient(
 {
     // this is degenerate, and should be caught by our caller
     SkASSERT(fCenter1 != fCenter2 || fRadius1 != fRadius2);
-    this->init();
+    fRec.init(fCenter1, fRadius1, fCenter2, fRadius2, fFlippedGrad);
 }
 
 bool SkTwoPointConicalGradient::isOpaque() const {
index c43f682c520cc57cf075979536d9e43aa9bc7f7b..941d12bc5a9406b9ecb53ec5dd6cfdd66b9094a8 100644 (file)
@@ -39,8 +39,6 @@ struct TwoPtRadial {
 
 class SkTwoPointConicalGradient : public SkGradientShaderBase {
     TwoPtRadial fRec;
-    void init();
-
 public:
     SkTwoPointConicalGradient(const SkPoint& start, SkScalar startRadius,
                               const SkPoint& end, SkScalar endRadius,
index 4fb2996226f145efb638087232f105f7604e1469..3a3921d14ccc0459fc6b5ef57c67ab3ec8e2b679 100644 (file)
@@ -167,16 +167,33 @@ void shadeSpan_twopoint_repeat(SkScalar fx, SkScalar dx,
 
 /////////////////////////////////////////////////////////////////////
 
+static SkMatrix pts_to_unit(const SkPoint& start, SkScalar diffRadius) {
+    SkScalar inv = diffRadius ? SkScalarInvert(diffRadius) : 0;
+    SkMatrix matrix;
+    matrix.setTranslate(-start.fX, -start.fY);
+    matrix.postScale(inv, inv);
+    return matrix;
+}
+
 SkTwoPointRadialGradient::SkTwoPointRadialGradient(const SkPoint& start, SkScalar startRadius,
                                                    const SkPoint& end, SkScalar endRadius,
                                                    const Descriptor& desc)
-    : SkGradientShaderBase(desc)
+    : SkGradientShaderBase(desc, pts_to_unit(start, endRadius - startRadius))
     , fCenter1(start)
     , fCenter2(end)
     , fRadius1(startRadius)
     , fRadius2(endRadius)
 {
-    init();
+    fDiff = fCenter1 - fCenter2;
+    fDiffRadius = fRadius2 - fRadius1;
+    // hack to avoid zero-divide for now
+    SkScalar inv = fDiffRadius ? SkScalarInvert(fDiffRadius) : 0;
+    fDiff.fX = SkScalarMul(fDiff.fX, inv);
+    fDiff.fY = SkScalarMul(fDiff.fY, inv);
+    fStartRadius = SkScalarMul(fRadius1, inv);
+    fSr2D2 = SkScalarSquare(fStartRadius);
+    fA = SkScalarSquare(fDiff.fX) + SkScalarSquare(fDiff.fY) - SK_Scalar1;
+    fOneOverTwoA = fA ? SkScalarInvert(fA * 2) : 0;
 }
 
 SkShader::BitmapType SkTwoPointRadialGradient::asABitmap(
@@ -366,22 +383,6 @@ void SkTwoPointRadialGradient::flatten(
     buffer.writeScalar(fRadius2);
 }
 
-void SkTwoPointRadialGradient::init() {
-    fDiff = fCenter1 - fCenter2;
-    fDiffRadius = fRadius2 - fRadius1;
-    // hack to avoid zero-divide for now
-    SkScalar inv = fDiffRadius ? SkScalarInvert(fDiffRadius) : 0;
-    fDiff.fX = SkScalarMul(fDiff.fX, inv);
-    fDiff.fY = SkScalarMul(fDiff.fY, inv);
-    fStartRadius = SkScalarMul(fRadius1, inv);
-    fSr2D2 = SkScalarSquare(fStartRadius);
-    fA = SkScalarSquare(fDiff.fX) + SkScalarSquare(fDiff.fY) - SK_Scalar1;
-    fOneOverTwoA = fA ? SkScalarInvert(fA * 2) : 0;
-
-    fPtsToUnit.setTranslate(-fCenter1.fX, -fCenter1.fY);
-    fPtsToUnit.postScale(inv, inv);
-}
-
 /////////////////////////////////////////////////////////////////////
 
 #if SK_SUPPORT_GPU
index da9c5fc029e5d5adcfba76b83d6450d5bcce11ad..dff2479fe746aa27a8fd0795906fe0ad26cc00dc 100644 (file)
@@ -56,8 +56,6 @@ private:
     SkPoint fDiff;
     SkScalar fStartRadius, fDiffRadius, fSr2D2, fA, fOneOverTwoA;
 
-    void init();
-
     friend class SkGradientShader;
     typedef SkGradientShaderBase INHERITED;
 };