Chromium Code Reviews| Index: src/gpu/GrAARectRenderer.cpp |
| diff --git a/src/gpu/GrAARectRenderer.cpp b/src/gpu/GrAARectRenderer.cpp |
| index ee7c024fe81aab548e9493dccd3cc721c759e70c..6b0a998bf0e7e7b2e89b31688f45beb9ecf398be 100644 |
| --- a/src/gpu/GrAARectRenderer.cpp |
| +++ b/src/gpu/GrAARectRenderer.cpp |
| @@ -289,7 +289,8 @@ static void set_inset_fan(GrPoint* pts, size_t stride, |
| void GrAARectRenderer::reset() { |
| SkSafeSetNull(fAAFillRectIndexBuffer); |
| - SkSafeSetNull(fAAStrokeRectIndexBuffer); |
| + SkSafeSetNull(fAAMiterStrokeRectIndexBuffer); |
| + SkSafeSetNull(fAABevelStrokeRectIndexBuffer); |
| } |
| static const uint16_t gFillAARectIdx[] = { |
| @@ -340,7 +341,7 @@ GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) { |
| return fAAFillRectIndexBuffer; |
| } |
| -static const uint16_t gStrokeAARectIdx[] = { |
| +static const uint16_t gMiterStrokeAARectIdx[] = { |
| 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0, |
| 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0, |
| 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0, |
| @@ -357,24 +358,98 @@ static const uint16_t gStrokeAARectIdx[] = { |
| 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8, |
| }; |
| -int GrAARectRenderer::aaStrokeRectIndexCount() { |
| - return GR_ARRAY_COUNT(gStrokeAARectIdx); |
| +/** |
| + * As in miter-stroke, index = a + b, and a is the current index, b is the shift |
| + * from the first index. The index layout: |
| + * outer AA line: 0~3, 4~7 |
| + * outer edge: 8~11, 12~15 |
| + * inner edge: 16~19 |
| + * inner AA line: 20~23 |
| + * Following comes a bevel-stroke rect and its indices: |
| + * |
| + * 4 7 |
| + * ********************************* |
| + * * ______________________________ * |
| + * * / 12 15 \ * |
| + * * / \ * |
| + * 0 * |8 16_____________________19 11 | * 3 |
| + * * | | | | * |
| + * * | | **************** | | * |
| + * * | | * 20 23 * | | * |
| + * * | | * * | | * |
| + * * | | * 21 22 * | | * |
| + * * | | **************** | | * |
| + * * | |____________________| | * |
| + * 1 * |9 17 18 10| * 2 |
| + * * \ / * |
| + * * \13 __________________________14/ * |
| + * * * |
| + * ********************************** |
| + * 5 6 |
| + */ |
| +static const uint16_t gBevelStrokeAARectIdx[] = { |
| + // Draw outer AA, from outer AA line to outer edge, shift is 0. |
| + 0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0, |
| + 1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0, |
| + 5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0, |
| + 6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0, |
| + 2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0, |
| + 3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0, |
| + 7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0, |
| + 4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0, |
| + |
| + // Draw the stroke, from outer edge to inner edge, shift is 8. |
| + 0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8, |
| + 1 + 8, 5 + 8, 9 + 8, |
| + 5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8, |
| + 6 + 8, 2 + 8, 10 + 8, |
| + 2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8, |
| + 3 + 8, 7 + 8, 11 + 8, |
| + 7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8, |
| + 4 + 8, 0 + 8, 8 + 8, |
| + |
| + // Draw the inner AA, from inner edge to inner AA line, shift is 16. |
| + 0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16, |
| + 1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16, |
| + 2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16, |
| + 3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16, |
| +}; |
| + |
| +int GrAARectRenderer::aaStrokeRectIndexCount(bool miterStroke) { |
| + return miterStroke ? GR_ARRAY_COUNT(gMiterStrokeAARectIdx) : |
| + GR_ARRAY_COUNT(gBevelStrokeAARectIdx); |
| } |
| -GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu) { |
| - if (NULL == fAAStrokeRectIndexBuffer) { |
| - fAAStrokeRectIndexBuffer = |
| - gpu->createIndexBuffer(sizeof(gStrokeAARectIdx), false); |
| - if (NULL != fAAStrokeRectIndexBuffer) { |
| +GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu, bool miterStroke) { |
| + if (miterStroke) { |
| + if (NULL == fAAMiterStrokeRectIndexBuffer) { |
| + fAAMiterStrokeRectIndexBuffer = |
| + gpu->createIndexBuffer(sizeof(gMiterStrokeAARectIdx), false); |
| + if (NULL != fAAMiterStrokeRectIndexBuffer) { |
| #ifdef SK_DEBUG |
| - bool updated = |
| + bool updated = |
| #endif |
| - fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx, |
| - sizeof(gStrokeAARectIdx)); |
| - GR_DEBUGASSERT(updated); |
| + fAAMiterStrokeRectIndexBuffer->updateData(gMiterStrokeAARectIdx, |
| + sizeof(gMiterStrokeAARectIdx)); |
| + GR_DEBUGASSERT(updated); |
| + } |
| } |
| + return fAAMiterStrokeRectIndexBuffer; |
| + } else { |
| + if (NULL == fAABevelStrokeRectIndexBuffer) { |
| + fAABevelStrokeRectIndexBuffer = |
| + gpu->createIndexBuffer(sizeof(gBevelStrokeAARectIdx), false); |
| + if (NULL != fAABevelStrokeRectIndexBuffer) { |
| +#ifdef SK_DEBUG |
| + bool updated = |
| +#endif |
| + fAABevelStrokeRectIndexBuffer->updateData(gBevelStrokeAARectIdx, |
| + sizeof(gBevelStrokeAARectIdx)); |
| + GR_DEBUGASSERT(updated); |
| + } |
| + } |
| + return fAABevelStrokeRectIndexBuffer; |
| } |
| - return fAAStrokeRectIndexBuffer; |
| } |
| void GrAARectRenderer::geometryFillAARect(GrGpu* gpu, |
| @@ -653,9 +728,10 @@ void GrAARectRenderer::strokeAARect(GrGpu* gpu, |
| const SkRect& rect, |
| const SkMatrix& combinedMatrix, |
| const SkRect& devRect, |
| - SkScalar width, |
| + const SkStrokeRec* stroke, |
| bool useVertexCoverage) { |
| GrVec devStrokeSize; |
| + SkScalar width = stroke->getWidth(); |
| if (width > 0) { |
| devStrokeSize.set(width, width); |
| combinedMatrix.mapVectors(&devStrokeSize, 1); |
| @@ -687,7 +763,13 @@ void GrAARectRenderer::strokeAARect(GrGpu* gpu, |
| SkRect devOutside(devRect); |
| devOutside.outset(rx, ry); |
| - if (spare <= 0) { |
| + bool miterStroke = true; |
| + // small miter limit means right angles show bevel... |
| + if (stroke->getJoin() != SkPaint::kMiter_Join || stroke->getMiter() < SK_ScalarSqrt2) { |
| + miterStroke = false; |
| + } |
| + |
| + if (spare <= 0 && miterStroke) { |
| this->fillAARect(gpu, target, devOutside, SkMatrix::I(), |
| devOutside, useVertexCoverage); |
| return; |
| @@ -696,24 +778,41 @@ void GrAARectRenderer::strokeAARect(GrGpu* gpu, |
| SkRect devInside(devRect); |
| devInside.inset(rx, ry); |
| - this->geometryStrokeAARect(gpu, target, devOutside, devInside, useVertexCoverage); |
| + SkRect devOutsideAssist(devRect); |
| + |
| + // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist) |
| + // to draw the outer of the rect. Because there are 8 vertices on the outer |
| + // edge, while vertex number of inner edge is 4, the same as miter-stroke. |
| + if (!miterStroke) { |
| + devOutside.inset(0, ry); |
| + devOutsideAssist.outset(0, ry); |
| + } |
| + |
| + this->geometryStrokeAARect(gpu, target, devOutside, devOutsideAssist, |
| + devInside, useVertexCoverage, miterStroke); |
| } |
| void GrAARectRenderer::geometryStrokeAARect(GrGpu* gpu, |
| GrDrawTarget* target, |
| const SkRect& devOutside, |
| + const SkRect& devOutsideAssist, |
| const SkRect& devInside, |
| - bool useVertexCoverage) { |
| + bool useVertexCoverage, |
| + bool miterStroke) { |
| GrDrawState* drawState = target->drawState(); |
| set_aa_rect_vertex_attributes(drawState, useVertexCoverage); |
| - GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0); |
| + int innerVertexNum = 4; |
| + int outerVertexNum = miterStroke ? 4 : 8; |
| + int totalVertexNum = (outerVertexNum + innerVertexNum) * 2; |
| + |
| + GrDrawTarget::AutoReleaseGeometry geo(target, totalVertexNum, 0); |
| if (!geo.succeeded()) { |
| GrPrintf("Failed to get space for vertices!\n"); |
| return; |
| } |
| - GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu); |
| + GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu, miterStroke); |
| if (NULL == indexBuffer) { |
| GrPrintf("Failed to create index buffer!\n"); |
| return; |
| @@ -727,9 +826,9 @@ void GrAARectRenderer::geometryStrokeAARect(GrGpu* gpu, |
| // coverage, one on the exterior of the stroke and the other on the interior. |
| // The following pointers refer to the four rects, from outermost to innermost. |
| GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts); |
| - GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize); |
| - GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize); |
| - GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize); |
| + GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + outerVertexNum * vsize); |
| + GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 2 * outerVertexNum * vsize); |
| + GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + (2 * outerVertexNum + innerVertexNum) * vsize); |
| #ifndef SK_IGNORE_THIN_STROKED_RECT_FIX |
| // TODO: this only really works if the X & Y margins are the same all around |
| @@ -737,23 +836,42 @@ void GrAARectRenderer::geometryStrokeAARect(GrGpu* gpu, |
| SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight); |
| inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft); |
| inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop); |
| - inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom); |
| + if (miterStroke) { |
| + inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom); |
| + } else { |
| + inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - devInside.fBottom); |
| + } |
| SkASSERT(inset >= 0); |
| #else |
| SkScalar inset = SK_ScalarHalf; |
| #endif |
| - // outermost |
| - set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf); |
| - // inner two |
| - set_inset_fan(fan1Pos, vsize, devOutside, inset, inset); |
| - set_inset_fan(fan2Pos, vsize, devInside, -inset, -inset); |
| - // innermost |
| - set_inset_fan(fan3Pos, vsize, devInside, SK_ScalarHalf, SK_ScalarHalf); |
| + if (miterStroke) { |
| + // outermost |
| + set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf); |
| + // inner two |
| + set_inset_fan(fan1Pos, vsize, devOutside, inset, inset); |
| + set_inset_fan(fan2Pos, vsize, devInside, -inset, -inset); |
| + // innermost |
| + set_inset_fan(fan3Pos, vsize, devInside, SK_ScalarHalf, SK_ScalarHalf); |
| + } else { |
| + GrPoint* fan0AssistPos = reinterpret_cast<GrPoint*>(verts + 4 * vsize); |
| + GrPoint* fan1AssistPos = reinterpret_cast<GrPoint*>(verts + (outerVertexNum + 4) * vsize); |
| + // outermost |
| + set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf); |
| + set_inset_fan(fan0AssistPos, vsize, devOutsideAssist, -SK_ScalarHalf, -SK_ScalarHalf); |
| + // outer one of the inner two |
| + set_inset_fan(fan1Pos, vsize, devOutside, inset, inset); |
| + set_inset_fan(fan1AssistPos, vsize, devOutsideAssist, inset, inset); |
| + // inner one of the inner two |
| + set_inset_fan(fan2Pos, vsize, devInside, -inset, -inset); |
| + // innermost |
| + set_inset_fan(fan3Pos, vsize, devInside, SK_ScalarHalf, SK_ScalarHalf); |
| + } |
| // The outermost rect has 0 coverage |
| verts += sizeof(GrPoint); |
| - for (int i = 0; i < 4; ++i) { |
| + for (int i = 0; i < outerVertexNum; ++i) { |
| *reinterpret_cast<GrColor*>(verts + i * vsize) = 0; |
| } |
| @@ -777,20 +895,20 @@ void GrAARectRenderer::geometryStrokeAARect(GrGpu* gpu, |
| } |
| } |
| - verts += 4 * vsize; |
| - for (int i = 0; i < 8; ++i) { |
| + verts += outerVertexNum * vsize; |
| + for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) { |
| *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor; |
| } |
| // The innermost rect has 0 coverage |
| - verts += 8 * vsize; |
| - for (int i = 0; i < 4; ++i) { |
| + verts += (outerVertexNum + innerVertexNum) * vsize; |
|
yunchao
2013/11/05 04:58:30
variable 'verts' needs to move 2*outerVertexNum+in
|
| + for (int i = 0; i < innerVertexNum; ++i) { |
| *reinterpret_cast<GrColor*>(verts + i * vsize) = 0; |
| } |
| target->setIndexSourceToBuffer(indexBuffer); |
| - target->drawIndexed(kTriangles_GrPrimitiveType, |
| - 0, 0, 16, aaStrokeRectIndexCount()); |
| + target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, |
| + totalVertexNum, aaStrokeRectIndexCount(miterStroke)); |
| } |
| void GrAARectRenderer::fillAANestedRects(GrGpu* gpu, |
| @@ -801,7 +919,7 @@ void GrAARectRenderer::fillAANestedRects(GrGpu* gpu, |
| SkASSERT(combinedMatrix.rectStaysRect()); |
| SkASSERT(!rects[1].isEmpty()); |
| - SkRect devOutside, devInside; |
| + SkRect devOutside, devOutsideAssist, devInside; |
| combinedMatrix.mapRect(&devOutside, rects[0]); |
| // can't call mapRect for devInside since it calls sort |
| combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2); |
| @@ -811,5 +929,6 @@ void GrAARectRenderer::fillAANestedRects(GrGpu* gpu, |
| return; |
| } |
| - this->geometryStrokeAARect(gpu, target, devOutside, devInside, useVertexCoverage); |
| + this->geometryStrokeAARect(gpu, target, devOutside, devOutsideAssist, |
| + devInside, useVertexCoverage, true); |
| } |