diff options
Diffstat (limited to 'gpu')
-rw-r--r-- | gpu/include/GrContext.h | 18 | ||||
-rw-r--r-- | gpu/include/GrGpu.h | 7 | ||||
-rw-r--r-- | gpu/include/GrMatrix.h | 24 | ||||
-rw-r--r-- | gpu/include/GrPoint.h | 8 | ||||
-rw-r--r-- | gpu/include/GrRect.h | 24 | ||||
-rw-r--r-- | gpu/include/GrScalar.h | 12 | ||||
-rw-r--r-- | gpu/src/GrContext.cpp | 296 | ||||
-rw-r--r-- | gpu/src/GrGpuGL.cpp | 2 | ||||
-rw-r--r-- | gpu/src/GrMatrix.cpp | 20 |
9 files changed, 398 insertions, 13 deletions
diff --git a/gpu/include/GrContext.h b/gpu/include/GrContext.h index 5eda2b7186..07d76f88e1 100644 --- a/gpu/include/GrContext.h +++ b/gpu/include/GrContext.h @@ -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(); diff --git a/gpu/include/GrGpu.h b/gpu/include/GrGpu.h index 7dd9959af9..5bbe85d877 100644 --- a/gpu/include/GrGpu.h +++ b/gpu/include/GrGpu.h @@ -273,6 +273,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 * value. @@ -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. diff --git a/gpu/include/GrMatrix.h b/gpu/include/GrMatrix.h index 9a2e660015..1ebc0b4e2a 100644 --- a/gpu/include/GrMatrix.h +++ b/gpu/include/GrMatrix.h @@ -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. diff --git a/gpu/include/GrPoint.h b/gpu/include/GrPoint.h index c07543bb30..8c540f0b99 100644 --- a/gpu/include/GrPoint.h +++ b/gpu/include/GrPoint.h @@ -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. diff --git a/gpu/include/GrRect.h b/gpu/include/GrRect.h index 67e366c3bf..a9ff6ec14d 100644 --- a/gpu/include/GrRect.h +++ b/gpu/include/GrRect.h @@ -206,6 +206,14 @@ struct GrRect { } /** + * 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. */ bool contains(const GrPoint& point) const { @@ -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 && diff --git a/gpu/include/GrScalar.h b/gpu/include/GrScalar.h index 1353fb2148..7aaa43d33f 100644 --- a/gpu/include/GrScalar.h +++ b/gpu/include/GrScalar.h @@ -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) diff --git a/gpu/src/GrContext.cpp b/gpu/src/GrContext.cpp index f68564a2ba..7cf0cca7cb 100644 --- a/gpu/src/GrContext.cpp +++ b/gpu/src/GrContext.cpp @@ -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(); } diff --git a/gpu/src/GrGpuGL.cpp b/gpu/src/GrGpuGL.cpp index 64431a35f8..f2ec450a0f 100644 --- a/gpu/src/GrGpuGL.cpp +++ b/gpu/src/GrGpuGL.cpp @@ -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. diff --git a/gpu/src/GrMatrix.cpp b/gpu/src/GrMatrix.cpp index 0a2d1b2b55..92a38ee1e9 100644 --- a/gpu/src/GrMatrix.cpp +++ b/gpu/src/GrMatrix.cpp @@ -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) { |