From 57263c2e0ccddf4dd62814c427a39d9d615acbe5 Mon Sep 17 00:00:00 2001 From: Jim Van Verth Date: Thu, 17 Jan 2019 15:52:33 -0500 Subject: [PATCH] Add compressed data support for SkImage. Adds a new SkImage::MakeFromCompressed method which takes raw data, a size, and a compression method, and returns a GPU-backed image. Bug: skia:8684 Change-Id: I570c9dafce283bcd64dfbef4fbe1c4bfeac6ce2a Reviewed-on: https://skia-review.googlesource.com/c/184484 Commit-Queue: Jim Van Verth Reviewed-by: Brian Salomon Reviewed-by: Robert Phillips --- gm/etc1.cpp | 46 ++++++++----------------------------- include/core/SkImage.h | 19 +++++++++++++++ src/gpu/GrProxyProvider.cpp | 36 +++++++++++++++++++++++++++++ src/gpu/GrProxyProvider.h | 5 ++++ src/image/SkImage_Gpu.cpp | 28 ++++++++++++++++++++++ 5 files changed, 97 insertions(+), 37 deletions(-) diff --git a/gm/etc1.cpp b/gm/etc1.cpp index a384b12446..f8432db309 100644 --- a/gm/etc1.cpp +++ b/gm/etc1.cpp @@ -7,6 +7,7 @@ #include "gm.h" #include "sk_tool_utils.h" +#include "SkImage.h" #include "SkRandom.h" #if SK_SUPPORT_GPU && !defined(SK_BUILD_FOR_GOOGLE3) @@ -51,13 +52,13 @@ protected: } int size = etc1_get_encoded_data_size(bm.width(), bm.height()); - fETC1Data.reset(size); + fETC1Data = SkData::MakeUninitialized(size); - unsigned char* pixels = (unsigned char*) fETC1Data.get(); + unsigned char* pixels = (unsigned char*) fETC1Data->writable_data(); if (etc1_encode_image((unsigned char*) bm.getAddr16(0, 0), bm.width(), bm.height(), 2, bm.rowBytes(), pixels)) { - fETC1Data.reset(); + fETC1Data = nullptr; } } @@ -74,40 +75,11 @@ protected: return; } - GrBackendTexture tex = context->contextPriv().getGpu()->createTestingOnlyBackendTexture( - fETC1Data.get(), - kTexWidth, - kTexHeight, - GrColorType::kRGB_ETC1, - false, - GrMipMapped::kNo, - kTexWidth/2); // rowbytes are meaningless for compressed textures, but this is - // basically right + sk_sp image = SkImage::MakeFromCompressed(context, fETC1Data, + kTexWidth, kTexHeight, + SkImage::kETC1_CompressionType); - if (!tex.isValid()) { - return; - } - - auto proxy = context->contextPriv().proxyProvider()->wrapBackendTexture( - tex, kTopLeft_GrSurfaceOrigin, - kAdopt_GrWrapOwnership, - kRead_GrIOType); - if (!proxy) { - return; - } - - const SkMatrix trans = SkMatrix::MakeTrans(-kPad, -kPad); - - auto fp = GrSimpleTextureEffect::Make(proxy, trans); - - GrPaint grPaint; - grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc)); - grPaint.addColorFragmentProcessor(std::move(fp)); - - SkRect rect = SkRect::MakeXYWH(kPad, kPad, kTexWidth, kTexHeight); - - renderTargetContext->priv().testingOnly_addDrawOp( - GrFillRectOp::Make(context, std::move(grPaint), GrAAType::kNone, SkMatrix::I(), rect)); + canvas->drawImage(image, 0, 0); } private: @@ -115,7 +87,7 @@ private: static const int kTexWidth = 16; static const int kTexHeight = 20; - SkAutoTMalloc fETC1Data; + sk_sp fETC1Data; typedef GM INHERITED; }; diff --git a/include/core/SkImage.h b/include/core/SkImage.h index 764447f39b..c83769ccf7 100644 --- a/include/core/SkImage.h +++ b/include/core/SkImage.h @@ -176,6 +176,25 @@ public: */ static sk_sp MakeFromEncoded(sk_sp encoded, const SkIRect* subset = nullptr); + enum CompressionType { + kETC1_CompressionType, //!< compressed data uses ETC1 compression + }; + + /** Creates a GPU-backed SkImage from compressed data. + + SkImage is returned if format of the compressed data is supported. + Supported formats vary by platform. + + @param context GPU context + @param data compressed data to store in SkImage + @param width width of full SkImage + @param height height of full SkImage + @param type type of compression used + @return created SkImage, or nullptr + */ + static sk_sp MakeFromCompressed(GrContext* context, sk_sp data, + int width, int height, CompressionType type); + /** User function called when supplied texture may be deleted. */ typedef void (*TextureReleaseProc)(ReleaseContext releaseContext); diff --git a/src/gpu/GrProxyProvider.cpp b/src/gpu/GrProxyProvider.cpp index 657d607a5b..3aa6262095 100644 --- a/src/gpu/GrProxyProvider.cpp +++ b/src/gpu/GrProxyProvider.cpp @@ -412,6 +412,42 @@ sk_sp GrProxyProvider::createProxy(const GrBackendFormat& format fit, budgeted, surfaceFlags)); } +sk_sp GrProxyProvider::createProxy(sk_sp data, const GrSurfaceDesc& desc) { + if (!this->caps()->isConfigTexturable(desc.fConfig)) { + return nullptr; + } + + const GrColorType ct = GrPixelConfigToColorType(desc.fConfig); + const GrBackendFormat format = fCaps->getBackendFormatFromGrColorType(ct, GrSRGBEncoded::kNo); + + sk_sp proxy = this->createLazyProxy( + [desc, data](GrResourceProvider* resourceProvider) { + if (!resourceProvider) { + return sk_sp(); + } + + GrMipLevel texels; + texels.fPixels = data->data(); + texels.fRowBytes = GrBytesPerPixel(desc.fConfig)*desc.fWidth; + return resourceProvider->createTexture(desc, SkBudgeted::kYes, &texels, 1); + }, + format, desc, kTopLeft_GrSurfaceOrigin, GrMipMapped::kNo, SkBackingFit::kExact, + SkBudgeted::kYes); + + if (!proxy) { + return nullptr; + } + + if (fResourceProvider) { + // In order to reuse code we always create a lazy proxy. When we aren't in DDL mode however + // we're better off instantiating the proxy immediately here. + if (!proxy->priv().doLazyInstantiation(fResourceProvider)) { + return nullptr; + } + } + return proxy; +} + sk_sp GrProxyProvider::wrapBackendTexture(const GrBackendTexture& backendTex, GrSurfaceOrigin origin, GrWrapOwnership ownership, diff --git a/src/gpu/GrProxyProvider.h b/src/gpu/GrProxyProvider.h index 8e8c2e015e..1abb49fd3c 100644 --- a/src/gpu/GrProxyProvider.h +++ b/src/gpu/GrProxyProvider.h @@ -99,6 +99,11 @@ public: surfaceFlags); } + /* + * Create a texture proxy with data. It's assumed that the data is packed tightly. + */ + sk_sp createProxy(sk_sp, const GrSurfaceDesc& desc); + // These match the definitions in SkImage & GrTexture.h, for whence they came typedef void* ReleaseContext; typedef void (*ReleaseProc)(ReleaseContext); diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp index 5bec1cdd53..a2a203ef6d 100644 --- a/src/image/SkImage_Gpu.cpp +++ b/src/image/SkImage_Gpu.cpp @@ -153,6 +153,34 @@ sk_sp SkImage::MakeFromAdoptedTexture(GrContext* ctx, kAdopt_GrWrapOwnership, nullptr, nullptr); } +sk_sp SkImage::MakeFromCompressed(GrContext* context, sk_sp data, + int width, int height, CompressionType type) { + // create the backing texture + GrSurfaceDesc desc; + desc.fFlags = kNone_GrSurfaceFlags; + desc.fWidth = width; + desc.fHeight = height; + switch (type) { + case kETC1_CompressionType: + desc.fConfig = kRGB_ETC1_GrPixelConfig; + break; + default: + desc.fConfig = kUnknown_GrPixelConfig; + break; + } + desc.fSampleCnt = 1; + + GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider(); + sk_sp proxy = proxyProvider->createProxy(std::move(data), desc); + + if (!proxy) { + return nullptr; + } + + return sk_make_sp(sk_ref_sp(context), kNeedNewImageUniqueID, kOpaque_SkAlphaType, + std::move(proxy), nullptr); +} + sk_sp SkImage_Gpu::ConvertYUVATexturesToRGB(GrContext* ctx, SkYUVColorSpace yuvColorSpace, const GrBackendTexture yuvaTextures[], const SkYUVAIndex yuvaIndices[4], SkISize size,