Add APIs and plumbing for external rendertaret-textures w/ and w/out MSAA.
authorbsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Mon, 11 Apr 2011 17:58:48 +0000 (17:58 +0000)
committerbsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Mon, 11 Apr 2011 17:58:48 +0000 (17:58 +0000)
Review URL: http://codereview.appspot.com/4388049/

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

12 files changed:
gpu/include/GrContext.h
gpu/include/GrGLTexture.h
gpu/include/GrGpu.h
gpu/include/GrTexture.h
gpu/include/GrTypes.h
gpu/src/GrContext.cpp
gpu/src/GrGLTexture.cpp
gpu/src/GrGpu.cpp
gpu/src/GrGpuGL.cpp
gpu/src/GrGpuGL.h
include/gpu/SkGpuDeviceFactory.h
src/gpu/SkGpuDevice.cpp

index 6759654..7b6803c 100644 (file)
@@ -158,6 +158,43 @@ public:
     // Render targets
 
     /**
+     * Sets the render target.
+     * @param target    the render target to set. (should not be NULL.)
+     */
+    void setRenderTarget(GrRenderTarget* target);
+
+    /**
+     * Gets the current render target.
+     * @return the currently bound render target. Should never be NULL.
+     */
+    const GrRenderTarget* getRenderTarget() const;
+    GrRenderTarget* getRenderTarget();
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Platform Surfaces
+
+    // GrContext provides an interface for wrapping externally created textures
+    // and rendertargets in their Gr-equivalents.
+
+    /**
+     * Wraps an existing 3D API surface in a GrObject. desc.fFlags determines
+     * the type of object returned. If kIsTexture is set the returned object
+     * will be a GrTexture*. Otherwise, it will be a GrRenderTarget*. If both 
+     * are set the render target object is accessible by
+     * GrTexture::asRenderTarget().
+     *
+     * GL: if the object is a texture Gr may change its GL texture parameters
+     *     when it is drawn.
+     *
+     * @param   desc    description of the object to create.
+     * @return either a GrTexture* or GrRenderTarget* depending on desc. NULL
+     *         on failure.
+     */
+    GrResource* createPlatformSurface(const GrPlatformSurfaceDesc& desc);
+
+    /**
+     * DEPRECATED, WILL BE REMOVED SOON. USE createPlatformSurface.
+     *
      * Wraps an externally-created rendertarget in a GrRenderTarget.
      * @param platformRenderTarget  3D API-specific render target identifier
      *                              e.g. in GL platforamRenderTarget is an FBO
@@ -172,9 +209,18 @@ public:
     GrRenderTarget* createPlatformRenderTarget(intptr_t platformRenderTarget,
                                                int stencilBits,
                                                bool isMultisampled,
-                                               int width, int height);
+                                               int width, int height) {
+    #if GR_DEBUG
+        GrPrintf("Using deprecated createPlatformRenderTarget API.");
+    #endif
+        return fGpu->createPlatformRenderTarget(platformRenderTarget, 
+                                                stencilBits, isMultisampled, 
+                                                width, height);
+    }
 
     /**
+     * DEPRECATED, WILL BE REMOVED SOON. USE createPlatformSurface.
+     *
      * 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
@@ -184,22 +230,12 @@ public:
      * @return the newly created GrRenderTarget
      */
     GrRenderTarget* createRenderTargetFrom3DApiState() {
+    #if GR_DEBUG
+        GrPrintf("Using deprecated createRenderTargetFrom3DApiState API.");
+    #endif
         return fGpu->createRenderTargetFrom3DApiState();
     }
 
-    /**
-     * Sets the render target.
-     * @param target    the render target to set. (should not be NULL.)
-     */
-    void setRenderTarget(GrRenderTarget* target);
-
-    /**
-     * Gets the current render target.
-     * @return the currently bound render target. Should never be NULL.
-     */
-    const GrRenderTarget* getRenderTarget() const;
-    GrRenderTarget* getRenderTarget();
-
     ///////////////////////////////////////////////////////////////////////////
     // Matrix state
 
index 94ae7b4..cb50a1e 100644 (file)
@@ -14,7 +14,6 @@
     limitations under the License.
  */
 
-
 #ifndef GrGLTexture_DEFINED
 #define GrGLTexture_DEFINED
 
