Remove notion of default rendertarget. This doesn't map well to usage patterns outside sample app. Make binding between SkGpuDevice and a GrRenderTarget more explicit. Create method on GrContext to wrap the current target in the 3D API with a GrRenderTarget.



git-svn-id: http://skia.googlecode.com/svn/trunk@706 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/include/GrContext.h b/gpu/include/GrContext.h
index a931695..905fe50 100644
--- a/gpu/include/GrContext.h
+++ b/gpu/include/GrContext.h
@@ -41,7 +41,7 @@
      *  Helper to create a opengl-shader based context

      */

     static GrContext* CreateGLShaderContext();

-    

+

     virtual ~GrContext();

 

     /**

@@ -115,6 +115,19 @@
                                                int width, int height);

 

     /**

+     * Reads the current target object (e.g. FBO or IDirect3DSurface9*) and

+     * viewport state from the underlying 3D API and wraps it in a

+     * GrRenderTarget. The GrRenderTarget will not attempt to delete/destroy the

+     * underlying object in its destructor and it is up to caller to guarantee

+     * that it remains valid while the GrRenderTarget is used.

+     *

+     * @return the newly created GrRenderTarget

+     */

+    GrRenderTarget* createRenderTargetFrom3DApiState() {

+        return fGpu->createRenderTargetFrom3DApiState();

+    }

+

+    /**

      *  Returns true if the specified use of an indexed texture is supported.

      */

     bool supportsIndex8PixelConfig(const GrSamplerState&, int width, int height);

@@ -126,8 +139,6 @@
     const GrClip& getClip() const { return fGpu->getClip(); }

 

     void setRenderTarget(GrRenderTarget* target);

-    void setDefaultRenderTargetSize(uint32_t width, uint32_t height);

-    GrRenderTarget* defaultRenderTarget() { return fGpu->defaultRenderTarget(); }

 

     void setTexture(int stage, GrTexture* texture);

     void setSamplerState(int stage, const GrSamplerState&);

