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