diff options
author | Brian Osman <brianosman@google.com> | 2017-11-07 10:37:00 -0500 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-11-07 15:59:38 +0000 |
commit | 63bc48d09323a62c8c67237fc66ad6ec7105e973 (patch) | |
tree | 465e2fafce0cdf0763de0aa28f3e42e283cf2deb | |
parent | 14efcbf3497e6a280cc141e6dec179b4ad4565af (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.cpp | 15 | ||||
-rw-r--r-- | include/core/SkImage.h | 19 | ||||
-rw-r--r-- | src/image/SkImage_Gpu.cpp | 35 | ||||
-rw-r--r-- | tests/ImageTest.cpp | 37 |
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"); |