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

Committed: https://skia.googlesource.com/skia/+/e6eddf7dd85add7da41f22f2643bdd573ad1f1cf

Review URL: https://codereview.chromium.org/922273002
This commit is contained in:
sugoi 2015-02-13 13:57:09 -08:00 committed by Commit bot
parent db0f9516ae
commit 4ccce7ea61
4 changed files with 53 additions and 25 deletions

View File

@ -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 @@ protected:
}
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 @@ protected:
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 size_t nbBytes = fBmp[i].rowBytes() * fBmp[i].height();
for (size_t 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 @@ protected:
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 @@ protected:
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);

View File

@ -391,7 +391,7 @@ static GrTexture* load_yuv_texture(GrContext* ctx, const GrContentKey& optionalK
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),

View File

@ -18,8 +18,22 @@ namespace {
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 @@ public:
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 @@ public:
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 @@ private:
GrInvariantOutput::kWillNot_ReadInput);
}
GrCoordTransform fCoordTransform;
GrCoordTransform fYTransform;
GrTextureAccess fYAccess;
GrCoordTransform fUTransform;
GrTextureAccess fUAccess;
GrCoordTransform fVTransform;
GrTextureAccess fVAccess;
SkYUVColorSpace fColorSpace;
@ -140,6 +158,7 @@ const GrGLfloat YUVtoRGBEffect::GLProcessor::kRec601ConversionMatrix[16] = {
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);
}

View File

@ -18,7 +18,7 @@ namespace GrYUVtoRGBEffect {
* 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