diff --git a/gpu/include/GrGpu.h b/gpu/include/GrGpu.h
index f1fdf01..6cbe53e 100644
--- a/gpu/include/GrGpu.h
+++ b/gpu/include/GrGpu.h
@@ -197,6 +197,17 @@
                                                 int width, int height) = 0;
 
     /**
+     * Reads the current target object (e.g. FBO or IDirect3DSurface9*) and
+     * viewport state from the underlying 3D API and wraps it in a
+     * GrRenderTarget. The GrRenderTarget will not attempt to delete/destroy the
+     * underlying object in its destructor and it is up to caller to guarantee
+     * that it remains valid while the GrRenderTarget is used.
+     *
+     * @return the newly created GrRenderTarget
+     */
+    virtual GrRenderTarget* createRenderTargetFrom3DApiState() = 0;
+
+    /**
      * Creates a vertex buffer.
      *
      * @param size    size in bytes of the vertex buffer
@@ -221,21 +232,6 @@
     virtual GrIndexBuffer* createIndexBuffer(uint32_t size, bool dynamic) = 0;
 
     /**
-     * Gets the default render target. This is the render target set in the
-     * 3D API at the time the GrGpu was created.
-     */
-    virtual GrRenderTarget* defaultRenderTarget() = 0;
-
-    /**
-     * At construction time the GrGpu infers the render target and viewport from
-     * the state of the underlying 3D API. However, a platform-specific resize
-     * event may occur.
-     * @param width     new width of the default rendertarget
-     * @param height    new height of the default rendertarget
-     */
-    virtual void setDefaultRenderTargetSize(uint32_t width, uint32_t height) = 0;
-
-    /**
      * Erase the entire render target, ignoring any clips/scissors.
      *
      * This is issued to the GPU driver immediately.
diff --git a/gpu/src/GrContext.cpp b/gpu/src/GrContext.cpp
index 94398cf..5128602 100644
--- a/gpu/src/GrContext.cpp
+++ b/gpu/src/GrContext.cpp
@@ -30,8 +30,8 @@
 

 #if DEFER_TEXT_RENDERING

     static const uint32_t POOL_VB_SIZE = 2048 *

-            GrDrawTarget::VertexSize(
-                GrDrawTarget::kTextFormat_VertexLayoutBit |
+            GrDrawTarget::VertexSize(

+                GrDrawTarget::kTextFormat_VertexLayoutBit |

                 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0));

     static const uint32_t NUM_POOL_VBS = 8;

 #else

@@ -856,10 +856,6 @@
     return fGpu->currentRenderTarget();

 }

 

-void GrContext::setDefaultRenderTargetSize(uint32_t width, uint32_t height) {

-    fGpu->setDefaultRenderTargetSize(width, height);

-}

-

 void GrContext::setSamplerState(int stage, const GrSamplerState& samplerState) {

     fGpu->setSamplerState(stage, samplerState);

 }

diff --git a/gpu/src/GrGpu.cpp b/gpu/src/GrGpu.cpp
index fe6d0c3..c48bd19 100644
--- a/gpu/src/GrGpu.cpp
+++ b/gpu/src/GrGpu.cpp
@@ -178,6 +178,14 @@
 bool GrGpu::setupClipAndFlushState(PrimitiveType type) {
     const GrIRect* r = NULL;
 
+    // we check this early because we need a valid
+    // render target to setup stencil clipping
+    // before even going into flushGraphicsState
+    if (NULL == fCurrDrawState.fRenderTarget) {
+        GrAssert(!"No render target bound.");
+        return false;
+    }
+
     if (fCurrDrawState.fFlagBits & kClip_StateBit) {
         fClipState.fClipInStencil = fClip.countRects() > 1;
 
diff --git a/gpu/src/GrGpuGL.cpp b/gpu/src/GrGpuGL.cpp
index 23636d1..084f98f 100644
--- a/gpu/src/GrGpuGL.cpp
+++ b/gpu/src/GrGpuGL.cpp
@@ -152,24 +152,7 @@
 
     resetContextHelper();
 
-    GrGLRenderTarget::GLRenderTargetIDs defaultRTIDs;
-    GR_GL_GetIntegerv(GR_FRAMEBUFFER_BINDING, (GLint*)&defaultRTIDs.fRTFBOID);
-    defaultRTIDs.fTexFBOID = defaultRTIDs.fRTFBOID;
-    defaultRTIDs.fMSColorRenderbufferID = 0;
-    defaultRTIDs.fStencilRenderbufferID = 0;
-    GLint vp[4];
-    GR_GL_GetIntegerv(GL_VIEWPORT, vp);
-    fHWBounds.fViewportRect.setLTRB(vp[0],
-                                    vp[1] + vp[3],
-                                    vp[0] + vp[2],
-                                    vp[1]);
-    defaultRTIDs.fOwnIDs = false;
-
-    fDefaultRenderTarget = new GrGLRenderTarget(defaultRTIDs,
-                                                fHWBounds.fViewportRect,
-                                                NULL,
-                                                this);
-    fHWDrawState.fRenderTarget = fDefaultRenderTarget;
+    fHWDrawState.fRenderTarget = NULL;
     fRenderTargetChanged = true;
 
     GLint maxTextureUnits;
@@ -445,17 +428,13 @@
     fMinRenderTargetWidth = GrMax<GLuint>(fMinRenderTargetWidth, 16);
     fMinRenderTargetHeight = GrMax<GLuint>(fMinRenderTargetHeight, 16);
 #endif
-    // bind back to original FBO
-    GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, defaultRTIDs.fRTFBOID));
+
 #if GR_COLLECT_STATS
     ++fStats.fRenderTargetChngCnt;
 #endif
-    eraseStencil(0, ~0);
 }
 
 GrGpuGL::~GrGpuGL() {
-    fDefaultRenderTarget->abandon();
-    fDefaultRenderTarget->unref();
 }
 
 void GrGpuGL::resetContextHelper() {
@@ -501,6 +480,7 @@
     fHWBounds.fScissorRect.setLTRB(0,0,0,0);
     fHWBounds.fScissorEnabled = false;
     GR_GL(Disable(GL_SCISSOR_TEST));
+    fHWBounds.fViewportRect.setLTRB(-1,-1,-1,-1);
 
     // disabling the stencil test also disables
     // stencil buffer writes
@@ -546,6 +526,30 @@
     return rt;
 }
 
+GrRenderTarget* GrGpuGL::createRenderTargetFrom3DApiState() {
+    
+    GrGLRenderTarget::GLRenderTargetIDs rtIDs;
+    
+    GR_GL_GetIntegerv(GR_FRAMEBUFFER_BINDING, (GLint*)&rtIDs.fRTFBOID);
+    rtIDs.fTexFBOID = rtIDs.fRTFBOID;
+    rtIDs.fMSColorRenderbufferID = 0;
+    rtIDs.fStencilRenderbufferID = 0;
+    
+    GLint vp[4];
+    GR_GL_GetIntegerv(GL_VIEWPORT, vp);
+    GrIRect viewportRect;
+    viewportRect.setLTRB(vp[0],
+                         vp[1] + vp[3],
+                         vp[0] + vp[2],
+                         vp[1]);
+    rtIDs.fOwnIDs = false;
+
+    return new GrGLRenderTarget(rtIDs,
+                                viewportRect,
+                                NULL,
+                                this);
+}
+
 // defines stencil formats from more to less preferred
 GLenum GR_GL_STENCIL_FORMAT_ARRAY[] = {

     GR_STENCIL_INDEX8,

@@ -979,10 +983,6 @@
     return tex;
 }
 
-GrRenderTarget* GrGpuGL::defaultRenderTarget() {
-    return fDefaultRenderTarget;
-}
-
 GrVertexBuffer* GrGpuGL::createVertexBuffer(uint32_t size, bool dynamic) {
     GLuint id;
     GR_GL(GenBuffers(1, &id));
@@ -1029,16 +1029,6 @@
     return NULL;
 }
 
-void GrGpuGL::setDefaultRenderTargetSize(uint32_t width, uint32_t height) {
-    GrIRect viewport(0, height, width, 0);
-    if (viewport != fDefaultRenderTarget->viewport()) {
-        fDefaultRenderTarget->setViewport(viewport);
-        if (fHWDrawState.fRenderTarget == fDefaultRenderTarget) {
-            fHWDrawState.fRenderTarget = NULL;
-        }
-    }
-}
-
 void GrGpuGL::flushScissor(const GrIRect* rect) {
     GrAssert(NULL != fCurrDrawState.fRenderTarget);
     const GrIRect& vp =
@@ -1153,6 +1143,9 @@
 }
 
 void GrGpuGL::flushRenderTarget() {
+
+    GrAssert(NULL != fCurrDrawState.fRenderTarget);
+
     if (fHWDrawState.fRenderTarget != fCurrDrawState.fRenderTarget) {
         GrGLRenderTarget* rt = (GrGLRenderTarget*)fCurrDrawState.fRenderTarget;
         GR_GLEXT(fExts, BindFramebuffer(GR_FRAMEBUFFER, rt->renderFBOID()));
@@ -1459,7 +1452,11 @@
     }
 }
 
-void GrGpuGL::flushGLStateCommon(PrimitiveType type) {
+bool GrGpuGL::flushGLStateCommon(PrimitiveType type) {
+
+    // GrGpu::setupClipAndFlushState should have already checked this
+    // and bailed if not true.
+    GrAssert(NULL != fCurrDrawState.fRenderTarget);
 
     for (int s = 0; s < kNumStages; ++s) {
         bool usingTexture = VertexUsesStage(s, fGeometrySrc.fVertexLayout);
@@ -1521,15 +1518,7 @@
                 nextTexture->setTexParams(newTexParams);
             } else {
                 GrAssert(!"Rendering with texture vert flag set but no texture");
-                if (NULL != fHWDrawState.fTextures[s]) {
-                    setTextureUnit(s);
-                    GR_GL(BindTexture(GL_TEXTURE_2D, 0));
-                    //            GrPrintf("---- bindtexture 0\n");
-                #if GR_COLLECT_STATS
-                    ++fStats.fTextureChngCnt;
-                #endif
-                    fHWDrawState.fTextures[s] = NULL;
-                }
+                return false;
             }
         }
     }
@@ -1607,6 +1596,7 @@
     flushStencil();
 
     fHWDrawState.fFlagBits = fCurrDrawState.fFlagBits;
+    return true;
 }
 
 void GrGpuGL::notifyVertexBufferBind(const GrGLVertexBuffer* buffer) {
@@ -1645,7 +1635,7 @@
     // b) we set more state than just FBO based on the RT
     // So trash the HW state to force an RT flush next time
     if (fCurrDrawState.fRenderTarget == renderTarget) {
-        fCurrDrawState.fRenderTarget = fDefaultRenderTarget;
+        fCurrDrawState.fRenderTarget = NULL;
     }
     if (fHWDrawState.fRenderTarget == renderTarget) {
         fHWDrawState.fRenderTarget = NULL;
diff --git a/gpu/src/GrGpuGL.h b/gpu/src/GrGpuGL.h
index 8c2cd80..611485d 100644
--- a/gpu/src/GrGpuGL.h
+++ b/gpu/src/GrGpuGL.h
@@ -42,9 +42,7 @@
                                                  intptr_t platformRenderTarget,
                                                  int width, int height);
 
-    virtual GrRenderTarget* defaultRenderTarget();
-
-    virtual void setDefaultRenderTargetSize(uint32_t width, uint32_t height);
+    virtual GrRenderTarget* createRenderTargetFrom3DApiState();
 
     virtual void eraseColor(GrColor color);
 
@@ -98,7 +96,7 @@
     // sampler state (filtering, tiling)
     // FBO binding
     // line width
-    void flushGLStateCommon(PrimitiveType type);
+    bool flushGLStateCommon(PrimitiveType type);
 
     // set when this class changes the rendertarget.
     // Subclass should notice at flush time, take appropriate action,
@@ -114,8 +112,6 @@
     GrGLExts fExts;
 
 private:
-    GrGLRenderTarget* fDefaultRenderTarget;
-
     void resetContextHelper();
 
     // notify callbacks to update state tracking when related
diff --git a/gpu/src/GrGpuGLFixed.cpp b/gpu/src/GrGpuGLFixed.cpp
index d142b66..99a593d 100644
--- a/gpu/src/GrGpuGLFixed.cpp
+++ b/gpu/src/GrGpuGLFixed.cpp
@@ -140,7 +140,9 @@
         }
     }
     
-    flushGLStateCommon(type);
+    if (!flushGLStateCommon(type)) {
+        return false;
+    }
 
     if (fRenderTargetChanged) {    
         flushProjectionMatrix();
diff --git a/gpu/src/GrGpuGLShaders.cpp b/gpu/src/GrGpuGLShaders.cpp
index 7cd1891..03d4674 100644
--- a/gpu/src/GrGpuGLShaders.cpp
+++ b/gpu/src/GrGpuGLShaders.cpp
@@ -741,7 +741,9 @@
         }
     }
 
-    flushGLStateCommon(type);
+    if (!flushGLStateCommon(type)) {
+        return false;
+    }
 
     if (fRenderTargetChanged) {
         // our coords are in pixel space and the GL matrices map to NDC
diff --git a/gpu/src/GrGpuGLShaders2.cpp b/gpu/src/GrGpuGLShaders2.cpp
index e47fe5d..1218a36 100644
--- a/gpu/src/GrGpuGLShaders2.cpp
+++ b/gpu/src/GrGpuGLShaders2.cpp
@@ -1233,7 +1233,9 @@
 
 bool GrGpuGLShaders2::flushGraphicsState(PrimitiveType type) {
 
-    flushGLStateCommon(type);
+    if (!flushGLStateCommon(type)) {
+        return false;
+    }
 
     if (fRenderTargetChanged) {
         // our coords are in pixel space and the GL matrices map to NDC
diff --git a/include/gpu/SkGpuCanvas.h b/include/gpu/SkGpuCanvas.h
index 8194e12..57a4b1b 100644
--- a/include/gpu/SkGpuCanvas.h
+++ b/include/gpu/SkGpuCanvas.h
@@ -21,6 +21,7 @@
 #include "SkCanvas.h"
 
 class GrContext;
+class GrRenderTarget;
 
 /**
  *  Subclass of canvas that creates devices compatible with the GrContext pass
@@ -32,8 +33,15 @@
      *  The GrContext object is reference counted. When passed to our
      *  constructor, its reference count is incremented. In our destructor, the
      *  GrGpu's reference count will be decremented.
+     *  GrRenderTarget represents the rendering destination in the underlying
+     *  3D API. Its reference count is incremented in the constructor and
+     *  decremented in the destructor.
+     *  SkGpuDevice::Current3DApiRenderTarget() can be passed as a special
+     *  value that will cause the factory to create a render target object
+     *  that reflects the state of the underlying 3D API at the time of
+     *  construction.
      */
