Add SkImage factory method that forces image to be resolved to a texture.
authorbsalomon <bsalomon@google.com>
Sat, 30 Jan 2016 18:01:40 +0000 (10:01 -0800)
committerCommit bot <commit-bot@chromium.org>
Sat, 30 Jan 2016 18:01:40 +0000 (10:01 -0800)
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1631053003

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

gm/image.cpp
include/core/SkImage.h
src/image/SkImage.cpp
src/image/SkImage_Gpu.cpp
tests/ImageTest.cpp

index 60c1f11..e79968a 100644 (file)
@@ -5,6 +5,7 @@
  * found in the LICENSE file.
  */
 
+#include <functional>
 #include "gm.h"
 #include "SkData.h"
 #include "SkCanvas.h"
@@ -429,3 +430,86 @@ private:
     typedef skiagm::GM INHERITED;
 };
 DEF_GM( return new ScaleGeneratorGM; )
+
+#if SK_SUPPORT_GPU
+#include "GrContextFactory.h"
+#endif
+
+DEF_SIMPLE_GM(new_texture_image, canvas, 225, 60) {
+    GrContext* context = nullptr;
+#if SK_SUPPORT_GPU
+    context = canvas->getGrContext();
+    GrContextFactory factory;
+#endif
+    if (!context) {
+        skiagm::GM::DrawGpuOnlyMessage(canvas);
+        return;
+    }
+
+    auto render_image = [](SkCanvas* canvas) {
+        canvas->clear(SK_ColorBLUE);
+        SkPaint paint;
+        paint.setColor(SK_ColorRED);
+        canvas->drawRect(SkRect::MakeXYWH(10.f,10.f,10.f,10.f), paint);
+        paint.setColor(SK_ColorGREEN);
+        canvas->drawRect(SkRect::MakeXYWH(30.f,10.f,10.f,10.f), paint);
+        paint.setColor(SK_ColorYELLOW);
+        canvas->drawRect(SkRect::MakeXYWH(10.f,30.f,10.f,10.f), paint);
+        paint.setColor(SK_ColorCYAN);
+        canvas->drawRect(SkRect::MakeXYWH(30.f,30.f,10.f,10.f), paint);
+    };
+
+    static const int kSize = 50;
+    SkBitmap bmp;
+    bmp.allocN32Pixels(kSize, kSize);
+    SkCanvas bmpCanvas(bmp);
+    render_image(&bmpCanvas);
+
+    std::function<SkImage*()> imageFactories[] = {
+        // Create sw raster image.
+        [bmp] {
+            return SkImage::NewFromBitmap(bmp);
+        },
+        // Create encoded image.
+        [bmp] {
+            SkAutoTUnref<SkData> src(
+                SkImageEncoder::EncodeData(bmp, SkImageEncoder::kPNG_Type, 100));
+            return SkImage::NewFromEncoded(src);
+        },
+        // Create a picture image.
+        [render_image] {
+            SkPictureRecorder recorder;
+            SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(kSize), SkIntToScalar(kSize));
+            render_image(canvas);
+            SkAutoTUnref<SkPicture> picture(recorder.endRecording());
+            return SkImage::NewFromPicture(picture, SkISize::Make(kSize, kSize), nullptr, nullptr);
+        },
+        // Create a texture image
+        [context, render_image]() -> SkImage* {
+            SkAutoTUnref<SkSurface> surface(
+                SkSurface::NewRenderTarget(context, SkSurface::kYes_Budgeted,
+                                           SkImageInfo::MakeN32Premul(kSize, kSize)));
+            if (!surface) {
+                return nullptr;
+            }
+            render_image(surface->getCanvas());
+            return surface->newImageSnapshot();
+        }
+    };
+
+    static const SkScalar kPad = 5.f;
+    canvas->translate(kPad, kPad);
+    for (auto factory : imageFactories) {
+        SkAutoTUnref<SkImage> image(factory());
+        if (!image) {
+            continue;
+        }
+        if (context) {
+            SkAutoTUnref<SkImage> texImage(image->newTextureImage(context));
+            if (texImage) {
+                canvas->drawImage(texImage, 0, 0);
+            }
+        }
+        canvas->translate(image->width() + kPad, 0);
+    }
+}
index 62a9e9c..e60902f 100644 (file)
@@ -300,6 +300,13 @@ public:
      */
     SkImage* newSubset(const SkIRect& subset) const;
 
+    /**
+     *  Ensures that an image is backed by a texture (when GrContext is non-null). If no
+     *  transformation is required, the returned image may be the same as this image. If the this
+     *  image is from a different GrContext, this will fail.
+     */
+    SkImage* newTextureImage(GrContext*) const;
+
     // Helper functions to convert to SkBitmap
 
     enum LegacyBitmapMode {
index 25370bc..4f31fc5 100644 (file)
@@ -339,4 +339,8 @@ SkImage* SkImage::NewFromTextureCopy(GrContext*, const GrBackendTextureDesc&, Sk
     return nullptr;
 }
 
+SkImage* SkImage::newTextureImage(GrContext*) const {
+    return nullptr;
+}
+
 #endif
index a758efe..1956958 100644 (file)
@@ -282,6 +282,37 @@ SkImage* SkImage::NewFromYUVTexturesCopy(GrContext* ctx , SkYUVColorSpace colorS
                            kOpaque_SkAlphaType, dst, budgeted);
 }
 
