From 993a4216a6014b9de8f4d8120360c94550dc6761 Mon Sep 17 00:00:00 2001 From: bsalomon Date: Fri, 29 May 2015 11:37:25 -0700 Subject: SkImage::NewFromYUVTexturesCopy Review URL: https://codereview.chromium.org/1149553002 --- gm/imagefromyuvtextures.cpp | 204 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 gm/imagefromyuvtextures.cpp (limited to 'gm') diff --git a/gm/imagefromyuvtextures.cpp b/gm/imagefromyuvtextures.cpp new file mode 100644 index 0000000000..b618abe2a4 --- /dev/null +++ b/gm/imagefromyuvtextures.cpp @@ -0,0 +1,204 @@ + +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +// This test only works with the GPU backend. + +#include "gm.h" + +#if SK_SUPPORT_GPU + +#include "GrContext.h" +#include "gl/GrGLInterface.h" +#include "gl/GrGLUtil.h" +#include "GrTest.h" +#include "SkBitmap.h" +#include "SkGradientShader.h" +#include "SkImage.h" + +namespace skiagm { +class ImageFromYUVTextures : public GM { +public: + ImageFromYUVTextures() { + this->setBGColor(0xFFFFFFFF); + } + +protected: + SkString onShortName() override { + return SkString("image_from_yuv_textures"); + } + + SkISize onISize() override { + return SkISize::Make(50, 135); + } + + void onOnceBeforeDraw() override { + // We create an RGB bitmap and then extract YUV bmps where the U and V bitmaps are + // subsampled by 2 in both dimensions. + SkPaint paint; + static const SkColor kColors[] = + { SK_ColorBLUE, SK_ColorYELLOW, SK_ColorGREEN, SK_ColorWHITE }; + paint.setShader(SkGradientShader::CreateRadial(SkPoint::Make(0,0), kBmpSize / 2.f, kColors, + NULL, SK_ARRAY_COUNT(kColors), + SkShader::kMirror_TileMode))->unref(); + SkBitmap rgbBmp; + rgbBmp.allocN32Pixels(kBmpSize, kBmpSize, true); + SkCanvas canvas(rgbBmp); + canvas.drawPaint(paint); + SkPMColor* rgbColors = static_cast(rgbBmp.getPixels()); + + SkImageInfo yinfo = SkImageInfo::MakeA8(kBmpSize, kBmpSize); + fYUVBmps[0].allocPixels(yinfo); + SkImageInfo uinfo = SkImageInfo::MakeA8(kBmpSize / 2, kBmpSize / 2); + fYUVBmps[1].allocPixels(uinfo); + SkImageInfo vinfo = SkImageInfo::MakeA8(kBmpSize / 2, kBmpSize / 2); + fYUVBmps[2].allocPixels(vinfo); + unsigned char* yPixels; + signed char* uvPixels[2]; + yPixels = static_cast(fYUVBmps[0].getPixels()); + uvPixels[0] = static_cast(fYUVBmps[1].getPixels()); + uvPixels[1] = static_cast(fYUVBmps[2 + ].getPixels()); + + // Here we encode using the NTC encoding (even though we will draw it with all the supported + // yuv color spaces when converted back to RGB) + for (int i = 0; i < kBmpSize * kBmpSize; ++i) { + yPixels[i] = static_cast(0.299f * SkGetPackedR32(rgbColors[i]) + + 0.587f * SkGetPackedG32(rgbColors[i]) + + 0.114f * SkGetPackedB32(rgbColors[i])); + } + for (int j = 0; j < kBmpSize / 2; ++j) { + for (int i = 0; i < kBmpSize / 2; ++i) { + // Average together 4 pixels of RGB. + int rgb[] = { 0, 0, 0 }; + for (int y = 0; y < 2; ++y) { + for (int x = 0; x < 2; ++x) { + int rgbIndex = (2 * j + y) * kBmpSize + 2 * i + x; + rgb[0] += SkGetPackedR32(rgbColors[rgbIndex]); + rgb[1] += SkGetPackedG32(rgbColors[rgbIndex]); + rgb[2] += SkGetPackedB32(rgbColors[rgbIndex]); + } + } + for (int c = 0; c < 3; ++c) { + rgb[c] /= 4; + } + int uvIndex = j * kBmpSize / 2 + i; + uvPixels[0][uvIndex] = static_cast( + ((-38 * rgb[0] - 74 * rgb[1] + 112 * rgb[2] + 128) >> 8) + 128); + uvPixels[1][uvIndex] = static_cast( + ((112 * rgb[0] - 94 * rgb[1] - 18 * rgb[2] + 128) >> 8) + 128); + } + } + fRGBImage.reset(SkImage::NewRasterCopy(rgbBmp.info(), rgbColors, rgbBmp.rowBytes())); + } + + void createYUVTextures(GrContext* context, GrGLuint yuvIDs[3]) { + GrTestTarget tt; + context->getTestTarget(&tt); + if (!tt.target()) { + SkDEBUGFAIL("Couldn't get Gr test target."); + return; + } + + // We currently hav only implemented the texture uploads for GL. + const GrGLInterface* gl = tt.glInterface(); + if (!gl) { + return; + } + + GR_GL_CALL(gl, GenTextures(3, yuvIDs)); + GR_GL_CALL(gl, ActiveTexture(GR_GL_TEXTURE0)); + GR_GL_CALL(gl, PixelStorei(GR_GL_UNPACK_ALIGNMENT, 1)); + for (int i = 0; i < 3; ++i) { + GR_GL_CALL(gl, BindTexture(GR_GL_TEXTURE_2D, yuvIDs[i])); + GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MAG_FILTER, + GR_GL_NEAREST)); + GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MIN_FILTER, + GR_GL_NEAREST)); + GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_WRAP_S, + GR_GL_CLAMP_TO_EDGE)); + GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_WRAP_T, + GR_GL_CLAMP_TO_EDGE)); + SkASSERT(fYUVBmps[i].width() == SkToInt(fYUVBmps[i].rowBytes())); + GR_GL_CALL(gl, TexImage2D(GR_GL_TEXTURE_2D, 0, GR_GL_RED, fYUVBmps[i].width(), + fYUVBmps[i].height(), 0, GR_GL_RED, GR_GL_UNSIGNED_BYTE, + fYUVBmps[i].getPixels())); + } + context->resetContext(); + } + + void deleteYUVTextures(GrContext* context, const GrGLuint yuvIDs[3]) { + GrTestTarget tt; + context->getTestTarget(&tt); + if (!tt.target()) { + SkDEBUGFAIL("Couldn't get Gr test target."); + return; + } + + const GrGLInterface* gl = tt.glInterface(); + if (!gl) { + return; + } + GR_GL_CALL(gl, DeleteTextures(3, yuvIDs)); + context->resetContext(); + } + + void onDraw(SkCanvas* canvas) override { + GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget(); + GrContext* context; + if (!rt || !(context = rt->getContext())) { + this->drawGpuOnlyMessage(canvas); + return; + } + + GrGLuint yuvIDs[3]; + this->createYUVTextures(context, yuvIDs); + + static const SkScalar kPad = 10.f; + + GrBackendObject backendTextureObjects[] = { + static_cast(yuvIDs[0]), + static_cast(yuvIDs[1]), + static_cast(yuvIDs[2]) + }; + SkISize sizes[] = { + { fYUVBmps[0].width(), fYUVBmps[0].height()}, + { fYUVBmps[1].width(), fYUVBmps[1].height()}, + { fYUVBmps[2].width(), fYUVBmps[2].height()}, + }; + SkTArray images; + images.push_back(SkRef(fRGBImage.get())); + for (int space = kJPEG_SkYUVColorSpace; space <= kLastEnum_SkYUVColorSpace; ++space) { + images.push_back(SkImage::NewFromYUVTexturesCopy(context, + static_cast(space), + backendTextureObjects, sizes, + kTopLeft_GrSurfaceOrigin)); + } + this->deleteYUVTextures(context, yuvIDs); + for (int i = 0; i < images.count(); ++ i) { + SkScalar y = (i + 1) * kPad + i * fYUVBmps[0].height(); + SkScalar x = kPad; + + canvas->drawImage(images[i], x, y); + images[i]->unref(); + images[i] = NULL; + } + } + +private: + SkAutoTUnref fRGBImage; + SkBitmap fYUVBmps[3]; + + static const int kBmpSize = 32; + + typedef GM INHERITED; +}; + +DEF_GM( return SkNEW(ImageFromYUVTextures); ) +} + +#endif -- cgit v1.2.3