Line data Source code
1 : /*
2 : * Copyright 2016 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 "GrTextureToYUVPlanes.h"
9 : #include "effects/GrSimpleTextureEffect.h"
10 : #include "effects/GrYUVEffect.h"
11 : #include "GrClip.h"
12 : #include "GrContext.h"
13 : #include "GrPaint.h"
14 : #include "GrRenderTargetContext.h"
15 : #include "GrResourceProvider.h"
16 :
17 : namespace {
18 : using MakeFPProc = sk_sp<GrFragmentProcessor> (*)(sk_sp<GrFragmentProcessor>,
19 : SkYUVColorSpace colorSpace);
20 : };
21 :
22 0 : static bool convert_proxy(sk_sp<GrTextureProxy> src,
23 : GrRenderTargetContext* dst, int dstW, int dstH,
24 : SkYUVColorSpace colorSpace, MakeFPProc proc) {
25 :
26 0 : SkScalar xScale = SkIntToScalar(src->width()) / dstW;
27 0 : SkScalar yScale = SkIntToScalar(src->height()) / dstH;
28 : GrSamplerParams::FilterMode filter;
29 0 : if (dstW == src->width() && dstW == src->height()) {
30 0 : filter = GrSamplerParams::kNone_FilterMode;
31 : } else {
32 0 : filter = GrSamplerParams::kBilerp_FilterMode;
33 : }
34 :
35 0 : GrResourceProvider* resourceProvider = dst->resourceProvider();
36 :
37 0 : sk_sp<GrFragmentProcessor> fp(GrSimpleTextureEffect::Make(resourceProvider, std::move(src),
38 : nullptr,
39 0 : SkMatrix::MakeScale(xScale, yScale),
40 0 : filter));
41 0 : if (!fp) {
42 0 : return false;
43 : }
44 0 : fp = proc(std::move(fp), colorSpace);
45 0 : if (!fp) {
46 0 : return false;
47 : }
48 0 : GrPaint paint;
49 0 : paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
50 0 : paint.addColorFragmentProcessor(std::move(fp));
51 0 : dst->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(),
52 0 : SkRect::MakeIWH(dstW, dstH));
53 0 : return true;
54 : }
55 :
56 0 : bool GrTextureToYUVPlanes(GrContext* context, sk_sp<GrTextureProxy> proxy,
57 : const SkISize sizes[3], void* const planes[3],
58 : const size_t rowBytes[3], SkYUVColorSpace colorSpace) {
59 0 : if (!context) {
60 0 : return false;
61 : }
62 :
63 : {
64 : // Depending on the relative sizes of the y, u, and v planes we may do 1 to 3 draws/
65 : // readbacks.
66 0 : sk_sp<GrRenderTargetContext> yuvRenderTargetContext;
67 0 : sk_sp<GrRenderTargetContext> yRenderTargetContext;
68 0 : sk_sp<GrRenderTargetContext> uvRenderTargetContext;
69 0 : sk_sp<GrRenderTargetContext> uRenderTargetContext;
70 0 : sk_sp<GrRenderTargetContext> vRenderTargetContext;
71 :
72 : // We issue draw(s) to convert from RGBA to Y, U, and V. All three planes may have different
73 : // sizes however we optimize for two other cases - all planes are the same (1 draw to YUV),
74 : // and U and V are the same but Y differs (2 draws, one for Y, one for UV).
75 0 : if (sizes[0] == sizes[1] && sizes[1] == sizes[2]) {
76 0 : yuvRenderTargetContext = context->makeRenderTargetContextWithFallback(
77 : SkBackingFit::kApprox,
78 0 : sizes[0].fWidth,
79 0 : sizes[0].fHeight,
80 : kRGBA_8888_GrPixelConfig,
81 0 : nullptr);
82 0 : if (!yuvRenderTargetContext) {
83 0 : return false;
84 : }
85 : } else {
86 0 : yRenderTargetContext = context->makeRenderTargetContextWithFallback(
87 : SkBackingFit::kApprox,
88 0 : sizes[0].fWidth,
89 0 : sizes[0].fHeight,
90 : kAlpha_8_GrPixelConfig,
91 0 : nullptr);
92 0 : if (!yRenderTargetContext) {
93 0 : return false;
94 : }
95 0 : if (sizes[1] == sizes[2]) {
96 : // TODO: Add support for GL_RG when available.
97 0 : uvRenderTargetContext = context->makeRenderTargetContextWithFallback(
98 : SkBackingFit::kApprox,
99 0 : sizes[1].fWidth,
100 0 : sizes[1].fHeight,
101 : kRGBA_8888_GrPixelConfig,
102 0 : nullptr);
103 0 : if (!uvRenderTargetContext) {
104 0 : return false;
105 : }
106 : } else {
107 0 : uRenderTargetContext = context->makeRenderTargetContextWithFallback(
108 : SkBackingFit::kApprox,
109 0 : sizes[1].fWidth,
110 0 : sizes[1].fHeight,
111 : kAlpha_8_GrPixelConfig,
112 0 : nullptr);
113 0 : vRenderTargetContext = context->makeRenderTargetContextWithFallback(
114 : SkBackingFit::kApprox,
115 0 : sizes[2].fWidth,
116 0 : sizes[2].fHeight,
117 : kAlpha_8_GrPixelConfig,
118 0 : nullptr);
119 0 : if (!uRenderTargetContext || !vRenderTargetContext) {
120 0 : return false;
121 : }
122 : }
123 : }
124 :
125 : // Do all the draws before any readback.
126 0 : if (yuvRenderTargetContext) {
127 0 : if (!convert_proxy(std::move(proxy), yuvRenderTargetContext.get(),
128 0 : sizes[0].fWidth, sizes[0].fHeight,
129 : colorSpace, GrYUVEffect::MakeRGBToYUV)) {
130 0 : return false;
131 : }
132 : } else {
133 0 : SkASSERT(yRenderTargetContext);
134 0 : if (!convert_proxy(proxy, yRenderTargetContext.get(),
135 0 : sizes[0].fWidth, sizes[0].fHeight,
136 : colorSpace, GrYUVEffect::MakeRGBToY)) {
137 0 : return false;
138 : }
139 0 : if (uvRenderTargetContext) {
140 0 : if (!convert_proxy(std::move(proxy), uvRenderTargetContext.get(),
141 0 : sizes[1].fWidth, sizes[1].fHeight,
142 : colorSpace, GrYUVEffect::MakeRGBToUV)) {
143 0 : return false;
144 : }
145 : } else {
146 0 : SkASSERT(uRenderTargetContext && vRenderTargetContext);
147 0 : if (!convert_proxy(proxy, uRenderTargetContext.get(),
148 0 : sizes[1].fWidth, sizes[1].fHeight,
149 : colorSpace, GrYUVEffect::MakeRGBToU)) {
150 0 : return false;
151 : }
152 0 : if (!convert_proxy(std::move(proxy), vRenderTargetContext.get(),
153 0 : sizes[2].fWidth, sizes[2].fHeight,
154 : colorSpace, GrYUVEffect::MakeRGBToV)) {
155 0 : return false;
156 : }
157 : }
158 : }
159 :
160 0 : if (yuvRenderTargetContext) {
161 0 : SkASSERT(sizes[0] == sizes[1] && sizes[1] == sizes[2]);
162 0 : SkISize yuvSize = sizes[0];
163 : // We have no kRGB_888 pixel format, so readback rgba and then copy three channels.
164 0 : SkAutoSTMalloc<128 * 128, uint32_t> tempYUV(yuvSize.fWidth * yuvSize.fHeight);
165 :
166 : const SkImageInfo ii = SkImageInfo::Make(yuvSize.fWidth, yuvSize.fHeight,
167 0 : kRGBA_8888_SkColorType, kOpaque_SkAlphaType);
168 0 : if (!yuvRenderTargetContext->readPixels(ii, tempYUV.get(), 0, 0, 0)) {
169 0 : return false;
170 : }
171 0 : size_t yRowBytes = rowBytes[0] ? rowBytes[0] : yuvSize.fWidth;
172 0 : size_t uRowBytes = rowBytes[1] ? rowBytes[1] : yuvSize.fWidth;
173 0 : size_t vRowBytes = rowBytes[2] ? rowBytes[2] : yuvSize.fWidth;
174 0 : if (yRowBytes < (size_t)yuvSize.fWidth || uRowBytes < (size_t)yuvSize.fWidth ||
175 0 : vRowBytes < (size_t)yuvSize.fWidth) {
176 0 : return false;
177 : }
178 0 : for (int j = 0; j < yuvSize.fHeight; ++j) {
179 0 : for (int i = 0; i < yuvSize.fWidth; ++i) {
180 : // These writes could surely be made more efficient.
181 0 : uint32_t y = GrColorUnpackR(tempYUV.get()[j * yuvSize.fWidth + i]);
182 0 : uint32_t u = GrColorUnpackG(tempYUV.get()[j * yuvSize.fWidth + i]);
183 0 : uint32_t v = GrColorUnpackB(tempYUV.get()[j * yuvSize.fWidth + i]);
184 0 : uint8_t* yLoc = ((uint8_t*)planes[0]) + j * yRowBytes + i;
185 0 : uint8_t* uLoc = ((uint8_t*)planes[1]) + j * uRowBytes + i;
186 0 : uint8_t* vLoc = ((uint8_t*)planes[2]) + j * vRowBytes + i;
187 0 : *yLoc = y;
188 0 : *uLoc = u;
189 0 : *vLoc = v;
190 : }
191 : }
192 0 : return true;
193 : } else {
194 0 : SkASSERT(yRenderTargetContext);
195 :
196 0 : SkImageInfo ii = SkImageInfo::MakeA8(sizes[0].fWidth, sizes[0].fHeight);
197 0 : if (!yRenderTargetContext->readPixels(ii, planes[0], rowBytes[0], 0, 0)) {
198 0 : return false;
199 : }
200 :
201 0 : if (uvRenderTargetContext) {
202 0 : SkASSERT(sizes[1].fWidth == sizes[2].fWidth);
203 0 : SkISize uvSize = sizes[1];
204 : // We have no kRG_88 pixel format, so readback rgba and then copy two channels.
205 0 : SkAutoSTMalloc<128 * 128, uint32_t> tempUV(uvSize.fWidth * uvSize.fHeight);
206 :
207 0 : ii = SkImageInfo::Make(uvSize.fWidth, uvSize.fHeight,
208 0 : kRGBA_8888_SkColorType, kOpaque_SkAlphaType);
209 :
210 0 : if (!uvRenderTargetContext->readPixels(ii, tempUV.get(), 0, 0, 0)) {
211 0 : return false;
212 : }
213 :
214 0 : size_t uRowBytes = rowBytes[1] ? rowBytes[1] : uvSize.fWidth;
215 0 : size_t vRowBytes = rowBytes[2] ? rowBytes[2] : uvSize.fWidth;
216 0 : if (uRowBytes < (size_t)uvSize.fWidth || vRowBytes < (size_t)uvSize.fWidth) {
217 0 : return false;
218 : }
219 0 : for (int j = 0; j < uvSize.fHeight; ++j) {
220 0 : for (int i = 0; i < uvSize.fWidth; ++i) {
221 : // These writes could surely be made more efficient.
222 0 : uint32_t u = GrColorUnpackR(tempUV.get()[j * uvSize.fWidth + i]);
223 0 : uint32_t v = GrColorUnpackG(tempUV.get()[j * uvSize.fWidth + i]);
224 0 : uint8_t* uLoc = ((uint8_t*)planes[1]) + j * uRowBytes + i;
225 0 : uint8_t* vLoc = ((uint8_t*)planes[2]) + j * vRowBytes + i;
226 0 : *uLoc = u;
227 0 : *vLoc = v;
228 : }
229 : }
230 0 : return true;
231 : } else {
232 0 : SkASSERT(uRenderTargetContext && vRenderTargetContext);
233 :
234 0 : ii = SkImageInfo::MakeA8(sizes[1].fWidth, sizes[1].fHeight);
235 0 : if (!uRenderTargetContext->readPixels(ii, planes[1], rowBytes[1], 0, 0)) {
236 0 : return false;
237 : }
238 :
239 0 : ii = SkImageInfo::MakeA8(sizes[2].fWidth, sizes[2].fHeight);
240 0 : if (!vRenderTargetContext->readPixels(ii, planes[2], rowBytes[2], 0, 0)) {
241 0 : return false;
242 : }
243 :
244 0 : return true;
245 : }
246 : }
247 : }
248 : return false;
249 : }
|