add ability to get FBO ID to Surface

BUG=skia:

Review URL: https://codereview.chromium.org/1220733007
diff --git a/include/core/SkSurface.h b/include/core/SkSurface.h
index 5860cf2..57527ed 100644
--- a/include/core/SkSurface.h
+++ b/include/core/SkSurface.h
@@ -159,11 +159,23 @@
      */
     void notifyContentWillChange(ContentChangeMode mode);
 
-    enum TextureHandleAccess {
-        kFlushRead_TextureHandleAccess,     //!< caller may read from the texture
-        kFlushWrite_TextureHandleAccess,    //!< caller may write to the texture
-        kDiscardWrite_TextureHandleAccess,  //!< caller must over-write the entire texture
+    enum BackendHandleAccess {
+        kFlushRead_BackendHandleAccess,     //!< caller may read from the backend object
+        kFlushWrite_BackendHandleAccess,    //!< caller may write to the backend object
+        kDiscardWrite_BackendHandleAccess,  //!< caller must over-write the entire backend object
     };
+
+    /*
+     * These are legacy aliases which will be removed soon
+     */
+    static const BackendHandleAccess kFlushRead_TextureHandleAccess =
+            kFlushRead_BackendHandleAccess;
+    static const BackendHandleAccess kFlushWrite_TextureHandleAccess =
+            kFlushWrite_BackendHandleAccess;
+    static const BackendHandleAccess kDiscardWrite_TextureHandleAccess =
+            kDiscardWrite_BackendHandleAccess;
+
+
     /**
      *  Retrieves the backend API handle of the texture used by this surface, or 0 if the surface
      *  is not backed by a GPU texture.
@@ -171,7 +183,15 @@
      *  The returned texture-handle is only valid until the next draw-call into the surface,
      *  or the surface is deleted.
      */
-    GrBackendObject getTextureHandle(TextureHandleAccess);
+    GrBackendObject getTextureHandle(BackendHandleAccess);
+
+    /**
+     *  Retrieves the backend API handle of the RenderTarget backing this surface.  Callers must
+     *  ensure this function returns 'true' or else the GrBackendObject will be invalid
+     *
+     *  In OpenGL this will return the FramebufferObject ID.
+     */
+    bool getRenderTargetHandle(GrBackendObject*, BackendHandleAccess);
 
     /**
      *  Return a canvas that will draw into this surface. This will always
diff --git a/include/gpu/GrRenderTarget.h b/include/gpu/GrRenderTarget.h
index 67dcd4f..8983d53 100644
--- a/include/gpu/GrRenderTarget.h
+++ b/include/gpu/GrRenderTarget.h
@@ -138,6 +138,12 @@
     };
     virtual ResolveType getResolveType() const = 0;
 
+    /**
+     *  Return the native ID or handle to the rendertarget, depending on the
+     *  platform. e.g. on OpenGL, return the FBO ID.
+     */
+    virtual GrBackendObject getRenderTargetHandle() const = 0;
+
     // Provides access to functions that aren't part of the public API.
     GrRenderTargetPriv renderTargetPriv();
     const GrRenderTargetPriv renderTargetPriv() const;
diff --git a/src/gpu/gl/GrGLRenderTarget.h b/src/gpu/gl/GrGLRenderTarget.h
index 2113a80..1e6dc7f 100644
--- a/src/gpu/gl/GrGLRenderTarget.h
+++ b/src/gpu/gl/GrGLRenderTarget.h
@@ -55,6 +55,8 @@
         }
     }
 
+    GrBackendObject getRenderTargetHandle() const override { return fRTFBOID; }
+
     /** When we don't own the FBO ID we don't attempt to modify its attachments. */
     bool canAttemptStencilAttachment() const override {
         return kCached_LifeCycle == fRTLifecycle || kUncached_LifeCycle == fRTLifecycle;
diff --git a/src/image/SkSurface.cpp b/src/image/SkSurface.cpp
index 35409be..2e8c7fa 100644
--- a/src/image/SkSurface.cpp
+++ b/src/image/SkSurface.cpp
@@ -175,10 +175,14 @@
     return this->getCanvas()->readPixels(dstInfo, dstPixels, dstRowBytes, srcX, srcY);
 }
 
