OLD | NEW |
---|---|
(Empty) | |
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 "GrDrawContext.h" | |
14 #include "GrPaint.h" | |
15 #include "GrTextureProvider.h" | |
16 | |
17 namespace { | |
18 using CreateFPProc = const GrFragmentProcessor* (*)(const GrFragmentProcesso r*, | |
19 SkYUVColorSpace colorSpa ce); | |
20 }; | |
21 | |
22 static bool convert_texture(GrTexture* src, GrDrawContext* dst, int dstW, int ds tH, | |
23 SkYUVColorSpace colorSpace, CreateFPProc proc) { | |
24 | |
25 SkScalar xScale = SkIntToScalar(src->width()) / dstW / src->width(); | |
26 SkScalar yScale = SkIntToScalar(src->height()) / dstH / src->height(); | |
27 GrTextureParams::FilterMode filter; | |
28 if (dstW == src->width() && dstW == src->height()) { | |
29 filter = GrTextureParams::kNone_FilterMode; | |
30 } else { | |
31 filter = GrTextureParams::kBilerp_FilterMode; | |
32 } | |
33 | |
34 SkAutoTUnref<const GrFragmentProcessor> fp( | |
35 GrSimpleTextureEffect::Create(src, SkMatrix::MakeScale(xScale, yScal e), filter)); | |
36 if (!fp) { | |
37 return false; | |
38 } | |
39 fp.reset(proc(fp, colorSpace)); | |
40 if (!fp) { | |
41 return false; | |
42 } | |
43 GrPaint paint; | |
44 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); | |
45 paint.addColorFragmentProcessor(fp); | |
46 dst->drawRect(GrClip::WideOpen(), paint, SkMatrix::I(), SkRect::MakeIWH(dstW , dstH)); | |
47 return true; | |
48 } | |
49 | |
50 bool GrTextureToYUVPlanes(GrTexture* texture, const SkISize sizes[3], void* cons t planes[3], | |
51 const size_t rowBytes[3], SkYUVColorSpace colorSpace) { | |
52 if (GrContext* context = texture->getContext()) { | |
53 // Depending on the relative sizes of the y, u, and v planes we may do 1 to 3 draws/ | |
54 // readbacks. | |
55 SkAutoTUnref<GrTexture> yuvTex; | |
56 SkAutoTUnref<GrTexture> yTex; | |
57 SkAutoTUnref<GrTexture> uvTex; | |
58 SkAutoTUnref<GrTexture> uTex; | |
59 SkAutoTUnref<GrTexture> vTex; | |
60 | |
61 GrPixelConfig singleChannelPixelConfig; | |
62 if (context->caps()->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) { | |
63 singleChannelPixelConfig = kAlpha_8_GrPixelConfig; | |
64 } else { | |
65 singleChannelPixelConfig = kRGBA_8888_GrPixelConfig; | |
66 } | |
67 | |
68 if (sizes[0] == sizes[1] && sizes[1] == sizes[2]) { | |
robertphillips
2016/01/29 20:33:13
// YUV444 - only 1 draw/readback
?
bsalomon
2016/02/01 20:27:45
I put a comment above the first if about the three
| |
69 GrSurfaceDesc yuvDesc; | |
70 yuvDesc.fConfig = kRGBA_8888_GrPixelConfig; | |
71 yuvDesc.fFlags = kRenderTarget_GrSurfaceFlag; | |
72 yuvDesc.fWidth = sizes[0].fWidth; | |
73 yuvDesc.fHeight = sizes[0].fHeight; | |
74 yuvTex.reset(context->textureProvider()->createApproxTexture(yuvDesc )); | |
75 if (!yuvTex) { | |
76 return false; | |
77 } | |
78 } else { | |
79 GrSurfaceDesc yDesc; | |
80 yDesc.fConfig = singleChannelPixelConfig; | |
81 yDesc.fFlags = kRenderTarget_GrSurfaceFlag; | |
82 yDesc.fWidth = sizes[0].fWidth; | |
83 yDesc.fHeight = sizes[0].fHeight; | |
84 yTex.reset(context->textureProvider()->createApproxTexture(yDesc)); | |
85 if (!yTex) { | |
86 return false; | |
87 } | |
88 if (sizes[1] == sizes[2]) { | |
robertphillips
2016/01/29 20:33:13
// Something like 422 or 411 - only 2 draws/readba
| |
89 GrSurfaceDesc uvDesc; | |
90 // TODO: Add support for GL_RG when available. | |
91 uvDesc.fConfig = kRGBA_8888_GrPixelConfig; | |
92 uvDesc.fFlags = kRenderTarget_GrSurfaceFlag; | |
93 uvDesc.fWidth = sizes[1].fWidth; | |
94 uvDesc.fHeight = sizes[1].fHeight; | |
95 uvTex.reset(context->textureProvider()->createApproxTexture(uvDe sc)); | |
96 if (!uvTex) { | |
97 return false; | |
98 } | |
99 } else { | |
robertphillips
2016/01/29 20:33:13
// Each channel is different sized - 3 draws/readb
| |
100 GrSurfaceDesc uvDesc; | |
101 uvDesc.fConfig = singleChannelPixelConfig; | |
102 uvDesc.fFlags = kRenderTarget_GrSurfaceFlag; | |
103 uvDesc.fWidth = sizes[1].fWidth; | |
104 uvDesc.fHeight = sizes[1].fHeight; | |
105 uTex.reset(context->textureProvider()->createApproxTexture(uvDes c)); | |
106 uvDesc.fWidth = sizes[2].fWidth; | |
107 uvDesc.fHeight = sizes[2].fHeight; | |
108 vTex.reset(context->textureProvider()->createApproxTexture(uvDes c)); | |
109 if (!uTex || !vTex) { | |
110 return false; | |
111 } | |
112 } | |
113 } | |
114 | |
115 // Do all the draws before any readback. | |
116 if (yuvTex) { | |
117 SkAutoTUnref<GrDrawContext> dc(context->drawContext(yuvTex->asRender Target())); | |
118 if (!dc) { | |
119 return false; | |
120 } | |
121 if (!convert_texture(texture, dc, sizes[0].fWidth, sizes[0].fHeight, colorSpace, | |
122 GrYUVEffect::CreateRGBToYUV)) { | |
123 return false; | |
124 } | |
125 | |
126 } else { | |
127 SkASSERT(yTex); | |
128 SkAutoTUnref<GrDrawContext> dc(context->drawContext(yTex->asRenderTa rget())); | |
129 if (!dc) { | |
130 return false; | |
131 } | |
132 if (!convert_texture(texture, dc, sizes[0].fWidth, sizes[0].fHeight, colorSpace, | |
133 GrYUVEffect::CreateRGBToY)) { | |
134 return false; | |
135 } | |
136 if (uvTex) { | |
137 dc.reset(context->drawContext(uvTex->asRenderTarget())); | |
138 if (!dc) { | |
139 return false; | |
140 } | |
141 if (!convert_texture(texture, dc, sizes[1].fWidth, sizes[1].fHei ght, | |
142 colorSpace, GrYUVEffect::CreateRGBToUV)) { | |
143 return false; | |
144 } | |
145 } else { | |
146 SkASSERT(uTex && vTex); | |
147 dc.reset(context->drawContext(uTex->asRenderTarget())); | |
148 if (!dc) { | |
149 return false; | |
150 } | |
151 if (!convert_texture(texture, dc, sizes[1].fWidth, sizes[1].fHei ght, | |
152 colorSpace, GrYUVEffect::CreateRGBToU)) { | |
153 return false; | |
154 } | |
155 dc.reset(context->drawContext(vTex->asRenderTarget())); | |
156 if (!dc) { | |
157 return false; | |
158 } | |
159 if (!convert_texture(texture, dc, sizes[2].fWidth, sizes[2].fHei ght, | |
160 colorSpace, GrYUVEffect::CreateRGBToV)) { | |
161 return false; | |
162 } | |
163 } | |
164 } | |
165 | |
166 if (yuvTex) { | |
robertphillips
2016/01/29 20:33:13
The use of sizes[0], [1] & [2] mildly bothers me h
bsalomon
2016/02/01 20:27:45
Compromise - assert and then use another scoped va
| |
167 // We have no kRGB_888 pixel format, so readback rgba and then copy three channels. | |
168 SkAutoSTMalloc<128 * 128, uint32_t> tempYUV(sizes[0].fWidth * sizes[ 0].fHeight); | |
169 if (!yuvTex->readPixels(0, 0, sizes[0].fWidth, sizes[0].fHeight, | |
170 kRGBA_8888_GrPixelConfig, tempYUV.get(), 0)) { | |
171 return false; | |
172 } | |
173 size_t yRowBytes = rowBytes[0] ? rowBytes[0] : sizes[0].fWidth; | |
174 size_t uRowBytes = rowBytes[1] ? rowBytes[1] : sizes[1].fWidth; | |
175 size_t vRowBytes = rowBytes[2] ? rowBytes[2] : sizes[2].fWidth; | |
176 for (int j = 0; j < sizes[1].fHeight; ++j) { | |
177 for (int i = 0; i < sizes[1].fWidth; ++i) { | |
178 // These writes could surely be made more efficient. | |
179 uint32_t y = GrColorUnpackR(tempYUV.get()[j * sizes[1].fWidt h + i]); | |
180 uint32_t u = GrColorUnpackG(tempYUV.get()[j * sizes[1].fWidt h + i]); | |
181 uint32_t v = GrColorUnpackB(tempYUV.get()[j * sizes[1].fWidt h + i]); | |
182 uint8_t* yLoc = ((uint8_t*)planes[0]) + j * yRowBytes + i; | |
183 uint8_t* uLoc = ((uint8_t*)planes[1]) + j * uRowBytes + i; | |
184 uint8_t* vLoc = ((uint8_t*)planes[2]) + j * vRowBytes + i; | |
185 *yLoc = y; | |
186 *uLoc = u; | |
187 *vLoc = v; | |
188 } | |
189 } | |
190 return true; | |
191 } else { | |
192 SkASSERT(yTex); | |
193 if (!yTex->readPixels(0, 0, sizes[0].fWidth, sizes[0].fHeight, | |
194 kAlpha_8_GrPixelConfig, planes[0], rowBytes[0] )) { | |
195 return false; | |
196 } | |
197 if (uvTex) { | |
198 // We have no kRG_88 pixel format, so readback rgba and then cop y two channels. | |
199 SkAutoSTMalloc<128 * 128, uint32_t> tempUV(sizes[1].fWidth * siz es[1].fHeight); | |
200 if (!uvTex->readPixels(0, 0, sizes[1].fWidth, sizes[1].fHeight, | |
201 kRGBA_8888_GrPixelConfig, tempUV.get(), 0 )) { | |
202 return false; | |
203 } | |
robertphillips
2016/01/29 20:33:13
SkASSERT(sizes[1].fWidth == sizes[2].fWidth); ?
bsalomon
2016/02/01 20:27:45
Done.
| |
204 size_t uRowBytes = rowBytes[1] ? rowBytes[1] : sizes[1].fWidth; | |
205 size_t vRowBytes = rowBytes[2] ? rowBytes[2] : sizes[2].fWidth; | |
206 for (int j = 0; j < sizes[1].fHeight; ++j) { | |
207 for (int i = 0; i < sizes[1].fWidth; ++i) { | |
208 // These writes could surely be made more efficient. | |
209 uint32_t u = GrColorUnpackR(tempUV.get()[j * sizes[1].fW idth + i]); | |
210 uint32_t v = GrColorUnpackG(tempUV.get()[j * sizes[1].fW idth + i]); | |
211 uint8_t* uLoc = ((uint8_t*)planes[1]) + j * uRowBytes + i; | |
212 uint8_t* vLoc = ((uint8_t*)planes[2]) + j * vRowBytes + i; | |
213 *uLoc = u; | |
214 *vLoc = v; | |
215 } | |
216 } | |
217 return true; | |
218 } else { | |
219 SkASSERT(uTex && vTex); | |
220 if (!uTex->readPixels(0, 0, sizes[1].fWidth, sizes[1].fHeight, | |
221 kAlpha_8_GrPixelConfig, planes[1], rowByte s[1])) { | |
222 return false; | |
223 } | |
224 if (!vTex->readPixels(0, 0, sizes[2].fWidth, sizes[2].fHeight, | |
225 kAlpha_8_GrPixelConfig, planes[2], rowByte s[2])) { | |
226 return false; | |
227 } | |
228 return true; | |
229 } | |
230 } | |
231 } | |
232 return false; | |
233 } | |
OLD | NEW |