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 8c65aec97619682b2c0191554f44ddf35f618a94dBrian Salomon#include "GrYUVProvider.h" 9c65aec97619682b2c0191554f44ddf35f618a94dBrian Salomon#include "GrClip.h" 1043fe6185c5043247c47daa450b015e26d86728fereed#include "GrContext.h" 11bc7a4fb06780f9829b4b21470fe6f0503d2297cdRobert Phillips#include "GrContextPriv.h" 12fb3abcd8c335132b6ad8434a171516102bbf4495Greg Daniel#include "GrProxyProvider.h" 131105224f9701e57ec5ce0354d6a380b664f5c638Brian Osman#include "GrRenderTargetContext.h" 14bc7a4fb06780f9829b4b21470fe6f0503d2297cdRobert Phillips#include "GrTextureProxy.h" 1595e3c058ef633782f7549e9e1c2727d60dbc8ee5Hal Canary#include "SkAutoMalloc.h" 1643fe6185c5043247c47daa450b015e26d86728fereed#include "SkCachedData.h" 1743fe6185c5043247c47daa450b015e26d86728fereed#include "SkRefCnt.h" 1843fe6185c5043247c47daa450b015e26d86728fereed#include "SkResourceCache.h" 1943fe6185c5043247c47daa450b015e26d86728fereed#include "SkYUVPlanesCache.h" 2077e966647f6b495fe44772086c709528c711fc6eChristopher Cameron#include "effects/GrNonlinearColorSpaceXformEffect.h" 21c65aec97619682b2c0191554f44ddf35f618a94dBrian Salomon#include "effects/GrSRGBEffect.h" 227461a4abe06ffdfbb62a479a71b14895a637bba9Ethan Nicholas#include "effects/GrYUVtoRGBEffect.h" 2343fe6185c5043247c47daa450b015e26d86728fereed 241445da6c03c7ce6a3039bd63498e1179a320722fGreg Danielsk_sp<SkCachedData> init_provider(GrYUVProvider* provider, SkYUVPlanesCache::Info* yuvInfo, 251445da6c03c7ce6a3039bd63498e1179a320722fGreg Daniel void* planes[3]) { 261445da6c03c7ce6a3039bd63498e1179a320722fGreg Daniel sk_sp<SkCachedData> data; 271445da6c03c7ce6a3039bd63498e1179a320722fGreg Daniel data.reset(SkYUVPlanesCache::FindAndRef(provider->onGetID(), yuvInfo)); 2843fe6185c5043247c47daa450b015e26d86728fereed 291445da6c03c7ce6a3039bd63498e1179a320722fGreg Daniel if (data.get()) { 301445da6c03c7ce6a3039bd63498e1179a320722fGreg Daniel planes[0] = (void*)data->data(); 314984c3c95f18eda44492a2126c9958e447f2cca8msarett planes[1] = (uint8_t*)planes[0] + (yuvInfo->fSizeInfo.fWidthBytes[SkYUVSizeInfo::kY] * 324984c3c95f18eda44492a2126c9958e447f2cca8msarett yuvInfo->fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight); 334984c3c95f18eda44492a2126c9958e447f2cca8msarett planes[2] = (uint8_t*)planes[1] + (yuvInfo->fSizeInfo.fWidthBytes[SkYUVSizeInfo::kU] * 344984c3c95f18eda44492a2126c9958e447f2cca8msarett yuvInfo->fSizeInfo.fSizes[SkYUVSizeInfo::kU].fHeight); 3543fe6185c5043247c47daa450b015e26d86728fereed } else { 364984c3c95f18eda44492a2126c9958e447f2cca8msarett // Fetch yuv plane sizes for memory allocation. 374984c3c95f18eda44492a2126c9958e447f2cca8msarett if (!provider->onQueryYUV8(&yuvInfo->fSizeInfo, &yuvInfo->fColorSpace)) { 381445da6c03c7ce6a3039bd63498e1179a320722fGreg Daniel return nullptr; 3943fe6185c5043247c47daa450b015e26d86728fereed } 4043fe6185c5043247c47daa450b015e26d86728fereed 4143fe6185c5043247c47daa450b015e26d86728fereed // Allocate the memory for YUV 4243fe6185c5043247c47daa450b015e26d86728fereed size_t totalSize(0); 434984c3c95f18eda44492a2126c9958e447f2cca8msarett for (int i = 0; i < 3; i++) { 444984c3c95f18eda44492a2126c9958e447f2cca8msarett totalSize += yuvInfo->fSizeInfo.fWidthBytes[i] * yuvInfo->fSizeInfo.fSizes[i].fHeight; 4543fe6185c5043247c47daa450b015e26d86728fereed } 461445da6c03c7ce6a3039bd63498e1179a320722fGreg Daniel data.reset(SkResourceCache::NewCachedData(totalSize)); 471445da6c03c7ce6a3039bd63498e1179a320722fGreg Daniel planes[0] = data->writable_data(); 484984c3c95f18eda44492a2126c9958e447f2cca8msarett planes[1] = (uint8_t*)planes[0] + (yuvInfo->fSizeInfo.fWidthBytes[SkYUVSizeInfo::kY] * 494984c3c95f18eda44492a2126c9958e447f2cca8msarett yuvInfo->fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight); 504984c3c95f18eda44492a2126c9958e447f2cca8msarett planes[2] = (uint8_t*)planes[1] + (yuvInfo->fSizeInfo.fWidthBytes[SkYUVSizeInfo::kU] * 514984c3c95f18eda44492a2126c9958e447f2cca8msarett yuvInfo->fSizeInfo.fSizes[SkYUVSizeInfo::kU].fHeight); 5243fe6185c5043247c47daa450b015e26d86728fereed 534984c3c95f18eda44492a2126c9958e447f2cca8msarett // Get the YUV planes. 544984c3c95f18eda44492a2126c9958e447f2cca8msarett if (!provider->onGetYUV8Planes(yuvInfo->fSizeInfo, planes)) { 551445da6c03c7ce6a3039bd63498e1179a320722fGreg Daniel return nullptr; 5643fe6185c5043247c47daa450b015e26d86728fereed } 5743fe6185c5043247c47daa450b015e26d86728fereed 581445da6c03c7ce6a3039bd63498e1179a320722fGreg Daniel // Decoding is done, cache the resulting YUV planes 591445da6c03c7ce6a3039bd63498e1179a320722fGreg Daniel SkYUVPlanesCache::Add(provider->onGetID(), data.get(), yuvInfo); 6043fe6185c5043247c47daa450b015e26d86728fereed } 611445da6c03c7ce6a3039bd63498e1179a320722fGreg Daniel return data; 6243fe6185c5043247c47daa450b015e26d86728fereed} 6343fe6185c5043247c47daa450b015e26d86728fereed 64fb3abcd8c335132b6ad8434a171516102bbf4495Greg Danielvoid GrYUVProvider::YUVGen_DataReleaseProc(const void*, void* data) { 65fb3abcd8c335132b6ad8434a171516102bbf4495Greg Daniel SkCachedData* cachedData = static_cast<SkCachedData*>(data); 66fb3abcd8c335132b6ad8434a171516102bbf4495Greg Daniel SkASSERT(cachedData); 67fb3abcd8c335132b6ad8434a171516102bbf4495Greg Daniel cachedData->unref(); 68fb3abcd8c335132b6ad8434a171516102bbf4495Greg Daniel} 69fb3abcd8c335132b6ad8434a171516102bbf4495Greg Daniel 7077e966647f6b495fe44772086c709528c711fc6eChristopher Cameronsk_sp<GrTextureProxy> GrYUVProvider::refAsTextureProxy(GrContext* ctx, const GrSurfaceDesc& desc, 7177e966647f6b495fe44772086c709528c711fc6eChristopher Cameron const SkColorSpace* srcColorSpace, 7277e966647f6b495fe44772086c709528c711fc6eChristopher Cameron const SkColorSpace* dstColorSpace) { 7343fe6185c5043247c47daa450b015e26d86728fereed SkYUVPlanesCache::Info yuvInfo; 7443fe6185c5043247c47daa450b015e26d86728fereed void* planes[3]; 751445da6c03c7ce6a3039bd63498e1179a320722fGreg Daniel 761445da6c03c7ce6a3039bd63498e1179a320722fGreg Daniel sk_sp<SkCachedData> dataStorage = init_provider(this, &yuvInfo, planes); 771445da6c03c7ce6a3039bd63498e1179a320722fGreg Daniel if (!dataStorage) { 7843fe6185c5043247c47daa450b015e26d86728fereed return nullptr; 7943fe6185c5043247c47daa450b015e26d86728fereed } 8043fe6185c5043247c47daa450b015e26d86728fereed 81fb3abcd8c335132b6ad8434a171516102bbf4495Greg Daniel sk_sp<GrTextureProxy> yuvTextureProxies[3]; 824984c3c95f18eda44492a2126c9958e447f2cca8msarett for (int i = 0; i < 3; i++) { 83fb3abcd8c335132b6ad8434a171516102bbf4495Greg Daniel int componentWidth = yuvInfo.fSizeInfo.fSizes[i].fWidth; 84fb3abcd8c335132b6ad8434a171516102bbf4495Greg Daniel int componentHeight = yuvInfo.fSizeInfo.fSizes[i].fHeight; 85fb3abcd8c335132b6ad8434a171516102bbf4495Greg Daniel // If the sizes of the components are not all the same we choose to create exact-match 86fb3abcd8c335132b6ad8434a171516102bbf4495Greg Daniel // textures for the smaller onces rather than add a texture domain to the draw. 87fb3abcd8c335132b6ad8434a171516102bbf4495Greg Daniel // TODO: revisit this decision to imporve texture reuse? 88bc7a4fb06780f9829b4b21470fe6f0503d2297cdRobert Phillips SkBackingFit fit = 89fb3abcd8c335132b6ad8434a171516102bbf4495Greg Daniel (componentWidth != yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fWidth) || 90fb3abcd8c335132b6ad8434a171516102bbf4495Greg Daniel (componentHeight != yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight) 91bc7a4fb06780f9829b4b21470fe6f0503d2297cdRobert Phillips ? SkBackingFit::kExact : SkBackingFit::kApprox; 92bc7a4fb06780f9829b4b21470fe6f0503d2297cdRobert Phillips 93fb3abcd8c335132b6ad8434a171516102bbf4495Greg Daniel SkImageInfo imageInfo = SkImageInfo::MakeA8(componentWidth, componentHeight); 94fb3abcd8c335132b6ad8434a171516102bbf4495Greg Daniel SkPixmap pixmap(imageInfo, planes[i], yuvInfo.fSizeInfo.fWidthBytes[i]); 95fb3abcd8c335132b6ad8434a171516102bbf4495Greg Daniel SkCachedData* dataStoragePtr = dataStorage.get(); 96fb3abcd8c335132b6ad8434a171516102bbf4495Greg Daniel // We grab a ref to cached yuv data. When the SkImage we create below goes away it will call 97fb3abcd8c335132b6ad8434a171516102bbf4495Greg Daniel // the YUVGen_DataReleaseProc which will release this ref. 98fb3abcd8c335132b6ad8434a171516102bbf4495Greg Daniel // DDL TODO: Currently we end up creating a lazy proxy that will hold onto a ref to the 99fb3abcd8c335132b6ad8434a171516102bbf4495Greg Daniel // SkImage in its lambda. This means that we'll keep the ref on the YUV data around for the 100fb3abcd8c335132b6ad8434a171516102bbf4495Greg Daniel // life time of the proxy and not just upload. For non-DDL draws we should look into 101fb3abcd8c335132b6ad8434a171516102bbf4495Greg Daniel // releasing this SkImage after uploads (by deleting the lambda after instantiation). 102fb3abcd8c335132b6ad8434a171516102bbf4495Greg Daniel dataStoragePtr->ref(); 103fb3abcd8c335132b6ad8434a171516102bbf4495Greg Daniel sk_sp<SkImage> yuvImage = SkImage::MakeFromRaster(pixmap, YUVGen_DataReleaseProc, 104fb3abcd8c335132b6ad8434a171516102bbf4495Greg Daniel dataStoragePtr); 105bc7a4fb06780f9829b4b21470fe6f0503d2297cdRobert Phillips 106fb3abcd8c335132b6ad8434a171516102bbf4495Greg Daniel auto proxyProvider = ctx->contextPriv().proxyProvider(); 107fb3abcd8c335132b6ad8434a171516102bbf4495Greg Daniel yuvTextureProxies[i] = proxyProvider->createTextureProxy(yuvImage, kNone_GrSurfaceFlags, 108fb3abcd8c335132b6ad8434a171516102bbf4495Greg Daniel kTopLeft_GrSurfaceOrigin, 109bdecacfbe47bc7211336bb847bb33c00ef85ea3eBrian Salomon 1, SkBudgeted::kYes, fit); 11043fe6185c5043247c47daa450b015e26d86728fereed } 11143fe6185c5043247c47daa450b015e26d86728fereed 112366093f2124c38fa5c590c9ed2d1811817fed8eeBrian Salomon // We never want to perform color-space conversion during the decode. However, if the proxy 113366093f2124c38fa5c590c9ed2d1811817fed8eeBrian Salomon // config is sRGB then we must use a sRGB color space. 114366093f2124c38fa5c590c9ed2d1811817fed8eeBrian Salomon sk_sp<SkColorSpace> colorSpace; 115366093f2124c38fa5c590c9ed2d1811817fed8eeBrian Salomon if (GrPixelConfigIsSRGB(desc.fConfig)) { 116366093f2124c38fa5c590c9ed2d1811817fed8eeBrian Salomon colorSpace = SkColorSpace::MakeSRGB(); 117366093f2124c38fa5c590c9ed2d1811817fed8eeBrian Salomon } 118e1da1d9a7dfa6c9ebdcbd2845acebd045edd2a6fGreg Daniel // TODO: investigate preallocating mip maps here 119dd3b3f41829d32d7eaf3eb4903570d49c2ba9ff8Robert Phillips sk_sp<GrRenderTargetContext> renderTargetContext(ctx->makeDeferredRenderTargetContext( 120366093f2124c38fa5c590c9ed2d1811817fed8eeBrian Salomon SkBackingFit::kExact, desc.fWidth, desc.fHeight, desc.fConfig, std::move(colorSpace), 121366093f2124c38fa5c590c9ed2d1811817fed8eeBrian Salomon desc.fSampleCnt, GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin)); 1221105224f9701e57ec5ce0354d6a380b664f5c638Brian Osman if (!renderTargetContext) { 12343fe6185c5043247c47daa450b015e26d86728fereed return nullptr; 12443fe6185c5043247c47daa450b015e26d86728fereed } 12543fe6185c5043247c47daa450b015e26d86728fereed 12643fe6185c5043247c47daa450b015e26d86728fereed GrPaint paint; 127aff329b8e9b239bca1d93b13a914fbef45ccf7feBrian Salomon auto yuvToRgbProcessor = 128fb3abcd8c335132b6ad8434a171516102bbf4495Greg Daniel GrYUVtoRGBEffect::Make(std::move(yuvTextureProxies[0]), 129fb3abcd8c335132b6ad8434a171516102bbf4495Greg Daniel std::move(yuvTextureProxies[1]), 130fb3abcd8c335132b6ad8434a171516102bbf4495Greg Daniel std::move(yuvTextureProxies[2]), 1317461a4abe06ffdfbb62a479a71b14895a637bba9Ethan Nicholas yuvInfo.fSizeInfo.fSizes, yuvInfo.fColorSpace, false); 13206ca8ec87cf6fab57cadd043a5ac18c4154a4129bungeman paint.addColorFragmentProcessor(std::move(yuvToRgbProcessor)); 133717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman 134717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman // If we're decoding an sRGB image, the result of our linear math on the YUV planes is already 135717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman // in sRGB. (The encoding is just math on bytes, with no concept of color spaces.) So, we need 136717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman // to output the results of that math directly to the buffer that we will then consider sRGB. 137717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman // If we have sRGB write control, we can just tell the HW not to do the Linear -> sRGB step. 138717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman // Otherwise, we do our shader math to go from YUV -> sRGB, manually convert sRGB -> Linear, 139717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman // then let the HW convert Linear -> sRGB. 140717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman if (GrPixelConfigIsSRGB(desc.fConfig)) { 141717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman if (ctx->caps()->srgbWriteControl()) { 142717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman paint.setDisableOutputConversionToSRGB(true); 143717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman } else { 14498308fb081687970278dce2a7631005f9cb424a8Mike Reed paint.addColorFragmentProcessor(GrSRGBEffect::Make(GrSRGBEffect::Mode::kSRGBToLinear, 14598308fb081687970278dce2a7631005f9cb424a8Mike Reed GrSRGBEffect::Alpha::kOpaque)); 146717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman } 147717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman } 148717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman 14977e966647f6b495fe44772086c709528c711fc6eChristopher Cameron // If the caller expects the pixels in a different color space than the one from the image, 15077e966647f6b495fe44772086c709528c711fc6eChristopher Cameron // apply a color conversion to do this. 151aff329b8e9b239bca1d93b13a914fbef45ccf7feBrian Salomon std::unique_ptr<GrFragmentProcessor> colorConversionProcessor = 15277e966647f6b495fe44772086c709528c711fc6eChristopher Cameron GrNonlinearColorSpaceXformEffect::Make(srcColorSpace, dstColorSpace); 15377e966647f6b495fe44772086c709528c711fc6eChristopher Cameron if (colorConversionProcessor) { 154aff329b8e9b239bca1d93b13a914fbef45ccf7feBrian Salomon paint.addColorFragmentProcessor(std::move(colorConversionProcessor)); 15577e966647f6b495fe44772086c709528c711fc6eChristopher Cameron } 15677e966647f6b495fe44772086c709528c711fc6eChristopher Cameron 157374772bd61951f01bf84fe17bf53d8867681c9aereed paint.setPorterDuffXPFactory(SkBlendMode::kSrc); 1584984c3c95f18eda44492a2126c9958e447f2cca8msarett const SkRect r = SkRect::MakeIWH(yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fWidth, 15967c18d6b5188a0497f6912a73d964c763d2f8f84Robert Phillips yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight); 16043fe6185c5043247c47daa450b015e26d86728fereed 16182f44319159bb98dcacdbbec7ea643dde5ed024bBrian Salomon renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), r); 16243fe6185c5043247c47daa450b015e26d86728fereed 163538f1a36e3cd0327ee2639693143179ec0359151Robert Phillips return renderTargetContext->asTextureProxyRef(); 16443fe6185c5043247c47daa450b015e26d86728fereed} 165