Adds read pixels to GrTexture and GrRenderTarget
Adds SkGrRenderTargetPixelRef for SkBitmaps that are backed by RTs that aren't textures.
Adds onReadPixels implementations for SkGr pixel ref types



git-svn-id: http://skia.googlecode.com/svn/trunk@1056 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/include/GrContext.h b/gpu/include/GrContext.h
index cccc14f..c178ed6 100644
--- a/gpu/include/GrContext.h
+++ b/gpu/include/GrContext.h
@@ -423,20 +423,49 @@
      *                          FlushBits.
      */
     void flush(int flagsBitfield = 0);
+    
     /**
-     *  Return true on success, i.e. if we could copy the specified range of
-     *  pixels from the current render-target into the buffer, converting into
-     *  the specified pixel-config.
+     * Reads a rectangle of pixels from a render target.
+     * @param renderTarget  the render target to read from. NULL means the
+     *                      current render target.
+     * @param left          left edge of the rectangle to read (inclusive)
+     * @param top           top edge of the rectangle to read (inclusive)
+     * @param width         width of rectangle to read in pixels.
+     * @param height        height of rectangle to read in pixels.
+     * @param config        the pixel config of the destination buffer
+     * @param buffer        memory to read the rectangle into.
+     *
+     * @return true if the read succeeded, false if not. The read can fail
+     *              because of a unsupported pixel config or because no render
+     *              target is currently set.
      */
-    bool readPixels(int left, int top, int width, int height,
-                    GrTexture::PixelConfig, void* buffer);
+    bool readRenderTargetPixels(GrRenderTarget* target,
+                                int left, int top, int width, int height,
+                                GrPixelConfig config, void* buffer);
+
+    /**
+     * Reads a rectangle of pixels from a texture.
+     * @param texture       the render target to read from.
+     * @param left          left edge of the rectangle to read (inclusive)
+     * @param top           top edge of the rectangle to read (inclusive)
+     * @param width         width of rectangle to read in pixels.
+     * @param height        height of rectangle to read in pixels.
+     * @param config        the pixel config of the destination buffer
+     * @param buffer        memory to read the rectangle into.
+     *
+     * @return true if the read succeeded, false if not. The read can fail
+     *              because of a unsupported pixel config.
+     */
+    bool readTexturePixels(GrTexture* target,
+                           int left, int top, int width, int height,
+                           GrPixelConfig config, void* buffer);
 
     /**
      *  Copy the src pixels [buffer, stride, pixelconfig] into the current
      *  render-target at the specified rectangle.
      */
     void writePixels(int left, int top, int width, int height,
-                     GrTexture::PixelConfig, const void* buffer, size_t stride);
+                     GrPixelConfig, const void* buffer, size_t stride);
 
 
     ///////////////////////////////////////////////////////////////////////////