@@ -31,10 +30,10 @@ class GrGLTexture;
 class GrGLTexID : public GrRefCnt {
 
 public:
-    GrGLTexID(GrGLuint texID) : fTexID(texID) {}
+    GrGLTexID(GrGLuint texID, bool ownsID) : fTexID(texID), fOwnsID(ownsID) {}
 
     virtual ~GrGLTexID() {
-        if (0 != fTexID) {
+        if (0 != fTexID && fOwnsID) {
             GR_GL(DeleteTextures(1, &fTexID));
         }
     }
@@ -44,27 +43,25 @@ public:
 
 private:
     GrGLuint      fTexID;
+    bool          fOwnsID;
 };
 
+////////////////////////////////////////////////////////////////////////////////
+
 class GrGLRenderTarget : public GrRenderTarget {
 
 public:
-    virtual ~GrGLRenderTarget() { this->release(); }
+    // set fTexFBOID to this value to indicate that it is multisampled but
+    // Gr doesn't know how to resolve it.
+    enum { kUnresolvableFBOID = 0 };
 
-    bool resolveable() const { return fRTFBOID != fTexFBOID; }
-    bool needsResolve() const { return fNeedsResolve; }
-    void setDirty(bool dirty) { fNeedsResolve = resolveable() && dirty; }
-
-    GrGLuint renderFBOID() const { return fRTFBOID; }
-    GrGLuint textureFBOID() const { return fTexFBOID; }
-
-protected:
     struct GLRenderTargetIDs {
         GrGLuint      fRTFBOID;
         GrGLuint      fTexFBOID;
         GrGLuint      fStencilRenderbufferID;
         GrGLuint      fMSColorRenderbufferID;
         bool          fOwnIDs;
+        void reset() { memset(this, 0, sizeof(GLRenderTargetIDs)); }
     };
 
     GrGLRenderTarget(GrGpuGL* gpu,
@@ -75,10 +72,33 @@ protected:
                      const GrGLIRect& fViewport,
                      GrGLTexture* texture);
 
+    virtual ~GrGLRenderTarget() { this->release(); }
+
     void setViewport(const GrGLIRect& rect) { fViewport = rect; }
     const GrGLIRect& getViewport() const { return fViewport; }
 
-    // overloads of GrResource
+    // The following two functions return the same ID when a 
+    // texture-rendertarget is multisampled, and different IDs when
+    // it is.
+    // FBO ID used to render into
+    GrGLuint renderFBOID() const { return fRTFBOID; }
+    // FBO ID that has texture ID attached.
+    GrGLuint textureFBOID() const { return fTexFBOID; }
+
+    // override of GrRenderTarget 
+    virtual ResolveType getResolveType() const {
+        if (fRTFBOID == fTexFBOID) {
+            // catches FBO 0 and non MSAA case
+            return kAutoResolves_ResolveType;
+        } else if (kUnresolvableFBOID == fTexFBOID) {
+            return kCantResolve_ResolveType;
+        } else {
+            return kCanResolve_ResolveType;
+        }
+    }
+
+protected:
+    // override of GrResource
     virtual void onAbandon();
     virtual void onRelease();
 
@@ -92,10 +112,6 @@ private:
     // else own them.
     bool        fOwnIDs;
 
-    // If there separate Texture and RenderTarget FBO IDs then the rendertarget
-    // must be resolved to the texture FBO before it is used as a texture.
-    bool fNeedsResolve;
-
     // when we switch to this rendertarget we want to set the viewport to
     // only render to to content area (as opposed to the whole allocation) and
     // we want the rendering to be at top left (GL has origin in bottom left)
@@ -104,12 +120,11 @@ private:
     // non-NULL if this RT was created by Gr with an associated GrGLTexture.
     GrGLTexID* fTexIDObj;
 
-    friend class GrGpuGL;
-    friend class GrGLTexture;
-
     typedef GrRenderTarget INHERITED;
 };
 
+////////////////////////////////////////////////////////////////////////////////
+
 class GrGLTexture : public GrTexture {
 
 public:
@@ -122,8 +137,31 @@ public:
         GrGLenum fFilter;
         GrGLenum fWrapS;
         GrGLenum fWrapT;
+        void invalidate() { memset(this, 0xff, sizeof(TexParams)); }
     };
 
+    struct GLTextureDesc {
+        uint32_t        fContentWidth;
+        uint32_t        fContentHeight;
+        uint32_t        fAllocWidth;
+        uint32_t        fAllocHeight;
+        GrPixelConfig   fFormat;
+        GrGLuint        fTextureID;
+        bool            fOwnsID;
+        GrGLenum        fUploadFormat;
+        GrGLenum        fUploadByteCount;
+        GrGLenum        fUploadType;
+        GrGLuint        fStencilBits;
+        Orientation     fOrientation;
+    };
+
+    typedef GrGLRenderTarget::GLRenderTargetIDs GLRenderTargetIDs;
+
+    GrGLTexture(GrGpuGL* gpu,
+                const GLTextureDesc& textureDesc,
+                const GLRenderTargetIDs& rtIDs,
+                const TexParams& initialTexParams);
+
     virtual ~GrGLTexture() { this->release(); }
 
     // overrides of GrTexture
@@ -176,26 +214,9 @@ public:
     // and it is up to the GrGpuGL derivative to handle y-mirroing.
     Orientation orientation() const { return fOrientation; }
 
-protected:
+    static const GrGLenum* WrapMode2GLWrap();
 
-    struct GLTextureDesc {
-        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,
-                const GLTextureDesc& textureDesc,
-                const GLRenderTargetIDs& rtIDs,
-                const TexParams& initialTexParams);
+protected:
 
     // overrides of GrTexture
     virtual void onAbandon();
@@ -215,10 +236,6 @@ private:
     Orientation         fOrientation;
     GrGpuGL*            fGpuGL;
 
-    static const GrGLenum* WrapMode2GLWrap();
-
-    friend class GrGpuGL;
-
     typedef GrTexture INHERITED;
 };
 
