Make swizzling in read/write pixel copy code more generic

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1617433002

Review URL: https://codereview.chromium.org/1617433002
This commit is contained in:
bsalomon 2016-01-22 07:17:34 -08:00 committed by Commit bot
parent 0ac723b6f4
commit 6c9cd55f00
7 changed files with 114 additions and 90 deletions

View File

@ -43,6 +43,7 @@ class GrTextContext;
class GrTextureParams; class GrTextureParams;
class GrVertexBuffer; class GrVertexBuffer;
class GrStrokeInfo; class GrStrokeInfo;
class GrSwizzle;
class SkTraceMemoryDump; class SkTraceMemoryDump;
class SK_API GrContext : public SkRefCnt { class SK_API GrContext : public SkRefCnt {
@ -429,11 +430,11 @@ private:
/** /**
* These functions create premul <-> unpremul effects if it is possible to generate a pair * These functions create premul <-> unpremul effects if it is possible to generate a pair
* of effects that make a readToUPM->writeToPM->readToUPM cycle invariant. Otherwise, they * of effects that make a readToUPM->writeToPM->readToUPM cycle invariant. Otherwise, they
* return NULL. * return NULL. They also can perform a swizzle as part of the draw.
*/ */
const GrFragmentProcessor* createPMToUPMEffect(GrTexture*, bool swapRAndB, const GrFragmentProcessor* createPMToUPMEffect(GrTexture*, const GrSwizzle&,
const SkMatrix&) const; const SkMatrix&) const;
const GrFragmentProcessor* createUPMToPMEffect(GrTexture*, bool swapRAndB, const GrFragmentProcessor* createUPMToPMEffect(GrTexture*, const GrSwizzle&,
const SkMatrix&) const; const SkMatrix&) const;
/** Called before either of the above two functions to determine the appropriate fragment /** Called before either of the above two functions to determine the appropriate fragment
processors for conversions. This must be called by readSurfacePixels before a mutex is processors for conversions. This must be called by readSurfacePixels before a mutex is

View File

@ -298,7 +298,7 @@ bool GrContext::writeSurfacePixels(GrSurface* surface,
SkMatrix textureMatrix; SkMatrix textureMatrix;
textureMatrix.setIDiv(tempTexture->width(), tempTexture->height()); textureMatrix.setIDiv(tempTexture->width(), tempTexture->height());
if (applyPremulToSrc) { if (applyPremulToSrc) {
fp.reset(this->createUPMToPMEffect(tempTexture, tempDrawInfo.fSwapRAndB, fp.reset(this->createUPMToPMEffect(tempTexture, tempDrawInfo.fSwizzle,
textureMatrix)); textureMatrix));
// If premultiplying was the only reason for the draw, fall back to a straight write. // If premultiplying was the only reason for the draw, fall back to a straight write.
if (!fp) { if (!fp) {
@ -311,7 +311,7 @@ bool GrContext::writeSurfacePixels(GrSurface* surface,
} }
if (tempTexture) { if (tempTexture) {
if (!fp) { if (!fp) {
fp.reset(GrConfigConversionEffect::Create(tempTexture, tempDrawInfo.fSwapRAndB, fp.reset(GrConfigConversionEffect::Create(tempTexture, tempDrawInfo.fSwizzle,
GrConfigConversionEffect::kNone_PMConversion, textureMatrix)); GrConfigConversionEffect::kNone_PMConversion, textureMatrix));
if (!fp) { if (!fp) {
return false; return false;
@ -334,7 +334,7 @@ bool GrContext::writeSurfacePixels(GrSurface* surface,
applyPremulToSrc = false; applyPremulToSrc = false;
} }
if (!fGpu->writePixels(tempTexture, 0, 0, width, height, if (!fGpu->writePixels(tempTexture, 0, 0, width, height,
tempDrawInfo.fTempSurfaceDesc.fConfig, buffer, tempDrawInfo.fWriteConfig, buffer,
rowBytes)) { rowBytes)) {
return false; return false;
} }
@ -438,7 +438,7 @@ bool GrContext::readSurfacePixels(GrSurface* src,
textureMatrix.postIDiv(src->width(), src->height()); textureMatrix.postIDiv(src->width(), src->height());
SkAutoTUnref<const GrFragmentProcessor> fp; SkAutoTUnref<const GrFragmentProcessor> fp;
if (unpremul) { if (unpremul) {
fp.reset(this->createPMToUPMEffect(src->asTexture(), tempDrawInfo.fSwapRAndB, fp.reset(this->createPMToUPMEffect(src->asTexture(), tempDrawInfo.fSwizzle,
textureMatrix)); textureMatrix));
if (fp) { if (fp) {
unpremul = false; // we no longer need to do this on CPU after the read back. unpremul = false; // we no longer need to do this on CPU after the read back.
@ -449,7 +449,7 @@ bool GrContext::readSurfacePixels(GrSurface* src,
} }
} }
if (!fp && temp) { if (!fp && temp) {
fp.reset(GrConfigConversionEffect::Create(src->asTexture(), tempDrawInfo.fSwapRAndB, fp.reset(GrConfigConversionEffect::Create(src->asTexture(), tempDrawInfo.fSwizzle,
GrConfigConversionEffect::kNone_PMConversion, textureMatrix)); GrConfigConversionEffect::kNone_PMConversion, textureMatrix));
} }
if (fp) { if (fp) {
@ -473,10 +473,7 @@ bool GrContext::readSurfacePixels(GrSurface* src,
GrPixelConfig configToRead = dstConfig; GrPixelConfig configToRead = dstConfig;
if (didTempDraw) { if (didTempDraw) {
this->flushSurfaceWrites(surfaceToRead); this->flushSurfaceWrites(surfaceToRead);
// We swapped R and B while doing the temp draw. Swap back on the read. configToRead = tempDrawInfo.fReadConfig;
if (tempDrawInfo.fSwapRAndB) {
configToRead = GrPixelConfigSwapRAndB(dstConfig);
}
} }
if (!fGpu->readPixels(surfaceToRead, left, top, width, height, configToRead, buffer, if (!fGpu->readPixels(surfaceToRead, left, top, width, height, configToRead, buffer,
rowBytes)) { rowBytes)) {
@ -608,7 +605,7 @@ void GrContext::testPMConversionsIfNecessary(uint32_t flags) {
} }
const GrFragmentProcessor* GrContext::createPMToUPMEffect(GrTexture* texture, const GrFragmentProcessor* GrContext::createPMToUPMEffect(GrTexture* texture,
bool swapRAndB, const GrSwizzle& swizzle,
const SkMatrix& matrix) const { const SkMatrix& matrix) const {
ASSERT_SINGLE_OWNER ASSERT_SINGLE_OWNER
// We should have already called this->testPMConversionsIfNecessary(). // We should have already called this->testPMConversionsIfNecessary().
@ -616,14 +613,14 @@ const GrFragmentProcessor* GrContext::createPMToUPMEffect(GrTexture* texture,
GrConfigConversionEffect::PMConversion pmToUPM = GrConfigConversionEffect::PMConversion pmToUPM =
static_cast<GrConfigConversionEffect::PMConversion>(fPMToUPMConversion); static_cast<GrConfigConversionEffect::PMConversion>(fPMToUPMConversion);
if (GrConfigConversionEffect::kNone_PMConversion != pmToUPM) { if (GrConfigConversionEffect::kNone_PMConversion != pmToUPM) {
return GrConfigConversionEffect::Create(texture, swapRAndB, pmToUPM, matrix); return GrConfigConversionEffect::Create(texture, swizzle, pmToUPM, matrix);
} else { } else {
return nullptr; return nullptr;
} }
} }
const GrFragmentProcessor* GrContext::createUPMToPMEffect(GrTexture* texture, const GrFragmentProcessor* GrContext::createUPMToPMEffect(GrTexture* texture,
bool swapRAndB, const GrSwizzle& swizzle,
const SkMatrix& matrix) const { const SkMatrix& matrix) const {
ASSERT_SINGLE_OWNER ASSERT_SINGLE_OWNER
// We should have already called this->testPMConversionsIfNecessary(). // We should have already called this->testPMConversionsIfNecessary().
@ -631,7 +628,7 @@ const GrFragmentProcessor* GrContext::createUPMToPMEffect(GrTexture* texture,
GrConfigConversionEffect::PMConversion upmToPM = GrConfigConversionEffect::PMConversion upmToPM =
static_cast<GrConfigConversionEffect::PMConversion>(fUPMToPMConversion); static_cast<GrConfigConversionEffect::PMConversion>(fUPMToPMConversion);
if (GrConfigConversionEffect::kNone_PMConversion != upmToPM) { if (GrConfigConversionEffect::kNone_PMConversion != upmToPM) {
return GrConfigConversionEffect::Create(texture, swapRAndB, upmToPM, matrix); return GrConfigConversionEffect::Create(texture, swizzle, upmToPM, matrix);
} else { } else {
return nullptr; return nullptr;
} }

View File

@ -11,6 +11,7 @@
#include "GrPipelineBuilder.h" #include "GrPipelineBuilder.h"
#include "GrProgramDesc.h" #include "GrProgramDesc.h"
#include "GrStencil.h" #include "GrStencil.h"
#include "GrSwizzle.h"
#include "GrTextureParamsAdjuster.h" #include "GrTextureParamsAdjuster.h"
#include "GrXferProcessor.h" #include "GrXferProcessor.h"
#include "SkPath.h" #include "SkPath.h"
@ -155,13 +156,15 @@ public:
/** Indicates whether there is a performance advantage to using an exact match texture /** Indicates whether there is a performance advantage to using an exact match texture
(in terms of width and height) for the intermediate texture instead of approximate. */ (in terms of width and height) for the intermediate texture instead of approximate. */
bool fUseExactScratch; bool fUseExactScratch;
/** The caller should swap the R and B channel in the temp draw and then instead of reading /** Swizzle to apply during the draw. This is used to compensate for either feature or
the desired config back it should read GrPixelConfigSwapRAndB(readConfig). The swap performance limitations in the underlying 3D API. */
during the draw and the swap at readback time cancel and the client gets the correct GrSwizzle fSwizzle;
data. The swapped read back is either faster for or required by the underlying backend /** The config that should be used to read from the temp surface after the draw. This may be
3D API. */ different than the original read config in order to compensate for swizzling. The
bool fSwapRAndB; read data will effectively be in the original read config. */
GrPixelConfig fReadConfig;
}; };
/** Describes why an intermediate draw must/should be performed before readPixels. */ /** Describes why an intermediate draw must/should be performed before readPixels. */
enum DrawPreference { enum DrawPreference {
/** On input means that the caller would proceed without draw if the GrGpu doesn't request /** On input means that the caller would proceed without draw if the GrGpu doesn't request
@ -202,12 +205,13 @@ public:
should upload the pixels such that the upper left pixel of the upload rect is at 0,0 in should upload the pixels such that the upper left pixel of the upload rect is at 0,0 in
the intermediate surface.*/ the intermediate surface.*/
GrSurfaceDesc fTempSurfaceDesc; GrSurfaceDesc fTempSurfaceDesc;
/** If set, fTempSurfaceDesc's config will be a R/B swap of the src pixel config. The caller /** Swizzle to apply during the draw. This is used to compensate for either feature or
should upload the pixels as is such that R and B will be swapped in the intermediate performance limitations in the underlying 3D API. */
surface. When the intermediate is drawn to the dst the shader should swap R/B again GrSwizzle fSwizzle;
such that the correct swizzle results in the dst. This is done to work around either /** The config that should be specified when uploading the *original* data to the temp
performance or API restrictions in the backend 3D API implementation. */ surface before the draw. This may be different than the original src data config in
bool fSwapRAndB; order to compensate for swizzling that will occur when drawing. */
GrPixelConfig fWriteConfig;
}; };
/** /**

View File

@ -8,8 +8,8 @@
#ifndef GrSwizzle_DEFINED #ifndef GrSwizzle_DEFINED
#define GrSwizzle_DEFINED #define GrSwizzle_DEFINED
#include "GrTypes.h"
#include "GrColor.h" #include "GrColor.h"
#include "SkRandom.h"
/** Represents a rgba swizzle. It can be converted either into a string or a eight bit int. /** Represents a rgba swizzle. It can be converted either into a string or a eight bit int.
Currently there is no way to specify an arbitrary swizzle, just some static swizzles and an Currently there is no way to specify an arbitrary swizzle, just some static swizzles and an
@ -84,6 +84,22 @@ public:
return gBGRA; return gBGRA;
} }
static const GrSwizzle& CreateRandom(SkRandom* random) {
switch (random->nextU() % 4) {
case 0:
return RGBA();
case 1:
return BGRA();
case 2:
return RRRR();
case 3:
return AAAA();
default:
SkFAIL("Mod is broken?!?");
return RGBA();
}
}
private: private:
char fSwiz[5]; char fSwiz[5];
uint8_t fKey; uint8_t fKey;

View File

@ -16,14 +16,13 @@
class GrGLConfigConversionEffect : public GrGLSLFragmentProcessor { class GrGLConfigConversionEffect : public GrGLSLFragmentProcessor {
public: public:
GrGLConfigConversionEffect(const GrProcessor& processor) { GrGLConfigConversionEffect() {}
const GrConfigConversionEffect& configConversionEffect =
processor.cast<GrConfigConversionEffect>();
fSwapRedAndBlue = configConversionEffect.swapsRedAndBlue();
fPMConversion = configConversionEffect.pmConversion();
}
virtual void emitCode(EmitArgs& args) override { virtual void emitCode(EmitArgs& args) override {
const GrConfigConversionEffect& cce = args.fFp.cast<GrConfigConversionEffect>();
const GrSwizzle& swizzle = cce.swizzle();
GrConfigConversionEffect::PMConversion pmConversion = cce.pmConversion();
// Using highp for GLES here in order to avoid some precision issues on specific GPUs. // Using highp for GLES here in order to avoid some precision issues on specific GPUs.
GrGLSLShaderVar tmpVar("tmpColor", kVec4f_GrSLType, 0, kHigh_GrSLPrecision); GrGLSLShaderVar tmpVar("tmpColor", kVec4f_GrSLType, 0, kHigh_GrSLPrecision);
SkString tmpDecl; SkString tmpDecl;
@ -38,16 +37,16 @@ public:
args.fCoords[0].getType()); args.fCoords[0].getType());
fragBuilder->codeAppend(";"); fragBuilder->codeAppend(";");
if (GrConfigConversionEffect::kNone_PMConversion == fPMConversion) { if (GrConfigConversionEffect::kNone_PMConversion == pmConversion) {
SkASSERT(fSwapRedAndBlue); SkASSERT(GrSwizzle::RGBA() != swizzle);
fragBuilder->codeAppendf("%s = %s.bgra;", args.fOutputColor, tmpVar.c_str()); fragBuilder->codeAppendf("%s = %s.%s;", args.fOutputColor, tmpVar.c_str(),
swizzle.c_str());
} else { } else {
const char* swiz = fSwapRedAndBlue ? "bgr" : "rgb"; switch (pmConversion) {
switch (fPMConversion) {
case GrConfigConversionEffect::kMulByAlpha_RoundUp_PMConversion: case GrConfigConversionEffect::kMulByAlpha_RoundUp_PMConversion:
fragBuilder->codeAppendf( fragBuilder->codeAppendf(
"%s = vec4(ceil(%s.%s * %s.a * 255.0) / 255.0, %s.a);", "%s = vec4(ceil(%s.rgb * %s.a * 255.0) / 255.0, %s.a);",
tmpVar.c_str(), tmpVar.c_str(), swiz, tmpVar.c_str(), tmpVar.c_str()); tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str());
break; break;
case GrConfigConversionEffect::kMulByAlpha_RoundDown_PMConversion: case GrConfigConversionEffect::kMulByAlpha_RoundDown_PMConversion:
// Add a compensation(0.001) here to avoid the side effect of the floor operation. // Add a compensation(0.001) here to avoid the side effect of the floor operation.
@ -55,24 +54,28 @@ public:
// is less than the integer value converted from %s.r by 1 when the %s.r is // is less than the integer value converted from %s.r by 1 when the %s.r is
// converted from the integer value 2^n, such as 1, 2, 4, 8, etc. // converted from the integer value 2^n, such as 1, 2, 4, 8, etc.
fragBuilder->codeAppendf( fragBuilder->codeAppendf(
"%s = vec4(floor(%s.%s * %s.a * 255.0 + 0.001) / 255.0, %s.a);", "%s = vec4(floor(%s.rgb * %s.a * 255.0 + 0.001) / 255.0, %s.a);",
tmpVar.c_str(), tmpVar.c_str(), swiz, tmpVar.c_str(), tmpVar.c_str()); tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str());
break; break;
case GrConfigConversionEffect::kDivByAlpha_RoundUp_PMConversion: case GrConfigConversionEffect::kDivByAlpha_RoundUp_PMConversion:
fragBuilder->codeAppendf( fragBuilder->codeAppendf(
"%s = %s.a <= 0.0 ? vec4(0,0,0,0) : vec4(ceil(%s.%s / %s.a * 255.0) / 255.0, %s.a);", "%s = %s.a <= 0.0 ? vec4(0,0,0,0) : vec4(ceil(%s.rgb / %s.a * 255.0) / 255.0, %s.a);",
tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str(), swiz, tmpVar.c_str(), tmpVar.c_str()); tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str(),
tmpVar.c_str());
break; break;
case GrConfigConversionEffect::kDivByAlpha_RoundDown_PMConversion: case GrConfigConversionEffect::kDivByAlpha_RoundDown_PMConversion:
fragBuilder->codeAppendf( fragBuilder->codeAppendf(
"%s = %s.a <= 0.0 ? vec4(0,0,0,0) : vec4(floor(%s.%s / %s.a * 255.0) / 255.0, %s.a);", "%s = %s.a <= 0.0 ? vec4(0,0,0,0) : vec4(floor(%s.rgb / %s.a * 255.0) / 255.0, %s.a);",
tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str(), swiz, tmpVar.c_str(), tmpVar.c_str()); tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str(),
tmpVar.c_str());
break; break;
default: default:
SkFAIL("Unknown conversion op."); SkFAIL("Unknown conversion op.");
break; break;
} }
fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, tmpVar.c_str()); fragBuilder->codeAppendf("%s = %s.%s;", args.fOutputColor, tmpVar.c_str(),
swizzle.c_str());
} }
SkString modulate; SkString modulate;
GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor); GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor);
@ -81,15 +84,12 @@ public:
static inline void GenKey(const GrProcessor& processor, const GrGLSLCaps&, static inline void GenKey(const GrProcessor& processor, const GrGLSLCaps&,
GrProcessorKeyBuilder* b) { GrProcessorKeyBuilder* b) {
const GrConfigConversionEffect& conv = processor.cast<GrConfigConversionEffect>(); const GrConfigConversionEffect& cce = processor.cast<GrConfigConversionEffect>();
uint32_t key = (conv.swapsRedAndBlue() ? 0 : 1) | (conv.pmConversion() << 1); uint32_t key = (cce.swizzle().asKey()) | (cce.pmConversion() << 16);
b->add32(key); b->add32(key);
} }
private: private:
bool fSwapRedAndBlue;
GrConfigConversionEffect::PMConversion fPMConversion;
typedef GrGLSLFragmentProcessor INHERITED; typedef GrGLSLFragmentProcessor INHERITED;
}; };
@ -97,11 +97,11 @@ private:
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
GrConfigConversionEffect::GrConfigConversionEffect(GrTexture* texture, GrConfigConversionEffect::GrConfigConversionEffect(GrTexture* texture,
bool swapRedAndBlue, const GrSwizzle& swizzle,
PMConversion pmConversion, PMConversion pmConversion,
const SkMatrix& matrix) const SkMatrix& matrix)
: INHERITED(texture, matrix) : INHERITED(texture, matrix)
, fSwapRedAndBlue(swapRedAndBlue) , fSwizzle(swizzle)
, fPMConversion(pmConversion) { , fPMConversion(pmConversion) {
this->initClassID<GrConfigConversionEffect>(); this->initClassID<GrConfigConversionEffect>();
// We expect to get here with non-BGRA/RGBA only if we're doing not doing a premul/unpremul // We expect to get here with non-BGRA/RGBA only if we're doing not doing a premul/unpremul
@ -110,12 +110,12 @@ GrConfigConversionEffect::GrConfigConversionEffect(GrTexture* texture,
kBGRA_8888_GrPixelConfig == texture->config()) || kBGRA_8888_GrPixelConfig == texture->config()) ||
kNone_PMConversion == pmConversion); kNone_PMConversion == pmConversion);
// Why did we pollute our texture cache instead of using a GrSingleTextureEffect? // Why did we pollute our texture cache instead of using a GrSingleTextureEffect?
SkASSERT(swapRedAndBlue || kNone_PMConversion != pmConversion); SkASSERT(swizzle != GrSwizzle::RGBA() || kNone_PMConversion != pmConversion);
} }
bool GrConfigConversionEffect::onIsEqual(const GrFragmentProcessor& s) const { bool GrConfigConversionEffect::onIsEqual(const GrFragmentProcessor& s) const {
const GrConfigConversionEffect& other = s.cast<GrConfigConversionEffect>(); const GrConfigConversionEffect& other = s.cast<GrConfigConversionEffect>();
return other.fSwapRedAndBlue == fSwapRedAndBlue && return other.fSwizzle == fSwizzle &&
other.fPMConversion == fPMConversion; other.fPMConversion == fPMConversion;
} }
@ -129,14 +129,12 @@ GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrConfigConversionEffect);
const GrFragmentProcessor* GrConfigConversionEffect::TestCreate(GrProcessorTestData* d) { const GrFragmentProcessor* GrConfigConversionEffect::TestCreate(GrProcessorTestData* d) {
PMConversion pmConv = static_cast<PMConversion>(d->fRandom->nextULessThan(kPMConversionCnt)); PMConversion pmConv = static_cast<PMConversion>(d->fRandom->nextULessThan(kPMConversionCnt));
bool swapRB; GrSwizzle swizzle;
if (kNone_PMConversion == pmConv) { do {
swapRB = true; swizzle = GrSwizzle::CreateRandom(d->fRandom);
} else { } while (pmConv == kNone_PMConversion && swizzle == GrSwizzle::RGBA());
swapRB = d->fRandom->nextBool();
}
return new GrConfigConversionEffect(d->fTextures[GrProcessorUnitTest::kSkiaPMTextureIdx], return new GrConfigConversionEffect(d->fTextures[GrProcessorUnitTest::kSkiaPMTextureIdx],
swapRB, pmConv, GrTest::TestMatrix(d->fRandom)); swizzle, pmConv, GrTest::TestMatrix(d->fRandom));
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -147,7 +145,7 @@ void GrConfigConversionEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
} }
GrGLSLFragmentProcessor* GrConfigConversionEffect::onCreateGLSLInstance() const { GrGLSLFragmentProcessor* GrConfigConversionEffect::onCreateGLSLInstance() const {
return new GrGLConfigConversionEffect(*this); return new GrGLConfigConversionEffect();
} }
@ -215,11 +213,11 @@ void GrConfigConversionEffect::TestForPreservingPMConversions(GrContext* context
GrPaint paint2; GrPaint paint2;
GrPaint paint3; GrPaint paint3;
SkAutoTUnref<GrFragmentProcessor> pmToUPM1(new GrConfigConversionEffect( SkAutoTUnref<GrFragmentProcessor> pmToUPM1(new GrConfigConversionEffect(
dataTex, false, *pmToUPMRule, SkMatrix::I())); dataTex, GrSwizzle::RGBA(), *pmToUPMRule, SkMatrix::I()));
SkAutoTUnref<GrFragmentProcessor> upmToPM(new GrConfigConversionEffect( SkAutoTUnref<GrFragmentProcessor> upmToPM(new GrConfigConversionEffect(
readTex, false, *upmToPMRule, SkMatrix::I())); readTex, GrSwizzle::RGBA(), *upmToPMRule, SkMatrix::I()));
SkAutoTUnref<GrFragmentProcessor> pmToUPM2(new GrConfigConversionEffect( SkAutoTUnref<GrFragmentProcessor> pmToUPM2(new GrConfigConversionEffect(
tempTex, false, *pmToUPMRule, SkMatrix::I())); tempTex, GrSwizzle::RGBA(), *pmToUPMRule, SkMatrix::I()));
paint1.addColorFragmentProcessor(pmToUPM1); paint1.addColorFragmentProcessor(pmToUPM1);
paint1.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); paint1.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
@ -289,10 +287,10 @@ void GrConfigConversionEffect::TestForPreservingPMConversions(GrContext* context
} }
const GrFragmentProcessor* GrConfigConversionEffect::Create(GrTexture* texture, const GrFragmentProcessor* GrConfigConversionEffect::Create(GrTexture* texture,
bool swapRedAndBlue, const GrSwizzle& swizzle,
PMConversion pmConversion, PMConversion pmConversion,
const SkMatrix& matrix) { const SkMatrix& matrix) {
if (!swapRedAndBlue && kNone_PMConversion == pmConversion) { if (swizzle == GrSwizzle::RGBA() && kNone_PMConversion == pmConversion) {
// If we returned a GrConfigConversionEffect that was equivalent to a GrSimpleTextureEffect // If we returned a GrConfigConversionEffect that was equivalent to a GrSimpleTextureEffect
// then we may pollute our texture cache with redundant shaders. So in the case that no // then we may pollute our texture cache with redundant shaders. So in the case that no
// conversions were requested we instead return a GrSimpleTextureEffect. // conversions were requested we instead return a GrSimpleTextureEffect.
@ -304,6 +302,6 @@ const GrFragmentProcessor* GrConfigConversionEffect::Create(GrTexture* texture,
// The PM conversions assume colors are 0..255 // The PM conversions assume colors are 0..255
return nullptr; return nullptr;
} }
return new GrConfigConversionEffect(texture, swapRedAndBlue, pmConversion, matrix); return new GrConfigConversionEffect(texture, swizzle, pmConversion, matrix);
} }
} }

View File

@ -9,14 +9,14 @@
#define GrConfigConversionEffect_DEFINED #define GrConfigConversionEffect_DEFINED
#include "GrSingleTextureEffect.h" #include "GrSingleTextureEffect.h"
#include "GrSwizzle.h"
class GrInvariantOutput; class GrInvariantOutput;
/** /**
* This class is used to perform config conversions. Clients may want to read/write data that is * This class is used to perform config conversions. Clients may want to read/write data that is
* unpremultiplied. Also on some systems reading/writing BGRA or RGBA is faster. In those cases we * unpremultiplied. Additionally, the channels may also be swizzled for optimal readback/upload
* read/write using the faster path and perform an R/B swap in the shader if the client data is in * performance.
* the slower config.
*/ */
class GrConfigConversionEffect : public GrSingleTextureEffect { class GrConfigConversionEffect : public GrSingleTextureEffect {
public: public:
@ -33,12 +33,12 @@ public:
kPMConversionCnt kPMConversionCnt
}; };
static const GrFragmentProcessor* Create(GrTexture*, bool swapRedAndBlue, PMConversion, static const GrFragmentProcessor* Create(GrTexture*, const GrSwizzle&, PMConversion,
const SkMatrix&); const SkMatrix&);
const char* name() const override { return "Config Conversion"; } const char* name() const override { return "Config Conversion"; }
bool swapsRedAndBlue() const { return fSwapRedAndBlue; } const GrSwizzle& swizzle() const { return fSwizzle; }
PMConversion pmConversion() const { return fPMConversion; } PMConversion pmConversion() const { return fPMConversion; }
// This function determines whether it is possible to choose PM->UPM and UPM->PM conversions // This function determines whether it is possible to choose PM->UPM and UPM->PM conversions
@ -52,7 +52,7 @@ public:
private: private:
GrConfigConversionEffect(GrTexture*, GrConfigConversionEffect(GrTexture*,
bool swapRedAndBlue, const GrSwizzle&,
PMConversion pmConversion, PMConversion pmConversion,
const SkMatrix& matrix); const SkMatrix& matrix);
@ -64,7 +64,7 @@ private:
void onComputeInvariantOutput(GrInvariantOutput* inout) const override; void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
bool fSwapRedAndBlue; GrSwizzle fSwizzle;
PMConversion fPMConversion; PMConversion fPMConversion;
GR_DECLARE_FRAGMENT_PROCESSOR_TEST; GR_DECLARE_FRAGMENT_PROCESSOR_TEST;