-GrBackendObject SkSurface::getTextureHandle(TextureHandleAccess access) {
+GrBackendObject SkSurface::getTextureHandle(BackendHandleAccess access) {
     return asSB(this)->onGetTextureHandle(access);
 }
 
+bool SkSurface::getRenderTargetHandle(GrBackendObject* obj, BackendHandleAccess access) {
+    return asSB(this)->onGetRenderTargetHandle(obj, access);
+}
+
 //////////////////////////////////////////////////////////////////////////////////////
 
 #if !SK_SUPPORT_GPU
diff --git a/src/image/SkSurface_Base.h b/src/image/SkSurface_Base.h
index 3f1301e..b8eb7dd 100644
--- a/src/image/SkSurface_Base.h
+++ b/src/image/SkSurface_Base.h
@@ -18,10 +18,14 @@
     SkSurface_Base(const SkImageInfo&, const SkSurfaceProps*);
     virtual ~SkSurface_Base();
 
-    virtual GrBackendObject onGetTextureHandle(TextureHandleAccess) {
+    virtual GrBackendObject onGetTextureHandle(BackendHandleAccess) {
         return 0;
     }
 
+    virtual bool onGetRenderTargetHandle(GrBackendObject*, BackendHandleAccess) {
+        return false;
+    }
+
     /**
      *  Allocate a canvas that will draw into this surface. We will cache this
      *  canvas, to return the same object to the caller multiple times. We
diff --git a/src/image/SkSurface_Gpu.cpp b/src/image/SkSurface_Gpu.cpp
index 3a306ad..67f54d5 100644
--- a/src/image/SkSurface_Gpu.cpp
+++ b/src/image/SkSurface_Gpu.cpp
@@ -26,21 +26,37 @@
     fDevice->unref();
 }
 
-GrBackendObject SkSurface_Gpu::onGetTextureHandle(TextureHandleAccess access) {
-    GrRenderTarget* rt = fDevice->accessRenderTarget();
+static GrRenderTarget* prepare_rt_for_external_access(SkSurface_Gpu* surface,
+                                                      SkSurface::BackendHandleAccess access) {
+    GrRenderTarget* rt = surface->getDevice()->accessRenderTarget();
     switch (access) {
-        case kFlushRead_TextureHandleAccess:
+        case SkSurface::kFlushRead_BackendHandleAccess:
             break;
-        case kFlushWrite_TextureHandleAccess:
-        case kDiscardWrite_TextureHandleAccess:
+        case SkSurface::kFlushWrite_BackendHandleAccess:
+        case SkSurface::kDiscardWrite_BackendHandleAccess:
             // for now we don't special-case on Discard, but we may in the future.
-            this->notifyContentWillChange(kRetain_ContentChangeMode);
+            surface->notifyContentWillChange(SkSurface::kRetain_ContentChangeMode);
             // legacy: need to dirty the bitmap's genID in our device (curse it)
-            fDevice->fLegacyBitmap.notifyPixelsChanged();
+            surface->getDevice()->accessBitmap(false).notifyPixelsChanged();
             break;
     }
     rt->prepareForExternalIO();
-    return rt->asTexture()->getTextureHandle();
+    return rt;
+}
+
+GrBackendObject SkSurface_Gpu::onGetTextureHandle(BackendHandleAccess access) {
+    GrRenderTarget* rt = prepare_rt_for_external_access(this, access);
+    GrTexture* texture = rt->asTexture();
+    if (texture) {
+        return texture->getTextureHandle();
+    }
+    return 0;
+}
+
+bool SkSurface_Gpu::onGetRenderTargetHandle(GrBackendObject* obj, BackendHandleAccess access) {
+    GrRenderTarget* rt = prepare_rt_for_external_access(this, access);
+    *obj = rt->getRenderTargetHandle();
+    return true;
 }
 
 SkCanvas* SkSurface_Gpu::onNewCanvas() {
diff --git a/src/image/SkSurface_Gpu.h b/src/image/SkSurface_Gpu.h
index ed94a24..2324154 100644
--- a/src/image/SkSurface_Gpu.h
+++ b/src/image/SkSurface_Gpu.h
@@ -16,12 +16,11 @@
 
 class SkSurface_Gpu : public SkSurface_Base {
 public:
-    
-
     SkSurface_Gpu(SkGpuDevice*);
     virtual ~SkSurface_Gpu();
 
-    GrBackendObject onGetTextureHandle(TextureHandleAccess) override;
+    GrBackendObject onGetTextureHandle(BackendHandleAccess) override;
+    bool onGetRenderTargetHandle(GrBackendObject*, BackendHandleAccess) override;
     SkCanvas* onNewCanvas() override;
     SkSurface* onNewSurface(const SkImageInfo&) override;
     SkImage* onNewImageSnapshot(Budgeted) override;
diff --git a/tests/SurfaceTest.cpp b/tests/SurfaceTest.cpp
index 1b57b77..e8ff63c 100644
--- a/tests/SurfaceTest.cpp
+++ b/tests/SurfaceTest.cpp
@@ -102,7 +102,7 @@
 }
 
 #if SK_SUPPORT_GPU
-static void test_wrapped_surface(skiatest::Reporter* reporter, GrContext* ctx) {
+static void test_wrapped_texture_surface(skiatest::Reporter* reporter, GrContext* ctx) {
     if (NULL == ctx) {
         return;
     }
@@ -120,107 +120,77 @@
         return;
     }
 
-    for (int useFBO = 0; useFBO < 2; ++useFBO) {
-        // Test the wrapped factory for SkSurface by creating a texture using GL and then wrap it in
-        // a SkSurface.
-        GrGLuint texID;
-        static const int kW = 100;
-        static const int kH = 100;
-        static const uint32_t kOrigColor = 0xFFAABBCC;
-        SkAutoTArray<uint32_t> pixels(kW * kH);
-        sk_memset32(pixels.get(), kOrigColor, kW * kH);
-        GR_GL_CALL(gl, GenTextures(1, &texID));
-        GR_GL_CALL(gl, ActiveTexture(GR_GL_TEXTURE0));
-        GR_GL_CALL(gl, PixelStorei(GR_GL_UNPACK_ALIGNMENT, 1));
-        GR_GL_CALL(gl, BindTexture(GR_GL_TEXTURE_2D, texID));
-        GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MAG_FILTER,
-                                     GR_GL_NEAREST));
-        GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MIN_FILTER,
-                                     GR_GL_NEAREST));
-        GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_WRAP_S,
-                                     GR_GL_CLAMP_TO_EDGE));
-        GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_WRAP_T,
-                                     GR_GL_CLAMP_TO_EDGE));
-        GR_GL_CALL(gl, TexImage2D(GR_GL_TEXTURE_2D, 0, GR_GL_RGBA, kW, kH, 0, GR_GL_RGBA,
-                                  GR_GL_UNSIGNED_BYTE,
-                                  pixels.get()));
+    // Test the wrapped factory for SkSurface by creating a texture using GL and then wrap it in
+    // a SkSurface.
+    GrGLuint texID;
+    static const int kW = 100;
+    static const int kH = 100;
+    static const uint32_t kOrigColor = 0xFFAABBCC;
+    SkAutoTArray<uint32_t> pixels(kW * kH);
+    sk_memset32(pixels.get(), kOrigColor, kW * kH);
+    GR_GL_CALL(gl, GenTextures(1, &texID));
+    GR_GL_CALL(gl, ActiveTexture(GR_GL_TEXTURE0));
+    GR_GL_CALL(gl, PixelStorei(GR_GL_UNPACK_ALIGNMENT, 1));
+    GR_GL_CALL(gl, BindTexture(GR_GL_TEXTURE_2D, texID));
+    GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MAG_FILTER,
+                                 GR_GL_NEAREST));
+    GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MIN_FILTER,
+                                 GR_GL_NEAREST));
+    GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_WRAP_S,
+                                 GR_GL_CLAMP_TO_EDGE));
+    GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_WRAP_T,
+                                 GR_GL_CLAMP_TO_EDGE));
+    GR_GL_CALL(gl, TexImage2D(GR_GL_TEXTURE_2D, 0, GR_GL_RGBA, kW, kH, 0, GR_GL_RGBA,
+                              GR_GL_UNSIGNED_BYTE,
+                              pixels.get()));
 
-        SkAutoTUnref<SkSurface> surface;
-        GrGLuint fboID = 0;
-        if (useFBO) {
-            GR_GL_CALL(gl, GenFramebuffers(1, &fboID));
-            GR_GL_CALL(gl, BindFramebuffer(GR_GL_FRAMEBUFFER, fboID));
-            GR_GL_CALL(gl, FramebufferTexture2D(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0,
-                                                GR_GL_TEXTURE_2D, texID, 0));
-            GrBackendRenderTargetDesc wrappedDesc;
-            wrappedDesc.fConfig = kRGBA_8888_GrPixelConfig;
-            wrappedDesc.fWidth = kW;
-            wrappedDesc.fHeight = kH;
-            wrappedDesc.fOrigin = kBottomLeft_GrSurfaceOrigin;
-            wrappedDesc.fSampleCnt = 0;
-            wrappedDesc.fRenderTargetHandle = fboID;
-            wrappedDesc.fStencilBits = 0;
+    GrBackendTextureDesc wrappedDesc;
+    wrappedDesc.fConfig = kRGBA_8888_GrPixelConfig;
+    wrappedDesc.fWidth = kW;
+    wrappedDesc.fHeight = kH;
+    wrappedDesc.fOrigin = kBottomLeft_GrSurfaceOrigin;
+    wrappedDesc.fSampleCnt = 0;
+    wrappedDesc.fFlags = kRenderTarget_GrBackendTextureFlag;
+    wrappedDesc.fTextureHandle = texID;
 
-            ctx->resetContext();
-            surface.reset(SkSurface::NewFromBackendRenderTarget(ctx, wrappedDesc, NULL));
-        } else {
-            GrBackendTextureDesc wrappedDesc;
-            wrappedDesc.fConfig = kRGBA_8888_GrPixelConfig;
-            wrappedDesc.fWidth = kW;
-            wrappedDesc.fHeight = kH;
-            wrappedDesc.fOrigin = kBottomLeft_GrSurfaceOrigin;
-            wrappedDesc.fSampleCnt = 0;
-            wrappedDesc.fFlags = kRenderTarget_GrBackendTextureFlag;
-            wrappedDesc.fTextureHandle = texID;
-
-            ctx->resetContext();
-            surface.reset(SkSurface::NewFromBackendTexture(ctx, wrappedDesc, NULL));
-        }
-        REPORTER_ASSERT(reporter, surface);
-        if (surface) {
-            // Validate that we can draw to the canvas and that the original texture color is
-            // preserved in pixels that aren't rendered to via the surface.
-            SkPaint paint;
-            static const SkColor kRectColor = ~kOrigColor | 0xFF000000;
-            paint.setColor(kRectColor);
-            surface->getCanvas()->drawRect(SkRect::MakeWH(SkIntToScalar(kW), SkIntToScalar(kH)/2),
-                                           paint);
-            SkImageInfo readInfo = SkImageInfo::MakeN32Premul(kW, kH);
-            surface->readPixels(readInfo, pixels.get(), kW * sizeof(uint32_t), 0, 0);
-            bool stop = false;
-            SkPMColor origColorPM = SkPackARGB32((kOrigColor >> 24 & 0xFF),
-                                                 (kOrigColor >>  0 & 0xFF),
-                                                 (kOrigColor >>  8 & 0xFF),
-                                                 (kOrigColor >> 16 & 0xFF));
-            SkPMColor rectColorPM = SkPackARGB32((kRectColor >> 24 & 0xFF),
-                                                 (kRectColor >> 16 & 0xFF),
-                                                 (kRectColor >>  8 & 0xFF),
-                                                 (kRectColor >>  0 & 0xFF));
-            for (int y = 0; y < kH/2 && !stop; ++y) {
-                for (int x = 0; x < kW && !stop; ++x) {
-                    REPORTER_ASSERT(reporter, rectColorPM == pixels[x + y * kW]);
-                    if (rectColorPM != pixels[x + y * kW]) {
-                        stop = true;
-                    }
-                }
-            }
-            stop = false;
-            for (int y = kH/2; y < kH && !stop; ++y) {
-                for (int x = 0; x < kW && !stop; ++x) {
-                    REPORTER_ASSERT(reporter, origColorPM == pixels[x + y * kW]);
-                    if (origColorPM != pixels[x + y * kW]) {
-                        stop = true;
-                    }
+    SkAutoTUnref<SkSurface> surface(SkSurface::NewWrappedRenderTarget(ctx, wrappedDesc, NULL));
+    REPORTER_ASSERT(reporter, surface);
+    if (surface) {
+        // Validate that we can draw to the canvas and that the original texture color is preserved
+        // in pixels that aren't rendered to via the surface.
+        SkPaint paint;
+        static const SkColor kRectColor = ~kOrigColor | 0xFF000000;
+        paint.setColor(kRectColor);
+        surface->getCanvas()->drawRect(SkRect::MakeWH(SkIntToScalar(kW), SkIntToScalar(kH)/2),
+                                       paint);
+        SkImageInfo readInfo = SkImageInfo::MakeN32Premul(kW, kH);
+        surface->readPixels(readInfo, pixels.get(), kW * sizeof(uint32_t), 0, 0);
+        bool stop = false;
+        SkPMColor origColorPM = SkPackARGB32((kOrigColor >> 24 & 0xFF),
+                                             (kOrigColor >>  0 & 0xFF),
+                                             (kOrigColor >>  8 & 0xFF),
+                                             (kOrigColor >> 16 & 0xFF));
+        SkPMColor rectColorPM = SkPackARGB32((kRectColor >> 24 & 0xFF),
+                                             (kRectColor >> 16 & 0xFF),
+                                             (kRectColor >>  8 & 0xFF),
+                                             (kRectColor >>  0 & 0xFF));
+        for (int y = 0; y < kH/2 && !stop; ++y) {
+            for (int x = 0; x < kW && !stop; ++x) {
+                REPORTER_ASSERT(reporter, rectColorPM == pixels[x + y * kW]);
+                if (rectColorPM != pixels[x + y * kW]) {
+                    stop = true;
                 }
             }
         }
-        if (texID) {
-            GR_GL_CALL(gl, DeleteTextures(1, &texID));
+        stop = false;
+        for (int y = kH/2; y < kH && !stop; ++y) {
+            for (int x = 0; x < kW && !stop; ++x) {
+                REPORTER_ASSERT(reporter, origColorPM == pixels[x + y * kW]);
+                if (origColorPM != pixels[x + y * kW]) {
+                    stop = true;
+                }
+            }
         }
-        if (fboID) {
-            GR_GL_CALL(gl, DeleteFramebuffers(1, &fboID));
-        }
-
     }
 }
 #endif
@@ -267,37 +237,39 @@
  *  Note: this needs to be tested separately from checking newImageSnapshot, as calling that
  *  can also incidentally bump the genID (when a new backing surface is created).
  */
-static void test_texture_handle_genID(skiatest::Reporter* reporter, SkSurface* surf) {
+template <class F>
+static void test_texture_handle_genID(skiatest::Reporter* reporter, SkSurface* surf, F f) {
     const uint32_t gen0 = get_legacy_gen_id(surf);
-    surf->getTextureHandle(SkSurface::kFlushRead_TextureHandleAccess);
+    f(surf, SkSurface::kFlushRead_BackendHandleAccess);
     const uint32_t gen1 = get_legacy_gen_id(surf);
     REPORTER_ASSERT(reporter, gen0 == gen1);
 
-    surf->getTextureHandle(SkSurface::kFlushWrite_TextureHandleAccess);
+    f(surf, SkSurface::kFlushWrite_BackendHandleAccess);
     const uint32_t gen2 = get_legacy_gen_id(surf);
     REPORTER_ASSERT(reporter, gen0 != gen2);
 
-    surf->getTextureHandle(SkSurface::kDiscardWrite_TextureHandleAccess);
+    f(surf, SkSurface::kDiscardWrite_BackendHandleAccess);
     const uint32_t gen3 = get_legacy_gen_id(surf);
     REPORTER_ASSERT(reporter, gen0 != gen3);
     REPORTER_ASSERT(reporter, gen2 != gen3);
 }
 
-static void test_texture_handle(skiatest::Reporter* reporter, SkSurface* surf) {
+template <class F>
+static void test_backend_handle(skiatest::Reporter* reporter, SkSurface* surf, F f) {
     SkAutoTUnref<SkImage> image0(surf->newImageSnapshot());
-    GrBackendObject obj = surf->getTextureHandle(SkSurface::kFlushRead_TextureHandleAccess);
+    GrBackendObject obj = f(surf, SkSurface::kFlushRead_BackendHandleAccess);
     REPORTER_ASSERT(reporter, obj != 0);
     SkAutoTUnref<SkImage> image1(surf->newImageSnapshot());
     // just read access should not affect the snapshot
     REPORTER_ASSERT(reporter, image0->uniqueID() == image1->uniqueID());
 
-    obj = surf->getTextureHandle(SkSurface::kFlushWrite_TextureHandleAccess);
+    obj = f(surf, SkSurface::kFlushWrite_BackendHandleAccess);
     REPORTER_ASSERT(reporter, obj != 0);
     SkAutoTUnref<SkImage> image2(surf->newImageSnapshot());
     // expect a new image, since we claimed we would write
     REPORTER_ASSERT(reporter, image0->uniqueID() != image2->uniqueID());
 
-    obj = surf->getTextureHandle(SkSurface::kDiscardWrite_TextureHandleAccess);
+    obj = f(surf, SkSurface::kDiscardWrite_BackendHandleAccess);
     REPORTER_ASSERT(reporter, obj != 0);
     SkAutoTUnref<SkImage> image3(surf->newImageSnapshot());
     // expect a new(er) image, since we claimed we would write
@@ -331,9 +303,20 @@
             SkAutoTUnref<SkSurface> surf(
                 SkSurface::NewRenderTarget(context, SkSurface::kNo_Budgeted, info, 0));
             surf->getCanvas()->clear(color);
-            // test our backing texture while were here...
-            test_texture_handle_genID(reporter, surf);
-            test_texture_handle(reporter, surf);
+            // test our backing texture / rendertarget while were here...
+            auto textureAccessorFunc =
+                    [](SkSurface* surf, SkSurface::BackendHandleAccess access) -> GrBackendObject {
+                        return surf->getTextureHandle(access); };
+            auto renderTargetAccessorFunc =
+                    [](SkSurface* surf, SkSurface::BackendHandleAccess access) -> GrBackendObject {
+                        GrBackendObject obj;
+                        SkAssertResult(surf->getRenderTargetHandle(&obj, access));
+                        return obj; };
+            test_backend_handle(reporter, surf, textureAccessorFunc);
+            test_backend_handle(reporter, surf, renderTargetAccessorFunc);
+            test_texture_handle_genID(reporter, surf, textureAccessorFunc);
+            test_texture_handle_genID(reporter, surf, renderTargetAccessorFunc);
+
             // redraw so our returned image looks as expected.
             surf->getCanvas()->clear(color);
             return surf->newImageSnapshot();
@@ -912,7 +895,7 @@
                 TestGetTexture(reporter, kGpuScratch_SurfaceType, context);
                 test_empty_surface(reporter, context);
                 test_surface_budget(reporter, context);
-                test_wrapped_surface(reporter, context);
+                test_wrapped_texture_surface(reporter, context);
             }
         }
     }