Move alpha-ramp AA to GrContext, detect cases when AA is applied via other methods...
authorbsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Mon, 25 Apr 2011 12:43:45 +0000 (12:43 +0000)
committerbsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Mon, 25 Apr 2011 12:43:45 +0000 (12:43 +0000)
Review URL: http://codereview.appspot.com/4449047/

git-svn-id: http://skia.googlecode.com/svn/trunk@1169 2bbb7eff-a529-9590-31e7-b0007b416f81

12 files changed:
gpu/include/GrContext.h
gpu/include/GrGpu.h
gpu/include/GrMatrix.h
gpu/include/GrPoint.h
gpu/include/GrRect.h
gpu/include/GrScalar.h
gpu/src/GrContext.cpp
gpu/src/GrGpuGL.cpp
gpu/src/GrMatrix.cpp
gyp/skia.gyp
samplecode/SampleAARects.cpp [new file with mode: 0644]
src/gpu/SkGpuDevice.cpp

index 5eda2b7..07d76f8 100644 (file)
@@ -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();
index 7dd9959..5bbe85d 100644 (file)
@@ -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.
index 9a2e660..1ebc0b4 100644 (file)
@@ -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.
index c07543b..8c540f0 100644 (file)
@@ -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.
index 67e366c..a9ff6ec 100644 (file)
@@ -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       &&
index 1353fb2..7aaa43d 100644 (file)
  */
 #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)
index f68564a..7cf0cca 100644 (file)
@@ -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();
 }
 
index 64431a3..f2ec450 100644 (file)
@@ -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.
index 0a2d1b2..92a38ee 100644 (file)
@@ -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) {
index 322f87c..94ba3cf 100644 (file)
         '../samplecode/SamplePicture.cpp',
         '../samplecode/SamplePoints.cpp',
         '../samplecode/SamplePolyToPoly.cpp',
+        '../samplecode/SampleAARects.cpp',
         '../samplecode/SampleRegion.cpp',
         '../samplecode/SampleRepeatTile.cpp',
         '../samplecode/SampleShaders.cpp',
diff --git a/samplecode/SampleAARects.cpp b/samplecode/SampleAARects.cpp
new file mode 100644 (file)
index 0000000..94f8ce9
--- /dev/null
@@ -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);
+
index f89d4b1..1c797c3 100644 (file)
@@ -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);\r
+\r
+    bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;\r
+    SkScalar width = paint.getStrokeWidth();\r
+\r
+    /*\r
+        We have special code for hairline strokes, miter-strokes, and fills.\r
+        Anything else we just call our path code.\r
+     */\r
+    bool usePath = doStroke && width > 0 &&\r
+                    paint.getStrokeJoin() != SkPaint::kMiter_Join;\r
+    // another reason we might need to call drawPath...\r
+    if (paint.getMaskFilter()) {\r
+        usePath = true;\r
+    }\r
+\r
+    if (usePath) {\r
+        SkPath path;\r
+        path.addRect(rect);\r
+        this->drawPath(draw, path, paint, NULL, true);\r
+        return;\r
+    }\r
+\r
+    GrPaint grPaint;\r
+    SkAutoCachedTexture act;\r
+    if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix,  &grPaint)) {\r
+        return;\r
+    }\r
+    fContext->drawRect(grPaint, Sk2Gr(rect), doStroke ? width : -1);
 }
 
 #include "SkMaskFilter.h"