aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar rileya <rileya@chromium.org>2014-09-12 17:45:58 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2014-09-12 17:45:58 -0700
commitabaef86f2b37d8a939506a2076da07f6db456951 (patch)
treee206bd6ee9f049c43c0ba9033c8417bb5008258c
parent94c415170b6f62fa80b598fe30bf2f99f0aecf6a (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.txt3
-rw-r--r--gm/yuvtorgbeffect.cpp57
-rw-r--r--include/core/SkImageGenerator.h7
-rw-r--r--include/core/SkImageInfo.h15
-rw-r--r--include/core/SkPixelRef.h11
-rw-r--r--src/core/SkImageGenerator.cpp17
-rw-r--r--src/core/SkPixelRef.cpp3
-rw-r--r--src/gpu/SkGr.cpp9
-rw-r--r--src/gpu/effects/GrYUVtoRGBEffect.cpp70
-rw-r--r--src/gpu/effects/GrYUVtoRGBEffect.h5
-rw-r--r--src/lazy/SkDiscardablePixelRef.h5
-rw-r--r--tests/ImageGeneratorTest.cpp13
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);
}