Index: src/gpu/GrContext.cpp |
=================================================================== |
--- src/gpu/GrContext.cpp (revision 8284) |
+++ src/gpu/GrContext.cpp (working copy) |
@@ -12,13 +12,12 @@ |
#include "effects/GrConvolutionEffect.h" |
#include "effects/GrSingleTextureEffect.h" |
#include "effects/GrConfigConversionEffect.h" |
-#include "effects/GrCircleEdgeEffect.h" |
-#include "effects/GrEllipseEdgeEffect.h" |
#include "GrBufferAllocPool.h" |
#include "GrGpu.h" |
#include "GrIndexBuffer.h" |
#include "GrInOrderDrawBuffer.h" |
+#include "GrOvalRenderer.h" |
#include "GrPathRenderer.h" |
#include "GrPathUtils.h" |
#include "GrResourceCache.h" |
@@ -99,6 +98,7 @@ |
fDrawBufferVBAllocPool = NULL; |
fDrawBufferIBAllocPool = NULL; |
fAARectRenderer = NULL; |
+ fOvalRenderer = NULL; |
} |
bool GrContext::init(GrBackend backend, GrBackendContext backendContext) { |
@@ -121,6 +121,7 @@ |
fLastDrawWasBuffered = kNo_BufferedDraw; |
fAARectRenderer = SkNEW(GrAARectRenderer); |
+ fOvalRenderer = SkNEW(GrOvalRenderer); |
fDidTestPMConversions = false; |
@@ -152,6 +153,7 @@ |
delete fDrawBufferIBAllocPool; |
fAARectRenderer->unref(); |
+ fOvalRenderer->unref(); |
fGpu->unref(); |
GrSafeUnref(fPathRendererChain); |
@@ -989,297 +991,21 @@ |
} |
/////////////////////////////////////////////////////////////////////////////// |
-namespace { |
-struct CircleVertex { |
- GrPoint fPos; |
- GrPoint fCenter; |
- SkScalar fOuterRadius; |
- 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(); |
-} |
- |
-} |
- |
void GrContext::drawOval(const GrPaint& paint, |
const GrRect& oval, |
const SkStrokeRec& stroke) { |
- bool isCircle; |
- if (!canDrawOval(paint, oval, &isCircle)) { |
- SkPath path; |
- path.addOval(oval); |
- this->drawPath(paint, path, stroke); |
- return; |
- } |
- |
- if (isCircle) { |
- this->internalDrawCircle(paint, oval, stroke); |
- } else { |
- this->internalDrawOval(paint, oval, stroke); |
- } |
-} |
- |
-bool GrContext::canDrawOval(const GrPaint& paint, const GrRect& oval, bool* isCircle) const { |
- GrAssert(isCircle != NULL); |
- |
- if (!paint.isAntiAlias()) { |
- return false; |
- } |
- |
- // 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 || isAxisAlignedEllipse; |
-} |
- |
-void GrContext::internalDrawOval(const GrPaint& paint, |
- const GrRect& oval, |
- const SkStrokeRec& stroke) { |
-#ifdef SK_DEBUG |
- { |
- // we should have checked for this previously |
- 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 GrRenderTarget* rt = drawState->getRenderTarget(); |
- if (NULL == rt) { |
- return; |
+ if (!fOvalRenderer->drawOval(target, this, paint, oval, stroke)) { |
+ SkPath path; |
+ path.addOval(oval); |
+ this->internalDrawPath(target, paint, path, stroke); |
} |
- |
- 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; |
- } |
- |
- // position + edge |
- static const GrVertexAttrib kVertexAttribs[] = { |
- {kVec2f_GrVertexAttribType, 0}, |
- {kVec4f_GrVertexAttribType, sizeof(GrPoint)} |
- }; |
- drawState->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs)); |
- drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0); |
- GrAssert(sizeof(CircleVertex) == drawState->getVertexSize()); |
- |
- GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0); |
- if (!geo.succeeded()) { |
- GrPrintf("Failed to get space for vertices!\n"); |
- return; |
- } |
- |
- CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices()); |
- |
- GrPoint center = GrPoint::Make(circle.centerX(), circle.centerY()); |
- vm.mapPoints(¢er, 1); |
- |
- 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(); |
- |
- radius = vm.mapRadius(radius); |
- |
- 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); |
- } |
- |
- outerRadius += halfWidth; |
- if (isStroked) { |
- innerRadius = SkMaxScalar(0, radius - halfWidth); |
- } |
- } |
- |
- 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; |
- 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::drawPath(const GrPaint& paint, const SkPath& path, const SkStrokeRec& stroke) { |
if (path.isEmpty()) { |
@@ -1289,33 +1015,26 @@ |
return; |
} |
+ // Note that internalDrawPath may sw-rasterize the path into a scratch texture. |
+ // Scratch textures can be recycled after they are returned to the texture |
+ // cache. This presents a potential hazard for buffered drawing. However, |
+ // the writePixels that uploads to the scratch will perform a flush so we're |
+ // OK. |
+ GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW); |
+ GrDrawState::AutoStageDisable atr(fDrawState); |
+ |
SkRect ovalRect; |
bool isOval = path.isOval(&ovalRect); |
- 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; |
+ if (!isOval || path.isInverseFillType() |
+ || !fOvalRenderer->drawOval(target, this, paint, ovalRect, stroke)) { |
+ this->internalDrawPath(target, paint, path, stroke); |
} |
- |
- this->internalDrawPath(paint, path, stroke); |
} |
-void GrContext::internalDrawPath(const GrPaint& paint, const SkPath& path, |
+void GrContext::internalDrawPath(GrDrawTarget* target, 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 |
- // cache. This presents a potential hazard for buffered drawing. However, |
- // the writePixels that uploads to the scratch will perform a flush so we're |
- // OK. |
- GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW); |
- GrDrawState::AutoStageDisable atr(fDrawState); |
- |
bool prAA = paint.isAntiAlias() && !this->getRenderTarget()->isMultisampled(); |
// An Assumption here is that path renderer would use some form of tweaking |