Move alpha-ramp AA to GrContext, detect cases when AA is applied via other methods (smooth lines, MSAA) or rect falls on integer coords and skip the alpha ramp path. Use pre-fab index buffer for alpha-ramped fill rects and stroke rects.

Review URL: http://codereview.appspot.com/4449047/

git-svn-id: http://skia.googlecode.com/svn/trunk@1169 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
bsalomon@google.com 2011-04-25 12:43:45 +00:00
Родитель e624caf6c3
Коммит 205d46067a
12 изменённых файлов: 625 добавлений и 183 удалений

Просмотреть файл

@ -568,8 +568,26 @@ private:
GrIndexBufferAllocPool* fDrawBufferIBAllocPool;
GrInOrderDrawBuffer* fDrawBuffer;
GrIndexBuffer* fAAFillRectIndexBuffer;
GrIndexBuffer* fAAStrokeRectIndexBuffer;
GrContext(GrGpu* gpu);
void fillAARect(GrDrawTarget* target,
const GrPaint& paint,
const GrRect& devRect);
void strokeAARect(GrDrawTarget* target,
const GrPaint& paint,
const GrRect& devRect,
const GrVec& devStrokeSize);
inline int aaFillRectIndexCount() const;
GrIndexBuffer* aaFillRectIndexBuffer();
inline int aaStrokeRectIndexCount() const;
GrIndexBuffer* aaStrokeRectIndexBuffer();
void setupDrawBuffer();
void flushDrawBuffer();

Просмотреть файл

@ -272,6 +272,12 @@ public:
*/
bool supportsBufferLocking() const { return fBufferLockSupport; }
/**
* Does the 3D API support anti-aliased lines. If so then line primitive
* types will use this functionality when the AA state flag is set.
*/
bool supportsAALines() const { return fAALineSupport; }
/**
* Gets the minimum width of a render target. If a texture/rt is created
* with a width less than this size the GrGpu object will clamp it to this
@ -445,6 +451,7 @@ protected:
bool fNPOTRenderTargetSupport;
bool fTwoSidedStencilSupport;
bool fStencilWrapOpsSupport;
bool fAALineSupport;
// set by subclass to true if index and vertex buffers can be locked, false
// otherwise.

Просмотреть файл

@ -254,6 +254,21 @@ public:
}
}
/**
* Transforms a vector by the matrix. Doesn't handle cases when a
* homogeneous vector maps to a point (i.e. perspective transform).
* In this case the desired answer is dependent on where the tail of
* the vector is in space.
*/
void mapVec(GrVec* vec) {
GrAssert(!this->hasPerspective());
if (!this->isIdentity()) {
GrScalar x = vec->fX;
vec->fX = (*this)[kScaleX] * x + (*this)[kSkewX] * vec->fY;
vec->fY = (*this)[kSkewY ] * x + (*this)[kScaleY] * vec->fY;
}
}
/**
* Transform the 4 corners of the src rect, and return the bounding rect
* in the dst rect. Note: src and dst may point to the same memory.
@ -279,6 +294,11 @@ public:
*/
bool isIdentity() const;
/**
* Do axis-aligned lines stay axis aligned? May do 90 degree rotation / mirroring.
*/
bool preservesAxisAlignment() const;
/**
* Calculates the maximum stretching factor of the matrix. Only defined if
* the matrix does not have perspective.

Просмотреть файл

@ -154,6 +154,14 @@ public:
fY = y;
}
/**
* set this to (abs(v.x), abs(v.y))
*/
void setAbs(const GrVec& v) {
fX = GrScalarAbs(v.fX);
fY = GrScalarAbs(v.fY);
}
/**
* set vector to point from a to b.
*/

Просмотреть файл

