| Index: src/gpu/SkGr.cpp
|
| diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
|
| index 29c4572859bee151cbf588838ee6d4e369c1a094..a1821c32c3085d998dfe831c9133b261cd53e83a 100644
|
| --- a/src/gpu/SkGr.cpp
|
| +++ b/src/gpu/SkGr.cpp
|
| @@ -10,6 +10,8 @@
|
| #include "GrCaps.h"
|
| #include "GrDrawContext.h"
|
| #include "GrXferProcessor.h"
|
| +#include "GrYUVProvider.h"
|
| +
|
| #include "SkColorFilter.h"
|
| #include "SkConfig8888.h"
|
| #include "SkCanvas.h"
|
| @@ -237,16 +239,18 @@ private:
|
| } // namespace
|
|
|
|
|
| -static GrTexture* create_texture_for_bmp(GrContext* ctx,
|
| - const GrUniqueKey& optionalKey,
|
| - GrSurfaceDesc desc,
|
| - SkPixelRef* pixelRefForInvalidationNotification,
|
| - const void* pixels,
|
| - size_t rowBytes) {
|
| +GrTexture* GrCreateTextureForPixels(GrContext* ctx,
|
| + const GrUniqueKey& optionalKey,
|
| + GrSurfaceDesc desc,
|
| + SkPixelRef* pixelRefForInvalidationNotification,
|
| + const void* pixels,
|
| + size_t rowBytes) {
|
| GrTexture* result = ctx->textureProvider()->createTexture(desc, true, pixels, rowBytes);
|
| if (result && optionalKey.isValid()) {
|
| - BitmapInvalidator* listener = new BitmapInvalidator(optionalKey);
|
| - pixelRefForInvalidationNotification->addGenIDChangeListener(listener);
|
| + if (pixelRefForInvalidationNotification) {
|
| + BitmapInvalidator* listener = new BitmapInvalidator(optionalKey);
|
| + pixelRefForInvalidationNotification->addGenIDChangeListener(listener);
|
| + }
|
| ctx->textureProvider()->assignUniqueKeyToTexture(optionalKey, result);
|
| }
|
| return result;
|
| @@ -294,8 +298,8 @@ GrTexture* stretch_texture(GrTexture* inputTexture, const Stretch& stretch,
|
| }
|
| }
|
|
|
| - GrTexture* stretched = create_texture_for_bmp(context, optionalKey, rtDesc, pixelRef, nullptr, 0);
|
| -
|
| + SkAutoTUnref<GrTexture> stretched(GrCreateTextureForPixels(context, optionalKey, rtDesc,
|
| + pixelRef, nullptr,0));
|
| if (!stretched) {
|
| return nullptr;
|
| }
|
| @@ -320,167 +324,111 @@ GrTexture* stretch_texture(GrTexture* inputTexture, const Stretch& stretch,
|
| drawContext->drawNonAARectToRect(stretched->asRenderTarget(), GrClip::WideOpen(), paint,
|
| SkMatrix::I(), rect, localRect);
|
|
|
| - return stretched;
|
| + return stretched.detach();
|
| }
|
|
|
| +GrPixelConfig GrIsCompressedTextureDataSupported(GrContext* ctx, SkData* data,
|
| + int expectedW, int expectedH,
|
| + const void** outStartOfDataToUpload) {
|
| + *outStartOfDataToUpload = nullptr;
|
| #ifndef SK_IGNORE_ETC1_SUPPORT
|
| -static GrTexture *load_etc1_texture(GrContext* ctx, const GrUniqueKey& optionalKey,
|
| - const SkBitmap &bm, GrSurfaceDesc desc) {
|
| - SkAutoTUnref<SkData> data(bm.pixelRef()->refEncodedData());
|
| -
|
| - // Is this even encoded data?
|
| - if (nullptr == data) {
|
| - return nullptr;
|
| + if (!ctx->caps()->isConfigTexturable(kETC1_GrPixelConfig)) {
|
| + return kUnknown_GrPixelConfig;
|
| }
|
|
|
| - // Is this a valid PKM encoded data?
|
| - const uint8_t *bytes = data->bytes();
|
| - if (etc1_pkm_is_valid(bytes)) {
|
| - uint32_t encodedWidth = etc1_pkm_get_width(bytes);
|
| - uint32_t encodedHeight = etc1_pkm_get_height(bytes);
|
| -
|
| + const uint8_t* bytes = data->bytes();
|
| + if (data->size() > ETC_PKM_HEADER_SIZE && etc1_pkm_is_valid(bytes)) {
|
| // Does the data match the dimensions of the bitmap? If not,
|
| // then we don't know how to scale the image to match it...
|
| - if (encodedWidth != static_cast<uint32_t>(bm.width()) ||
|
| - encodedHeight != static_cast<uint32_t>(bm.height())) {
|
| - return nullptr;
|
| + if (etc1_pkm_get_width(bytes) != (unsigned)expectedW ||
|
| + etc1_pkm_get_height(bytes) != (unsigned)expectedH)
|
| + {
|
| + return kUnknown_GrPixelConfig;
|
| }
|
|
|
| - // Everything seems good... skip ahead to the data.
|
| - bytes += ETC_PKM_HEADER_SIZE;
|
| - desc.fConfig = kETC1_GrPixelConfig;
|
| + *outStartOfDataToUpload = bytes + ETC_PKM_HEADER_SIZE;
|
| + return kETC1_GrPixelConfig;
|
| } else if (SkKTXFile::is_ktx(bytes)) {
|
| SkKTXFile ktx(data);
|
|
|
| // Is it actually an ETC1 texture?
|
| if (!ktx.isCompressedFormat(SkTextureCompressor::kETC1_Format)) {
|
| - return nullptr;
|
| + return kUnknown_GrPixelConfig;
|
| }
|
|
|
| // Does the data match the dimensions of the bitmap? If not,
|
| // then we don't know how to scale the image to match it...
|
| - if (ktx.width() != bm.width() || ktx.height() != bm.height()) {
|
| - return nullptr;
|
| + if (ktx.width() != expectedW || ktx.height() != expectedH) {
|
| + return kUnknown_GrPixelConfig;
|
| }
|
|
|
| - bytes = ktx.pixelData();
|
| - desc.fConfig = kETC1_GrPixelConfig;
|
| - } else {
|
| - return nullptr;
|
| + *outStartOfDataToUpload = ktx.pixelData();
|
| + return kETC1_GrPixelConfig;
|
| }
|
| -
|
| - return create_texture_for_bmp(ctx, optionalKey, desc, bm.pixelRef(), bytes, 0);
|
| +#endif
|
| + return kUnknown_GrPixelConfig;
|
| }
|
| -#endif // SK_IGNORE_ETC1_SUPPORT
|
|
|
| -static GrTexture* load_yuv_texture(GrContext* ctx, const GrUniqueKey& optionalKey,
|
| - const SkBitmap& bm, const GrSurfaceDesc& desc) {
|
| - // Subsets are not supported, the whole pixelRef is loaded when using YUV decoding
|
| - SkPixelRef* pixelRef = bm.pixelRef();
|
| - if ((nullptr == pixelRef) ||
|
| - (pixelRef->info().width() != bm.info().width()) ||
|
| - (pixelRef->info().height() != bm.info().height())) {
|
| +static GrTexture* load_etc1_texture(GrContext* ctx, const GrUniqueKey& optionalKey,
|
| + const SkBitmap &bm, GrSurfaceDesc desc) {
|
| + SkAutoTUnref<SkData> data(bm.pixelRef()->refEncodedData());
|
| + if (!data) {
|
| return nullptr;
|
| }
|
|
|
| - const bool useCache = optionalKey.isValid();
|
| - SkYUVPlanesCache::Info yuvInfo;
|
| - SkAutoTUnref<SkCachedData> cachedData;
|
| - SkAutoMalloc storage;
|
| - if (useCache) {
|
| - cachedData.reset(SkYUVPlanesCache::FindAndRef(pixelRef->getGenerationID(), &yuvInfo));
|
| + const void* startOfTexData;
|
| + desc.fConfig = GrIsCompressedTextureDataSupported(ctx, data, bm.width(), bm.height(),
|
| + &startOfTexData);
|
| + if (kUnknown_GrPixelConfig == desc.fConfig) {
|
| + return nullptr;
|
| }
|
|
|
| - void* planes[3];
|
| - if (cachedData.get()) {
|
| - planes[0] = (void*)cachedData->data();
|
| - planes[1] = (uint8_t*)planes[0] + yuvInfo.fSizeInMemory[0];
|
| - planes[2] = (uint8_t*)planes[1] + yuvInfo.fSizeInMemory[1];
|
| - } else {
|
| - // Fetch yuv plane sizes for memory allocation. Here, width and height can be
|
| - // rounded up to JPEG block size and be larger than the image's width and height.
|
| - if (!pixelRef->getYUV8Planes(yuvInfo.fSize, nullptr, nullptr, nullptr)) {
|
| - return nullptr;
|
| - }
|
| + return GrCreateTextureForPixels(ctx, optionalKey, desc, bm.pixelRef(), startOfTexData, 0);
|
| +}
|
|
|
| - // Allocate the memory for YUV
|
| - size_t totalSize(0);
|
| - for (int i = 0; i < 3; ++i) {
|
| - yuvInfo.fRowBytes[i] = yuvInfo.fSize[i].fWidth;
|
| - yuvInfo.fSizeInMemory[i] = yuvInfo.fRowBytes[i] * yuvInfo.fSize[i].fHeight;
|
| - totalSize += yuvInfo.fSizeInMemory[i];
|
| - }
|
| - if (useCache) {
|
| - cachedData.reset(SkResourceCache::NewCachedData(totalSize));
|
| - planes[0] = cachedData->writable_data();
|
| - } else {
|
| - storage.reset(totalSize);
|
| - planes[0] = storage.get();
|
| - }
|
| - planes[1] = (uint8_t*)planes[0] + yuvInfo.fSizeInMemory[0];
|
| - planes[2] = (uint8_t*)planes[1] + yuvInfo.fSizeInMemory[1];
|
| +/*
|
| + * Once we have made SkImages handle all lazy/deferred/generated content, the YUV apis will
|
| + * be gone from SkPixelRef, and we can remove this subclass entirely.
|
| + */
|
| +class PixelRef_GrYUVProvider : public GrYUVProvider {
|
| + SkPixelRef* fPR;
|
|
|
| - // Get the YUV planes and update plane sizes to actual image size
|
| - if (!pixelRef->getYUV8Planes(yuvInfo.fSize, planes, yuvInfo.fRowBytes,
|
| - &yuvInfo.fColorSpace)) {
|
| - return nullptr;
|
| - }
|
| +public:
|
| + PixelRef_GrYUVProvider(SkPixelRef* pr) : fPR(pr) {}
|
|
|
| - if (useCache) {
|
| - // Decoding is done, cache the resulting YUV planes
|
| - SkYUVPlanesCache::Add(pixelRef->getGenerationID(), cachedData, &yuvInfo);
|
| - }
|
| + uint32_t onGetID() override { return fPR->getGenerationID(); }
|
| + bool onGetYUVSizes(SkISize sizes[3]) override {
|
| + return fPR->getYUV8Planes(sizes, nullptr, nullptr, nullptr);
|
| }
|
| -
|
| - GrSurfaceDesc yuvDesc;
|
| - yuvDesc.fConfig = kAlpha_8_GrPixelConfig;
|
| - SkAutoTUnref<GrTexture> yuvTextures[3];
|
| - for (int i = 0; i < 3; ++i) {
|
| - yuvDesc.fWidth = yuvInfo.fSize[i].fWidth;
|
| - yuvDesc.fHeight = yuvInfo.fSize[i].fHeight;
|
| - bool needsExactTexture =
|
| - (yuvDesc.fWidth != yuvInfo.fSize[0].fWidth) ||
|
| - (yuvDesc.fHeight != yuvInfo.fSize[0].fHeight);
|
| - if (needsExactTexture) {
|
| - yuvTextures[i].reset(ctx->textureProvider()->createTexture(yuvDesc, true));
|
| - } else {
|
| - yuvTextures[i].reset(ctx->textureProvider()->createApproxTexture(yuvDesc));
|
| - }
|
| - if (!yuvTextures[i] ||
|
| - !yuvTextures[i]->writePixels(0, 0, yuvDesc.fWidth, yuvDesc.fHeight,
|
| - yuvDesc.fConfig, planes[i], yuvInfo.fRowBytes[i])) {
|
| - return nullptr;
|
| - }
|
| + bool onGetYUVPlanes(SkISize sizes[3], void* planes[3], size_t rowBytes[3],
|
| + SkYUVColorSpace* space) override {
|
| + return fPR->getYUV8Planes(sizes, planes, rowBytes, space);
|
| }
|
| +};
|
|
|
| - GrSurfaceDesc rtDesc = desc;
|
| - rtDesc.fFlags = rtDesc.fFlags | kRenderTarget_GrSurfaceFlag;
|
| -
|
| - GrTexture* result = create_texture_for_bmp(ctx, optionalKey, rtDesc, pixelRef, nullptr, 0);
|
| - if (!result) {
|
| +static GrTexture* load_yuv_texture(GrContext* ctx, const GrUniqueKey& optionalKey,
|
| + const SkBitmap& bm, const GrSurfaceDesc& desc) {
|
| + // Subsets are not supported, the whole pixelRef is loaded when using YUV decoding
|
| + SkPixelRef* pixelRef = bm.pixelRef();
|
| + if ((nullptr == pixelRef) ||
|
| + (pixelRef->info().width() != bm.info().width()) ||
|
| + (pixelRef->info().height() != bm.info().height())) {
|
| return nullptr;
|
| }
|
|
|
| - GrRenderTarget* renderTarget = result->asRenderTarget();
|
| - SkASSERT(renderTarget);
|
| -
|
| - GrPaint paint;
|
| - SkAutoTUnref<GrFragmentProcessor>
|
| - yuvToRgbProcessor(GrYUVtoRGBEffect::Create(paint.getProcessorDataManager(), yuvTextures[0],
|
| - yuvTextures[1], yuvTextures[2],
|
| - yuvInfo.fSize, yuvInfo.fColorSpace));
|
| - paint.addColorFragmentProcessor(yuvToRgbProcessor);
|
| - SkRect r = SkRect::MakeWH(SkIntToScalar(yuvInfo.fSize[0].fWidth),
|
| - SkIntToScalar(yuvInfo.fSize[0].fHeight));
|
| -
|
| - SkAutoTUnref<GrDrawContext> drawContext(ctx->drawContext());
|
| - if (!drawContext) {
|
| + const bool useCache = optionalKey.isValid();
|
| + PixelRef_GrYUVProvider provider(pixelRef);
|
| + GrTexture* texture = provider.refAsTexture(ctx, desc, useCache);
|
| + if (!texture) {
|
| return nullptr;
|
| }
|
|
|
| - drawContext->drawRect(renderTarget, GrClip::WideOpen(), paint, SkMatrix::I(), r);
|
| -
|
| - return result;
|
| + if (useCache) {
|
| + BitmapInvalidator* listener = new BitmapInvalidator(optionalKey);
|
| + pixelRef->addGenIDChangeListener(listener);
|
| + ctx->textureProvider()->assignUniqueKeyToTexture(optionalKey, texture);
|
| + }
|
| + return texture;
|
| }
|
|
|
| static GrTexture* create_unstretched_bitmap_texture(GrContext* ctx,
|
| @@ -507,32 +455,24 @@ static GrTexture* create_unstretched_bitmap_texture(GrContext* ctx,
|
|
|
| // our compressed data will be trimmed, so pass width() for its
|
| // "rowBytes", since they are the same now.
|
| - return create_texture_for_bmp(ctx, optionalKey, desc, origBitmap.pixelRef(),
|
| - storage.get(), bitmap->width());
|
| + return GrCreateTextureForPixels(ctx, optionalKey, desc, origBitmap.pixelRef(),
|
| + storage.get(), bitmap->width());
|
| } else {
|
| origBitmap.copyTo(&tmpBitmap, kN32_SkColorType);
|
| // now bitmap points to our temp, which has been promoted to 32bits
|
| bitmap = &tmpBitmap;
|
| desc.fConfig = SkImageInfo2GrPixelConfig(bitmap->info());
|
| }
|
| - }
|
| -
|
| - // Is this an ETC1 encoded texture?
|
| -#ifndef SK_IGNORE_ETC1_SUPPORT
|
| - // Make sure that the underlying device supports ETC1 textures before we go ahead
|
| - // and check the data.
|
| - else if (caps->isConfigTexturable(kETC1_GrPixelConfig)
|
| - // If the bitmap had compressed data and was then uncompressed, it'll still return
|
| - // compressed data on 'refEncodedData' and upload it. Probably not good, since if
|
| - // the bitmap has available pixels, then they might not be what the decompressed
|
| - // data is.
|
| - && !(bitmap->readyToDraw())) {
|
| + } else if (!bitmap->readyToDraw()) {
|
| + // If the bitmap had compressed data and was then uncompressed, it'll still return
|
| + // compressed data on 'refEncodedData' and upload it. Probably not good, since if
|
| + // the bitmap has available pixels, then they might not be what the decompressed
|
| + // data is.
|
| GrTexture *texture = load_etc1_texture(ctx, optionalKey, *bitmap, desc);
|
| if (texture) {
|
| return texture;
|
| }
|
| }
|
| -#endif // SK_IGNORE_ETC1_SUPPORT
|
|
|
| GrTexture *texture = load_yuv_texture(ctx, optionalKey, *bitmap, desc);
|
| if (texture) {
|
| @@ -544,8 +484,8 @@ static GrTexture* create_unstretched_bitmap_texture(GrContext* ctx,
|
| return nullptr;
|
| }
|
|
|
| - return create_texture_for_bmp(ctx, optionalKey, desc, origBitmap.pixelRef(),
|
| - bitmap->getPixels(), bitmap->rowBytes());
|
| + return GrCreateTextureForPixels(ctx, optionalKey, desc, origBitmap.pixelRef(),
|
| + bitmap->getPixels(), bitmap->rowBytes());
|
| }
|
|
|
| static SkBitmap stretch_on_cpu(const SkBitmap& bmp, const Stretch& stretch) {
|
|
|