GrYUVProvider.cpp revision dfe4f2e4fe5b162d4adb4486fe751f1e3b30bea7
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" 943fe6185c5043247c47daa450b015e26d86728fereed#include "GrDrawContext.h" 1043fe6185c5043247c47daa450b015e26d86728fereed#include "GrYUVProvider.h" 11717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman#include "effects/GrGammaEffect.h" 12f267c1efe7de7a8e71404afde6cbf93c3808d267bsalomon#include "effects/GrYUVEffect.h" 1343fe6185c5043247c47daa450b015e26d86728fereed 1443fe6185c5043247c47daa450b015e26d86728fereed#include "SkCachedData.h" 1543fe6185c5043247c47daa450b015e26d86728fereed#include "SkRefCnt.h" 1643fe6185c5043247c47daa450b015e26d86728fereed#include "SkResourceCache.h" 1743fe6185c5043247c47daa450b015e26d86728fereed#include "SkYUVPlanesCache.h" 1843fe6185c5043247c47daa450b015e26d86728fereed 1943fe6185c5043247c47daa450b015e26d86728fereednamespace { 2043fe6185c5043247c47daa450b015e26d86728fereed/** 2143fe6185c5043247c47daa450b015e26d86728fereed * Helper class to manage the resources used for storing the YUV planar data. Depending on the 2243fe6185c5043247c47daa450b015e26d86728fereed * useCache option, we may find (and lock) the data in our ResourceCache, or we may have allocated 2343fe6185c5043247c47daa450b015e26d86728fereed * it in scratch storage. 2443fe6185c5043247c47daa450b015e26d86728fereed */ 2543fe6185c5043247c47daa450b015e26d86728fereedclass YUVScoper { 2643fe6185c5043247c47daa450b015e26d86728fereedpublic: 2743fe6185c5043247c47daa450b015e26d86728fereed bool init(GrYUVProvider*, SkYUVPlanesCache::Info*, void* planes[3], bool useCache); 2843fe6185c5043247c47daa450b015e26d86728fereed 2943fe6185c5043247c47daa450b015e26d86728fereedprivate: 3043fe6185c5043247c47daa450b015e26d86728fereed // we only use one or the other of these 3143fe6185c5043247c47daa450b015e26d86728fereed SkAutoTUnref<SkCachedData> fCachedData; 3243fe6185c5043247c47daa450b015e26d86728fereed SkAutoMalloc fStorage; 3343fe6185c5043247c47daa450b015e26d86728fereed}; 3443fe6185c5043247c47daa450b015e26d86728fereed} 3543fe6185c5043247c47daa450b015e26d86728fereed 3643fe6185c5043247c47daa450b015e26d86728fereedbool YUVScoper::init(GrYUVProvider* provider, SkYUVPlanesCache::Info* yuvInfo, void* planes[3], 3743fe6185c5043247c47daa450b015e26d86728fereed bool useCache) { 3843fe6185c5043247c47daa450b015e26d86728fereed if (useCache) { 3943fe6185c5043247c47daa450b015e26d86728fereed fCachedData.reset(SkYUVPlanesCache::FindAndRef(provider->onGetID(), yuvInfo)); 4043fe6185c5043247c47daa450b015e26d86728fereed } 4143fe6185c5043247c47daa450b015e26d86728fereed 4243fe6185c5043247c47daa450b015e26d86728fereed if (fCachedData.get()) { 4343fe6185c5043247c47daa450b015e26d86728fereed planes[0] = (void*)fCachedData->data(); 444984c3c95f18eda44492a2126c9958e447f2cca8msarett planes[1] = (uint8_t*)planes[0] + (yuvInfo->fSizeInfo.fWidthBytes[SkYUVSizeInfo::kY] * 454984c3c95f18eda44492a2126c9958e447f2cca8msarett yuvInfo->fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight); 464984c3c95f18eda44492a2126c9958e447f2cca8msarett planes[2] = (uint8_t*)planes[1] + (yuvInfo->fSizeInfo.fWidthBytes[SkYUVSizeInfo::kU] * 474984c3c95f18eda44492a2126c9958e447f2cca8msarett yuvInfo->fSizeInfo.fSizes[SkYUVSizeInfo::kU].fHeight); 4843fe6185c5043247c47daa450b015e26d86728fereed } else { 494984c3c95f18eda44492a2126c9958e447f2cca8msarett // Fetch yuv plane sizes for memory allocation. 504984c3c95f18eda44492a2126c9958e447f2cca8msarett if (!provider->onQueryYUV8(&yuvInfo->fSizeInfo, &yuvInfo->fColorSpace)) { 5143fe6185c5043247c47daa450b015e26d86728fereed return false; 5243fe6185c5043247c47daa450b015e26d86728fereed } 5343fe6185c5043247c47daa450b015e26d86728fereed 5443fe6185c5043247c47daa450b015e26d86728fereed // Allocate the memory for YUV 5543fe6185c5043247c47daa450b015e26d86728fereed size_t totalSize(0); 564984c3c95f18eda44492a2126c9958e447f2cca8msarett for (int i = 0; i < 3; i++) { 574984c3c95f18eda44492a2126c9958e447f2cca8msarett totalSize += yuvInfo->fSizeInfo.fWidthBytes[i] * yuvInfo->fSizeInfo.fSizes[i].fHeight; 5843fe6185c5043247c47daa450b015e26d86728fereed } 5943fe6185c5043247c47daa450b015e26d86728fereed if (useCache) { 6043fe6185c5043247c47daa450b015e26d86728fereed fCachedData.reset(SkResourceCache::NewCachedData(totalSize)); 6143fe6185c5043247c47daa450b015e26d86728fereed planes[0] = fCachedData->writable_data(); 6243fe6185c5043247c47daa450b015e26d86728fereed } else { 6343fe6185c5043247c47daa450b015e26d86728fereed fStorage.reset(totalSize); 6443fe6185c5043247c47daa450b015e26d86728fereed planes[0] = fStorage.get(); 6543fe6185c5043247c47daa450b015e26d86728fereed } 664984c3c95f18eda44492a2126c9958e447f2cca8msarett planes[1] = (uint8_t*)planes[0] + (yuvInfo->fSizeInfo.fWidthBytes[SkYUVSizeInfo::kY] * 674984c3c95f18eda44492a2126c9958e447f2cca8msarett yuvInfo->fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight); 684984c3c95f18eda44492a2126c9958e447f2cca8msarett planes[2] = (uint8_t*)planes[1] + (yuvInfo->fSizeInfo.fWidthBytes[SkYUVSizeInfo::kU] * 694984c3c95f18eda44492a2126c9958e447f2cca8msarett yuvInfo->fSizeInfo.fSizes[SkYUVSizeInfo::kU].fHeight); 7043fe6185c5043247c47daa450b015e26d86728fereed 714984c3c95f18eda44492a2126c9958e447f2cca8msarett // Get the YUV planes. 724984c3c95f18eda44492a2126c9958e447f2cca8msarett if (!provider->onGetYUV8Planes(yuvInfo->fSizeInfo, planes)) { 7343fe6185c5043247c47daa450b015e26d86728fereed return false; 7443fe6185c5043247c47daa450b015e26d86728fereed } 7543fe6185c5043247c47daa450b015e26d86728fereed 7643fe6185c5043247c47daa450b015e26d86728fereed if (useCache) { 7743fe6185c5043247c47daa450b015e26d86728fereed // Decoding is done, cache the resulting YUV planes 7843fe6185c5043247c47daa450b015e26d86728fereed SkYUVPlanesCache::Add(provider->onGetID(), fCachedData, yuvInfo); 7943fe6185c5043247c47daa450b015e26d86728fereed } 8043fe6185c5043247c47daa450b015e26d86728fereed } 8143fe6185c5043247c47daa450b015e26d86728fereed return true; 8243fe6185c5043247c47daa450b015e26d86728fereed} 8343fe6185c5043247c47daa450b015e26d86728fereed 84677da9d4af2558ddd50a900e90a093d1b522bd5frobertphillipssk_sp<GrTexture> GrYUVProvider::refAsTexture(GrContext* ctx, 85677da9d4af2558ddd50a900e90a093d1b522bd5frobertphillips const GrSurfaceDesc& desc, 86677da9d4af2558ddd50a900e90a093d1b522bd5frobertphillips bool useCache) { 8743fe6185c5043247c47daa450b015e26d86728fereed SkYUVPlanesCache::Info yuvInfo; 8843fe6185c5043247c47daa450b015e26d86728fereed void* planes[3]; 8943fe6185c5043247c47daa450b015e26d86728fereed YUVScoper scoper; 9043fe6185c5043247c47daa450b015e26d86728fereed if (!scoper.init(this, &yuvInfo, planes, useCache)) { 9143fe6185c5043247c47daa450b015e26d86728fereed return nullptr; 9243fe6185c5043247c47daa450b015e26d86728fereed } 9343fe6185c5043247c47daa450b015e26d86728fereed 9443fe6185c5043247c47daa450b015e26d86728fereed GrSurfaceDesc yuvDesc; 9543fe6185c5043247c47daa450b015e26d86728fereed yuvDesc.fConfig = kAlpha_8_GrPixelConfig; 9643fe6185c5043247c47daa450b015e26d86728fereed SkAutoTUnref<GrTexture> yuvTextures[3]; 974984c3c95f18eda44492a2126c9958e447f2cca8msarett for (int i = 0; i < 3; i++) { 984984c3c95f18eda44492a2126c9958e447f2cca8msarett yuvDesc.fWidth = yuvInfo.fSizeInfo.fSizes[i].fWidth; 994984c3c95f18eda44492a2126c9958e447f2cca8msarett yuvDesc.fHeight = yuvInfo.fSizeInfo.fSizes[i].fHeight; 10043fe6185c5043247c47daa450b015e26d86728fereed // TODO: why do we need this check? 1014984c3c95f18eda44492a2126c9958e447f2cca8msarett bool needsExactTexture = 1024984c3c95f18eda44492a2126c9958e447f2cca8msarett (yuvDesc.fWidth != yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fWidth) || 1034984c3c95f18eda44492a2126c9958e447f2cca8msarett (yuvDesc.fHeight != yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight); 10443fe6185c5043247c47daa450b015e26d86728fereed if (needsExactTexture) { 1055ec26ae9bfca635ccc98283aad5deda11519d826bsalomon yuvTextures[i].reset(ctx->textureProvider()->createTexture(yuvDesc, SkBudgeted::kYes)); 10643fe6185c5043247c47daa450b015e26d86728fereed } else { 10743fe6185c5043247c47daa450b015e26d86728fereed yuvTextures[i].reset(ctx->textureProvider()->createApproxTexture(yuvDesc)); 10843fe6185c5043247c47daa450b015e26d86728fereed } 10943fe6185c5043247c47daa450b015e26d86728fereed if (!yuvTextures[i] || 1104984c3c95f18eda44492a2126c9958e447f2cca8msarett !yuvTextures[i]->writePixels(0, 0, yuvDesc.fWidth, yuvDesc.fHeight, yuvDesc.fConfig, 1114984c3c95f18eda44492a2126c9958e447f2cca8msarett planes[i], yuvInfo.fSizeInfo.fWidthBytes[i])) { 11243fe6185c5043247c47daa450b015e26d86728fereed return nullptr; 11343fe6185c5043247c47daa450b015e26d86728fereed } 11443fe6185c5043247c47daa450b015e26d86728fereed } 11543fe6185c5043247c47daa450b015e26d86728fereed 116dfe4f2e4fe5b162d4adb4486fe751f1e3b30bea7brianosman // We never want to perform color-space conversion during the decode 117677da9d4af2558ddd50a900e90a093d1b522bd5frobertphillips sk_sp<GrDrawContext> drawContext(ctx->newDrawContext(SkBackingFit::kExact, 118677da9d4af2558ddd50a900e90a093d1b522bd5frobertphillips desc.fWidth, desc.fHeight, 119dfe4f2e4fe5b162d4adb4486fe751f1e3b30bea7brianosman desc.fConfig, nullptr, 120dfe4f2e4fe5b162d4adb4486fe751f1e3b30bea7brianosman desc.fSampleCnt)); 121677da9d4af2558ddd50a900e90a093d1b522bd5frobertphillips if (!drawContext) { 12243fe6185c5043247c47daa450b015e26d86728fereed return nullptr; 12343fe6185c5043247c47daa450b015e26d86728fereed } 12443fe6185c5043247c47daa450b015e26d86728fereed 12543fe6185c5043247c47daa450b015e26d86728fereed GrPaint paint; 126b445a57e6c36cce86580b618701b5af708a6f271jbauman sk_sp<GrFragmentProcessor> yuvToRgbProcessor( 127b445a57e6c36cce86580b618701b5af708a6f271jbauman GrYUVEffect::MakeYUVToRGB(yuvTextures[0], yuvTextures[1], yuvTextures[2], 128b445a57e6c36cce86580b618701b5af708a6f271jbauman yuvInfo.fSizeInfo.fSizes, yuvInfo.fColorSpace, false)); 12906ca8ec87cf6fab57cadd043a5ac18c4154a4129bungeman paint.addColorFragmentProcessor(std::move(yuvToRgbProcessor)); 130717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman 131717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman // If we're decoding an sRGB image, the result of our linear math on the YUV planes is already 132717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman // in sRGB. (The encoding is just math on bytes, with no concept of color spaces.) So, we need 133717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman // to output the results of that math directly to the buffer that we will then consider sRGB. 134717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman // If we have sRGB write control, we can just tell the HW not to do the Linear -> sRGB step. 135717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman // Otherwise, we do our shader math to go from YUV -> sRGB, manually convert sRGB -> Linear, 136717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman // then let the HW convert Linear -> sRGB. 137717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman if (GrPixelConfigIsSRGB(desc.fConfig)) { 138717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman if (ctx->caps()->srgbWriteControl()) { 139717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman paint.setDisableOutputConversionToSRGB(true); 140717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman } else { 14106ca8ec87cf6fab57cadd043a5ac18c4154a4129bungeman paint.addColorFragmentProcessor(GrGammaEffect::Make(2.2f)); 142717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman } 143717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman } 144717abfd2a9edcf57d07c42a03ed9f4c0062cd703brianosman 145c4b72720e75313079212e69e46a5ef7c474b2305egdaniel paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); 1464984c3c95f18eda44492a2126c9958e447f2cca8msarett const SkRect r = SkRect::MakeIWH(yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fWidth, 1474984c3c95f18eda44492a2126c9958e447f2cca8msarett yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight); 14843fe6185c5043247c47daa450b015e26d86728fereed 149846c051a4800b3cea341a0195db24297d6d9047fcdalton drawContext->drawRect(GrNoClip(), paint, SkMatrix::I(), r); 15043fe6185c5043247c47daa450b015e26d86728fereed 151677da9d4af2558ddd50a900e90a093d1b522bd5frobertphillips return drawContext->asTexture(); 15243fe6185c5043247c47daa450b015e26d86728fereed} 153