зеркало из https://github.com/mozilla/moz-skia.git
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:
Родитель
e624caf6c3
Коммит
205d46067a
|
@ -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.
|
||||
|
|
|
@ -135,7 +135,7 @@ public:
|
|||
GrScalar scaleY,
|
||||
GrScalar transY,
|
||||
GrScalar persp0,
|
||||
GrScalar persp1,
|
||||
GrScalar persp1,
|
||||
GrScalar persp2) {
|
||||
fM[kScaleX] = scaleX;
|
||||
fM[kSkewX] = skewX;
|
||||
|
@ -253,6 +253,21 @@ public:
|
|||
start = (GrPoint*)((intptr_t)start + stride);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -278,7 +293,12 @@ public:
|
|||
* @return true if matrix is idenity
|
||||
*/
|
||||
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.
|
||||
|
|
|
@ -153,6 +153,14 @@ public:
|
|||
fX = x;
|
||||
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);
|
||||
|
||||
if (SkDraw::kPath_RectType == type) {
|
||||
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");
|
||||
}
|
||||
}
|
||||
CHECK_SHOULD_DRAW(draw);
|
||||
|
||||
bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;
|
||||
SkScalar width = paint.getStrokeWidth();
|
||||
|
||||
/*
|
||||
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);
|
||||
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"
|
||||
|
|
Загрузка…
Ссылка в новой задаче