skia: Add support for CHROMIUM_image backed textures.
authorerikchen <erikchen@chromium.org>
Thu, 4 Feb 2016 20:03:07 +0000 (12:03 -0800)
committerCommit bot <commit-bot@chromium.org>
Thu, 4 Feb 2016 20:03:08 +0000 (12:03 -0800)
I created a new abstract base class TextureStorageAllocator that consumers of
Skia can subclass and pass back to Skia. When a surface is created with a
pointer to a TextureStorageAllocator, any textures it creates, or that are
derived from the original surface, will allocate and deallocate storage using
the methods on TextureStorageAllocator.

BUG=https://code.google.com/p/chromium/issues/detail?id=579664
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1623653002

Review URL: https://codereview.chromium.org/1623653002

12 files changed:
include/core/SkSurface.h
include/gpu/GrTypes.h
src/gpu/GrTexture.cpp
src/gpu/GrTextureProvider.cpp
src/gpu/SkGpuDevice.cpp
src/gpu/SkGpuDevice.h
src/gpu/SkGrPixelRef.cpp
src/gpu/gl/GrGLGpu.cpp
src/gpu/gl/GrGLGpu.h
src/gpu/gl/GrGLTexture.cpp
src/image/SkSurface.cpp
src/image/SkSurface_Gpu.cpp

index 52097be..45262d7 100644 (file)
@@ -120,12 +120,16 @@ public:
     /**
      *  Return a new surface whose contents will be drawn to an offscreen
      *  render target, allocated by the surface.
+     *
+     *  The GrTextureStorageAllocator will be reused if SkImage snapshots create
+     *  additional textures.
      */
-    static SkSurface* NewRenderTarget(GrContext*, Budgeted, const SkImageInfo&, int sampleCount,
-                                      const SkSurfaceProps* = NULL);
+    static SkSurface* NewRenderTarget(
+            GrContext*, Budgeted, const SkImageInfo&, int sampleCount, const SkSurfaceProps* = NULL,
+            GrTextureStorageAllocator = GrTextureStorageAllocator());
 
     static SkSurface* NewRenderTarget(GrContext* gr, Budgeted b, const SkImageInfo& info) {
-        return NewRenderTarget(gr, b, info, 0, NULL);
+        return NewRenderTarget(gr, b, info, 0);
     }
 
     int width() const { return fWidth; }
