Line data Source code
1 : /*
2 : * Copyright 2015 Google Inc.
3 : *
4 : * Use of this source code is governed by a BSD-style license that can be
5 : * found in the LICENSE file.
6 : */
7 :
8 : #include "GrYUVProvider.h"
9 : #include "GrClip.h"
10 : #include "GrContext.h"
11 : #include "GrContextPriv.h"
12 : #include "GrRenderTargetContext.h"
13 : #include "GrTextureProxy.h"
14 : #include "SkAutoMalloc.h"
15 : #include "SkCachedData.h"
16 : #include "SkRefCnt.h"
17 : #include "SkResourceCache.h"
18 : #include "SkYUVPlanesCache.h"
19 : #include "effects/GrSRGBEffect.h"
20 : #include "effects/GrYUVEffect.h"
21 :
22 : namespace {
23 : /**
24 : * Helper class to manage the resources used for storing the YUV planar data. Depending on the
25 : * useCache option, we may find (and lock) the data in our ResourceCache, or we may have allocated
26 : * it in scratch storage.
27 : */
28 0 : class YUVScoper {
29 : public:
30 : bool init(GrYUVProvider*, SkYUVPlanesCache::Info*, void* planes[3], bool useCache);
31 :
32 : private:
33 : // we only use one or the other of these
34 : sk_sp<SkCachedData> fCachedData;
35 : SkAutoMalloc fStorage;
36 : };
37 : }
38 :
39 0 : bool YUVScoper::init(GrYUVProvider* provider, SkYUVPlanesCache::Info* yuvInfo, void* planes[3],
40 : bool useCache) {
41 0 : if (useCache) {
42 0 : fCachedData.reset(SkYUVPlanesCache::FindAndRef(provider->onGetID(), yuvInfo));
43 : }
44 :
45 0 : if (fCachedData.get()) {
46 0 : planes[0] = (void*)fCachedData->data();
47 0 : planes[1] = (uint8_t*)planes[0] + (yuvInfo->fSizeInfo.fWidthBytes[SkYUVSizeInfo::kY] *
48 0 : yuvInfo->fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight);
49 0 : planes[2] = (uint8_t*)planes[1] + (yuvInfo->fSizeInfo.fWidthBytes[SkYUVSizeInfo::kU] *
50 0 : yuvInfo->fSizeInfo.fSizes[SkYUVSizeInfo::kU].fHeight);
51 : } else {
52 : // Fetch yuv plane sizes for memory allocation.
53 0 : if (!provider->onQueryYUV8(&yuvInfo->fSizeInfo, &yuvInfo->fColorSpace)) {
54 0 : return false;
55 : }
56 :
57 : // Allocate the memory for YUV
58 0 : size_t totalSize(0);
59 0 : for (int i = 0; i < 3; i++) {
60 0 : totalSize += yuvInfo->fSizeInfo.fWidthBytes[i] * yuvInfo->fSizeInfo.fSizes[i].fHeight;
61 : }
62 0 : if (useCache) {
63 0 : fCachedData.reset(SkResourceCache::NewCachedData(totalSize));
64 0 : planes[0] = fCachedData->writable_data();
65 : } else {
66 0 : fStorage.reset(totalSize);
67 0 : planes[0] = fStorage.get();
68 : }
69 0 : planes[1] = (uint8_t*)planes[0] + (yuvInfo->fSizeInfo.fWidthBytes[SkYUVSizeInfo::kY] *
70 0 : yuvInfo->fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight);
71 0 : planes[2] = (uint8_t*)planes[1] + (yuvInfo->fSizeInfo.fWidthBytes[SkYUVSizeInfo::kU] *
72 0 : yuvInfo->fSizeInfo.fSizes[SkYUVSizeInfo::kU].fHeight);
73 :
74 : // Get the YUV planes.
75 0 : if (!provider->onGetYUV8Planes(yuvInfo->fSizeInfo, planes)) {
76 0 : return false;
77 : }
78 :
79 0 : if (useCache) {
80 : // Decoding is done, cache the resulting YUV planes
81 0 : SkYUVPlanesCache::Add(provider->onGetID(), fCachedData.get(), yuvInfo);
82 : }
83 : }
84 0 : return true;
85 : }
86 :
87 0 : sk_sp<GrTextureProxy> GrYUVProvider::refAsTextureProxy(GrContext* ctx,
88 : const GrSurfaceDesc& desc,
89 : bool useCache) {
90 : SkYUVPlanesCache::Info yuvInfo;
91 : void* planes[3];
92 0 : YUVScoper scoper;
93 0 : if (!scoper.init(this, &yuvInfo, planes, useCache)) {
94 0 : return nullptr;
95 : }
96 :
97 0 : GrSurfaceDesc yuvDesc;
98 0 : yuvDesc.fOrigin = kTopLeft_GrSurfaceOrigin;
99 0 : yuvDesc.fConfig = kAlpha_8_GrPixelConfig;
100 0 : sk_sp<GrSurfaceContext> yuvTextureContexts[3];
101 0 : for (int i = 0; i < 3; i++) {
102 0 : yuvDesc.fWidth = yuvInfo.fSizeInfo.fSizes[i].fWidth;
103 0 : yuvDesc.fHeight = yuvInfo.fSizeInfo.fSizes[i].fHeight;
104 : // TODO: why do we need this check?
105 : SkBackingFit fit =
106 0 : (yuvDesc.fWidth != yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fWidth) ||
107 0 : (yuvDesc.fHeight != yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight)
108 0 : ? SkBackingFit::kExact : SkBackingFit::kApprox;
109 :
110 0 : yuvTextureContexts[i] = ctx->contextPriv().makeDeferredSurfaceContext(yuvDesc, fit,
111 0 : SkBudgeted::kYes);
112 0 : if (!yuvTextureContexts[i]) {
113 0 : return nullptr;
114 : }
115 :
116 0 : const SkImageInfo ii = SkImageInfo::MakeA8(yuvDesc.fWidth, yuvDesc.fHeight);
117 0 : if (!yuvTextureContexts[i]->writePixels(ii, planes[i],
118 : yuvInfo.fSizeInfo.fWidthBytes[i], 0, 0)) {
119 0 : return nullptr;
120 : }
121 : }
122 :
123 : // We never want to perform color-space conversion during the decode
124 : sk_sp<GrRenderTargetContext> renderTargetContext(ctx->makeRenderTargetContext(
125 : SkBackingFit::kExact,
126 0 : desc.fWidth, desc.fHeight,
127 0 : desc.fConfig, nullptr,
128 0 : desc.fSampleCnt));
129 0 : if (!renderTargetContext) {
130 0 : return nullptr;
131 : }
132 :
133 0 : GrPaint paint;
134 : sk_sp<GrFragmentProcessor> yuvToRgbProcessor(
135 : GrYUVEffect::MakeYUVToRGB(ctx->resourceProvider(),
136 0 : yuvTextureContexts[0]->asTextureProxyRef(),
137 0 : yuvTextureContexts[1]->asTextureProxyRef(),
138 0 : yuvTextureContexts[2]->asTextureProxyRef(),
139 0 : yuvInfo.fSizeInfo.fSizes, yuvInfo.fColorSpace, false));
140 0 : paint.addColorFragmentProcessor(std::move(yuvToRgbProcessor));
141 :
142 : // If we're decoding an sRGB image, the result of our linear math on the YUV planes is already
143 : // in sRGB. (The encoding is just math on bytes, with no concept of color spaces.) So, we need
144 : // to output the results of that math directly to the buffer that we will then consider sRGB.
145 : // If we have sRGB write control, we can just tell the HW not to do the Linear -> sRGB step.
146 : // Otherwise, we do our shader math to go from YUV -> sRGB, manually convert sRGB -> Linear,
147 : // then let the HW convert Linear -> sRGB.
148 0 : if (GrPixelConfigIsSRGB(desc.fConfig)) {
149 0 : if (ctx->caps()->srgbWriteControl()) {
150 0 : paint.setDisableOutputConversionToSRGB(true);
151 : } else {
152 0 : paint.addColorFragmentProcessor(GrSRGBEffect::Make(GrSRGBEffect::Mode::kSRGBToLinear));
153 : }
154 : }
155 :
156 0 : paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
157 : const SkRect r = SkRect::MakeIWH(yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fWidth,
158 0 : yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight);
159 :
160 0 : renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), r);
161 :
162 0 : return renderTargetContext->asTextureProxyRef();
163 : }
|