Add asAGradient shader extraction API.

Store initial gradient parameters.
Add compile asserts in GPU code for BitmapType ordering.

Review URL: http://codereview.appspot.com/4178063

git-svn-id: http://skia.googlecode.com/svn/trunk@845 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
vandebo@chromium.org 2011-02-24 00:21:06 +00:00
parent 7d7ca79c3e
commit d3ae77965e
5 changed files with 235 additions and 48 deletions

View File

@ -51,6 +51,9 @@ public:
SkMatrix* outMatrix,
TileMode xy[2],
SkScalar* twoPointRadialParams);
virtual GradientType asAGradient(GradientInfo* info) const;
protected:
SkColorShader(SkFlattenableReadBuffer& );
virtual void flatten(SkFlattenableWriteBuffer& );

View File

@ -163,7 +163,7 @@ public:
// to (0,0) as bitmap x coord, where angle = 0 is
// bitmap left edge of bitmap = 2pi is the
// right edge. Bitmap is 1 pixel tall. No extras
kTwoPointRadial_BitmapType
kTwoPointRadial_BitmapType,
//<! Matrix transforms to space where (0,0) is
// the center of the starting circle. The second
// circle will be centered (x, 0) where x may be
@ -176,7 +176,8 @@ public:
// space
// 2: the second radius minus the first radius
// in pre-transformed space.
kLast_BitmapType = kTwoPointRadial_BitmapType
};
/** Optional methods for shaders that can pretend to be a bitmap/texture
to play along with opengl. Default just returns kNone_BitmapType and
@ -196,6 +197,59 @@ public:
virtual BitmapType asABitmap(SkBitmap* outTexture, SkMatrix* outMatrix,
TileMode xy[2], SkScalar* twoPointRadialParams);
/**
* If the shader subclass can be represented as a gradient, asAGradient
* returns the matching GradientType enum (or kNone_GradientType if it
* cannot). Also, if info is not null, asAGradient populates info with
* the relevant (see below) parameters for the gradient. fColorCount
* is both an input and output parameter. On input, it indicates how
* many entries in fColors and fColorOffsets can be used, if they are
* non-NULL. After asAGradient has run, fColorCount indicates how
* many color-offset pairs there are in the gradient. If there is
* insufficient space to store all of the color-offset pairs, fColors
* and fColorOffsets will not be altered. fColorOffsets specifies
* where on the range of 0 to 1 to transition to the given color.
* The meaning of fPoint and fRadius is dependant on the type of gradient.
*
* None:
* info is ignored.
* Color:
* fColorOffsets[0] is meaningless.
* Linear:
* fPoint[0] and fPoint[1] are the end-points of the gradient
* Radial:
* fPoint[0] and fRadius[0] are the center and radius
* Radial2:
* fPoint[0] and fRadius[0] are the center and radius of the 1st circle
* fPoint[1] and fRadius[1] are the center and radius of the 2nd circle
* Sweep:
* fPoint[0] is the center of the sweep.
*/
enum GradientType {
kNone_GradientType,
kColor_GradientType,
kLinear_GradientType,
kRadial_GradientType,
kRadial2_GradientType,
kSweep_GradientType,
kLast_GradientType = kSweep_GradientType
};
struct GradientInfo {
int fColorCount; //!< In-out parameter, specifies passed size
// of fColors/fColorOffsets on input, and
// actual number of colors/offsets on
// output.
SkColor* fColors; //!< The colors in the gradient.
SkScalar* fColorOffsets; //!< The unit offset for color transitions.
SkPoint fPoint[2]; //!< Type specific, see above.
SkScalar fRadius[2]; //!< Type specific, see above.
TileMode fTileMode; //!< The tile mode used.
};
virtual GradientType asAGradient(GradientInfo* info) const;
//////////////////////////////////////////////////////////////////////////
// Factory methods for stock shaders

View File

