GrYUVProvider.cpp revision bc7a4fb06780f9829b4b21470fe6f0503d2297cd
143fe6185c5043247c47daa450b015e26d86728fereed/* 243fe6185c5043247c47daa450b015e26d86728fereed * Copyright 2015 Google Inc. 343fe6185c5043247c47daa450b015e26d86728fereed * 443fe6185c5043247c47daa450b015e26d86728fereed * Use of this source code is governed by a BSD-style license that can be 543fe6185c5043247c47daa450b015e26d86728fereed * found in the LICENSE file. 643fe6185c5043247c47daa450b015e26d86728fereed */ 743fe6185c5043247c47daa450b015e26d86728fereed 843fe6185c5043247c47daa450b015e26d86728fereed#include "GrContext.h" 9bc7a4fb06780f9829b4b21470fe6f0503d2297cdRobert Phillips#include "GrContextPriv.h" 101105224f9701e57ec5ce0354d6a380b664f5c638Brian Osman#include "GrRenderTargetContext.h" 11bc7a4fb06780f9829b4b21470fe6f0503d2297cdRobert Phillips#include "GrTextureProxy.h" 1243fe6185c5043247c47daa450b015e26d86728fereed#include "GrYUVProvider.h" 13717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman#include "effects/GrGammaEffect.h" 14f267c1efe7de7a8e71404afde6cbf93c3808d267bsalomon#include "effects/GrYUVEffect.h" 1543fe6185c5043247c47daa450b015e26d86728fereed 1695e3c058ef633782f7549e9e1c2727d60dbc8ee5Hal Canary#include "SkAutoMalloc.h" 1743fe6185c5043247c47daa450b015e26d86728fereed#include "SkCachedData.h" 1843fe6185c5043247c47daa450b015e26d86728fereed#include "SkRefCnt.h" 1943fe6185c5043247c47daa450b015e26d86728fereed#include "SkResourceCache.h" 2043fe6185c5043247c47daa450b015e26d86728fereed#include "SkYUVPlanesCache.h" 2143fe6185c5043247c47daa450b015e26d86728fereed 2243fe6185c5043247c47daa450b015e26d86728fereednamespace { 2343fe6185c5043247c47daa450b015e26d86728fereed/** 2443fe6185c5043247c47daa450b015e26d86728fereed * Helper class to manage the resources used for storing the YUV planar data. Depending on the 2543fe6185c5043247c47daa450b015e26d86728fereed * useCache option, we may find (and lock) the data in our ResourceCache, or we may have allocated 2643fe6185c5043247c47daa450b015e26d86728fereed * it in scratch storage. 2743fe6185c5043247c47daa450b015e26d86728fereed */ 2843fe6185c5043247c47daa450b015e26d86728fereedclass YUVScoper { 2943fe6185c5043247c47daa450b015e26d86728fereedpublic: 3043fe6185c5043247c47daa450b015e26d86728fereed bool init(GrYUVProvider*, SkYUVPlanesCache::Info*, void* planes[3], bool useCache); 3143fe6185c5043247c47daa450b015e26d86728fereed 3243fe6185c5043247c47daa450b015e26d86728fereedprivate: 3343fe6185c5043247c47daa450b015e26d86728fereed // we only use one or the other of these 34144caf55ffc692bcda77703a73bb9a894f7d024fHal Canary sk_sp<SkCachedData> fCachedData; 35144caf55ffc692bcda77703a73bb9a894f7d024fHal Canary SkAutoMalloc fStorage; 3643fe6185c5043247c47daa450b015e26d86728fereed}; 3743fe6185c5043247c47daa450b015e26d86728fereed} 3843fe6185c5043247c47daa450b015e26d86728fereed 3943fe6185c5043247c47daa450b015e26d86728fereedbool YUVScoper::init(GrYUVProvider* provider, SkYUVPlanesCache::Info* yuvInfo, void* planes[3], 4043fe6185c5043247c47daa450b015e26d86728fereed bool useCache) { 4143fe6185c5043247c47daa450b015e26d86728fereed if (useCache) { 4243fe6185c5043247c47daa450b015e26d86728fereed fCachedData.reset(SkYUVPlanesCache::FindAndRef(provider->onGetID(), yuvInfo)); 4343fe6185c5043247c47daa450b015e26d86728fereed } 4443fe6185c5043247c47daa450b015e26d86728fereed 4543fe6185c5043247c47daa450b015e26d86728fereed if (fCachedData.get()) { 4643fe6185c5043247c47daa450b015e26d86728fereed planes[0] = (void*)fCachedData->data(); 474984c3c95f18eda44492a2126c9958e447f2cca8msarett planes[1] = (uint8_t*)planes[0] + (yuvInfo->fSizeInfo.fWidthBytes[SkYUVSizeInfo::kY] * 484984c3c95f18eda44492a2126c9958e447f2cca8msarett yuvInfo->fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight); 494984c3c95f18eda44492a2126c9958e447f2cca8msarett planes[2] = (uint8_t*)planes[1] + (yuvInfo->fSizeInfo.fWidthBytes[SkYUVSizeInfo::kU] * 504984c3c95f18eda44492a2126c9958e447f2cca8msarett yuvInfo->fSizeInfo.fSizes[SkYUVSizeInfo::kU].fHeight); 5143fe6185c5043247c47daa450b015e26d86728fereed } else { 524984c3c95f18eda44492a2126c9958e447f2cca8msarett // Fetch yuv plane sizes for memory allocation. 534984c3c95f18eda44492a2126c9958e447f2cca8msarett if (!provider->onQueryYUV8(&yuvInfo->fSizeInfo, &yuvInfo->fColorSpace)) { 5443fe6185c5043247c47daa450b015e26d86728fereed return false; 5543fe6185c5043247c47daa450b015e26d86728fereed } 5643fe6185c5043247c47daa450b015e26d86728fereed 5743fe6185c5043247c47daa450b015e26d86728fereed // Allocate the memory for YUV 5843fe6185c5043247c47daa450b015e26d86728fereed size_t totalSize(0); 594984c3c95f18eda44492a2126c9958e447f2cca8msarett for (int i = 0; i < 3; i++) { 604984c3c95f18eda44492a2126c9958e447f2cca8msarett totalSize += yuvInfo->fSizeInfo.fWidthBytes[i] * yuvInfo->fSizeInfo.fSizes[i].fHeight; 6143fe6185c5043247c47daa450b015e26d86728fereed } 6243fe6185c5043247c47daa450b015e26d86728fereed if (useCache) { 6343fe6185c5043247c47daa450b015e26d86728fereed fCachedData.reset(SkResourceCache::NewCachedData(totalSize)); 6443fe6185c5043247c47daa450b015e26d86728fereed planes[0] = fCachedData->writable_data(); 6543fe6185c5043247c47daa450b015e26d86728fereed } else { 6643fe6185c5043247c47daa450b015e26d86728fereed fStorage.reset(totalSize); 6743fe6185c5043247c47daa450b015e26d86728fereed planes[0] = fStorage.get(); 6843fe6185c5043247c47daa450b015e26d86728fereed } 694984c3c95f18eda44492a2126c9958e447f2cca8msarett planes[1] = (uint8_t*)planes[0] + (yuvInfo->fSizeInfo.fWidthBytes[SkYUVSizeInfo::kY] * 704984c3c95f18eda44492a2126c9958e447f2cca8msarett yuvInfo->fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight); 714984c3c95f18eda44492a2126c9958e447f2cca8msarett planes[2] = (uint8_t*)planes[1] + (yuvInfo->fSizeInfo.fWidthBytes[SkYUVSizeInfo::kU] * 724984c3c95f18eda44492a2126c9958e447f2cca8msarett yuvInfo->fSizeInfo.fSizes[SkYUVSizeInfo::kU].fHeight); 7343fe6185c5043247c47daa450b015e26d86728fereed 744984c3c95f18eda44492a2126c9958e447f2cca8msarett // Get the YUV planes. 754984c3c95f18eda44492a2126c9958e447f2cca8msarett if (!provider->onGetYUV8Planes(yuvInfo->fSizeInfo, planes)) { 7643fe6185c5043247c47daa450b015e26d86728fereed return false; 7743fe6185c5043247c47daa450b015e26d86728fereed } 7843fe6185c5043247c47daa450b015e26d86728fereed 7943fe6185c5043247c47daa450b015e26d86728fereed if (useCache) { 8043fe6185c5043247c47daa450b015e26d86728fereed // Decoding is done, cache the resulting YUV planes 81144caf55ffc692bcda77703a73bb9a894f7d024fHal Canary SkYUVPlanesCache::Add(provider->onGetID(), fCachedData.get(), yuvInfo); 8243fe6185c5043247c47daa450b015e26d86728fereed } 8343fe6185c5043247c47daa450b015e26d86728fereed } 8443fe6185c5043247c47daa450b015e26d86728fereed return true; 8543fe6185c5043247c47daa450b015e26d86728fereed} 8643fe6185c5043247c47daa450b015e26d86728fereed 87677da9d4af2558ddd50a900e90a093d1b522bd5frobertphillipssk_sp<GrTexture> GrYUVProvider::refAsTexture(GrContext* ctx, 88677da9d4af2558ddd50a900e90a093d1b522bd5frobertphillips const GrSurfaceDesc& desc, 89677da9d4af2558ddd50a900e90a093d1b522bd5frobertphillips bool useCache) { 9043fe6185c5043247c47daa450b015e26d86728fereed SkYUVPlanesCache::Info yuvInfo; 9143fe6185c5043247c47daa450b015e26d86728fereed void* planes[3]; 9243fe6185c5043247c47daa450b015e26d86728fereed YUVScoper scoper; 9343fe6185c5043247c47daa450b015e26d86728fereed if (!scoper.init(this, &yuvInfo, planes, useCache)) { 9443fe6185c5043247c47daa450b015e26d86728fereed return nullptr; 9543fe6185c5043247c47daa450b015e26d86728fereed } 9643fe6185c5043247c47daa450b015e26d86728fereed 9743fe6185c5043247c47daa450b015e26d86728fereed GrSurfaceDesc yuvDesc; 98bc7a4fb06780f9829b4b21470fe6f0503d2297cdRobert Phillips yuvDesc.fOrigin = kTopLeft_GrSurfaceOrigin; 9943fe6185c5043247c47daa450b015e26d86728fereed yuvDesc.fConfig = kAlpha_8_GrPixelConfig; 100bc7a4fb06780f9829b4b21470fe6f0503d2297cdRobert Phillips sk_sp<GrSurfaceContext> yuvTextureContexts[3]; 1014984c3c95f18eda44492a2126c9958e447f2cca8msarett for (int i = 0; i < 3; i++) { 1024984c3c95f18eda44492a2126c9958e447f2cca8msarett yuvDesc.fWidth = yuvInfo.fSizeInfo.fSizes[i].fWidth; 1034984c3c95f18eda44492a2126c9958e447f2cca8msarett yuvDesc.fHeight = yuvInfo.fSizeInfo.fSizes[i].fHeight; 10443fe6185c5043247c47daa450b015e26d86728fereed // TODO: why do we need this check? 105bc7a4fb06780f9829b4b21470fe6f0503d2297cdRobert Phillips SkBackingFit fit = 1064984c3c95f18eda44492a2126c9958e447f2cca8msarett (yuvDesc.fWidth != yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fWidth) || 107bc7a4fb06780f9829b4b21470fe6f0503d2297cdRobert Phillips (yuvDesc.fHeight != yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight) 108bc7a4fb06780f9829b4b21470fe6f0503d2297cdRobert Phillips ? SkBackingFit::kExact : SkBackingFit::kApprox; 109bc7a4fb06780f9829b4b21470fe6f0503d2297cdRobert Phillips 110bc7a4fb06780f9829b4b21470fe6f0503d2297cdRobert Phillips yuvTextureContexts[i] = ctx->contextPriv().makeDeferredSurfaceContext(yuvDesc, fit, 111bc7a4fb06780f9829b4b21470fe6f0503d2297cdRobert Phillips SkBudgeted::kYes); 112bc7a4fb06780f9829b4b21470fe6f0503d2297cdRobert Phillips if (!yuvTextureContexts[i]) { 113bc7a4fb06780f9829b4b21470fe6f0503d2297cdRobert Phillips return nullptr; 114bc7a4fb06780f9829b4b21470fe6f0503d2297cdRobert Phillips } 115bc7a4fb06780f9829b4b21470fe6f0503d2297cdRobert Phillips 116bc7a4fb06780f9829b4b21470fe6f0503d2297cdRobert Phillips const SkImageInfo ii = SkImageInfo::MakeA8(yuvDesc.fWidth, yuvDesc.fHeight); 117bc7a4fb06780f9829b4b21470fe6f0503d2297cdRobert Phillips if (!yuvTextureContexts[i]->writePixels(ii, planes[i], 118bc7a4fb06780f9829b4b21470fe6f0503d2297cdRobert Phillips yuvInfo.fSizeInfo.fWidthBytes[i], 0, 0)) { 119bc7a4fb06780f9829b4b21470fe6f0503d2297cdRobert Phillips return nullptr; 12043fe6185c5043247c47daa450b015e26d86728fereed } 12143fe6185c5043247c47daa450b015e26d86728fereed } 12243fe6185c5043247c47daa450b015e26d86728fereed 123dfe4f2e4fe5b162d4adb4486fe751f1e3b30bea7brianosman // We never want to perform color-space conversion during the decode 1241105224f9701e57ec5ce0354d6a380b664f5c638Brian Osman sk_sp<GrRenderTargetContext> renderTargetContext(ctx->makeRenderTargetContext( 1251105224f9701e57ec5ce0354d6a380b664f5c638Brian Osman SkBackingFit::kExact, 1261105224f9701e57ec5ce0354d6a380b664f5c638Brian Osman desc.fWidth, desc.fHeight, 1271105224f9701e57ec5ce0354d6a380b664f5c638Brian Osman desc.fConfig, nullptr, 1281105224f9701e57ec5ce0354d6a380b664f5c638Brian Osman desc.fSampleCnt)); 1291105224f9701e57ec5ce0354d6a380b664f5c638Brian Osman if (!renderTargetContext) { 13043fe6185c5043247c47daa450b015e26d86728fereed return nullptr; 13143fe6185c5043247c47daa450b015e26d86728fereed } 13243fe6185c5043247c47daa450b015e26d86728fereed 13343fe6185c5043247c47daa450b015e26d86728fereed GrPaint paint; 134b445a57e6c36cce86580b618701b5af708a6f271jbauman sk_sp<GrFragmentProcessor> yuvToRgbProcessor( 135bc7a4fb06780f9829b4b21470fe6f0503d2297cdRobert Phillips GrYUVEffect::MakeYUVToRGB(ctx, 136bc7a4fb06780f9829b4b21470fe6f0503d2297cdRobert Phillips sk_ref_sp(yuvTextureContexts[0]->asDeferredTexture()), 137bc7a4fb06780f9829b4b21470fe6f0503d2297cdRobert Phillips sk_ref_sp(yuvTextureContexts[1]->asDeferredTexture()), 138bc7a4fb06780f9829b4b21470fe6f0503d2297cdRobert Phillips sk_ref_sp(yuvTextureContexts[2]->asDeferredTexture()), 139b445a57e6c36cce86580b618701b5af708a6f271jbauman yuvInfo.fSizeInfo.fSizes, yuvInfo.fColorSpace, false)); 14006ca8ec87cf6fab57cadd043a5ac18c4154a4129bungeman paint.addColorFragmentProcessor(std::move(yuvToRgbProcessor)); 141717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman 142717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman // If we're decoding an sRGB image, the result of our linear math on the YUV planes is already 143717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman // in sRGB. (The encoding is just math on bytes, with no concept of color spaces.) So, we need 144717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman // to output the results of that math directly to the buffer that we will then consider sRGB. 145717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman // If we have sRGB write control, we can just tell the HW not to do the Linear -> sRGB step. 146717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman // Otherwise, we do our shader math to go from YUV -> sRGB, manually convert sRGB -> Linear, 147717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman // then let the HW convert Linear -> sRGB. 148717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman if (GrPixelConfigIsSRGB(desc.fConfig)) { 149717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman if (ctx->caps()->srgbWriteControl()) { 150717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman paint.setDisableOutputConversionToSRGB(true); 151717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman } else { 15206ca8ec87cf6fab57cadd043a5ac18c4154a4129bungeman paint.addColorFragmentProcessor(GrGammaEffect::Make(2.2f)); 153717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman } 154717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman } 155717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman 156374772bd61951f01bf84fe17bf53d8867681c9aereed paint.setPorterDuffXPFactory(SkBlendMode::kSrc); 1574984c3c95f18eda44492a2126c9958e447f2cca8msarett const SkRect r = SkRect::MakeIWH(yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fWidth, 15867c18d6b5188a0497f6912a73d964c763d2f8f84Robert Phillips yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight); 15943fe6185c5043247c47daa450b015e26d86728fereed 16082f44319159bb98dcacdbbec7ea643dde5ed024bBrian Salomon renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), r); 16143fe6185c5043247c47daa450b015e26d86728fereed 1621105224f9701e57ec5ce0354d6a380b664f5c638Brian Osman return renderTargetContext->asTexture(); 16343fe6185c5043247c47daa450b015e26d86728fereed} 164