blob: d6acf753f65548291a7e298610de218dc9d8ab8f [file] [log] [blame]
Michael Ludwigd9958f82019-03-21 13:08:36 -04001/*
2 * Copyright 2019 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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "tools/gpu/YUVUtils.h"
Michael Ludwigd9958f82019-03-21 13:08:36 -04009
Brian Salomon7db71392020-10-16 10:05:21 -040010#include "include/core/SkColorPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "include/core/SkData.h"
Brian Salomonefb5f072020-07-28 21:06:43 -040012#include "include/gpu/GrRecordingContext.h"
Brian Salomonc1a249d2020-10-19 10:55:45 -040013#include "include/gpu/GrYUVABackendTextures.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "src/codec/SkCodecImageGenerator.h"
Brian Salomon7db71392020-10-16 10:05:21 -040015#include "src/core/SkYUVMath.h"
Adlai Hollera0693042020-10-14 11:23:11 -040016#include "src/gpu/GrDirectContextPriv.h"
Brian Salomonefb5f072020-07-28 21:06:43 -040017#include "src/gpu/GrRecordingContextPriv.h"
Brian Salomon7db71392020-10-16 10:05:21 -040018#include "tools/gpu/ManagedBackendTexture.h"
19
20namespace {
21
22static SkPMColor convert_yuva_to_rgba(const float mtx[20], uint8_t yuva[4]) {
23 uint8_t y = yuva[0];
24 uint8_t u = yuva[1];
25 uint8_t v = yuva[2];
26 uint8_t a = yuva[3];
27
28 uint8_t r = SkTPin(SkScalarRoundToInt(mtx[ 0]*y + mtx[ 1]*u + mtx[ 2]*v + mtx[ 4]*255), 0, 255);
29 uint8_t g = SkTPin(SkScalarRoundToInt(mtx[ 5]*y + mtx[ 6]*u + mtx[ 7]*v + mtx[ 9]*255), 0, 255);
30 uint8_t b = SkTPin(SkScalarRoundToInt(mtx[10]*y + mtx[11]*u + mtx[12]*v + mtx[14]*255), 0, 255);
31
32 return SkPremultiplyARGBInline(a, r, g, b);
33}
34
35static uint8_t look_up(float x1, float y1, const SkPixmap& pmap, SkColorChannel channel) {
36 SkASSERT(x1 > 0 && x1 < 1.0f);
37 SkASSERT(y1 > 0 && y1 < 1.0f);
38 int x = SkScalarFloorToInt(x1 * pmap.width());
39 int y = SkScalarFloorToInt(y1 * pmap.height());
40
41 auto ii = pmap.info().makeColorType(kRGBA_8888_SkColorType).makeWH(1, 1);
42 uint32_t pixel;
43 SkAssertResult(pmap.readPixels(ii, &pixel, sizeof(pixel), x, y));
44 int shift = static_cast<int>(channel) * 8;
45 return static_cast<uint8_t>((pixel >> shift) & 0xff);
46}
47
48class Generator : public SkImageGenerator {
49public:
50 Generator(SkYUVAPixmaps pixmaps, sk_sp<SkColorSpace> cs)
51 : SkImageGenerator(SkImageInfo::Make(pixmaps.yuvaInfo().dimensions(),
52 kN32_SkColorType,
53 kPremul_SkAlphaType,
54 std::move(cs)))
55 , fPixmaps(std::move(pixmaps)) {}
56
57protected:
58 bool onGetPixels(const SkImageInfo& info,
59 void* pixels,
60 size_t rowBytes,
61 const Options&) override {
62 if (kUnknown_SkColorType == fFlattened.colorType()) {
63 fFlattened.allocPixels(info);
64 SkASSERT(info == this->getInfo());
65
66 float mtx[20];
67 SkColorMatrix_YUV2RGB(fPixmaps.yuvaInfo().yuvColorSpace(), mtx);
68 SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount];
69 SkAssertResult(fPixmaps.toYUVAIndices(yuvaIndices));
70
71 for (int y = 0; y < info.height(); ++y) {
72 for (int x = 0; x < info.width(); ++x) {
73 float x1 = (x + 0.5f) / info.width();
74 float y1 = (y + 0.5f) / info.height();
75
76 uint8_t yuva[4] = {0, 0, 0, 255};
77
78 for (auto c : {SkYUVAIndex::kY_Index,
79 SkYUVAIndex::kU_Index,
80 SkYUVAIndex::kV_Index}) {
81 const auto& pmap = fPixmaps.plane(yuvaIndices[c].fIndex);
82 yuva[c] = look_up(x1, y1, pmap, yuvaIndices[c].fChannel);
83 }
84 if (yuvaIndices[SkYUVAIndex::kA_Index].fIndex >= 0) {
85 const auto& pmap =
86 fPixmaps.plane(yuvaIndices[SkYUVAIndex::kA_Index].fIndex);
87 yuva[3] =
88 look_up(x1, y1, pmap, yuvaIndices[SkYUVAIndex::kA_Index].fChannel);
89 }
90
91 // Making premul here.
92 *fFlattened.getAddr32(x, y) = convert_yuva_to_rgba(mtx, yuva);
93 }
94 }
95 }
96
97 return fFlattened.readPixels(info, pixels, rowBytes, 0, 0);
98 }
99
100 bool onQueryYUVAInfo(const SkYUVAPixmapInfo::SupportedDataTypes& types,
101 SkYUVAPixmapInfo* info) const override {
102 *info = fPixmaps.pixmapsInfo();
103 return info->isValid();
104 }
105
106 bool onGetYUVAPlanes(const SkYUVAPixmaps& pixmaps) override {
107 SkASSERT(pixmaps.yuvaInfo() == fPixmaps.yuvaInfo());
108 for (int i = 0; i < pixmaps.numPlanes(); ++i) {
109 SkASSERT(fPixmaps.plane(i).colorType() == pixmaps.plane(i).colorType());
110 SkASSERT(fPixmaps.plane(i).dimensions() == pixmaps.plane(i).dimensions());
111 SkASSERT(fPixmaps.plane(i).rowBytes() == pixmaps.plane(i).rowBytes());
112 fPixmaps.plane(i).readPixels(pixmaps.plane(i));
113 }
114 return true;
115 }
116
117private:
118 SkYUVAPixmaps fPixmaps;
119 SkBitmap fFlattened;
120};
121
122} // anonymous namespace
Michael Ludwigd9958f82019-03-21 13:08:36 -0400123
124namespace sk_gpu_test {
125
Brian Salomon7db71392020-10-16 10:05:21 -0400126std::unique_ptr<LazyYUVImage> LazyYUVImage::Make(sk_sp<SkData> data,
127 GrMipmapped mipmapped,
128 sk_sp<SkColorSpace> cs) {
Michael Ludwigd9958f82019-03-21 13:08:36 -0400129 std::unique_ptr<LazyYUVImage> image(new LazyYUVImage());
Brian Salomon7db71392020-10-16 10:05:21 -0400130 if (image->reset(std::move(data), mipmapped, std::move(cs))) {
Michael Ludwigd9958f82019-03-21 13:08:36 -0400131 return image;
132 } else {
133 return nullptr;
134 }
135}
136
Brian Salomon7db71392020-10-16 10:05:21 -0400137std::unique_ptr<LazyYUVImage> LazyYUVImage::Make(SkYUVAPixmaps pixmaps,
138 GrMipmapped mipmapped,
139 sk_sp<SkColorSpace> cs) {
140 std::unique_ptr<LazyYUVImage> image(new LazyYUVImage());
141 if (image->reset(std::move(pixmaps), mipmapped, std::move(cs))) {
142 return image;
Michael Ludwigd9958f82019-03-21 13:08:36 -0400143 } else {
144 return nullptr;
145 }
146}
147
Brian Salomon7db71392020-10-16 10:05:21 -0400148sk_sp<SkImage> LazyYUVImage::refImage(GrRecordingContext* rContext, Type type) {
149 if (this->ensureYUVImage(rContext, type)) {
150 size_t idx = static_cast<size_t>(type);
Brian Salomon6c11ba22020-10-16 11:11:40 -0400151 SkASSERT(idx < SK_ARRAY_COUNT(fYUVImage));
Brian Salomon7db71392020-10-16 10:05:21 -0400152 return fYUVImage[idx];
Michael Ludwigd9958f82019-03-21 13:08:36 -0400153 } else {
154 return nullptr;
155 }
156}
157
Brian Salomon7db71392020-10-16 10:05:21 -0400158bool LazyYUVImage::reset(sk_sp<SkData> data, GrMipmapped mipmapped, sk_sp<SkColorSpace> cs) {
Brian Salomon6db78b82020-07-31 08:57:48 -0400159 fMipmapped = mipmapped;
Michael Ludwigd9958f82019-03-21 13:08:36 -0400160 auto codec = SkCodecImageGenerator::MakeFromEncodedCodec(data);
161 if (!codec) {
162 return false;
163 }
164
Brian Salomonbe0e42c2020-08-27 11:00:04 -0400165 SkYUVAPixmapInfo yuvaPixmapInfo;
Brian Salomon59c60b02020-09-01 15:01:15 -0400166 if (!codec->queryYUVAInfo(SkYUVAPixmapInfo::SupportedDataTypes::All(), &yuvaPixmapInfo)) {
Brian Salomon87d42e52020-08-24 09:18:16 -0400167 return false;
168 }
Brian Salomonbe0e42c2020-08-27 11:00:04 -0400169 fPixmaps = SkYUVAPixmaps::Allocate(yuvaPixmapInfo);
Brian Salomon87d42e52020-08-24 09:18:16 -0400170 if (!fPixmaps.isValid()) {
Michael Ludwigd9958f82019-03-21 13:08:36 -0400171 return false;
172 }
173
Brian Salomonbe0e42c2020-08-27 11:00:04 -0400174 if (!codec->getYUVAPlanes(fPixmaps)) {
Michael Ludwigd9958f82019-03-21 13:08:36 -0400175 return false;
176 }
177
Brian Salomon7db71392020-10-16 10:05:21 -0400178 fColorSpace = std::move(cs);
179
Brian Salomondb0288d2020-10-15 10:31:43 -0400180 // The SkPixmap data is fully configured now for MakeFromYUVAPixmaps once we get a GrContext
181 return true;
182}
183
Brian Salomon7db71392020-10-16 10:05:21 -0400184bool LazyYUVImage::reset(SkYUVAPixmaps pixmaps, GrMipmapped mipmapped, sk_sp<SkColorSpace> cs) {
185 if (!pixmaps.isValid()) {
186 return false;
Brian Salomon839fb222020-10-16 13:30:54 +0000187 }
Brian Salomon7db71392020-10-16 10:05:21 -0400188 fMipmapped = mipmapped;
189 if (pixmaps.ownsStorage()) {
190 fPixmaps = std::move(pixmaps);
191 } else {
192 fPixmaps = SkYUVAPixmaps::MakeCopy(std::move(pixmaps));
193 }
194 fColorSpace = std::move(cs);
195 // The SkPixmap data is fully configured now for MakeFromYUVAPixmaps once we get a GrContext
196 return true;
197}
198
199bool LazyYUVImage::ensureYUVImage(GrRecordingContext* rContext, Type type) {
200 size_t idx = static_cast<size_t>(type);
Brian Salomon6c11ba22020-10-16 11:11:40 -0400201 SkASSERT(idx < SK_ARRAY_COUNT(fYUVImage));
Brian Salomon7db71392020-10-16 10:05:21 -0400202 if (fYUVImage[idx] && fYUVImage[idx]->isValid(rContext)) {
203 return true; // Have already made a YUV image valid for this context.
Michael Ludwigd9958f82019-03-21 13:08:36 -0400204 }
Brian Salomonefb5f072020-07-28 21:06:43 -0400205 // Try to make a new YUV image for this context.
Brian Salomon7db71392020-10-16 10:05:21 -0400206 switch (type) {
207 case Type::kFromPixmaps:
208 if (!rContext || rContext->abandoned()) {
209 return false;
210 }
211 fYUVImage[idx] = SkImage::MakeFromYUVAPixmaps(rContext,
212 fPixmaps,
213 fMipmapped,
214 /*limit to max tex size*/ false,
215 fColorSpace);
216 break;
217 case Type::kFromGenerator: {
218 // Make sure the generator has ownership of its backing planes.
219 auto generator = std::make_unique<Generator>(fPixmaps, fColorSpace);
220 fYUVImage[idx] = SkImage::MakeFromGenerator(std::move(generator));
221 break;
Brian Salomon839fb222020-10-16 13:30:54 +0000222 }
Brian Salomon7db71392020-10-16 10:05:21 -0400223 case Type::kFromTextures:
Brian Salomon694ff172020-11-04 16:54:28 -0500224 case Type::kFromTexturesCopyToExternal:
Brian Salomon7db71392020-10-16 10:05:21 -0400225 if (!rContext || rContext->abandoned()) {
226 return false;
227 }
Brian Salomon694ff172020-11-04 16:54:28 -0500228 if (fMipmapped == GrMipmapped::kYes) {
229 // If this becomes necessary we should invoke SkMipmapBuilder here to make mip
230 // maps from our src data (and then pass a pixmaps array to initialize the planar
231 // textures.
232 return false;
233 }
Brian Salomon7db71392020-10-16 10:05:21 -0400234 if (auto direct = rContext->asDirectContext()) {
235 sk_sp<sk_gpu_test::ManagedBackendTexture> mbets[SkYUVAInfo::kMaxPlanes];
236 GrBackendTexture textures[SkYUVAInfo::kMaxPlanes];
Brian Salomon7db71392020-10-16 10:05:21 -0400237 for (int i = 0; i < fPixmaps.numPlanes(); ++i) {
238 mbets[i] = sk_gpu_test::ManagedBackendTexture::MakeWithData(
239 direct, fPixmaps.plane(i), GrRenderable::kNo, GrProtected::kNo);
240 if (mbets[i]) {
241 textures[i] = mbets[i]->texture();
Brian Salomon7db71392020-10-16 10:05:21 -0400242 } else {
243 return false;
244 }
245 }
Brian Salomonc1a249d2020-10-19 10:55:45 -0400246 GrYUVABackendTextures yuvaTextures(fPixmaps.yuvaInfo(),
247 textures,
248 kTopLeft_GrSurfaceOrigin);
249 if (!yuvaTextures.isValid()) {
Brian Salomonbe8004d2020-10-16 22:32:35 +0000250 return false;
251 }
Brian Salomon694ff172020-11-04 16:54:28 -0500252 if (type == Type::kFromTextures) {
253 void* planeRelContext =
254 sk_gpu_test::ManagedBackendTexture::MakeYUVAReleaseContext(mbets);
255 fYUVImage[idx] = SkImage::MakeFromYUVATextures(
256 direct,
257 yuvaTextures,
258 fColorSpace,
259 sk_gpu_test::ManagedBackendTexture::ReleaseProc,
260 planeRelContext);
261 } else {
262 SkASSERT(type == Type::kFromTexturesCopyToExternal);
263 sk_sp<sk_gpu_test::ManagedBackendTexture> rgbaMBET;
264 for (auto ct : {SkYUVAPixmaps::RecommendedRGBAColorType(fPixmaps.dataType()),
265 kRGBA_8888_SkColorType}) {
266 rgbaMBET = sk_gpu_test::ManagedBackendTexture::MakeWithoutData(
267 direct,
268 fPixmaps.yuvaInfo().width(),
269 fPixmaps.yuvaInfo().height(),
270 kUnknown_SkColorType,
271 GrMipmapped::kNo,
272 GrRenderable::kYes);
273 if (rgbaMBET) {
274 void* planeRelContext =
275 sk_gpu_test::ManagedBackendTexture::MakeYUVAReleaseContext(
276 mbets);
277 fYUVImage[idx] = SkImage::MakeFromYUVATexturesCopyToExternal(
278 direct,
279 yuvaTextures,
280 rgbaMBET->texture(),
281 ct,
282 fColorSpace,
283 sk_gpu_test::ManagedBackendTexture::ReleaseProc,
284 planeRelContext,
285 sk_gpu_test::ManagedBackendTexture::ReleaseProc,
286 rgbaMBET->releaseContext());
287 if (fYUVImage[idx]) {
288 break;
289 }
290 }
291 }
292 }
Brian Salomon7db71392020-10-16 10:05:21 -0400293 }
Brian Salomon839fb222020-10-16 13:30:54 +0000294 }
Brian Salomon7db71392020-10-16 10:05:21 -0400295 return fYUVImage[idx] != nullptr;
Brian Salomon839fb222020-10-16 13:30:54 +0000296}
Michael Ludwigd9958f82019-03-21 13:08:36 -0400297} // namespace sk_gpu_test