index dbcb9a6..767e072 100644 (file)
@@ -409,6 +409,9 @@ enum GrSurfaceFlags {
 
 GR_MAKE_BITFIELD_OPS(GrSurfaceFlags)
 
+// opaque type for 3D API object handles
+typedef intptr_t GrBackendObject;
+
 /**
  * Some textures will be stored such that the upper and left edges of the content meet at the
  * the origin (in texture coord space) and for other textures the lower and left edges meet at
@@ -423,6 +426,58 @@ enum GrSurfaceOrigin {
 };
 
 /**
+ * An container of function pointers which consumers of Skia can fill in and
+ * pass to Skia. Skia will use these function pointers in place of its backend
+ * API texture creation function. Either all of the function pointers should be
+ * filled in, or they should all be nullptr.
+ */
+struct GrTextureStorageAllocator {
+    GrTextureStorageAllocator()
+    : fAllocateTextureStorage(nullptr)
+    , fDeallocateTextureStorage(nullptr) {
+    }
+
+    enum class Result {
+        kSucceededAndUploaded,
+        kSucceededWithoutUpload,
+        kFailed
+    };
+    typedef Result (*AllocateTextureStorageProc)(
+            void* ctx, GrBackendObject texture, unsigned width,
+            unsigned height, GrPixelConfig config, const void* srcData, GrSurfaceOrigin);
+    typedef void (*DeallocateTextureStorageProc)(void* ctx, GrBackendObject texture);
+
+    /*
+     * Generates and binds a texture to |textureStorageTarget()|. Allocates
+     * storage for the texture.
+     *
+     * In OpenGL, the MIN and MAX filters for the created texture must be
+     * GL_LINEAR. The WRAP_S and WRAP_T must be GL_CLAMP_TO_EDGE.
+     *
+     * If |srcData| is not nullptr, then the implementation of this function
+     * may attempt to upload the data into the texture. On successful upload,
+     * or if |srcData| is nullptr, returns kSucceededAndUploaded.
+     */
+    AllocateTextureStorageProc fAllocateTextureStorage;
+
+    /*
+     * Deallocate the storage for the given texture.
+     *
+     * Skia does not always destroy its outstanding textures. See
+     * GrContext::abandonContext() for more details. The consumer of Skia is
+     * responsible for making sure that all textures are destroyed, even if this
+     * callback is not invoked.
+     */
+    DeallocateTextureStorageProc fDeallocateTextureStorage;
+
+    /*
+     * The context to use when invoking fAllocateTextureStorage and
+     * fDeallocateTextureStorage.
+     */
+    void* fCtx;
+};
+
+/**
  * Describes a surface to be created.
  */
 struct GrSurfaceDesc {
@@ -454,6 +509,12 @@ struct GrSurfaceDesc {
      * max supported count.
      */
     int                    fSampleCnt;
+
+    /**
+     * A custom platform-specific allocator to use in place of the backend APIs
+     * usual texture creation method (e.g. TexImage2D in OpenGL).
+     */
+    GrTextureStorageAllocator fTextureStorageAllocator;
 };
 
 // Legacy alias
@@ -469,9 +530,6 @@ enum GrClipType {
 
 ///////////////////////////////////////////////////////////////////////////////
 
-// opaque type for 3D API object handles
-typedef intptr_t GrBackendObject;
-
 
 /** Ownership rules for external GPU resources imported into Skia. */
 enum GrWrapOwnership {
index 249fe98..fe5b2c3 100644 (file)
@@ -85,7 +85,8 @@ GrTexture::GrTexture(GrGpu* gpu, LifeCycle lifeCycle, const GrSurfaceDesc& desc)
     : INHERITED(gpu, lifeCycle, desc)
     , fMipMapsStatus(kNotAllocated_MipMapsStatus) {
 
-    if (!this->isExternal() && !GrPixelConfigIsCompressed(desc.fConfig)) {
+    if (!this->isExternal() && !GrPixelConfigIsCompressed(desc.fConfig) &&
+        !desc.fTextureStorageAllocator.fAllocateTextureStorage) {
         GrScratchKey key;
         GrTexturePriv::ComputeScratchKey(desc, &key);
         this->setScratchKey(key);
index 105cce2..7d720eb 100644 (file)
@@ -39,7 +39,8 @@ GrTexture* GrTextureProvider::createTexture(const GrSurfaceDesc& desc, bool budg
         !fGpu->caps()->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) {
         return nullptr;
     }
-    if (!GrPixelConfigIsCompressed(desc.fConfig)) {
+    if (!GrPixelConfigIsCompressed(desc.fConfig) &&
+        !desc.fTextureStorageAllocator.fAllocateTextureStorage) {
         static const uint32_t kFlags = kExact_ScratchTextureFlag |
                                        kNoCreate_ScratchTextureFlag;
         if (GrTexture* texture = this->refScratchTexture(desc, kFlags)) {
index 4fdd4ae..270c458 100644 (file)
@@ -156,13 +156,15 @@ SkGpuDevice* SkGpuDevice::Create(GrRenderTarget* rt, int width, int height,
 
 SkGpuDevice* SkGpuDevice::Create(GrContext* context, SkSurface::Budgeted budgeted,
                                  const SkImageInfo& info, int sampleCount,
-                                 const SkSurfaceProps* props, InitContents init) {
+                                 const SkSurfaceProps* props, InitContents init,
+                                 GrTextureStorageAllocator customAllocator) {
     unsigned flags;
     if (!CheckAlphaTypeAndGetFlags(&info, init, &flags)) {
         return nullptr;
     }
 
-    SkAutoTUnref<GrRenderTarget> rt(CreateRenderTarget(context, budgeted, info,  sampleCount));
+    SkAutoTUnref<GrRenderTarget> rt(CreateRenderTarget(
+            context, budgeted, info, sampleCount, customAllocator));
     if (nullptr == rt) {
         return nullptr;
     }
@@ -187,8 +189,9 @@ SkGpuDevice::SkGpuDevice(GrRenderTarget* rt, int width, int height,
     fDrawContext.reset(this->context()->drawContext(rt, &this->surfaceProps()));
 }
 
-GrRenderTarget* SkGpuDevice::CreateRenderTarget(GrContext* context, SkSurface::Budgeted budgeted,
-                                                const SkImageInfo& origInfo, int sampleCount) {
+GrRenderTarget* SkGpuDevice::CreateRenderTarget(
+        GrContext* context, SkSurface::Budgeted budgeted, const SkImageInfo& origInfo,
+        int sampleCount, GrTextureStorageAllocator textureStorageAllocator) {
     if (kUnknown_SkColorType == origInfo.colorType() ||
         origInfo.width() < 0 || origInfo.height() < 0) {
         return nullptr;
@@ -217,6 +220,7 @@ GrRenderTarget* SkGpuDevice::CreateRenderTarget(GrContext* context, SkSurface::B
     desc.fHeight = info.height();
     desc.fConfig = SkImageInfo2GrPixelConfig(info);
     desc.fSampleCnt = sampleCount;
+    desc.fTextureStorageAllocator = textureStorageAllocator;
     GrTexture* texture = context->textureProvider()->createTexture(
         desc, SkToBool(budgeted), nullptr, 0);
     if (nullptr == texture) {
@@ -336,7 +340,8 @@ void SkGpuDevice::replaceRenderTarget(bool shouldRetainContent) {
                                                        : SkSurface::kNo_Budgeted;
 
     SkAutoTUnref<GrRenderTarget> newRT(CreateRenderTarget(
-        this->context(), budgeted, this->imageInfo(), fRenderTarget->desc().fSampleCnt));
+        this->context(), budgeted, this->imageInfo(), fRenderTarget->desc().fSampleCnt,
+        fRenderTarget->desc().fTextureStorageAllocator));
 
     if (nullptr == newRT) {
         return;
@@ -1488,7 +1493,7 @@ void SkGpuDevice::drawProducerNine(const SkDraw& draw, GrTextureProducer* produc
 
         SkRect srcR, dstR;
         while (iter.next(&srcR, &dstR)) {
-            this->drawTextureProducer(producer, &srcR, &dstR, SkCanvas::kStrict_SrcRectConstraint, 
+            this->drawTextureProducer(producer, &srcR, &dstR, SkCanvas::kStrict_SrcRectConstraint,
                                       *draw.fMatrix, fClip, paint);
         }
         return;
index 19bef21..388dbb1 100644 (file)
@@ -18,6 +18,7 @@
 #include "GrDrawContext.h"
 #include "GrContext.h"
 #include "GrSurfacePriv.h"
+#include "GrTypes.h"
 
 class GrAccelData;
 class GrTextureProducer;
@@ -52,7 +53,8 @@ public:
      * the resource cache budget. On failure, returns nullptr.
      */
     static SkGpuDevice* Create(GrContext*, SkSurface::Budgeted, const SkImageInfo&,
-                               int sampleCount, const SkSurfaceProps*, InitContents);
+                               int sampleCount, const SkSurfaceProps*,
+                               InitContents, GrTextureStorageAllocator = GrTextureStorageAllocator());
 
     ~SkGpuDevice() override {}
 
@@ -256,7 +258,7 @@ private:
     bool drawDashLine(const SkPoint pts[2], const SkPaint& paint);
 
     static GrRenderTarget* CreateRenderTarget(GrContext*, SkSurface::Budgeted, const SkImageInfo&,
-                                              int sampleCount);
+                                              int sampleCount, GrTextureStorageAllocator);
 
     friend class GrAtlasTextContext;
     friend class SkSurface_Gpu;      // for access to surfaceProps
index 58f516a..3876f17 100644 (file)
@@ -76,6 +76,7 @@ static SkGrPixelRef* copy_to_new_texture_pixelref(GrTexture* texture, SkColorTyp
     }
     desc.fFlags = kRenderTarget_GrSurfaceFlag;
     desc.fConfig = SkImageInfo2GrPixelConfig(dstCT, kPremul_SkAlphaType, dstPT);
+    desc.fTextureStorageAllocator = texture->desc().fTextureStorageAllocator;
 
     GrTexture* dst = context->textureProvider()->createTexture(desc, false, nullptr, 0);
     if (nullptr == dst) {
index 3b7ccd3..0b2c5f6 100644 (file)
@@ -755,8 +755,11 @@ bool GrGLGpu::onWritePixels(GrSurface* surface,
         success = this->uploadCompressedTexData(glTex->desc(), glTex->target(), buffer, 
                                                 kWrite_UploadType, left, top, width, height);
     } else {
-        success = this->uploadTexData(glTex->desc(), glTex->target(), kWrite_UploadType,
-                                      left, top, width, height, config, buffer, rowBytes);
+      success = this->uploadTexData(
+          glTex->desc(),
+          reinterpret_cast<GrGLTextureInfo*>(glTex->getTextureHandle()),
+          kWrite_UploadType, left, top, width, height, config, buffer,
+          rowBytes);
     }
 
     if (success) {
@@ -793,8 +796,11 @@ bool GrGLGpu::onTransferPixels(GrSurface* surface,
     GL_CALL(BindBuffer(glBuffer->bufferType(), glBuffer->bufferID()));
 
     bool success = false;
-    success = this->uploadTexData(glTex->desc(), glTex->target(), kTransfer_UploadType,
-                                  left, top, width, height, config, buffer, rowBytes);
+    success = this->uploadTexData(
+        glTex->desc(),
+        reinterpret_cast<GrGLTextureInfo*>(glTex->getTextureHandle()),
+        kTransfer_UploadType, left, top, width, height, config, buffer,
+        rowBytes);
 
     if (success) {
         glTex->texturePriv().dirtyMipMaps(true);
@@ -835,7 +841,7 @@ static inline GrGLenum check_alloc_error(const GrSurfaceDesc& desc,
 }
 
 bool GrGLGpu::uploadTexData(const GrSurfaceDesc& desc,
-                            GrGLenum target,
+                            GrGLTextureInfo* info,
                             UploadType uploadType,
                             int left, int top, int width, int height,
                             GrPixelConfig dataConfig,
@@ -932,20 +938,30 @@ bool GrGLGpu::uploadTexData(const GrSurfaceDesc& desc,
             !(0 == left && 0 == top && desc.fWidth == width && desc.fHeight == height)) {
             succeeded = false;
         } else {
-            CLEAR_ERROR_BEFORE_ALLOC(this->glInterface());
-            GL_ALLOC_CALL(this->glInterface(), TexImage2D(target, 0, internalFormat, desc.fWidth,
-                                                          desc.fHeight, 0, externalFormat,
-                                                          externalType, dataOrOffset));
-            GrGLenum error = check_alloc_error(desc, this->glInterface());
-            if (error != GR_GL_NO_ERROR) {
-                succeeded = false;
-            }
+            if (desc.fTextureStorageAllocator.fAllocateTextureStorage) {
+                if (dataOrOffset) {
+                    GL_CALL(TexSubImage2D(info->fTarget,
+                                          0, // level
+                                          left, top,
+                                          width, height,
+                                          externalFormat, externalType, dataOrOffset));
+                }
+            } else {                                                              
+                CLEAR_ERROR_BEFORE_ALLOC(this->glInterface());                    
+                GL_ALLOC_CALL(this->glInterface(), TexImage2D(                    
+                    info->fTarget, 0, internalFormat, desc.fWidth, desc.fHeight, 0, externalFormat,
+                    externalType, dataOrOffset));                                 
+                GrGLenum error = check_alloc_error(desc, this->glInterface()); 
+                if (error != GR_GL_NO_ERROR) {                                    
+                    succeeded = false;                                            
+                }
+            }  
         }
     } else {
         if (swFlipY || glFlipY) {
             top = desc.fHeight - (top + height);
         }
-        GL_CALL(TexSubImage2D(target,
+        GL_CALL(TexSubImage2D(info->fTarget,
                               0, // level
                               left, top,
                               width, height,
@@ -1208,52 +1224,10 @@ GrTexture* GrGLGpu::onCreateTexture(const GrSurfaceDesc& desc,
     bool renderTarget = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag);
 
     GrGLTexture::IDDesc idDesc;
-    idDesc.fInfo.fID = 0;
-    GL_CALL(GenTextures(1, &idDesc.fInfo.fID));
     idDesc.fLifeCycle = lifeCycle;
-    // We only support GL_TEXTURE_2D at the moment.
-    idDesc.fInfo.fTarget = GR_GL_TEXTURE_2D;
-
-    if (!idDesc.fInfo.fID) {
-        return return_null_texture();
-    }
-
-    this->setScratchTextureUnit();
-    GL_CALL(BindTexture(idDesc.fInfo.fTarget, idDesc.fInfo.fID));
-
-    if (renderTarget && this->glCaps().textureUsageSupport()) {
-        // provides a hint about how this texture will be used
-        GL_CALL(TexParameteri(idDesc.fInfo.fTarget,
-                              GR_GL_TEXTURE_USAGE,
-                              GR_GL_FRAMEBUFFER_ATTACHMENT));
-    }
-
-    // Some drivers like to know filter/wrap before seeing glTexImage2D. Some
-    // drivers have a bug where an FBO won't be complete if it includes a
-    // texture that is not mipmap complete (considering the filter in use).
     GrGLTexture::TexParams initialTexParams;
-    // we only set a subset here so invalidate first
-    initialTexParams.invalidate();
-    initialTexParams.fMinFilter = GR_GL_NEAREST;
-    initialTexParams.fMagFilter = GR_GL_NEAREST;
-    initialTexParams.fWrapS = GR_GL_CLAMP_TO_EDGE;
-    initialTexParams.fWrapT = GR_GL_CLAMP_TO_EDGE;
-    GL_CALL(TexParameteri(idDesc.fInfo.fTarget,
-                          GR_GL_TEXTURE_MAG_FILTER,
-                          initialTexParams.fMagFilter));
-    GL_CALL(TexParameteri(idDesc.fInfo.fTarget,
-                          GR_GL_TEXTURE_MIN_FILTER,
-                          initialTexParams.fMinFilter));
-    GL_CALL(TexParameteri(idDesc.fInfo.fTarget,
-                          GR_GL_TEXTURE_WRAP_S,
-                          initialTexParams.fWrapS));
-    GL_CALL(TexParameteri(idDesc.fInfo.fTarget,
-                          GR_GL_TEXTURE_WRAP_T,
-                          initialTexParams.fWrapT));
-    if (!this->uploadTexData(desc, idDesc.fInfo.fTarget, kNewTexture_UploadType, 0, 0,
-                             desc.fWidth, desc.fHeight,
-                             desc.fConfig, srcData, rowBytes)) {
-        GL_CALL(DeleteTextures(1, &idDesc.fInfo.fID));
+    if (!this->createTextureImpl(desc, &idDesc.fInfo, renderTarget, srcData,
+                                 &initialTexParams, rowBytes)) {
         return return_null_texture();
     }
 
@@ -1476,6 +1450,86 @@ int GrGLGpu::getCompatibleStencilIndex(GrPixelConfig config) {
     return this->glCaps().getStencilFormatIndexForConfig(config);
 }
 
+bool GrGLGpu::createTextureImpl(const GrSurfaceDesc& desc, GrGLTextureInfo* info,
+                                bool renderTarget, const void* srcData,
+                                GrGLTexture::TexParams* initialTexParams, size_t rowBytes) {
+    // Some drivers like to know filter/wrap before seeing glTexImage2D. Some
+    // drivers have a bug where an FBO won't be complete if it includes a
+    // texture that is not mipmap complete (considering the filter in use).
+
+    // we only set a subset here so invalidate first
+    initialTexParams->invalidate();
+    initialTexParams->fMinFilter = GR_GL_NEAREST;
+    initialTexParams->fMagFilter = GR_GL_NEAREST;
+    initialTexParams->fWrapS = GR_GL_CLAMP_TO_EDGE;
+    initialTexParams->fWrapT = GR_GL_CLAMP_TO_EDGE;
+
+    if (desc.fTextureStorageAllocator.fAllocateTextureStorage) {
+        return this->createTextureExternalAllocatorImpl(desc, info, srcData, rowBytes);
+    }
+
+    info->fID = 0;
+    info->fTarget = GR_GL_TEXTURE_2D;
+    GL_CALL(GenTextures(1, &(info->fID)));
+
+    if (!info->fID) {
+        return false;
+    }
+
+    this->setScratchTextureUnit();
+    GL_CALL(BindTexture(info->fTarget, info->fID));
+
+    if (renderTarget && this->glCaps().textureUsageSupport()) {
+        // provides a hint about how this texture will be used
+        GL_CALL(TexParameteri(info->fTarget,
+                              GR_GL_TEXTURE_USAGE,
+                              GR_GL_FRAMEBUFFER_ATTACHMENT));
+    }
+
+    GL_CALL(TexParameteri(info->fTarget,
+                          GR_GL_TEXTURE_MAG_FILTER,
+                          initialTexParams->fMagFilter));
+    GL_CALL(TexParameteri(info->fTarget,
+                          GR_GL_TEXTURE_MIN_FILTER,
+                          initialTexParams->fMinFilter));
+    GL_CALL(TexParameteri(info->fTarget,
+                          GR_GL_TEXTURE_WRAP_S,
+                          initialTexParams->fWrapS));
+    GL_CALL(TexParameteri(info->fTarget,
+                          GR_GL_TEXTURE_WRAP_T,
+                          initialTexParams->fWrapT));
+    if (!this->uploadTexData(desc, info, kNewTexture_UploadType, 0, 0,
+                             desc.fWidth, desc.fHeight,
+                             desc.fConfig, srcData, rowBytes)) {
+        GL_CALL(DeleteTextures(1, &(info->fID)));
+        return false;
+    }
+    return true;
+}
+
+bool GrGLGpu::createTextureExternalAllocatorImpl(
+        const GrSurfaceDesc& desc, GrGLTextureInfo* info, const void* srcData, size_t rowBytes) {
+    switch (desc.fTextureStorageAllocator.fAllocateTextureStorage(
+                    desc.fTextureStorageAllocator.fCtx, reinterpret_cast<GrBackendObject>(info),
+                    desc.fWidth, desc.fHeight, desc.fConfig, srcData, desc.fOrigin)) {
+        case GrTextureStorageAllocator::Result::kSucceededAndUploaded:
+            return true;
+        case GrTextureStorageAllocator::Result::kFailed:
+            return false;
+        case GrTextureStorageAllocator::Result::kSucceededWithoutUpload:
+            break;
+    }
+
+    if (!this->uploadTexData(desc, info, kNewTexture_UploadType, 0, 0,
+                             desc.fWidth, desc.fHeight,
+                             desc.fConfig, srcData, rowBytes)) {
+        desc.fTextureStorageAllocator.fDeallocateTextureStorage(
+                desc.fTextureStorageAllocator.fCtx, reinterpret_cast<GrBackendObject>(info));
+        return false;
+    }
+    return true;
+}
+
 GrStencilAttachment* GrGLGpu::createStencilAttachmentForRenderTarget(const GrRenderTarget* rt,
                                                                      int width,
                                                                      int height) {
index 6f194dc..1ed91a5 100644 (file)
@@ -159,6 +159,18 @@ private:
     // compatible stencil format, or negative if there is no compatible stencil format.
     int getCompatibleStencilIndex(GrPixelConfig config);
 
+    // If |desc.fTextureStorageAllocator| exists, use that to create the
+    // texture. Otherwise, create the texture directly.
+    // Returns whether the texture is successfully created. On success, the
+    // result is stored in |info|.
+    // The texture is populated with |srcData|, if it exists.
+    // The texture parameters are cached in |initialTexParams|.
+    bool createTextureImpl(const GrSurfaceDesc& desc, GrGLTextureInfo* info,
+                           bool renderTarget, const void* srcData,
+                           GrGLTexture::TexParams* initialTexParams, size_t rowBytes);
+    bool createTextureExternalAllocatorImpl(const GrSurfaceDesc& desc, GrGLTextureInfo* info,
+                                            const void* srcData, size_t rowBytes);
+
     void onClear(GrRenderTarget*, const SkIRect& rect, GrColor color) override;
 
     void onClearStencilClip(GrRenderTarget*, const SkIRect& rect, bool insideClip) override;
@@ -319,7 +331,7 @@ private:
         kTransfer_UploadType,      // we are using a transfer buffer to copy data
     };
     bool uploadTexData(const GrSurfaceDesc& desc,
-                       GrGLenum target,
+                       GrGLTextureInfo* info,
                        UploadType uploadType,
                        int left, int top, int width, int height,
                        GrPixelConfig dataConfig,
index 39a8d92..864547a 100644 (file)
@@ -37,7 +37,13 @@ void GrGLTexture::init(const GrSurfaceDesc& desc, const IDDesc& idDesc) {
 void GrGLTexture::onRelease() {
     if (fInfo.fID) {
         if (GrGpuResource::kBorrowed_LifeCycle != fTextureIDLifecycle) {
-            GL_CALL(DeleteTextures(1, &fInfo.fID));
+            if (this->desc().fTextureStorageAllocator.fDeallocateTextureStorage) {
+                this->desc().fTextureStorageAllocator.fDeallocateTextureStorage(
+                        this->desc().fTextureStorageAllocator.fCtx,
+                        reinterpret_cast<GrBackendObject>(&fInfo));
+            } else {
+                GL_CALL(DeleteTextures(1, &fInfo.fID));
+            }
         }
         fInfo.fID = 0;
     }
index 0315f6c..fed13a2 100644 (file)
@@ -204,7 +204,7 @@ SkSurface* SkSurface::NewRenderTargetDirect(GrRenderTarget*, const SkSurfaceProp
 }
 
 SkSurface* SkSurface::NewRenderTarget(GrContext*, Budgeted, const SkImageInfo&, int,
-                                      const SkSurfaceProps*) {
+                                      const SkSurfaceProps*, GrTextureStorageAllocator) {
     return nullptr;
 }
 
index 2d5645b..f7a31c0 100644 (file)
@@ -121,9 +121,11 @@ SkSurface* SkSurface::NewRenderTargetDirect(GrRenderTarget* target, const SkSurf
 }
 
 SkSurface* SkSurface::NewRenderTarget(GrContext* ctx, Budgeted budgeted, const SkImageInfo& info,
-                                      int sampleCount, const SkSurfaceProps* props) {
-    SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(ctx, budgeted, info, sampleCount, props,
-                                                         SkGpuDevice::kClear_InitContents));
+                                      int sampleCount, const SkSurfaceProps* props,
+                                      GrTextureStorageAllocator customAllocator) {
+    SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(
+            ctx, budgeted, info, sampleCount, props, SkGpuDevice::kClear_InitContents,
+            customAllocator));
     if (!device) {
         return nullptr;
     }