-    explicit SkGpuCanvas(GrContext*);
+    explicit SkGpuCanvas(GrContext*, GrRenderTarget*);
     virtual ~SkGpuCanvas();
 
     /**
diff --git a/include/gpu/SkGpuDevice.h b/include/gpu/SkGpuDevice.h
index 141ed96..9c612c5 100644
--- a/include/gpu/SkGpuDevice.h
+++ b/include/gpu/SkGpuDevice.h
@@ -32,7 +32,22 @@
  */
 class SkGpuDevice : public SkDevice {
 public:
-    SkGpuDevice(GrContext*, const SkBitmap& bitmap, bool isLayer);
+    /**
+     * The SkGpuDevice will render to the GrRenderTarget, or if the paremeter is
+     * null it will create its own render target and manage that target's
+     * lifetime.
+     */
+    SkGpuDevice(GrContext*,
+                const SkBitmap& bitmap,
+                GrRenderTarget* renderTargetOrNull);
+
+    /**
+     * Magic value that can be passed to constructor. Causes
+     * the device to infer rendertarget from underlying 3D API (e.g. GL or D3D).
+     * This isn't a valid pointer, don't attempt to dereference.
+     */
+    static GrRenderTarget* Current3DApiRenderTarget();
+
     virtual ~SkGpuDevice();
 
     GrContext* context() const { return fContext; }
@@ -46,14 +61,6 @@
      */
     intptr_t getLayerTextureHandle() const;
 
-    /**
-     * Attaches the device to a rendering surface. This device will then render
-     * to the surface.
-     * For example, in OpenGL, the device will interpret handle as an FBO ID
-     * and drawing to the device would direct GL to the FBO.
-     */
-    void bindDeviceToTargetHandle(intptr_t handle);
-
     // call to set the clip to the specified rect
     void scissor(const SkIRect&);
 
diff --git a/include/gpu/SkGpuDeviceFactory.h b/include/gpu/SkGpuDeviceFactory.h
index dd57da2..5dcba6a 100644
--- a/include/gpu/SkGpuDeviceFactory.h
+++ b/include/gpu/SkGpuDeviceFactory.h
@@ -26,8 +26,14 @@
     /**
      *  The constructor will ref() the context, passing it to each device
      *  that it creates. It will be unref()'d in the destructor
+     *  Non-layered devices created by the factory will draw to the
+     *  rootRenderTarget. rootRenderTarget is ref-counted by the factory.
+     *  SkGpuDevice::Current3DApiRenderTarget() can be passed as a special
+     *  value that will cause the factory to create a render target object
+     *  that reflects the state of the underlying 3D API at the time of
+     *  construction.
      */
-    SkGpuDeviceFactory(GrContext*);
+    SkGpuDeviceFactory(GrContext*, GrRenderTarget* rootRenderTarget);
 
     virtual ~SkGpuDeviceFactory();
 
@@ -36,6 +42,7 @@
 
 private:
     GrContext* fContext;
+    GrRenderTarget* fRootRenderTarget;
 };
 
 #endif
diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp
index 9600b95..bf8cb6b 100644
--- a/samplecode/SampleApp.cpp
+++ b/samplecode/SampleApp.cpp
@@ -36,7 +36,7 @@
         gHead = NULL;
         gOnce = true;
     }
-    
+
     fChain = gHead;
     gHead = this;
 }
@@ -45,21 +45,6 @@
     #define SK_USE_SHADERS
 #endif
 
-static GrContext* get_global_grctx(SkOSWindow* oswin) {
-    // should be pthread-local at least
-    static GrContext* ctx;
-    if (NULL == ctx) {
-#if defined(SK_SUPPORT_GL)
-    #if defined(SK_USE_SHADERS)
-        ctx = GrContext::Create(GrGpu::kOpenGL_Shaders_Engine, NULL);
-    #else
-        ctx = GrContext::Create(GrGpu::kOpenGL_Fixed_Engine, NULL);
-    #endif
-#endif
-    }
-    return ctx;
-}
-
 //////////////////////////////////////////////////////////////////////////////
 
 static const char gCharEvtName[] = "SampleCode_Char_Event";
@@ -156,12 +141,12 @@
     virtual bool onHandleKey(SkKey key);
     virtual bool onHandleChar(SkUnichar);
     virtual void onSizeChange();
-    
+
     virtual SkCanvas* beforeChildren(SkCanvas*);
     virtual void afterChildren(SkCanvas*);
     virtual void beforeChild(SkView* child, SkCanvas* canvas);
     virtual void afterChild(SkView* child, SkCanvas* canvas);
