Batch consecutive draw rects.

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

git-svn-id: http://skia.googlecode.com/svn/trunk@800 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/include/GrAllocPool.h b/gpu/include/GrAllocPool.h
index 46359e5..251c0b4 100644
--- a/gpu/include/GrAllocPool.h
+++ b/gpu/include/GrAllocPool.h
@@ -33,7 +33,7 @@
     /**
      *  Returns a block of memory bytes size big. This address must not be
      *  passed to realloc/free/delete or any other function that assumes the
-     *  address was allocated by malloc or new (becuase it hasn't).
+     *  address was allocated by malloc or new (because it hasn't).
      */
     void* alloc(size_t bytes);
     
diff --git a/gpu/include/GrContext.h b/gpu/include/GrContext.h
index 6b9c3f3..973198b 100644
--- a/gpu/include/GrContext.h
+++ b/gpu/include/GrContext.h
@@ -445,25 +445,33 @@
     GrFontCache* getFontCache() { return fFontCache; }

     GrDrawTarget* getTextTarget(const GrPaint& paint);

     void flushText();

-

-    const GrIndexBuffer* quadIndexBuffer() const;

-    int maxQuadsInIndexBuffer() const;

+    const GrIndexBuffer* getQuadIndexBuffer() const;

 

 private:

+    // used to keep track of when we need to flush the draw buffer

+    enum DrawCategory {

+        kBuffered_DrawCategory,      // last draw was inserted in draw buffer

+        kUnbuffered_DrawCategory,    // last draw was not inserted in the draw buffer

+        kText_DrawCategory           // text context was last to draw

+    };

+    DrawCategory fLastDrawCategory;

+

     GrGpu*          fGpu;

     GrTextureCache* fTextureCache;

     GrFontCache*    fFontCache;

 

-    GrVertexBufferAllocPool*    fTextVBAllocPool;

-    GrIndexBufferAllocPool*     fTextIBAllocPool;

-    GrInOrderDrawBuffer*        fTextDrawBuffer;

+    GrVertexBufferAllocPool*    fDrawBufferVBAllocPool;

+    GrIndexBufferAllocPool*     fDrawBufferIBAllocPool;

+    GrInOrderDrawBuffer*        fDrawBuffer;

 

     GrContext(GrGpu* gpu);

+    void flushDrawBuffer();

 

     static void SetPaint(const GrPaint& paint, GrDrawTarget* target);

 

     bool finalizeTextureKey(GrTextureKey*, const GrSamplerState&) const;

-    void prepareToDraw(const GrPaint& paint);

+    

+    GrDrawTarget* prepareToDraw(const GrPaint& paint, DrawCategory drawType);

 

     void drawClipIntoStencil();

 };

diff --git a/gpu/include/GrContext_impl.h b/gpu/include/GrContext_impl.h
index b54e927..8af38e6 100644
--- a/gpu/include/GrContext_impl.h
+++ b/gpu/include/GrContext_impl.h
@@ -30,7 +30,7 @@
 

     GrDrawTarget::AutoReleaseGeometry geo;

 

-    this->prepareToDraw(paint);

+    GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);

 

     if (NULL != paint.getTexture()) {

         if (NULL != texCoordSrc) {

@@ -47,7 +47,7 @@
     int vertexCount = posSrc.count();

     int indexCount = (NULL != idxSrc) ? idxSrc->count() : 0;

 

-    if (!geo.set(fGpu, layout, vertexCount, indexCount)) {

+    if (!geo.set(target, layout, vertexCount, indexCount)) {

         GrPrintf("Failed to get space for vertices!");

         return;

     }

@@ -77,9 +77,9 @@
     }

 

     if (NULL == idxSrc) {

-        fGpu->drawNonIndexed(primitiveType, 0, vertexCount);

+        target->drawNonIndexed(primitiveType, 0, vertexCount);

     } else {

-        fGpu->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);

+        target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);

     }

 }

 

diff --git a/gpu/include/GrDrawTarget.h b/gpu/include/GrDrawTarget.h
index 88782f1..91af9ce 100644
--- a/gpu/include/GrDrawTarget.h
+++ b/gpu/include/GrDrawTarget.h
@@ -18,7 +18,6 @@
 #ifndef GrDrawTarget_DEFINED
 #define GrDrawTarget_DEFINED
 
-#include "GrScalar.h"
 #include "GrMatrix.h"
 #include "GrColor.h"
 #include "GrRefCnt.h"
