add SkImage::NewFromBitmap
authorreed <reed@chromium.org>
Tue, 7 Jul 2015 13:11:19 +0000 (06:11 -0700)
committerCommit bot <commit-bot@chromium.org>
Tue, 7 Jul 2015 13:11:20 +0000 (06:11 -0700)
BUG=skia:

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

gm/colormatrix.cpp
include/core/SkImage.h
src/core/SkRecorder.cpp
src/image/SkImage.cpp
src/image/SkImagePriv.h
src/image/SkImage_Gpu.cpp
src/image/SkImage_Raster.cpp
src/image/SkSurface_Raster.cpp
tests/DeferredCanvasTest.cpp
tests/SkImageTest.cpp

index 8dcdf15..a80f8cb 100644 (file)
@@ -8,60 +8,40 @@
 #include "gm.h"
 #include "SkColorMatrixFilter.h"
 #include "SkGradientShader.h"
+#include "SkImage.h"
 
 #define WIDTH 500
 #define HEIGHT 500
 
-class SkDoOnce {
-public:
-    SkDoOnce() : fOnce(false) {};
-
-    bool once() const {
-        if (fOnce) {
-            return false;
-        }
-        fOnce = true;
-        return true;
-    }
-
-private:
-    mutable bool fOnce;
-};
-
-static void setColorMatrix(SkPaint* paint, const SkColorMatrix& matrix) {
+static void set_color_matrix(SkPaint* paint, const SkColorMatrix& matrix) {
     paint->setColorFilter(SkColorMatrixFilter::Create(matrix))->unref();
 }
 
-static void setArray(SkPaint* paint, const SkScalar array[]) {
+static void set_array(SkPaint* paint, const SkScalar array[]) {
     paint->setColorFilter(SkColorMatrixFilter::Create(array))->unref();
 }
 
-namespace skiagm {
-
-class ColorMatrixGM : public GM {
-    SkDoOnce fOnce;
-    void init() {
-        if (fOnce.once()) {
-            fSolidBitmap = this->createSolidBitmap(64, 64);
-            fTransparentBitmap = this->createTransparentBitmap(64, 64);
-        }
-    }
-
+class ColorMatrixGM : public skiagm::GM {
 public:
     ColorMatrixGM() {
         this->setBGColor(sk_tool_utils::color_to_565(0xFF808080));
     }
 
 protected:
-    virtual SkString onShortName() {
+    SkString onShortName() override {
         return SkString("colormatrix");
     }
 
-    virtual SkISize onISize() {
+    SkISize onISize() override {
         return SkISize::Make(WIDTH, HEIGHT);
     }
+    
+    void onOnceBeforeDraw() override {
+        fSolidImg.reset(CreateSolidBitmap(64, 64));
+        fTransparentImg.reset(CreateTransparentBitmap(64, 64));
+    }
 
-    SkBitmap createSolidBitmap(int width, int height) {
+    static SkImage* CreateSolidBitmap(int width, int height) {
         SkBitmap bm;
         bm.allocN32Pixels(width, height);
         SkCanvas canvas(bm);
@@ -74,11 +54,11 @@ protected:
                     SkIntToScalar(y), SK_Scalar1, SK_Scalar1), paint);
             }
         }
-        return bm;
+        return SkImage::NewFromBitmap(bm);
     }
 
     // creates a bitmap with shades of transparent gray.
-    SkBitmap createTransparentBitmap(int width, int height) {
+    static SkImage* CreateTransparentBitmap(int width, int height) {
         SkBitmap bm;
         bm.allocN32Pixels(width, height);
         SkCanvas canvas(bm);
@@ -90,58 +70,56 @@ protected:
         paint.setShader(SkGradientShader::CreateLinear(pts, colors, NULL, 2,
                                                        SkShader::kClamp_TileMode))->unref();
         canvas.drawRect(SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)), paint);
-        return bm;
+        return SkImage::NewFromBitmap(bm);
     }
 
-    virtual void onDraw(SkCanvas* canvas) {
-        this->init();
-
+    void onDraw(SkCanvas* canvas) override {
         SkPaint paint;
         SkColorMatrix matrix;
 
         paint.setXfermodeMode(SkXfermode::kSrc_Mode);
-        const SkBitmap bmps[] = { fSolidBitmap, fTransparentBitmap };
+        const SkImage* bmps[] = { fSolidImg, fTransparentImg };
 
         for (size_t i = 0; i < SK_ARRAY_COUNT(bmps); ++i) {
             matrix.setIdentity();
-            setColorMatrix(&paint, matrix);
-            canvas->drawBitmap(bmps[i], 0, 0, &paint);
+            set_color_matrix(&paint, matrix);
+            canvas->drawImage(bmps[i], 0, 0, &paint);
 
             matrix.setRotate(SkColorMatrix::kR_Axis, 90);
-            setColorMatrix(&paint, matrix);
-            canvas->drawBitmap(bmps[i], 80, 0, &paint);
+            set_color_matrix(&paint, matrix);
+            canvas->drawImage(bmps[i], 80, 0, &paint);
 
             matrix.setRotate(SkColorMatrix::kG_Axis, 90);
-            setColorMatrix(&paint, matrix);
-            canvas->drawBitmap(bmps[i], 160, 0, &paint);
+            set_color_matrix(&paint, matrix);
+            canvas->drawImage(bmps[i], 160, 0, &paint);
 
             matrix.setRotate(SkColorMatrix::kB_Axis, 90);
-            setColorMatrix(&paint, matrix);
-            canvas->drawBitmap(bmps[i], 240, 0, &paint);
-
+            set_color_matrix(&paint, matrix);
+            canvas->drawImage(bmps[i], 240, 0, &paint);
+            ///////////////////////////////////////////////
             matrix.setSaturation(0.0f);
-            setColorMatrix(&paint, matrix);
-            canvas->drawBitmap(bmps[i], 0, 80, &paint);
+            set_color_matrix(&paint, matrix);
+            canvas->drawImage(bmps[i], 0, 80, &paint);
 
             matrix.setSaturation(0.5f);
-            setColorMatrix(&paint, matrix);
-            canvas->drawBitmap(bmps[i], 80, 80, &paint);
+            set_color_matrix(&paint, matrix);
+            canvas->drawImage(bmps[i], 80, 80, &paint);
 
             matrix.setSaturation(1.0f);
-            setColorMatrix(&paint, matrix);
-            canvas->drawBitmap(bmps[i], 160, 80, &paint);
+            set_color_matrix(&paint, matrix);
+            canvas->drawImage(bmps[i], 160, 80, &paint);
 
             matrix.setSaturation(2.0f);
-            setColorMatrix(&paint, matrix);
-            canvas->drawBitmap(bmps[i], 240, 80, &paint);
-
+            set_color_matrix(&paint, matrix);
+            canvas->drawImage(bmps[i], 240, 80, &paint);
+            ///////////////////////////////////////////////
             matrix.setRGB2YUV();
-            setColorMatrix(&paint, matrix);
-            canvas->drawBitmap(bmps[i], 0, 160, &paint);
+            set_color_matrix(&paint, matrix);
+            canvas->drawImage(bmps[i], 0, 160, &paint);
 
             matrix.setYUV2RGB();
-            setColorMatrix(&paint, matrix);
-            canvas->drawBitmap(bmps[i], 80, 160, &paint);
+            set_color_matrix(&paint, matrix);
+            canvas->drawImage(bmps[i], 80, 160, &paint);
 
             SkScalar s1 = SK_Scalar1;
             SkScalar s255 = SkIntToScalar(255);
@@ -153,22 +131,18 @@ protected:
                 s1, 0, 0, 0, 0,
             };
 
-            setArray(&paint, data);
-            canvas->drawBitmap(bmps[i], 160, 160, &paint);
-
+            set_array(&paint, data);
+            canvas->drawImage(bmps[i], 160, 160, &paint);
+            ///////////////////////////////////////////////
             canvas->translate(0, 240);
         }
     }
 
 private:
-    SkBitmap fSolidBitmap;
-    SkBitmap fTransparentBitmap;
-    typedef GM INHERITED;
-};
-
-//////////////////////////////////////////////////////////////////////////////
+    SkAutoTUnref<SkImage>   fSolidImg;
+    SkAutoTUnref<SkImage>   fTransparentImg;
 
-static GM* MyFactory(void*) { return new ColorMatrixGM; }
-static GMRegistry reg(MyFactory);
+    typedef skiagm::GM INHERITED;
+};
+DEF_GM( return new ColorMatrixGM; )
 
-}
index 7557e8e..41a1bd8 100644 (file)
@@ -62,6 +62,12 @@ public:
                                   RasterReleaseProc, ReleaseContext);
 
     /**
+     *  Construct a new image from the specified bitmap. If the bitmap is marked immutable, and
+     *  its pixel memory is shareable, it may be shared instead of copied.
+     */
+    static SkImage* NewFromBitmap(const SkBitmap&);
+    
+    /**
      *  Construct a new SkImage based on the given ImageGenerator.
      *  This function will always take ownership of the passed
      *  ImageGenerator.  Returns NULL on error.
index 775a7e0..7433a5b 100644 (file)
@@ -12,6 +12,8 @@
 #include "SkPictureUtils.h"
 #include "SkRecorder.h"
 
+//#define WRAP_BITMAP_AS_IMAGE
+
 SkDrawableList::~SkDrawableList() {
     fArray.unrefAll();
 }
@@ -170,7 +172,14 @@ void SkRecorder::onDrawBitmap(const SkBitmap& bitmap,
                               SkScalar left,
                               SkScalar top,
                               const SkPaint* paint) {
+#ifdef WRAP_BITMAP_AS_IMAGE
+    SkAutoTUnref<SkImage> image(SkImage::NewFromBitmap(bitmap));
+    if (image) {
+        this->onDrawImage(image, left, top, paint);
+    }
+#else
     APPEND(DrawBitmap, this->copy(paint), bitmap, left, top);
+#endif
 }
 
 void SkRecorder::onDrawBitmapRect(const SkBitmap& bitmap,
@@ -178,6 +187,13 @@ void SkRecorder::onDrawBitmapRect(const SkBitmap& bitmap,
                                   const SkRect& dst,
                                   const SkPaint* paint,
                                   DrawBitmapRectFlags flags) {
+#ifdef WRAP_BITMAP_AS_IMAGE
+    // TODO: need a way to support the flags for images...
+    SkAutoTUnref<SkImage> image(SkImage::NewFromBitmap(bitmap));
+    if (image) {
+        this->onDrawImageRect(image, src, dst, paint);
+    }
+#else
     TRY_MINIRECORDER(drawBitmapRectToRect, bitmap, src, dst, paint, flags);
     if (kBleed_DrawBitmapRectFlag == flags) {
         APPEND(DrawBitmapRectToRectBleed,
@@ -187,13 +203,21 @@ void SkRecorder::onDrawBitmapRect(const SkBitmap& bitmap,
     SkASSERT(kNone_DrawBitmapRectFlag == flags);
     APPEND(DrawBitmapRectToRect,
            this->copy(paint), bitmap, this->copy(src), dst);
+#endif
 }
 
 void SkRecorder::onDrawBitmapNine(const SkBitmap& bitmap,
                                   const SkIRect& center,
                                   const SkRect& dst,
                                   const SkPaint* paint) {
+#ifdef WRAP_BITMAP_AS_IMAGE
+    SkAutoTUnref<SkImage> image(SkImage::NewFromBitmap(bitmap));
+    if (image) {
+        this->onDrawImageNine(image, center, dst, paint);
+    }
+#else
     APPEND(DrawBitmapNine, this->copy(paint), bitmap, center, dst);
+#endif
 }
 
 void SkRecorder::onDrawImage(const SkImage* image, SkScalar left, SkScalar top,
index 1d61438..d3533a9 100644 (file)
 #include "SkImageGenerator.h"
 #include "SkImagePriv.h"
 #include "SkImage_Base.h"
+#include "SkPixelRef.h"
 #include "SkReadPixelsRec.h"
 #include "SkString.h"
 #include "SkSurface.h"
+
 #if SK_SUPPORT_GPU
 #include "GrTexture.h"
 #include "GrContext.h"
+#include "SkImage_Gpu.h"
 #endif
 
 uint32_t SkImage::NextUniqueID() {
@@ -227,6 +230,41 @@ bool SkImage::readPixels(const SkPixmap& pmap, int srcX, int srcY) const {
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
+SkImage* SkImage::NewFromBitmap(const SkBitmap& bm) {
+    SkPixelRef* pr = bm.pixelRef();
+    if (NULL == pr) {
+        return NULL;
+    }
+
+#if SK_SUPPORT_GPU
+    if (GrTexture* tex = pr->getTexture()) {
+        SkAutoTUnref<GrTexture> unrefCopy;
+        if (!bm.isImmutable()) {
+            const bool notBudgeted = false;
+            tex = GrDeepCopyTexture(tex, notBudgeted);
+            if (NULL == tex) {
+                return NULL;
+            }
+            unrefCopy.reset(tex);
+        }
+        const SkImageInfo info = bm.info();
+        return SkNEW_ARGS(SkImage_Gpu, (info.width(), info.height(), info.alphaType(),
+                                        tex, 0, SkSurface::kNo_Budgeted));
+    }
+#endif
+
+    // Encoded version?
+    if (SkData* encoded = pr->refEncodedData()) {
+        SkAutoTUnref<SkData> data(encoded);
+        return SkImage::NewFromEncoded(encoded);   // todo: add origin/subset/etc?
+    }
+
+    // This will check for immutable (share or copy)
+    return SkNewImageFromRasterBitmap(bm, false, NULL);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+
 #if !SK_SUPPORT_GPU
 
 SkImage* SkImage::NewFromTexture(GrContext*, const GrBackendTextureDesc&, SkAlphaType,
index d3b1c79..afaf3f1 100644 (file)
@@ -23,11 +23,14 @@ extern SkImage* SkNewImageFromPixelRef(const SkImageInfo&, SkPixelRef*,
  *  be shared if either the bitmap is marked as immutable, or canSharePixelRef
  *  is true.
  *
+ *  It is illegal to call this with a texture-backed bitmap.
+ *
  *  If the bitmap's colortype cannot be converted into a corresponding
  *  SkImageInfo, or the bitmap's pixels cannot be accessed, this will return
  *  NULL.
  */
