diff --git a/docs/SkImage_Reference.bmh b/docs/SkImage_Reference.bmh index 97538cd5a7..7a0bc330e6 100644 --- a/docs/SkImage_Reference.bmh +++ b/docs/SkImage_Reference.bmh @@ -462,6 +462,27 @@ if (source.peekPixels(&pixmap)) { #Method ## +#Method static sk_sp MakeFromYUVAPixmaps( + GrContext* context, + SkYUVColorSpace yuvColorSpace, + const SkPixmap yuvaPixmaps[], + const SkYUVAIndex yuvaIndices[4], + SkISize imageSize, + GrSurfaceOrigin imageOrigin, + bool buildMips, + bool limitToMaxTextureSize = false, + sk_sp imageColorSpace = nullptr); + +#In Constructor +#Line # creates Image from YUV_ColorSpace data ## +#Populate + +#NoExample +## + +#SeeAlso MakeFromYUVATextures + +#Method ## # ------------------------------------------------------------------------------ diff --git a/gm/wacky_yuv_formats.cpp b/gm/wacky_yuv_formats.cpp index 8ea25c0bc1..00c2fe10cd 100644 --- a/gm/wacky_yuv_formats.cpp +++ b/gm/wacky_yuv_formats.cpp @@ -743,6 +743,7 @@ protected: } GrBackendTexture yuvaTextures[4]; + SkPixmap yuvaPixmaps[4]; for (int i = 0; i < 4; ++i) { if (!used[i]) { @@ -757,9 +758,12 @@ protected: false, GrMipMapped::kNo, resultBMs[i].rowBytes()); + yuvaPixmaps[i] = resultBMs[i].pixmap(); } - if (counter & 0x1) { + int counterMod = counter % 3; + switch (counterMod) { + case 0: fImages[opaque][cs][format] = SkImage::MakeFromYUVATexturesCopy( context, (SkYUVColorSpace)cs, @@ -767,7 +771,8 @@ protected: yuvaIndices, { fOriginalBMs[opaque].width(), fOriginalBMs[opaque].height() }, kTopLeft_GrSurfaceOrigin); - } else { + break; + case 1: fImages[opaque][cs][format] = SkImage::MakeFromYUVATextures( context, (SkYUVColorSpace)cs, @@ -775,7 +780,19 @@ protected: yuvaIndices, { fOriginalBMs[opaque].width(), fOriginalBMs[opaque].height() }, kTopLeft_GrSurfaceOrigin); + break; + case 2: + default: + fImages[opaque][cs][format] = SkImage::MakeFromYUVAPixmaps( + context, + (SkYUVColorSpace)cs, + yuvaPixmaps, + yuvaIndices, + { fOriginalBMs[opaque].width(), fOriginalBMs[opaque].height() }, + kTopLeft_GrSurfaceOrigin, true); + break; } + ++counter; } else { fImages[opaque][cs][format] = make_yuv_gen_image( fOriginalBMs[opaque].info(), @@ -785,7 +802,6 @@ protected: } } } - ++counter; } } diff --git a/include/core/SkImage.h b/include/core/SkImage.h index 79067af119..9b97884d42 100644 --- a/include/core/SkImage.h +++ b/include/core/SkImage.h @@ -357,31 +357,6 @@ public: GrSurfaceOrigin imageOrigin, sk_sp imageColorSpace = nullptr); - /** Creates an SkImage by storing the specified YUVA planes into an image, to be rendered - via multitexturing. - - @param context GPU context - @param yuvColorSpace How the YUV values are converted to RGB. One of: - kJPEG_SkYUVColorSpace, kRec601_SkYUVColorSpace, - kRec709_SkYUVColorSpace - @param yuvaTextures array of (up to four) YUVA textures on GPU which contain the, - possibly interleaved, YUVA planes - @param yuvaIndices array indicating which texture in yuvaTextures, and channel - in that texture, maps to each component of YUVA. - @param imageSize size of the resulting image - @param imageOrigin origin of the resulting image. One of: kBottomLeft_GrSurfaceOrigin, - kTopLeft_GrSurfaceOrigin - @param imageColorSpace range of colors of the resulting image; may be nullptr - @return created SkImage, or nullptr - */ - static sk_sp MakeFromYUVATextures(GrContext* context, - SkYUVColorSpace yuvColorSpace, - const GrBackendTexture yuvaTextures[], - const SkYUVAIndex yuvaIndices[4], - SkISize imageSize, - GrSurfaceOrigin imageOrigin, - sk_sp imageColorSpace = nullptr); - /** Creates an SkImage by flattening the specified YUVA planes into a single, interleaved RGBA image. 'backendTexture' is used to store the result of the flattening. @@ -410,36 +385,71 @@ public: const GrBackendTexture& backendTexture, sk_sp imageColorSpace = nullptr); - /** Creates SkImage from copy of yuvTextures, an array of textures on GPU. - yuvTextures contain pixels for YUV planes of SkImage. Returned SkImage has the dimensions - yuvTextures[0]. yuvColorSpace describes how YUV colors convert to RGB colors. + /** Creates an SkImage by storing the specified YUVA planes into an image, to be rendered + via multitexturing. @param context GPU context - @param yuvColorSpace one of: kJPEG_SkYUVColorSpace, kRec601_SkYUVColorSpace, - kRec709_SkYUVColorSpace - @param yuvTextures array of YUV textures on GPU - @param imageOrigin one of: kBottomLeft_GrSurfaceOrigin, kTopLeft_GrSurfaceOrigin - @param imageColorSpace range of colors; may be nullptr + @param yuvColorSpace How the YUV values are converted to RGB. One of: + kJPEG_SkYUVColorSpace, kRec601_SkYUVColorSpace, + kRec709_SkYUVColorSpace + @param yuvaTextures array of (up to four) YUVA textures on GPU which contain the, + possibly interleaved, YUVA planes + @param yuvaIndices array indicating which texture in yuvaTextures, and channel + in that texture, maps to each component of YUVA. + @param imageSize size of the resulting image + @param imageOrigin origin of the resulting image. One of: kBottomLeft_GrSurfaceOrigin, + kTopLeft_GrSurfaceOrigin + @param imageColorSpace range of colors of the resulting image; may be nullptr @return created SkImage, or nullptr */ + static sk_sp MakeFromYUVATextures(GrContext* context, + SkYUVColorSpace yuvColorSpace, + const GrBackendTexture yuvaTextures[], + const SkYUVAIndex yuvaIndices[4], + SkISize imageSize, + GrSurfaceOrigin imageOrigin, + sk_sp imageColorSpace = nullptr); + + /** Creates SkImage from pixmap array representing YUVA data. + SkImage is uploaded to GPU back-end using context. + + Each GrBackendTexture created from yuvaPixmaps array is uploaded to match SkSurface + using SkColorSpace of SkPixmap. SkColorSpace of SkImage is determined by imageColorSpace. + + SkImage is returned referring to GPU back-end if context is not nullptr and + format of data is recognized and supported. Otherwise, nullptr is returned. + Recognized GPU formats vary by platform and GPU back-end. + + @param context GPU context + @param yuvColorSpace How the YUV values are converted to RGB. One of: + kJPEG_SkYUVColorSpace, kRec601_SkYUVColorSpace, + kRec709_SkYUVColorSpace + @param yuvaPixmaps array of (up to four) SkPixmap which contain the, + possibly interleaved, YUVA planes + @param yuvaIndices array indicating which pixmap in yuvaPixmaps, and channel + in that pixmap, maps to each component of YUVA. + @param imageSize size of the resulting image + @param imageOrigin origin of the resulting image. One of: + kBottomLeft_GrSurfaceOrigin, kTopLeft_GrSurfaceOrigin + @param buildMips create internal YUVA textures as mip map if true + @param limitToMaxTextureSize downscale image to GPU maximum texture size, if necessary + @param imageColorSpace range of colors of the resulting image; may be nullptr + @return created SkImage, or nullptr + */ + static sk_sp MakeFromYUVAPixmaps( + GrContext* context, SkYUVColorSpace yuvColorSpace, const SkPixmap yuvaPixmaps[], + const SkYUVAIndex yuvaIndices[4], SkISize imageSize, GrSurfaceOrigin imageOrigin, + bool buildMips, bool limitToMaxTextureSize = false, + sk_sp imageColorSpace = nullptr); + + /** To be deprecated. + */ static sk_sp MakeFromYUVTexturesCopy(GrContext* context, SkYUVColorSpace yuvColorSpace, const GrBackendTexture yuvTextures[3], GrSurfaceOrigin imageOrigin, sk_sp imageColorSpace = nullptr); - /** Creates SkImage from copy of yuvTextures, an array of textures on GPU. - yuvTextures contain pixels for YUV planes of SkImage. Returned SkImage has the dimensions - yuvTextures[0] and stores pixels in backendTexture. yuvColorSpace describes how YUV colors - convert to RGB colors. - - @param context GPU context - @param yuvColorSpace one of: kJPEG_SkYUVColorSpace, kRec601_SkYUVColorSpace, - kRec709_SkYUVColorSpace - @param yuvTextures array of YUV textures on GPU - @param imageOrigin one of: kBottomLeft_GrSurfaceOrigin, kTopLeft_GrSurfaceOrigin - @param backendTexture the resource that stores the final pixels - @param imageColorSpace range of colors; may be nullptr - @return created SkImage, or nullptr + /** To be deprecated. */ static sk_sp MakeFromYUVTexturesCopyWithExternalBackend( GrContext* context, SkYUVColorSpace yuvColorSpace, diff --git a/src/image/SkImage_Gpu.h b/src/image/SkImage_Gpu.h index 7da0ca4594..e184e177ff 100644 --- a/src/image/SkImage_Gpu.h +++ b/src/image/SkImage_Gpu.h @@ -94,6 +94,8 @@ public: PromiseDoneProc promiseDoneProc, TextureContext textureContext); + /** To be deprecated. Use SkImage_GpuYUVA::MakePromiseYUVATexture instead. + */ static sk_sp MakePromiseYUVATexture(GrContext* context, SkYUVColorSpace yuvColorSpace, const GrBackendFormat yuvaFormats[], diff --git a/src/image/SkImage_GpuYUVA.cpp b/src/image/SkImage_GpuYUVA.cpp index a1d06964d5..3113c1cce3 100644 --- a/src/image/SkImage_GpuYUVA.cpp +++ b/src/image/SkImage_GpuYUVA.cpp @@ -16,6 +16,7 @@ #include "GrRenderTargetContext.h" #include "GrTexture.h" #include "GrTextureProducer.h" +#include "SkAutoPixmapStorage.h" #include "SkGr.h" #include "SkImage_Gpu.h" #include "SkImage_GpuYUVA.h" @@ -144,6 +145,68 @@ sk_sp SkImage::MakeFromYUVATextures(GrContext* ctx, numTextures, yuvaIndices, imageOrigin, imageColorSpace, SkBudgeted::kYes); } + +sk_sp SkImage::MakeFromYUVAPixmaps( + GrContext* context, SkYUVColorSpace yuvColorSpace, const SkPixmap yuvaPixmaps[], + const SkYUVAIndex yuvaIndices[4], SkISize imageSize, GrSurfaceOrigin imageOrigin, + bool buildMips, bool limitToMaxTextureSize, sk_sp imageColorSpace) { + int numPixmaps; + if (!SkYUVAIndex::AreValidIndices(yuvaIndices, &numPixmaps)) { + return nullptr; + } + + // Make proxies + GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider(); + sk_sp tempTextureProxies[4]; + for (int i = 0; i < numPixmaps; ++i) { + const SkPixmap* pixmap = &yuvaPixmaps[i]; + SkAutoPixmapStorage resized; + int maxTextureSize = context->contextPriv().caps()->maxTextureSize(); + int maxDim = SkTMax(yuvaPixmaps[i].width(), yuvaPixmaps[i].height()); + if (limitToMaxTextureSize && maxDim > maxTextureSize) { + float scale = static_cast(maxTextureSize) / maxDim; + int newWidth = SkTMin(static_cast(yuvaPixmaps[i].width() * scale), + maxTextureSize); + int newHeight = SkTMin(static_cast(yuvaPixmaps[i].height() * scale), + maxTextureSize); + SkImageInfo info = yuvaPixmaps[i].info().makeWH(newWidth, newHeight); + if (!resized.tryAlloc(info) || + !yuvaPixmaps[i].scalePixels(resized, kLow_SkFilterQuality)) { + return nullptr; + } + pixmap = &resized; + } + // Turn the pixmap into a GrTextureProxy + if (buildMips) { + SkBitmap bmp; + bmp.installPixels(*pixmap); + tempTextureProxies[i] = proxyProvider->createMipMapProxyFromBitmap(bmp); + } else { + if (SkImageInfoIsValid(pixmap->info())) { + ATRACE_ANDROID_FRAMEWORK("Upload Texture [%ux%u]", + pixmap->width(), pixmap->height()); + // We don't need a release proc on the data in pixmap since we know we are in a + // GrContext that has a resource provider. Thus the createTextureProxy call will + // immediately upload the data. + sk_sp image = SkImage::MakeFromRaster(*pixmap, nullptr, nullptr); + tempTextureProxies[i] = + proxyProvider->createTextureProxy(std::move(image), kNone_GrSurfaceFlags, 1, + SkBudgeted::kYes, SkBackingFit::kExact); + } + } + + if (!tempTextureProxies[i]) { + return nullptr; + } + } + + return sk_make_sp(sk_ref_sp(context), imageSize.width(), imageSize.height(), + kNeedNewImageUniqueID, yuvColorSpace, tempTextureProxies, + numPixmaps, yuvaIndices, imageOrigin, imageColorSpace, + SkBudgeted::kYes); +} + + ///////////////////////////////////////////////////////////////////////////////////////////////// sk_sp SkImage_GpuYUVA::MakePromiseYUVATexture(GrContext* context, SkYUVColorSpace yuvColorSpace,