aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gm/image.cpp81
-rw-r--r--include/core/SkImage.h8
-rw-r--r--src/image/SkImage.cpp4
-rw-r--r--src/image/SkImage_Gpu.cpp32
-rw-r--r--tests/DeviceTest.cpp4
-rw-r--r--tests/ImageTest.cpp68
6 files changed, 194 insertions, 3 deletions
diff --git a/gm/image.cpp b/gm/image.cpp
index 595a5ef628..1a4b712491 100644
--- a/gm/image.cpp
+++ b/gm/image.cpp
@@ -427,3 +427,84 @@ private:
typedef skiagm::GM INHERITED;
};
DEF_GM( return new ScaleGeneratorGM; )
+
+DEF_SIMPLE_GM(new_texture_image, canvas, 225, 60) {
+ GrContext* context = nullptr;
+#if SK_SUPPORT_GPU
+ context = canvas->getGrContext();
+#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 constexpr int kSize = 50;
+ SkBitmap bmp;
+ bmp.allocPixels(SkImageInfo::MakeS32(kSize, kSize, kPremul_SkAlphaType));
+ SkCanvas bmpCanvas(bmp);
+ render_image(&bmpCanvas);
+
+ std::function<sk_sp<SkImage>()> imageFactories[] = {
+ // Create sw raster image.
+ [bmp] {
+ return SkImage::MakeFromBitmap(bmp);
+ },
+ // Create encoded image.
+ [bmp] {
+ sk_sp<SkData> src(
+ sk_tool_utils::EncodeImageToData(bmp, SkEncodedImageFormat::kPNG, 100));
+ return SkImage::MakeFromEncoded(std::move(src));
+ },
+ // Create a picture image.
+ [render_image] {
+ SkPictureRecorder recorder;
+ SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(kSize), SkIntToScalar(kSize));
+ render_image(canvas);
+ sk_sp<SkColorSpace> srgbColorSpace = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
+ return SkImage::MakeFromPicture(recorder.finishRecordingAsPicture(),
+ SkISize::Make(kSize, kSize), nullptr, nullptr,
+ SkImage::BitDepth::kU8, srgbColorSpace);
+ },
+ // Create a texture image
+ [context, render_image]() -> sk_sp<SkImage> {
+ auto surface(SkSurface::MakeRenderTarget(context, SkBudgeted::kYes,
+ SkImageInfo::MakeS32(kSize, kSize,
+ kPremul_SkAlphaType)));
+ if (!surface) {
+ return nullptr;
+ }
+ render_image(surface->getCanvas());
+ return surface->makeImageSnapshot();
+ }
+ };
+
+ constexpr SkScalar kPad = 5.f;
+ canvas->translate(kPad, kPad);
+ for (auto factory : imageFactories) {
+ auto image(factory());
+ if (!image) {
+ continue;
+ }
+ if (context) {
+ sk_sp<SkImage> texImage(image->makeTextureImage(context,
+ canvas->imageInfo().colorSpace()));
+ 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 2e421c90d1..532708a3d0 100644
--- a/include/core/SkImage.h
+++ b/include/core/SkImage.h
@@ -323,6 +323,14 @@ public:
sk_sp<SkImage> makeSubset(const SkIRect& subset) const;
/**
+ * Ensures that an image is backed by a texture (when GrContext is non-null), suitable for use
+ * with surfaces that have the supplied destination color space. If no transformation is
+ * required, the returned image may be the same as this image. If this image is from a
+ * different GrContext, this will fail.
+ */
+ sk_sp<SkImage> makeTextureImage(GrContext*, SkColorSpace* dstColorSpace) const;
+
+ /**
* If the image is texture-backed this will make a raster copy of it (or nullptr if reading back
* the pixels fails). Otherwise, it returns the original image.
*/
diff --git a/src/image/SkImage.cpp b/src/image/SkImage.cpp
index 40586fd06d..67c96d7ed2 100644
--- a/src/image/SkImage.cpp
+++ b/src/image/SkImage.cpp
@@ -370,6 +370,10 @@ sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopy(GrContext* ctx, SkYUVColorSpace
return nullptr;
}
+sk_sp<SkImage> SkImage::makeTextureImage(GrContext*, SkColorSpace* dstColorSpace) const {
+ return nullptr;
+}
+
sk_sp<SkImage> SkImage::makeNonTextureImage() const {
return sk_ref_sp(const_cast<SkImage*>(this));
}
diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp
index ef25844a0f..98a7101e6b 100644
--- a/src/image/SkImage_Gpu.cpp
+++ b/src/image/SkImage_Gpu.cpp
@@ -350,6 +350,38 @@ sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopy(GrContext* ctx, SkYUVColorSpace
std::move(imageColorSpace));
}
+static sk_sp<SkImage> create_image_from_maker(GrTextureMaker* maker, SkAlphaType at, uint32_t id,
+ SkColorSpace* dstColorSpace) {
+ sk_sp<SkColorSpace> texColorSpace;
+ sk_sp<GrTexture> texture(maker->refTextureForParams(GrSamplerParams::ClampNoFilter(),
+ dstColorSpace, &texColorSpace, nullptr));
+ if (!texture) {
+ return nullptr;
+ }
+ return sk_make_sp<SkImage_Gpu>(texture->width(), texture->height(), id, at, std::move(texture),
+ std::move(texColorSpace), SkBudgeted::kNo);
+}
+
+sk_sp<SkImage> SkImage::makeTextureImage(GrContext *context, SkColorSpace* dstColorSpace) const {
+ if (!context) {
+ return nullptr;
+ }
+ if (GrTexture* peek = as_IB(this)->peekTexture()) {
+ return peek->getContext() == context ? sk_ref_sp(const_cast<SkImage*>(this)) : nullptr;
+ }
+
+ if (SkImageCacherator* cacher = as_IB(this)->peekCacherator()) {
+ GrImageTextureMaker maker(context, cacher, this, kDisallow_CachingHint);
+ return create_image_from_maker(&maker, this->alphaType(), this->uniqueID(), dstColorSpace);
+ }
+
+ if (const SkBitmap* bmp = as_IB(this)->onPeekBitmap()) {
+ GrBitmapTextureMaker maker(context, *bmp);
+ return create_image_from_maker(&maker, this->alphaType(), this->uniqueID(), dstColorSpace);
+ }
+ return nullptr;
+}
+
sk_sp<SkImage> SkImage::makeNonTextureImage() const {
if (!this->isTextureBacked()) {
return sk_ref_sp(const_cast<SkImage*>(this));
diff --git a/tests/DeviceTest.cpp b/tests/DeviceTest.cpp
index dd1a9f2379..55c9421dbb 100644
--- a/tests/DeviceTest.cpp
+++ b/tests/DeviceTest.cpp
@@ -106,8 +106,8 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SpecialImage_GPUDevice, reporter, ctxInfo) {
SkASSERT(SkIRect::MakeWH(kWidth, kHeight) == special->subset());
// Create a gpu-backed special image from a gpu-backed SkImage
- sk_sp<SkSurface> surface(SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, bm.info()));
- image = surface->makeImageSnapshot();
+ SkColorSpace* legacyColorSpace = nullptr;
+ image = image->makeTextureImage(context, legacyColorSpace);
special = DeviceTestingAccess::MakeSpecial(gpuDev.get(), image.get());
SkASSERT(special->isTextureBacked());
SkASSERT(kWidth == special->width());
diff --git a/tests/ImageTest.cpp b/tests/ImageTest.cpp
index 76ddd9600f..500efef0d6 100644
--- a/tests/ImageTest.cpp
+++ b/tests/ImageTest.cpp
@@ -457,6 +457,69 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(c, reporter, ctxInfo) {
}
}
+DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkImage_makeTextureImage, reporter, contextInfo) {
+ GrContext* context = contextInfo.grContext();
+ sk_gpu_test::TestContext* testContext = contextInfo.testContext();
+
+ GrContextFactory otherFactory;
+ GrContextFactory::ContextType otherContextType =
+ GrContextFactory::NativeContextTypeForBackend(testContext->backend());
+ ContextInfo otherContextInfo = otherFactory.getContextInfo(otherContextType);
+ testContext->makeCurrent();
+
+ std::function<sk_sp<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.
+ [testContext, otherContextInfo] {
+ otherContextInfo.testContext()->makeCurrent();
+ sk_sp<SkImage> otherContextImage = create_gpu_image(otherContextInfo.grContext());
+ testContext->makeCurrent();
+ return otherContextImage;
+ }
+ };
+
+ SkColorSpace* legacyColorSpace = nullptr;
+ for (auto factory : imageFactories) {
+ sk_sp<SkImage> image(factory());
+ if (!image) {
+ ERRORF(reporter, "Error creating image.");
+ continue;
+ }
+ GrTexture* origTexture = as_IB(image)->peekTexture();
+
+ sk_sp<SkImage> texImage(image->makeTextureImage(context, legacyColorSpace));
+ if (!texImage) {
+ // We execpt to fail if image comes from a different GrContext.
+ if (!origTexture || origTexture->getContext() == context) {
+ ERRORF(reporter, "makeTextureImage failed.");
+ }
+ continue;
+ }
+ GrTexture* copyTexture = as_IB(texImage)->peekTexture();
+ if (!copyTexture) {
+ ERRORF(reporter, "makeTextureImage returned non-texture image.");
+ continue;
+ }
+ if (origTexture) {
+ if (origTexture != copyTexture) {
+ ERRORF(reporter, "makeTextureImage made unnecessary texture copy.");
+ }
+ }
+ if (image->width() != texImage->width() || image->height() != texImage->height()) {
+ ERRORF(reporter, "makeTextureImage changed the image size.");
+ }
+ if (image->alphaType() != texImage->alphaType()) {
+ ERRORF(reporter, "makeTextureImage changed image alpha type.");
+ }
+ }
+}
+
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkImage_makeNonTextureImage, reporter, contextInfo) {
GrContext* context = contextInfo.grContext();
@@ -467,11 +530,14 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkImage_makeNonTextureImage, reporter, contex
create_picture_image,
[context] { return create_gpu_image(context); },
};
+ SkColorSpace* legacyColorSpace = nullptr;
for (auto factory : imageFactories) {
sk_sp<SkImage> image = factory();
if (!image->isTextureBacked()) {
REPORTER_ASSERT(reporter, image->makeNonTextureImage().get() == image.get());
- continue;
+ if (!(image = image->makeTextureImage(context, legacyColorSpace))) {
+ continue;
+ }
}
auto rasterImage = image->makeNonTextureImage();
if (!rasterImage) {