diff options
author | rileya <rileya@chromium.org> | 2014-09-12 17:45:58 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-09-12 17:45:58 -0700 |
commit | abaef86f2b37d8a939506a2076da07f6db456951 (patch) | |
tree | e206bd6ee9f049c43c0ba9033c8417bb5008258c | |
parent | 94c415170b6f62fa80b598fe30bf2f99f0aecf6a (diff) |
Add support for the Rec601 YUV color space to GrYUVtoRGBEffect.
R=bsalomon@google.com, senorblanco@chromium.org, sugoi@chromium.org, reed@google.com
Author: rileya@chromium.org
Review URL: https://codereview.chromium.org/516463005
-rw-r--r-- | expectations/gm/ignored-tests.txt | 3 | ||||
-rw-r--r-- | gm/yuvtorgbeffect.cpp | 57 | ||||
-rw-r--r-- | include/core/SkImageGenerator.h | 7 | ||||
-rw-r--r-- | include/core/SkImageInfo.h | 15 | ||||
-rw-r--r-- | include/core/SkPixelRef.h | 11 | ||||
-rw-r--r-- | src/core/SkImageGenerator.cpp | 17 | ||||
-rw-r--r-- | src/core/SkPixelRef.cpp | 3 | ||||
-rw-r--r-- | src/gpu/SkGr.cpp | 9 | ||||
-rw-r--r-- | src/gpu/effects/GrYUVtoRGBEffect.cpp | 70 | ||||
-rw-r--r-- | src/gpu/effects/GrYUVtoRGBEffect.h | 5 | ||||
-rw-r--r-- | src/lazy/SkDiscardablePixelRef.h | 5 | ||||
-rw-r--r-- | tests/ImageGeneratorTest.cpp | 13 |
12 files changed, 154 insertions, 61 deletions
diff --git a/expectations/gm/ignored-tests.txt b/expectations/gm/ignored-tests.txt index b8771612a0..377575edad 100644 --- a/expectations/gm/ignored-tests.txt +++ b/expectations/gm/ignored-tests.txt @@ -38,3 +38,6 @@ fontcache # reed - conservative_rasterclip CL multipicturedraw_pathclip_tiled + +# rileya - https://codereview.chromium.org/516463005/ will rebaseline after bots cycle +yuv_to_rgb_effect diff --git a/gm/yuvtorgbeffect.cpp b/gm/yuvtorgbeffect.cpp index 12676f262e..acb6f2251b 100644 --- a/gm/yuvtorgbeffect.cpp +++ b/gm/yuvtorgbeffect.cpp @@ -35,7 +35,7 @@ protected: } virtual SkISize onISize() SK_OVERRIDE { - return SkISize::Make(334, 64); + return SkISize::Make(334, 128); } virtual uint32_t onGetFlags() const SK_OVERRIDE { @@ -93,31 +93,36 @@ protected: static const SkScalar kDrawPad = 10.f; static const SkScalar kTestPad = 10.f; - - SkRect renderRect = SkRect::MakeWH(SkIntToScalar(fBmp[0].width()), - SkIntToScalar(fBmp[0].height())); - renderRect.outset(kDrawPad, kDrawPad); - - SkScalar y = kDrawPad + kTestPad; - SkScalar x = kDrawPad + kTestPad; - - const int indices[6][3] = {{0, 1, 2}, {0, 2, 1}, {1, 0, 2}, {1, 2, 0}, {2, 0, 1}, {2, 1, 0}}; - - for (int i = 0; i < 6; ++i) { - SkAutoTUnref<GrEffect> effect( - GrYUVtoRGBEffect::Create(texture[indices[i][0]], - texture[indices[i][1]], - texture[indices[i][2]])); - if (effect) { - SkMatrix viewMatrix; - viewMatrix.setTranslate(x, y); - drawState->reset(viewMatrix); - drawState->setRenderTarget(rt); - drawState->setColor(0xffffffff); - drawState->addColorEffect(effect, 1); - tt.target()->drawSimpleRect(renderRect); - } - x += renderRect.width() + kTestPad; + static const SkScalar kColorSpaceOffset = 64.f; + + for (int space = kJPEG_SkYUVColorSpace; space <= kLastEnum_SkYUVColorSpace; + ++space) { + SkRect renderRect = SkRect::MakeWH(SkIntToScalar(fBmp[0].width()), + SkIntToScalar(fBmp[0].height())); + renderRect.outset(kDrawPad, kDrawPad); + + SkScalar y = kDrawPad + kTestPad + space * kColorSpaceOffset; + SkScalar x = kDrawPad + kTestPad; + + const int indices[6][3] = {{0, 1, 2}, {0, 2, 1}, {1, 0, 2}, {1, 2, 0}, {2, 0, 1}, {2, 1, 0}}; + + for (int i = 0; i < 6; ++i) { + SkAutoTUnref<GrEffect> effect( + GrYUVtoRGBEffect::Create(texture[indices[i][0]], + texture[indices[i][1]], + texture[indices[i][2]], + static_cast<SkYUVColorSpace>(space))); + if (effect) { + SkMatrix viewMatrix; + viewMatrix.setTranslate(x, y); + drawState->reset(viewMatrix); + drawState->setRenderTarget(rt); + drawState->setColor(0xffffffff); + drawState->addColorEffect(effect, 1); + tt.target()->drawSimpleRect(renderRect); + } + x += renderRect.width() + kTestPad; + } } GrUnlockAndUnrefCachedBitmapTexture(texture[0]); diff --git a/include/core/SkImageGenerator.h b/include/core/SkImageGenerator.h index 4eb5cf85d6..fc6b1b4421 100644 --- a/include/core/SkImageGenerator.h +++ b/include/core/SkImageGenerator.h @@ -8,8 +8,8 @@ #ifndef SkImageGenerator_DEFINED #define SkImageGenerator_DEFINED -#include "SkImageInfo.h" #include "SkColor.h" +#include "SkImageInfo.h" class SkBitmap; class SkData; @@ -121,7 +121,8 @@ public: * associated YUV data into those planes of memory supplied by the caller. It should validate * that the sizes match what it expected. If the sizes do not match, it should return false. */ - bool getYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3]); + bool getYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3], + SkYUVColorSpace* colorSpace); protected: virtual SkData* onRefEncodedData(); @@ -130,6 +131,8 @@ protected: void* pixels, size_t rowBytes, SkPMColor ctable[], int* ctableCount); virtual bool onGetYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3]); + virtual bool onGetYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3], + SkYUVColorSpace* colorSpace); }; #endif // SkImageGenerator_DEFINED diff --git a/include/core/SkImageInfo.h b/include/core/SkImageInfo.h index 6204cb3b81..7fedfa1a4a 100644 --- a/include/core/SkImageInfo.h +++ b/include/core/SkImageInfo.h @@ -133,6 +133,21 @@ bool SkColorTypeValidateAlphaType(SkColorType colorType, SkAlphaType alphaType, /////////////////////////////////////////////////////////////////////////////// /** + * Describes the color space a YUV pixel. + */ +enum SkYUVColorSpace { + /** Standard JPEG color space. */ + kJPEG_SkYUVColorSpace, + /** SDTV standard Rec. 601 color space. Uses "studio swing" [16, 235] color + range. See http://en.wikipedia.org/wiki/Rec._601 for details. */ + kRec601_SkYUVColorSpace, + + kLastEnum_SkYUVColorSpace = kRec601_SkYUVColorSpace +}; + +/////////////////////////////////////////////////////////////////////////////// + +/** * Describe an image's dimensions and pixel type. */ struct SkImageInfo { diff --git a/include/core/SkPixelRef.h b/include/core/SkPixelRef.h index afab7fad9e..02d696edd8 100644 --- a/include/core/SkPixelRef.h +++ b/include/core/SkPixelRef.h @@ -227,9 +227,13 @@ public: * If all planes and rowBytes are not NULL, then it should copy the associated Y,U,V data * into those planes of memory supplied by the caller. It should validate that the sizes * match what it expected. If the sizes do not match, it should return false. + * + * If colorSpace is not NULL, the YUV color space of the data should be stored in the address + * it points at. */ - bool getYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3]) { - return this->onGetYUV8Planes(sizes, planes, rowBytes); + bool getYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3], + SkYUVColorSpace* colorSpace) { + return this->onGetYUV8Planes(sizes, planes, rowBytes, colorSpace); } bool readPixels(SkBitmap* dst, const SkIRect* subset = NULL); @@ -319,7 +323,8 @@ protected: virtual SkData* onRefEncodedData(); // default impl returns false. - virtual bool onGetYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3]); + virtual bool onGetYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3], + SkYUVColorSpace* colorSpace); /** * Returns the size (in bytes) of the internally allocated memory. diff --git a/src/core/SkImageGenerator.cpp b/src/core/SkImageGenerator.cpp index 7008e7b42f..c062978f0f 100644 --- a/src/core/SkImageGenerator.cpp +++ b/src/core/SkImageGenerator.cpp @@ -57,7 +57,8 @@ bool SkImageGenerator::getPixels(const SkImageInfo& info, void* pixels, size_t r } #endif -bool SkImageGenerator::getYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3]) { +bool SkImageGenerator::getYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3], + SkYUVColorSpace* colorSpace) { #ifdef SK_DEBUG // In all cases, we need the sizes array SkASSERT(sizes); @@ -89,13 +90,25 @@ bool SkImageGenerator::getYUV8Planes(SkISize sizes[3], void* planes[3], size_t r (rowBytes[2] >= (size_t)sizes[2].fWidth))); #endif - return this->onGetYUV8Planes(sizes, planes, rowBytes); + return this->onGetYUV8Planes(sizes, planes, rowBytes, colorSpace); } bool SkImageGenerator::onGetYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3]) { return false; } +bool SkImageGenerator::onGetYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3], + SkYUVColorSpace* colorSpace) { + // In order to maintain compatibility with clients that implemented the original + // onGetYUV8Planes interface, we assume that the color space is JPEG. + // TODO(rileya): remove this and the old onGetYUV8Planes once clients switch over to + // the new interface. + if (colorSpace) { + *colorSpace = kJPEG_SkYUVColorSpace; + } + return this->onGetYUV8Planes(sizes, planes, rowBytes); +} + ///////////////////////////////////////////////////////////////////////////////////////////// SkData* SkImageGenerator::onRefEncodedData() { diff --git a/src/core/SkPixelRef.cpp b/src/core/SkPixelRef.cpp index 1e6db7ec5a..0aa00e0bf5 100644 --- a/src/core/SkPixelRef.cpp +++ b/src/core/SkPixelRef.cpp @@ -253,7 +253,8 @@ SkData* SkPixelRef::onRefEncodedData() { return NULL; } -bool SkPixelRef::onGetYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3]) { +bool SkPixelRef::onGetYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3], + SkYUVColorSpace* colorSpace) { return false; } diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp index 73773b00d1..56f3a16b6d 100644 --- a/src/gpu/SkGr.cpp +++ b/src/gpu/SkGr.cpp @@ -222,7 +222,7 @@ static GrTexture *load_yuv_texture(GrContext* ctx, bool cache, const GrTexturePa const SkBitmap& bm, const GrTextureDesc& desc) { SkPixelRef* pixelRef = bm.pixelRef(); SkISize yuvSizes[3]; - if ((NULL == pixelRef) || !pixelRef->getYUV8Planes(yuvSizes, NULL, NULL)) { + if ((NULL == pixelRef) || !pixelRef->getYUV8Planes(yuvSizes, NULL, NULL, NULL)) { return NULL; } @@ -239,8 +239,10 @@ static GrTexture *load_yuv_texture(GrContext* ctx, bool cache, const GrTexturePa planes[1] = (uint8_t*)planes[0] + sizes[0]; planes[2] = (uint8_t*)planes[1] + sizes[1]; + SkYUVColorSpace colorSpace; + // Get the YUV planes - if (!pixelRef->getYUV8Planes(yuvSizes, planes, rowBytes)) { + if (!pixelRef->getYUV8Planes(yuvSizes, planes, rowBytes, &colorSpace)) { return NULL; } @@ -269,7 +271,8 @@ static GrTexture *load_yuv_texture(GrContext* ctx, bool cache, const GrTexturePa GrRenderTarget* renderTarget = result ? result->asRenderTarget() : NULL; if (renderTarget) { SkAutoTUnref<GrEffect> yuvToRgbEffect(GrYUVtoRGBEffect::Create( - yuvTextures[0].texture(), yuvTextures[1].texture(), yuvTextures[2].texture())); + yuvTextures[0].texture(), yuvTextures[1].texture(), yuvTextures[2].texture(), + colorSpace)); GrPaint paint; paint.addColorEffect(yuvToRgbEffect); SkRect r = SkRect::MakeWH(SkIntToScalar(yuvSizes[0].fWidth), diff --git a/src/gpu/effects/GrYUVtoRGBEffect.cpp b/src/gpu/effects/GrYUVtoRGBEffect.cpp index 1a46c969ef..0023b1b300 100644 --- a/src/gpu/effects/GrYUVtoRGBEffect.cpp +++ b/src/gpu/effects/GrYUVtoRGBEffect.cpp @@ -17,8 +17,9 @@ namespace { class YUVtoRGBEffect : public GrEffect { public: - static GrEffect* Create(GrTexture* yTexture, GrTexture* uTexture, GrTexture* vTexture) { - return SkNEW_ARGS(YUVtoRGBEffect, (yTexture, uTexture, vTexture)); + static GrEffect* Create(GrTexture* yTexture, GrTexture* uTexture, GrTexture* vTexture, + SkYUVColorSpace colorSpace) { + return SkNEW_ARGS(YUVtoRGBEffect, (yTexture, uTexture, vTexture, colorSpace)); } static const char* Name() { return "YUV to RGB"; } @@ -34,8 +35,15 @@ public: *validFlags = kA_GrColorComponentFlag; } + SkYUVColorSpace getColorSpace() const { + return fColorSpace; + } + class GLEffect : public GrGLEffect { public: + static const GrGLfloat kJPEGConversionMatrix[16]; + static const GrGLfloat kRec601ConversionMatrix[16]; + // this class always generates the same code. static void GenKey(const GrDrawEffect&, const GrGLCaps&, GrEffectKeyBuilder*) {} @@ -45,19 +53,18 @@ public: } virtual void emitCode(GrGLProgramBuilder* builder, - const GrDrawEffect&, + const GrDrawEffect& drawEffect, const GrEffectKey&, const char* outputColor, const char* inputColor, const TransformedCoordsArray& coords, const TextureSamplerArray& samplers) SK_OVERRIDE { GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder(); - const char* yuvMatrix = "yuvMatrix"; - fsBuilder->codeAppendf("\tconst mat4 %s = mat4(1.0, 0.0, 1.402, -0.701,\n\t\t\t" - "1.0, -0.344, -0.714, 0.529,\n\t\t\t" - "1.0, 1.772, 0.0, -0.886,\n\t\t\t" - "0.0, 0.0, 0.0, 1.0);\n", - yuvMatrix); + + const char* yuvMatrix = NULL; + fMatrixUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, + kMat44f_GrSLType, "YUVMatrix", + &yuvMatrix); fsBuilder->codeAppendf("\t%s = vec4(\n\t\t", outputColor); fsBuilder->appendTextureLookup(samplers[0], coords[0].c_str(), coords[0].type()); fsBuilder->codeAppend(".r,\n\t\t"); @@ -67,16 +74,34 @@ public: fsBuilder->codeAppendf(".r,\n\t\t1.0) * %s;\n", yuvMatrix); } + virtual void setData(const GrGLProgramDataManager& pdman, + const GrDrawEffect& drawEffect) SK_OVERRIDE { + const YUVtoRGBEffect& yuvEffect = drawEffect.castEffect<YUVtoRGBEffect>(); + switch (yuvEffect.getColorSpace()) { + case kJPEG_SkYUVColorSpace: + pdman.setMatrix4f(fMatrixUni, kJPEGConversionMatrix); + break; + case kRec601_SkYUVColorSpace: + pdman.setMatrix4f(fMatrixUni, kRec601ConversionMatrix); + break; + } + } + + private: + GrGLProgramDataManager::UniformHandle fMatrixUni; + typedef GrGLEffect INHERITED; }; private: - YUVtoRGBEffect(GrTexture* yTexture, GrTexture* uTexture, GrTexture* vTexture) - : fCoordTransform(kLocal_GrCoordSet, GrCoordTransform::MakeDivByTextureWHMatrix(yTexture), - yTexture) + YUVtoRGBEffect(GrTexture* yTexture, GrTexture* uTexture, GrTexture* vTexture, + SkYUVColorSpace colorSpace) + : fCoordTransform(kLocal_GrCoordSet, GrCoordTransform::MakeDivByTextureWHMatrix(yTexture), + yTexture) , fYAccess(yTexture) , fUAccess(uTexture) - , fVAccess(vTexture) { + , fVAccess(vTexture) + , fColorSpace(colorSpace) { this->addCoordTransform(&fCoordTransform); this->addTextureAccess(&fYAccess); this->addTextureAccess(&fUAccess); @@ -88,21 +113,34 @@ private: const YUVtoRGBEffect& s = CastEffect<YUVtoRGBEffect>(sBase); return fYAccess.getTexture() == s.fYAccess.getTexture() && fUAccess.getTexture() == s.fUAccess.getTexture() && - fVAccess.getTexture() == s.fVAccess.getTexture(); + fVAccess.getTexture() == s.fVAccess.getTexture() && + fColorSpace == s.getColorSpace(); } GrCoordTransform fCoordTransform; GrTextureAccess fYAccess; GrTextureAccess fUAccess; GrTextureAccess fVAccess; + SkYUVColorSpace fColorSpace; typedef GrEffect INHERITED; }; +const GrGLfloat YUVtoRGBEffect::GLEffect::kJPEGConversionMatrix[16] = { + 1.0f, 0.0f, 1.402f, -0.701f, + 1.0f, -0.34414f, -0.71414f, 0.529f, + 1.0f, 1.772f, 0.0f, -0.886f, + 0.0f, 0.0f, 0.0f, 1.0}; +const GrGLfloat YUVtoRGBEffect::GLEffect::kRec601ConversionMatrix[16] = { + 1.164f, 0.0f, 1.596f, -1.08175f, + 1.164f, -0.391f, -0.813f, 0.529f, + 1.164f, 2.018f, 0.0f, -1.08175f, + 0.0f, 0.0f, 0.0f, 1.0}; } ////////////////////////////////////////////////////////////////////////////// -GrEffect* GrYUVtoRGBEffect::Create(GrTexture* yTexture, GrTexture* uTexture, GrTexture* vTexture) { - return YUVtoRGBEffect::Create(yTexture, uTexture, vTexture); +GrEffect* GrYUVtoRGBEffect::Create(GrTexture* yTexture, GrTexture* uTexture, GrTexture* vTexture, + SkYUVColorSpace colorSpace) { + return YUVtoRGBEffect::Create(yTexture, uTexture, vTexture, colorSpace); } diff --git a/src/gpu/effects/GrYUVtoRGBEffect.h b/src/gpu/effects/GrYUVtoRGBEffect.h index 150acd5a90..52ccd23bbb 100644 --- a/src/gpu/effects/GrYUVtoRGBEffect.h +++ b/src/gpu/effects/GrYUVtoRGBEffect.h @@ -8,6 +8,8 @@ #ifndef GrYUVtoRGBEffect_DEFINED #define GrYUVtoRGBEffect_DEFINED +#include "SkImageInfo.h" + class GrEffect; class GrTexture; @@ -15,7 +17,8 @@ namespace GrYUVtoRGBEffect { /** * Creates an effect that performs color conversion from YUV to RGB */ - GrEffect* Create(GrTexture* yTexture, GrTexture* uTexture, GrTexture* vTexture); + GrEffect* Create(GrTexture* yTexture, GrTexture* uTexture, GrTexture* vTexture, + SkYUVColorSpace colorSpace); }; #endif diff --git a/src/lazy/SkDiscardablePixelRef.h b/src/lazy/SkDiscardablePixelRef.h index d31a040164..142c8a4539 100644 --- a/src/lazy/SkDiscardablePixelRef.h +++ b/src/lazy/SkDiscardablePixelRef.h @@ -50,8 +50,9 @@ private: virtual bool onGetYUV8Planes(SkISize sizes[3], void* planes[3], - size_t rowBytes[3]) SK_OVERRIDE { - return fGenerator->getYUV8Planes(sizes, planes, rowBytes); + size_t rowBytes[3], + SkYUVColorSpace* colorSpace) SK_OVERRIDE { + return fGenerator->getYUV8Planes(sizes, planes, rowBytes, colorSpace); } friend bool SkInstallDiscardablePixelRef(SkImageGenerator*, SkBitmap*, diff --git a/tests/ImageGeneratorTest.cpp b/tests/ImageGeneratorTest.cpp index aaf149b37c..1f960ea9e9 100644 --- a/tests/ImageGeneratorTest.cpp +++ b/tests/ImageGeneratorTest.cpp @@ -16,16 +16,19 @@ DEF_TEST(ImageGenerator, reporter) { sizes[2] = SkISize::Make( 50, 50); void* planes[3] = { NULL }; size_t rowBytes[3] = { 0 }; + SkYUVColorSpace colorSpace; // Check that the YUV decoding API does not cause any crashes - ig.getYUV8Planes(sizes, NULL, NULL); - ig.getYUV8Planes(sizes, planes, NULL); - ig.getYUV8Planes(sizes, NULL, rowBytes); - ig.getYUV8Planes(sizes, planes, rowBytes); + ig.getYUV8Planes(sizes, NULL, NULL, &colorSpace); + ig.getYUV8Planes(sizes, NULL, NULL, NULL); + ig.getYUV8Planes(sizes, planes, NULL, NULL); + ig.getYUV8Planes(sizes, NULL, rowBytes, NULL); + ig.getYUV8Planes(sizes, planes, rowBytes, NULL); + ig.getYUV8Planes(sizes, planes, rowBytes, &colorSpace); int dummy; planes[0] = planes[1] = planes[2] = &dummy; rowBytes[0] = rowBytes[1] = rowBytes[2] = 250; - ig.getYUV8Planes(sizes, planes, rowBytes); + ig.getYUV8Planes(sizes, planes, rowBytes, &colorSpace); } |