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