diff --git a/gpu/include/GrGLTexture.h b/gpu/include/GrGLTexture.h
index 0624f40..2cd833c 100644
--- a/gpu/include/GrGLTexture.h
+++ b/gpu/include/GrGLTexture.h
@@ -180,17 +180,17 @@
 protected:
 
     struct GLTextureDesc {
-        uint32_t    fContentWidth;
-        uint32_t    fContentHeight;
-        uint32_t    fAllocWidth;
-        uint32_t    fAllocHeight;
-        PixelConfig fFormat;
-        GrGLuint    fTextureID;
-        GrGLenum    fUploadFormat;
-        GrGLenum    fUploadByteCount;
-        GrGLenum    fUploadType;
-        GrGLuint    fStencilBits;
-        Orientation fOrientation;
+        uint32_t        fContentWidth;
+        uint32_t        fContentHeight;
+        uint32_t        fAllocWidth;
+        uint32_t        fAllocHeight;
+        GrPixelConfig   fFormat;
+        GrGLuint        fTextureID;
+        GrGLenum        fUploadFormat;
+        GrGLenum        fUploadByteCount;
+        GrGLenum        fUploadType;
+        GrGLuint        fStencilBits;
+        Orientation     fOrientation;
     };
     typedef GrGLRenderTarget::GLRenderTargetIDs GLRenderTargetIDs;
     GrGLTexture(GrGpuGL* gpu,
diff --git a/gpu/include/GrGpu.h b/gpu/include/GrGpu.h
index c4f5e4b..cbe3e95 100644
--- a/gpu/include/GrGpu.h
+++ b/gpu/include/GrGpu.h
@@ -17,15 +17,16 @@
 #ifndef GrGpu_DEFINED
 #define GrGpu_DEFINED
 
+#include "GrDrawTarget.h"
+#include "GrPathRenderer.h"
 #include "GrRect.h"
 #include "GrRefCnt.h"
-#include "GrDrawTarget.h"
 #include "GrTexture.h"
-#include "GrPathRenderer.h"
 
-class GrVertexBufferAllocPool;
+class GrContext;
 class GrIndexBufferAllocPool;
 class GrResource;
+class GrVertexBufferAllocPool;
 
 class GrGpu : public GrDrawTarget {
 
@@ -104,7 +105,7 @@
                                         //   kRenderTarget_TextureFlag.
         uint32_t               fWidth;  //!< Width of the texture
         uint32_t               fHeight; //!< Height of the texture
-        GrTexture::PixelConfig fFormat; //!< Format of source data of the
+        GrPixelConfig          fFormat; //!< Format of source data of the
                                         //   texture. Not guaraunteed to be the
                                         //   same as internal format used by
                                         //   3D API.
@@ -143,6 +144,14 @@
     GrGpu();
     virtual ~GrGpu();
 
+    // The GrContext sets itself as the owner of this Gpu object
+    void setContext(GrContext* context) {
+        GrAssert(NULL == fContext); 
+        fContext = context;
+    }
+    GrContext* getContext() { return fContext; }
+    const GrContext* getContext() const { return fContext; }
+
     /**
      * The GrGpu object normally assumes that no outsider is setting state
      * within the underlying 3D API's context/device/whatever. This call informs
@@ -340,19 +349,23 @@
     void forceRenderTargetFlush();
 
     /**
-     * Reads a rectangle of pixels from the current render target.
-     * @param left      left edge of the rectangle to read (inclusive)
-     * @param top       top edge of the rectangle to read (inclusive)
-     * @param width     width of rectangle to read in pixels.
-     * @param height    height of rectangle to read in pixels.
-     * @param buffer    memory to read the rectangle into.
+     * Reads a rectangle of pixels from a render target.
+     * @param renderTarget  the render target to read from. NULL means the
+     *                      current render target.
+     * @param left          left edge of the rectangle to read (inclusive)
+     * @param top           top edge of the rectangle to read (inclusive)
+     * @param width         width of rectangle to read in pixels.
+     * @param height        height of rectangle to read in pixels.
+     * @param config        the pixel config of the destination buffer
+     * @param buffer        memory to read the rectangle into.
      *
      * @return true if the read succeeded, false if not. The read can fail
      *              because of a unsupported pixel config or because no render
      *              target is currently set.
      */
-    bool readPixels(int left, int top, int width, int height,
-                    GrTexture::PixelConfig, void* buffer);
+    bool readPixels(GrRenderTarget* renderTarget,
+                    int left, int top, int width, int height,
+                    GrPixelConfig config, void* buffer);
 
     const Stats& getStats() const;
     void resetStats();
@@ -499,7 +512,7 @@
 
     // overridden by API-specific derived class to perform the read pixels.
     virtual bool readPixelsHelper(int left, int top, int width, int height,
-                                  GrTexture::PixelConfig, void* buffer) = 0;
+                                  GrPixelConfig, void* buffer) = 0;
 
     // called to program the vertex data, indexCount will be 0 if drawing non-
     // indexed geometry. The subclass may adjust the startVertex and/or
@@ -523,20 +536,7 @@
     virtual void eraseStencilClip(const GrIRect& rect) = 0;
 
 private:
-    // readies the pools to provide vertex/index data.
-    void prepareVertexPool();
-    void prepareIndexPool();
-
-    // determines the path renderer used to draw a clip path element.
-    GrPathRenderer* getClipPathRenderer(GrPathIter* path,
-                                        GrPathFill fill);
-
-    void handleDirtyContext() {
-        if (fContextIsDirty) {
-            this->resetContext();
-            fContextIsDirty = false;
-        }
-    }
+    GrContext*                  fContext; // not reffed (context refs gpu)
 
     GrVertexBufferAllocPool*    fVertexPool;
 
@@ -561,6 +561,21 @@
 
     GrResource*                 fResourceHead;
 
+    // readies the pools to provide vertex/index data.
+    void prepareVertexPool();
+    void prepareIndexPool();
+
+    // determines the path renderer used to draw a clip path element.
+    GrPathRenderer* getClipPathRenderer(GrPathIter* path,
+                                        GrPathFill fill);
+
+    void handleDirtyContext() {
+        if (fContextIsDirty) {
+            this->resetContext();
+            fContextIsDirty = false;
+        }
+    }
+
     // used to save and restore state when the GrGpu needs
     // to make its geometry pools available internally
     class AutoInternalDrawGeomRestore {
diff --git a/gpu/include/GrTexture.h b/gpu/include/GrTexture.h
index d1853e3..2aa80ab 100644
--- a/gpu/include/GrTexture.h
+++ b/gpu/include/GrTexture.h
@@ -52,6 +52,21 @@
      */
     GrTexture* asTexture() {return fTexture;}
 
+    /**
+     * Reads a rectangle of pixels from the render target.
+     * @param left          left edge of the rectangle to read (inclusive)
+     * @param top           top edge of the rectangle to read (inclusive)
+     * @param width         width of rectangle to read in pixels.
+     * @param height        height of rectangle to read in pixels.
+     * @param config        the pixel config of the destination buffer
+     * @param buffer        memory to read the rectangle into.
+     *
+     * @return true if the read succeeded, false if not. The read can fail
+     *              because of a unsupported pixel config.
+     */
+    bool readPixels(int left, int top, int width, int height,
+                    GrPixelConfig config, void* buffer);
+
 protected:
     GrRenderTarget(GrGpu* gpu,
                    GrTexture* texture,
@@ -81,25 +96,11 @@
 };
 
 class GrTexture : public GrResource {
-public:
-    enum PixelConfig {
-        kUnknown_PixelConfig,
-        kAlpha_8_PixelConfig,
-        kIndex_8_PixelConfig,
-        kRGB_565_PixelConfig,
-        kRGBA_4444_PixelConfig, //!< premultiplied
-        kRGBA_8888_PixelConfig, //!< premultiplied
-        kRGBX_8888_PixelConfig, //!< treat the alpha channel as opaque
-    };
-    static size_t BytesPerPixel(PixelConfig);
-    static bool PixelConfigIsOpaque(PixelConfig);
-    static bool PixelConfigIsAlphaOnly(PixelConfig);
-
 protected:
     GrTexture(GrGpu* gpu,
               int width,
               int height,
-              PixelConfig config)
+              GrPixelConfig config)
     : INHERITED(gpu)
     , fWidth(width)
     , fHeight(height)
@@ -138,13 +139,13 @@
     /**
      * Retrieves the pixel config specified when the texture was created.
      */
-    PixelConfig config() const { return fConfig; }
+    GrPixelConfig config() const { return fConfig; }
 
     /**
      *  Approximate number of bytes used by the texture
      */
     size_t sizeInBytes() const {
-        return fWidth * fHeight * BytesPerPixel(fConfig);
+        return fWidth * fHeight * GrBytesPerPixel(fConfig);
     }
 
     /**
@@ -164,6 +165,21 @@
                                    const void* srcData) = 0;
 
     /**
+     * Reads a rectangle of pixels from the texture.
+     * @param left          left edge of the rectangle to read (inclusive)
+     * @param top           top edge of the rectangle to read (inclusive)
+     * @param width         width of rectangle to read in pixels.
+     * @param height        height of rectangle to read in pixels.
+     * @param config        the pixel config of the destination buffer
+     * @param buffer        memory to read the rectangle into.
+     *
+     * @return true if the read succeeded, false if not. The read can fail
+     *              because of a unsupported pixel config.
+     */
+    bool readPixels(int left, int top, int width, int height,
+                    GrPixelConfig config, void* buffer);
+
+    /**
      * Retrieves the render target underlying this texture that can be passed to
      * GrGpu::setRenderTarget().
      *
@@ -200,7 +216,8 @@
     // for this texture if the texture is power of two sized.
     int      fShiftFixedX;
     int      fShiftFixedY;
-    PixelConfig fConfig;
+
+    GrPixelConfig fConfig;
 
     typedef GrResource INHERITED;
 };
diff --git a/gpu/include/GrTypes.h b/gpu/include/GrTypes.h
index cc78c3e..2d8c116 100644
--- a/gpu/include/GrTypes.h
+++ b/gpu/include/GrTypes.h
@@ -213,6 +213,54 @@
 }
 
 /**
+ * Pixel configurations.
+ */
+enum GrPixelConfig {
+    kUnknown_GrPixelConfig,
+    kAlpha_8_GrPixelConfig,
+    kIndex_8_GrPixelConfig,
+    kRGB_565_GrPixelConfig,
+    kRGBA_4444_GrPixelConfig, //!< premultiplied
+    kRGBA_8888_GrPixelConfig, //!< premultiplied
+    kRGBX_8888_GrPixelConfig, //!< treat the alpha channel as opaque
+};
+
+static inline size_t GrBytesPerPixel(GrPixelConfig config) {
+    switch (config) {
+        case kAlpha_8_GrPixelConfig:
+        case kIndex_8_GrPixelConfig:
+            return 1;
+        case kRGB_565_GrPixelConfig:
+        case kRGBA_4444_GrPixelConfig:
+            return 2;
+        case kRGBA_8888_GrPixelConfig:
+        case kRGBX_8888_GrPixelConfig:
+            return 4;
+        default:
+            return 0;
+    }
+}
+
+static inline bool GrPixelConfigIsOpaque(GrPixelConfig config) {
+    switch (config) {
+        case kRGB_565_GrPixelConfig:
+        case kRGBX_8888_GrPixelConfig:
+            return true;
+        default:
+            return false;
+    }
+}
+
+static inline bool GrPixelConfigIsAlphaOnly(GrPixelConfig config) {
+    switch (config) {
+        case kAlpha_8_GrPixelConfig:
+            return true;
+        default:
+            return false;
+    }
+}
+
+/**
  * Set Operations used to construct clips.
  */
 enum GrSetOp {
diff --git a/gpu/src/GrAtlas.cpp b/gpu/src/GrAtlas.cpp
index a37df9c..dfc0a69 100644
--- a/gpu/src/GrAtlas.cpp
+++ b/gpu/src/GrAtlas.cpp
@@ -142,16 +142,16 @@
     fGpu->unref();
 }
 
-static GrTexture::PixelConfig maskformat2pixelconfig(GrMaskFormat format) {
+static GrPixelConfig maskformat2pixelconfig(GrMaskFormat format) {
     switch (format) {
         case kA8_GrMaskFormat:
-            return GrTexture::kAlpha_8_PixelConfig;
+            return kAlpha_8_GrPixelConfig;
         case kA565_GrMaskFormat:
-            return GrTexture::kRGB_565_PixelConfig;
+            return kRGB_565_GrPixelConfig;
         default:
             GrAssert(!"unknown maskformat");
     }
-    return GrTexture::kUnknown_PixelConfig;
+    return kUnknown_GrPixelConfig;
 }
 
 GrAtlas* GrAtlasMgr::addToAtlas(GrAtlas* atlas,
diff --git a/gpu/src/GrContext.cpp b/gpu/src/GrContext.cpp
index d093d7c..a0f5c51 100644
--- a/gpu/src/GrContext.cpp
+++ b/gpu/src/GrContext.cpp
@@ -206,7 +206,7 @@
             // no longer need to clamp at min RT size.
             rtDesc.fWidth  = GrNextPow2(desc.fWidth);
             rtDesc.fHeight = GrNextPow2(desc.fHeight);
-            int bpp = GrTexture::BytesPerPixel(desc.fFormat);
+            int bpp = GrBytesPerPixel(desc.fFormat);
             GrAutoSMalloc<128*128*4> stretchedPixels(bpp *
                                                      rtDesc.fWidth *
                                                      rtDesc.fHeight);
@@ -609,14 +609,39 @@
 #endif
 }
 
-bool GrContext::readPixels(int left, int top, int width, int height,
-                           GrTexture::PixelConfig config, void* buffer) {
-    this->flush(true);
-    return fGpu->readPixels(left, top, width, height, config, buffer);
+bool GrContext::readTexturePixels(GrTexture* texture,
+                                  int left, int top, int width, int height,
+                                  GrPixelConfig config, void* buffer) {
+
+    // TODO: code read pixels for textures that aren't rendertargets
+
+    this->flush();
+    GrRenderTarget* target = texture->asRenderTarget();
+    if (NULL != target) {
+        return fGpu->readPixels(target,
+                                left, top, width, height, 
+                                config, buffer);
+    } else {
+        return false;
+    }
+}
+
+bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
+                                      int left, int top, int width, int height,
+                                      GrPixelConfig config, void* buffer) {
+    uint32_t flushFlags = 0;
+    if (NULL == target) { 
+        flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
+    }
+
+    this->flush(flushFlags);
+    return fGpu->readPixels(target,
+                            left, top, width, height, 
+                            config, buffer);
 }
 
 void GrContext::writePixels(int left, int top, int width, int height,
-                            GrTexture::PixelConfig config, const void* buffer,
+                            GrPixelConfig config, const void* buffer,
                             size_t stride) {
 
     // TODO: when underlying api has a direct way to do this we should use it
@@ -764,6 +789,7 @@
 
     fGpu = gpu;
     fGpu->ref();
+    fGpu->setContext(this);
 
     fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
     fGpu->setClipPathRenderer(fCustomPathRenderer);
diff --git a/gpu/src/GrDrawTarget.cpp b/gpu/src/GrDrawTarget.cpp
index 7973361..bf4b91d 100644
--- a/gpu/src/GrDrawTarget.cpp
+++ b/gpu/src/GrDrawTarget.cpp
@@ -492,10 +492,10 @@
     for (int s = 0; s < kNumStages; ++s) {
         if (VertexUsesStage(s, fGeometrySrc.fVertexLayout)) {
             GrAssert(NULL != fCurrDrawState.fTextures[s]);
-            GrTexture::PixelConfig config = fCurrDrawState.fTextures[s]->config();
+            GrPixelConfig config = fCurrDrawState.fTextures[s]->config();
 
-            if (GrTexture::kRGB_565_PixelConfig != config &&
-                GrTexture::kRGBX_8888_PixelConfig != config) {
+            if (kRGB_565_GrPixelConfig != config &&
+                kRGBX_8888_GrPixelConfig != config) {
                 return false;
             }
         }
diff --git a/gpu/src/GrGpu.cpp b/gpu/src/GrGpu.cpp
index 31e4d99..06de3ac 100644
--- a/gpu/src/GrGpu.cpp
+++ b/gpu/src/GrGpu.cpp
@@ -28,42 +28,6 @@
 static const size_t VERTEX_POOL_VB_SIZE = 1 << 12;
 static const int VERTEX_POOL_VB_COUNT = 1;
 
-////////////////////////////////////////////////////////////////////////////////
-
-size_t GrTexture::BytesPerPixel(PixelConfig config) {
-    switch (config) {
-        case kAlpha_8_PixelConfig:
-        case kIndex_8_PixelConfig:
-            return 1;
-        case kRGB_565_PixelConfig:
-        case kRGBA_4444_PixelConfig:
-            return 2;
-        case kRGBA_8888_PixelConfig:
-        case kRGBX_8888_PixelConfig:
-            return 4;
-        default:
-            return 0;
-    }
-}
-
-bool GrTexture::PixelConfigIsOpaque(PixelConfig config) {
-    switch (config) {
-        case GrTexture::kRGB_565_PixelConfig:
-        case GrTexture::kRGBX_8888_PixelConfig:
-            return true;
-        default:
-            return false;
-    }
-}
-
-bool GrTexture::PixelConfigIsAlphaOnly(PixelConfig config) {
-    switch (config) {
-        case GrTexture::kAlpha_8_PixelConfig:
-            return true;
-        default:
-            return false;
-    }
-}
 
 ////////////////////////////////////////////////////////////////////////////////
 
@@ -75,6 +39,7 @@
     , fCurrPoolStartVertex(0)
     , fCurrPoolIndexBuffer(NULL)
     , fCurrPoolStartIndex(0)
+    , fContext(NULL)
     , fVertexPool(NULL)
     , fIndexPool(NULL)
     , fQuadIndexBuffer(NULL)
@@ -85,6 +50,7 @@
     , fVertexPoolInUse(false)
     , fIndexPoolInUse(false)
     , fResourceHead(NULL) {
+
 #if GR_DEBUG
     //gr_run_unittests();
 #endif
@@ -210,10 +176,17 @@
     this->forceRenderTargetFlushHelper();
 }
 
-bool GrGpu::readPixels(int left, int top, int width, int height,
-                       GrTexture::PixelConfig config, void* buffer) {
+bool GrGpu::readPixels(GrRenderTarget* target,
+                       int left, int top, int width, int height,
+                       GrPixelConfig config, void* buffer) {
+
     this->handleDirtyContext();
+    GrRenderTarget* prevTarget = fCurrDrawState.fRenderTarget;
+    if (NULL != target) {
+        fCurrDrawState.fRenderTarget = target;
+    }
     return this->readPixelsHelper(left, top, width, height, config, buffer);
+    fCurrDrawState.fRenderTarget = prevTarget;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -775,12 +748,6 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-
-GrTexture::~GrTexture() {
-    // use this to set a break-point if needed
-//    Gr_clz(3);
-}
-
 const GrSamplerState GrSamplerState::gClampNoFilter(
     GrSamplerState::kClamp_WrapMode,
     GrSamplerState::kClamp_WrapMode,
diff --git a/gpu/src/GrGpuGL.cpp b/gpu/src/GrGpuGL.cpp
index 1d159e3..e5f9fa2 100644
--- a/gpu/src/GrGpuGL.cpp
+++ b/gpu/src/GrGpuGL.cpp
@@ -666,7 +666,7 @@
         return return_null_texture();
     }
 
-    glDesc.fUploadByteCount = GrTexture::BytesPerPixel(desc.fFormat);
+    glDesc.fUploadByteCount = GrBytesPerPixel(desc.fFormat);
 
     // in case we need a temporary, trimmed copy of the src pixels
     GrAutoSMalloc<128 * 128> trimStorage;
@@ -728,7 +728,7 @@
                         DEFAULT_PARAMS.fWrapT));
 
     GR_GL(PixelStorei(GR_GL_UNPACK_ALIGNMENT, glDesc.fUploadByteCount));
-    if (GrTexture::kIndex_8_PixelConfig == desc.fFormat &&
+    if (kIndex_8_GrPixelConfig == desc.fFormat &&
         supports8BitPalette()) {
         // ES only supports CompressedTexImage2D, not CompressedTexSubimage2D
         GrAssert(desc.fWidth == glDesc.fAllocWidth);
@@ -1155,7 +1155,7 @@
 }
 
 bool GrGpuGL::readPixelsHelper(int left, int top, int width, int height,
-                               GrTexture::PixelConfig config, void* buffer) {
+                               GrPixelConfig config, void* buffer) {
     GrGLenum internalFormat;  // we don't use this for glReadPixels
     GrGLenum format;
     GrGLenum type;
@@ -1180,7 +1180,7 @@
     // now reverse the order of the rows, since GL's are bottom-to-top, but our
     // API presents top-to-bottom
     {
-        size_t stride = width * GrTexture::BytesPerPixel(config);
+        size_t stride = width * GrBytesPerPixel(config);
         GrAutoMalloc rowStorage(stride);
         void* tmp = rowStorage.get();
 
@@ -1767,13 +1767,13 @@
     }
 }
 
-bool GrGpuGL::canBeTexture(GrTexture::PixelConfig config,
+bool GrGpuGL::canBeTexture(GrPixelConfig config,
                            GrGLenum* internalFormat,
                            GrGLenum* format,
                            GrGLenum* type) {
     switch (config) {
-        case GrTexture::kRGBA_8888_PixelConfig:
-        case GrTexture::kRGBX_8888_PixelConfig: // todo: can we tell it our X?
+        case kRGBA_8888_GrPixelConfig:
+        case kRGBX_8888_GrPixelConfig: // todo: can we tell it our X?
             *format = GR_GL_32BPP_COLOR_FORMAT;
             if (GR_GL_SUPPORT_ES) {
                 // according to GL_EXT_texture_format_BGRA8888 the *internal*
@@ -1784,17 +1784,17 @@
             }
             *type = GR_GL_UNSIGNED_BYTE;
             break;
-        case GrTexture::kRGB_565_PixelConfig:
+        case kRGB_565_GrPixelConfig:
             *format = GR_GL_RGB;
             *internalFormat = GR_GL_RGB;
             *type = GR_GL_UNSIGNED_SHORT_5_6_5;
             break;
-        case GrTexture::kRGBA_4444_PixelConfig:
+        case kRGBA_4444_GrPixelConfig:
             *format = GR_GL_RGBA;
             *internalFormat = GR_GL_RGBA;
             *type = GR_GL_UNSIGNED_SHORT_4_4_4_4;
             break;
-        case GrTexture::kIndex_8_PixelConfig:
+        case kIndex_8_GrPixelConfig:
             if (this->supports8BitPalette()) {
                 *format = GR_GL_PALETTE8_RGBA8;
                 *internalFormat = GR_GL_PALETTE8_RGBA8;
@@ -1803,7 +1803,7 @@
                 return false;
             }
             break;
-        case GrTexture::kAlpha_8_PixelConfig:
+        case kAlpha_8_GrPixelConfig:
             *format = GR_GL_ALPHA;
             *internalFormat = GR_GL_ALPHA;
             *type = GR_GL_UNSIGNED_BYTE;
@@ -1835,23 +1835,23 @@
    RenderBufferStorage* has to be a specific format (not a base format like
    GL_RGBA).
  */
-bool GrGpuGL::fboInternalFormat(GrTexture::PixelConfig config, GrGLenum* format) {
+bool GrGpuGL::fboInternalFormat(GrPixelConfig config, GrGLenum* format) {
     switch (config) {
-        case GrTexture::kRGBA_8888_PixelConfig:
-        case GrTexture::kRGBX_8888_PixelConfig:
+        case kRGBA_8888_GrPixelConfig:
+        case kRGBX_8888_GrPixelConfig:
             if (fRGBA8Renderbuffer) {
                 *format = GR_GL_RGBA8;
                 return true;
             } else {
                 return false;
             }
-        case GrTexture::kRGB_565_PixelConfig:
+        case kRGB_565_GrPixelConfig:
             GrAssert(GR_GL_SUPPORT_ES);  // ES2 supports 565. ES1 supports it
                                          // with FBO extension desktop GL has
                                          // no such internal format
             *format = GR_GL_RGB565;
             return true;
-        case GrTexture::kRGBA_4444_PixelConfig:
+        case kRGBA_4444_GrPixelConfig:
             *format = GR_GL_RGBA4;
             return true;
         default:
diff --git a/gpu/src/GrGpuGL.h b/gpu/src/GrGpuGL.h
index 25414e4..3eedabf 100644
--- a/gpu/src/GrGpuGL.h
+++ b/gpu/src/GrGpuGL.h
@@ -87,7 +87,7 @@
     virtual void forceRenderTargetFlushHelper();
 
     virtual bool readPixelsHelper(int left, int top, int width, int height,
-                                  GrTexture::PixelConfig, void* buffer);
+                                  GrPixelConfig, void* buffer);
 
     virtual void drawIndexedHelper(GrPrimitiveType type,
                                    uint32_t startVertex,
@@ -149,11 +149,11 @@
     void flushStencil();
     void resolveTextureRenderTarget(GrGLTexture* texture);
 
-    bool canBeTexture(GrTexture::PixelConfig config,
+    bool canBeTexture(GrPixelConfig config,
                       GrGLenum* internalFormat,
                       GrGLenum* format,
                       GrGLenum* type);
-    bool fboInternalFormat(GrTexture::PixelConfig config, GrGLenum* format);
+    bool fboInternalFormat(GrPixelConfig config, GrGLenum* format);
 
     friend class GrGLVertexBuffer;
     friend class GrGLIndexBuffer;
diff --git a/gpu/src/GrGpuGLFixed.cpp b/gpu/src/GrGpuGLFixed.cpp
index 3e6d909..446949f 100644
--- a/gpu/src/GrGpuGLFixed.cpp
+++ b/gpu/src/GrGpuGLFixed.cpp
@@ -192,7 +192,7 @@
             GrGLTexture* texture = (GrGLTexture*)fCurrDrawState.fTextures[s];
             if (NULL != texture) {
                 TextureEnvRGBOperands nextRGBOperand0 =
-                    (texture->config() == GrTexture::kAlpha_8_PixelConfig) ?
+                    (GrPixelConfigIsAlphaOnly(texture->config())) ?
                         kAlpha_TextureEnvRGBOperand :
                         kColor_TextureEnvRGBOperand;
                 if (fHWRGBOperand0[s] != nextRGBOperand0) {
diff --git a/gpu/src/GrGpuGLShaders.cpp b/gpu/src/GrGpuGLShaders.cpp
index e4d9b3e..37931e3 100644
--- a/gpu/src/GrGpuGLShaders.cpp
+++ b/gpu/src/GrGpuGLShaders.cpp
@@ -508,7 +508,7 @@
                 break;
             }
 
-            if (GrTexture::kAlpha_8_PixelConfig == texture->config()) {
+            if (GrPixelConfigIsAlphaOnly(texture->config())) {
                 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation;
             } else {
                 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation;
diff --git a/gpu/src/GrGpuGLShaders2.cpp b/gpu/src/GrGpuGLShaders2.cpp
index a56e511..4deecd4 100644
--- a/gpu/src/GrGpuGLShaders2.cpp
+++ b/gpu/src/GrGpuGLShaders2.cpp
@@ -1042,7 +1042,7 @@
                 GrAssert(!"Unexpected sample mode!");
                 break;
             }
-            if (GrTexture::kAlpha_8_PixelConfig == texture->config()) {
+            if (GrPixelConfigIsAlphaOnly(texture->config())) {
                 stage.fModulation = StageDesc::kAlpha_Modulation;
             } else {
                 stage.fModulation = StageDesc::kColor_Modulation;
diff --git a/gpu/src/GrTextContext.cpp b/gpu/src/GrTextContext.cpp
index e2c81c7..09113e0 100644
--- a/gpu/src/GrTextContext.cpp
+++ b/gpu/src/GrTextContext.cpp
@@ -47,7 +47,7 @@
         GrAssert(fCurrTexture);
         fDrawTarget->setTexture(TEXT_STAGE, fCurrTexture);
 
-        if (!GrTexture::PixelConfigIsAlphaOnly(fCurrTexture->config())) {
+        if (!GrPixelConfigIsAlphaOnly(fCurrTexture->config())) {
             if (kOne_BlendCoeff != fPaint.fSrcBlendCoeff ||
                 kISA_BlendCoeff != fPaint.fDstBlendCoeff ||
                 NULL != fPaint.getTexture()) {
diff --git a/gpu/src/GrTexture.cpp b/gpu/src/GrTexture.cpp
new file mode 100644
index 0000000..7c5f87f
--- /dev/null
+++ b/gpu/src/GrTexture.cpp
@@ -0,0 +1,45 @@
+/*
+    Copyright 2011 Google Inc.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+ */
+
+#include "GrTexture.h"
+#include "GrContext.h"
+
+bool GrRenderTarget::readPixels(int left, int top, int width, int height,
+                                GrPixelConfig config, void* buffer) {
+    // go through context so that all necessary flushing occurs
+    GrContext* context = this->getGpu()->getContext();
+    GrAssert(NULL != context);
+    return context->readRenderTargetPixels(this,
+                                           left, top, 
+                                           width, height,
+                                           config, buffer);
+}
+
+GrTexture::~GrTexture() {
+    // use this to set a break-point if needed
+//    Gr_clz(3);
+}
+
+bool GrTexture::readPixels(int left, int top, int width, int height,
+                           GrPixelConfig config, void* buffer) {
+    // go through context so that all necessary flushing occurs
+    GrContext* context = this->getGpu()->getContext();
+    GrAssert(NULL != context);
+    return context->readTexturePixels(this,
+                                        left, top, 
+                                        width, height,
+                                        config, buffer);
+}
diff --git a/gyp/skia.gyp b/gyp/skia.gyp
index 123a34d..bd19c04 100644
--- a/gyp/skia.gyp
+++ b/gyp/skia.gyp
@@ -990,6 +990,7 @@
         '../gpu/src/GrTextContext.cpp',
         '../gpu/src/GrTextStrike.cpp',
         '../gpu/src/GrTextStrike_impl.h',
+        '../gpu/src/GrTexture.cpp',
         '../gpu/src/GrTextureCache.cpp',
         '../gpu/src/gr_unittests.cpp',
 
diff --git a/include/gpu/SkGr.h b/include/gpu/SkGr.h
index 49dac74..10f1bd0 100644
--- a/include/gpu/SkGr.h
+++ b/include/gpu/SkGr.h
@@ -129,10 +129,10 @@
      *  Convert the SkBitmap::Config to the corresponding PixelConfig, or
      *  kUnknown_PixelConfig if the conversion cannot be done.
      */
-    static GrTexture::PixelConfig BitmapConfig2PixelConfig(SkBitmap::Config,
-                                                        bool isOpaque);
+    static GrPixelConfig BitmapConfig2PixelConfig(SkBitmap::Config,
+                                                  bool isOpaque);
 
-    static GrTexture::PixelConfig Bitmap2PixelConfig(const SkBitmap& bm) {
+    static GrPixelConfig Bitmap2PixelConfig(const SkBitmap& bm) {
         return BitmapConfig2PixelConfig(bm.config(), bm.isOpaque());
     }
 
diff --git a/include/gpu/SkGrTexturePixelRef.h b/include/gpu/SkGrTexturePixelRef.h
index a423251..5bc64f5 100644
--- a/include/gpu/SkGrTexturePixelRef.h
+++ b/include/gpu/SkGrTexturePixelRef.h
@@ -47,5 +47,31 @@
     typedef SkPixelRef INHERITED;
 };
 
+class SkGrRenderTargetPixelRef : public SkPixelRef {
+public:
+            SkGrRenderTargetPixelRef(GrRenderTarget* rt);
+    virtual ~SkGrRenderTargetPixelRef();
+
+    // override from SkPixelRef
+    virtual SkGpuTexture* getTexture();
+
+protected:
+    // override from SkPixelRef
+    virtual void* onLockPixels(SkColorTable** ptr) {
+        if (ptr) {
+            *ptr = NULL;
+        }
+        return NULL;
+    }
+
+    // override from SkPixelRef
+    virtual void onUnlockPixels() {}
+    virtual bool onReadPixels(SkBitmap* dst, const SkIRect* subset);
+
+private:
+    GrRenderTarget*  fRenderTarget;
+    typedef SkPixelRef INHERITED;
+};
+
 #endif
 
diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp
index c525a5d..e58fa26 100644
--- a/samplecode/SampleApp.cpp
+++ b/samplecode/SampleApp.cpp
@@ -766,17 +766,12 @@
 
         SkCanvas* canvas = fGpuCanvas ? fGpuCanvas : orig;
         SkDevice* device = canvas->getDevice();
-        SkBitmap bitmap;
-        SkIRect bounds = {
-            0, 0,
-            SkScalarRound(this->width()),
-            SkScalarRound(this->height())
-        };
-        if (device->readPixels(bounds, &bitmap)) {
+        SkBitmap bmp;
+        if (device->accessBitmap(false).copyTo(&bmp, SkBitmap::kARGB_8888_Config)) {
             static int gSampleGrabCounter;
             SkString name;
             name.printf("sample_grab_%d", gSampleGrabCounter++);
-            SkImageEncoder::EncodeFile(name.c_str(), bitmap,
+            SkImageEncoder::EncodeFile(name.c_str(), bmp,
                                        SkImageEncoder::kPNG_Type, 100);
         }
     }
diff --git a/src/core/SkBitmap.cpp b/src/core/SkBitmap.cpp
index a9b9c99..c19e84d 100644
--- a/src/core/SkBitmap.cpp
+++ b/src/core/SkBitmap.cpp
@@ -869,10 +869,7 @@
     SkBitmap tmpSrc;
     const SkBitmap* src = this;
 
-    if (this->getTexture()) {
-        if (!fPixelRef->readPixels(&tmpSrc)) {
-            return false;
-        }
+    if (fPixelRef && fPixelRef->readPixels(&tmpSrc)) {
         SkASSERT(tmpSrc.width() == this->width());
         SkASSERT(tmpSrc.height() == this->height());
 
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index ce48be6..76777f0 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -171,11 +171,15 @@
                      this->width(), this->height());
             GrAssert(false);
         }
-    } else if (Current3DApiRenderTarget() == renderTargetOrNull) {
-        fRenderTarget = fContext->createRenderTargetFrom3DApiState();
     } else {
-        fRenderTarget = renderTargetOrNull;
-        fRenderTarget->ref();
+        if (Current3DApiRenderTarget() == renderTargetOrNull) {
+            fRenderTarget = fContext->createRenderTargetFrom3DApiState();
+        } else {
+            fRenderTarget = renderTargetOrNull;
+            fRenderTarget->ref();
+        }
+        SkGrRenderTargetPixelRef* pr = new SkGrRenderTargetPixelRef(fRenderTarget);
+        this->setPixelRef(pr, 0)->unref();
     }
 }
 
@@ -233,15 +237,12 @@
     }
 
     SkAutoLockPixels alp(tmp);
-    fContext->setRenderTarget(fRenderTarget);
-    // we aren't setting the clip or matrix, so mark as dirty
-    // we don't need to set them for this call and don't have them anyway
-    fNeedPrepareRenderTarget = true;
 
-    if (!fContext->readPixels(bounds.fLeft, bounds.fTop,
-                              bounds.width(), bounds.height(),
-                              GrTexture::kRGBA_8888_PixelConfig,
-                              tmp.getPixels())) {
+    if (!fContext->readRenderTargetPixels(fRenderTarget,
+                                          bounds.fLeft, bounds.fTop,
+                                          bounds.width(), bounds.height(),
+                                          kRGBA_8888_GrPixelConfig,
+                                          tmp.getPixels())) {
         return false;
     }
 
@@ -254,8 +255,8 @@
     if (!bitmap.readyToDraw()) {
         return;
     }
-    GrTexture::PixelConfig config = SkGr::BitmapConfig2PixelConfig(bitmap.config(),
-                                                                   bitmap.isOpaque());
+    GrPixelConfig config = SkGr::BitmapConfig2PixelConfig(bitmap.config(),
+                                                          bitmap.isOpaque());
     fContext->setRenderTarget(fRenderTarget);
     // we aren't setting the clip or matrix, so mark as dirty
     // we don't need to set them for this call and don't have them anyway
@@ -709,7 +710,7 @@
         GrGpu::kNone_AALevel,
         dstM.fBounds.width(),
         dstM.fBounds.height(),
-        GrTexture::kAlpha_8_PixelConfig
+        kAlpha_8_GrPixelConfig
     };
 
     GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index 630c3f4..e7e2365 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -213,25 +213,25 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-GrTexture::PixelConfig SkGr::BitmapConfig2PixelConfig(SkBitmap::Config config,
+GrPixelConfig SkGr::BitmapConfig2PixelConfig(SkBitmap::Config config,
                                                     bool isOpaque) {
     switch (config) {
         case SkBitmap::kA8_Config:
-            return GrTexture::kAlpha_8_PixelConfig;
+            return kAlpha_8_GrPixelConfig;
         case SkBitmap::kIndex8_Config:
-            return GrTexture::kIndex_8_PixelConfig;
+            return kIndex_8_GrPixelConfig;
         case SkBitmap::kRGB_565_Config:
-            return GrTexture::kRGB_565_PixelConfig;
+            return kRGB_565_GrPixelConfig;
         case SkBitmap::kARGB_4444_Config:
-            return GrTexture::kRGBA_4444_PixelConfig;
+            return kRGBA_4444_GrPixelConfig;
         case SkBitmap::kARGB_8888_Config:
             if (isOpaque) {
-                return GrTexture::kRGBX_8888_PixelConfig;
+                return kRGBX_8888_GrPixelConfig;
             } else {
-                return GrTexture::kRGBA_8888_PixelConfig;
+                return kRGBA_8888_GrPixelConfig;
             }
         default:
-            return GrTexture::kUnknown_PixelConfig;
+            return kUnknown_GrPixelConfig;
     }
 }
 
diff --git a/src/gpu/SkGrTexturePixelRef.cpp b/src/gpu/SkGrTexturePixelRef.cpp
index de19f1d..2b173f1 100644
--- a/src/gpu/SkGrTexturePixelRef.cpp
+++ b/src/gpu/SkGrTexturePixelRef.cpp
@@ -16,8 +16,12 @@
 
 
 #include "SkGrTexturePixelRef.h"
+
 #include "GrTexture.h"
 
+#include "SkRect.h"
+#include "SkBitmap.h"
+
 SkGrTexturePixelRef::SkGrTexturePixelRef(GrTexture* tex) {
     fTexture = tex;
     GrSafeRef(tex);
@@ -28,6 +32,71 @@
 }
 
 bool SkGrTexturePixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) {
-    return false;
+    if (NULL != fTexture && fTexture->isValid()) {
+        int left, top, width, height;
+        if (NULL != subset) {
+            left = subset->fLeft;
+            width = subset->width();
+            top = subset->fTop;
+            height = subset->height();
+        } else {
+            left = 0;
+            width = fTexture->width();
+            top = 0;
+            height = fTexture->height();
+        }
+        dst->setConfig(SkBitmap::kARGB_8888_Config, width, height);
+        dst->allocPixels();
+        SkAutoLockPixels al(*dst);
+        void* buffer = dst->getPixels();
+        return fTexture->readPixels(left, top, width, height,
+                                    kRGBA_8888_GrPixelConfig,
+                                    buffer);
+    } else {
+        return false;
+    }
 }
 
+////////////////////////////////////////////////////////////////////////////////
+
+SkGrRenderTargetPixelRef::SkGrRenderTargetPixelRef(GrRenderTarget* rt) {
+    fRenderTarget = rt;
+    GrSafeRef(fRenderTarget);
+}
+
+SkGrRenderTargetPixelRef::~SkGrRenderTargetPixelRef() {
+    GrSafeUnref(fRenderTarget);
+}
+
+SkGpuTexture* SkGrRenderTargetPixelRef::getTexture() { 
+    if (NULL != fRenderTarget) {
+        return (SkGpuTexture*) fRenderTarget->asTexture();
+    }
+    return NULL;
+}
+
+bool SkGrRenderTargetPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) {
+    if (NULL != fRenderTarget && fRenderTarget->isValid()) {
+        int left, top, width, height;
+        if (NULL != subset) {
+            left = subset->fLeft;
+            width = subset->width();
+            top = subset->fTop;
+            height = subset->height();
+        } else {
+            left = 0;
+            width = fRenderTarget->width();
+            top = 0;
+            height = fRenderTarget->height();
+        }
+        dst->setConfig(SkBitmap::kARGB_8888_Config, width, height);
+        dst->allocPixels();
+        SkAutoLockPixels al(*dst);
+        void* buffer = dst->getPixels();
+        return fRenderTarget->readPixels(left, top, width, height,
+                                         kRGBA_8888_GrPixelConfig,
+                                         buffer);
+    } else {
+        return false;
+    }
+}
\ No newline at end of file