View File

@ -670,7 +670,9 @@ bool GrGLGpu::onGetWritePixelsInfo(GrSurface* dstSurface, int width, int height,
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference); ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
} }
tempDrawInfo->fSwapRAndB = false; // Start off assuming no swizzling
tempDrawInfo->fSwizzle = GrSwizzle::RGBA();
tempDrawInfo->fWriteConfig = srcConfig;
// These settings we will always want if a temp draw is performed. Initially set the config // These settings we will always want if a temp draw is performed. Initially set the config
// to srcConfig, though that may be modified if we decide to do a R/G swap. // to srcConfig, though that may be modified if we decide to do a R/G swap.
@ -687,19 +689,22 @@ bool GrGLGpu::onGetWritePixelsInfo(GrSurface* dstSurface, int width, int height,
if (!this->caps()->isConfigTexturable(srcConfig)) { if (!this->caps()->isConfigTexturable(srcConfig)) {
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference); ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
tempDrawInfo->fTempSurfaceDesc.fConfig = dstSurface->config(); tempDrawInfo->fTempSurfaceDesc.fConfig = dstSurface->config();
tempDrawInfo->fSwapRAndB = true; tempDrawInfo->fSwizzle = GrSwizzle::BGRA();
tempDrawInfo->fWriteConfig = dstSurface->config();
} else if (this->glCaps().rgba8888PixelsOpsAreSlow() && } else if (this->glCaps().rgba8888PixelsOpsAreSlow() &&
kRGBA_8888_GrPixelConfig == srcConfig) { kRGBA_8888_GrPixelConfig == srcConfig) {
ElevateDrawPreference(drawPreference, kGpuPrefersDraw_DrawPreference); ElevateDrawPreference(drawPreference, kGpuPrefersDraw_DrawPreference);
tempDrawInfo->fTempSurfaceDesc.fConfig = dstSurface->config(); tempDrawInfo->fTempSurfaceDesc.fConfig = dstSurface->config();
tempDrawInfo->fSwapRAndB = true; tempDrawInfo->fSwizzle = GrSwizzle::BGRA();
tempDrawInfo->fWriteConfig = dstSurface->config();
} else if (kGLES_GrGLStandard == this->glStandard() && } else if (kGLES_GrGLStandard == this->glStandard() &&
this->glCaps().bgraIsInternalFormat()) { this->glCaps().bgraIsInternalFormat()) {
// The internal format and external formats must match texture uploads so we can't // The internal format and external formats must match texture uploads so we can't
// swizzle while uploading when BGRA is a distinct internal format. // swizzle while uploading when BGRA is a distinct internal format.
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference); ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
tempDrawInfo->fTempSurfaceDesc.fConfig = dstSurface->config(); tempDrawInfo->fTempSurfaceDesc.fConfig = dstSurface->config();
tempDrawInfo->fSwapRAndB = true; tempDrawInfo->fSwizzle = GrSwizzle::BGRA();
tempDrawInfo->fWriteConfig = dstSurface->config();
} }
} }
@ -2077,7 +2082,8 @@ bool GrGLGpu::onGetReadPixelsInfo(GrSurface* srcSurface, int width, int height,
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference); ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
} }
tempDrawInfo->fSwapRAndB = false; tempDrawInfo->fSwizzle = GrSwizzle::RGBA();
tempDrawInfo->fReadConfig = readConfig;
// These settings we will always want if a temp draw is performed. The config is set below // These settings we will always want if a temp draw is performed. The config is set below
// depending on whether we want to do a R/B swap or not. // depending on whether we want to do a R/B swap or not.
@ -2095,20 +2101,23 @@ bool GrGLGpu::onGetReadPixelsInfo(GrSurface* srcSurface, int width, int height,
if (this->glCaps().rgba8888PixelsOpsAreSlow() && kRGBA_8888_GrPixelConfig == readConfig) { if (this->glCaps().rgba8888PixelsOpsAreSlow() && kRGBA_8888_GrPixelConfig == readConfig) {
tempDrawInfo->fTempSurfaceDesc.fConfig = kBGRA_8888_GrPixelConfig; tempDrawInfo->fTempSurfaceDesc.fConfig = kBGRA_8888_GrPixelConfig;
tempDrawInfo->fSwapRAndB = true; tempDrawInfo->fSwizzle = GrSwizzle::BGRA();
tempDrawInfo->fReadConfig = kBGRA_8888_GrPixelConfig;
ElevateDrawPreference(drawPreference, kGpuPrefersDraw_DrawPreference); ElevateDrawPreference(drawPreference, kGpuPrefersDraw_DrawPreference);
} else if (kMesa_GrGLDriver == this->glContext().driver() && } else if (kMesa_GrGLDriver == this->glContext().driver() &&
GrBytesPerPixel(readConfig) == 4 && GrBytesPerPixel(readConfig) == 4 &&
GrPixelConfigSwapRAndB(readConfig) == srcConfig) { GrPixelConfigSwapRAndB(readConfig) == srcConfig) {
// Mesa 3D takes a slow path on when reading back BGRA from an RGBA surface and vice-versa. // Mesa 3D takes a slow path on when reading back BGRA from an RGBA surface and vice-versa.
// Better to do a draw with a R/B swap and then read as the original config. // Better to do a draw with a R/B swap and then read as the original config.
tempDrawInfo->fTempSurfaceDesc.fConfig = srcConfig; tempDrawInfo->fTempSurfaceDesc.fConfig = srcConfig;
tempDrawInfo->fSwapRAndB = true; tempDrawInfo->fSwizzle = GrSwizzle::BGRA();
tempDrawInfo->fReadConfig = srcConfig;
ElevateDrawPreference(drawPreference, kGpuPrefersDraw_DrawPreference); ElevateDrawPreference(drawPreference, kGpuPrefersDraw_DrawPreference);
} else if (readConfig == kBGRA_8888_GrPixelConfig && } else if (readConfig == kBGRA_8888_GrPixelConfig &&
!this->glCaps().readPixelsSupported(this->glInterface(), readConfig, srcConfig)) { !this->glCaps().readPixelsSupported(this->glInterface(), readConfig, srcConfig)) {
tempDrawInfo->fTempSurfaceDesc.fConfig = kRGBA_8888_GrPixelConfig; tempDrawInfo->fTempSurfaceDesc.fConfig = kRGBA_8888_GrPixelConfig;
tempDrawInfo->fSwapRAndB = true; tempDrawInfo->fSwizzle = GrSwizzle::BGRA();
tempDrawInfo->fReadConfig = kRGBA_8888_GrPixelConfig;
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference); ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
} }
@ -2160,8 +2169,7 @@ bool GrGLGpu::onReadPixels(GrSurface* surface,
this->onResolveRenderTarget(tgt); this->onResolveRenderTarget(tgt);
// we don't track the state of the READ FBO ID. // we don't track the state of the READ FBO ID.
fStats.incRenderTargetBinds(); fStats.incRenderTargetBinds();
GL_CALL(BindFramebuffer(GR_GL_READ_FRAMEBUFFER, GL_CALL(BindFramebuffer(GR_GL_READ_FRAMEBUFFER, tgt->textureFBOID()));
tgt->textureFBOID()));
break; break;
default: default:
SkFAIL("Unknown resolve type"); SkFAIL("Unknown resolve type");