aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Brian Osman <brianosman@google.com>2017-11-07 10:37:00 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-11-07 15:59:38 +0000
commit63bc48d09323a62c8c67237fc66ad6ec7105e973 (patch)
tree465e2fafce0cdf0763de0aa28f3e42e283cf2deb
parent14efcbf3497e6a280cc141e6dec179b4ad4565af (diff)
Add MakeCrossContextFromPixmap
This operates just like MakeCrossContextFromEncoded, but starting from raster data. This version is defensive (always uses copies if a raster image needs to be made). Bug: skia: Change-Id: Ibc2b9a235c89a41fbbfd022d943f15ac212d0677 Reviewed-on: https://skia-review.googlesource.com/68205 Reviewed-by: Brian Salomon <bsalomon@google.com> Commit-Queue: Brian Osman <brianosman@google.com>
-rw-r--r--gm/crosscontextimage.cpp15
-rw-r--r--include/core/SkImage.h19
-rw-r--r--src/image/SkImage_Gpu.cpp35
-rw-r--r--tests/ImageTest.cpp37
4 files changed, 92 insertions, 14 deletions
diff --git a/gm/crosscontextimage.cpp b/gm/crosscontextimage.cpp
index cf973dbe61..ff56a280d9 100644
--- a/gm/crosscontextimage.cpp
+++ b/gm/crosscontextimage.cpp
@@ -12,7 +12,7 @@
#include "GrContext.h"
#include "SkImage.h"
-DEF_SIMPLE_GM(cross_context_image, canvas, 512 + 512 + 30, 512 + 128 + 30) {
+DEF_SIMPLE_GM(cross_context_image, canvas, 512 * 3 + 60, 512 + 128 + 30) {
GrContext* context = canvas->getGrContext();
if (!context) {
skiagm::GM::DrawGpuOnlyMessage(canvas);
@@ -25,15 +25,26 @@ DEF_SIMPLE_GM(cross_context_image, canvas, 512 + 512 + 30, 512 + 128 + 30) {
canvas->drawImage(encodedImage, 10, 10);
sk_sp<SkImage> crossContextImage = SkImage::MakeCrossContextFromEncoded(
- context, encodedData, false, canvas->imageInfo().colorSpace());
+ context, encodedData, false, canvas->imageInfo().colorSpace());
canvas->drawImage(crossContextImage, 512 + 30, 10);
+ SkBitmap bmp;
+ SkPixmap pixmap;
+ SkAssertResult(encodedImage->asLegacyBitmap(&bmp, SkImage::kRO_LegacyBitmapMode) &&
+ bmp.peekPixels(&pixmap));
+
+ sk_sp<SkImage> crossContextRaster = SkImage::MakeCrossContextFromPixmap(
+ context, pixmap, false, canvas->imageInfo().colorSpace());
+ canvas->drawImage(crossContextRaster, 512 + 512 + 60, 10);
+
SkIRect subset = SkIRect::MakeXYWH(256 - 64, 256 - 64, 128, 128);
sk_sp<SkImage> encodedSubset = encodedImage->makeSubset(subset);
sk_sp<SkImage> crossContextSubset = crossContextImage->makeSubset(subset);
+ sk_sp<SkImage> crossContextRasterSubset = crossContextRaster->makeSubset(subset);
canvas->drawImage(encodedSubset, 10, 512 + 30);
canvas->drawImage(crossContextSubset, 512 + 30, 512 + 30);
+ canvas->drawImage(crossContextRasterSubset, 512 + 512 + 60, 512 + 30);
}
#endif
diff --git a/include/core/SkImage.h b/include/core/SkImage.h
index 540f099dfe..1d725c237d 100644
--- a/include/core/SkImage.h
+++ b/include/core/SkImage.h
@@ -136,8 +136,23 @@ public:
* from the encoded data.
*/
static sk_sp<SkImage> MakeCrossContextFromEncoded(GrContext* context, sk_sp<SkData> data,
- bool buildMips,
- SkColorSpace* dstColorSpace);
+ bool buildMips, SkColorSpace* dstColorSpace);
+
+ /**
+ * Uploads the pixmap to a GPU backed image using the supplied GrContext.
+ * That image can be safely used by other GrContexts, across thread boundaries. The GrContext
+ * used here, and the ones used to draw this image later must be in the same GL share group,
+ * or otherwise be able to share resources.
+ *
+ * When the image's ref count reaches zero, the original GrContext will destroy the texture,
+ * asynchronously.
+ *
+ * The texture will be processed to be suitable for use with surfaces that have the
+ * supplied destination color space. The color space of the image itself will be determined
+ * from the pixmap.
+ */
+ static sk_sp<SkImage> MakeCrossContextFromPixmap(GrContext* context, const SkPixmap& pixmap,
+ bool buildMips, SkColorSpace* dstColorSpace);
/**
* Create a new image from the specified descriptor. Note - Skia will delete or recycle the
diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp
index d279188f44..b829f64694 100644
--- a/src/image/SkImage_Gpu.cpp
+++ b/src/image/SkImage_Gpu.cpp
@@ -508,6 +508,41 @@ sk_sp<SkImage> SkImage::MakeCrossContextFromEncoded(GrContext* context, sk_sp<Sk
return SkImage::MakeFromGenerator(std::move(gen));
}
+sk_sp<SkImage> SkImage::MakeCrossContextFromPixmap(GrContext* context, const SkPixmap& pixmap,
+ bool buildMips, SkColorSpace* dstColorSpace) {
+ // Some backends or drivers don't support (safely) moving resources between contexts
+ if (!context || !context->caps()->crossContextTextureSupport()) {
+ return SkImage::MakeRasterCopy(pixmap);
+ }
+
+ // Turn the pixmap into a GrTextureProxy
+ sk_sp<GrTextureProxy> proxy;
+ if (buildMips) {
+ SkBitmap bmp;
+ bmp.installPixels(pixmap);
+ proxy = GrGenerateMipMapsAndUploadToTextureProxy(context, bmp, dstColorSpace);
+ } else {
+ proxy = GrUploadPixmapToTextureProxy(context->resourceProvider(), pixmap, SkBudgeted::kYes,
+ dstColorSpace);
+ }
+
+ if (!proxy) {
+ return SkImage::MakeRasterCopy(pixmap);
+ }
+
+ sk_sp<GrTexture> texture = sk_ref_sp(proxy->priv().peekTexture());
+
+ // Flush any writes or uploads
+ context->contextPriv().prepareSurfaceForExternalIO(proxy.get());
+
+ sk_sp<GrSemaphore> sema = context->getGpu()->prepareTextureForCrossContextUsage(texture.get());
+
+ auto gen = GrBackendTextureImageGenerator::Make(std::move(texture), proxy->origin(),
+ std::move(sema), pixmap.alphaType(),
+ pixmap.info().refColorSpace());
+ return SkImage::MakeFromGenerator(std::move(gen));
+}
+
#if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26
sk_sp<SkImage> SkImage::MakeFromAHardwareBuffer(AHardwareBuffer* graphicBuffer, SkAlphaType at,
sk_sp<SkColorSpace> cs) {
diff --git a/tests/ImageTest.cpp b/tests/ImageTest.cpp
index 8eecbbd0a5..49ef86847d 100644
--- a/tests/ImageTest.cpp
+++ b/tests/ImageTest.cpp
@@ -810,12 +810,10 @@ DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(SkImage_NewFromTextureRelease, reporter, c
ctxInfo.grContext()->getGpu()->deleteTestingOnlyBackendTexture(backendTexHandle);
}
-DEF_GPUTEST(SkImage_MakeCrossContextRelease, reporter, /*factory*/) {
+static void test_cross_context_image(skiatest::Reporter* reporter,
+ std::function<sk_sp<SkImage>(GrContext*)> imageMaker) {
GrContextFactory testFactory;
- sk_sp<SkData> data = GetResourceAsData("mandrill_128.png");
- SkASSERT(data.get());
-
for (int i = 0; i < GrContextFactory::kContextTypeCnt; ++i) {
GrContextFactory::ContextType ctxType = static_cast<GrContextFactory::ContextType>(i);
ContextInfo ctxInfo = testFactory.getContextInfo(ctxType);
@@ -841,7 +839,7 @@ DEF_GPUTEST(SkImage_MakeCrossContextRelease, reporter, /*factory*/) {
// Case #1: Create image, free image
{
- sk_sp<SkImage> refImg(SkImage::MakeCrossContextFromEncoded(ctx, data, false, nullptr));
+ sk_sp<SkImage> refImg(imageMaker(ctx));
refImg.reset(nullptr); // force a release of the image
}
@@ -851,7 +849,7 @@ DEF_GPUTEST(SkImage_MakeCrossContextRelease, reporter, /*factory*/) {
// Case #2: Create image, draw, flush, free image
{
- sk_sp<SkImage> refImg(SkImage::MakeCrossContextFromEncoded(ctx, data, false, nullptr));
+ sk_sp<SkImage> refImg(imageMaker(ctx));
canvas->drawImage(refImg, 0, 0);
canvas->flush();
@@ -861,7 +859,7 @@ DEF_GPUTEST(SkImage_MakeCrossContextRelease, reporter, /*factory*/) {
// Case #3: Create image, draw, free image, flush
{
- sk_sp<SkImage> refImg(SkImage::MakeCrossContextFromEncoded(ctx, data, false, nullptr));
+ sk_sp<SkImage> refImg(imageMaker(ctx));
canvas->drawImage(refImg, 0, 0);
refImg.reset(nullptr); // force a release of the image
@@ -887,7 +885,7 @@ DEF_GPUTEST(SkImage_MakeCrossContextRelease, reporter, /*factory*/) {
// Case #4: Create image, draw*, flush*, free image
{
testContext->makeCurrent();
- sk_sp<SkImage> refImg(SkImage::MakeCrossContextFromEncoded(ctx, data, false, nullptr));
+ sk_sp<SkImage> refImg(imageMaker(ctx));
otherTestContext->makeCurrent();
canvas->drawImage(refImg, 0, 0);
@@ -900,7 +898,7 @@ DEF_GPUTEST(SkImage_MakeCrossContextRelease, reporter, /*factory*/) {
// Case #5: Create image, draw*, free image, flush*
{
testContext->makeCurrent();
- sk_sp<SkImage> refImg(SkImage::MakeCrossContextFromEncoded(ctx, data, false, nullptr));
+ sk_sp<SkImage> refImg(imageMaker(ctx));
otherTestContext->makeCurrent();
canvas->drawImage(refImg, 0, 0);
@@ -923,7 +921,7 @@ DEF_GPUTEST(SkImage_MakeCrossContextRelease, reporter, /*factory*/) {
// Case #6: Verify that only one context can be using the image at a time
{
testContext->makeCurrent();
- sk_sp<SkImage> refImg(SkImage::MakeCrossContextFromEncoded(ctx, data, false, nullptr));
+ sk_sp<SkImage> refImg(imageMaker(ctx));
// Any context should be able to borrow the texture at this point
sk_sp<SkColorSpace> texColorSpace;
@@ -960,6 +958,25 @@ DEF_GPUTEST(SkImage_MakeCrossContextRelease, reporter, /*factory*/) {
}
}
+DEF_GPUTEST(SkImage_MakeCrossContextFromEncodedRelease, reporter, /*factory*/) {
+ sk_sp<SkData> data = GetResourceAsData("mandrill_128.png");
+ SkASSERT(data.get());
+
+ test_cross_context_image(reporter, [&data](GrContext* ctx) {
+ return SkImage::MakeCrossContextFromEncoded(ctx, data, false, nullptr);
+ });
+}
+
+DEF_GPUTEST(SkImage_MakeCrossContextFromPixmapRelease, reporter, /*factory*/) {
+ SkBitmap bitmap;
+ SkPixmap pixmap;
+ SkAssertResult(GetResourceAsBitmap("mandrill_128.png", &bitmap) && bitmap.peekPixels(&pixmap));
+
+ test_cross_context_image(reporter, [&pixmap](GrContext* ctx) {
+ return SkImage::MakeCrossContextFromPixmap(ctx, pixmap, false, nullptr);
+ });
+}
+
static void check_images_same(skiatest::Reporter* reporter, const SkImage* a, const SkImage* b) {
if (a->width() != b->width() || a->height() != b->height()) {
ERRORF(reporter, "Images must have the same size");