Fix hairline pathrenderer for Nexus-10. Switches to using additional
geometry and passing in the coverage value instead. BUG= R=robertphillips@google.com, bsalomon@google.com Author: jvanverth@google.com Review URL: https://chromiumcodereview.appspot.com/22486003 git-svn-id: http://skia.googlecode.com/svn/trunk@10640 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
53766103b5
commit
78b64aebef
@ -29,15 +29,20 @@ namespace {
|
||||
static const int kVertsPerQuad = 5;
|
||||
static const int kIdxsPerQuad = 9;
|
||||
|
||||
static const int kVertsPerLineSeg = 4;
|
||||
static const int kIdxsPerLineSeg = 6;
|
||||
static const int kVertsPerLineSeg = 6;
|
||||
static const int kIdxsPerLineSeg = 12;
|
||||
|
||||
static const int kNumQuadsInIdxBuffer = 256;
|
||||
static const size_t kQuadIdxSBufize = kIdxsPerQuad *
|
||||
sizeof(uint16_t) *
|
||||
kNumQuadsInIdxBuffer;
|
||||
|
||||
bool push_quad_index_data(GrIndexBuffer* qIdxBuffer) {
|
||||
static const int kNumLineSegsInIdxBuffer = 256;
|
||||
static const size_t kLineSegIdxSBufize = kIdxsPerLineSeg *
|
||||
sizeof(uint16_t) *
|
||||
kNumLineSegsInIdxBuffer;
|
||||
|
||||
static bool push_quad_index_data(GrIndexBuffer* qIdxBuffer) {
|
||||
uint16_t* data = (uint16_t*) qIdxBuffer->lock();
|
||||
bool tempData = NULL == data;
|
||||
if (tempData) {
|
||||
@ -78,22 +83,66 @@ bool push_quad_index_data(GrIndexBuffer* qIdxBuffer) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool push_line_index_data(GrIndexBuffer* lIdxBuffer) {
|
||||
uint16_t* data = (uint16_t*) lIdxBuffer->lock();
|
||||
bool tempData = NULL == data;
|
||||
if (tempData) {
|
||||
data = SkNEW_ARRAY(uint16_t, kNumLineSegsInIdxBuffer * kIdxsPerLineSeg);
|
||||
}
|
||||
for (int i = 0; i < kNumLineSegsInIdxBuffer; ++i) {
|
||||
// Each line segment is rendered as two quads, with alpha = 1 along the
|
||||
// spine of the segment, and alpha = 0 along the outer edges, represented
|
||||
// horizontally (i.e., the line equation is t*(p1-p0) + p0)
|
||||
//
|
||||
// p4 p5
|
||||
// p0 p1
|
||||
// p2 p3
|
||||
//
|
||||
// Each is drawn as four triangles specified by these 12 indices:
|
||||
int baseIdx = i * kIdxsPerLineSeg;
|
||||
uint16_t baseVert = (uint16_t)(i * kVertsPerLineSeg);
|
||||
data[0 + baseIdx] = baseVert + 0; // p0
|
||||
data[1 + baseIdx] = baseVert + 1; // p1
|
||||
data[2 + baseIdx] = baseVert + 2; // p2
|
||||
|
||||
data[3 + baseIdx] = baseVert + 2; // p2
|
||||
data[4 + baseIdx] = baseVert + 1; // p1
|
||||
data[5 + baseIdx] = baseVert + 3; // p3
|
||||
|
||||
data[6 + baseIdx] = baseVert + 0; // p0
|
||||
data[7 + baseIdx] = baseVert + 5; // p5
|
||||
data[8 + baseIdx] = baseVert + 1; // p1
|
||||
|
||||
data[9 + baseIdx] = baseVert + 0; // p0
|
||||
data[10+ baseIdx] = baseVert + 4; // p4
|
||||
data[11+ baseIdx] = baseVert + 5; // p5
|
||||
}
|
||||
if (tempData) {
|
||||
bool ret = lIdxBuffer->updateData(data, kLineSegIdxSBufize);
|
||||
delete[] data;
|
||||
return ret;
|
||||
} else {
|
||||
lIdxBuffer->unlock();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GrPathRenderer* GrAAHairLinePathRenderer::Create(GrContext* 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);
|
||||
if (NULL == qIdxBuf ||
|
||||
!push_quad_index_data(qIdxBuf)) {
|
||||
if (NULL == qIdxBuf || !push_quad_index_data(qIdxBuf)) {
|
||||
return NULL;
|
||||
}
|
||||
GrIndexBuffer* lIdxBuf = gpu->createIndexBuffer(kLineSegIdxSBufize, false);
|
||||
SkAutoTUnref<GrIndexBuffer> lIdxBuffer(lIdxBuf);
|
||||
if (NULL == lIdxBuf || !push_line_index_data(lIdxBuf)) {
|
||||
return NULL;
|
||||
}
|
||||
return SkNEW_ARGS(GrAAHairLinePathRenderer,
|
||||
(context, lIdxBuffer, qIdxBuf));
|
||||
(context, lIdxBuf, qIdxBuf));
|
||||
}
|
||||
|
||||
GrAAHairLinePathRenderer::GrAAHairLinePathRenderer(
|
||||
@ -436,9 +485,7 @@ struct Vertex {
|
||||
GrPoint fPos;
|
||||
union {
|
||||
struct {
|
||||
SkScalar fA;
|
||||
SkScalar fB;
|
||||
SkScalar fC;
|
||||
SkScalar fCoverage;
|
||||
} fLine;
|
||||
struct {
|
||||
SkScalar fK;
|
||||
@ -661,17 +708,17 @@ void add_line(const SkPoint p[2],
|
||||
if (orthVec.setLength(SK_Scalar1)) {
|
||||
orthVec.setOrthog(orthVec);
|
||||
|
||||
SkScalar lineC = -(a.dot(orthVec));
|
||||
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 = (i & 0x1) ? b : a;
|
||||
if (i & 0x2) {
|
||||
(*vert)[i].fPos += orthVec;
|
||||
(*vert)[i].fLine.fCoverage = 0;
|
||||
} else if (i & 0x4) {
|
||||
(*vert)[i].fPos -= orthVec;
|
||||
(*vert)[i].fLine.fCoverage = 0;
|
||||
} else {
|
||||
(*vert)[i].fLine.fCoverage = SK_Scalar1;
|
||||
}
|
||||
(*vert)[i].fLine.fA = orthVec.fX;
|
||||
(*vert)[i].fLine.fB = orthVec.fY;
|
||||
(*vert)[i].fLine.fC = lineC;
|
||||
}
|
||||
if (NULL != toSrc) {
|
||||
toSrc->mapPointsWithStride(&(*vert)->fPos,
|
||||
@ -684,6 +731,8 @@ void add_line(const SkPoint p[2],
|
||||
(*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)[4].fPos.set(SK_ScalarMax, SK_ScalarMax);
|
||||
(*vert)[5].fPos.set(SK_ScalarMax, SK_ScalarMax);
|
||||
}
|
||||
|
||||
*vert += kVertsPerLineSeg;
|
||||
@ -936,7 +985,7 @@ GrEffectRef* HairQuadEdgeEffect::TestCreate(SkMWCRandom* random,
|
||||
|
||||
/**
|
||||
* The output of this effect is a 1-pixel wide line.
|
||||
* Input is 2D implicit device coord line eq (a*x + b*y +c = 0). 4th component unused.
|
||||
* Input is coverage relative to the line.
|
||||
*/
|
||||
class HairLineEdgeEffect : public GrEffect {
|
||||
public:
|
||||
@ -978,9 +1027,7 @@ public:
|
||||
|
||||
builder->addVarying(kVec4f_GrSLType, "HairLineEdge", &vsName, &fsName);
|
||||
|
||||
builder->fsCodeAppendf("\t\tedgeAlpha = abs(dot(vec3(%s.xy,1), %s.xyz));\n",
|
||||
builder->fragmentPosition(), fsName);
|
||||
builder->fsCodeAppendf("\t\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
|
||||
builder->fsCodeAppendf("\t\tedgeAlpha = %s.x;\n", fsName);
|
||||
|
||||
SkString modulate;
|
||||
GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha");
|
||||
@ -1191,13 +1238,15 @@ bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path,
|
||||
#endif
|
||||
|
||||
{
|
||||
// the fact we're using an effect to pass per-vertex coverage is kind of dumb,
|
||||
// but necessary due to the shared vertex buffer
|
||||
// TODO: refactor so that we render lines with a separate vertex buffer
|
||||
GrDrawState::AutoRestoreEffects are(drawState);
|
||||
target->setIndexSourceToBuffer(fLinesIndexBuffer);
|
||||
int lines = 0;
|
||||
int nBufLines = fLinesIndexBuffer->maxQuads();
|
||||
drawState->addCoverageEffect(hairLineEffect, kEdgeAttrIndex)->unref();
|
||||
while (lines < lineCnt) {
|
||||
int n = GrMin(lineCnt - lines, nBufLines);
|
||||
int n = GrMin(lineCnt - lines, kNumLineSegsInIdxBuffer);
|
||||
target->drawIndexed(kTriangles_GrPrimitiveType,
|
||||
kVertsPerLineSeg*lines, // startV
|
||||
0, // startI
|
||||
|
Loading…
Reference in New Issue
Block a user