зеркало из https://github.com/mozilla/moz-skia.git
Add GrAAHairLinePathRenderer
Review URL: http://codereview.appspot.com/4926045 git-svn-id: http://skia.googlecode.com/svn/trunk@2196 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
Родитель
dec9f2d351
Коммит
aeb2160b1d
|
@ -0,0 +1,633 @@
|
||||||
|
#include "GrAAHairLinePathRenderer.h"
|
||||||
|
|
||||||
|
#include "GrContext.h"
|
||||||
|
#include "GrGpu.h"
|
||||||
|
#include "GrIndexBuffer.h"
|
||||||
|
#include "SkGeometry.h"
|
||||||
|
#include "SkTemplates.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// quadratics are rendered as 5-sided polys in order to bound the
|
||||||
|
// AA stroke around the center-curve. See comments in push_quad_index_buffer and
|
||||||
|
// bloat_quad.
|
||||||
|
static const int kVertsPerQuad = 5;
|
||||||
|
static const int kIdxsPerQuad = 9;
|
||||||
|
|
||||||
|
static const int kVertsPerLineSeg = 4;
|
||||||
|
static const int kIdxsPerLineSeg = 6;
|
||||||
|
|
||||||
|
static const int kNumQuadsInIdxBuffer = 256;
|
||||||
|
static const size_t kQuadIdxSBufize = kIdxsPerQuad *
|
||||||
|
sizeof(uint16_t) *
|
||||||
|
kNumQuadsInIdxBuffer;
|
||||||
|
|
||||||
|
bool push_quad_index_data(GrIndexBuffer* qIdxBuffer) {
|
||||||
|
uint16_t* data = (uint16_t*) qIdxBuffer->lock();
|
||||||
|
bool tempData = NULL == data;
|
||||||
|
if (tempData) {
|
||||||
|
data = new uint16_t[kNumQuadsInIdxBuffer * kIdxsPerQuad];
|
||||||
|
}
|
||||||
|
for (int i = 0; i < kNumQuadsInIdxBuffer; ++i) {
|
||||||
|
|
||||||
|
// Each quadratic is rendered as a five sided polygon. This poly bounds
|
||||||
|
// the quadratic's bounding triangle but has been expanded so that the
|
||||||
|
// 1-pixel wide area around the curve is inside the poly.
|
||||||
|
// If a,b,c are the original control points then the poly a0,b0,c0,c1,a1
|
||||||
|
// that is rendered would look like this:
|
||||||
|
// b0
|
||||||
|
// b
|
||||||
|
//
|
||||||
|
// a0 c0
|
||||||
|
// a c
|
||||||
|
// a1 c1
|
||||||
|
// Each is drawn as three triagnles specified by these 9 indices:
|
||||||
|
int baseIdx = i * kIdxsPerQuad;
|
||||||
|
uint16_t baseVert = (uint16_t)(i * kVertsPerQuad);
|
||||||
|
data[0 + baseIdx] = baseVert + 0; // a0
|
||||||
|
data[1 + baseIdx] = baseVert + 1; // a1
|
||||||
|
data[2 + baseIdx] = baseVert + 2; // b0
|
||||||
|
data[3 + baseIdx] = baseVert + 2; // b0
|
||||||
|
data[4 + baseIdx] = baseVert + 4; // c1
|
||||||
|
data[5 + baseIdx] = baseVert + 3; // c0
|
||||||
|
data[6 + baseIdx] = baseVert + 1; // a1
|
||||||
|
data[7 + baseIdx] = baseVert + 4; // c1
|
||||||
|
data[8 + baseIdx] = baseVert + 2; // b0
|
||||||
|
}
|
||||||
|
if (tempData) {
|
||||||
|
bool ret = qIdxBuffer->updateData(data, kQuadIdxSBufize);
|
||||||
|
delete[] data;
|
||||||
|
return ret;
|
||||||
|
} else {
|
||||||
|
qIdxBuffer->unlock();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GrPathRenderer* GrAAHairLinePathRenderer::Create(GrContext* context) {
|
||||||
|
if (CanBeUsed(context)) {
|
||||||
|
const GrIndexBuffer* lIdxBuffer = context->getQuadIndexBuffer();
|
||||||
|
if (NULL == lIdxBuffer) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
GrGpu* gpu = context->getGpu();
|
||||||
|
GrIndexBuffer* qIdxBuf = gpu->createIndexBuffer(kQuadIdxSBufize, false);
|
||||||
|
SkAutoTUnref<GrIndexBuffer> qIdxBuffer(qIdxBuf); // cons will take a ref
|
||||||
|
if (NULL == qIdxBuf ||
|
||||||
|
!push_quad_index_data(qIdxBuffer.get())) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return new GrAAHairLinePathRenderer(context,
|
||||||
|
lIdxBuffer,
|
||||||
|
qIdxBuf);
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GrAAHairLinePathRenderer::CanBeUsed(const GrContext* context) {
|
||||||
|
return context->getGpu()->supportsShaderDerivatives();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
GrAAHairLinePathRenderer::GrAAHairLinePathRenderer(
|
||||||
|
const GrContext* context,
|
||||||
|
const GrIndexBuffer* linesIndexBuffer,
|
||||||
|
const GrIndexBuffer* quadsIndexBuffer) {
|
||||||
|
GrAssert(CanBeUsed(context));
|
||||||
|
fLinesIndexBuffer = linesIndexBuffer;
|
||||||
|
linesIndexBuffer->ref();
|
||||||
|
fQuadsIndexBuffer = quadsIndexBuffer;
|
||||||
|
quadsIndexBuffer->ref();
|
||||||
|
this->resetGeom();
|
||||||
|
}
|
||||||
|
|
||||||
|
GrAAHairLinePathRenderer::~GrAAHairLinePathRenderer() {
|
||||||
|
fLinesIndexBuffer->unref();
|
||||||
|
fQuadsIndexBuffer->unref();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GrAAHairLinePathRenderer::supportsAA(GrDrawTarget* target,
|
||||||
|
const SkPath& path,
|
||||||
|
GrPathFill fill) {
|
||||||
|
return kHairLine_PathFill == fill;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GrAAHairLinePathRenderer::canDrawPath(const GrDrawTarget* target,
|
||||||
|
const SkPath& path,
|
||||||
|
GrPathFill fill) const {
|
||||||
|
// TODO: support perspective
|
||||||
|
return kHairLine_PathFill == fill &&
|
||||||
|
!target->getViewMatrix().hasPerspective();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GrAAHairLinePathRenderer::pathWillClear() {
|
||||||
|
this->resetGeom();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GrAAHairLinePathRenderer::resetGeom() {
|
||||||
|
fPreviousStages = ~0;
|
||||||
|
fPreviousRTHeight = ~0;
|
||||||
|
fPreviousViewMatrix = GrMatrix::InvalidMatrix();
|
||||||
|
fLineSegmentCnt = 0;
|
||||||
|
fQuadCnt = 0;
|
||||||
|
if ((fQuadCnt || fLineSegmentCnt) && NULL != fTarget) {
|
||||||
|
fTarget->resetVertexSource();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
typedef GrTArray<SkPoint, true> PtArray;
|
||||||
|
typedef GrTArray<int, true> IntArray;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We convert cubics to quadratics (for now).
|
||||||
|
*/
|
||||||
|
void convert_noninflect_cubic_to_quads(const SkPoint p[4],
|
||||||
|
PtArray* quads,
|
||||||
|
int sublevel = 0) {
|
||||||
|
SkVector ab = p[1];
|
||||||
|
ab -= p[0];
|
||||||
|
SkVector dc = p[2];
|
||||||
|
dc -= p[3];
|
||||||
|
|
||||||
|
static const SkScalar gLengthScale = 3 * SK_Scalar1 / 2;
|
||||||
|
static const SkScalar gDistanceSqdTol = 2 * SK_Scalar1;
|
||||||
|
static const int kMaxSubdivs = 30;
|
||||||
|
|
||||||
|
ab.scale(gLengthScale);
|
||||||
|
dc.scale(gLengthScale);
|
||||||
|
|
||||||
|
SkVector c0 = p[0];
|
||||||
|
c0 += ab;
|
||||||
|
SkVector c1 = p[3];
|
||||||
|
c1 += dc;
|
||||||
|
|
||||||
|
SkScalar dSqd = c0.distanceToSqd(c1);
|
||||||
|
if (sublevel > kMaxSubdivs || dSqd <= gDistanceSqdTol) {
|
||||||
|
SkPoint cAvg = c0;
|
||||||
|
cAvg += c1;
|
||||||
|
cAvg.scale(SK_ScalarHalf);
|
||||||
|
|
||||||
|
int idx = quads->count();
|
||||||
|
quads->push_back_n(3);
|
||||||
|
(*quads)[idx+0] = p[0];
|
||||||
|
(*quads)[idx+1] = cAvg;
|
||||||
|
(*quads)[idx+2] = p[3];
|
||||||
|
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
SkPoint choppedPts[7];
|
||||||
|
SkChopCubicAtHalf(p, choppedPts);
|
||||||
|
convert_noninflect_cubic_to_quads(choppedPts + 0, quads, sublevel + 1);
|
||||||
|
convert_noninflect_cubic_to_quads(choppedPts + 3, quads, sublevel + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void convert_cubic_to_quads(const SkPoint p[4], PtArray* quads) {
|
||||||
|
SkPoint chopped[13];
|
||||||
|
int count = SkChopCubicAtInflections(p, chopped);
|
||||||
|
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
SkPoint* cubic = chopped + 3*i;
|
||||||
|
convert_noninflect_cubic_to_quads(cubic, quads);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Takes 178th time of logf on Z600 / VC2010
|
||||||
|
int get_float_exp(float x) {
|
||||||
|
GR_STATIC_ASSERT(sizeof(int) == sizeof(float));
|
||||||
|
#if GR_DEBUG
|
||||||
|
static bool tested;
|
||||||
|
if (!tested) {
|
||||||
|
tested = true;
|
||||||
|
GrAssert(get_float_exp(0.25f) == -2);
|
||||||
|
GrAssert(get_float_exp(0.3f) == -2);
|
||||||
|
GrAssert(get_float_exp(0.5f) == -1);
|
||||||
|
GrAssert(get_float_exp(1.f) == 0);
|
||||||
|
GrAssert(get_float_exp(2.f) == 1);
|
||||||
|
GrAssert(get_float_exp(2.5f) == 1);
|
||||||
|
GrAssert(get_float_exp(8.f) == 3);
|
||||||
|
GrAssert(get_float_exp(100.f) == 6);
|
||||||
|
GrAssert(get_float_exp(1000.f) == 9);
|
||||||
|
GrAssert(get_float_exp(1024.f) == 10);
|
||||||
|
GrAssert(get_float_exp(3000000.f) == 21);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return (((*(int*)&x) & 0x7f800000) >> 23) - 127;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we subdivide the quads to avoid huge overfill
|
||||||
|
// if it returns -1 then should be drawn as lines
|
||||||
|
int num_quad_subdivs(const SkPoint p[3]) {
|
||||||
|
static const SkScalar gDegenerateToLineTol = SK_Scalar1;
|
||||||
|
|
||||||
|
GrScalar dsqd = p[1].distanceToLineBetweenSqd(p[0], p[2]);
|
||||||
|
if (dsqd < gDegenerateToLineTol*gDegenerateToLineTol) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (p[2].distanceToLineBetweenSqd(p[1],p[0]) <
|
||||||
|
gDegenerateToLineTol*gDegenerateToLineTol) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const int kMaxSub = 4;
|
||||||
|
// tolerance of triangle height in pixels
|
||||||
|
// tuned on windows Quadro FX 380 / Z600
|
||||||
|
// trade off of fill vs cpu time on verts
|
||||||
|
// maybe different when do this using gpu (geo or tess shaders)
|
||||||
|
static const SkScalar gSubdivTol = 175 * SK_Scalar1;
|
||||||
|
|
||||||
|
if (dsqd <= gSubdivTol*gSubdivTol) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
// subdividing the quad reduces d by 4. so we want x = log4(d/tol)
|
||||||
|
// = log4(d*d/tol*tol)/2
|
||||||
|
// = log2(d*d/tol*tol)
|
||||||
|
|
||||||
|
#ifdef SK_SCALAR_IS_FLOAT
|
||||||
|
// +1 since we're ignoring the mantissa contribution.
|
||||||
|
int log = get_float_exp(dsqd/(gSubdivTol*gSubdivTol)) + 1;
|
||||||
|
log = GrMin(GrMax(0, log), kMaxSub);
|
||||||
|
return log;
|
||||||
|
#else
|
||||||
|
SkScalar log = SkScalarLog(SkScalarDiv(dsqd,kTol*kTol));
|
||||||
|
static const SkScalar conv = SkScalarInvert(SkScalarLog(2));
|
||||||
|
log = SkScalarMul(log, conv);
|
||||||
|
return GrMin(GrMax(0, SkScalarCeilToInt(log)),kMaxSub);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_lines_and_quads(const SkPath& path, const SkMatrix& m, GrIRect clip,
|
||||||
|
PtArray* lines, PtArray* quads,
|
||||||
|
IntArray* quadSubdivCnts) {
|
||||||
|
SkPath::Iter iter(path, false);
|
||||||
|
|
||||||
|
int totalQuadCount = 0;
|
||||||
|
GrRect bounds;
|
||||||
|
GrIRect ibounds;
|
||||||
|
for (;;) {
|
||||||
|
GrPoint pts[4];
|
||||||
|
GrPathCmd cmd = (GrPathCmd)iter.next(pts);
|
||||||
|
switch (cmd) {
|
||||||
|
case kMove_PathCmd:
|
||||||
|
break;
|
||||||
|
case kLine_PathCmd:
|
||||||
|
m.mapPoints(pts,2);
|
||||||
|
bounds.setBounds(pts, 2);
|
||||||
|
bounds.outset(SK_Scalar1, SK_Scalar1);
|
||||||
|
bounds.roundOut(&ibounds);
|
||||||
|
if (SkIRect::Intersects(clip, ibounds)) {
|
||||||
|
lines->push_back() = pts[0];
|
||||||
|
lines->push_back() = pts[1];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case kQuadratic_PathCmd: {
|
||||||
|
bounds.setBounds(pts, 3);
|
||||||
|
bounds.outset(SK_Scalar1, SK_Scalar1);
|
||||||
|
bounds.roundOut(&ibounds);
|
||||||
|
if (SkIRect::Intersects(clip, ibounds)) {
|
||||||
|
m.mapPoints(pts, 3);
|
||||||
|
int subdiv = num_quad_subdivs(pts);
|
||||||
|
GrAssert(subdiv >= -1);
|
||||||
|
if (-1 == subdiv) {
|
||||||
|
lines->push_back() = pts[0];
|
||||||
|
lines->push_back() = pts[1];
|
||||||
|
lines->push_back() = pts[1];
|
||||||
|
lines->push_back() = pts[2];
|
||||||
|
} else {
|
||||||
|
quads->push_back() = pts[0];
|
||||||
|
quads->push_back() = pts[1];
|
||||||
|
quads->push_back() = pts[2];
|
||||||
|
quadSubdivCnts->push_back() = subdiv;
|
||||||
|
totalQuadCount += 1 << subdiv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case kCubic_PathCmd: {
|
||||||
|
bounds.setBounds(pts, 4);
|
||||||
|
bounds.outset(SK_Scalar1, SK_Scalar1);
|
||||||
|
bounds.roundOut(&ibounds);
|
||||||
|
if (SkIRect::Intersects(clip, ibounds)) {
|
||||||
|
m.mapPoints(pts, 4);
|
||||||
|
SkPoint stackStorage[32];
|
||||||
|
PtArray q((void*)stackStorage, 32);
|
||||||
|
convert_cubic_to_quads(pts, &q);
|
||||||
|
for (int i = 0; i < q.count(); i += 3) {
|
||||||
|
bounds.setBounds(&q[i], 3);
|
||||||
|
bounds.outset(SK_Scalar1, SK_Scalar1);
|
||||||
|
bounds.roundOut(&ibounds);
|
||||||
|
if (SkIRect::Intersects(clip, ibounds)) {
|
||||||
|
int subdiv = num_quad_subdivs(&q[i]);
|
||||||
|
GrAssert(subdiv >= -1);
|
||||||
|
if (-1 == subdiv) {
|
||||||
|
lines->push_back() = q[0 + i];
|
||||||
|
lines->push_back() = q[1 + i];
|
||||||
|
lines->push_back() = q[1 + i];
|
||||||
|
lines->push_back() = q[2 + i];
|
||||||
|
} else {
|
||||||
|
quads->push_back() = q[0 + i];
|
||||||
|
quads->push_back() = q[1 + i];
|
||||||
|
quads->push_back() = q[2 + i];
|
||||||
|
quadSubdivCnts->push_back() = subdiv;
|
||||||
|
totalQuadCount += 1 << subdiv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case kClose_PathCmd:
|
||||||
|
break;
|
||||||
|
case kEnd_PathCmd:
|
||||||
|
return totalQuadCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Vertex {
|
||||||
|
GrPoint fPos;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
GrScalar fA;
|
||||||
|
GrScalar fB;
|
||||||
|
GrScalar fC;
|
||||||
|
} fLine;
|
||||||
|
GrVec fQuadCoord;
|
||||||
|
struct {
|
||||||
|
GrScalar fBogus[4];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
GR_STATIC_ASSERT(sizeof(Vertex) == 3 * sizeof(GrPoint));
|
||||||
|
|
||||||
|
void intersect_lines(const SkPoint& ptA, const SkVector& normA,
|
||||||
|
const SkPoint& ptB, const SkVector& normB,
|
||||||
|
SkPoint* result) {
|
||||||
|
|
||||||
|
SkScalar lineAW = -normA.dot(ptA);
|
||||||
|
SkScalar lineBW = -normB.dot(ptB);
|
||||||
|
|
||||||
|
SkScalar wInv = SkScalarMul(normA.fX, normB.fY) -
|
||||||
|
SkScalarMul(normA.fY, normB.fX);
|
||||||
|
wInv = SkScalarInvert(wInv);
|
||||||
|
|
||||||
|
result->fX = SkScalarMul(normA.fY, lineBW) - SkScalarMul(lineAW, normB.fY);
|
||||||
|
result->fX = SkScalarMul(result->fX, wInv);
|
||||||
|
|
||||||
|
result->fY = SkScalarMul(lineAW, normB.fX) - SkScalarMul(normA.fX, lineBW);
|
||||||
|
result->fY = SkScalarMul(result->fY, wInv);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bloat_quad(const SkPoint qpts[3], Vertex verts[kVertsPerQuad]) {
|
||||||
|
// original quad is specified by tri a,b,c
|
||||||
|
const SkPoint& a = qpts[0];
|
||||||
|
const SkPoint& b = qpts[1];
|
||||||
|
const SkPoint& c = qpts[2];
|
||||||
|
// make a new poly where we replace a and c by a 1-pixel wide edges orthog
|
||||||
|
// to edges ab and bc:
|
||||||
|
//
|
||||||
|
// before | after
|
||||||
|
// | b0
|
||||||
|
// b |
|
||||||
|
// |
|
||||||
|
// | a0 c0
|
||||||
|
// a c | a1 c1
|
||||||
|
//
|
||||||
|
// edges a0->b0 and b0->c0 are parallel to original edges a->b and b->c,
|
||||||
|
// respectively.
|
||||||
|
Vertex& a0 = verts[0];
|
||||||
|
Vertex& a1 = verts[1];
|
||||||
|
Vertex& b0 = verts[2];
|
||||||
|
Vertex& c0 = verts[3];
|
||||||
|
Vertex& c1 = verts[4];
|
||||||
|
|
||||||
|
// compute a matrix that goes from device coords to U,V quad params
|
||||||
|
SkMatrix DevToUV;
|
||||||
|
DevToUV.setAll(a.fX, b.fX, c.fX,
|
||||||
|
a.fY, b.fY, c.fY,
|
||||||
|
SK_Scalar1, SK_Scalar1, SK_Scalar1);
|
||||||
|
DevToUV.invert(&DevToUV);
|
||||||
|
// can't make this static, no cons :(
|
||||||
|
SkMatrix UVpts;
|
||||||
|
UVpts.setAll(0, SK_ScalarHalf, SK_Scalar1,
|
||||||
|
0, 0, SK_Scalar1,
|
||||||
|
SK_Scalar1, SK_Scalar1, SK_Scalar1);
|
||||||
|
DevToUV.postConcat(UVpts);
|
||||||
|
|
||||||
|
// We really want to avoid perspective matrix muls.
|
||||||
|
// These may wind up really close to zero
|
||||||
|
DevToUV.setPerspX(0);
|
||||||
|
DevToUV.setPerspY(0);
|
||||||
|
|
||||||
|
SkVector ab = b;
|
||||||
|
ab -= a;
|
||||||
|
SkVector ac = c;
|
||||||
|
ac -= a;
|
||||||
|
SkVector cb = b;
|
||||||
|
cb -= c;
|
||||||
|
|
||||||
|
// We should have already handled degenerates
|
||||||
|
GrAssert(ab.length() > 0 && cb.length() > 0);
|
||||||
|
|
||||||
|
ab.normalize();
|
||||||
|
SkVector abN;
|
||||||
|
abN.setOrthog(ab, SkVector::kLeft_Side);
|
||||||
|
if (abN.dot(ac) > 0) {
|
||||||
|
abN.negate();
|
||||||
|
}
|
||||||
|
|
||||||
|
cb.normalize();
|
||||||
|
SkVector cbN;
|
||||||
|
cbN.setOrthog(cb, SkVector::kLeft_Side);
|
||||||
|
if (cbN.dot(ac) < 0) {
|
||||||
|
cbN.negate();
|
||||||
|
}
|
||||||
|
|
||||||
|
a0.fPos = a;
|
||||||
|
a0.fPos += abN;
|
||||||
|
a1.fPos = a;
|
||||||
|
a1.fPos -= abN;
|
||||||
|
|
||||||
|
c0.fPos = c;
|
||||||
|
c0.fPos += cbN;
|
||||||
|
c1.fPos = c;
|
||||||
|
c1.fPos -= cbN;
|
||||||
|
|
||||||
|
intersect_lines(a0.fPos, abN, c0.fPos, cbN, &b0.fPos);
|
||||||
|
|
||||||
|
DevToUV.mapPointsWithStride(&verts[0].fQuadCoord,
|
||||||
|
&verts[0].fPos, sizeof(Vertex), kVertsPerQuad);
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_quads(const SkPoint p[3],
|
||||||
|
int subdiv,
|
||||||
|
Vertex** vert) {
|
||||||
|
GrAssert(subdiv >= 0);
|
||||||
|
if (subdiv) {
|
||||||
|
SkPoint newP[5];
|
||||||
|
SkChopQuadAtHalf(p, newP);
|
||||||
|
add_quads(newP + 0, subdiv-1, vert);
|
||||||
|
add_quads(newP + 2, subdiv-1, vert);
|
||||||
|
} else {
|
||||||
|
bloat_quad(p, *vert);
|
||||||
|
*vert += kVertsPerQuad;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_line(const SkPoint p[2],
|
||||||
|
int rtHeight,
|
||||||
|
Vertex** vert) {
|
||||||
|
const SkPoint& a = p[0];
|
||||||
|
const SkPoint& b = p[1];
|
||||||
|
|
||||||
|
SkVector orthVec = b;
|
||||||
|
orthVec -= a;
|
||||||
|
|
||||||
|
if (orthVec.setLength(SK_Scalar1)) {
|
||||||
|
orthVec.setOrthog(orthVec);
|
||||||
|
|
||||||
|
// the values we pass down to the frag shader
|
||||||
|
// have to be in y-points-up space;
|
||||||
|
SkVector normal;
|
||||||
|
normal.fX = orthVec.fX;
|
||||||
|
normal.fY = -orthVec.fY;
|
||||||
|
SkPoint aYDown;
|
||||||
|
aYDown.fX = a.fX;
|
||||||
|
aYDown.fY = rtHeight - a.fY;
|
||||||
|
|
||||||
|
SkScalar lineC = -(aYDown.dot(normal));
|
||||||
|
for (int i = 0; i < kVertsPerLineSeg; ++i) {
|
||||||
|
(*vert)[i].fPos = (i < 2) ? a : b;
|
||||||
|
if (0 == i || 3 == i) {
|
||||||
|
(*vert)[i].fPos -= orthVec;
|
||||||
|
} else {
|
||||||
|
(*vert)[i].fPos += orthVec;
|
||||||
|
}
|
||||||
|
(*vert)[i].fLine.fA = normal.fX;
|
||||||
|
(*vert)[i].fLine.fB = normal.fY;
|
||||||
|
(*vert)[i].fLine.fC = lineC;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// just make it degenerate and likely offscreen
|
||||||
|
(*vert)[0].fPos.set(SK_ScalarMax, SK_ScalarMax);
|
||||||
|
(*vert)[1].fPos.set(SK_ScalarMax, SK_ScalarMax);
|
||||||
|
(*vert)[2].fPos.set(SK_ScalarMax, SK_ScalarMax);
|
||||||
|
(*vert)[3].fPos.set(SK_ScalarMax, SK_ScalarMax);
|
||||||
|
}
|
||||||
|
|
||||||
|
*vert += kVertsPerLineSeg;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GrAAHairLinePathRenderer::createGeom(GrDrawTarget::StageBitfield stages) {
|
||||||
|
|
||||||
|
int rtHeight = fTarget->getRenderTarget()->height();
|
||||||
|
|
||||||
|
GrIRect clip;
|
||||||
|
if (fTarget->getClip().hasConservativeBounds()) {
|
||||||
|
GrRect clipRect = fTarget->getClip().getConservativeBounds();
|
||||||
|
clipRect.roundOut(&clip);
|
||||||
|
} else {
|
||||||
|
clip.setLargest();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stages == fPreviousStages &&
|
||||||
|
fPreviousViewMatrix == fTarget->getViewMatrix() &&
|
||||||
|
rtHeight == fPreviousRTHeight &&
|
||||||
|
fClipRect == clip) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
GrVertexLayout layout = GrDrawTarget::kEdge_VertexLayoutBit;
|
||||||
|
for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
|
||||||
|
if ((1 << s) & stages) {
|
||||||
|
layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GrMatrix viewM = fTarget->getViewMatrix();
|
||||||
|
viewM.preTranslate(fTranslate.fX, fTranslate.fY);
|
||||||
|
|
||||||
|
GrAlignedSTStorage<128, GrPoint> lineStorage;
|
||||||
|
GrAlignedSTStorage<128, GrPoint> quadStorage;
|
||||||
|
PtArray lines(&lineStorage);
|
||||||
|
PtArray quads(&quadStorage);
|
||||||
|
IntArray qSubdivs;
|
||||||
|
fQuadCnt = get_lines_and_quads(*fPath, viewM, clip,
|
||||||
|
&lines, &quads, &qSubdivs);
|
||||||
|
|
||||||
|
fLineSegmentCnt = lines.count() / 2;
|
||||||
|
int vertCnt = kVertsPerLineSeg * fLineSegmentCnt + kVertsPerQuad * fQuadCnt;
|
||||||
|
|
||||||
|
GrAssert(sizeof(Vertex) == GrDrawTarget::VertexSize(layout));
|
||||||
|
|
||||||
|
Vertex* verts;
|
||||||
|
if (!fTarget->reserveVertexSpace(layout, vertCnt, (void**)&verts)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < fLineSegmentCnt; ++i) {
|
||||||
|
add_line(&lines[2*i], rtHeight, &verts);
|
||||||
|
}
|
||||||
|
int unsubdivQuadCnt = quads.count() / 3;
|
||||||
|
for (int i = 0; i < unsubdivQuadCnt; ++i) {
|
||||||
|
GrAssert(qSubdivs[i] >= 0);
|
||||||
|
add_quads(&quads[3*i], qSubdivs[i], &verts);
|
||||||
|
}
|
||||||
|
|
||||||
|
fPreviousStages = stages;
|
||||||
|
fPreviousViewMatrix = fTarget->getViewMatrix();
|
||||||
|
fPreviousRTHeight = rtHeight;
|
||||||
|
fClipRect = clip;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GrAAHairLinePathRenderer::drawPath(GrDrawTarget::StageBitfield stages) {
|
||||||
|
GrDrawTarget::AutoStateRestore asr(fTarget);
|
||||||
|
|
||||||
|
GrMatrix ivm;
|
||||||
|
|
||||||
|
if (!this->createGeom(stages)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fTarget->getViewInverse(&ivm)) {
|
||||||
|
fTarget->preConcatSamplerMatrices(stages, ivm);
|
||||||
|
}
|
||||||
|
|
||||||
|
fTarget->setViewMatrix(GrMatrix::I());
|
||||||
|
|
||||||
|
// TODO: See whether rendering lines as degenerate quads improves perf
|
||||||
|
// when we have a mix
|
||||||
|
fTarget->setIndexSourceToBuffer(fLinesIndexBuffer);
|
||||||
|
int lines = 0;
|
||||||
|
int nBufLines = fLinesIndexBuffer->maxQuads();
|
||||||
|
while (lines < fLineSegmentCnt) {
|
||||||
|
int n = GrMin(fLineSegmentCnt-lines, nBufLines);
|
||||||
|
fTarget->setVertexEdgeType(GrDrawTarget::kHairLine_EdgeType);
|
||||||
|
fTarget->drawIndexed(kTriangles_PrimitiveType,
|
||||||
|
kVertsPerLineSeg*lines, // startV
|
||||||
|
0, // startI
|
||||||
|
kVertsPerLineSeg*n, // vCount
|
||||||
|
kIdxsPerLineSeg*n); // iCount
|
||||||
|
lines += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
fTarget->setIndexSourceToBuffer(fQuadsIndexBuffer);
|
||||||
|
int quads = 0;
|
||||||
|
while (quads < fQuadCnt) {
|
||||||
|
int n = GrMin(fQuadCnt-quads, kNumQuadsInIdxBuffer);
|
||||||
|
fTarget->setVertexEdgeType(GrDrawTarget::kHairQuad_EdgeType);
|
||||||
|
fTarget->drawIndexed(kTriangles_PrimitiveType,
|
||||||
|
4*fLineSegmentCnt + kVertsPerQuad*quads, // startV
|
||||||
|
0, // startI
|
||||||
|
kVertsPerQuad*n, // vCount
|
||||||
|
kIdxsPerQuad*n); // iCount
|
||||||
|
quads += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2011 Google Inc.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GrAAHairLinePathRenderer_DEFINED
|
||||||
|
#define GrAAHairLinePathRenderer_DEFINED
|
||||||
|
|
||||||
|
#include "GrPathRenderer.h"
|
||||||
|
|
||||||
|
class GrAAHairLinePathRenderer : public GrPathRenderer {
|
||||||
|
public:
|
||||||
|
virtual ~GrAAHairLinePathRenderer();
|
||||||
|
|
||||||
|
static GrPathRenderer* Create(GrContext* context);
|
||||||
|
// GrPathRenderer overrides
|
||||||
|
virtual bool supportsAA(GrDrawTarget* target,
|
||||||
|
const SkPath& path,
|
||||||
|
GrPathFill fill);
|
||||||
|
virtual bool canDrawPath(const GrDrawTarget* target,
|
||||||
|
const SkPath& path,
|
||||||
|
GrPathFill fill) const;
|
||||||
|
virtual void drawPath(GrDrawTarget::StageBitfield stages);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
// GrPathRenderer overrides
|
||||||
|
virtual void pathWillClear();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void resetGeom();
|
||||||
|
|
||||||
|
static bool CanBeUsed(const GrContext* context);
|
||||||
|
GrAAHairLinePathRenderer(const GrContext* context,
|
||||||
|
const GrIndexBuffer* fLinesIndexBuffer,
|
||||||
|
const GrIndexBuffer* fQuadsIndexBuffer);
|
||||||
|
|
||||||
|
bool createGeom(GrDrawTarget::StageBitfield stages);
|
||||||
|
|
||||||
|
GrContext* fContext;
|
||||||
|
const GrIndexBuffer* fLinesIndexBuffer;
|
||||||
|
const GrIndexBuffer* fQuadsIndexBuffer;
|
||||||
|
|
||||||
|
// have to recreate geometry if stages in use changes :(
|
||||||
|
GrDrawTarget::StageBitfield fPreviousStages;
|
||||||
|
int fPreviousRTHeight;
|
||||||
|
GrIRect fClipRect;
|
||||||
|
|
||||||
|
// this path renderer draws everything in device coordinates
|
||||||
|
GrMatrix fPreviousViewMatrix;
|
||||||
|
int fLineSegmentCnt;
|
||||||
|
int fQuadCnt;
|
||||||
|
|
||||||
|
typedef GrPathRenderer INHERITED;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2011 Google Inc.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "GrAAHairLinePathRenderer.h"
|
||||||
|
|
||||||
|
void GrPathRenderer::AddPathRenderers(GrContext* ctx,
|
||||||
|
GrPathRendererChain::UsageFlags flags,
|
||||||
|
GrPathRendererChain* chain) {
|
||||||
|
if (!(GrPathRendererChain::kNonAAOnly_UsageFlag & flags)) {
|
||||||
|
if (GrPathRenderer* pr = GrAAHairLinePathRenderer::Create(ctx)) {
|
||||||
|
chain->addPathRenderer(pr)->unref();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1378,9 +1378,12 @@ void GrContext::drawVertices(const GrPaint& paint,
|
||||||
}
|
}
|
||||||
int texOffsets[GrDrawTarget::kMaxTexCoords];
|
int texOffsets[GrDrawTarget::kMaxTexCoords];
|
||||||
int colorOffset;
|
int colorOffset;
|
||||||
|
int edgeOffset;
|
||||||
GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
|
GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
|
||||||
texOffsets,
|
texOffsets,
|
||||||
&colorOffset);
|
&colorOffset,
|
||||||
|
&edgeOffset);
|
||||||
|
GrAssert(-1 == edgeOffset);
|
||||||
void* curVertex = geo.vertices();
|
void* curVertex = geo.vertices();
|
||||||
|
|
||||||
for (int i = 0; i < vertexCount; ++i) {
|
for (int i = 0; i < vertexCount; ++i) {
|
||||||
|
|
|
@ -20,7 +20,8 @@ public:
|
||||||
GrDefaultPathRenderer(bool separateStencilSupport,
|
GrDefaultPathRenderer(bool separateStencilSupport,
|
||||||
bool stencilWrapOpsSupport);
|
bool stencilWrapOpsSupport);
|
||||||
|
|
||||||
virtual bool canDrawPath(const SkPath& path,
|
virtual bool canDrawPath(const GrDrawTarget* target,
|
||||||
|
const SkPath& path,
|
||||||
GrPathFill fill) const { return true; }
|
GrPathFill fill) const { return true; }
|
||||||
|
|
||||||
virtual bool requiresStencilPass(const GrDrawTarget* target,
|
virtual bool requiresStencilPass(const GrDrawTarget* target,
|
||||||
|
|
|
@ -63,6 +63,17 @@ bool check_layout(GrVertexLayout layout) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int num_tex_coords(GrVertexLayout layout) {
|
||||||
|
int cnt = 0;
|
||||||
|
// figure out how many tex coordinates are present
|
||||||
|
for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
|
||||||
|
if (tex_coord_idx_mask(t) & layout) {
|
||||||
|
++cnt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
} //unnamed namespace
|
} //unnamed namespace
|
||||||
|
|
||||||
size_t GrDrawTarget::VertexSize(GrVertexLayout vertexLayout) {
|
size_t GrDrawTarget::VertexSize(GrVertexLayout vertexLayout) {
|
||||||
|
@ -73,14 +84,13 @@ size_t GrDrawTarget::VertexSize(GrVertexLayout vertexLayout) {
|
||||||
sizeof(GrPoint);
|
sizeof(GrPoint);
|
||||||
|
|
||||||
size_t size = vecSize; // position
|
size_t size = vecSize; // position
|
||||||
for (int t = 0; t < kMaxTexCoords; ++t) {
|
size += num_tex_coords(vertexLayout) * vecSize;
|
||||||
if (tex_coord_idx_mask(t) & vertexLayout) {
|
|
||||||
size += vecSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (vertexLayout & kColor_VertexLayoutBit) {
|
if (vertexLayout & kColor_VertexLayoutBit) {
|
||||||
size += sizeof(GrColor);
|
size += sizeof(GrColor);
|
||||||
}
|
}
|
||||||
|
if (vertexLayout & kEdge_VertexLayoutBit) {
|
||||||
|
size += 4 * sizeof(GrScalar);
|
||||||
|
}
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,16 +121,27 @@ int GrDrawTarget::VertexStageCoordOffset(int stage, GrVertexLayout vertexLayout)
|
||||||
int GrDrawTarget::VertexColorOffset(GrVertexLayout vertexLayout) {
|
int GrDrawTarget::VertexColorOffset(GrVertexLayout vertexLayout) {
|
||||||
GrAssert(check_layout(vertexLayout));
|
GrAssert(check_layout(vertexLayout));
|
||||||
|
|
||||||
|
// color is after the pos and tex coords
|
||||||
if (vertexLayout & kColor_VertexLayoutBit) {
|
if (vertexLayout & kColor_VertexLayoutBit) {
|
||||||
int vecSize = (vertexLayout & kTextFormat_VertexLayoutBit) ?
|
int vecSize = (vertexLayout & kTextFormat_VertexLayoutBit) ?
|
||||||
sizeof(GrGpuTextVertex) :
|
sizeof(GrGpuTextVertex) :
|
||||||
sizeof(GrPoint);
|
sizeof(GrPoint);
|
||||||
int offset = vecSize; // position
|
return vecSize * (num_tex_coords(vertexLayout) + 1); //+1 for pos
|
||||||
// figure out how many tex coordinates are present and precede this one.
|
|
||||||
for (int t = 0; t < kMaxTexCoords; ++t) {
|
|
||||||
if (tex_coord_idx_mask(t) & vertexLayout) {
|
|
||||||
offset += vecSize;
|
|
||||||
}
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GrDrawTarget::VertexEdgeOffset(GrVertexLayout vertexLayout) {
|
||||||
|
GrAssert(check_layout(vertexLayout));
|
||||||
|
|
||||||
|
// edge pts are after the pos, tex coords, and color
|
||||||
|
if (vertexLayout & kEdge_VertexLayoutBit) {
|
||||||
|
int vecSize = (vertexLayout & kTextFormat_VertexLayoutBit) ?
|
||||||
|
sizeof(GrGpuTextVertex) :
|
||||||
|
sizeof(GrPoint);
|
||||||
|
int offset = vecSize * (num_tex_coords(vertexLayout) + 1); //+1 for pos
|
||||||
|
if (vertexLayout & kColor_VertexLayoutBit) {
|
||||||
|
offset += sizeof(GrColor);
|
||||||
}
|
}
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
@ -129,11 +150,13 @@ int GrDrawTarget::VertexColorOffset(GrVertexLayout vertexLayout) {
|
||||||
|
|
||||||
int GrDrawTarget::VertexSizeAndOffsetsByIdx(GrVertexLayout vertexLayout,
|
int GrDrawTarget::VertexSizeAndOffsetsByIdx(GrVertexLayout vertexLayout,
|
||||||
int texCoordOffsetsByIdx[kMaxTexCoords],
|
int texCoordOffsetsByIdx[kMaxTexCoords],
|
||||||
int* colorOffset) {
|
int* colorOffset,
|
||||||
|
int* edgeOffset) {
|
||||||
GrAssert(check_layout(vertexLayout));
|
GrAssert(check_layout(vertexLayout));
|
||||||
|
|
||||||
GrAssert(NULL != texCoordOffsetsByIdx);
|
GrAssert(NULL != texCoordOffsetsByIdx);
|
||||||
GrAssert(NULL != colorOffset);
|
GrAssert(NULL != colorOffset);
|
||||||
|
GrAssert(NULL != edgeOffset);
|
||||||
|
|
||||||
int vecSize = (vertexLayout & kTextFormat_VertexLayoutBit) ?
|
int vecSize = (vertexLayout & kTextFormat_VertexLayoutBit) ?
|
||||||
sizeof(GrGpuTextVertex) :
|
sizeof(GrGpuTextVertex) :
|
||||||
|
@ -154,21 +177,30 @@ int GrDrawTarget::VertexSizeAndOffsetsByIdx(GrVertexLayout vertexLayout,
|
||||||
} else {
|
} else {
|
||||||
*colorOffset = -1;
|
*colorOffset = -1;
|
||||||
}
|
}
|
||||||
|
if (kEdge_VertexLayoutBit & vertexLayout) {
|
||||||
|
*edgeOffset = size;
|
||||||
|
size += 4 * sizeof(GrScalar);
|
||||||
|
} else {
|
||||||
|
*edgeOffset = -1;
|
||||||
|
}
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GrDrawTarget::VertexSizeAndOffsetsByStage(GrVertexLayout vertexLayout,
|
int GrDrawTarget::VertexSizeAndOffsetsByStage(GrVertexLayout vertexLayout,
|
||||||
int texCoordOffsetsByStage[kNumStages],
|
int texCoordOffsetsByStage[kNumStages],
|
||||||
int* colorOffset) {
|
int* colorOffset,
|
||||||
|
int* edgeOffset) {
|
||||||
GrAssert(check_layout(vertexLayout));
|
GrAssert(check_layout(vertexLayout));
|
||||||
|
|
||||||
GrAssert(NULL != texCoordOffsetsByStage);
|
GrAssert(NULL != texCoordOffsetsByStage);
|
||||||
GrAssert(NULL != colorOffset);
|
GrAssert(NULL != colorOffset);
|
||||||
|
GrAssert(NULL != edgeOffset);
|
||||||
|
|
||||||
int texCoordOffsetsByIdx[kMaxTexCoords];
|
int texCoordOffsetsByIdx[kMaxTexCoords];
|
||||||
int size = VertexSizeAndOffsetsByIdx(vertexLayout,
|
int size = VertexSizeAndOffsetsByIdx(vertexLayout,
|
||||||
texCoordOffsetsByIdx,
|
texCoordOffsetsByIdx,
|
||||||
colorOffset);
|
colorOffset,
|
||||||
|
edgeOffset);
|
||||||
for (int s = 0; s < kNumStages; ++s) {
|
for (int s = 0; s < kNumStages; ++s) {
|
||||||
int tcIdx;
|
int tcIdx;
|
||||||
if (StagePosAsTexCoordVertexLayoutBit(s) & vertexLayout) {
|
if (StagePosAsTexCoordVertexLayoutBit(s) & vertexLayout) {
|
||||||
|
@ -250,22 +282,39 @@ void GrDrawTarget::VertexLayoutUnitTest() {
|
||||||
GrAssert(VertexUsesStage(s2, posAsTex));
|
GrAssert(VertexUsesStage(s2, posAsTex));
|
||||||
GrAssert(2*sizeof(GrPoint) == VertexSize(posAsTex));
|
GrAssert(2*sizeof(GrPoint) == VertexSize(posAsTex));
|
||||||
GrAssert(-1 == VertexTexCoordsForStage(s2, posAsTex));
|
GrAssert(-1 == VertexTexCoordsForStage(s2, posAsTex));
|
||||||
|
GrAssert(-1 == VertexEdgeOffset(posAsTex));
|
||||||
}
|
}
|
||||||
|
GrAssert(-1 == VertexEdgeOffset(tcMask));
|
||||||
|
GrAssert(-1 == VertexColorOffset(tcMask));
|
||||||
#if GR_DEBUG
|
#if GR_DEBUG
|
||||||
GrVertexLayout withColor = tcMask | kColor_VertexLayoutBit;
|
GrVertexLayout withColor = tcMask | kColor_VertexLayoutBit;
|
||||||
#endif
|
#endif
|
||||||
GrAssert(2*sizeof(GrPoint) == VertexColorOffset(withColor));
|
GrAssert(2*sizeof(GrPoint) == VertexColorOffset(withColor));
|
||||||
GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexSize(withColor));
|
GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexSize(withColor));
|
||||||
|
#if GR_DEBUG
|
||||||
|
GrVertexLayout withEdge = tcMask | kEdge_VertexLayoutBit;
|
||||||
|
#endif
|
||||||
|
GrAssert(-1 == VertexColorOffset(withEdge));
|
||||||
|
GrAssert(2*sizeof(GrPoint) == VertexEdgeOffset(withEdge));
|
||||||
|
GrAssert(4*sizeof(GrPoint) == VertexSize(withEdge));
|
||||||
|
#if GR_DEBUG
|
||||||
|
GrVertexLayout withColorAndEdge = withColor | kEdge_VertexLayoutBit;
|
||||||
|
#endif
|
||||||
|
GrAssert(2*sizeof(GrPoint) == VertexColorOffset(withColorAndEdge));
|
||||||
|
GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexEdgeOffset(withColorAndEdge));
|
||||||
|
GrAssert(4*sizeof(GrPoint) + sizeof(GrColor) == VertexSize(withColorAndEdge));
|
||||||
}
|
}
|
||||||
GrAssert(tex_coord_idx_mask(t) == tcMask);
|
GrAssert(tex_coord_idx_mask(t) == tcMask);
|
||||||
GrAssert(check_layout(tcMask));
|
GrAssert(check_layout(tcMask));
|
||||||
|
|
||||||
int stageOffsets[kNumStages];
|
int stageOffsets[kNumStages];
|
||||||
int colorOffset;
|
int colorOffset;
|
||||||
|
int edgeOffset;
|
||||||
int size;
|
int size;
|
||||||
size = VertexSizeAndOffsetsByStage(tcMask, stageOffsets, &colorOffset);
|
size = VertexSizeAndOffsetsByStage(tcMask, stageOffsets, &colorOffset, &edgeOffset);
|
||||||
GrAssert(2*sizeof(GrPoint) == size);
|
GrAssert(2*sizeof(GrPoint) == size);
|
||||||
GrAssert(-1 == colorOffset);
|
GrAssert(-1 == colorOffset);
|
||||||
|
GrAssert(-1 == edgeOffset);
|
||||||
for (int s = 0; s < kNumStages; ++s) {
|
for (int s = 0; s < kNumStages; ++s) {
|
||||||
GrAssert(VertexUsesStage(s, tcMask));
|
GrAssert(VertexUsesStage(s, tcMask));
|
||||||
GrAssert(sizeof(GrPoint) == stageOffsets[s]);
|
GrAssert(sizeof(GrPoint) == stageOffsets[s]);
|
||||||
|
@ -698,7 +747,8 @@ void GrDrawTarget::drawNonIndexed(GrPrimitiveType type,
|
||||||
bool GrDrawTarget::CanDisableBlend(GrVertexLayout layout, const DrState& state) {
|
bool GrDrawTarget::CanDisableBlend(GrVertexLayout layout, const DrState& state) {
|
||||||
// If we compute a coverage value (using edge AA or a coverage stage) then
|
// If we compute a coverage value (using edge AA or a coverage stage) then
|
||||||
// we can't force blending off.
|
// we can't force blending off.
|
||||||
if (state.fEdgeAANumEdges > 0) {
|
if (state.fEdgeAANumEdges > 0 ||
|
||||||
|
layout & kEdge_VertexLayoutBit) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (int s = state.fFirstCoverageStage; s < kNumStages; ++s) {
|
for (int s = state.fFirstCoverageStage; s < kNumStages; ++s) {
|
||||||
|
@ -837,8 +887,11 @@ void GrDrawTarget::SetRectVertices(const GrRect& rect,
|
||||||
|
|
||||||
int stageOffsets[kNumStages];
|
int stageOffsets[kNumStages];
|
||||||
int colorOffset;
|
int colorOffset;
|
||||||
int vsize = VertexSizeAndOffsetsByStage(layout, stageOffsets, &colorOffset);
|
int edgeOffset;
|
||||||
|
int vsize = VertexSizeAndOffsetsByStage(layout, stageOffsets,
|
||||||
|
&colorOffset, &edgeOffset);
|
||||||
GrAssert(-1 == colorOffset);
|
GrAssert(-1 == colorOffset);
|
||||||
|
GrAssert(-1 == edgeOffset);
|
||||||
|
|
||||||
GrTCast<GrPoint*>(vertices)->setRectFan(rect.fLeft, rect.fTop,
|
GrTCast<GrPoint*>(vertices)->setRectFan(rect.fLeft, rect.fTop,
|
||||||
rect.fRight, rect.fBottom,
|
rect.fRight, rect.fBottom,
|
||||||
|
|
|
@ -59,6 +59,20 @@ public:
|
||||||
kMaxEdges = 32
|
kMaxEdges = 32
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When specifying edges as vertex data this enum specifies what type of
|
||||||
|
* edges are in use. The edges are always 4 GrScalars in memory, even when
|
||||||
|
* the edge type requires fewer than 4.
|
||||||
|
*/
|
||||||
|
enum VertexEdgeType {
|
||||||
|
/* 1-pixel wide line
|
||||||
|
2D implicit line eq (a*x + b*y +c = 0). 4th component unused */
|
||||||
|
kHairLine_EdgeType,
|
||||||
|
/* 1-pixel wide quadratic
|
||||||
|
u^2-v canonical coords (only 2 components used) */
|
||||||
|
kHairQuad_EdgeType
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bitfield used to indicate which stages are in use.
|
* Bitfield used to indicate which stages are in use.
|
||||||
*/
|
*/
|
||||||
|
@ -167,6 +181,7 @@ protected:
|
||||||
|
|
||||||
GrStencilSettings fStencilSettings;
|
GrStencilSettings fStencilSettings;
|
||||||
GrMatrix fViewMatrix;
|
GrMatrix fViewMatrix;
|
||||||
|
VertexEdgeType fVertexEdgeType;
|
||||||
Edge fEdgeAAEdges[kMaxEdges];
|
Edge fEdgeAAEdges[kMaxEdges];
|
||||||
int fEdgeAANumEdges;
|
int fEdgeAANumEdges;
|
||||||
bool operator ==(const DrState& s) const {
|
bool operator ==(const DrState& s) const {
|
||||||
|
@ -267,6 +282,18 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shortcut for preConcatSamplerMatrix on all enabled stages in mask with
|
||||||
|
* same matrix
|
||||||
|
*
|
||||||
|
* @param stage the stage of the sampler to set
|
||||||
|
* @param matrix the matrix to concat
|
||||||
|
*/
|
||||||
|
void preConcatEnabledSamplerMatrices(const GrMatrix& matrix) {
|
||||||
|
StageBitfield stageMask = this->enabledStages();
|
||||||
|
this->preConcatSamplerMatrices(stageMask, matrix);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the matrix of a stage's sampler
|
* Gets the matrix of a stage's sampler
|
||||||
*
|
*
|
||||||
|
@ -535,6 +562,15 @@ public:
|
||||||
*/
|
*/
|
||||||
bool canDisableBlend() const;
|
bool canDisableBlend() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines the interpretation per-vertex edge data when the
|
||||||
|
* kEdge_VertexLayoutBit is set (see below). When per-vertex edges are not
|
||||||
|
* specified the value of this setting has no effect.
|
||||||
|
*/
|
||||||
|
void setVertexEdgeType(VertexEdgeType type) {
|
||||||
|
fCurrDrawState.fVertexEdgeType = type;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given the current draw state, vertex layout, and hw support, will HW AA
|
* Given the current draw state, vertex layout, and hw support, will HW AA
|
||||||
* lines be used (if line primitive type is drawn)? (Note that lines are
|
* lines be used (if line primitive type is drawn)? (Note that lines are
|
||||||
|
@ -575,15 +611,14 @@ public:
|
||||||
* Additional Bits that can be specified in GrVertexLayout.
|
* Additional Bits that can be specified in GrVertexLayout.
|
||||||
*/
|
*/
|
||||||
enum VertexLayoutBits {
|
enum VertexLayoutBits {
|
||||||
|
/* vertices have colors */
|
||||||
kColor_VertexLayoutBit = 1 << (STAGE_BIT_CNT + 0),
|
kColor_VertexLayoutBit = 1 << (STAGE_BIT_CNT + 0),
|
||||||
//<! vertices have colors
|
|
||||||
|
/* Use text vertices. (Pos and tex coords may be a different type for
|
||||||
|
text [GrGpuTextVertex vs GrPoint].) */
|
||||||
kTextFormat_VertexLayoutBit = 1 << (STAGE_BIT_CNT + 1),
|
kTextFormat_VertexLayoutBit = 1 << (STAGE_BIT_CNT + 1),
|
||||||
//<! use text vertices. (Pos
|
|
||||||
// and tex coords may be
|
kEdge_VertexLayoutBit = 1 << (STAGE_BIT_CNT + 2),
|
||||||
// a different type for
|
|
||||||
// text [GrGpuTextVertex vs
|
|
||||||
// GrPoint].)
|
|
||||||
// for below assert
|
// for below assert
|
||||||
kDummyVertexLayoutBit,
|
kDummyVertexLayoutBit,
|
||||||
kHighVertexLayoutBit = kDummyVertexLayoutBit - 1
|
kHighVertexLayoutBit = kDummyVertexLayoutBit - 1
|
||||||
|
@ -1030,6 +1065,13 @@ public:
|
||||||
*/
|
*/
|
||||||
static int VertexColorOffset(GrVertexLayout vertexLayout);
|
static int VertexColorOffset(GrVertexLayout vertexLayout);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to compute the offset of the edge pts in a vertex
|
||||||
|
* @return offset of edge in vertex layout or -1 if the
|
||||||
|
* layout has no edge.
|
||||||
|
*/
|
||||||
|
static int VertexEdgeOffset(GrVertexLayout vertexLayout);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function to determine if vertex layout contains explicit texture
|
* Helper function to determine if vertex layout contains explicit texture
|
||||||
* coordinates of some index.
|
* coordinates of some index.
|
||||||
|
@ -1069,7 +1111,8 @@ public:
|
||||||
*/
|
*/
|
||||||
static int VertexSizeAndOffsetsByIdx(GrVertexLayout vertexLayout,
|
static int VertexSizeAndOffsetsByIdx(GrVertexLayout vertexLayout,
|
||||||
int texCoordOffsetsByIdx[kMaxTexCoords],
|
int texCoordOffsetsByIdx[kMaxTexCoords],
|
||||||
int *colorOffset);
|
int *colorOffset,
|
||||||
|
int* edgeOffset);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function to compute the size of each vertex and the offsets of
|
* Helper function to compute the size of each vertex and the offsets of
|
||||||
|
@ -1086,7 +1129,8 @@ public:
|
||||||
*/
|
*/
|
||||||
static int VertexSizeAndOffsetsByStage(GrVertexLayout vertexLayout,
|
static int VertexSizeAndOffsetsByStage(GrVertexLayout vertexLayout,
|
||||||
int texCoordOffsetsByStage[kNumStages],
|
int texCoordOffsetsByStage[kNumStages],
|
||||||
int *colorOffset);
|
int *colorOffset,
|
||||||
|
int* edgeOffset);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accessing positions, texture coords, or colors, of a vertex within an
|
* Accessing positions, texture coords, or colors, of a vertex within an
|
||||||
|
@ -1194,6 +1238,14 @@ protected:
|
||||||
fCurrDrawState);
|
fCurrDrawState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StageBitfield enabledStages() const {
|
||||||
|
StageBitfield mask = 0;
|
||||||
|
for (int s = 0; s < kNumStages; ++s) {
|
||||||
|
mask |= this->isStageEnabled(s) ? 1 : 0;
|
||||||
|
}
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
// Helpers for GrDrawTarget subclasses that won't have private access to
|
// Helpers for GrDrawTarget subclasses that won't have private access to
|
||||||
// SavedDrawState but need to peek at the state values.
|
// SavedDrawState but need to peek at the state values.
|
||||||
static DrState& accessSavedDrawState(SavedDrawState& sds)
|
static DrState& accessSavedDrawState(SavedDrawState& sds)
|
||||||
|
|
|
@ -44,6 +44,7 @@ const char* GrShaderPrecision(const GrGLInterface* gl) {
|
||||||
|
|
||||||
#define POS_ATTR_NAME "aPosition"
|
#define POS_ATTR_NAME "aPosition"
|
||||||
#define COL_ATTR_NAME "aColor"
|
#define COL_ATTR_NAME "aColor"
|
||||||
|
#define EDGE_ATTR_NAME "aEdge"
|
||||||
#define COL_UNI_NAME "uColor"
|
#define COL_UNI_NAME "uColor"
|
||||||
#define EDGES_UNI_NAME "uEdges"
|
#define EDGES_UNI_NAME "uEdges"
|
||||||
#define COL_FILTER_UNI_NAME "uColorFilter"
|
#define COL_FILTER_UNI_NAME "uColorFilter"
|
||||||
|
@ -539,6 +540,25 @@ bool GrGLProgram::genProgram(const GrGLInterface* gl,
|
||||||
segments.fFSCode.append(";\n");
|
segments.fFSCode.append(";\n");
|
||||||
}
|
}
|
||||||
inCoverage = "edgeAlpha";
|
inCoverage = "edgeAlpha";
|
||||||
|
} else if (layout & GrDrawTarget::kEdge_VertexLayoutBit) {
|
||||||
|
segments.fVSAttrs.append("attribute vec4 " EDGE_ATTR_NAME ";\n");
|
||||||
|
segments.fVaryings.append("varying vec4 vEdge;\n");
|
||||||
|
segments.fVSCode.append("\tvEdge = " EDGE_ATTR_NAME ";\n");
|
||||||
|
if (GrDrawTarget::kHairLine_EdgeType == fProgramDesc.fVertexEdgeType) {
|
||||||
|
segments.fFSCode.append("\tfloat edgeAlpha = abs(dot(vec3(gl_FragCoord.xy,1), vEdge.xyz));\n");
|
||||||
|
} else {
|
||||||
|
GrAssert(GrDrawTarget::kHairQuad_EdgeType == fProgramDesc.fVertexEdgeType);
|
||||||
|
// for now we know we're not in perspective, so we could compute this
|
||||||
|
// per-quadratic rather than per pixel
|
||||||
|
segments.fFSCode.append("\tvec2 duvdx = dFdx(vEdge.xy);\n");
|
||||||
|
segments.fFSCode.append("\tvec2 duvdy = dFdy(vEdge.xy);\n");
|
||||||
|
segments.fFSCode.append("\tfloat dfdx = 2.0*vEdge.x*duvdx.x - duvdx.y;\n");
|
||||||
|
segments.fFSCode.append("\tfloat dfdy = 2.0*vEdge.x*duvdy.x - duvdy.y;\n");
|
||||||
|
segments.fFSCode.append("\tfloat edgeAlpha = (vEdge.x*vEdge.x - vEdge.y);\n");
|
||||||
|
segments.fFSCode.append("\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / (dfdx*dfdx + dfdy*dfdy));\n");
|
||||||
|
}
|
||||||
|
segments.fFSCode.append("\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
|
||||||
|
inCoverage = "edgeAlpha";
|
||||||
}
|
}
|
||||||
|
|
||||||
GrStringBuilder outCoverage;
|
GrStringBuilder outCoverage;
|
||||||
|
@ -841,6 +861,8 @@ bool GrGLProgram::bindOutputsAttribsAndLinkProgram(
|
||||||
|
|
||||||
GR_GL_CALL(gl, BindAttribLocation(progID, ColorAttributeIdx(),
|
GR_GL_CALL(gl, BindAttribLocation(progID, ColorAttributeIdx(),
|
||||||
COL_ATTR_NAME));
|
COL_ATTR_NAME));
|
||||||
|
GR_GL_CALL(gl, BindAttribLocation(progID, EdgeAttributeIdx(),
|
||||||
|
EDGE_ATTR_NAME));
|
||||||
|
|
||||||
GR_GL_CALL(gl, LinkProgram(progID));
|
GR_GL_CALL(gl, LinkProgram(progID));
|
||||||
|
|
||||||
|
|
|
@ -65,6 +65,8 @@ public:
|
||||||
static int PositionAttributeIdx() { return 0; }
|
static int PositionAttributeIdx() { return 0; }
|
||||||
static int TexCoordAttributeIdx(int tcIdx) { return 1 + tcIdx; }
|
static int TexCoordAttributeIdx(int tcIdx) { return 1 + tcIdx; }
|
||||||
static int ColorAttributeIdx() { return 1 + GrDrawTarget::kMaxTexCoords; }
|
static int ColorAttributeIdx() { return 1 + GrDrawTarget::kMaxTexCoords; }
|
||||||
|
static int EdgeAttributeIdx() { return 2 + GrDrawTarget::kMaxTexCoords; }
|
||||||
|
|
||||||
static int ViewMatrixAttributeIdx() {
|
static int ViewMatrixAttributeIdx() {
|
||||||
return 2 + GrDrawTarget::kMaxTexCoords;
|
return 2 + GrDrawTarget::kMaxTexCoords;
|
||||||
}
|
}
|
||||||
|
@ -150,6 +152,8 @@ private:
|
||||||
kDualSrcOutputCnt
|
kDualSrcOutputCnt
|
||||||
};
|
};
|
||||||
|
|
||||||
|
GrDrawTarget::VertexEdgeType fVertexEdgeType;
|
||||||
|
|
||||||
// stripped of bits that don't affect prog generation
|
// stripped of bits that don't affect prog generation
|
||||||
GrVertexLayout fVertexLayout;
|
GrVertexLayout fVertexLayout;
|
||||||
|
|
||||||
|
|
|
@ -276,15 +276,22 @@ void GrGpuGLFixed::setupGeometry(int* startVertex,
|
||||||
|
|
||||||
int newColorOffset;
|
int newColorOffset;
|
||||||
int newTexCoordOffsets[kNumStages];
|
int newTexCoordOffsets[kNumStages];
|
||||||
|
int newEdgeOffset;
|
||||||
|
|
||||||
GrGLsizei newStride = VertexSizeAndOffsetsByStage(this->getGeomSrc().fVertexLayout,
|
GrGLsizei newStride = VertexSizeAndOffsetsByStage(this->getGeomSrc().fVertexLayout,
|
||||||
newTexCoordOffsets,
|
newTexCoordOffsets,
|
||||||
&newColorOffset);
|
&newColorOffset,
|
||||||
|
&newEdgeOffset);
|
||||||
|
GrAssert(-1 == newEdgeOffset); // not supported by fixed pipe
|
||||||
|
|
||||||
int oldColorOffset;
|
int oldColorOffset;
|
||||||
int oldTexCoordOffsets[kNumStages];
|
int oldTexCoordOffsets[kNumStages];
|
||||||
|
int oldEdgeOffset;
|
||||||
GrGLsizei oldStride = VertexSizeAndOffsetsByStage(fHWGeometryState.fVertexLayout,
|
GrGLsizei oldStride = VertexSizeAndOffsetsByStage(fHWGeometryState.fVertexLayout,
|
||||||
oldTexCoordOffsets,
|
oldTexCoordOffsets,
|
||||||
&oldColorOffset);
|
&oldColorOffset,
|
||||||
|
&oldEdgeOffset);
|
||||||
|
GrAssert(-1 == oldEdgeOffset);
|
||||||
|
|
||||||
bool indexed = NULL != startIndex;
|
bool indexed = NULL != startIndex;
|
||||||
|
|
||||||
|
|
|
@ -186,8 +186,21 @@ bool GrGpuGLShaders::programUnitTest() {
|
||||||
|
|
||||||
bool edgeAA = random.nextF() > .5f;
|
bool edgeAA = random.nextF() > .5f;
|
||||||
if (edgeAA) {
|
if (edgeAA) {
|
||||||
|
bool vertexEdgeAA = random.nextF() > .5f;
|
||||||
|
if (vertexEdgeAA) {
|
||||||
|
pdesc.fVertexLayout |= GrDrawTarget::kEdge_VertexLayoutBit;
|
||||||
|
if (this->supportsShaderDerivatives()) {
|
||||||
|
pdesc.fVertexEdgeType = random.nextF() > 0.5f ?
|
||||||
|
kHairQuad_EdgeType :
|
||||||
|
kHairLine_EdgeType;
|
||||||
|
} else {
|
||||||
|
pdesc.fVertexEdgeType = kHairLine_EdgeType;
|
||||||
|
}
|
||||||
|
pdesc.fEdgeAANumEdges = 0;
|
||||||
|
} else {
|
||||||
pdesc.fEdgeAANumEdges = random.nextF() * this->getMaxEdges() + 1;
|
pdesc.fEdgeAANumEdges = random.nextF() * this->getMaxEdges() + 1;
|
||||||
pdesc.fEdgeAAConcave = random.nextF() > .5f;
|
pdesc.fEdgeAAConcave = random.nextF() > .5f;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
pdesc.fEdgeAANumEdges = 0;
|
pdesc.fEdgeAANumEdges = 0;
|
||||||
}
|
}
|
||||||
|
@ -307,6 +320,7 @@ void GrGpuGLShaders::resetContext() {
|
||||||
fHWGeometryState.fVertexLayout = 0;
|
fHWGeometryState.fVertexLayout = 0;
|
||||||
fHWGeometryState.fVertexOffset = ~0;
|
fHWGeometryState.fVertexOffset = ~0;
|
||||||
GL_CALL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
|
GL_CALL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
|
||||||
|
GL_CALL(DisableVertexAttribArray(GrGLProgram::EdgeAttributeIdx()));
|
||||||
for (int t = 0; t < kMaxTexCoords; ++t) {
|
for (int t = 0; t < kMaxTexCoords; ++t) {
|
||||||
GL_CALL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
|
GL_CALL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
|
||||||
}
|
}
|
||||||
|
@ -641,17 +655,22 @@ void GrGpuGLShaders::setupGeometry(int* startVertex,
|
||||||
|
|
||||||
int newColorOffset;
|
int newColorOffset;
|
||||||
int newTexCoordOffsets[kMaxTexCoords];
|
int newTexCoordOffsets[kMaxTexCoords];
|
||||||
|
int newEdgeOffset;
|
||||||
|
|
||||||
GrGLsizei newStride = VertexSizeAndOffsetsByIdx(
|
GrGLsizei newStride = VertexSizeAndOffsetsByIdx(
|
||||||
this->getGeomSrc().fVertexLayout,
|
this->getGeomSrc().fVertexLayout,
|
||||||
newTexCoordOffsets,
|
newTexCoordOffsets,
|
||||||
&newColorOffset);
|
&newColorOffset,
|
||||||
|
&newEdgeOffset);
|
||||||
int oldColorOffset;
|
int oldColorOffset;
|
||||||
int oldTexCoordOffsets[kMaxTexCoords];
|
int oldTexCoordOffsets[kMaxTexCoords];
|
||||||
|
int oldEdgeOffset;
|
||||||
|
|
||||||
GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(
|
GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(
|
||||||
fHWGeometryState.fVertexLayout,
|
fHWGeometryState.fVertexLayout,
|
||||||
oldTexCoordOffsets,
|
oldTexCoordOffsets,
|
||||||
&oldColorOffset);
|
&oldColorOffset,
|
||||||
|
&oldEdgeOffset);
|
||||||
bool indexed = NULL != startIndex;
|
bool indexed = NULL != startIndex;
|
||||||
|
|
||||||
int extraVertexOffset;
|
int extraVertexOffset;
|
||||||
|
@ -727,6 +746,21 @@ void GrGpuGLShaders::setupGeometry(int* startVertex,
|
||||||
GL_CALL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
|
GL_CALL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (newEdgeOffset > 0) {
|
||||||
|
GrGLvoid* edgeOffset = (int8_t*)(vertexOffset + newEdgeOffset);
|
||||||
|
int idx = GrGLProgram::EdgeAttributeIdx();
|
||||||
|
if (oldEdgeOffset <= 0) {
|
||||||
|
GL_CALL(EnableVertexAttribArray(idx));
|
||||||
|
GL_CALL(VertexAttribPointer(idx, 4, scalarType,
|
||||||
|
false, newStride, edgeOffset));
|
||||||
|
} else if (allOffsetsChange || newEdgeOffset != oldEdgeOffset) {
|
||||||
|
GL_CALL(VertexAttribPointer(idx, 4, scalarType,
|
||||||
|
false, newStride, edgeOffset));
|
||||||
|
}
|
||||||
|
} else if (oldEdgeOffset > 0) {
|
||||||
|
GL_CALL(DisableVertexAttribArray(GrGLProgram::EdgeAttributeIdx()));
|
||||||
|
}
|
||||||
|
|
||||||
fHWGeometryState.fVertexLayout = this->getGeomSrc().fVertexLayout;
|
fHWGeometryState.fVertexLayout = this->getGeomSrc().fVertexLayout;
|
||||||
fHWGeometryState.fArrayPtrsDirty = false;
|
fHWGeometryState.fArrayPtrsDirty = false;
|
||||||
}
|
}
|
||||||
|
@ -734,6 +768,11 @@ void GrGpuGLShaders::setupGeometry(int* startVertex,
|
||||||
void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
|
void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
|
||||||
ProgramDesc& desc = fCurrentProgram.fProgramDesc;
|
ProgramDesc& desc = fCurrentProgram.fProgramDesc;
|
||||||
|
|
||||||
|
// The descriptor is used as a cache key. Thus when a field of the
|
||||||
|
// descriptor will not affect program generation (because of the vertex
|
||||||
|
// layout in use or other descriptor field settings) it should be set
|
||||||
|
// to a canonical value to avoid duplicate programs with different keys.
|
||||||
|
|
||||||
// Must initialize all fields or cache will have false negatives!
|
// Must initialize all fields or cache will have false negatives!
|
||||||
desc.fVertexLayout = this->getGeomSrc().fVertexLayout;
|
desc.fVertexLayout = this->getGeomSrc().fVertexLayout;
|
||||||
|
|
||||||
|
@ -767,6 +806,13 @@ void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
|
||||||
|
|
||||||
int lastEnabledStage = -1;
|
int lastEnabledStage = -1;
|
||||||
|
|
||||||
|
if (desc.fVertexLayout & GrDrawTarget::kEdge_VertexLayoutBit) {
|
||||||
|
desc.fVertexEdgeType = fCurrDrawState.fVertexEdgeType;
|
||||||
|
} else {
|
||||||
|
// use canonical value when not set to avoid cache misses
|
||||||
|
desc.fVertexEdgeType = GrDrawTarget::kHairLine_EdgeType;
|
||||||
|
}
|
||||||
|
|
||||||
for (int s = 0; s < kNumStages; ++s) {
|
for (int s = 0; s < kNumStages; ++s) {
|
||||||
StageDesc& stage = desc.fStages[s];
|
StageDesc& stage = desc.fStages[s];
|
||||||
|
|
||||||
|
|
|
@ -52,13 +52,28 @@ public:
|
||||||
/**
|
/**
|
||||||
* Returns true if this path renderer is able to render the path.
|
* Returns true if this path renderer is able to render the path.
|
||||||
* Returning false allows the caller to fallback to another path renderer.
|
* Returning false allows the caller to fallback to another path renderer.
|
||||||
|
* When searching for a path renderer capable of rendering a path this
|
||||||
|
* function is called. The path renderer can examine the path, fill rule,
|
||||||
|
* and draw settings that will be used (via the targetparameter). If "true"
|
||||||
|
* is reported note that the caller is permitted to make modifications to
|
||||||
|
* the following settings of the target between the calls to canDrawPath and
|
||||||
|
* drawPath:
|
||||||
|
* 1. view matrix: The matrix at drawPath time may have additional scale
|
||||||
|
* scale and translation applied
|
||||||
|
* 2. render target: The render target may change between canDrawPath
|
||||||
|
* and drawPath.
|
||||||
|
* The GrPathRenderer subclass's decision about whether to return true
|
||||||
|
* or false in its implementation of this function should consider these
|
||||||
|
* possible state changes.
|
||||||
*
|
*
|
||||||
* @param path The path to draw
|
* @param path The path to draw
|
||||||
* @param fill The fill rule to use
|
* @param fill The fill rule to use
|
||||||
*
|
*
|
||||||
* @return true if the path can be drawn by this object, false otherwise.
|
* @return true if the path can be drawn by this object, false otherwise.
|
||||||
*/
|
*/
|
||||||
virtual bool canDrawPath(const SkPath& path, GrPathFill fill) const = 0;
|
virtual bool canDrawPath(const GrDrawTarget* target,
|
||||||
|
const SkPath& path,
|
||||||
|
GrPathFill fill) const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For complex clips Gr uses the stencil buffer. The path renderer must be
|
* For complex clips Gr uses the stencil buffer. The path renderer must be
|
||||||
|
|
|
@ -43,7 +43,7 @@ GrPathRenderer* GrPathRendererChain::getPathRenderer(const GrDrawTarget* target,
|
||||||
!target->getRenderTarget()->isMultisampled();
|
!target->getRenderTarget()->isMultisampled();
|
||||||
GrPathRenderer* nonAAPR = NULL;
|
GrPathRenderer* nonAAPR = NULL;
|
||||||
for (int i = 0; i < fChain.count(); ++i) {
|
for (int i = 0; i < fChain.count(); ++i) {
|
||||||
if (fChain[i]->canDrawPath(path, fill)) {
|
if (fChain[i]->canDrawPath(target, path, fill)) {
|
||||||
if (!preferAA || fChain[i]->supportsAA(target, path, fill)) {
|
if (!preferAA || fChain[i]->supportsAA(target, path, fill)) {
|
||||||
return fChain[i];
|
return fChain[i];
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -599,7 +599,8 @@ FINISHED:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GrTesselatedPathRenderer::canDrawPath(const SkPath& path,
|
bool GrTesselatedPathRenderer::canDrawPath(const GrDrawTarget* target,
|
||||||
|
const SkPath& path,
|
||||||
GrPathFill fill) const {
|
GrPathFill fill) const {
|
||||||
return kHairLine_PathFill != fill;
|
return kHairLine_PathFill != fill;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,8 @@ public:
|
||||||
GrTesselatedPathRenderer();
|
GrTesselatedPathRenderer();
|
||||||
|
|
||||||
virtual void drawPath(GrDrawTarget::StageBitfield stages);
|
virtual void drawPath(GrDrawTarget::StageBitfield stages);
|
||||||
virtual bool canDrawPath(const GrPath& path,
|
virtual bool canDrawPath(const GrDrawTarget* target,
|
||||||
|
const GrPath& path,
|
||||||
GrPathFill fill) const;
|
GrPathFill fill) const;
|
||||||
|
|
||||||
virtual bool requiresStencilPass(const GrDrawTarget* target,
|
virtual bool requiresStencilPass(const GrDrawTarget* target,
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
'../samplecode/ClockFaceView.cpp',
|
'../samplecode/ClockFaceView.cpp',
|
||||||
'../samplecode/OverView.cpp',
|
'../samplecode/OverView.cpp',
|
||||||
'../samplecode/Sample2PtRadial.cpp',
|
'../samplecode/Sample2PtRadial.cpp',
|
||||||
|
'../samplecode/SampleAARects.cpp',
|
||||||
'../samplecode/SampleAll.cpp',
|
'../samplecode/SampleAll.cpp',
|
||||||
'../samplecode/SampleAnimator.cpp',
|
'../samplecode/SampleAnimator.cpp',
|
||||||
'../samplecode/SampleApp.cpp',
|
'../samplecode/SampleApp.cpp',
|
||||||
|
@ -68,6 +69,7 @@
|
||||||
'../samplecode/SampleFuzz.cpp',
|
'../samplecode/SampleFuzz.cpp',
|
||||||
'../samplecode/SampleGM.cpp',
|
'../samplecode/SampleGM.cpp',
|
||||||
'../samplecode/SampleGradients.cpp',
|
'../samplecode/SampleGradients.cpp',
|
||||||
|
'../samplecode/SampleHairCurves.cpp',
|
||||||
'../samplecode/SampleHairline.cpp',
|
'../samplecode/SampleHairline.cpp',
|
||||||
'../samplecode/SampleImage.cpp',
|
'../samplecode/SampleImage.cpp',
|
||||||
'../samplecode/SampleImageDir.cpp',
|
'../samplecode/SampleImageDir.cpp',
|
||||||
|
@ -90,7 +92,6 @@
|
||||||
'../samplecode/SamplePicture.cpp',
|
'../samplecode/SamplePicture.cpp',
|
||||||
'../samplecode/SamplePoints.cpp',
|
'../samplecode/SamplePoints.cpp',
|
||||||
'../samplecode/SamplePolyToPoly.cpp',
|
'../samplecode/SamplePolyToPoly.cpp',
|
||||||
'../samplecode/SampleAARects.cpp',
|
|
||||||
'../samplecode/SampleRegion.cpp',
|
'../samplecode/SampleRegion.cpp',
|
||||||
'../samplecode/SampleRepeatTile.cpp',
|
'../samplecode/SampleRepeatTile.cpp',
|
||||||
'../samplecode/SampleShaders.cpp',
|
'../samplecode/SampleShaders.cpp',
|
||||||
|
|
|
@ -126,7 +126,9 @@
|
||||||
'../gpu/include/GrTypes.h',
|
'../gpu/include/GrTypes.h',
|
||||||
'../gpu/include/GrUserConfig.h',
|
'../gpu/include/GrUserConfig.h',
|
||||||
|
|
||||||
'../gpu/src/GrAddPathRenderers_none.cpp',
|
'../gpu/src/GrAAHairlinePathRenderer.cpp',
|
||||||
|
'../gpu/src/GrAAHairlinePathRenderer.h',
|
||||||
|
'../gpu/src/GrAddPathRenderers_aahairline.cpp',
|
||||||
'../gpu/src/GrAllocPool.cpp',
|
'../gpu/src/GrAllocPool.cpp',
|
||||||
'../gpu/src/GrAtlas.cpp',
|
'../gpu/src/GrAtlas.cpp',
|
||||||
'../gpu/src/GrBinHashKey.h',
|
'../gpu/src/GrBinHashKey.h',
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2011 Google Inc.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
#include "SampleCode.h"
|
||||||
|
#include "SkView.h"
|
||||||
|
#include "SkCanvas.h"
|
||||||
|
#include "SkPath.h"
|
||||||
|
#include "SkRandom.h"
|
||||||
|
|
||||||
|
class HairCurvesView : public SampleView {
|
||||||
|
public:
|
||||||
|
HairCurvesView() {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// overrides from SkEventSink
|
||||||
|
virtual bool onQuery(SkEvent* evt) {
|
||||||
|
if (SampleCode::TitleQ(*evt)) {
|
||||||
|
SampleCode::TitleR(evt, "HairCurves");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return this->INHERITED::onQuery(evt);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
virtual void onDrawContent(SkCanvas* canvas) {
|
||||||
|
SkPaint paint;
|
||||||
|
paint.setAntiAlias(true);
|
||||||
|
paint.setStyle(SkPaint::kStroke_Style);
|
||||||
|
paint.setStrokeWidth(-1);
|
||||||
|
canvas->save();
|
||||||
|
canvas->scale(1000 * SK_Scalar1, 1000 * SK_Scalar1);
|
||||||
|
SkRandom rand;
|
||||||
|
SkPath curves;
|
||||||
|
SkPath hulls;
|
||||||
|
SkPath ctrlPts;
|
||||||
|
for (int i = 0; i < 100; ++i) {
|
||||||
|
SkScalar pts[] = {
|
||||||
|
rand.nextUScalar1(), rand.nextUScalar1(),
|
||||||
|
rand.nextUScalar1(), rand.nextUScalar1(),
|
||||||
|
rand.nextUScalar1(), rand.nextUScalar1(),
|
||||||
|
rand.nextUScalar1(), rand.nextUScalar1()
|
||||||
|
};
|
||||||
|
curves.moveTo(pts[0], pts[1]);
|
||||||
|
curves.cubicTo(pts[2], pts[3],
|
||||||
|
pts[4], pts[5],
|
||||||
|
pts[6], pts[7]);
|
||||||
|
|
||||||
|
hulls.moveTo(pts[0], pts[1]);
|
||||||
|
hulls.lineTo(pts[2], pts[3]);
|
||||||
|
hulls.lineTo(pts[4], pts[5]);
|
||||||
|
hulls.lineTo(pts[6], pts[7]);
|
||||||
|
|
||||||
|
ctrlPts.addCircle(pts[0], pts[1], SK_Scalar1 / 200);
|
||||||
|
ctrlPts.addCircle(pts[2], pts[3], SK_Scalar1 / 200);
|
||||||
|
ctrlPts.addCircle(pts[4], pts[5], SK_Scalar1 / 200);
|
||||||
|
ctrlPts.addCircle(pts[6], pts[7], SK_Scalar1 / 200);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 100; ++i) {
|
||||||
|
SkScalar pts[] = {
|
||||||
|
rand.nextUScalar1(), rand.nextUScalar1(),
|
||||||
|
rand.nextUScalar1(), rand.nextUScalar1(),
|
||||||
|
rand.nextUScalar1(), rand.nextUScalar1(),
|
||||||
|
};
|
||||||
|
curves.moveTo(pts[0], pts[1]);
|
||||||
|
curves.quadTo(pts[2], pts[3],
|
||||||
|
pts[4], pts[5]);
|
||||||
|
|
||||||
|
hulls.moveTo(pts[0], pts[1]);
|
||||||
|
hulls.lineTo(pts[2], pts[3]);
|
||||||
|
hulls.lineTo(pts[4], pts[5]);
|
||||||
|
|
||||||
|
ctrlPts.addCircle(pts[0], pts[1], SK_Scalar1 / 200);
|
||||||
|
ctrlPts.addCircle(pts[2], pts[3], SK_Scalar1 / 200);
|
||||||
|
ctrlPts.addCircle(pts[4], pts[5], SK_Scalar1 / 200);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 100; ++i) {
|
||||||
|
SkScalar pts[] = {
|
||||||
|
rand.nextUScalar1(), rand.nextUScalar1(),
|
||||||
|
rand.nextUScalar1(), rand.nextUScalar1(),
|
||||||
|
};
|
||||||
|
curves.moveTo(pts[0], pts[1]);
|
||||||
|
curves.lineTo(pts[2], pts[3]);
|
||||||
|
|
||||||
|
ctrlPts.addCircle(pts[0], pts[1], SK_Scalar1 / 200);
|
||||||
|
ctrlPts.addCircle(pts[2], pts[3], SK_Scalar1 / 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
paint.setColor(SK_ColorBLACK);
|
||||||
|
canvas->drawPath(curves, paint);
|
||||||
|
paint.setColor(SK_ColorRED);
|
||||||
|
//canvas->drawPath(hulls, paint);
|
||||||
|
paint.setStyle(SkPaint::kFill_Style);
|
||||||
|
paint.setColor(SK_ColorBLUE);
|
||||||
|
//canvas->drawPath(ctrlPts, paint);
|
||||||
|
|
||||||
|
canvas->restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef SampleView INHERITED;
|
||||||
|
};
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static SkView* MyFactory() { return new HairCurvesView; }
|
||||||
|
static SkViewRegister reg(MyFactory);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче