Gradient shaders: make fPtsToUnit const, pre-cache getType().
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
diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp
index dce079e..0c14794 100644
--- a/src/effects/gradients/SkGradientShader.cpp
+++ b/src/effects/gradients/SkGradientShader.cpp
@@ -67,9 +67,11 @@
////////////////////////////////////////////////////////////////////////////////////////////
-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);
diff --git a/src/effects/gradients/SkGradientShaderPriv.h b/src/effects/gradients/SkGradientShaderPriv.h
index 72014d3..125c7b0 100644
--- a/src/effects/gradients/SkGradientShaderPriv.h
+++ b/src/effects/gradients/SkGradientShaderPriv.h
@@ -121,7 +121,7 @@
};
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 @@
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;
diff --git a/src/effects/gradients/SkLinearGradient.cpp b/src/effects/gradients/SkLinearGradient.cpp
index 958862f..6bd5d83 100644
--- a/src/effects/gradients/SkLinearGradient.cpp
+++ b/src/effects/gradients/SkLinearGradient.cpp
@@ -39,25 +39,25 @@
#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) {
diff --git a/src/effects/gradients/SkRadialGradient.cpp b/src/effects/gradients/SkRadialGradient.cpp
index e880df2..c10c555 100644
--- a/src/effects/gradients/SkRadialGradient.cpp
+++ b/src/effects/gradients/SkRadialGradient.cpp
@@ -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 @@
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 @@
/////////////////////////////////////////////////////////////////////
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 {
diff --git a/src/effects/gradients/SkSweepGradient.cpp b/src/effects/gradients/SkSweepGradient.cpp
index 2493060..6e91e2b 100644
--- a/src/effects/gradients/SkSweepGradient.cpp
+++ b/src/effects/gradients/SkSweepGradient.cpp
@@ -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;
}
diff --git a/src/effects/gradients/SkTwoPointConicalGradient.cpp b/src/effects/gradients/SkTwoPointConicalGradient.cpp
index 2fc848e..94751a8 100644
--- a/src/effects/gradients/SkTwoPointConicalGradient.cpp
+++ b/src/effects/gradients/SkTwoPointConicalGradient.cpp
@@ -186,18 +186,13 @@
}
}
-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 @@
{
// 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 {
diff --git a/src/effects/gradients/SkTwoPointConicalGradient.h b/src/effects/gradients/SkTwoPointConicalGradient.h
index c43f682..941d12b 100644
--- a/src/effects/gradients/SkTwoPointConicalGradient.h
+++ b/src/effects/gradients/SkTwoPointConicalGradient.h
@@ -39,8 +39,6 @@
class SkTwoPointConicalGradient : public SkGradientShaderBase {
TwoPtRadial fRec;
- void init();
-
public:
SkTwoPointConicalGradient(const SkPoint& start, SkScalar startRadius,
const SkPoint& end, SkScalar endRadius,
diff --git a/src/effects/gradients/SkTwoPointRadialGradient.cpp b/src/effects/gradients/SkTwoPointRadialGradient.cpp
index 4fb29962..3a3921d 100644
--- a/src/effects/gradients/SkTwoPointRadialGradient.cpp
+++ b/src/effects/gradients/SkTwoPointRadialGradient.cpp
@@ -167,16 +167,33 @@
/////////////////////////////////////////////////////////////////////
+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 @@
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
diff --git a/src/effects/gradients/SkTwoPointRadialGradient.h b/src/effects/gradients/SkTwoPointRadialGradient.h
index da9c5fc..dff2479 100644
--- a/src/effects/gradients/SkTwoPointRadialGradient.h
+++ b/src/effects/gradients/SkTwoPointRadialGradient.h
@@ -56,8 +56,6 @@
SkPoint fDiff;
SkScalar fStartRadius, fDiffRadius, fSr2D2, fA, fOneOverTwoA;
- void init();
-
friend class SkGradientShader;
typedef SkGradientShaderBase INHERITED;
};