index ebf28b1..705bf3c 100644 (file)
@@ -192,12 +192,13 @@ public:
      * @param width                 width of the render target
      * @param height                height of the render target
      */
-    virtual GrRenderTarget* createPlatformRenderTarget(
-                                                intptr_t platformRenderTarget,
+     GrRenderTarget* createPlatformRenderTarget(intptr_t platformRenderTarget,
                                                 int stencilBits,
                                                 bool isMultisampled,
                                                 int width, int height);
 
+    GrResource* createPlatformSurface(const GrPlatformSurfaceDesc& desc);
+
     /**
      * Reads the current target object (e.g. FBO or IDirect3DSurface9*) and
      * viewport state from the underlying 3D API and wraps it in a
@@ -485,6 +486,7 @@ protected:
     virtual GrTexture* createTextureHelper(const TextureDesc& desc,
                                            const void* srcData,
                                            size_t rowBytes) = 0;
+    virtual GrResource* onCreatePlatformSurface(const GrPlatformSurfaceDesc& desc) = 0;
     virtual GrRenderTarget* createPlatformRenderTargetHelper(
                                                 intptr_t platformRenderTarget,
                                                 int stencilBits,
@@ -514,8 +516,9 @@ protected:
     virtual void forceRenderTargetFlushHelper() = 0;
 
     // overridden by API-specific derived class to perform the read pixels.
-    virtual bool readPixelsHelper(int left, int top, int width, int height,
-                                  GrPixelConfig, void* buffer) = 0;
+    virtual bool onReadPixels(GrRenderTarget* target,
+                              int left, int top, int width, int height,
+                              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
index 493bb8d..6d4f4d7 100644 (file)
@@ -59,6 +59,29 @@ public:
     bool isMultisampled() { return fIsMultisampled; }
 
     /**
+     * Call to indicate the multisample contents were modified such that the
+     * render target needs to be resolved before it can be used as texture. Gr
+     * tracks this for its own drawing and thus this only needs to be called
+     * when the render target has been modified outside of Gr. Only meaningful
+     * for Gr-created RT/Textures and Platform RT/Textures created with the
+     * kGrCanResolve flag.
+     */
+    void flagAsNeedingResolve() {
+        fNeedsResolve = kCanResolve_ResolveType == getResolveType();
+    }
+
+    /**
+     * Call to indicate that GrRenderTarget was externally resolved. This may
+     * allow Gr to skip a redundant resolve step.
+     */
+    void flagAsResolved() { fNeedsResolve = false; }
+
+    /**
+     * @return true if the GrRenderTarget requires MSAA resolving
+     */
+    bool needsResolve() { return fNeedsResolve; }
+
+    /**
      * 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)
@@ -73,6 +96,16 @@ public:
     bool readPixels(int left, int top, int width, int height,
                     GrPixelConfig config, void* buffer);
 
+    // a MSAA RT may require explicit resolving , it may auto-resolve (e.g. FBO
+    // 0 in GL), or be unresolvable because the client didn't give us the 
+    // resolve destination.
+    enum ResolveType {
+        kCanResolve_ResolveType,
+        kAutoResolves_ResolveType,
+        kCantResolve_ResolveType,
+    };
+    virtual ResolveType getResolveType() const = 0;
+
 protected:
     GrRenderTarget(GrGpu* gpu,
                    GrTexture* texture,
@@ -86,6 +119,7 @@ protected:
         , fHeight(height)
         , fStencilBits(stencilBits)
         , fIsMultisampled(isMultisampled)
+        , fNeedsResolve(false)
     {}
 
     friend class GrTexture;
@@ -104,6 +138,7 @@ protected:
     int        fHeight;
     int        fStencilBits;
     bool       fIsMultisampled;
+    bool       fNeedsResolve;
 
 private:
     // GrGpu keeps a cached clip in the render target to avoid redundantly
index 3a55c84..fb62333 100644 (file)
@@ -154,6 +154,50 @@ template <typename Dst, typename Src> Dst GrTCast(Src src) {
 
 ///////////////////////////////////////////////////////////////////////////////
 
+// saves value of T* in and restores in destructor
+// e.g.:
+// {
+//      GrAutoTPtrValueRestore<int*> autoCountRestore;
+//      if (useExtra) {
+//          autoCountRestore.save(&fCount);
+//          fCount += fExtraCount;
+//      }
+//      ...
+//  }  // fCount is restored
+//
+template <typename T>
+class GrAutoTPtrValueRestore {
+public:
+    GrAutoTPtrValueRestore() : fPtr(NULL), fVal() {}
+    
+    GrAutoTPtrValueRestore(T* ptr) {
+        fPtr = ptr;
+        if (NULL != ptr) {
+            fVal = *ptr;
+        }
+    }
+    
+    ~GrAutoTPtrValueRestore() {
+        if (NULL != fPtr) {
+            *fPtr = fVal;
+        }
+    }
+    
+    // restores previously saved value (if any) and saves value for passed T*
+    void save(T* ptr) {
+        if (NULL != fPtr) {
+            *fPtr = fVal;
+        }
+        fPtr = ptr;
+        fVal = *ptr;
+    }
+private:
+    T* fPtr;
+    T  fVal;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
 /**
  * Type used to describe format of vertices in arrays
  * Values are defined in GrDrawTarget
@@ -390,6 +434,139 @@ enum GrConvexHint {
 
 ///////////////////////////////////////////////////////////////////////////////
 
+enum GrPlatformSurfaceType {
+    /**
+     * Specifies that the object being created is a render target.
+     */
+    kRenderTarget_GrPlatformSurfaceType,
+    /**
+     * Specifies that the object being created is a texture.
+     */
+    kTexture_GrPlatformSurfaceType,
+    /**
+     * Specifies that the object being created is a texture and a render
+     * target.
+     */
+    kTextureRenderTarget_GrPlatformSurfaceType,
+};
+
+enum GrPlatformRenderTargetFlags {
+    kNone_GrPlatformRenderTargetFlagBit             = 0x0,
+    /**
+     * Specifies that the object being created is multisampled.
+     */
+    kIsMultisampled_GrPlatformRenderTargetFlagBit   = 0x1,
+    /**
+     * Gives permission to Gr to perform the downsample-resolve of a
+     * multisampled render target. If this is not set then read pixel
+     * operations may fail. If the object is both a texture and render target
+     * then this *must* be set. Otherwise, if the client wants do its own
+     * resolves it must create separate GrRenderTarget and GrTexture objects
+     * and insert appropriate flushes and resolves betweeen data hazards.
+     * GrRenderTarget has a flagForResolve()
+     */
+    kGrCanResolve_GrPlatformRenderTargetFlagBit     = 0x2,
+};
+
+static inline GrPlatformRenderTargetFlags operator | (GrPlatformRenderTargetFlags a, GrPlatformRenderTargetFlags b) {
+    return (GrPlatformRenderTargetFlags) (+a | +b);
+}
+
+static inline GrPlatformRenderTargetFlags operator & (GrPlatformRenderTargetFlags a, GrPlatformRenderTargetFlags b) {
+    return (GrPlatformRenderTargetFlags) (+a & +b);
+}
+
+// opaque type for 3D API object handles
+typedef intptr_t GrPlatform3DObject;
+
+/**
+ * Description of platform surface to create. See below for GL example.
+ */
+struct GrPlatformSurfaceDesc {
+    GrPlatformSurfaceType           fSurfaceType;   // type of surface to create
+    /**
+     * Flags for kRenderTarget and kTextureRenderTarget surface types
+     */
+    GrPlatformRenderTargetFlags     fRenderTargetFlags;
+
+    int                             fWidth;         // width in pixels
+    int                             fHeight;        // height in pixels
+    GrPixelConfig                   fConfig;        // color format
+    /**
+     * Number of per sample stencil buffer. Only relevant if kIsRenderTarget is
+     * set in fFlags.
+     */
+    int                             fStencilBits;
+    /**
+     * Texture object in 3D API. Only relevant if fSurfaceType is kTexture or
+     * kTextureRenderTarget.
+     * GL: this is a texture object (glGenTextures)
+     */
+    GrPlatform3DObject              fPlatformTexture;
+    /**
+     * Render target object in 3D API. Only relevant if fSurfaceType is
+     * kRenderTarget or kTextureRenderTarget
+     * GL: this is a FBO object (glGenFramebuffers)
+     */
+    GrPlatform3DObject              fPlatformRenderTarget;
+    /**
+     * 3D API object used as destination of resolve. Only relevant if
+     * fSurfaceType is kRenderTarget or kTextureRenderTarget and
+     * kGrCanResolve is set in fRenderTargetFlags.
+     * fFlags.
+     * GL: this is a FBO object (glGenFramebuffers)
+     */
+    GrPlatform3DObject              fPlatformResolveDestination;
+
+    void reset() { memset(this, 0, sizeof(GrPlatformSurfaceDesc)); }
+};
+
+/**
+ * Example of how to wrap render-to-texture-with-MSAA GL objects with a GrPlatformSurace
+ *
+ * GLint colorBufferID;
+ * glGenRenderbuffers(1, &colorID);
+ * glBindRenderbuffer(GL_RENDERBUFFER, colorBufferID);
+ * glRenderbufferStorageMultisample(GL_RENDERBUFFER, S, GL_RGBA, W, H);
+ *
+ * GLint stencilBufferID;
+ * glGenRenderBuffers(1, &stencilBufferID);
+ * glBindRenderbuffer(GL_RENDERBUFFER, stencilBufferID);
+ * glRenderbufferStorageMultisample(GL_RENDERBUFFER, S, GL_STENCIL_INDEX8, W, H);
+ *
+ * GLint drawFBOID;
+ * glGenFramebuffers(1, &drawFBOID);
+ * glBindFramebuffer(GL_FRAMEBUFFER, drawFBOID);
+ * glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorBufferID);
+ * glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, stencilBufferID);
+ *
+ * GLint textureID;
+ * glGenTextures(1, &textureID);
+ * glBindTexture(GL_TEXTURE_2D, textureID);
+ * glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, W, H, ...);
+ *
+ * GLint readFBOID;
+ * glGenFramebuffers(1, &readFBOID);
+ * glBindFramebuffer(GL_FRAMEBUFFER, readFBOID);
+ * glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textureID, 0);
+ *
+ * GrPlatformSurfaceDesc renderTargetTextureDesc;
+ * renderTargetTextureDesc.fSurfaceType       = kTextureRenderTarget_GrPlatformSurfaceType;
+ * renderTargetTextureDesc.fRenderTargetFlags = (kIsMultisampled_GrPlatformRenderTargetFlagBit | kGrCanResolve_GrPlatformRenderTargetFlagBit);
+ * renderTargetTextureDesc.fWidth = W;
+ * renderTargetTextureDesc.fHeight = H;
+ * renderTargetTextureDesc.fConfig = kRGBA_8888_GrPixelConfig
+ * renderTargetTextureDesc.fStencilBits = 8;
+ * renderTargetTextureDesc.fPlatformTexture = textureID;
+ * renderTargetTextureDesc.fPlatformRenderTarget = drawFBOID;
+ * renderTargetTextureDesc.fPlatformResolveDestination = readFBOID;
+ *
+ * GrTexture* texture = static_cast<GrTexture*>(grContext->createPlatrformSurface(renderTargetTextureDesc));
+ */
+
+
+///////////////////////////////////////////////////////////////////////////////
+
 // this is included only to make it easy to use this debugging facility
 #include "GrInstanceCounter.h"
 
