2 * Copyright 2015 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 // This test only works with the GPU backend.
14 #include "GrContext.h"
18 #include "SkGradientShader.h"
22 class ImageFromYUVTextures : public GM {
24 ImageFromYUVTextures() {
25 this->setBGColor(0xFFFFFFFF);
29 SkString onShortName() override {
30 return SkString("image_from_yuv_textures");
33 SkISize onISize() override {
34 return SkISize::Make(50, 175);
37 void onOnceBeforeDraw() override {
38 // We create an RGB bitmap and then extract YUV bmps where the U and V bitmaps are
39 // subsampled by 2 in both dimensions.
41 constexpr SkColor kColors[] =
42 { SK_ColorBLUE, SK_ColorYELLOW, SK_ColorGREEN, SK_ColorWHITE };
43 paint.setShader(SkGradientShader::MakeRadial(SkPoint::Make(0,0), kBmpSize / 2.f, kColors,
44 nullptr, SK_ARRAY_COUNT(kColors),
45 SkShader::kMirror_TileMode));
47 rgbBmp.allocN32Pixels(kBmpSize, kBmpSize, true);
48 SkCanvas canvas(rgbBmp);
49 canvas.drawPaint(paint);
50 SkPMColor* rgbColors = static_cast<SkPMColor*>(rgbBmp.getPixels());
52 SkImageInfo yinfo = SkImageInfo::MakeA8(kBmpSize, kBmpSize);
53 fYUVBmps[0].allocPixels(yinfo);
54 SkImageInfo uinfo = SkImageInfo::MakeA8(kBmpSize / 2, kBmpSize / 2);
55 fYUVBmps[1].allocPixels(uinfo);
56 SkImageInfo vinfo = SkImageInfo::MakeA8(kBmpSize / 2, kBmpSize / 2);
57 fYUVBmps[2].allocPixels(vinfo);
58 unsigned char* yPixels;
59 signed char* uvPixels[2];
60 yPixels = static_cast<unsigned char*>(fYUVBmps[0].getPixels());
61 uvPixels[0] = static_cast<signed char*>(fYUVBmps[1].getPixels());
62 uvPixels[1] = static_cast<signed char*>(fYUVBmps[2].getPixels());
64 // Here we encode using the NTC encoding (even though we will draw it with all the supported
65 // yuv color spaces when converted back to RGB)
66 for (int i = 0; i < kBmpSize * kBmpSize; ++i) {
67 yPixels[i] = static_cast<unsigned char>(0.299f * SkGetPackedR32(rgbColors[i]) +
68 0.587f * SkGetPackedG32(rgbColors[i]) +
69 0.114f * SkGetPackedB32(rgbColors[i]));
71 for (int j = 0; j < kBmpSize / 2; ++j) {
72 for (int i = 0; i < kBmpSize / 2; ++i) {
73 // Average together 4 pixels of RGB.
74 int rgb[] = { 0, 0, 0 };
75 for (int y = 0; y < 2; ++y) {
76 for (int x = 0; x < 2; ++x) {
77 int rgbIndex = (2 * j + y) * kBmpSize + 2 * i + x;
78 rgb[0] += SkGetPackedR32(rgbColors[rgbIndex]);
79 rgb[1] += SkGetPackedG32(rgbColors[rgbIndex]);
80 rgb[2] += SkGetPackedB32(rgbColors[rgbIndex]);
83 for (int c = 0; c < 3; ++c) {
86 int uvIndex = j * kBmpSize / 2 + i;
87 uvPixels[0][uvIndex] = static_cast<signed char>(
88 ((-38 * rgb[0] - 74 * rgb[1] + 112 * rgb[2] + 128) >> 8) + 128);
89 uvPixels[1][uvIndex] = static_cast<signed char>(
90 ((112 * rgb[0] - 94 * rgb[1] - 18 * rgb[2] + 128) >> 8) + 128);
93 fRGBImage = SkImage::MakeRasterCopy(SkPixmap(rgbBmp.info(), rgbColors, rgbBmp.rowBytes()));
96 void createYUVTextures(GrContext* context, GrBackendObject yuvHandles[3]) {
97 GrGpu* gpu = context->getGpu();
102 for (int i = 0; i < 3; ++i) {
103 SkASSERT(fYUVBmps[i].width() == SkToInt(fYUVBmps[i].rowBytes()));
104 yuvHandles[i] = gpu->createTestingOnlyBackendTexture(fYUVBmps[i].getPixels(),
106 fYUVBmps[i].height(),
107 kAlpha_8_GrPixelConfig);
109 context->resetContext();
112 void deleteYUVTextures(GrContext* context, const GrBackendObject yuvHandles[3]) {
114 GrGpu* gpu = context->getGpu();
119 for (int i = 0; i < 3; ++i) {
120 gpu->deleteTestingOnlyBackendTexture(yuvHandles[i]);
123 context->resetContext();
126 void onDraw(SkCanvas* canvas) override {
127 GrContext* context = canvas->getGrContext();
129 skiagm::GM::DrawGpuOnlyMessage(canvas);
134 constexpr SkScalar kPad = 10.f;
137 { fYUVBmps[0].width(), fYUVBmps[0].height()},
138 { fYUVBmps[1].width(), fYUVBmps[1].height()},
139 { fYUVBmps[2].width(), fYUVBmps[2].height()},
141 SkTArray<sk_sp<SkImage>> images;
142 images.push_back(fRGBImage);
143 for (int space = kJPEG_SkYUVColorSpace; space <= kLastEnum_SkYUVColorSpace; ++space) {
144 GrBackendObject yuvHandles[3];
145 this->createYUVTextures(context, yuvHandles);
146 images.push_back(SkImage::MakeFromYUVTexturesCopy(context,
147 static_cast<SkYUVColorSpace>(space),
149 kTopLeft_GrSurfaceOrigin));
150 this->deleteYUVTextures(context, yuvHandles);
152 for (int i = 0; i < images.count(); ++ i) {
153 SkScalar y = (i + 1) * kPad + i * fYUVBmps[0].height();
156 canvas->drawImage(images[i].get(), x, y);
161 sk_sp<SkImage> fRGBImage;
162 SkBitmap fYUVBmps[3];
164 static constexpr int kBmpSize = 32;
166 typedef GM INHERITED;
169 DEF_GM(return new ImageFromYUVTextures;)