@ -15,6 +15,7 @@
** limitations under the License.
*/
#include "SkScalar.h"
#include "SkShader.h"
#include "SkPaint.h"
#include "SkMallocPixelRef.h"
@ -196,11 +197,15 @@ SkShader::MatrixClass SkShader::ComputeMatrixClass(const SkMatrix& mat) {
//////////////////////////////////////////////////////////////////////////////
SkShader::BitmapType SkShader::asABitmap(SkBitmap*, SkMatrix*,
SkShader::BitmapType SkShader::asABitmap(SkBitmap*, SkMatrix*,
TileMode*, SkScalar*) {
return kNone_BitmapType;
}
SkShader::GradientType SkShader::asAGradient(GradientInfo* info) const {
return kNone_GradientType;
}
SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
TileMode tmx, TileMode tmy) {
return SkShader::CreateBitmapShader(src, tmx, tmy, NULL, 0);
@ -258,20 +263,18 @@ bool SkColorShader::setContext(const SkBitmap& device, const SkPaint& paint,
return false;
}
SkColor c;
unsigned a;
if (fInheritColor) {
c = paint.getColor();
a = SkColorGetA(c);
fColor = paint.getColor();
a = SkColorGetA(fColor);
} else {
c = fColor;
a = SkAlphaMul(SkColorGetA(c), SkAlpha255To256(paint.getAlpha()));
a = SkAlphaMul(SkColorGetA(fColor), SkAlpha255To256(paint.getAlpha()));
}
unsigned r = SkColorGetR(c);
unsigned g = SkColorGetG(c);
unsigned b = SkColorGetB(c);
unsigned r = SkColorGetR(fColor);
unsigned g = SkColorGetG(fColor);
unsigned b = SkColorGetB(fColor);
// we want this before we apply any alpha
fColor16 = SkPack888ToRGB16(r, g, b);
@ -331,3 +334,13 @@ SkShader::BitmapType SkColorShader::asABitmap(SkBitmap* bitmap, SkMatrix* matrix
return kDefault_BitmapType;
}
SkShader::GradientType SkColorShader::asAGradient(GradientInfo* info) const {
if (info) {
if (info->fColors && info->fColorCount >= 1) {
info->fColors[0] = fColor;
}
info->fColorCount = 1;
info->fTileMode = SkShader::kRepeat_TileMode;
}
return kColor_GradientType;
}

View File

@ -129,6 +129,7 @@ protected:
SkMallocPixelRef* fCache32PixelRef;
void commonAsABitmap(SkBitmap*);
void commonAsAGradient(GradientInfo*) const;
private:
enum {
@ -687,6 +688,28 @@ void Gradient_Shader::commonAsABitmap(SkBitmap* bitmap) {
}
}
void Gradient_Shader::commonAsAGradient(GradientInfo* info) const {
if (info) {
if (info->fColorCount >= fColorCount) {
if (info->fColors) {
memcpy(info->fColors, fOrigColors,
fColorCount * sizeof(SkColor));
}
if (info->fColorOffsets) {
if (fColorCount == 2) {
info->fColorOffsets[0] = 0;
info->fColorOffsets[1] = SK_Scalar1;
} else if (fColorCount > 2) {
for (int i = 0; i < fColorCount; i++)
info->fColorOffsets[i] = SkFixedToScalar(fRecs[i].fPos);
}
}
}
info->fColorCount = fColorCount;
info->fTileMode = fTileMode;
}
}
///////////////////////////////////////////////////////////////////////////
static void pts_to_unit_matrix(const SkPoint pts[2], SkMatrix* matrix) {
@ -707,7 +730,9 @@ public:
Linear_Gradient(const SkPoint pts[2],
const SkColor colors[], const SkScalar pos[], int colorCount,
SkShader::TileMode mode, SkUnitMapper* mapper)
: Gradient_Shader(colors, pos, colorCount, mode, mapper)
: Gradient_Shader(colors, pos, colorCount, mode, mapper),
fStart(pts[0]),
fEnd(pts[1])
{
pts_to_unit_matrix(pts, &fPtsToUnit);
}
@ -717,17 +742,32 @@ public:
virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count);
virtual BitmapType asABitmap(SkBitmap*, SkMatrix*,
TileMode*, SkScalar* twoPointRadialParams);
virtual GradientType asAGradient(GradientInfo* info) const;
static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
return SkNEW_ARGS(Linear_Gradient, (buffer));
}
virtual void flatten(SkFlattenableWriteBuffer& buffer) {
this->INHERITED::flatten(buffer);
buffer.writeScalar(fStart.fX);
buffer.writeScalar(fStart.fY);
buffer.writeScalar(fEnd.fX);
buffer.writeScalar(fEnd.fY);
}
protected:
Linear_Gradient(SkFlattenableReadBuffer& buffer) : Gradient_Shader(buffer) {}
Linear_Gradient(SkFlattenableReadBuffer& buffer)
: Gradient_Shader(buffer),
fStart(SkPoint::Make(buffer.readScalar(), buffer.readScalar())),
fEnd(SkPoint::Make(buffer.readScalar(), buffer.readScalar())) {
}
virtual Factory getFactory() { return CreateProc; }
private:
typedef Gradient_Shader INHERITED;
const SkPoint fStart;
const SkPoint fEnd;
};
bool Linear_Gradient::setContext(const SkBitmap& device, const SkPaint& paint,
@ -850,6 +890,15 @@ SkShader::BitmapType Linear_Gradient::asABitmap(SkBitmap* bitmap,
return kDefault_BitmapType;
}
SkShader::GradientType Linear_Gradient::asAGradient(GradientInfo* info) const {
if (info) {
commonAsAGradient(info);
info->fPoint[0] = fStart;
info->fPoint[1] = fEnd;
}
return kLinear_GradientType;
}
static void dither_memset16(uint16_t dst[], uint16_t value, uint16_t other,
int count) {
if (reinterpret_cast<uintptr_t>(dst) & 2) {
@ -989,7 +1038,9 @@ public:
Radial_Gradient(const SkPoint& center, SkScalar radius,
const SkColor colors[], const SkScalar pos[], int colorCount,
SkShader::TileMode mode, SkUnitMapper* mapper)
: Gradient_Shader(colors, pos, colorCount, mode, mapper)
: Gradient_Shader(colors, pos, colorCount, mode, mapper),
fCenter(center),
fRadius(radius)
{
// make sure our table is insync with our current #define for kSQRT_TABLE_SIZE
SkASSERT(sizeof(gSqrt8Table) == kSQRT_TABLE_SIZE);
@ -1199,17 +1250,38 @@ public:
}
return kRadial_BitmapType;
}
virtual GradientType asAGradient(GradientInfo* info) const {
if (info) {
commonAsAGradient(info);
info->fPoint[0] = fCenter;
info->fRadius[0] = fRadius;
}
return kRadial_GradientType;
}
static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
return SkNEW_ARGS(Radial_Gradient, (buffer));
}
virtual void flatten(SkFlattenableWriteBuffer& buffer) {
this->INHERITED::flatten(buffer);
buffer.writeScalar(fCenter.fX);
buffer.writeScalar(fCenter.fY);
buffer.writeScalar(fRadius);
}
protected:
Radial_Gradient(SkFlattenableReadBuffer& buffer) : Gradient_Shader(buffer) {};
Radial_Gradient(SkFlattenableReadBuffer& buffer)
: Gradient_Shader(buffer),
fCenter(SkPoint::Make(buffer.readScalar(), buffer.readScalar())),
fRadius(buffer.readScalar()) {
}
virtual Factory getFactory() { return CreateProc; }
private:
typedef Gradient_Shader INHERITED;
const SkPoint fCenter;
const SkScalar fRadius;
};
/* Two-point radial gradients are specified by two circles, each with a center
@ -1305,20 +1377,12 @@ public:
const SkColor colors[], const SkScalar pos[],
int colorCount, SkShader::TileMode mode,
SkUnitMapper* mapper)
: Gradient_Shader(colors, pos, colorCount, mode, mapper)
{
fDiff = start - end;
fDiffRadius = endRadius - startRadius;
SkScalar inv = SkScalarInvert(fDiffRadius);
fDiff.fX = SkScalarMul(fDiff.fX, inv);
fDiff.fY = SkScalarMul(fDiff.fY, inv);
fStartRadius = SkScalarMul(startRadius, inv);
fSr2D2 = SkScalarSquare(fStartRadius);
fA = SkScalarSquare(fDiff.fX) + SkScalarSquare(fDiff.fY) - SK_Scalar1;
fOneOverTwoA = SkScalarInvert(fA * 2);
fPtsToUnit.setTranslate(-start.fX, -start.fY);
fPtsToUnit.postScale(inv, inv);
: Gradient_Shader(colors, pos, colorCount, mode, mapper),
fCenter1(start),
fCenter2(end),
fRadius1(startRadius),
fRadius2(endRadius) {
init();
}
virtual BitmapType asABitmap(SkBitmap* bitmap,
@ -1351,6 +1415,17 @@ public:
return kTwoPointRadial_BitmapType;
}
virtual GradientType asAGradient(GradientInfo* info) const {
if (info) {
commonAsAGradient(info);
info->fPoint[0] = fCenter1;
info->fPoint[1] = fCenter2;
info->fRadius[0] = fRadius1;
info->fRadius[1] = fRadius2;
}
return kRadial2_GradientType;
}
virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count)
{
SkASSERT(count > 0);
@ -1468,32 +1543,48 @@ public:
virtual void flatten(SkFlattenableWriteBuffer& buffer) {
this->INHERITED::flatten(buffer);
buffer.writeScalar(fDiff.fX);
buffer.writeScalar(fDiff.fY);
buffer.writeScalar(fStartRadius);
buffer.writeScalar(fDiffRadius);
buffer.writeScalar(fSr2D2);
buffer.writeScalar(fA);
buffer.writeScalar(fOneOverTwoA);
buffer.writeScalar(fCenter1.fX);
buffer.writeScalar(fCenter1.fY);
buffer.writeScalar(fCenter2.fX);
buffer.writeScalar(fCenter2.fY);
buffer.writeScalar(fRadius1);
buffer.writeScalar(fRadius2);
}
protected:
Two_Point_Radial_Gradient(SkFlattenableReadBuffer& buffer)
: Gradient_Shader(buffer) {
fDiff.fX = buffer.readScalar();
fDiff.fY = buffer.readScalar();
fStartRadius = buffer.readScalar();
fDiffRadius = buffer.readScalar();
fSr2D2 = buffer.readScalar();
fA = buffer.readScalar();
fOneOverTwoA = buffer.readScalar();
: Gradient_Shader(buffer),
fCenter1(SkPoint::Make(buffer.readScalar(), buffer.readScalar())),
fCenter2(SkPoint::Make(buffer.readScalar(), buffer.readScalar())),
fRadius1(buffer.readScalar()),
fRadius2(buffer.readScalar()) {
init();
};
virtual Factory getFactory() { return CreateProc; }
private:
typedef Gradient_Shader INHERITED;
const SkPoint fCenter1;
const SkPoint fCenter2;
const SkScalar fRadius1;
const SkScalar fRadius2;
SkPoint fDiff;
SkScalar fStartRadius, fDiffRadius, fSr2D2, fA, fOneOverTwoA;
void init() {
fDiff = fCenter1 - fCenter2;
fDiffRadius = fRadius2 - fRadius1;
SkScalar inv = SkScalarInvert(fDiffRadius);
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 = SkScalarInvert(fA * 2);
fPtsToUnit.setTranslate(-fCenter1.fX, -fCenter1.fY);
fPtsToUnit.postScale(inv, inv);
}
};
///////////////////////////////////////////////////////////////////////////////
@ -1502,7 +1593,8 @@ class Sweep_Gradient : public Gradient_Shader {
public:
Sweep_Gradient(SkScalar cx, SkScalar cy, const SkColor colors[],
const SkScalar pos[], int count, SkUnitMapper* mapper)
: Gradient_Shader(colors, pos, count, SkShader::kClamp_TileMode, mapper)
: Gradient_Shader(colors, pos, count, SkShader::kClamp_TileMode, mapper),
fCenter(SkPoint::Make(cx, cy))
{
fPtsToUnit.setTranslate(-cx, -cy);
}
@ -1526,16 +1618,35 @@ public:
return kSweep_BitmapType;
}
virtual GradientType asAGradient(GradientInfo* info) const {
if (info) {
commonAsAGradient(info);
info->fPoint[0] = fCenter;
}
return kSweep_GradientType;
}
static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
return SkNEW_ARGS(Sweep_Gradient, (buffer));
}
virtual void flatten(SkFlattenableWriteBuffer& buffer) {
this->INHERITED::flatten(buffer);
buffer.writeScalar(fCenter.fX);
buffer.writeScalar(fCenter.fY);
}
protected:
Sweep_Gradient(SkFlattenableReadBuffer& buffer) : Gradient_Shader(buffer) {}
Sweep_Gradient(SkFlattenableReadBuffer& buffer)
: Gradient_Shader(buffer),
fCenter(SkPoint::Make(buffer.readScalar(), buffer.readScalar())) {
}
virtual Factory getFactory() { return CreateProc; }
private:
typedef Gradient_Shader INHERITED;
const SkPoint fCenter;
};
#ifdef COMPUTE_SWEEP_TABLE

View File

@ -325,7 +325,13 @@ bool SkGpuDevice::bindDeviceAsTexture(GrPaint* paint) {
///////////////////////////////////////////////////////////////////////////////
// must be in SkShader::BitmapTypeOrder
SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch);
SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch);
SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch);
SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4,
shader_type_mismatch);
SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 4, shader_type_mismatch);
static const GrSamplerState::SampleMode sk_bmp_type_to_sample_mode[] = {
(GrSamplerState::SampleMode) -1, // kNone_BitmapType