-    
+
     virtual bool onEvent(const SkEvent& evt);
     virtual bool onQuery(SkEvent* evt);
 
@@ -170,18 +155,21 @@
     virtual bool handleEvent(const SkEvent& evt);
     virtual bool handleKey(SkKey key);
     virtual bool handleKeyUp(SkKey key);
-    
+
     virtual bool onClick(Click* click);
     virtual Click* onFindClickHandler(SkScalar x, SkScalar y);
     virtual bool onHandleKeyUp(SkKey key);
 #endif
+
 private:
     int fCurrIndex;
-    
+
     SkPicture* fPicture;
     SkGpuCanvas* fGpuCanvas;
+    GrContext* fGrContext;
+    GrRenderTarget* fGrRenderTarget;
     SkPath fClipPath;
-    
+
     enum CanvasType {
         kRaster_CanvasType,
         kPicture_CanvasType,
@@ -196,9 +184,11 @@
     bool fRotate;
     bool fScale;
     bool fRequestGrabImage;
-    
+
     int fScrollTestX, fScrollTestY;
-    
+
+    bool make3DReady();
+
     void loadView(SkView*);
     void updateTitle();
     bool nextSample();
@@ -209,13 +199,48 @@
             evt->post(this->getSinkID(), ANIMATING_DELAY);
         }
     }
-    
-    
+
+
     static CanvasType cycle_canvastype(CanvasType);
 
     typedef SkOSWindow INHERITED;
 };
 
