aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gm/image.cpp84
-rw-r--r--include/core/SkImage.h7
-rw-r--r--src/image/SkImage.cpp4
-rw-r--r--src/image/SkImage_Gpu.cpp31
-rw-r--r--tests/ImageTest.cpp76
5 files changed, 196 insertions, 6 deletions
diff --git a/gm/image.cpp b/gm/image.cpp
index 60c1f11418..e79968a18f 100644
--- a/gm/image.cpp
+++ b/gm/image.cpp
@@ -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);
+ }
+}
diff --git a/include/core/SkImage.h b/include/core/SkImage.h
index 62a9e9cf42..e60902fc07 100644
--- a/include/core/SkImage.h
+++ b/include/core/SkImage.h
@@ -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 {
diff --git a/src/image/SkImage.cpp b/src/image/SkImage.cpp
index 25370bcff1..4f31fc5672 100644
--- a/src/image/SkImage.cpp
+++ b/src/image/SkImage.cpp
@@ -339,4 +339,8 @@ SkImage* SkImage::NewFromTextureCopy(GrContext*, const GrBackendTextureDesc&, Sk
return nullptr;
}
+SkImage* SkImage::newTextureImage(GrContext*) const {
+ return nullptr;
+}
+
#endif
diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp
index a758efed5c..1956958b3c 100644
--- a/src/image/SkImage_Gpu.cpp
+++ b/src/image/SkImage_Gpu.cpp
@@ -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) {
diff --git a/tests/ImageTest.cpp b/tests/ImageTest.cpp
index 575fc1c287..1bf56c53a2 100644
--- a/tests/ImageTest.cpp
+++ b/tests/ImageTest.cpp
@@ -5,6 +5,9 @@
* found in the LICENSE file.
*/
+#include <functional>
+#include "DMGpuSupport.h"
+
#include "SkBitmap.h"
#include "SkCanvas.h"
#include "SkData.h"
@@ -21,12 +24,6 @@
#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