@@ -347,7 +346,11 @@
     void disableState(uint32_t stateBits);
 
     bool isDitherState() const {
-        return fCurrDrawState.fFlagBits & kDither_StateBit;
+        return 0 != (fCurrDrawState.fFlagBits & kDither_StateBit);
+    }
+
+    bool isClipState() const {
+        return 0 != (fCurrDrawState.fFlagBits & kClip_StateBit);
     }
 
     /**
@@ -435,6 +438,16 @@
         GrAssert(texCoordIdx < kMaxTexCoords);
         return 1 << (stage + (texCoordIdx * kNumStages));
     }
+
+    /**
+     * Determines if blend is effectively disabled.
+     *
+     * @return true if blend can be disabled without changing the rendering
+     *  result given the current state including the vertex layout specified
+     *  with the vertex source.
+     */
+    bool canDisableBlend() const;
+
 private:
     static const int TEX_COORD_BIT_CNT = kNumStages*kMaxTexCoords;
 public:
@@ -655,6 +668,45 @@
                                 int startVertex,
                                 int vertexCount)  = 0;
 
+    /**
+     * Helper function for drawing rects. This does not use the current index
+     * and vertex sources. After returning, the vertex and index sources may
+     * have changed. They should be reestablished before the next drawIndexed
+     * or drawNonIndexed. This cannot be called between reserving and releasing
+     * geometry. The GrDrawTarget subclass may be able to perform additional
+     * optimizations if drawRect is used rather than drawIndexed or 
+     * drawNonIndexed.
+     * @param rect      the rect to draw
+     * @param matrix    optional matrix applied to rect (before viewMatrix)
+     * @param stageEnableMask   bitmask indicating which stages are enabled.
+     *                          Bit i indicates whether stage i is enabled.
+     * @param srcRects  specifies rects for stages enabled by stageEnableMask.
+     *                  if stageEnableMask bit i is 1, srcRects is not NULL,
+     *                  and srcRects[i] is not NULL, then srcRects[i] will be
+     *                  used as coordinates for stage i. Otherwise, if stage i
+     *                  is enabled then rect is used as the coordinates.
+     * @param srcMatrices   optional matrices applied to srcRects. If
+     *                      srcRect[i] is non-NULL and srcMatrices[i] is
+     *                      non-NULL then srcRect[i] will be transformed by
+     *                      srcMatrix[i]. srcMatrices can be NULL when no
+     *                      srcMatrices are desired.
+     */
+    virtual void drawRect(const GrRect& rect, 
+                          const GrMatrix* matrix,
+                          int stageEnableMask,
+                          const GrRect* srcRects[],
+                          const GrMatrix* srcMatrices[]);
+
+    /**
+     * Helper for drawRect when the caller doesn't need separate src rects or 
+     * matrices.
+     */
+    void drawSimpleRect(const GrRect& rect, 
+                        const GrMatrix* matrix, 
+                        int stageEnableMask) {
+         drawRect(rect, matrix, stageEnableMask, NULL, NULL);
+    }
+
     ///////////////////////////////////////////////////////////////////////////
 
     class AutoStateRestore : ::GrNoncopyable {
@@ -869,6 +921,65 @@
     static int VertexSizeAndOffsetsByStage(GrVertexLayout vertexLayout,
                                            int texCoordOffsetsByStage[kNumStages],
                                            int *colorOffset);
+
+    /**
+     * Accessing positions, texture coords, or colors, of a vertex within an
+     * array is a hassle involving casts and simple math. These helpers exist
+     * to keep GrDrawTarget clients' code a bit nicer looking.
+     */
+
+    /**
+     * Gets a pointer to a GrPoint of a vertex's position or texture
+     * coordinate.
+     * @param vertices      the vetex array
+     * @param vertexIndex   the index of the vertex in the array
+     * @param vertexSize    the size of each vertex in the array
+     * @param offset        the offset in bytes of the vertex component.
+     *                      Defaults to zero (corresponding to vertex position)
+     * @return pointer to the vertex component as a GrPoint
+     */
+    static GrPoint* GetVertexPoint(void* vertices, 
+                                   int vertexIndex,
+                                   int vertexSize,
+                                   int offset = 0) {
+        intptr_t start = GrTCast<intptr_t>(vertices);
+        return GrTCast<GrPoint*>(start + offset + 
+                                 vertexIndex * vertexSize);
+    }
+    static const GrPoint* GetVertexPoint(const void* vertices,
+                                         int vertexIndex,
+                                         int vertexSize, 
+                                         int offset = 0) {
+        intptr_t start = GrTCast<intptr_t>(vertices);
+        return GrTCast<const GrPoint*>(start + offset + 
+                                       vertexIndex * vertexSize);
+    }
+
+    /**
+     * Gets a pointer to a GrColor inside a vertex within a vertex array.
+     * @param vertices      the vetex array
+     * @param vertexIndex   the index of the vertex in the array
+     * @param vertexSize    the size of each vertex in the array
+     * @param offset        the offset in bytes of the vertex color
+     * @return pointer to the vertex component as a GrColor
+     */
+    static GrColor* GetVertexColor(void* vertices, 
+                                   int vertexIndex,
+                                   int vertexSize,
+                                   int offset) {
+        intptr_t start = GrTCast<intptr_t>(vertices);
+        return GrTCast<GrColor*>(start + offset + 
+                                 vertexIndex * vertexSize);
+    }
+    static const GrColor* GetVertexColor(const void* vertices,
+                                         int vertexIndex,
+                                         int vertexSize, 
+                                         int offset) {
+        const intptr_t start = GrTCast<intptr_t>(vertices);
+        return GrTCast<const GrColor*>(start + offset + 
+                                       vertexIndex * vertexSize);
+    }
+
 protected:
 
     // Helpers for GrDrawTarget subclasses that won't have private access to
@@ -885,7 +996,8 @@
 
     virtual void releaseGeometryHelper() = 0;
 
-    virtual void clipWillChange(const GrClip& clip) = 0;
+    // subclass overrides to be notified when clip is set.
+    virtual void clipWillBeSet(const GrClip& clip) = 0;
 
     virtual void setVertexSourceToArrayHelper(const void* vertexArray,
                                               int vertexCount) = 0;
@@ -893,6 +1005,18 @@
     virtual void setIndexSourceToArrayHelper(const void* indexArray,
                                              int indexCount) = 0;
 
+    // Helpers for drawRect, protected so subclasses that override drawRect
+    // can use them.
+    static GrVertexLayout GetRectVertexLayout(int stageEnableMask, 
+                                              const GrRect* srcRects[]);
+
+    static void SetRectVertices(const GrRect& rect,
+                                const GrMatrix* matrix, 
+                                const GrRect* srcRects[], 
+                                const GrMatrix* srcMatrices[],
+                                GrVertexLayout layout, 
+                                void* vertices);
+
     enum GeometrySrcType {
         kReserved_GeometrySrcType,  // src was set using reserveAndLockGeometry
         kArray_GeometrySrcType,     // src was set using set*SourceToArray
diff --git a/gpu/include/GrGeometryBuffer.h b/gpu/include/GrGeometryBuffer.h
index fc3e358..af6eed5 100644
--- a/gpu/include/GrGeometryBuffer.h
+++ b/gpu/include/GrGeometryBuffer.h
@@ -31,7 +31,7 @@
      *

      * @return the size of the buffer in bytes

      */

-    size_t size() { return fSizeInBytes; }

+    size_t size() const { return fSizeInBytes; }

     

     /**

      *Retrieves whether the buffer was created with the dynamic flag

@@ -107,9 +107,9 @@
         fDynamic(dynamic) {}

 

 private:

-    size_t fSizeInBytes;

+    size_t   fSizeInBytes;

     bool     fDynamic;

-    

+

     typedef GrRefCnt INHERITED;

 };

 

diff --git a/gpu/include/GrGpu.h b/gpu/include/GrGpu.h
index 9fb7b9c..a132e9f 100644
--- a/gpu/include/GrGpu.h
+++ b/gpu/include/GrGpu.h
@@ -21,9 +21,7 @@
 #include "GrRect.h"
 #include "GrRefCnt.h"
 #include "GrDrawTarget.h"
-#include "GrGpuVertex.h"
 #include "GrTexture.h"
-#include "GrMemory.h"
 
 class GrVertexBufferAllocPool;
 class GrIndexBufferAllocPool;
@@ -295,29 +293,20 @@
                                 int vertexCount);
 
     /**
-     * Determines if blend is effectively disabled.
-     *
-     * @return true if blend can be disabled without changing the rendering
-     *  result given the current state including the vertex layout specified
-     *  with the vertex source.
-     */
-    bool canDisableBlend() const;
-
-    /**
      * Returns an index buffer that can be used to render quads.
-     * Indices are 0, 1, 2, 0, 2, 3, etc.
+     * Six indices per quad: 0, 1, 2, 0, 2, 3, etc.
+     * The max number of quads can be queried using GrIndexBuffer::maxQuads().
      * Draw with kTriangles_PrimitiveType
+     * @ return the quad index buffer
      */
-    const GrIndexBuffer* quadIndexBuffer() const;
-    /**
-     * Gets the number of quads that can be rendered using quadIndexBuffer.
-     */
-    int maxQuadsInIndexBuffer() const;
+    const GrIndexBuffer* getQuadIndexBuffer() const;
 
     /**
-     * Returns a vertex buffer with four position-only vertices [(0,0), (1,0), (1,1), (0,1)]
+     * Returns a vertex buffer with four position-only vertices [(0,0), (1,0), 
+     * (1,1), (0,1)].
+     * @ return unit square vertex buffer
      */
-    const GrVertexBuffer* unitSquareVertexBuffer() const;
+    const GrVertexBuffer* getUnitSquareVertexBuffer() const;
 
     /**
      * Ensures that the current render target is actually set in the
@@ -356,7 +345,10 @@
         GrRenderTarget* fStencilClipTarget;
     } fClipState;
 
-    virtual void clipWillChange(const GrClip& clip);
+    // GrDrawTarget override
+    virtual void clipWillBeSet(const GrClip& newClip);
+
+    // prepares clip flushes gpu state before a draw
     bool setupClipAndFlushState(PrimitiveType type);
 
     struct BoundsState {
diff --git a/gpu/include/GrInOrderDrawBuffer.h b/gpu/include/GrInOrderDrawBuffer.h
index 463ea2d..0dba8e3 100644
--- a/gpu/include/GrInOrderDrawBuffer.h
+++ b/gpu/include/GrInOrderDrawBuffer.h
@@ -41,31 +41,65 @@
 class GrInOrderDrawBuffer : public GrDrawTarget {
 public:
 
+    /**
+     * Creates a GrInOrderDrawBuffer
+     *
+     * @param vertexPool pool where vertices for queued draws will be saved when
+     *                   the vertex source is either reserved or array.
+     * @param indexPool  pool where indices for queued draws will be saved when
+     *                   the index source is either reserved or array.
+     */
     GrInOrderDrawBuffer(GrVertexBufferAllocPool* vertexPool,
                         GrIndexBufferAllocPool* indexPool);
 
     virtual ~GrInOrderDrawBuffer();
 
+    /**
+     * Copies the draw state and clip from target to this draw buffer.
+     *
+     * @param target    the target whose clip and state should be copied.
+     */
     void initializeDrawStateAndClip(const GrDrawTarget& target);
 
+    /**
+     * Provides the buffer with an index buffer that can be used for quad rendering.
+     * The buffer may be able to batch consecutive drawRects if this is provided.
+     * @param indexBuffer   index buffer with quad indices.
+     */
+    void setQuadIndexBuffer(const GrIndexBuffer* indexBuffer);
+
+    /**
+     * Empties the draw buffer of any queued up draws.
+     */
+    void reset();
+
+    /**
+     * plays the queued up draws to another target. Does not empty this buffer so
+     * that it can be played back multiple times.
+     * @param target    the target to receive the playback
+     */
+    void playback(GrDrawTarget* target);
+    
+    // overrides from GrDrawTarget
     virtual void drawIndexed(PrimitiveType primitiveType,
                              int startVertex,
                              int startIndex,
                              int vertexCount,
                              int indexCount);
-
     virtual void drawNonIndexed(PrimitiveType primitiveType,
                                 int startVertex,
                                 int vertexCount);
 
+    virtual void drawRect(const GrRect& rect, 
+                          const GrMatrix* matrix = NULL,
+                          int stageEnableMask = 0,
+                          const GrRect* srcRects[] = NULL,
+                          const GrMatrix* srcMatrices[] = NULL);
+
     virtual bool geometryHints(GrVertexLayout vertexLayout,
                                int* vertexCount,
                                int* indexCount) const;
 
-    void reset();
-
-    void playback(GrDrawTarget* target);
-
 private:
 
     struct Draw {
@@ -85,7 +119,7 @@
                                        void**         vertices,
                                        void**         indices);
     virtual void releaseGeometryHelper();
-    virtual void clipWillChange(const GrClip& clip);
+    virtual void clipWillBeSet(const GrClip& newClip);
 
     virtual void setVertexSourceToArrayHelper(const void* vertexArray,
                                               int vertexCount);
@@ -93,9 +127,11 @@
     virtual void setIndexSourceToArrayHelper(const void* indexArray,
                                              int indexCount);
 
+    bool needsNewState() const;
+    bool needsNewClip() const;
 
-    bool grabState();
-    bool grabClip();
+    void pushState();
+    void pushClip();
 
     GrTAllocator<Draw>              fDraws;
     // HACK: We currently do not hold refs on RTs in the saved draw states.
@@ -106,7 +142,12 @@
     GrTAllocator<SavedDrawState>    fStates;
 
     GrTAllocator<GrClip>            fClips;
-    bool                            fClipChanged;
+    bool                            fClipSet;
+
+    GrVertexLayout                  fLastRectVertexLayout;
+    const GrIndexBuffer*            fQuadIndexBuffer;
+    int                             fMaxQuads;
+    int                             fCurrQuad;
 
     GrVertexBufferAllocPool&        fVertexPool;
     const GrVertexBuffer*           fCurrPoolVertexBuffer;
@@ -134,6 +175,7 @@
                                                    STATES_BLOCK_SIZE];
     int8_t                          fClipsStorage[sizeof(GrClip) *
                                                   CLIPS_BLOCK_SIZE];
+    typedef GrDrawTarget INHERITED;
 };
 
 #endif
