Moved SW path renderer from GrContext.cpp to GrSoftwarePathRenderer.cpp
http://codereview.appspot.com/6138056/ git-svn-id: http://skia.googlecode.com/svn/trunk@3807 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
a5f406e998
commit
ed4155d610
@ -1268,173 +1268,8 @@ void GrContext::drawVertices(const GrPaint& paint,
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#include "SkDraw.h"
|
||||
#include "SkRasterClip.h"
|
||||
|
||||
namespace {
|
||||
|
||||
SkPath::FillType gr_fill_to_sk_fill(GrPathFill fill) {
|
||||
switch (fill) {
|
||||
case kWinding_PathFill:
|
||||
return SkPath::kWinding_FillType;
|
||||
case kEvenOdd_PathFill:
|
||||
return SkPath::kEvenOdd_FillType;
|
||||
case kInverseWinding_PathFill:
|
||||
return SkPath::kInverseWinding_FillType;
|
||||
case kInverseEvenOdd_PathFill:
|
||||
return SkPath::kInverseEvenOdd_FillType;
|
||||
default:
|
||||
GrCrash("Unexpected fill.");
|
||||
return SkPath::kWinding_FillType;
|
||||
}
|
||||
}
|
||||
|
||||
// gets device coord bounds of path (not considering the fill) and clip. The
|
||||
// path bounds will be a subset of the clip bounds. returns false if
|
||||
// path bounds would be empty.
|
||||
bool get_path_and_clip_bounds(const GrDrawTarget* target,
|
||||
const SkPath& path,
|
||||
const GrVec* translate,
|
||||
GrIRect* pathBounds,
|
||||
GrIRect* clipBounds) {
|
||||
// compute bounds as intersection of rt size, clip, and path
|
||||
const GrRenderTarget* rt = target->getDrawState().getRenderTarget();
|
||||
if (NULL == rt) {
|
||||
return false;
|
||||
}
|
||||
*pathBounds = GrIRect::MakeWH(rt->width(), rt->height());
|
||||
const GrClip& clip = target->getClip();
|
||||
if (clip.hasConservativeBounds()) {
|
||||
clip.getConservativeBounds().roundOut(clipBounds);
|
||||
if (!pathBounds->intersect(*clipBounds)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// pathBounds is currently the rt extent, set clip bounds to that rect.
|
||||
*clipBounds = *pathBounds;
|
||||
}
|
||||
GrRect pathSBounds = path.getBounds();
|
||||
if (!pathSBounds.isEmpty()) {
|
||||
if (NULL != translate) {
|
||||
pathSBounds.offset(*translate);
|
||||
}
|
||||
target->getDrawState().getViewMatrix().mapRect(&pathSBounds,
|
||||
pathSBounds);
|
||||
GrIRect pathIBounds;
|
||||
pathSBounds.roundOut(&pathIBounds);
|
||||
if (!pathBounds->intersect(pathIBounds)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* sw rasterizes path to A8 mask using the context's matrix and uploads to a
|
||||
* scratch texture.
|
||||
*/
|
||||
|
||||
bool sw_draw_path_to_mask_texture(const SkPath& clientPath,
|
||||
const GrIRect& pathDevBounds,
|
||||
GrPathFill fill,
|
||||
GrContext* context,
|
||||
const GrPoint* translate,
|
||||
GrAutoScratchTexture* tex,
|
||||
bool antiAlias) {
|
||||
SkPaint paint;
|
||||
SkPath tmpPath;
|
||||
const SkPath* pathToDraw = &clientPath;
|
||||
if (kHairLine_PathFill == fill) {
|
||||
paint.setStyle(SkPaint::kStroke_Style);
|
||||
paint.setStrokeWidth(SK_Scalar1);
|
||||
} else {
|
||||
paint.setStyle(SkPaint::kFill_Style);
|
||||
SkPath::FillType skfill = gr_fill_to_sk_fill(fill);
|
||||
if (skfill != pathToDraw->getFillType()) {
|
||||
tmpPath = *pathToDraw;
|
||||
tmpPath.setFillType(skfill);
|
||||
pathToDraw = &tmpPath;
|
||||
}
|
||||
}
|
||||
paint.setAntiAlias(antiAlias);
|
||||
paint.setColor(SK_ColorWHITE);
|
||||
|
||||
GrMatrix matrix = context->getMatrix();
|
||||
if (NULL != translate) {
|
||||
matrix.postTranslate(translate->fX, translate->fY);
|
||||
}
|
||||
|
||||
matrix.postTranslate(-pathDevBounds.fLeft * SK_Scalar1,
|
||||
-pathDevBounds.fTop * SK_Scalar1);
|
||||
GrIRect bounds = GrIRect::MakeWH(pathDevBounds.width(),
|
||||
pathDevBounds.height());
|
||||
|
||||
SkBitmap bm;
|
||||
bm.setConfig(SkBitmap::kA8_Config, bounds.fRight, bounds.fBottom);
|
||||
if (!bm.allocPixels()) {
|
||||
return false;
|
||||
}
|
||||
sk_bzero(bm.getPixels(), bm.getSafeSize());
|
||||
|
||||
SkDraw draw;
|
||||
sk_bzero(&draw, sizeof(draw));
|
||||
SkRasterClip rc(bounds);
|
||||
draw.fRC = &rc;
|
||||
draw.fClip = &rc.bwRgn();
|
||||
draw.fMatrix = &matrix;
|
||||
draw.fBitmap = &bm;
|
||||
draw.drawPath(*pathToDraw, paint);
|
||||
|
||||
const GrTextureDesc desc = {
|
||||
kNone_GrTextureFlags,
|
||||
bounds.fRight,
|
||||
bounds.fBottom,
|
||||
kAlpha_8_GrPixelConfig,
|
||||
0 // samples
|
||||
};
|
||||
|
||||
tex->set(context, desc);
|
||||
GrTexture* texture = tex->texture();
|
||||
|
||||
if (NULL == texture) {
|
||||
return false;
|
||||
}
|
||||
SkAutoLockPixels alp(bm);
|
||||
texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
|
||||
bm.getPixels(), bm.rowBytes());
|
||||
return true;
|
||||
}
|
||||
|
||||
void draw_around_inv_path(GrDrawTarget* target,
|
||||
GrDrawState::StageMask stageMask,
|
||||
const GrIRect& clipBounds,
|
||||
const GrIRect& pathBounds) {
|
||||
GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
|
||||
GrRect rect;
|
||||
if (clipBounds.fTop < pathBounds.fTop) {
|
||||
rect.iset(clipBounds.fLeft, clipBounds.fTop,
|
||||
clipBounds.fRight, pathBounds.fTop);
|
||||
target->drawSimpleRect(rect, NULL, stageMask);
|
||||
}
|
||||
if (clipBounds.fLeft < pathBounds.fLeft) {
|
||||
rect.iset(clipBounds.fLeft, pathBounds.fTop,
|
||||
pathBounds.fLeft, pathBounds.fBottom);
|
||||
target->drawSimpleRect(rect, NULL, stageMask);
|
||||
}
|
||||
if (clipBounds.fRight > pathBounds.fRight) {
|
||||
rect.iset(pathBounds.fRight, pathBounds.fTop,
|
||||
clipBounds.fRight, pathBounds.fBottom);
|
||||
target->drawSimpleRect(rect, NULL, stageMask);
|
||||
}
|
||||
if (clipBounds.fBottom > pathBounds.fBottom) {
|
||||
rect.iset(clipBounds.fLeft, pathBounds.fBottom,
|
||||
clipBounds.fRight, clipBounds.fBottom);
|
||||
target->drawSimpleRect(rect, NULL, stageMask);
|
||||
}
|
||||
}
|
||||
|
||||
struct CircleVertex {
|
||||
GrPoint fPos;
|
||||
GrPoint fCenter;
|
||||
@ -1554,58 +1389,6 @@ void GrContext::drawOval(const GrPaint& paint,
|
||||
target->drawNonIndexed(kTriangleStrip_PrimitiveType, 0, 4);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// return true on success; false on failure
|
||||
bool onDrawPath(const SkPath& path,
|
||||
GrPathFill fill,
|
||||
const GrVec* translate,
|
||||
GrDrawTarget* target,
|
||||
GrDrawState::StageMask stageMask,
|
||||
bool antiAlias,
|
||||
GrContext* context) {
|
||||
|
||||
GrAutoScratchTexture ast;
|
||||
GrIRect pathBounds, clipBounds;
|
||||
if (!get_path_and_clip_bounds(target, path, translate,
|
||||
&pathBounds, &clipBounds)) {
|
||||
return true; // path is empty so there is nothing to do
|
||||
}
|
||||
if (sw_draw_path_to_mask_texture(path, pathBounds,
|
||||
fill, context,
|
||||
translate, &ast, antiAlias)) {
|
||||
GrTexture* texture = ast.texture();
|
||||
GrAssert(NULL != texture);
|
||||
GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
|
||||
enum {
|
||||
kPathMaskStage = GrPaint::kTotalStages,
|
||||
};
|
||||
target->drawState()->setTexture(kPathMaskStage, texture);
|
||||
target->drawState()->sampler(kPathMaskStage)->reset();
|
||||
GrScalar w = GrIntToScalar(pathBounds.width());
|
||||
GrScalar h = GrIntToScalar(pathBounds.height());
|
||||
GrRect maskRect = GrRect::MakeWH(w / texture->width(),
|
||||
h / texture->height());
|
||||
const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
|
||||
srcRects[kPathMaskStage] = &maskRect;
|
||||
stageMask |= 1 << kPathMaskStage;
|
||||
GrRect dstRect = GrRect::MakeLTRB(
|
||||
SK_Scalar1* pathBounds.fLeft,
|
||||
SK_Scalar1* pathBounds.fTop,
|
||||
SK_Scalar1* pathBounds.fRight,
|
||||
SK_Scalar1* pathBounds.fBottom);
|
||||
target->drawRect(dstRect, NULL, stageMask, srcRects, NULL);
|
||||
target->drawState()->setTexture(kPathMaskStage, NULL);
|
||||
if (GrIsFillInverted(fill)) {
|
||||
draw_around_inv_path(target, stageMask,
|
||||
clipBounds, pathBounds);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void GrContext::drawPath(const GrPaint& paint, const SkPath& path,
|
||||
GrPathFill fill, const GrPoint* translate) {
|
||||
|
||||
@ -1655,19 +1438,7 @@ void GrContext::internalDrawPath(const GrPaint& paint, const SkPath& path,
|
||||
prAA = false;
|
||||
}
|
||||
|
||||
GrPathRenderer* pr = NULL;
|
||||
if (prAA) {
|
||||
pr = this->getPathRenderer(path, fill, target, true);
|
||||
if (NULL == pr) {
|
||||
if (onDrawPath(path, fill, translate,
|
||||
target, stageMask, prAA, this)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pr = this->getPathRenderer(path, fill, target, false);
|
||||
}
|
||||
|
||||
GrPathRenderer* pr = this->getPathRenderer(path, fill, target, prAA);
|
||||
if (NULL == pr) {
|
||||
#if GR_DEBUG
|
||||
GrPrintf("Unable to find path renderer compatible with path.\n");
|
||||
|
@ -7,21 +7,203 @@
|
||||
*/
|
||||
|
||||
#include "GrSoftwarePathRenderer.h"
|
||||
#include "GrPaint.h"
|
||||
#include "SkPaint.h"
|
||||
#include "GrRenderTarget.h"
|
||||
#include "GrContext.h"
|
||||
#include "SkDraw.h"
|
||||
#include "SkRasterClip.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool GrSoftwarePathRenderer::canDrawPath(const SkPath& path,
|
||||
GrPathFill fill,
|
||||
const GrDrawTarget* target,
|
||||
bool antiAlias) const {
|
||||
if (!antiAlias) {
|
||||
// TODO: the SW renderer can also handle non-AA paths
|
||||
if (!antiAlias || NULL == fContext) {
|
||||
// TODO: We could allow the SW path to also handle non-AA paths but
|
||||
// this would mean that GrDefaultPathRenderer would never be called
|
||||
// (since it appears after the SW renderer in the path renderer
|
||||
// chain). Some testing would need to be done r.e. performance
|
||||
// and consistency of the resulting images before removing
|
||||
// the "!antiAlias" clause from the above test
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: set to true when filled out
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
SkPath::FillType gr_fill_to_sk_fill(GrPathFill fill) {
|
||||
switch (fill) {
|
||||
case kWinding_PathFill:
|
||||
return SkPath::kWinding_FillType;
|
||||
case kEvenOdd_PathFill:
|
||||
return SkPath::kEvenOdd_FillType;
|
||||
case kInverseWinding_PathFill:
|
||||
return SkPath::kInverseWinding_FillType;
|
||||
case kInverseEvenOdd_PathFill:
|
||||
return SkPath::kInverseEvenOdd_FillType;
|
||||
default:
|
||||
GrCrash("Unexpected fill.");
|
||||
return SkPath::kWinding_FillType;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// gets device coord bounds of path (not considering the fill) and clip. The
|
||||
// path bounds will be a subset of the clip bounds. returns false if
|
||||
// path bounds would be empty.
|
||||
bool get_path_and_clip_bounds(const GrDrawTarget* target,
|
||||
const SkPath& path,
|
||||
const GrVec* translate,
|
||||
GrIRect* pathBounds,
|
||||
GrIRect* clipBounds) {
|
||||
// compute bounds as intersection of rt size, clip, and path
|
||||
const GrRenderTarget* rt = target->getDrawState().getRenderTarget();
|
||||
if (NULL == rt) {
|
||||
return false;
|
||||
}
|
||||
*pathBounds = GrIRect::MakeWH(rt->width(), rt->height());
|
||||
const GrClip& clip = target->getClip();
|
||||
if (clip.hasConservativeBounds()) {
|
||||
clip.getConservativeBounds().roundOut(clipBounds);
|
||||
if (!pathBounds->intersect(*clipBounds)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// pathBounds is currently the rt extent, set clip bounds to that rect.
|
||||
*clipBounds = *pathBounds;
|
||||
}
|
||||
GrRect pathSBounds = path.getBounds();
|
||||
if (!pathSBounds.isEmpty()) {
|
||||
if (NULL != translate) {
|
||||
pathSBounds.offset(*translate);
|
||||
}
|
||||
target->getDrawState().getViewMatrix().mapRect(&pathSBounds,
|
||||
pathSBounds);
|
||||
GrIRect pathIBounds;
|
||||
pathSBounds.roundOut(&pathIBounds);
|
||||
if (!pathBounds->intersect(pathIBounds)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* sw rasterizes path to A8 mask using the context's matrix and uploads to a
|
||||
* scratch texture.
|
||||
*/
|
||||
|
||||
bool sw_draw_path_to_mask_texture(const SkPath& clientPath,
|
||||
const GrIRect& pathDevBounds,
|
||||
GrPathFill fill,
|
||||
GrContext* context,
|
||||
const GrPoint* translate,
|
||||
GrAutoScratchTexture* tex,
|
||||
bool antiAlias) {
|
||||
SkPaint paint;
|
||||
SkPath tmpPath;
|
||||
const SkPath* pathToDraw = &clientPath;
|
||||
if (kHairLine_PathFill == fill) {
|
||||
paint.setStyle(SkPaint::kStroke_Style);
|
||||
paint.setStrokeWidth(SK_Scalar1);
|
||||
} else {
|
||||
paint.setStyle(SkPaint::kFill_Style);
|
||||
SkPath::FillType skfill = gr_fill_to_sk_fill(fill);
|
||||
if (skfill != pathToDraw->getFillType()) {
|
||||
tmpPath = *pathToDraw;
|
||||
tmpPath.setFillType(skfill);
|
||||
pathToDraw = &tmpPath;
|
||||
}
|
||||
}
|
||||
paint.setAntiAlias(antiAlias);
|
||||
paint.setColor(SK_ColorWHITE);
|
||||
|
||||
GrMatrix matrix = context->getMatrix();
|
||||
if (NULL != translate) {
|
||||
matrix.postTranslate(translate->fX, translate->fY);
|
||||
}
|
||||
|
||||
matrix.postTranslate(-pathDevBounds.fLeft * SK_Scalar1,
|
||||
-pathDevBounds.fTop * SK_Scalar1);
|
||||
GrIRect bounds = GrIRect::MakeWH(pathDevBounds.width(),
|
||||
pathDevBounds.height());
|
||||
|
||||
SkBitmap bm;
|
||||
bm.setConfig(SkBitmap::kA8_Config, bounds.fRight, bounds.fBottom);
|
||||
if (!bm.allocPixels()) {
|
||||
return false;
|
||||
}
|
||||
sk_bzero(bm.getPixels(), bm.getSafeSize());
|
||||
|
||||
SkDraw draw;
|
||||
sk_bzero(&draw, sizeof(draw));
|
||||
SkRasterClip rc(bounds);
|
||||
draw.fRC = &rc;
|
||||
draw.fClip = &rc.bwRgn();
|
||||
draw.fMatrix = &matrix;
|
||||
draw.fBitmap = &bm;
|
||||
draw.drawPath(*pathToDraw, paint);
|
||||
|
||||
const GrTextureDesc desc = {
|
||||
kNone_GrTextureFlags,
|
||||
bounds.fRight,
|
||||
bounds.fBottom,
|
||||
kAlpha_8_GrPixelConfig,
|
||||
0 // samples
|
||||
};
|
||||
|
||||
tex->set(context, desc);
|
||||
GrTexture* texture = tex->texture();
|
||||
|
||||
if (NULL == texture) {
|
||||
return false;
|
||||
}
|
||||
SkAutoLockPixels alp(bm);
|
||||
texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
|
||||
bm.getPixels(), bm.rowBytes());
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void draw_around_inv_path(GrDrawTarget* target,
|
||||
GrDrawState::StageMask stageMask,
|
||||
const GrIRect& clipBounds,
|
||||
const GrIRect& pathBounds) {
|
||||
GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
|
||||
GrRect rect;
|
||||
if (clipBounds.fTop < pathBounds.fTop) {
|
||||
rect.iset(clipBounds.fLeft, clipBounds.fTop,
|
||||
clipBounds.fRight, pathBounds.fTop);
|
||||
target->drawSimpleRect(rect, NULL, stageMask);
|
||||
}
|
||||
if (clipBounds.fLeft < pathBounds.fLeft) {
|
||||
rect.iset(clipBounds.fLeft, pathBounds.fTop,
|
||||
pathBounds.fLeft, pathBounds.fBottom);
|
||||
target->drawSimpleRect(rect, NULL, stageMask);
|
||||
}
|
||||
if (clipBounds.fRight > pathBounds.fRight) {
|
||||
rect.iset(pathBounds.fRight, pathBounds.fTop,
|
||||
clipBounds.fRight, pathBounds.fBottom);
|
||||
target->drawSimpleRect(rect, NULL, stageMask);
|
||||
}
|
||||
if (clipBounds.fBottom > pathBounds.fBottom) {
|
||||
rect.iset(clipBounds.fLeft, pathBounds.fBottom,
|
||||
clipBounds.fRight, clipBounds.fBottom);
|
||||
target->drawSimpleRect(rect, NULL, stageMask);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// return true on success; false on failure
|
||||
bool GrSoftwarePathRenderer::onDrawPath(const SkPath& path,
|
||||
GrPathFill fill,
|
||||
const GrVec* translate,
|
||||
@ -29,7 +211,48 @@ bool GrSoftwarePathRenderer::onDrawPath(const SkPath& path,
|
||||
GrDrawState::StageMask stageMask,
|
||||
bool antiAlias) {
|
||||
|
||||
// TODO: move onDrawPath routine (& its helpers) here from GrContext.cpp
|
||||
if (NULL == fContext) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GrAutoScratchTexture ast;
|
||||
GrIRect pathBounds, clipBounds;
|
||||
if (!get_path_and_clip_bounds(target, path, translate,
|
||||
&pathBounds, &clipBounds)) {
|
||||
return true; // path is empty so there is nothing to do
|
||||
}
|
||||
if (sw_draw_path_to_mask_texture(path, pathBounds,
|
||||
fill, fContext,
|
||||
translate, &ast, antiAlias)) {
|
||||
GrTexture* texture = ast.texture();
|
||||
GrAssert(NULL != texture);
|
||||
GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
|
||||
enum {
|
||||
kPathMaskStage = GrPaint::kTotalStages,
|
||||
};
|
||||
target->drawState()->setTexture(kPathMaskStage, texture);
|
||||
target->drawState()->sampler(kPathMaskStage)->reset();
|
||||
GrScalar w = GrIntToScalar(pathBounds.width());
|
||||
GrScalar h = GrIntToScalar(pathBounds.height());
|
||||
GrRect maskRect = GrRect::MakeWH(w / texture->width(),
|
||||
h / texture->height());
|
||||
const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
|
||||
srcRects[kPathMaskStage] = &maskRect;
|
||||
stageMask |= 1 << kPathMaskStage;
|
||||
GrRect dstRect = GrRect::MakeLTRB(
|
||||
SK_Scalar1* pathBounds.fLeft,
|
||||
SK_Scalar1* pathBounds.fTop,
|
||||
SK_Scalar1* pathBounds.fRight,
|
||||
SK_Scalar1* pathBounds.fBottom);
|
||||
target->drawRect(dstRect, NULL, stageMask, srcRects, NULL);
|
||||
target->drawState()->setTexture(kPathMaskStage, NULL);
|
||||
if (GrIsFillInverted(fill)) {
|
||||
draw_around_inv_path(target, stageMask,
|
||||
clipBounds, pathBounds);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user