@ -205,6 +205,14 @@ struct GrRect {
return (fLeft > fRight) || (fTop > fBottom);
}
/**
* Returns true if the rects edges are integer-aligned.
*/
bool isIRect() const {
return GrScalarIsInt(fLeft) && GrScalarIsInt(fTop) &&
GrScalarIsInt(fRight) && GrScalarIsInt(fBottom);
}
/**
* Does this rect contain a point.
*/
@ -363,6 +371,22 @@ struct GrRect {
return pts + 4;
}
/**
* Swaps (left and right) and/or (top and bottom) if they are inverted
*/
void sort() {
if (fLeft > fRight) {
GrScalar temp = fLeft;
fLeft = fRight;
fRight = temp;
}
if (fTop > fBottom) {
GrScalar temp = fTop;
fTop = fBottom;
fBottom = temp;
}
}
bool operator ==(const GrRect& r) const {
return fLeft == r.fLeft &&
fTop == r.fTop &&

Просмотреть файл

@ -56,11 +56,19 @@
*/
#define GrFloatToFixed(x) ((GrFixed)((x) * GR_Fixed1))
inline GrFixed GrFixedAbs(GrFixed x) {
static inline GrFixed GrFixedAbs(GrFixed x) {
int32_t s = (x & 0x80000000) >> 31;
return (GrFixed)(((int32_t)x ^ s) - s);
}
static inline bool GrFixedIsInt(GrFixed x) {
return 0 == (x & 0xffff);
}
static inline bool GrFloatIsInt(float x) {
return x == (float)(int)x;
}
///////////////////////////////////////////////////////////////////////////////
#if GR_SCALAR_IS_FIXED
@ -72,6 +80,7 @@ inline GrFixed GrFixedAbs(GrFixed x) {
#define GrScalarHalf(x) ((x) >> 1)
#define GrScalarAve(x,y) (((x)+(y)) >> 1)
#define GrScalarAbs(x) GrFixedAbs(x)
#define GrScalarIsInt GrFixedIsInt
#define GR_Scalar1 GR_Fixed1
#define GR_ScalarHalf GR_FixedHalf
#define GR_ScalarMax GR_FixedMax
@ -85,6 +94,7 @@ inline GrFixed GrFixedAbs(GrFixed x) {
#define GrScalarHalf(x) ((x) * 0.5f)
#define GrScalarAbs(x) fabsf(x)
#define GrScalarAve(x,y) (((x) + (y)) * 0.5f)
#define GrScalarIsInt GrFloatIsInt
#define GR_Scalar1 1.f
#define GR_ScalarHalf 0.5f
#define GR_ScalarMax (FLT_MAX)

Просмотреть файл

@ -58,29 +58,38 @@ GrContext* GrContext::CreateGLShaderContext() {
GrContext::~GrContext() {
this->flush();
fGpu->unref();
delete fTextureCache;
delete fFontCache;
delete fDrawBuffer;
delete fDrawBufferVBAllocPool;
delete fDrawBufferIBAllocPool;
GrSafeUnref(fCustomPathRenderer);
GrSafeUnref(fAAFillRectIndexBuffer);
GrSafeUnref(fAAStrokeRectIndexBuffer);
fGpu->unref();
}
void GrContext::contextLost() {
// abandon first to so destructors
// don't try to free the resources in the API.
fGpu->abandonResources();
delete fDrawBuffer;
fDrawBuffer = NULL;
delete fDrawBufferVBAllocPool;
fDrawBufferVBAllocPool = NULL;
delete fDrawBufferIBAllocPool;
fDrawBufferIBAllocPool = NULL;
GrSafeSetNull(fAAFillRectIndexBuffer);
GrSafeSetNull(fAAStrokeRectIndexBuffer);
fTextureCache->removeAll();
fFontCache->freeAll();
fGpu->markContextDirty();
fGpu->abandonResources();
this->setupDrawBuffer();
}
@ -348,14 +357,17 @@ void GrContext::drawPaint(const GrPaint& paint) {
this->drawRect(paint, r);
}
////////////////////////////////////////////////////////////////////////////////
/* create a triangle strip that strokes the specified triangle. There are 8
unique vertices, but we repreat the last 2 to close up. Alternatively we
could use an indices array, and then only send 8 verts, but not sure that
would be faster.
*/
static void setStrokeRectStrip(GrPoint verts[10], const GrRect& rect,
static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
GrScalar width) {
const GrScalar rad = GrScalarHalf(width);
rect.sort();
verts[0].set(rect.fLeft + rad, rect.fTop + rad);
verts[1].set(rect.fLeft - rad, rect.fTop - rad);
@ -369,6 +381,235 @@ static void setStrokeRectStrip(GrPoint verts[10], const GrRect& rect,
verts[9] = verts[1];
}
static GrColor getColorForMesh(const GrPaint& paint) {
if (NULL == paint.getTexture()) {
return paint.fColor;
} else {
unsigned a = GrColorUnpackA(paint.fColor);
return GrColorPackRGBA(a, a, a, a);
}
}
static void setInsetFan(GrPoint* pts, size_t stride,
const GrRect& r, GrScalar dx, GrScalar dy) {
pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
}
static const uint16_t gFillAARectIdx[] = {
0, 1, 5, 5, 4, 0,
1, 2, 6, 6, 5, 1,
2, 3, 7, 7, 6, 2,
3, 0, 4, 4, 7, 3,
4, 5, 6, 6, 7, 4,
};
int GrContext::aaFillRectIndexCount() const {
return GR_ARRAY_COUNT(gFillAARectIdx);
}
GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
if (NULL == fAAFillRectIndexBuffer) {
fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
false);
GrAssert(NULL != fAAFillRectIndexBuffer);
#if GR_DEBUG
bool updated =
#endif
fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
sizeof(gFillAARectIdx));
GR_DEBUGASSERT(updated);
}
return fAAFillRectIndexBuffer;
}
static const uint16_t gStrokeAARectIdx[] = {
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,
3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
};
int GrContext::aaStrokeRectIndexCount() const {
return GR_ARRAY_COUNT(gStrokeAARectIdx);
}
GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
if (NULL == fAAStrokeRectIndexBuffer) {
fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
false);
GrAssert(NULL != fAAStrokeRectIndexBuffer);
#if GR_DEBUG
bool updated =
#endif
fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
sizeof(gStrokeAARectIdx));
GR_DEBUGASSERT(updated);
}
return fAAStrokeRectIndexBuffer;
}
void GrContext::fillAARect(GrDrawTarget* target,
const GrPaint& paint,
const GrRect& devRect) {
GrVertexLayout layout = GrDrawTarget::kColor_VertexLayoutBit;
if (NULL != paint.getTexture()) {
layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
}
size_t vsize = GrDrawTarget::VertexSize(layout);
GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
verts += sizeof(GrPoint);
for (int i = 0; i < 4; ++i) {
*reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
}
GrColor innerColor = getColorForMesh(paint);
verts += 4 * vsize;
for (int i = 0; i < 4; ++i) {
*reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
}
target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer());
target->drawIndexed(kTriangles_PrimitiveType, 0,
0, 8, this->aaFillRectIndexCount());
}
void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
const GrRect& devRect, const GrVec& devStrokeSize) {
const GrScalar& dx = devStrokeSize.fX;
const GrScalar& dy = devStrokeSize.fY;
const GrScalar rx = GrMul(dx, GR_ScalarHalf);
const GrScalar ry = GrMul(dy, GR_ScalarHalf);
GrVertexLayout layout = GrDrawTarget::kColor_VertexLayoutBit;
if (NULL != paint.getTexture()) {
layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
}
GrScalar spare;
{
GrScalar w = devRect.width() - dx;
GrScalar h = devRect.height() - dy;
spare = GrMin(w, h);
}
if (spare <= 0) {
GrRect r(devRect);
r.inset(-rx, -ry);
fillAARect(target, paint, r);
return;
}
size_t vsize = GrDrawTarget::VertexSize(layout);
GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
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);
setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
verts += sizeof(GrPoint);
for (int i = 0; i < 4; ++i) {
*reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
}
GrColor innerColor = getColorForMesh(paint);
verts += 4 * vsize;
for (int i = 0; i < 8; ++i) {
*reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
}
verts += 8 * vsize;
for (int i = 0; i < 8; ++i) {
*reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
}
target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer());
target->drawIndexed(kTriangles_PrimitiveType,
0, 0, 16, aaStrokeRectIndexCount());
}
static bool apply_aa_to_rect(GrDrawTarget* target,
GrGpu* gpu,
const GrPaint& paint,
const GrRect& rect,
GrScalar width,
const GrMatrix* matrix,
GrMatrix* combinedMatrix,
GrRect* devRect) {
// we use a simple alpha ramp to do aa on axis-aligned rects
// do AA with alpha ramp if the caller requested AA, the rect
// will be axis-aligned,the render target is not
// multisampled, and the rect won't land on integer coords.
if (!paint.fAntiAlias) {
return false;
}
if (target->getRenderTarget()->isMultisampled()) {
return false;
}
if (0 == width && gpu->supportsAALines()) {
return false;
}
if (!target->getViewMatrix().preservesAxisAlignment()) {
return false;
}
if (NULL != matrix &&
!matrix->preservesAxisAlignment()) {
return false;
}
*combinedMatrix = target->getViewMatrix();
if (NULL != matrix) {
combinedMatrix->preConcat(*matrix);
GrAssert(combinedMatrix->preservesAxisAlignment());
}
combinedMatrix->mapRect(devRect, rect);
devRect->sort();
if (width < 0) {
return !devRect->isIRect();
} else {
return true;
}
}
void GrContext::drawRect(const GrPaint& paint,
const GrRect& rect,
GrScalar width,
@ -378,13 +619,43 @@ void GrContext::drawRect(const GrPaint& paint,
GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
GrRect devRect = rect;
GrMatrix combinedMatrix;
bool doAA = apply_aa_to_rect(target, fGpu, paint, rect, width, matrix,
&combinedMatrix, &devRect);
if (doAA) {
GrDrawTarget::AutoViewMatrixRestore avm(target);
if (textured) {
GrMatrix inv;
if (combinedMatrix.invert(&inv)) {
target->preConcatSamplerMatrix(0, inv);
}
}
target->setViewMatrix(GrMatrix::I());
if (width >= 0) {
GrVec strokeSize;;
if (width > 0) {
strokeSize.set(width, width);
combinedMatrix.mapVec(&strokeSize);
strokeSize.setAbs(strokeSize);
} else {
strokeSize.set(GR_Scalar1, GR_Scalar1);
}
strokeAARect(target, paint, devRect, strokeSize);
} else {
fillAARect(target, paint, devRect);
}
return;
}
if (width >= 0) {
// TODO: consider making static vertex buffers for these cases.
// Hairline could be done by just adding closing vertex to
// unitSquareVertexBuffer()
GrVertexLayout layout = (textured) ?
GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
0;
GrVertexLayout layout = textured ?
GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
0;
static const int worstCaseVertCount = 10;
GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
@ -415,7 +686,9 @@ void GrContext::drawRect(const GrPaint& paint,
if (NULL != matrix) {
avmr.set(target);
target->preConcatViewMatrix(*matrix);
target->preConcatSamplerMatrix(0, *matrix);
if (textured) {
target->preConcatSamplerMatrix(0, *matrix);
}
}
target->drawNonIndexed(primType, 0, vertCount);
@ -429,8 +702,8 @@ void GrContext::drawRect(const GrPaint& paint,
GrDrawTarget::AutoViewMatrixRestore avmr(target);
GrMatrix m;
m.setAll(rect.width(), 0, rect.fLeft,
0, rect.height(), rect.fTop,
0, 0, GrMatrix::I()[8]);
0, rect.height(), rect.fTop,
0, 0, GrMatrix::I()[8]);
if (NULL != matrix) {
m.postConcat(*matrix);
@ -819,6 +1092,9 @@ GrContext::GrContext(GrGpu* gpu) :
fDrawBufferVBAllocPool = NULL;
fDrawBufferIBAllocPool = NULL;
fAAFillRectIndexBuffer = NULL;
fAAStrokeRectIndexBuffer = NULL;
this->setupDrawBuffer();
}

Просмотреть файл

@ -361,6 +361,8 @@ GrGpuGL::GrGpuGL() {
}
}
fAALineSupport = GR_GL_SUPPORT_DESKTOP;
////////////////////////////////////////////////////////////////////////////
// Experiments to determine limitations that can't be queried. TODO: Make
// these a preprocess that generate some compile time constants.

Просмотреть файл

@ -259,6 +259,26 @@ bool GrMatrix::isIdentity() const {
}
bool GrMatrix::preservesAxisAlignment() const {
// check if matrix is trans and scale only
static const int gAllowedMask1 = kScale_TypeBit | kTranslate_TypeBit;
if (!(~gAllowedMask1 & fTypeMask)) {
return true;
}
// check matrix is trans and skew only (0 scale)
static const int gAllowedMask2 = kScale_TypeBit | kSkew_TypeBit |
kTranslate_TypeBit | kZeroScale_TypeBit;
if (!(~gAllowedMask2 & fTypeMask) && (kZeroScale_TypeBit & fTypeMask)) {
return true;
}
return false;
}
GrScalar GrMatrix::getMaxStretch() const {
if (fTypeMask & kPerspective_TypeBit) {

Просмотреть файл

@ -1444,6 +1444,7 @@
'../samplecode/SamplePicture.cpp',
'../samplecode/SamplePoints.cpp',
'../samplecode/SamplePolyToPoly.cpp',
'../samplecode/SampleAARects.cpp',
'../samplecode/SampleRegion.cpp',
'../samplecode/SampleRepeatTile.cpp',
'../samplecode/SampleShaders.cpp',

Просмотреть файл

@ -0,0 +1,197 @@
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
#include "SkDevice.h"
#include "SkPaint.h"
#include "SkShader.h"
static SkBitmap createBitmap(int n) {
SkBitmap bitmap;
bitmap.setConfig(SkBitmap::kARGB_8888_Config, n, n);
bitmap.allocPixels();
bitmap.eraseColor(SK_ColorGREEN);
SkCanvas canvas(bitmap);
SkRect r;
r.set(0, 0, SkIntToScalar(n), SkIntToScalar(n));
SkPaint paint;
paint.setAntiAlias(true);
paint.setColor(SK_ColorRED);
canvas.drawOval(r, paint);
paint.setColor(SK_ColorBLUE);
paint.setStrokeWidth(SkIntToScalar(n)/15);
paint.setStyle(SkPaint::kStroke_Style);
canvas.drawLine(0, 0, r.fRight, r.fBottom, paint);
canvas.drawLine(0, r.fBottom, r.fRight, 0, paint);
return bitmap;
}
class AARectView : public SkView {
SkBitmap fBitmap;
enum {
N = 64
};
public:
AARectView() {
fBitmap = createBitmap(N);
fWidth = N;
}
protected:
// overrides from SkEventSink
virtual bool onQuery(SkEvent* evt) {
if (SampleCode::TitleQ(*evt)) {
SampleCode::TitleR(evt, "AA Rects");
return true;
}
return this->INHERITED::onQuery(evt);
}
void drawBG(SkCanvas* canvas) {
canvas->drawColor(SK_ColorWHITE);
}
virtual void onDraw(SkCanvas* canvas) {
this->drawBG(canvas);
canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
SkPaint bluePaint;
bluePaint.setARGB(0xff, 0x0, 0x0, 0xff);
SkPaint bmpPaint;
SkShader* bmpShader = SkShader::CreateBitmapShader(fBitmap, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode);
bmpPaint.setShader(bmpShader);
bmpShader->unref();
bluePaint.setStrokeWidth(3);
bmpPaint.setStrokeWidth(3);
SkPaint paints[] = { bluePaint, bmpPaint };
SkRect rect;
SkScalar dx = SkIntToScalar(80);
SkScalar dy = SkIntToScalar(100);
SkMatrix matrix;
for (int p = 0; p < SK_ARRAY_COUNT(paints); ++p) {
for (int stroke = 0; stroke < 2; ++stroke) {
paints[p].setStyle(stroke ? SkPaint::kStroke_Style : SkPaint::kFill_Style);
for (int a = 0; a < 3; ++ a) {
paints[p].setAntiAlias(a > 0);
paints[p].setAlpha(a > 1 ? 0x80 : 0xff);
canvas->save();
rect = SkRect::MakeLTRB(SkFloatToScalar(0.f),
SkFloatToScalar(0.f),
SkFloatToScalar(40.f),
SkFloatToScalar(40.f));
canvas->drawRect(rect, paints[p]);
canvas->translate(dx, 0);
rect = SkRect::MakeLTRB(SkFloatToScalar(0.5f),
SkFloatToScalar(0.5f),
SkFloatToScalar(40.5f),
SkFloatToScalar(40.5f));
canvas->drawRect(rect, paints[p]);
canvas->translate(dx, 0);
rect = SkRect::MakeLTRB(SkFloatToScalar(0.5f),
SkFloatToScalar(0.5f),
SkFloatToScalar(40.f),
SkFloatToScalar(40.f));
canvas->drawRect(rect, paints[p]);
canvas->translate(dx, 0);
rect = SkRect::MakeLTRB(SkFloatToScalar(0.75f),
SkFloatToScalar(0.75f),
SkFloatToScalar(40.75f),
SkFloatToScalar(40.75f));
canvas->drawRect(rect, paints[p]);
canvas->translate(dx, 0);
canvas->save();
canvas->translate(SkFloatToScalar(.33f), SkFloatToScalar(.67f));
rect = SkRect::MakeLTRB(SkFloatToScalar(0.0f),
SkFloatToScalar(0.0f),
SkFloatToScalar(40.0f),
SkFloatToScalar(40.0f));
canvas->drawRect(rect, paints[p]);
canvas->restore();
canvas->translate(dx, 0);
canvas->save();
matrix.setRotate(SkFloatToScalar(45.f));
canvas->concat(matrix);
canvas->translate(SkFloatToScalar(20.0f / sqrtf(2.f)),
SkFloatToScalar(20.0f / sqrtf(2.f)));
rect = SkRect::MakeLTRB(SkFloatToScalar(-20.0f),
SkFloatToScalar(-20.0f),
SkFloatToScalar(20.0f),
SkFloatToScalar(20.0f));
canvas->drawRect(rect, paints[p]);
canvas->restore();
canvas->translate(dx, 0);
canvas->save();
canvas->rotate(SkFloatToScalar(90.f));
rect = SkRect::MakeLTRB(SkFloatToScalar(0.0f),
SkFloatToScalar(0.0f),
SkFloatToScalar(40.0f),
SkFloatToScalar(-40.0f));
canvas->drawRect(rect, paints[p]);
canvas->restore();
canvas->translate(dx, 0);
canvas->save();
canvas->rotate(SkFloatToScalar(90.f));
rect = SkRect::MakeLTRB(SkFloatToScalar(0.5f),
SkFloatToScalar(0.5f),
SkFloatToScalar(40.5f),
SkFloatToScalar(-40.5f));
canvas->drawRect(rect, paints[p]);
canvas->restore();
canvas->translate(dx, 0);
canvas->save();
matrix.setScale(SkFloatToScalar(-1.f), SkFloatToScalar(-1.f));
canvas->concat(matrix);
rect = SkRect::MakeLTRB(SkFloatToScalar(0.5f),
SkFloatToScalar(0.5f),
SkFloatToScalar(-40.5f),
SkFloatToScalar(-40.5f));
canvas->drawRect(rect, paints[p]);
canvas->restore();
canvas->translate(dx, 0);
canvas->save();
matrix.setScale(SkFloatToScalar(2.1f), SkFloatToScalar(4.1f));
canvas->concat(matrix);
rect = SkRect::MakeLTRB(SkFloatToScalar(0.1f),
SkFloatToScalar(0.1f),
SkFloatToScalar(19.1f),
SkFloatToScalar(9.1f));
canvas->drawRect(rect, paints[p]);
canvas->restore();
canvas->translate(dx, 0);
canvas->restore();
canvas->translate(0, dy);
}
}
}
}
private:
int fWidth;
typedef SkView INHERITED;
};
//////////////////////////////////////////////////////////////////////////////
static SkView* MyFactory() { return new AARectView; }
static SkViewRegister reg(MyFactory);

Просмотреть файл

@ -653,178 +653,37 @@ void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
///////////////////////////////////////////////////////////////////////////////
static void setInsetFan(GrPoint pts[4], const GrRect& r,
GrScalar dx, GrScalar dy) {
pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy);
}
static GrColor getColorForMesh(const GrPaint& paint) {
if (NULL == paint.getTexture()) {
return paint.fColor;
} else {
unsigned a = GrColorUnpackA(paint.fColor);
return GrColorPackRGBA(a, a, a, a);
}
}
static const uint16_t gFillAARectIdx1[] = {
0, 1, 5, 5, 4, 0,
1, 2, 6, 6, 5, 1,
2, 3, 7, 7, 6, 2,
3, 0, 4, 4, 7, 3,
4, 5, 6, 6, 7, 4,
};
static void fillDevAARect(GrContext* ctx, const GrPaint& paint,
const GrRect& rect) {
if (rect.isEmpty()) {
return;
}
GrAutoMatrix avm(ctx, GrMatrix::I());
GrPoint verts[8];
GrPoint* texs = NULL;
GrColor colors[8];
setInsetFan(&verts[ 0], rect, -0.5f, -0.5f);
setInsetFan(&verts[ 4], rect, 0.5f, 0.5f);
sk_memset32(&colors[ 0], 0, 4);
sk_memset32(&colors[ 4], getColorForMesh(paint), 4);
ctx->drawVertices(paint, kTriangles_PrimitiveType,
8, verts, texs, colors,
gFillAARectIdx1, SK_ARRAY_COUNT(gFillAARectIdx1));
}
static const uint16_t gStrokeAARectIdx[] = {
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,
3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
};
static void strokeDevAARect(GrContext* ctx, const GrPaint& paint,
const GrRect& rect, const SkPoint& strokeSize) {
const GrScalar dx = SkScalarToGrScalar(strokeSize.fX);
const GrScalar dy = SkScalarToGrScalar(strokeSize.fY);
const GrScalar rx = dx * 0.5f;
const GrScalar ry = dy * 0.5f;
GrScalar spare;
{
GrScalar w = rect.width() - dx;
GrScalar h = rect.height() - dy;
spare = GrMin(w, h);
}
if (spare <= 0) {
GrRect r(rect);
r.inset(-rx, -ry);
fillDevAARect(ctx, paint, r);
return;
}
GrAutoMatrix avm(ctx, GrMatrix::I());
GrPoint verts[16];
GrPoint* texs = NULL;
GrColor colors[16];
setInsetFan(&verts[ 0], rect, -rx - 0.5f, -ry - 0.5f);
setInsetFan(&verts[ 4], rect, -rx + 0.5f, -ry + 0.5f);
setInsetFan(&verts[ 8], rect, rx - 0.5f, ry - 0.5f);
setInsetFan(&verts[12], rect, rx + 0.5f, ry + 0.5f);
sk_memset32(&colors[ 0], 0, 4);
sk_memset32(&colors[ 4], getColorForMesh(paint), 8);
sk_memset32(&colors[12], 0, 4);
ctx->drawVertices(paint, kTriangles_PrimitiveType,
16, verts, texs, colors,
gStrokeAARectIdx, SK_ARRAY_COUNT(gStrokeAARectIdx));
}
/*
* If the paint has a texture, preconcat the ctx's inverse, since when we
* draw verts which are already in device coordinates, we need to "undo" that
* before we run our vertex shaders, which expect the coordinates to be local.
*/
static void preConcatInverseToTextureMatrix(GrContext* ctx, GrPaint* paint) {
if (paint->getTexture()) {
GrMatrix inverse;
if (ctx->getMatrix().invert(&inverse)) {
paint->fSampler.preConcatMatrix(inverse);
}
}
}
void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
const SkPaint& paint) {
CHECK_SHOULD_DRAW(draw);
const SkMatrix& matrix = *draw.fMatrix;
SkPoint strokeSize;
SkDraw::RectType type = SkDraw::ComputeRectType(paint, matrix, &strokeSize);
bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;
SkScalar width = paint.getStrokeWidth();
if (SkDraw::kPath_RectType == type) {
/*
We have special code for hairline strokes, miter-strokes, and fills.
Anything else we just call our path code.
*/
bool usePath = doStroke && width > 0 &&
paint.getStrokeJoin() != SkPaint::kMiter_Join;
// another reason we might need to call drawPath...
if (paint.getMaskFilter()) {
usePath = true;
}
if (usePath) {
SkPath path;
path.addRect(rect);
this->drawPath(draw, path, paint, NULL, true);
} else {
GrPaint grPaint;
SkAutoCachedTexture act;
if (!this->skPaint2GrPaintShader(paint, &act, matrix, &grPaint)) {
return;
}
bool doAA = paint.isAntiAlias();
if (SkDraw::kHair_RectType == type && doAA) {
strokeSize.set(SK_Scalar1, SK_Scalar1);
type = SkDraw::kStroke_RectType;
}
switch (type) {
case SkDraw::kHair_RectType:
SkASSERT(!doAA);
fContext->drawRect(grPaint, Sk2Gr(rect), 0);
break;
case SkDraw::kFill_RectType:
if (doAA) {
SkRect devRect;
matrix.mapRect(&devRect, rect);
preConcatInverseToTextureMatrix(fContext, &grPaint);
fillDevAARect(fContext, grPaint, Sk2Gr(devRect));
} else {
fContext->drawRect(grPaint, Sk2Gr(rect), -1);
}
break;
case SkDraw::kStroke_RectType:
if (doAA) {
SkRect devRect;
matrix.mapRect(&devRect, rect);
preConcatInverseToTextureMatrix(fContext, &grPaint);
strokeDevAARect(fContext, grPaint, Sk2Gr(devRect), strokeSize);
} else {
fContext->drawRect(grPaint, Sk2Gr(rect), paint.getStrokeWidth());
}
break;
default:
SkASSERT(!"bad value for RectType");
}
return;
}
GrPaint grPaint;
SkAutoCachedTexture act;
if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
return;
}
fContext->drawRect(grPaint, Sk2Gr(rect), doStroke ? width : -1);
}
#include "SkMaskFilter.h"