diff --git a/gpu/include/GrIndexBuffer.h b/gpu/include/GrIndexBuffer.h
index 85ff749..09d1977 100644
--- a/gpu/include/GrIndexBuffer.h
+++ b/gpu/include/GrIndexBuffer.h
@@ -21,6 +21,13 @@
 #include "GrGeometryBuffer.h"
 
 class GrIndexBuffer : public GrGeometryBuffer {
+public:
+        /**
+         * Retrieves the maximum number of quads that could be rendered
+         * from the index buffer (using kTriangles_PrimitiveType).
+         * @return the maximum number of quads using full size of index buffer.
+         */
+        int maxQuads() const { return size() / (sizeof(uint16_t) * 6); }
 protected:
     GrIndexBuffer(size_t sizeInBytes, bool dynamic) :
         INHERITED(sizeInBytes, dynamic) {}
diff --git a/gpu/include/GrRect.h b/gpu/include/GrRect.h
index 5192ebd..e98913a 100644
--- a/gpu/include/GrRect.h
+++ b/gpu/include/GrRect.h
@@ -131,7 +131,7 @@
      *  Initialize a rectangle to a point.
      *  @param pt the point used to initialize the rectanglee.
      */
-    GrRect(GrPoint pt) {
+    explicit GrRect(const GrPoint& pt) {
         setToPoint(pt);
     }
 
@@ -187,6 +187,11 @@
     bool isInverted() const {
         return (fLeft > fRight) || (fTop > fBottom);
     }
+
+    bool contains(const GrPoint& point) const {
+        return point.fX >= fLeft && point.fX < fRight &&
+               point.fY >= fTop && point.fY < fBottom;
+    }
     
     /**
      *  Initialize a rectangle to a point.
diff --git a/gpu/include/GrTextContext.h b/gpu/include/GrTextContext.h
index 727358e..3dc9c7a 100644
--- a/gpu/include/GrTextContext.h
+++ b/gpu/include/GrTextContext.h
@@ -19,8 +19,10 @@
 #define GrTextContext_DEFINED
 
 #include "GrGlyph.h"
-#include "GrGpuVertex.h"
+#include "GrPaint.h"
 
+struct GrGpuTextVertex;
+class GrMatrix;
 class GrContext;
 class GrTextStrike;
 class GrFontScaler;
diff --git a/gpu/include/GrTypes.h b/gpu/include/GrTypes.h
index 9553678..8311239 100644
--- a/gpu/include/GrTypes.h
+++ b/gpu/include/GrTypes.h
@@ -141,14 +141,14 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 /**
- *  Use to cast a pointer to a different type, and maintaining strict-aliasing
+ *  Use to cast a ptr to a different type, and maintain strict-aliasing
  */
-template <typename Dst> Dst GrTCast(const void* ptr) {
+template <typename Dst, typename Src> Dst GrTCast(Src src) {
     union {
-        const void* src;
+        Src src;
         Dst dst;
     } data;
-    data.src = ptr;
+    data.src = src;
     return data.dst;
 }