-extern SkImage* SkNewImageFromBitmap(const SkBitmap&, bool canSharePixelRef, const SkSurfaceProps*);
+extern SkImage* SkNewImageFromRasterBitmap(const SkBitmap&, bool forceSharePixelRef,
+                                           const SkSurfaceProps*);
 
 static inline size_t SkImageMinRowBytes(const SkImageInfo& info) {
     size_t minRB = info.minRowBytes();
@@ -53,4 +56,6 @@ extern void SkTextureImageApplyBudgetedDecision(SkImage* textureImage);
 // surface needs to perform a copy-on-write
 extern void SkTextureImageSetTexture(SkImage* image, GrTexture* texture);
 
+GrTexture* GrDeepCopyTexture(GrTexture* src, bool isBudgeted);
+
 #endif
index 4003631..d9ae619 100644 (file)
@@ -144,42 +144,27 @@ SkImage* SkImage::NewFromAdoptedTexture(GrContext* ctx, const GrBackendTextureDe
     return new_wrapped_texture_common(ctx, desc, at, kAdopt_GrWrapOwnership, NULL, NULL);
 }
 
-SkImage* SkImage::NewFromTextureCopy(GrContext* ctx, const GrBackendTextureDesc& srcDesc,
+SkImage* SkImage::NewFromTextureCopy(GrContext* ctx, const GrBackendTextureDesc& desc,
                                      SkAlphaType at) {
-    const bool isBudgeted = true;
-    const SkSurface::Budgeted budgeted = SkSurface::kYes_Budgeted;
-
-    if (srcDesc.fWidth <= 0 || srcDesc.fHeight <= 0) {
+    if (desc.fWidth <= 0 || desc.fHeight <= 0) {
         return NULL;
     }
+
     SkAutoTUnref<GrTexture> src(ctx->textureProvider()->wrapBackendTexture(
-        srcDesc, kBorrow_GrWrapOwnership));
+        desc, kBorrow_GrWrapOwnership));
     if (!src) {
         return NULL;
     }
 
-    GrSurfaceDesc dstDesc;
-    // need to be a rendertarget for readpixels to work, instead of kNone_GrSurfaceFlags
-    dstDesc.fFlags = kRenderTarget_GrSurfaceFlag;
-    dstDesc.fOrigin = srcDesc.fOrigin;
-    dstDesc.fWidth = srcDesc.fWidth;
-    dstDesc.fHeight = srcDesc.fHeight;
-    dstDesc.fConfig = srcDesc.fConfig;
-    dstDesc.fSampleCnt = srcDesc.fSampleCnt;
-
-    SkAutoTUnref<GrTexture> dst(ctx->textureProvider()->createTexture(
-                                                                  dstDesc, isBudgeted, NULL, 0));
+    const bool isBudgeted = true;
+    SkAutoTUnref<GrTexture> dst(GrDeepCopyTexture(src, isBudgeted));
     if (!dst) {
         return NULL;
     }
 
-    const SkIRect srcR = SkIRect::MakeWH(dstDesc.fWidth, dstDesc.fHeight);
-    const SkIPoint dstP = SkIPoint::Make(0, 0);
-    ctx->copySurface(dst, src, srcR, dstP, GrContext::kFlushWrites_PixelOp);
-
+    const SkSurface::Budgeted budgeted = SkSurface::kYes_Budgeted;
     const int sampleCount = 0;  // todo: make this an explicit parameter to newSurface()?
-    return SkNEW_ARGS(SkImage_Gpu, (dstDesc.fWidth, dstDesc.fHeight, at, dst, sampleCount,
-                                    budgeted));
+    return SkNEW_ARGS(SkImage_Gpu, (desc.fWidth, desc.fHeight, at, dst, sampleCount, budgeted));
 }
 
 SkImage* SkImage::NewFromYUVTexturesCopy(GrContext* ctx , SkYUVColorSpace colorSpace,
@@ -256,3 +241,23 @@ SkImage* SkImage::NewFromYUVTexturesCopy(GrContext* ctx , SkYUVColorSpace colorS
     return SkNEW_ARGS(SkImage_Gpu, (dstDesc.fWidth, dstDesc.fHeight, kOpaque_SkAlphaType, dst, 0,
                                     budgeted));
 }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+GrTexture* GrDeepCopyTexture(GrTexture* src, bool budgeted) {
+    GrContext* ctx = src->getContext();
+
+    GrSurfaceDesc desc = src->desc();
+    // need to be a rendertarget for readpixels to work, instead of kNone_GrSurfaceFlags
+    desc.fFlags = kRenderTarget_GrSurfaceFlag;
+    GrTexture* dst = ctx->textureProvider()->createTexture(desc, budgeted, NULL, 0);
+    if (!dst) {
+        return NULL;
+    }
+    
+    const SkIRect srcR = SkIRect::MakeWH(desc.fWidth, desc.fHeight);
+    const SkIPoint dstP = SkIPoint::Make(0, 0);
+    ctx->copySurface(dst, src, srcR, dstP, GrContext::kFlushWrites_PixelOp);
+    return dst;
+}
+
index 0316d53..250e362 100644 (file)
@@ -227,21 +227,24 @@ SkImage* SkNewImageFromPixelRef(const SkImageInfo& info, SkPixelRef* pr,
     return SkNEW_ARGS(SkImage_Raster, (info, pr, pixelRefOrigin, rowBytes, props));
 }
 
-SkImage* SkNewImageFromBitmap(const SkBitmap& bm, bool canSharePixelRef,
-                              const SkSurfaceProps* props) {
+SkImage* SkNewImageFromRasterBitmap(const SkBitmap& bm, bool forceSharePixelRef,
+                                    const SkSurfaceProps* props) {
+    SkASSERT(NULL == bm.getTexture());
+
     if (!SkImage_Raster::ValidArgs(bm.info(), bm.rowBytes(), NULL, NULL)) {
         return NULL;
     }
 
     SkImage* image = NULL;
-    if (canSharePixelRef || bm.isImmutable()) {
+    if (forceSharePixelRef || bm.isImmutable()) {
         image = SkNEW_ARGS(SkImage_Raster, (bm, props));
     } else {
-        bm.lockPixels();
-        if (bm.getPixels()) {
-            image = SkImage::NewRasterCopy(bm.info(), bm.getPixels(), bm.rowBytes());
+        SkBitmap tmp(bm);
+        tmp.lockPixels();
+        if (tmp.getPixels()) {
+            image = SkImage::NewRasterCopy(tmp.info(), tmp.getPixels(), tmp.rowBytes(),
+                                           tmp.getColorTable());
         }
-        bm.unlockPixels();
 
         // we don't expose props to NewRasterCopy (need a private vers) so post-init it here
         if (image && props) {
index 4e0ba08..d66aed2 100644 (file)
@@ -118,7 +118,7 @@ void SkSurface_Raster::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y,
 }
 
 SkImage* SkSurface_Raster::onNewImageSnapshot(Budgeted) {
-    return SkNewImageFromBitmap(fBitmap, fWeOwnThePixels, &this->props());
+    return SkNewImageFromRasterBitmap(fBitmap, fWeOwnThePixels, &this->props());
 }
 
 void SkSurface_Raster::onCopyOnWrite(ContentChangeMode mode) {
index fff213b..a34f5bc 100644 (file)
@@ -64,7 +64,7 @@ public:
     }
 
     SkImage* onNewImageSnapshot(Budgeted) override {
-        return SkNewImageFromBitmap(fBitmap, true, &this->props());
+        return SkNewImageFromRasterBitmap(fBitmap, true, &this->props());
     }
 
     void onCopyOnWrite(ContentChangeMode mode) override {
index c058ef0..2f23b3f 100644 (file)
@@ -26,7 +26,7 @@ DEF_TEST(SkImageFromBitmap_extractSubset, reporter) {
         canvas.drawIRect(r, p);
         SkBitmap dstBitmap;
         srcBitmap.extractSubset(&dstBitmap, r);
-        image.reset(SkNewImageFromBitmap(dstBitmap, true, NULL));
+        image.reset(SkNewImageFromRasterBitmap(dstBitmap, true, NULL));
     }
 
     SkBitmap tgt;