add getTextureHandle to SkSurface
authorreed <reed@google.com>
Mon, 29 Jun 2015 14:37:01 +0000 (07:37 -0700)
committerCommit bot <commit-bot@chromium.org>
Mon, 29 Jun 2015 14:37:01 +0000 (07:37 -0700)
BUG=485243

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

include/core/SkSurface.h
src/image/SkSurface.cpp
src/image/SkSurface_Base.h
src/image/SkSurface_Gpu.cpp
src/image/SkSurface_Gpu.h
tests/SurfaceTest.cpp

index 8ccfa31..5d08ee6 100644 (file)
@@ -138,9 +138,25 @@ public:
     /**
      *  Call this if the contents are about to change. This will (lazily) force a new
      *  value to be returned from generationID() when it is called next.
+     *
+     *  CAN WE DEPRECATE THIS?
      */
     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
+    };
+    /**
+     *  Retrieves the backend API handle of the texture used by this surface, or 0 if the surface
+     *  is not backed by a GPU texture.
+     *
+     *  The returned texture-handle is only valid until the next draw-call into the surface,
+     *  or the surface is deleted.
+     */
+    GrBackendObject getTextureHandle(TextureHandleAccess);
+
     /**
      *  Return a canvas that will draw into this surface. This will always
      *  return the same canvas for a given surface, and is manged/owned by the
index a999973..34035a3 100644 (file)
@@ -175,6 +175,10 @@ bool SkSurface::readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t d
     return this->getCanvas()->readPixels(dstInfo, dstPixels, dstRowBytes, srcX, srcY);
 }
 
+GrBackendObject SkSurface::getTextureHandle(TextureHandleAccess access) {
+    return asSB(this)->onGetTextureHandle(access);
+}
+
 //////////////////////////////////////////////////////////////////////////////////////
 
 #if !SK_SUPPORT_GPU
index 30af976..3f1301e 100644 (file)
@@ -18,6 +18,10 @@ public:
     SkSurface_Base(const SkImageInfo&, const SkSurfaceProps*);
     virtual ~SkSurface_Base();
 
+    virtual GrBackendObject onGetTextureHandle(TextureHandleAccess) {
+        return 0;
+    }
+
     /**
      *  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
index fa006a6..34532f7 100644 (file)
@@ -26,6 +26,24 @@ SkSurface_Gpu::~SkSurface_Gpu() {
     fDevice->unref();
 }
 
+GrBackendObject SkSurface_Gpu::onGetTextureHandle(TextureHandleAccess access) {
+    GrRenderTarget* rt = fDevice->accessRenderTarget();
+    switch (access) {
+        case kFlushRead_TextureHandleAccess:
+            rt->prepareForExternalRead();   // todo: rename to prepareForExternalAccess()
+            break;
+        case kFlushWrite_TextureHandleAccess:
+            this->notifyContentWillChange(kRetain_ContentChangeMode);
+            rt->flushWrites();
+            break;
+        case kDiscardWrite_TextureHandleAccess:
+            this->notifyContentWillChange(kDiscard_ContentChangeMode);
+            rt->discard();
+            break;
+    }
+    return rt->asTexture()->getTextureHandle();
+}
+
 SkCanvas* SkSurface_Gpu::onNewCanvas() {
     SkCanvas::InitFlags flags = SkCanvas::kDefault_InitFlags;
     // When we think this works...
index 025cb7d..ed94a24 100644 (file)
@@ -21,6 +21,7 @@ public:
     SkSurface_Gpu(SkGpuDevice*);
     virtual ~SkSurface_Gpu();
 
+    GrBackendObject onGetTextureHandle(TextureHandleAccess) override;
     SkCanvas* onNewCanvas() override;
     SkSurface* onNewSurface(const SkImageInfo&) override;
     SkImage* onNewImageSnapshot(Budgeted) override;
index c45e94e..8179060 100644 (file)
@@ -223,7 +223,30 @@ struct ReleaseDataContext {
     }
 };
 
-static SkImage* create_image(ImageType imageType, GrContext* context, SkColor color,
+static void test_texture_handle(skiatest::Reporter* reporter, SkSurface* surf) {
+    SkAutoTUnref<SkImage> image0(surf->newImageSnapshot());
+    GrBackendObject obj = surf->getTextureHandle(SkSurface::kFlushRead_TextureHandleAccess);
+    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);
+    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);
+    REPORTER_ASSERT(reporter, obj != 0);
+    SkAutoTUnref<SkImage> image3(surf->newImageSnapshot());
+    // expect a new(er) image, since we claimed we would write
+    REPORTER_ASSERT(reporter, image0->uniqueID() != image3->uniqueID());
+    REPORTER_ASSERT(reporter, image2->uniqueID() != image3->uniqueID());
+}
+
+static SkImage* create_image(skiatest::Reporter* reporter,
+                             ImageType imageType, GrContext* context, SkColor color,
                              ReleaseDataContext* releaseContext) {
     const SkPMColor pmcolor = SkPreMultiplyColor(color);
     const SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10);
@@ -248,6 +271,10 @@ static SkImage* create_image(ImageType imageType, GrContext* context, SkColor co
             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(reporter, surf);
+            // redraw so our returned image looks as expected.
+            surf->getCanvas()->clear(color);
             return surf->newImageSnapshot();
         }
         case kCodec_ImageType: {
@@ -351,7 +378,7 @@ static void test_imagepeek(skiatest::Reporter* reporter, GrContextFactory* facto
         size_t rowBytes;
 
         releaseCtx.fData = NULL;
-        SkAutoTUnref<SkImage> image(create_image(gRec[i].fType, ctx, color, &releaseCtx));
+        SkAutoTUnref<SkImage> image(create_image(reporter, gRec[i].fType, ctx, color, &releaseCtx));
         if (!image.get()) {
             SkDebugf("failed to createImage[%d] %s\n", i, gRec[i].fName);
             continue;   // gpu may not be enabled