+static SkImage* create_image_from_maker(GrTextureMaker* maker, SkAlphaType at, uint32_t id) {
+    SkAutoTUnref<GrTexture> texture(maker->refTextureForParams(GrTextureParams::ClampNoFilter()));
+    if (!texture) {
+        return nullptr;
+    }
+    return new SkImage_Gpu(texture->width(), texture->height(), id, at, texture,
+                           SkSurface::kNo_Budgeted);
+}
+
+SkImage* SkImage::newTextureImage(GrContext *context) const {
+    if (!context) {
+        return nullptr;
+    }
+    if (GrTexture* peek = as_IB(this)->peekTexture()) {
+        return peek->getContext() == context ? SkRef(const_cast<SkImage*>(this)) : nullptr;
+    }
+    // No way to check whether a image is premul or not?
+    SkAlphaType at = this->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
+
+    if (SkImageCacherator* cacher = as_IB(this)->peekCacherator()) {
+        GrImageTextureMaker maker(context, cacher, this, kDisallow_CachingHint);
+        return create_image_from_maker(&maker, at, this->uniqueID());
+    }
+    SkBitmap bmp;
+    if (!this->asLegacyBitmap(&bmp, kRO_LegacyBitmapMode)) {
+        return nullptr;
+    }
+    GrBitmapTextureMaker maker(context, bmp);
+    return create_image_from_maker(&maker, at, this->uniqueID());
+}
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 GrTexture* GrDeepCopyTexture(GrTexture* src, bool budgeted) {
index 575fc1c..1bf56c5 100644 (file)
@@ -5,6 +5,9 @@
  * found in the LICENSE file.
  */
 
+#include <functional>
+#include "DMGpuSupport.h"
+
 #include "SkBitmap.h"
 #include "SkCanvas.h"
 #include "SkData.h"
 #include "SkUtils.h"
 #include "Test.h"
 
-#if SK_SUPPORT_GPU
-#include "GrContext.h"
-#include "gl/GrGLInterface.h"
-#include "gl/GrGLUtil.h"
-#endif
-
 static void assert_equal(skiatest::Reporter* reporter, SkImage* a, const SkIRect* subsetA,
                          SkImage* b) {
     const int widthA = subsetA ? subsetA->width() : a->width();
@@ -87,6 +84,15 @@ static SkImage* create_data_image() {
     SkAutoTUnref<SkData> data(create_image_data(&info));
     return SkImage::NewRasterData(info, data, info.minRowBytes());
 }
+#if SK_SUPPORT_GPU // not gpu-specific but currently only used in GPU tests
+static SkImage* create_picture_image() {
+    SkPictureRecorder recorder;
+    SkCanvas* canvas = recorder.beginRecording(10, 10);
+    canvas->clear(SK_ColorCYAN);
+    SkAutoTUnref<SkPicture> picture(recorder.endRecording());
+    return SkImage::NewFromPicture(picture, SkISize::Make(10, 10), nullptr, nullptr);
+};
+#endif
 // Want to ensure that our Release is called when the owning image is destroyed
 struct RasterDataHolder {
     RasterDataHolder() : fReleaseCount(0) {}
@@ -376,6 +382,64 @@ DEF_GPUTEST_FOR_NATIVE_CONTEXT(SkImage_Gpu2Cpu, reporter, context) {
         REPORTER_ASSERT(reporter, !SkBitmapCache::Find(uniqueID, &cachedBitmap));
     }
 }
+
+DEF_GPUTEST_FOR_NATIVE_CONTEXT(SkImage_newTextureImage, reporter, context, glContext) {
+    GrContextFactory otherFactory;
+    GrContextFactory::ContextInfo otherContextInfo =
+        otherFactory.getContextInfo(GrContextFactory::kNative_GLContextType);
+    glContext->makeCurrent();
+
+    std::function<SkImage*()> imageFactories[] = {
+        create_image,
+        create_codec_image,
+        create_data_image,
+        // Create an image from a picture.
+        create_picture_image,
+        // Create a texture image.
+        [context] { return create_gpu_image(context); },
+        // Create a texture image in a another GrContext.
+        [glContext, otherContextInfo] {
+            otherContextInfo.fGLContext->makeCurrent();
+            SkImage* otherContextImage = create_gpu_image(otherContextInfo.fGrContext);
+            glContext->makeCurrent();
+            return otherContextImage;
+        }
+    };
+
+    for (auto factory : imageFactories) {
+        SkAutoTUnref<SkImage> image(factory());
+        if (!image) {
+            ERRORF(reporter, "Error creating image.");
+            continue;
+        }
+        GrTexture* origTexture = as_IB(image)->peekTexture();
+
+        SkAutoTUnref<SkImage> texImage(image->newTextureImage(context));
+        if (!texImage) {
+            // We execpt to fail if image comes from a different GrContext.
+            if (!origTexture || origTexture->getContext() == context) {
+                ERRORF(reporter, "newTextureImage failed.");
+            }
+            continue;
+        }
+        GrTexture* copyTexture = as_IB(texImage)->peekTexture();
+        if (!copyTexture) {
+            ERRORF(reporter, "newTextureImage returned non-texture image.");
+            continue;
+        }
+        if (origTexture) {
+            if (origTexture != copyTexture) {
+                ERRORF(reporter, "newTextureImage made unnecessary texture copy.");
+            }
+        }
+        if (image->width() != texImage->width() || image->height() != texImage->height()) {
+            ERRORF(reporter, "newTextureImage changed the image size.");
+        }
+        if (image->isOpaque() != texImage->isOpaque()) {
+            ERRORF(reporter, "newTextureImage changed image opaqueness.");
+        }
+    }
+}
 #endif
 
 // https://bug.skia.org/4390