YUV scale fix
There was a scaling mistake visible in some JPEG images because the ratio between Y, U and V planes were assumed to be the same ratios as the ratio between texture sizes, which was wrong because texture have a minimum size of 16 and are rounded up to the next POT. Since the ratios between Y and UV planes are generally 1, 2 or 4, rounding up to the next POT would generally preserve this ratio, so that this bug was not very visible, apart from very small jpeg images of 8 or less pixels in either width or height.
BUG=457954
Review URL: https://codereview.chromium.org/922273002
diff --git a/gm/yuvtorgbeffect.cpp b/gm/yuvtorgbeffect.cpp
index fb0c67d..2cff764 100644
--- a/gm/yuvtorgbeffect.cpp
+++ b/gm/yuvtorgbeffect.cpp
@@ -19,6 +19,10 @@
#include "SkGr.h"
#include "SkGradientShader.h"
+#define YSIZE 8
+#define USIZE 4
+#define VSIZE 4
+
namespace skiagm {
/**
* This GM directly exercises GrYUVtoRGBEffect.
@@ -35,14 +39,16 @@
}
SkISize onISize() SK_OVERRIDE {
- return SkISize::Make(334, 128);
+ return SkISize::Make(238, 84);
}
void onOnceBeforeDraw() SK_OVERRIDE {
- SkImageInfo info = SkImageInfo::MakeA8(24, 24);
- fBmp[0].allocPixels(info);
- fBmp[1].allocPixels(info);
- fBmp[2].allocPixels(info);
+ SkImageInfo yinfo = SkImageInfo::MakeA8(YSIZE, YSIZE);
+ fBmp[0].allocPixels(yinfo);
+ SkImageInfo uinfo = SkImageInfo::MakeA8(USIZE, USIZE);
+ fBmp[1].allocPixels(uinfo);
+ SkImageInfo vinfo = SkImageInfo::MakeA8(VSIZE, VSIZE);
+ fBmp[2].allocPixels(vinfo);
unsigned char* pixels[3];
for (int i = 0; i < 3; ++i) {
pixels[i] = (unsigned char*)fBmp[i].getPixels();
@@ -51,8 +57,9 @@
const int limit[] = {255, 0, 255};
const int invl[] = {0, 255, 0};
const int inc[] = {1, -1, 1};
- for (int j = 0; j < 576; ++j) {
- for (int i = 0; i < 3; ++i) {
+ for (int i = 0; i < 3; ++i) {
+ const int nbBytes = fBmp[i].rowBytes() * fBmp[i].height();
+ for (int j = 0; j < nbBytes; ++j) {
pixels[i][j] = (unsigned char)color[i];
color[i] = (color[i] == limit[i]) ? invl[i] : color[i] + inc[i];
}
@@ -88,7 +95,8 @@
static const SkScalar kDrawPad = 10.f;
static const SkScalar kTestPad = 10.f;
- static const SkScalar kColorSpaceOffset = 64.f;
+ static const SkScalar kColorSpaceOffset = 36.f;
+ SkISize sizes[3] = {{YSIZE, YSIZE}, {USIZE, USIZE}, {VSIZE, VSIZE}};
for (int space = kJPEG_SkYUVColorSpace; space <= kLastEnum_SkYUVColorSpace;
++space) {
@@ -105,9 +113,10 @@
for (int i = 0; i < 6; ++i) {
SkAutoTUnref<GrFragmentProcessor> fp(
GrYUVtoRGBEffect::Create(texture[indices[i][0]],
- texture[indices[i][1]],
- texture[indices[i][2]],
- static_cast<SkYUVColorSpace>(space)));
+ texture[indices[i][1]],
+ texture[indices[i][2]],
+ sizes,
+ static_cast<SkYUVColorSpace>(space)));
if (fp) {
SkMatrix viewMatrix;
viewMatrix.setTranslate(x, y);
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index 9ee415e..2d96ebc 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -391,7 +391,7 @@
SkAutoTUnref<GrFragmentProcessor>
yuvToRgbProcessor(GrYUVtoRGBEffect::Create(yuvTextures[0], yuvTextures[1], yuvTextures[2],
- yuvInfo.fColorSpace));
+ yuvInfo.fSize, yuvInfo.fColorSpace));
GrPaint paint;
paint.addColorProcessor(yuvToRgbProcessor);
SkRect r = SkRect::MakeWH(SkIntToScalar(yuvInfo.fSize[0].fWidth),
diff --git a/src/gpu/effects/GrYUVtoRGBEffect.cpp b/src/gpu/effects/GrYUVtoRGBEffect.cpp
index 7361352..8daf348 100644
--- a/src/gpu/effects/GrYUVtoRGBEffect.cpp
+++ b/src/gpu/effects/GrYUVtoRGBEffect.cpp
@@ -18,8 +18,22 @@
class YUVtoRGBEffect : public GrFragmentProcessor {
public:
static GrFragmentProcessor* Create(GrTexture* yTexture, GrTexture* uTexture,
- GrTexture* vTexture, SkYUVColorSpace colorSpace) {
- return SkNEW_ARGS(YUVtoRGBEffect, (yTexture, uTexture, vTexture, colorSpace));
+ GrTexture* vTexture, SkISize sizes[3],
+ SkYUVColorSpace colorSpace) {
+ SkScalar w[3], h[3];
+ w[0] = SkIntToScalar(sizes[0].fWidth) / SkIntToScalar(yTexture->width());
+ h[0] = SkIntToScalar(sizes[0].fHeight) / SkIntToScalar(yTexture->height());
+ w[1] = SkIntToScalar(sizes[1].fWidth) / SkIntToScalar(uTexture->width());
+ h[1] = SkIntToScalar(sizes[1].fHeight) / SkIntToScalar(uTexture->height());
+ w[2] = SkIntToScalar(sizes[2].fWidth) / SkIntToScalar(vTexture->width());
+ h[2] = SkIntToScalar(sizes[2].fHeight) / SkIntToScalar(vTexture->height());
+ SkMatrix yuvMatrix[3];
+ yuvMatrix[0] = GrCoordTransform::MakeDivByTextureWHMatrix(yTexture);
+ yuvMatrix[1] = yuvMatrix[0];
+ yuvMatrix[1].preScale(w[1] / w[0], h[1] / h[0]);
+ yuvMatrix[2] = yuvMatrix[0];
+ yuvMatrix[2].preScale(w[2] / w[0], h[2] / h[0]);
+ return SkNEW_ARGS(YUVtoRGBEffect, (yTexture, uTexture, vTexture, yuvMatrix, colorSpace));
}
const char* name() const SK_OVERRIDE { return "YUV to RGB"; }
@@ -53,9 +67,9 @@
fsBuilder->codeAppendf("\t%s = vec4(\n\t\t", outputColor);
fsBuilder->appendTextureLookup(samplers[0], coords[0].c_str(), coords[0].getType());
fsBuilder->codeAppend(".r,\n\t\t");
- fsBuilder->appendTextureLookup(samplers[1], coords[0].c_str(), coords[0].getType());
+ fsBuilder->appendTextureLookup(samplers[1], coords[1].c_str(), coords[1].getType());
fsBuilder->codeAppend(".r,\n\t\t");
- fsBuilder->appendTextureLookup(samplers[2], coords[0].c_str(), coords[0].getType());
+ fsBuilder->appendTextureLookup(samplers[2], coords[2].c_str(), coords[2].getType());
fsBuilder->codeAppendf(".r,\n\t\t1.0) * %s;\n", yuvMatrix);
}
@@ -89,18 +103,20 @@
private:
YUVtoRGBEffect(GrTexture* yTexture, GrTexture* uTexture, GrTexture* vTexture,
- SkYUVColorSpace colorSpace)
- : fCoordTransform(kLocal_GrCoordSet,
- GrCoordTransform::MakeDivByTextureWHMatrix(yTexture),
- yTexture, GrTextureParams::kNone_FilterMode)
+ SkMatrix yuvMatrix[3], SkYUVColorSpace colorSpace)
+ : fYTransform(kLocal_GrCoordSet, yuvMatrix[0], yTexture, GrTextureParams::kNone_FilterMode)
, fYAccess(yTexture)
+ , fUTransform(kLocal_GrCoordSet, yuvMatrix[1], uTexture, GrTextureParams::kNone_FilterMode)
, fUAccess(uTexture)
+ , fVTransform(kLocal_GrCoordSet, yuvMatrix[2], vTexture, GrTextureParams::kNone_FilterMode)
, fVAccess(vTexture)
, fColorSpace(colorSpace) {
this->initClassID<YUVtoRGBEffect>();
- this->addCoordTransform(&fCoordTransform);
+ this->addCoordTransform(&fYTransform);
this->addTextureAccess(&fYAccess);
+ this->addCoordTransform(&fUTransform);
this->addTextureAccess(&fUAccess);
+ this->addCoordTransform(&fVTransform);
this->addTextureAccess(&fVAccess);
}
@@ -115,9 +131,11 @@
GrInvariantOutput::kWillNot_ReadInput);
}
- GrCoordTransform fCoordTransform;
+ GrCoordTransform fYTransform;
GrTextureAccess fYAccess;
+ GrCoordTransform fUTransform;
GrTextureAccess fUAccess;
+ GrCoordTransform fVTransform;
GrTextureAccess fVAccess;
SkYUVColorSpace fColorSpace;
@@ -140,6 +158,7 @@
GrFragmentProcessor*
GrYUVtoRGBEffect::Create(GrTexture* yTexture, GrTexture* uTexture, GrTexture* vTexture,
- SkYUVColorSpace colorSpace) {
- return YUVtoRGBEffect::Create(yTexture, uTexture, vTexture, colorSpace);
+ SkISize sizes[3], SkYUVColorSpace colorSpace) {
+ SkASSERT(yTexture && uTexture && vTexture && sizes);
+ return YUVtoRGBEffect::Create(yTexture, uTexture, vTexture, sizes, colorSpace);
}
diff --git a/src/gpu/effects/GrYUVtoRGBEffect.h b/src/gpu/effects/GrYUVtoRGBEffect.h
index 4c057bd..2a2e74a 100644
--- a/src/gpu/effects/GrYUVtoRGBEffect.h
+++ b/src/gpu/effects/GrYUVtoRGBEffect.h
@@ -18,7 +18,7 @@
* Creates an effect that performs color conversion from YUV to RGB
*/
GrFragmentProcessor* Create(GrTexture* yTexture, GrTexture* uTexture, GrTexture* vTexture,
- SkYUVColorSpace colorSpace);
+ SkISize sizes[3], SkYUVColorSpace colorSpace);
};
#endif