Add stroked ovals and CircleEdgeEffect.
Adds some optimizations to the circle and ellipse shaders, static effect instances for their GrEffects, and some minor changes to GrDrawState::setEffect to make GrEffect setup faster. git-svn-id: http://skia.googlecode.com/svn/trunk@8238 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
0b735631b7
commit
65eb4d5a21
@ -122,6 +122,8 @@
|
||||
'<(skia_src_path)/gpu/gr_unittests.cpp',
|
||||
|
||||
'<(skia_src_path)/gpu/effects/Gr1DKernelEffect.h',
|
||||
'<(skia_src_path)/gpu/effects/GrCircleEdgeEffect.cpp',
|
||||
'<(skia_src_path)/gpu/effects/GrCircleEdgeEffect.h',
|
||||
'<(skia_src_path)/gpu/effects/GrConfigConversionEffect.cpp',
|
||||
'<(skia_src_path)/gpu/effects/GrConfigConversionEffect.h',
|
||||
'<(skia_src_path)/gpu/effects/GrConvolutionEffect.cpp',
|
||||
|
@ -894,7 +894,8 @@ private:
|
||||
void internalDrawPath(const GrPaint& paint, const SkPath& path, const SkStrokeRec& stroke);
|
||||
|
||||
void internalDrawOval(const GrPaint& paint, const GrRect& oval, const SkStrokeRec& stroke);
|
||||
bool canDrawOval(const GrPaint& paint, const GrRect& oval, const SkStrokeRec& stroke) const;
|
||||
void internalDrawCircle(const GrPaint& paint, const GrRect& circle, const SkStrokeRec& stroke);
|
||||
bool canDrawOval(const GrPaint& paint, const GrRect& oval, bool* isCircle) const;
|
||||
|
||||
GrTexture* createResizedTexture(const GrTextureDesc& desc,
|
||||
const GrCacheID& cacheID,
|
||||
|
@ -116,7 +116,8 @@ public:
|
||||
stage.fEffectRef->get()->incDeferredRefCounts();
|
||||
fEffect = stage.fEffectRef->get();
|
||||
fCoordChangeMatrix = stage.fCoordChangeMatrix;
|
||||
fVertexAttribIndices = stage.fVertexAttribIndices;
|
||||
fVertexAttribIndices[0] = stage.fVertexAttribIndices[0];
|
||||
fVertexAttribIndices[1] = stage.fVertexAttribIndices[1];
|
||||
}
|
||||
SkDEBUGCODE(fInitialized = true;)
|
||||
}
|
||||
@ -127,7 +128,8 @@ public:
|
||||
if (NULL != fEffect) {
|
||||
stage->fEffectRef = GrEffect::CreateEffectRef(fEffect);
|
||||
stage->fCoordChangeMatrix = fCoordChangeMatrix;
|
||||
stage->fVertexAttribIndices = fVertexAttribIndices;
|
||||
stage->fVertexAttribIndices[0] = fVertexAttribIndices[0];
|
||||
stage->fVertexAttribIndices[1] = fVertexAttribIndices[1];
|
||||
} else {
|
||||
stage->fEffectRef = NULL;
|
||||
}
|
||||
@ -141,7 +143,8 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fVertexAttribIndices != stage.fVertexAttribIndices) {
|
||||
if (fVertexAttribIndices[0] != stage.fVertexAttribIndices[0]
|
||||
|| fVertexAttribIndices[1] != stage.fVertexAttribIndices[1]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -155,7 +158,8 @@ public:
|
||||
private:
|
||||
const GrEffect* fEffect;
|
||||
SkMatrix fCoordChangeMatrix;
|
||||
SkSTArray<GrEffect::kMaxVertexAttribs, int, true> fVertexAttribIndices;
|
||||
int fVertexAttribIndices[2];
|
||||
int fVertexAttribCount;
|
||||
SkDEBUGCODE(bool fInitialized;)
|
||||
};
|
||||
|
||||
@ -169,28 +173,37 @@ public:
|
||||
GrSafeSetNull(fEffectRef);
|
||||
}
|
||||
|
||||
const GrEffectRef* setEffect(const GrEffectRef* EffectRef, const int* attribIndices = NULL) {
|
||||
const GrEffectRef* setEffect(const GrEffectRef* EffectRef) {
|
||||
GrAssert(0 == fSavedCoordChangeCnt);
|
||||
GrSafeAssign(fEffectRef, EffectRef);
|
||||
fCoordChangeMatrix.reset();
|
||||
|
||||
fVertexAttribIndices.reset();
|
||||
int numVertexAttribs = (EffectRef == NULL) ? 0 : EffectRef->get()->numVertexAttribs();
|
||||
GrAssert(numVertexAttribs == 0 || attribIndices != NULL);
|
||||
fVertexAttribIndices.push_back_n(numVertexAttribs, attribIndices);
|
||||
|
||||
fVertexAttribIndices[0] = -1;
|
||||
fVertexAttribIndices[1] = -1;
|
||||
|
||||
return EffectRef;
|
||||
}
|
||||
|
||||
const GrEffectRef* setEffect(const GrEffectRef* EffectRef, int attr0, int attr1 = -1) {
|
||||
GrAssert(0 == fSavedCoordChangeCnt);
|
||||
GrSafeAssign(fEffectRef, EffectRef);
|
||||
fCoordChangeMatrix.reset();
|
||||
|
||||
fVertexAttribIndices[0] = attr0;
|
||||
fVertexAttribIndices[1] = attr1;
|
||||
|
||||
return EffectRef;
|
||||
}
|
||||
|
||||
const GrEffectRef* getEffect() const { return fEffectRef; }
|
||||
|
||||
const int* getVertexAttribIndices() const { return fVertexAttribIndices.begin(); }
|
||||
int getVertexAttribIndexCount() const { return fVertexAttribIndices.count(); }
|
||||
const int* getVertexAttribIndices() const { return fVertexAttribIndices; }
|
||||
int getVertexAttribIndexCount() const { return fEffectRef->get()->numVertexAttribs(); }
|
||||
|
||||
private:
|
||||
SkMatrix fCoordChangeMatrix;
|
||||
const GrEffectRef* fEffectRef;
|
||||
SkSTArray<2, int, true> fVertexAttribIndices;
|
||||
int fVertexAttribIndices[2];
|
||||
|
||||
GR_DEBUGCODE(mutable int fSavedCoordChangeCnt;)
|
||||
};
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "effects/GrConvolutionEffect.h"
|
||||
#include "effects/GrSingleTextureEffect.h"
|
||||
#include "effects/GrConfigConversionEffect.h"
|
||||
#include "effects/GrCircleEdgeEffect.h"
|
||||
#include "effects/GrEllipseEdgeEffect.h"
|
||||
|
||||
#include "GrBufferAllocPool.h"
|
||||
@ -36,7 +37,8 @@ SK_DEFINE_INST_COUNT(GrDrawState)
|
||||
// It can be useful to set this to false to test whether a bug is caused by using the
|
||||
// InOrderDrawBuffer, to compare performance of using/not using InOrderDrawBuffer, or to make
|
||||
// debugging simpler.
|
||||
SK_CONF_DECLARE(bool, c_Defer, "gpu.deferContext", true, "Defers rendering in GrContext via GrInOrderDrawBuffer.");
|
||||
SK_CONF_DECLARE(bool, c_Defer, "gpu.deferContext", true,
|
||||
"Defers rendering in GrContext via GrInOrderDrawBuffer.");
|
||||
|
||||
#define BUFFERED_DRAW (c_Defer ? kYes_BufferedDraw : kNo_BufferedDraw)
|
||||
|
||||
@ -358,7 +360,8 @@ GrTexture* GrContext::createResizedTexture(const GrTextureDesc& desc,
|
||||
{kVec2f_GrVertexAttribType, 0},
|
||||
{kVec2f_GrVertexAttribType, sizeof(GrPoint)}
|
||||
};
|
||||
static const GrAttribBindings kAttribBindings = GrDrawState::ExplicitTexCoordAttribBindingsBit(0);
|
||||
static const GrAttribBindings kAttribBindings =
|
||||
GrDrawState::ExplicitTexCoordAttribBindingsBit(0);
|
||||
drawState->setAttribBindings(kAttribBindings);
|
||||
drawState->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs));
|
||||
drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0);
|
||||
@ -389,7 +392,8 @@ GrTexture* GrContext::createResizedTexture(const GrTextureDesc& desc,
|
||||
|
||||
size_t stretchedRowBytes = rtDesc.fWidth * bpp;
|
||||
|
||||
SkDEBUGCODE(GrTexture* texture = )fGpu->createTexture(rtDesc, stretchedPixels.get(), stretchedRowBytes);
|
||||
SkDEBUGCODE(GrTexture* texture = )fGpu->createTexture(rtDesc, stretchedPixels.get(),
|
||||
stretchedRowBytes);
|
||||
GrAssert(NULL != texture);
|
||||
}
|
||||
|
||||
@ -999,6 +1003,15 @@ struct CircleVertex {
|
||||
SkScalar fInnerRadius;
|
||||
};
|
||||
|
||||
struct EllipseVertex {
|
||||
GrPoint fPos;
|
||||
GrPoint fCenter;
|
||||
SkScalar fOuterXRadius;
|
||||
SkScalar fOuterXYRatio;
|
||||
SkScalar fInnerXRadius;
|
||||
SkScalar fInnerXYRatio;
|
||||
};
|
||||
|
||||
inline bool circleStaysCircle(const SkMatrix& m) {
|
||||
return m.isSimilarity();
|
||||
}
|
||||
@ -1009,64 +1022,186 @@ void GrContext::drawOval(const GrPaint& paint,
|
||||
const GrRect& oval,
|
||||
const SkStrokeRec& stroke) {
|
||||
|
||||
if (!canDrawOval(paint, oval, stroke)) {
|
||||
bool isCircle;
|
||||
if (!canDrawOval(paint, oval, &isCircle)) {
|
||||
SkPath path;
|
||||
path.addOval(oval);
|
||||
this->drawPath(paint, path, stroke);
|
||||
return;
|
||||
}
|
||||
|
||||
internalDrawOval(paint, oval, stroke);
|
||||
if (isCircle) {
|
||||
this->internalDrawCircle(paint, oval, stroke);
|
||||
} else {
|
||||
this->internalDrawOval(paint, oval, stroke);
|
||||
}
|
||||
}
|
||||
|
||||
bool GrContext::canDrawOval(const GrPaint& paint, const GrRect& oval, const SkStrokeRec& stroke) const {
|
||||
bool GrContext::canDrawOval(const GrPaint& paint, const GrRect& oval, bool* isCircle) const {
|
||||
GrAssert(isCircle != NULL);
|
||||
|
||||
if (!paint.isAntiAlias()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// we can draw circles in any style
|
||||
bool isCircle = SkScalarNearlyEqual(oval.width(), oval.height())
|
||||
&& circleStaysCircle(this->getMatrix());
|
||||
// and for now, axis-aligned ellipses only with fill or stroke-and-fill
|
||||
SkStrokeRec::Style style = stroke.getStyle();
|
||||
bool isStroke = (style == SkStrokeRec::kStroke_Style || style == SkStrokeRec::kHairline_Style);
|
||||
bool isFilledAxisAlignedEllipse = this->getMatrix().rectStaysRect() && !isStroke;
|
||||
// we can draw circles
|
||||
*isCircle = SkScalarNearlyEqual(oval.width(), oval.height())
|
||||
&& circleStaysCircle(this->getMatrix());
|
||||
// and axis-aligned ellipses only
|
||||
bool isAxisAlignedEllipse = this->getMatrix().rectStaysRect();
|
||||
|
||||
return isCircle || isFilledAxisAlignedEllipse;
|
||||
return *isCircle || isAxisAlignedEllipse;
|
||||
}
|
||||
|
||||
void GrContext::internalDrawOval(const GrPaint& paint,
|
||||
const GrRect& oval,
|
||||
const SkStrokeRec& stroke) {
|
||||
|
||||
SkScalar xRadius = SkScalarHalf(oval.width());
|
||||
SkScalar yRadius = SkScalarHalf(oval.height());
|
||||
|
||||
SkScalar strokeWidth = stroke.getWidth();
|
||||
SkStrokeRec::Style style = stroke.getStyle();
|
||||
|
||||
bool isCircle = SkScalarNearlyEqual(xRadius, yRadius) && circleStaysCircle(this->getMatrix());
|
||||
#ifdef SK_DEBUG
|
||||
{
|
||||
// we should have checked for this previously
|
||||
bool isStroke = (style == SkStrokeRec::kStroke_Style || style == SkStrokeRec::kHairline_Style);
|
||||
bool isFilledAxisAlignedEllipse = this->getMatrix().rectStaysRect() && !isStroke;
|
||||
SkASSERT(paint.isAntiAlias() && (isCircle || isFilledAxisAlignedEllipse));
|
||||
bool isAxisAlignedEllipse = this->getMatrix().rectStaysRect();
|
||||
SkASSERT(paint.isAntiAlias() && isAxisAlignedEllipse);
|
||||
}
|
||||
#endif
|
||||
|
||||
GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW);
|
||||
|
||||
GrDrawState* drawState = target->drawState();
|
||||
GrDrawState::AutoStageDisable atr(fDrawState);
|
||||
const SkMatrix vm = drawState->getViewMatrix();
|
||||
|
||||
const GrRenderTarget* rt = drawState->getRenderTarget();
|
||||
if (NULL == rt) {
|
||||
return;
|
||||
}
|
||||
|
||||
const SkMatrix vm = drawState->getViewMatrix();
|
||||
|
||||
GrDrawState::AutoDeviceCoordDraw adcd(drawState);
|
||||
if (!adcd.succeeded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// position + edge
|
||||
static const GrVertexAttrib kVertexAttribs[] = {
|
||||
{kVec2f_GrVertexAttribType, 0},
|
||||
{kVec2f_GrVertexAttribType, sizeof(GrPoint)},
|
||||
{kVec4f_GrVertexAttribType, 2*sizeof(GrPoint)}
|
||||
};
|
||||
drawState->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs));
|
||||
drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0);
|
||||
GrAssert(sizeof(EllipseVertex) == drawState->getVertexSize());
|
||||
|
||||
GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
|
||||
if (!geo.succeeded()) {
|
||||
GrPrintf("Failed to get space for vertices!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices());
|
||||
|
||||
GrPoint center = GrPoint::Make(oval.centerX(), oval.centerY());
|
||||
vm.mapPoints(¢er, 1);
|
||||
|
||||
SkStrokeRec::Style style = stroke.getStyle();
|
||||
bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style);
|
||||
enum {
|
||||
// the edge effects share this stage with glyph rendering
|
||||
// (kGlyphMaskStage in GrTextContext) && SW path rendering
|
||||
// (kPathMaskStage in GrSWMaskHelper)
|
||||
kEdgeEffectStage = GrPaint::kTotalStages,
|
||||
};
|
||||
drawState->setAttribBindings(GrDrawState::kDefault_AttribBindings);
|
||||
|
||||
GrEffectRef* effect = GrEllipseEdgeEffect::Create(isStroked);
|
||||
static const int kEllipseCenterAttrIndex = 1;
|
||||
static const int kEllipseEdgeAttrIndex = 2;
|
||||
drawState->setEffect(kEdgeEffectStage, effect,
|
||||
kEllipseCenterAttrIndex, kEllipseEdgeAttrIndex)->unref();
|
||||
|
||||
SkRect xformedRect;
|
||||
vm.mapRect(&xformedRect, oval);
|
||||
|
||||
SkScalar xRadius = SkScalarHalf(xformedRect.width());
|
||||
SkScalar yRadius = SkScalarHalf(xformedRect.height());
|
||||
SkScalar innerXRadius = 0.0f;
|
||||
SkScalar innerRatio = 1.0f;
|
||||
|
||||
if (SkStrokeRec::kFill_Style != style) {
|
||||
SkScalar strokeWidth = stroke.getWidth();
|
||||
|
||||
// do (potentially) anisotropic mapping
|
||||
SkVector scaledStroke;
|
||||
scaledStroke.set(strokeWidth, strokeWidth);
|
||||
vm.mapVectors(&scaledStroke, 1);
|
||||
|
||||
if (SkScalarNearlyZero(scaledStroke.length())) {
|
||||
scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
|
||||
} else {
|
||||
scaledStroke.scale(0.5f);
|
||||
}
|
||||
|
||||
// this is legit only if scale & translation (which should be the case at the moment)
|
||||
if (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style) {
|
||||
SkScalar innerYRadius = SkMaxScalar(0, yRadius - scaledStroke.fY);
|
||||
if (innerYRadius > SK_ScalarNearlyZero) {
|
||||
innerXRadius = SkMaxScalar(0, xRadius - scaledStroke.fX);
|
||||
innerRatio = innerXRadius/innerYRadius;
|
||||
}
|
||||
}
|
||||
xRadius += scaledStroke.fX;
|
||||
yRadius += scaledStroke.fY;
|
||||
}
|
||||
|
||||
SkScalar outerRatio = SkScalarDiv(xRadius, yRadius);
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
verts[i].fCenter = center;
|
||||
verts[i].fOuterXRadius = xRadius + 0.5f;
|
||||
verts[i].fOuterXYRatio = outerRatio;
|
||||
verts[i].fInnerXRadius = innerXRadius - 0.5f;
|
||||
verts[i].fInnerXYRatio = innerRatio;
|
||||
}
|
||||
|
||||
SkScalar L = -xRadius;
|
||||
SkScalar R = +xRadius;
|
||||
SkScalar T = -yRadius;
|
||||
SkScalar B = +yRadius;
|
||||
|
||||
// We've extended the outer x radius out half a pixel to antialias.
|
||||
// Expand the drawn rect here so all the pixels will be captured.
|
||||
L += center.fX - SK_ScalarHalf;
|
||||
R += center.fX + SK_ScalarHalf;
|
||||
T += center.fY - SK_ScalarHalf;
|
||||
B += center.fY + SK_ScalarHalf;
|
||||
|
||||
verts[0].fPos = SkPoint::Make(L, T);
|
||||
verts[1].fPos = SkPoint::Make(R, T);
|
||||
verts[2].fPos = SkPoint::Make(L, B);
|
||||
verts[3].fPos = SkPoint::Make(R, B);
|
||||
|
||||
target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4);
|
||||
}
|
||||
|
||||
void GrContext::internalDrawCircle(const GrPaint& paint,
|
||||
const GrRect& circle,
|
||||
const SkStrokeRec& stroke) {
|
||||
|
||||
SkScalar radius = SkScalarHalf(circle.width());
|
||||
|
||||
SkScalar strokeWidth = stroke.getWidth();
|
||||
SkStrokeRec::Style style = stroke.getStyle();
|
||||
|
||||
GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW);
|
||||
|
||||
GrDrawState* drawState = target->drawState();
|
||||
GrDrawState::AutoStageDisable atr(fDrawState);
|
||||
|
||||
const GrRenderTarget* rt = drawState->getRenderTarget();
|
||||
if (NULL == rt) {
|
||||
return;
|
||||
}
|
||||
|
||||
const SkMatrix vm = drawState->getViewMatrix();
|
||||
|
||||
GrDrawState::AutoDeviceCoordDraw adcd(drawState);
|
||||
if (!adcd.succeeded()) {
|
||||
return;
|
||||
@ -1089,95 +1224,54 @@ void GrContext::internalDrawOval(const GrPaint& paint,
|
||||
|
||||
CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices());
|
||||
|
||||
GrPoint center = GrPoint::Make(oval.centerX(), oval.centerY());
|
||||
GrPoint center = GrPoint::Make(circle.centerX(), circle.centerY());
|
||||
vm.mapPoints(¢er, 1);
|
||||
|
||||
SkScalar L;
|
||||
SkScalar R;
|
||||
SkScalar T;
|
||||
SkScalar B;
|
||||
bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style);
|
||||
enum {
|
||||
// the edge effects share this stage with glyph rendering
|
||||
// (kGlyphMaskStage in GrTextContext) && SW path rendering
|
||||
// (kPathMaskStage in GrSWMaskHelper)
|
||||
kEdgeEffectStage = GrPaint::kTotalStages,
|
||||
};
|
||||
drawState->setAttribBindings(GrDrawState::kDefault_AttribBindings);
|
||||
|
||||
GrEffectRef* effect = GrCircleEdgeEffect::Create(isStroked);
|
||||
static const int kCircleEdgeAttrIndex = 1;
|
||||
drawState->setEffect(kEdgeEffectStage, effect, kCircleEdgeAttrIndex)->unref();
|
||||
|
||||
if (isCircle) {
|
||||
drawState->setAttribBindings(GrDrawState::kEdge_AttribBindingsBit);
|
||||
drawState->setVertexEdgeType(GrDrawState::kCircle_EdgeType);
|
||||
drawState->setAttribIndex(GrDrawState::kEdge_AttribIndex, 1);
|
||||
radius = vm.mapRadius(radius);
|
||||
|
||||
xRadius = vm.mapRadius(xRadius);
|
||||
|
||||
SkScalar outerRadius = xRadius;
|
||||
SkScalar innerRadius = 0;
|
||||
SkScalar halfWidth = 0;
|
||||
if (style != SkStrokeRec::kFill_Style) {
|
||||
strokeWidth = vm.mapRadius(strokeWidth);
|
||||
if (SkScalarNearlyZero(strokeWidth)) {
|
||||
halfWidth = SK_ScalarHalf;
|
||||
} else {
|
||||
halfWidth = SkScalarHalf(strokeWidth);
|
||||
}
|
||||
|
||||
outerRadius += halfWidth;
|
||||
if (style == SkStrokeRec::kStroke_Style || style == SkStrokeRec::kHairline_Style) {
|
||||
innerRadius = SkMaxScalar(0, xRadius - halfWidth);
|
||||
}
|
||||
SkScalar innerRadius = -2.0f;
|
||||
SkScalar outerRadius = radius;
|
||||
SkScalar halfWidth = 0;
|
||||
if (style != SkStrokeRec::kFill_Style) {
|
||||
strokeWidth = vm.mapRadius(strokeWidth);
|
||||
if (SkScalarNearlyZero(strokeWidth)) {
|
||||
halfWidth = SK_ScalarHalf;
|
||||
} else {
|
||||
halfWidth = SkScalarHalf(strokeWidth);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
verts[i].fCenter = center;
|
||||
verts[i].fOuterRadius = outerRadius;
|
||||
verts[i].fInnerRadius = innerRadius;
|
||||
outerRadius += halfWidth;
|
||||
if (isStroked) {
|
||||
innerRadius = SkMaxScalar(0, radius - halfWidth);
|
||||
}
|
||||
|
||||
L = -outerRadius;
|
||||
R = +outerRadius;
|
||||
T = -outerRadius;
|
||||
B = +outerRadius;
|
||||
} else { // is axis-aligned ellipse
|
||||
drawState->setAttribBindings(GrDrawState::kDefault_AttribBindings);
|
||||
|
||||
enum {
|
||||
// the edge effects share this stage with glyph rendering
|
||||
// (kGlyphMaskStage in GrTextContext) && SW path rendering
|
||||
// (kPathMaskStage in GrSWMaskHelper)
|
||||
kEdgeEffectStage = GrPaint::kTotalStages,
|
||||
};
|
||||
GrEffectRef* effect = GrEllipseEdgeEffect::Create();
|
||||
static const int kEdgeAttrIndex = 1;
|
||||
drawState->setEffect(kEdgeEffectStage, effect, &kEdgeAttrIndex)->unref();
|
||||
|
||||
SkRect xformedRect;
|
||||
vm.mapRect(&xformedRect, oval);
|
||||
|
||||
xRadius = SkScalarHalf(xformedRect.width());
|
||||
yRadius = SkScalarHalf(xformedRect.height());
|
||||
|
||||
if (style == SkStrokeRec::kStrokeAndFill_Style && strokeWidth > 0.0f) {
|
||||
SkScalar halfWidth = SkScalarHalf(strokeWidth);
|
||||
// do (potentially) anisotropic mapping
|
||||
SkVector scaledStroke;
|
||||
scaledStroke.set(halfWidth, halfWidth);
|
||||
vm.mapVectors(&scaledStroke, 1);
|
||||
// this is legit only if scale & translation (which should be the case at the moment)
|
||||
xRadius += scaledStroke.fX;
|
||||
yRadius += scaledStroke.fY;
|
||||
}
|
||||
|
||||
SkScalar ratio = SkScalarDiv(xRadius, yRadius);
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
verts[i].fCenter = center;
|
||||
verts[i].fOuterRadius = xRadius;
|
||||
verts[i].fInnerRadius = ratio;
|
||||
}
|
||||
|
||||
L = -xRadius;
|
||||
R = +xRadius;
|
||||
T = -yRadius;
|
||||
B = +yRadius;
|
||||
}
|
||||
|
||||
// The fragment shader will extend the radius out half a pixel
|
||||
// to antialias. Expand the drawn rect here so all the pixels
|
||||
// will be captured.
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
verts[i].fCenter = center;
|
||||
verts[i].fOuterRadius = outerRadius + 0.5f;
|
||||
verts[i].fInnerRadius = innerRadius - 0.5f;
|
||||
}
|
||||
|
||||
SkScalar L = -outerRadius;
|
||||
SkScalar R = +outerRadius;
|
||||
SkScalar T = -outerRadius;
|
||||
SkScalar B = +outerRadius;
|
||||
|
||||
// We've extended the outer radius out half a pixel to antialias.
|
||||
// Expand the drawn rect here so all the pixels will be captured.
|
||||
L += center.fX - SK_ScalarHalf;
|
||||
R += center.fX + SK_ScalarHalf;
|
||||
T += center.fY - SK_ScalarHalf;
|
||||
@ -1203,15 +1297,21 @@ void GrContext::drawPath(const GrPaint& paint, const SkPath& path, const SkStrok
|
||||
SkRect ovalRect;
|
||||
bool isOval = path.isOval(&ovalRect);
|
||||
|
||||
if (isOval && !path.isInverseFillType() && this->canDrawOval(paint, ovalRect, stroke)) {
|
||||
this->drawOval(paint, ovalRect, stroke);
|
||||
bool isCircle;
|
||||
if (isOval && !path.isInverseFillType() && this->canDrawOval(paint, ovalRect, &isCircle)) {
|
||||
if (isCircle) {
|
||||
this->internalDrawCircle(paint, ovalRect, stroke);
|
||||
} else {
|
||||
this->internalDrawOval(paint, ovalRect, stroke);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this->internalDrawPath(paint, path, stroke);
|
||||
}
|
||||
|
||||
void GrContext::internalDrawPath(const GrPaint& paint, const SkPath& path, const SkStrokeRec& stroke) {
|
||||
void GrContext::internalDrawPath(const GrPaint& paint, const SkPath& path,
|
||||
const SkStrokeRec& stroke) {
|
||||
|
||||
// Note that below we may sw-rasterize the path into a scratch texture.
|
||||
// Scratch textures can be recycled after they are returned to the texture
|
||||
|
@ -485,9 +485,14 @@ public:
|
||||
/// @name Effect Stages
|
||||
////
|
||||
|
||||
const GrEffectRef* setEffect(int stageIdx, const GrEffectRef* effect) {
|
||||
fStages[stageIdx].setEffect(effect);
|
||||
return effect;
|
||||
}
|
||||
|
||||
const GrEffectRef* setEffect(int stageIdx, const GrEffectRef* effect,
|
||||
const int* indices = NULL) {
|
||||
fStages[stageIdx].setEffect(effect, indices);
|
||||
int attr0, int attr1 = -1) {
|
||||
fStages[stageIdx].setEffect(effect, attr0, attr1);
|
||||
return effect;
|
||||
}
|
||||
|
||||
@ -518,7 +523,7 @@ public:
|
||||
}
|
||||
|
||||
void disableStage(int stageIdx) {
|
||||
this->setEffect(stageIdx, NULL, NULL);
|
||||
this->setEffect(stageIdx, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1023,9 +1028,6 @@ public:
|
||||
/* Same as above but for hairline quadratics. Uses unsigned distance.
|
||||
Coverage is min(0, 1-distance). */
|
||||
kHairQuad_EdgeType,
|
||||
/* Circle specified as center_x, center_y, outer_radius, inner_radius
|
||||
all in window space (y-down). */
|
||||
kCircle_EdgeType,
|
||||
|
||||
kVertexEdgeTypeCnt
|
||||
};
|
||||
|
87
src/gpu/effects/GrCircleEdgeEffect.cpp
Normal file
87
src/gpu/effects/GrCircleEdgeEffect.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "GrCircleEdgeEffect.h"
|
||||
#include "gl/GrGLEffect.h"
|
||||
#include "gl/GrGLEffectMatrix.h"
|
||||
#include "gl/GrGLSL.h"
|
||||
#include "gl/GrGLTexture.h"
|
||||
#include "GrTBackendEffectFactory.h"
|
||||
#include "GrTexture.h"
|
||||
|
||||
#include "SkRTConf.h"
|
||||
|
||||
class GrGLCircleEdgeEffect : public GrGLEffect {
|
||||
public:
|
||||
GrGLCircleEdgeEffect(const GrBackendEffectFactory& factory, const GrEffectRef&)
|
||||
: INHERITED (factory) {}
|
||||
|
||||
virtual void emitCode(GrGLShaderBuilder* builder,
|
||||
const GrEffectStage& stage,
|
||||
EffectKey key,
|
||||
const char* vertexCoords,
|
||||
const char* outputColor,
|
||||
const char* inputColor,
|
||||
const TextureSamplerArray& samplers) SK_OVERRIDE {
|
||||
const GrCircleEdgeEffect& effect = GetEffectFromStage<GrCircleEdgeEffect>(stage);
|
||||
|
||||
const char *vsName, *fsName;
|
||||
builder->addVarying(kVec4f_GrSLType, "CircleEdge", &vsName, &fsName);
|
||||
|
||||
const SkString* attrName =
|
||||
builder->getEffectAttributeName(stage.getVertexAttribIndices()[0]);
|
||||
builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str());
|
||||
|
||||
builder->fsCodeAppendf("\tfloat d = distance(%s.xy, %s.xy);\n",
|
||||
builder->fragmentPosition(), fsName);
|
||||
builder->fsCodeAppendf("\tfloat edgeAlpha = clamp(%s.z - d, 0.0, 1.0);\n", fsName);
|
||||
if (effect.isStroked()) {
|
||||
builder->fsCodeAppendf("\tfloat innerAlpha = clamp(d - %s.w, 0.0, 1.0);\n", fsName);
|
||||
builder->fsCodeAppend("\tedgeAlpha *= innerAlpha;\n");
|
||||
}
|
||||
SkString modulate;
|
||||
GrGLSLModulate4f(&modulate, inputColor, "edgeAlpha");
|
||||
builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
|
||||
}
|
||||
|
||||
static inline EffectKey GenKey(const GrEffectStage& stage, const GrGLCaps&) {
|
||||
const GrCircleEdgeEffect& effect = GetEffectFromStage<GrCircleEdgeEffect>(stage);
|
||||
|
||||
return effect.isStroked() ? 0x1 : 0x0;
|
||||
}
|
||||
|
||||
virtual void setData(const GrGLUniformManager& uman, const GrEffectStage& stage) SK_OVERRIDE {
|
||||
}
|
||||
|
||||
private:
|
||||
typedef GrGLEffect INHERITED;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GrCircleEdgeEffect::GrCircleEdgeEffect(bool stroke) : GrEffect() {
|
||||
this->addVertexAttrib(kVec4f_GrSLType);
|
||||
fStroke = stroke;
|
||||
}
|
||||
|
||||
void GrCircleEdgeEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
|
||||
*validFlags = 0;
|
||||
}
|
||||
|
||||
const GrBackendEffectFactory& GrCircleEdgeEffect::getFactory() const {
|
||||
return GrTBackendEffectFactory<GrCircleEdgeEffect>::getInstance();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GR_DEFINE_EFFECT_TEST(GrCircleEdgeEffect);
|
||||
|
||||
GrEffectRef* GrCircleEdgeEffect::TestCreate(SkMWCRandom* random,
|
||||
GrContext* context,
|
||||
GrTexture* textures[]) {
|
||||
return GrCircleEdgeEffect::Create(random->nextBool());
|
||||
}
|
65
src/gpu/effects/GrCircleEdgeEffect.h
Normal file
65
src/gpu/effects/GrCircleEdgeEffect.h
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrCircleEdgeEffect_DEFINED
|
||||
#define GrCircleEdgeEffect_DEFINED
|
||||
|
||||
#include "GrEffect.h"
|
||||
|
||||
class GrGLCircleEdgeEffect;
|
||||
|
||||
/**
|
||||
* The output of this effect is a modulation of the input color and coverage for a circle,
|
||||
* specified as center_x, center_y, x_radius, inner radius and outer radius in window space
|
||||
* (y-down).
|
||||
*/
|
||||
|
||||
class GrCircleEdgeEffect : public GrEffect {
|
||||
public:
|
||||
static GrEffectRef* Create(bool stroke) {
|
||||
// we go through this so we only have one copy of each effect (stroked/filled)
|
||||
static SkAutoTUnref<GrEffectRef> gCircleStrokeEdgeEffectRef(
|
||||
CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(GrCircleEdgeEffect, (true)))));
|
||||
static SkAutoTUnref<GrEffectRef> gCircleFillEdgeEffectRef(
|
||||
CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(GrCircleEdgeEffect, (false)))));
|
||||
|
||||
if (stroke) {
|
||||
gCircleStrokeEdgeEffectRef.get()->ref();
|
||||
return gCircleStrokeEdgeEffectRef;
|
||||
} else {
|
||||
gCircleFillEdgeEffectRef.get()->ref();
|
||||
return gCircleFillEdgeEffectRef;
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~GrCircleEdgeEffect() {}
|
||||
|
||||
static const char* Name() { return "CircleEdge"; }
|
||||
|
||||
virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
|
||||
|
||||
typedef GrGLCircleEdgeEffect GLEffect;
|
||||
|
||||
virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
|
||||
|
||||
inline bool isStroked() const { return fStroke; }
|
||||
|
||||
private:
|
||||
GrCircleEdgeEffect(bool stroke);
|
||||
|
||||
virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fStroke;
|
||||
|
||||
GR_DECLARE_EFFECT_TEST;
|
||||
|
||||
typedef GrEffect INHERITED;
|
||||
};
|
||||
|
||||
#endif
|
@ -25,27 +25,49 @@ public:
|
||||
const char* outputColor,
|
||||
const char* inputColor,
|
||||
const TextureSamplerArray& samplers) SK_OVERRIDE {
|
||||
const char *vsName, *fsName;
|
||||
builder->addVarying(kVec4f_GrSLType, "EllipseEdge", &vsName, &fsName);
|
||||
const GrEllipseEdgeEffect& effect = GetEffectFromStage<GrEllipseEdgeEffect>(stage);
|
||||
|
||||
const char *vsCenterName, *fsCenterName;
|
||||
const char *vsEdgeName, *fsEdgeName;
|
||||
|
||||
const SkString* attrName = builder->getEffectAttributeName(stage.getVertexAttribIndices()[0]);
|
||||
builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str());
|
||||
builder->addVarying(kVec2f_GrSLType, "EllipseCenter", &vsCenterName, &fsCenterName);
|
||||
const SkString* attr0Name =
|
||||
builder->getEffectAttributeName(stage.getVertexAttribIndices()[0]);
|
||||
builder->vsCodeAppendf("\t%s = %s;\n", vsCenterName, attr0Name->c_str());
|
||||
|
||||
builder->addVarying(kVec4f_GrSLType, "EllipseEdge", &vsEdgeName, &fsEdgeName);
|
||||
const SkString* attr1Name =
|
||||
builder->getEffectAttributeName(stage.getVertexAttribIndices()[1]);
|
||||
builder->vsCodeAppendf("\t%s = %s;\n", vsEdgeName, attr1Name->c_str());
|
||||
|
||||
builder->fsCodeAppend("\tfloat edgeAlpha;\n");
|
||||
// translate to origin
|
||||
builder->fsCodeAppendf("\tvec2 offset = (%s.xy - %s.xy);\n", builder->fragmentPosition(), fsName);
|
||||
builder->fsCodeAppendf("\tvec2 outerOffset = (%s.xy - %s.xy);\n",
|
||||
builder->fragmentPosition(), fsCenterName);
|
||||
builder->fsCodeAppend("\tvec2 innerOffset = outerOffset;\n");
|
||||
// scale y by xRadius/yRadius
|
||||
builder->fsCodeAppendf("\toffset.y *= %s.w;\n", fsName);
|
||||
builder->fsCodeAppend("\tfloat d = length(offset);\n");
|
||||
// compare length against xRadius
|
||||
builder->fsCodeAppendf("\tedgeAlpha = smoothstep(d - 0.5, d + 0.5, %s.z);\n", fsName);
|
||||
builder->fsCodeAppendf("\touterOffset.y *= %s.y;\n", fsEdgeName);
|
||||
builder->fsCodeAppend("\tfloat dOuter = length(outerOffset);\n");
|
||||
// compare outer lengths against xOuterRadius
|
||||
builder->fsCodeAppendf("\tfloat edgeAlpha = clamp(%s.x-dOuter, 0.0, 1.0);\n", fsEdgeName);
|
||||
|
||||
if (effect.isStroked()) {
|
||||
builder->fsCodeAppendf("\tinnerOffset.y *= %s.w;\n", fsEdgeName);
|
||||
builder->fsCodeAppend("\tfloat dInner = length(innerOffset);\n");
|
||||
|
||||
// compare inner lengths against xInnerRadius
|
||||
builder->fsCodeAppendf("\tfloat innerAlpha = clamp(dInner-%s.z, 0.0, 1.0);\n", fsEdgeName);
|
||||
builder->fsCodeAppend("\tedgeAlpha *= innerAlpha;\n");
|
||||
}
|
||||
|
||||
SkString modulate;
|
||||
GrGLSLModulate4f(&modulate, inputColor, "edgeAlpha");
|
||||
builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
|
||||
}
|
||||
|
||||
static inline EffectKey GenKey(const GrEffectStage& stage, const GrGLCaps&) {
|
||||
return 0;
|
||||
const GrEllipseEdgeEffect& effect = GetEffectFromStage<GrEllipseEdgeEffect>(stage);
|
||||
|
||||
return effect.isStroked() ? 0x1 : 0x0;
|
||||
}
|
||||
|
||||
virtual void setData(const GrGLUniformManager& uman, const GrEffectStage& stage) SK_OVERRIDE {
|
||||
@ -57,8 +79,11 @@ private:
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GrEllipseEdgeEffect::GrEllipseEdgeEffect() : GrEffect() {
|
||||
GrEllipseEdgeEffect::GrEllipseEdgeEffect(bool stroke) : GrEffect() {
|
||||
this->addVertexAttrib(kVec2f_GrSLType);
|
||||
this->addVertexAttrib(kVec4f_GrSLType);
|
||||
|
||||
fStroke = stroke;
|
||||
}
|
||||
|
||||
void GrEllipseEdgeEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
|
||||
@ -76,5 +101,5 @@ GR_DEFINE_EFFECT_TEST(GrEllipseEdgeEffect);
|
||||
GrEffectRef* GrEllipseEdgeEffect::TestCreate(SkMWCRandom* random,
|
||||
GrContext* context,
|
||||
GrTexture* textures[]) {
|
||||
return GrEllipseEdgeEffect::Create();
|
||||
return GrEllipseEdgeEffect::Create(random->nextBool());
|
||||
}
|
||||
|
@ -19,10 +19,20 @@ class GrGLEllipseEdgeEffect;
|
||||
|
||||
class GrEllipseEdgeEffect : public GrEffect {
|
||||
public:
|
||||
static GrEffectRef* Create() {
|
||||
// maybe only have one static copy?
|
||||
AutoEffectUnref effect(SkNEW(GrEllipseEdgeEffect));
|
||||
return CreateEffectRef(effect);
|
||||
static GrEffectRef* Create(bool stroke) {
|
||||
// we go through this so we only have one copy of each effect (stroked/filled)
|
||||
static SkAutoTUnref<GrEffectRef> gEllipseStrokeEdgeEffectRef(
|
||||
CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(GrEllipseEdgeEffect, (true)))));
|
||||
static SkAutoTUnref<GrEffectRef> gEllipseFillEdgeEffectRef(
|
||||
CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(GrEllipseEdgeEffect, (false)))));
|
||||
|
||||
if (stroke) {
|
||||
gEllipseStrokeEdgeEffectRef.get()->ref();
|
||||
return gEllipseStrokeEdgeEffectRef;
|
||||
} else {
|
||||
gEllipseFillEdgeEffectRef.get()->ref();
|
||||
return gEllipseFillEdgeEffectRef;
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~GrEllipseEdgeEffect() {}
|
||||
@ -35,13 +45,17 @@ public:
|
||||
|
||||
virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
|
||||
|
||||
inline bool isStroked() const { return fStroke; }
|
||||
|
||||
private:
|
||||
GrEllipseEdgeEffect();
|
||||
GrEllipseEdgeEffect(bool stroke);
|
||||
|
||||
virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fStroke;
|
||||
|
||||
GR_DECLARE_EFFECT_TEST;
|
||||
|
||||
typedef GrEffect INHERITED;
|
||||
|
@ -23,7 +23,8 @@ SK_DEFINE_INST_COUNT(GrGLProgram)
|
||||
#define GL_CALL(X) GR_GL_CALL(fContext.interface(), X)
|
||||
#define GL_CALL_RET(R, X) GR_GL_CALL_RET(fContext.interface(), R, X)
|
||||
|
||||
SK_CONF_DECLARE(bool, c_PrintShaders, "gpu.printShaders", false, "Print the source code for all shaders generated.");
|
||||
SK_CONF_DECLARE(bool, c_PrintShaders, "gpu.printShaders", false,
|
||||
"Print the source code for all shaders generated.");
|
||||
|
||||
#define TEX_ATTR_NAME "aTexCoord"
|
||||
#define COL_ATTR_NAME "aColor"
|
||||
@ -69,15 +70,16 @@ void GrGLProgram::BuildDesc(const GrDrawState& drawState,
|
||||
|
||||
desc->fEmitsPointSize = isPoints;
|
||||
|
||||
bool requiresAttributeColors = !skipColor &&
|
||||
SkToBool(desc->fAttribBindings & GrDrawState::kColor_AttribBindingsBit);
|
||||
bool requiresAttributeCoverage = !skipCoverage &&
|
||||
SkToBool(desc->fAttribBindings & GrDrawState::kCoverage_AttribBindingsBit);
|
||||
bool requiresAttributeColors =
|
||||
!skipColor && SkToBool(desc->fAttribBindings & GrDrawState::kColor_AttribBindingsBit);
|
||||
bool requiresAttributeCoverage =
|
||||
!skipCoverage && SkToBool(desc->fAttribBindings & GrDrawState::kCoverage_AttribBindingsBit);
|
||||
|
||||
// fColorInput/fCoverageInput records how colors are specified for the program So we strip the
|
||||
// bits from the bindings to avoid false negatives when searching for an existing program in the
|
||||
// cache.
|
||||
desc->fAttribBindings &= ~(GrDrawState::kColor_AttribBindingsBit | GrDrawState::kCoverage_AttribBindingsBit);
|
||||
desc->fAttribBindings &=
|
||||
~(GrDrawState::kColor_AttribBindingsBit | GrDrawState::kCoverage_AttribBindingsBit);
|
||||
|
||||
desc->fColorFilterXfermode = skipColor ?
|
||||
SkXfermode::kDst_Mode :
|
||||
@ -423,7 +425,8 @@ bool GrGLProgram::genEdgeCoverage(SkString* coverageVar,
|
||||
builder->vsCodeAppendf("\t%s = " EDGE_ATTR_NAME ";\n", vsName);
|
||||
switch (fDesc.fVertexEdgeType) {
|
||||
case GrDrawState::kHairLine_EdgeType:
|
||||
builder->fsCodeAppendf("\tfloat edgeAlpha = abs(dot(vec3(%s.xy,1), %s.xyz));\n", builder->fragmentPosition(), fsName);
|
||||
builder->fsCodeAppendf("\tfloat edgeAlpha = abs(dot(vec3(%s.xy,1), %s.xyz));\n",
|
||||
builder->fragmentPosition(), fsName);
|
||||
builder->fsCodeAppendf("\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
|
||||
break;
|
||||
case GrDrawState::kQuad_EdgeType:
|
||||
@ -433,7 +436,8 @@ bool GrGLProgram::genEdgeCoverage(SkString* coverageVar,
|
||||
builder->fsCodeAppendf("\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
|
||||
builder->fsCodeAppendf("\tif (%s.z > 0.0 && %s.w > 0.0) {\n", fsName, fsName);
|
||||
// today we know z and w are in device space. We could use derivatives
|
||||
builder->fsCodeAppendf("\t\tedgeAlpha = min(min(%s.z, %s.w) + 0.5, 1.0);\n", fsName, fsName);
|
||||
builder->fsCodeAppendf("\t\tedgeAlpha = min(min(%s.z, %s.w) + 0.5, 1.0);\n", fsName,
|
||||
fsName);
|
||||
builder->fsCodeAppendf ("\t} else {\n");
|
||||
builder->fsCodeAppendf("\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
|
||||
"\t\t 2.0*%s.x*duvdy.x - duvdy.y);\n",
|
||||
@ -451,20 +455,14 @@ bool GrGLProgram::genEdgeCoverage(SkString* coverageVar,
|
||||
builder->fsCodeAppendf("\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
|
||||
"\t 2.0*%s.x*duvdy.x - duvdy.y);\n",
|
||||
fsName, fsName);
|
||||
builder->fsCodeAppendf("\tfloat edgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName, fsName);
|
||||
builder->fsCodeAppendf("\tfloat edgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName,
|
||||
fsName);
|
||||
builder->fsCodeAppend("\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / dot(gF, gF));\n");
|
||||
builder->fsCodeAppend("\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
|
||||
if (kES2_GrGLBinding == fContext.info().binding()) {
|
||||
builder->fHeader.printf("#extension GL_OES_standard_derivatives: enable\n");
|
||||
}
|
||||
break;
|
||||
case GrDrawState::kCircle_EdgeType:
|
||||
builder->fsCodeAppend("\tfloat edgeAlpha;\n");
|
||||
builder->fsCodeAppendf("\tfloat d = distance(%s.xy, %s.xy);\n", builder->fragmentPosition(), fsName);
|
||||
builder->fsCodeAppendf("\tfloat outerAlpha = smoothstep(d - 0.5, d + 0.5, %s.z);\n", fsName);
|
||||
builder->fsCodeAppendf("\tfloat innerAlpha = %s.w == 0.0 ? 1.0 : smoothstep(%s.w - 0.5, %s.w + 0.5, d);\n", fsName, fsName, fsName);
|
||||
builder->fsCodeAppend("\tedgeAlpha = outerAlpha * innerAlpha;\n");
|
||||
break;
|
||||
default:
|
||||
GrCrash("Unknown Edge Type!");
|
||||
break;
|
||||
@ -905,7 +903,9 @@ bool GrGLProgram::genProgram(const GrEffectStage* stages[]) {
|
||||
|
||||
// discard if coverage is zero
|
||||
if (fDesc.fDiscardIfOutsideEdge && !outCoverage.isEmpty()) {
|
||||
builder.fsCodeAppendf("\tif (all(lessThanEqual(%s, vec4(0.0)))) {\n\t\tdiscard;\n\t}\n", outCoverage.c_str());
|
||||
builder.fsCodeAppendf(
|
||||
"\tif (all(lessThanEqual(%s, vec4(0.0)))) {\n\t\tdiscard;\n\t}\n",
|
||||
outCoverage.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,7 +134,7 @@ bool GrGpuGL::programUnitTest(int maxStages) {
|
||||
for (int i = 0; i < effect.get()->get()->numVertexAttribs(); ++i) {
|
||||
attribIndices[i] = currAttribIndex++;
|
||||
}
|
||||
stages[s].setEffect(effect.get(), attribIndices);
|
||||
stages[s].setEffect(effect.get(), attribIndices[0], attribIndices[1]);
|
||||
}
|
||||
}
|
||||
pdesc.setRandom(&random, this, stages);
|
||||
|
Loading…
Reference in New Issue
Block a user