+bool SampleWindow::make3DReady() {
+
+#if defined(SK_SUPPORT_GL)
+    #if defined(USE_OFFSCREEN)
+        // first clear the raster bitmap, so we don't see any leftover bits
+        bitmap.eraseColor(0);
+        // now setup our glcanvas
+        attachGL(&bitmap);
+    #else
+        attachGL(NULL);
+    #endif
+
+    if (NULL == fGrContext) {
+        SkASSERT(NULL == fGrRenderTarget);
+    #if defined(SK_USE_SHADERS)
+        fGrContext = GrContext::Create(GrGpu::kOpenGL_Shaders_Engine, NULL);
+    #else
+        fGrContext = GrContext::Create(GrGpu::kOpenGL_Fixed_Engine, NULL);
+    #endif
+        if (NULL != fGrContext) {
+            fGrRenderTarget = fGrContext->createRenderTargetFrom3DApiState();
+        }
+    }
+
+    if (NULL != fGrContext) {
+        SkASSERT(NULL != fGrRenderTarget);
+        return true;
+    } else {
+        detachGL();
+    }
+#endif
+    SkDebugf("Failed to setup 3D");
+    return false;
+}
+
 SampleWindow::CanvasType SampleWindow::cycle_canvastype(CanvasType ct) {
     static const CanvasType gCT[] = {
         kPicture_CanvasType,
@@ -229,6 +254,9 @@
     fPicture = NULL;
     fGpuCanvas = NULL;
 
+    fGrContext = NULL;
+    fGrRenderTarget = NULL;
+
 #ifdef DEFAULT_TO_GPU
     fCanvasType = kGPU_CanvasType;
 #else
@@ -263,6 +291,12 @@
 SampleWindow::~SampleWindow() {
     delete fPicture;
     delete fGpuCanvas;
+    if (NULL != fGrRenderTarget) {
+        fGrRenderTarget->unref();
+    }
+    if (NULL != fGrContext) {
+        fGrContext->unref();
+    }
 }
 
 static SkBitmap capture_bitmap(SkCanvas* canvas) {
@@ -275,7 +309,7 @@
 static bool bitmap_diff(SkCanvas* canvas, const SkBitmap& orig,
                         SkBitmap* diff) {
     const SkBitmap& src = canvas->getDevice()->accessBitmap(false);
-    
+
     SkAutoLockPixels alp0(src);
     SkAutoLockPixels alp1(orig);
     for (int y = 0; y < src.height(); y++) {
@@ -324,7 +358,7 @@
                 this->INHERITED::draw(canvas);
             }
         }
-        
+
         SkBitmap diff;
         if (bitmap_diff(canvas, orig, &diff)) {
         }
@@ -360,13 +394,13 @@
 SkCanvas* SampleWindow::beforeChildren(SkCanvas* canvas) {
     SkIPoint viewport;
     bool alreadyGPU = canvas->getViewport(&viewport);
-    
+
     if (kGPU_CanvasType != fCanvasType) {
 #ifdef SK_SUPPORT_GL
         detachGL();
-#endif   
+#endif
     }
-    
+
     switch (fCanvasType) {
         case kRaster_CanvasType:
             canvas = this->INHERITED::beforeChildren(canvas);
@@ -376,27 +410,17 @@
             canvas = fPicture->beginRecording(9999, 9999);
             break;
         case kGPU_CanvasType: {
-            if (!alreadyGPU) {
+            if (!alreadyGPU && make3DReady()) {
                 SkDevice* device = canvas->getDevice();
-                const SkBitmap& bitmap = device->accessBitmap(true);            
-#ifdef SK_SUPPORT_GL                
-    #ifdef USE_OFFSCREEN
-                // first clear the raster bitmap, so we don't see any leftover bits
-                bitmap.eraseColor(0);
-                // now setup our glcanvas
-                attachGL(&bitmap);
-    #else
-                attachGL(NULL);
-    #endif
-                glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
-#endif
-                fGpuCanvas = new SkGpuCanvas(get_global_grctx(this));
+                const SkBitmap& bitmap = device->accessBitmap(true);
+
+                fGpuCanvas = new SkGpuCanvas(fGrContext, fGrRenderTarget);
                 device = fGpuCanvas->createDevice(SkBitmap::kARGB_8888_Config,
                                                   bitmap.width(), bitmap.height(),
                                                   false, false);
                 fGpuCanvas->setDevice(device)->unref();
                 canvas = fGpuCanvas;
-                
+
             } else {
                 canvas = this->INHERITED::beforeChildren(canvas);
             }
@@ -425,7 +449,7 @@
 void SampleWindow::afterChildren(SkCanvas* orig) {
     if (fRequestGrabImage) {
         fRequestGrabImage = false;
-        
+
         SkCanvas* canvas = fGpuCanvas ? fGpuCanvas : orig;
         SkDevice* device = canvas->getDevice();
         SkBitmap bitmap;
@@ -452,7 +476,7 @@
                 SkDynamicMemoryWStream ostream;
                 fPicture->serialize(&ostream);
                 fPicture->unref();
-                
+
                 SkMemoryStream istream(ostream.getStream(), ostream.getOffset());
                 SkPicture pict(&istream);
                 orig->drawPicture(pict);
@@ -473,7 +497,7 @@
             break;
 #endif
     }
-    
+
 //    if ((fScrollTestX | fScrollTestY) != 0)
     if (false) {
         const SkBitmap& bm = orig->getDevice()->accessBitmap(true);
@@ -481,7 +505,7 @@
         int dy = fScrollTestY * 7;
         SkIRect r;
         SkRegion inval;
-        
+
         r.set(50, 50, 50+100, 50+100);
         bm.scrollRect(&r, dx, dy, &inval);
         paint_rgn(bm, r, inval);
@@ -589,7 +613,7 @@
             }
         }
     }
-    
+
     int dx = 0xFF;
     int dy = 0xFF;
 
@@ -603,11 +627,11 @@
         case '9': dx =  1; dy = -1; break;
         case '3': dx =  1; dy =  1; break;
         case '1': dx = -1; dy =  1; break;
-            
+
         default:
             break;
     }
-    
+
     if (0xFF != dx && 0xFF != dy) {
         if ((dx | dy) == 0) {
             fScrollTestX = fScrollTestY = 0;
@@ -618,7 +642,7 @@
         this->inval(NULL);
         return true;
     }
-    
+
     switch (uni) {
         case 'a':
             fAnimating = !fAnimating;
@@ -659,7 +683,7 @@
         default:
             break;
     }
-    
+
     return this->INHERITED::onHandleChar(uni);
 }
 
@@ -724,7 +748,7 @@
     if (prev) {
         prev->detachFromParent();
     }
-    
+
     if (NULL == view) {
         view = create_overview(fSamples.count(), fSamples.begin());
     }
@@ -768,12 +792,12 @@
     if (title.size() == 0) {
         title.set("<unknown>");
     }
-    
+
     title.prepend(gCanvasTypePrefix[fCanvasType]);
 
     title.prepend(" ");
     title.prepend(configToString(this->getBitmap().config()));
-    
+
     if (fAnimating) {
         title.prepend("<A> ");
     }
@@ -795,12 +819,12 @@
     SkView::F2BIter iter(this);
     SkView* view = iter.next();
     view->setSize(this->width(), this->height());
-    
+
     // rebuild our clippath
     {
         const SkScalar W = this->width();
         const SkScalar H = this->height();
-        
+
         fClipPath.reset();
 #if 0
         for (SkScalar y = SK_Scalar1; y < H; y += SkIntToScalar(32)) {
@@ -817,7 +841,7 @@
         fClipPath.addRect(r, SkPath::kCW_Direction);
 #endif
     }
-    
+
     this->updateTitle();    // to refresh our config
 }
 
@@ -838,7 +862,7 @@
             break;
         }
     }
-    
+
     for (int k = 0; k < count - 1; k++) {
         SkASSERT(!(array[k+1] < array[k]));
     }
@@ -909,7 +933,7 @@
     for (i = 0; i < SK_ARRAY_COUNT(gRecs); i++) {
         test_rects(gRecs[i].fRects, gRecs[i].fCount);
     }
-    
+
     SkRandom rand;
     for (i = 0; i < 10000; i++) {
         SkRegion rgn0, rgn1;
diff --git a/src/gpu/SkGpuCanvas.cpp b/src/gpu/SkGpuCanvas.cpp
index 5ca1736..9513bbd 100644
--- a/src/gpu/SkGpuCanvas.cpp
+++ b/src/gpu/SkGpuCanvas.cpp
@@ -23,11 +23,14 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-static SkDeviceFactory* make_df(GrContext* context) {
-    return SkNEW_ARGS(SkGpuDeviceFactory, (context));
+static SkDeviceFactory* make_df(GrContext* context, 
+                                GrRenderTarget* renderTarget) {
+    return SkNEW_ARGS(SkGpuDeviceFactory, (context, renderTarget));
 }
 
-SkGpuCanvas::SkGpuCanvas(GrContext* context) : SkCanvas(make_df(context)) {
+SkGpuCanvas::SkGpuCanvas(GrContext* context,
+                         GrRenderTarget* renderTarget) 
+      : SkCanvas(make_df(context, renderTarget)) {
     SkASSERT(context);
     fContext = context;
     fContext->ref();
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index d55f6f2..f14de35 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -109,8 +109,14 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-SkGpuDevice::SkGpuDevice(GrContext* context, const SkBitmap& bitmap, bool isLayer)
-        : SkDevice(NULL, bitmap, false) {
+GrRenderTarget* SkGpuDevice::Current3DApiRenderTarget() {
+    return (GrRenderTarget*) -1;
+}
+
+SkGpuDevice::SkGpuDevice(GrContext* context,
+                         const SkBitmap& bitmap,
+                         GrRenderTarget* renderTargetOrNull)
+        : SkDevice(NULL, bitmap, (NULL == renderTargetOrNull)) {
 
     fNeedPrepareRenderTarget = false;
     fDrawProcs = NULL;
@@ -123,7 +129,7 @@
     fRenderTarget = NULL;
     fNeedClear = false;
 
-    if (isLayer) {
+    if (NULL == renderTargetOrNull) {
         SkBitmap::Config c = bitmap.config();
         if (c != SkBitmap::kRGB_565_Config) {
             c = SkBitmap::kARGB_8888_Config;
@@ -164,16 +170,13 @@
         } else {
             GrPrintf("--- failed to create gpu-offscreen [%d %d]\n",
                      this->width(), this->height());
+            GrAssert(false);
         }
-    }
-
-    if (NULL == fRenderTarget) {
-        GrAssert(NULL == fCache);
-        GrAssert(NULL == fTexture);
-
-        fRenderTarget = fContext->currentRenderTarget();
+    } else if (Current3DApiRenderTarget() == renderTargetOrNull) {
+        fRenderTarget = fContext->createRenderTargetFrom3DApiState();
+    } else {
+        fRenderTarget = renderTargetOrNull;
         fRenderTarget->ref();
-        fContext->setDefaultRenderTargetSize(this->width(), this->height());
     }
 }
 
@@ -196,26 +199,6 @@
     }
 }
 
-void SkGpuDevice::bindDeviceToTargetHandle(intptr_t handle) {
-    if (fCache) {
-        GrAssert(NULL != fTexture);
-        GrAssert(fRenderTarget == fTexture->asRenderTarget());
-        // IMPORTANT: reattach the rendertarget/tex back to the cache.
-        fContext->reattachAndUnlockCachedTexture((GrTextureEntry*)fCache);
-    } else if (NULL != fTexture) {
-        GrAssert(!CACHE_LAYER_TEXTURES);
-        fTexture->unref();
-    } else if (NULL != fRenderTarget) {
-        fRenderTarget->unref();
-    }
-
-    fCache  = NULL;
-    fTexture = NULL;
-    fRenderTarget = fContext->createPlatformRenderTarget(handle,
-                                                         this->width(),
-                                                         this->height());
-}
-
 intptr_t SkGpuDevice::getLayerTextureHandle() const {
     if (fTexture) {
         return fTexture->getTextureHandle();
@@ -1050,12 +1033,29 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context) : fContext(context) {
+SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
+                                       GrRenderTarget* rootRenderTarget)
+        : fContext(context) {
+
+    GrAssert(NULL != context);
+    GrAssert(NULL != rootRenderTarget);
+
+    // check this now rather than passing this value to SkGpuDevice cons.
+    // we want the rt that is bound *now* in the 3D API, not the one
+    // at the time of newDevice.
+    if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
+        fRootRenderTarget = context->createRenderTargetFrom3DApiState();
+    } else {
+        fRootRenderTarget = rootRenderTarget;
+        rootRenderTarget->ref();
+    }
     context->ref();
+
 }
 
 SkGpuDeviceFactory::~SkGpuDeviceFactory() {
     fContext->unref();
+    fRootRenderTarget->unref();
 }
 
 SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
@@ -1064,6 +1064,6 @@
     SkBitmap bm;
     bm.setConfig(config, width, height);
     bm.setIsOpaque(isOpaque);
-    return new SkGpuDevice(fContext, bm, isLayer);
+    return new SkGpuDevice(fContext, bm, isLayer ?  NULL : fRootRenderTarget);
 }
 
diff --git a/src/utils/mac/SkOSWindow_Mac.cpp b/src/utils/mac/SkOSWindow_Mac.cpp
index 6828a95..d4ef7e9 100644
--- a/src/utils/mac/SkOSWindow_Mac.cpp
+++ b/src/utils/mac/SkOSWindow_Mac.cpp
@@ -512,6 +512,7 @@
     
     if (success) {
         glClearColor(0, 0, 0, 0);
+        glClearStencil(0);
         glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
     }
     return success;
diff --git a/src/utils/win/SkOSWindow_Win.cpp b/src/utils/win/SkOSWindow_Win.cpp
index 40455d2..53449b1 100644
--- a/src/utils/win/SkOSWindow_Win.cpp
+++ b/src/utils/win/SkOSWindow_Win.cpp
@@ -439,7 +439,8 @@
     }
     if (wglMakeCurrent(GetDC((HWND)fHWND), (HGLRC)fHGLRC)) {
         glClearColor(0, 0, 0, 0);
-        glClear(GL_COLOR_BUFFER_BIT);
+        glClearStencil(0);
+        glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
         fGLAttached = true;
         return true;
     }