index b17a238..8017f73 100644 (file)
@@ -267,16 +267,26 @@ int GrContext::getMaxTextureDimension() {
 
 ///////////////////////////////////////////////////////////////////////////////
 
-GrRenderTarget* GrContext::createPlatformRenderTarget(
-                                                intptr_t platformRenderTarget,
-                                                int stencilBits,
-                                                bool isMultisampled,
-                                                int width, int height) {
-    return fGpu->createPlatformRenderTarget(platformRenderTarget, stencilBits,
-                                            isMultisampled,
-                                            width, height);
+GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
+    // validate flags here so that GrGpu subclasses don't have to check
+    if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
+        0 != desc.fRenderTargetFlags) {
+            return NULL;
+    }
+    if (!(kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
+        (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
+            return NULL;
+    }
+    if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
+        (kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
+        !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
+        return NULL;
+    }
+    return fGpu->createPlatformSurface(desc);
 }
 
+///////////////////////////////////////////////////////////////////////////////
+
 bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
                                           int width, int height) {
     if (!fGpu->supports8BitPalette()) {
index 6a5a005..3c6504d 100644 (file)
@@ -108,7 +108,8 @@ GrGLTexture::GrGLTexture(GrGpuGL* gpu,
                 textureDesc.fFormat) {
 
     fTexParams          = initialTexParams;
-    fTexIDObj           = new GrGLTexID(textureDesc.fTextureID);
+    fTexIDObj           = new GrGLTexID(textureDesc.fTextureID,
+                                        textureDesc.fOwnsID);
     fUploadFormat       = textureDesc.fUploadFormat;
     fUploadByteCount    = textureDesc.fUploadByteCount;
     fUploadType         = textureDesc.fUploadType;
index 4aaed79..2407cdf 100644 (file)
@@ -158,6 +158,11 @@ GrRenderTarget* GrGpu::createRenderTargetFrom3DApiState() {
     return this->createRenderTargetFrom3DApiStateHelper();
 }
 
+GrResource* GrGpu::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
+    this->handleDirtyContext();
+    return this->onCreatePlatformSurface(desc);
+}
+
 GrVertexBuffer* GrGpu::createVertexBuffer(uint32_t size, bool dynamic) {
     this->handleDirtyContext();
     return this->createVertexBufferHelper(size, dynamic);
@@ -183,12 +188,7 @@ bool GrGpu::readPixels(GrRenderTarget* target,
                        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;
+    return this->onReadPixels(target, left, top, width, height, config, buffer);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
index 86d6342..e62949b 100644 (file)
@@ -533,6 +533,73 @@ void GrGpuGL::resetContext() {
     fHWDrawState.fRenderTarget = NULL;
 }
 
+GrResource* GrGpuGL::onCreatePlatformSurface(const GrPlatformSurfaceDesc& desc) {
+
+    bool isTexture = kTexture_GrPlatformSurfaceType == desc.fSurfaceType ||
+                     kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType;
+    bool isRenderTarget = kRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType ||
+                          kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType;
+
+    GrGLRenderTarget::GLRenderTargetIDs rtIDs;
+    if (isRenderTarget) {
+        rtIDs.fRTFBOID = desc.fPlatformRenderTarget;
+        if (kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) {
+            if (kGrCanResolve_GrPlatformRenderTargetFlagBit  & desc.fRenderTargetFlags) {
+                rtIDs.fTexFBOID = desc.fPlatformResolveDestination;
+            } else {
+                GrAssert(!isTexture); // this should have been filtered by GrContext
+                rtIDs.fTexFBOID = GrGLRenderTarget::kUnresolvableFBOID;
+            }
+        } else {
+            rtIDs.fTexFBOID = desc.fPlatformRenderTarget;
+        }
+        // we don't know what the RB ids are without glGets and we don't care
+        // since we aren't responsible for deleting them.
+        rtIDs.fStencilRenderbufferID = 0;
+        rtIDs.fMSColorRenderbufferID = 0;
+
+        rtIDs.fOwnIDs = false;
+    } else {
+        rtIDs.reset();
+    }
+
+    if (isTexture) {
+        GrGLTexture::GLTextureDesc texDesc;
+        GrGLenum dontCare;
+        if (!canBeTexture(desc.fConfig, &dontCare,
+                         &texDesc.fUploadFormat,
+                         &texDesc.fUploadType)) {
+            return NULL;
+        }
+
+        GrGLTexture::TexParams params;
+
+        texDesc.fAllocWidth  = texDesc.fContentWidth  = desc.fWidth;
+        texDesc.fAllocHeight = texDesc.fContentHeight = desc.fHeight;
+
+        texDesc.fFormat             = texDesc.fFormat;
+        texDesc.fOrientation        = GrGLTexture::kBottomUp_Orientation;
+        texDesc.fStencilBits        = desc.fStencilBits;
+        texDesc.fTextureID          = desc.fPlatformTexture;
+        texDesc.fUploadByteCount    = GrBytesPerPixel(desc.fConfig);
+        texDesc.fOwnsID             = false;
+
+        params.invalidate(); // rather than do glGets.
+
+        return new GrGLTexture(this, texDesc, rtIDs, params);
+    } else {
+        GrGLIRect viewport;
+        viewport.fLeft   = 0;
+        viewport.fBottom = 0;
+        viewport.fWidth  = desc.fWidth;
+        viewport.fHeight = desc.fHeight;
+
+        return new GrGLRenderTarget(this, rtIDs, NULL, desc.fStencilBits,
+                                    kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags,
+                                    viewport, NULL);
+    }
+}
+
 GrRenderTarget* GrGpuGL::createPlatformRenderTargetHelper(
                                                 intptr_t platformRenderTarget,
                                                 int stencilBits,
@@ -655,6 +722,7 @@ GrTexture* GrGpuGL::createTextureHelper(const TextureDesc& desc,
     glDesc.fAllocHeight   = desc.fHeight;
     glDesc.fStencilBits   = 0;
     glDesc.fFormat        = desc.fFormat;
+    glDesc.fOwnsID        = true;
 
     bool renderTarget = 0 != (desc.fFlags & kRenderTarget_TextureFlag);
     if (!canBeTexture(desc.fFormat,
@@ -1154,21 +1222,35 @@ void GrGpuGL::forceRenderTargetFlushHelper() {
     flushRenderTarget();
 }
 
-bool GrGpuGL::readPixelsHelper(int left, int top, int width, int height,
-                               GrPixelConfig config, void* buffer) {
+bool GrGpuGL::onReadPixels(GrRenderTarget* target,
+                           int left, int top, int width, int height,
+                           GrPixelConfig config, void* buffer) {
     GrGLenum internalFormat;  // we don't use this for glReadPixels
     GrGLenum format;
     GrGLenum type;
     if (!this->canBeTexture(config, &internalFormat, &format, &type)) {
         return false;
+    }    
+    GrGLRenderTarget* tgt = static_cast<GrGLRenderTarget*>(target);
+    GrAutoTPtrValueRestore<GrRenderTarget*> autoTargetRestore;
+    switch (tgt->getResolveType()) {
+        case GrGLRenderTarget::kCantResolve_ResolveType:
+            return false;
+        case GrGLRenderTarget::kAutoResolves_ResolveType:
+            autoTargetRestore.save(&fCurrDrawState.fRenderTarget);
+            fCurrDrawState.fRenderTarget = target;
+            flushRenderTarget();
+            break;
+        case GrGLRenderTarget::kCanResolve_ResolveType:
+            resolveRenderTarget(tgt);
+            // we don't track the state of the READ FBO ID.
+            GR_GL(BindFramebuffer(GR_GL_READ_FRAMEBUFFER, tgt->textureFBOID()));
+            break;
+        default:
+            GrCrash("Unknown resolve type");
     }
 
-    if (NULL == fCurrDrawState.fRenderTarget) {
-        return false;
-    }
-    flushRenderTarget();
-
-    const GrGLIRect& glvp = ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->getViewport();
+    const GrGLIRect& glvp = tgt->getViewport();
 
     // the read rect is viewport-relative
     GrGLIRect readRect;
@@ -1208,7 +1290,7 @@ void GrGpuGL::flushRenderTarget() {
     #if GR_COLLECT_STATS
         ++fStats.fRenderTargetChngCnt;
     #endif
-        rt->setDirty(true);
+        rt->flagAsNeedingResolve();
     #if GR_DEBUG
         GrGLenum status = GR_GL(CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
         if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
@@ -1316,10 +1398,9 @@ void GrGpuGL::drawNonIndexedHelper(GrPrimitiveType type,
 #endif
 }
 
-void GrGpuGL::resolveTextureRenderTarget(GrGLTexture* texture) {
-    GrGLRenderTarget* rt = (GrGLRenderTarget*) texture->asRenderTarget();
+void GrGpuGL::resolveRenderTarget(GrGLRenderTarget* rt) {
 
-    if (NULL != rt && rt->needsResolve()) {
+    if (rt->needsResolve()) {
         GrAssert(kNone_MSFBO != fMSFBOType);
         GrAssert(rt->textureFBOID() != rt->renderFBOID());
         GR_GL(BindFramebuffer(GR_GL_READ_FRAMEBUFFER,
@@ -1329,32 +1410,32 @@ void GrGpuGL::resolveTextureRenderTarget(GrGLTexture* texture) {
     #if GR_COLLECT_STATS
         ++fStats.fRenderTargetChngCnt;
     #endif
-        // make sure we go through set render target
+        // make sure we go through flushRenderTarget() since we've modified
+        // the bound DRAW FBO ID.
         fHWDrawState.fRenderTarget = NULL;
+        const GrGLIRect& vp = rt->getViewport();
 
-        GrGLint left = 0;
-        GrGLint right = texture->width();
-        // we will have rendered to the top of the FBO.
-        GrGLint top = texture->allocHeight();
-        GrGLint bottom = texture->allocHeight() - texture->height();
         if (kAppleES_MSFBO == fMSFBOType) {
             // Apple's extension uses the scissor as the blit bounds.
             GR_GL(Enable(GR_GL_SCISSOR_TEST));
-            GR_GL(Scissor(left, bottom, right-left, top-bottom));
+            GR_GL(Scissor(vp.fLeft, vp.fBottom,
+                          vp.fWidth, vp.fHeight));
             GR_GL(ResolveMultisampleFramebuffer());
             fHWBounds.fScissorRect.invalidate();
             fHWBounds.fScissorEnabled = true;
         } else {
             if (kDesktopARB_MSFBO != fMSFBOType) {
-                // these respect the scissor during the blit, so disable it.
+                // this respects the scissor during the blit, so disable it.
                 GrAssert(kDesktopEXT_MSFBO == fMSFBOType);
                 flushScissor(NULL);
             }
-            GR_GL(BlitFramebuffer(left, bottom, right, top,
-                                     left, bottom, right, top,
-                                     GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST));
+            int right = vp.fLeft + vp.fWidth;
+            int top = vp.fBottom + vp.fHeight;
+            GR_GL(BlitFramebuffer(vp.fLeft, vp.fBottom, right, top,
+                                  vp.fLeft, vp.fBottom, right, top,
+                                  GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST));
         }
-        rt->setDirty(false);
+        rt->flagAsResolved();
     }
 }
 
@@ -1631,7 +1712,11 @@ bool GrGpuGL::flushGLStateCommon(GrPrimitiveType type) {
                 // texture and now we're texuring from the rt it will still be
                 // the last bound texture, but it needs resolving. So keep this
                 // out of the "last != next" check.
-                resolveTextureRenderTarget(nextTexture);
+                GrGLRenderTarget* texRT = 
+                    static_cast<GrGLRenderTarget*>(nextTexture->asRenderTarget());
+                if (NULL != texRT) {
+                    resolveRenderTarget(texRT);
+                }
 
                 if (fHWDrawState.fTextures[s] != nextTexture) {
                     setTextureUnit(s);
index 1b5f7f7..cffa671 100644 (file)
@@ -79,21 +79,21 @@ protected:
                                                      bool dynamic);
     virtual GrIndexBuffer* createIndexBufferHelper(uint32_t size,
                                                    bool dynamic);
-
+    virtual GrResource* onCreatePlatformSurface(const GrPlatformSurfaceDesc& desc);
     virtual GrRenderTarget* createPlatformRenderTargetHelper(
                                                  intptr_t platformRenderTarget,
                                                  int stencilBits,
                                                  bool isMultisampled,
                                                  int width, int height);
-
     virtual GrRenderTarget* createRenderTargetFrom3DApiStateHelper();
 
     virtual void eraseColorHelper(GrColor color);
 
     virtual void forceRenderTargetFlushHelper();
 
-    virtual bool readPixelsHelper(int left, int top, int width, int height,
-                                  GrPixelConfig, void* buffer);
+    virtual bool onReadPixels(GrRenderTarget* target,
+                              int left, int top, int width, int height,
+                              GrPixelConfig, void* buffer);
 
     virtual void drawIndexedHelper(GrPrimitiveType type,
                                    uint32_t startVertex,
@@ -158,7 +158,7 @@ private:
     void flushAAState(GrPrimitiveType type);
     void flushBlend(GrPrimitiveType type);
 
-    void resolveTextureRenderTarget(GrGLTexture* texture);
+    void resolveRenderTarget(GrGLRenderTarget* texture);
 
     bool canBeTexture(GrPixelConfig config,
                       GrGLenum* internalFormat,
index a2e67f2..6f62ad6 100644 (file)
@@ -34,6 +34,14 @@ public:
      *  construction.
      */
     SkGpuDeviceFactory(GrContext*, GrRenderTarget* rootRenderTarget);
+    
+    /**
+     * When the root layer is both a GrRenderTarget and a GrTexture it
+     * is handy to have the factory hang on to a ref to the GrTexture object.
+     * This is because the GrTexture has a ref to the GrRenderTarget but not
+     * vice-versa.
+     */
+    SkGpuDeviceFactory(GrContext*, GrTexture* rootRenderTargetTexture);
 
     virtual ~SkGpuDeviceFactory();
 
@@ -43,6 +51,7 @@ public:
 private:
     GrContext* fContext;
     GrRenderTarget* fRootRenderTarget;
+    GrTexture* fRootTexture;
 };
 
 #endif
index 2d50c36..4d3aa3a 100644 (file)
@@ -1453,12 +1453,27 @@ SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
         rootRenderTarget->ref();
     }
     context->ref();
+    fRootTexture = NULL;
+}
+
+SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context, GrTexture* rootRenderTargetTexture) {
+    GrAssert(NULL != context);
+    GrAssert(NULL != rootRenderTargetTexture);
+    GrAssert(NULL != rootRenderTargetTexture->asRenderTarget());
 
+    fRootTexture = rootRenderTargetTexture;
+    rootRenderTargetTexture->ref();
+
+    fRootRenderTarget = rootRenderTargetTexture->asRenderTarget();
+    fRootRenderTarget->ref();
+
+    context->ref();
 }
 
 SkGpuDeviceFactory::~SkGpuDeviceFactory() {
     fContext->unref();
     fRootRenderTarget->unref();
+    GrSafeUnref(fRootTexture);
 }
 
 SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,