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 GrVertexBuffer;
class GrStrokeInfo;
class GrSwizzle;
class SkTraceMemoryDump;
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
* 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 GrFragmentProcessor* createUPMToPMEffect(GrTexture*, bool swapRAndB,
const GrFragmentProcessor* createUPMToPMEffect(GrTexture*, const GrSwizzle&,
const SkMatrix&) const;
/** 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

View File

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

View File

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

View File

@ -8,8 +8,8 @@
#ifndef GrSwizzle_DEFINED
#define GrSwizzle_DEFINED
#include "GrTypes.h"
#include "GrColor.h"
#include "SkRandom.h"
/** 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
@ -84,6 +84,22 @@ public:
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:
char fSwiz[5];
uint8_t fKey;

View File

@ -16,14 +16,13 @@
class GrGLConfigConversionEffect : public GrGLSLFragmentProcessor {
public:
GrGLConfigConversionEffect(const GrProcessor& processor) {
const GrConfigConversionEffect& configConversionEffect =
processor.cast<GrConfigConversionEffect>();
fSwapRedAndBlue = configConversionEffect.swapsRedAndBlue();
fPMConversion = configConversionEffect.pmConversion();
}
GrGLConfigConversionEffect() {}
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.
GrGLSLShaderVar tmpVar("tmpColor", kVec4f_GrSLType, 0, kHigh_GrSLPrecision);
SkString tmpDecl;
@ -38,16 +37,16 @@ public:
args.fCoords[0].getType());
fragBuilder->codeAppend(";");
if (GrConfigConversionEffect::kNone_PMConversion == fPMConversion) {
SkASSERT(fSwapRedAndBlue);
fragBuilder->codeAppendf("%s = %s.bgra;", args.fOutputColor, tmpVar.c_str());
if (GrConfigConversionEffect::kNone_PMConversion == pmConversion) {
SkASSERT(GrSwizzle::RGBA() != swizzle);
fragBuilder->codeAppendf("%s = %s.%s;", args.fOutputColor, tmpVar.c_str(),
swizzle.c_str());
} else {
const char* swiz = fSwapRedAndBlue ? "bgr" : "rgb";
switch (fPMConversion) {
switch (pmConversion) {
case GrConfigConversionEffect::kMulByAlpha_RoundUp_PMConversion:
fragBuilder->codeAppendf(
"%s = vec4(ceil(%s.%s * %s.a * 255.0) / 255.0, %s.a);",
tmpVar.c_str(), tmpVar.c_str(), swiz, tmpVar.c_str(), tmpVar.c_str());
"%s = vec4(ceil(%s.rgb * %s.a * 255.0) / 255.0, %s.a);",
tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str());
break;
case GrConfigConversionEffect::kMulByAlpha_RoundDown_PMConversion:
// 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
// converted from the integer value 2^n, such as 1, 2, 4, 8, etc.
fragBuilder->codeAppendf(
"%s = vec4(floor(%s.%s * %s.a * 255.0 + 0.001) / 255.0, %s.a);",
tmpVar.c_str(), tmpVar.c_str(), swiz, tmpVar.c_str(), tmpVar.c_str());
"%s = vec4(floor(%s.rgb * %s.a * 255.0 + 0.001) / 255.0, %s.a);",
tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str());
break;
case GrConfigConversionEffect::kDivByAlpha_RoundUp_PMConversion:
fragBuilder->codeAppendf(
"%s = %s.a <= 0.0 ? vec4(0,0,0,0) : vec4(ceil(%s.%s / %s.a * 255.0) / 255.0, %s.a);",
tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str(), swiz, tmpVar.c_str(), tmpVar.c_str());
"%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(), tmpVar.c_str(),
tmpVar.c_str());
break;
case GrConfigConversionEffect::kDivByAlpha_RoundDown_PMConversion:
fragBuilder->codeAppendf(
"%s = %s.a <= 0.0 ? vec4(0,0,0,0) : vec4(floor(%s.%s / %s.a * 255.0) / 255.0, %s.a);",
tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str(), swiz, tmpVar.c_str(), tmpVar.c_str());
"%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(), tmpVar.c_str(),
tmpVar.c_str());
break;
default:
SkFAIL("Unknown conversion op.");
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;
GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor);
@ -81,15 +84,12 @@ public:
static inline void GenKey(const GrProcessor& processor, const GrGLSLCaps&,
GrProcessorKeyBuilder* b) {
const GrConfigConversionEffect& conv = processor.cast<GrConfigConversionEffect>();
uint32_t key = (conv.swapsRedAndBlue() ? 0 : 1) | (conv.pmConversion() << 1);
const GrConfigConversionEffect& cce = processor.cast<GrConfigConversionEffect>();
uint32_t key = (cce.swizzle().asKey()) | (cce.pmConversion() << 16);
b->add32(key);
}
private:
bool fSwapRedAndBlue;
GrConfigConversionEffect::PMConversion fPMConversion;
typedef GrGLSLFragmentProcessor INHERITED;
};
@ -97,11 +97,11 @@ private:
///////////////////////////////////////////////////////////////////////////////
GrConfigConversionEffect::GrConfigConversionEffect(GrTexture* texture,
bool swapRedAndBlue,
const GrSwizzle& swizzle,
PMConversion pmConversion,
const SkMatrix& matrix)
: INHERITED(texture, matrix)
, fSwapRedAndBlue(swapRedAndBlue)
, fSwizzle(swizzle)
, fPMConversion(pmConversion) {
this->initClassID<GrConfigConversionEffect>();
// 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()) ||
kNone_PMConversion == pmConversion);
// 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 {
const GrConfigConversionEffect& other = s.cast<GrConfigConversionEffect>();
return other.fSwapRedAndBlue == fSwapRedAndBlue &&
return other.fSwizzle == fSwizzle &&
other.fPMConversion == fPMConversion;
}
@ -129,14 +129,12 @@ GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrConfigConversionEffect);
const GrFragmentProcessor* GrConfigConversionEffect::TestCreate(GrProcessorTestData* d) {
PMConversion pmConv = static_cast<PMConversion>(d->fRandom->nextULessThan(kPMConversionCnt));
bool swapRB;
if (kNone_PMConversion == pmConv) {
swapRB = true;
} else {
swapRB = d->fRandom->nextBool();
}
GrSwizzle swizzle;
do {
swizzle = GrSwizzle::CreateRandom(d->fRandom);
} while (pmConv == kNone_PMConversion && swizzle == GrSwizzle::RGBA());
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 {
return new GrGLConfigConversionEffect(*this);
return new GrGLConfigConversionEffect();
}
@ -215,11 +213,11 @@ void GrConfigConversionEffect::TestForPreservingPMConversions(GrContext* context
GrPaint paint2;
GrPaint paint3;
SkAutoTUnref<GrFragmentProcessor> pmToUPM1(new GrConfigConversionEffect(
dataTex, false, *pmToUPMRule, SkMatrix::I()));
dataTex, GrSwizzle::RGBA(), *pmToUPMRule, SkMatrix::I()));
SkAutoTUnref<GrFragmentProcessor> upmToPM(new GrConfigConversionEffect(
readTex, false, *upmToPMRule, SkMatrix::I()));
readTex, GrSwizzle::RGBA(), *upmToPMRule, SkMatrix::I()));
SkAutoTUnref<GrFragmentProcessor> pmToUPM2(new GrConfigConversionEffect(
tempTex, false, *pmToUPMRule, SkMatrix::I()));
tempTex, GrSwizzle::RGBA(), *pmToUPMRule, SkMatrix::I()));
paint1.addColorFragmentProcessor(pmToUPM1);
paint1.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
@ -289,10 +287,10 @@ void GrConfigConversionEffect::TestForPreservingPMConversions(GrContext* context
}
const GrFragmentProcessor* GrConfigConversionEffect::Create(GrTexture* texture,
bool swapRedAndBlue,
const GrSwizzle& swizzle,
PMConversion pmConversion,
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
// then we may pollute our texture cache with redundant shaders. So in the case that no
// 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
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
#include "GrSingleTextureEffect.h"
#include "GrSwizzle.h"
class GrInvariantOutput;
/**
* 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
* read/write using the faster path and perform an R/B swap in the shader if the client data is in
* the slower config.
* unpremultiplied. Additionally, the channels may also be swizzled for optimal readback/upload
* performance.
*/
class GrConfigConversionEffect : public GrSingleTextureEffect {
public:
@ -33,12 +33,12 @@ public:
kPMConversionCnt
};
static const GrFragmentProcessor* Create(GrTexture*, bool swapRedAndBlue, PMConversion,
static const GrFragmentProcessor* Create(GrTexture*, const GrSwizzle&, PMConversion,
const SkMatrix&);
const char* name() const override { return "Config Conversion"; }
bool swapsRedAndBlue() const { return fSwapRedAndBlue; }
const GrSwizzle& swizzle() const { return fSwizzle; }
PMConversion pmConversion() const { return fPMConversion; }
// This function determines whether it is possible to choose PM->UPM and UPM->PM conversions
@ -52,7 +52,7 @@ public:
private:
GrConfigConversionEffect(GrTexture*,
bool swapRedAndBlue,
const GrSwizzle&,
PMConversion pmConversion,
const SkMatrix& matrix);
@ -64,7 +64,7 @@ private:
void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
bool fSwapRedAndBlue;
GrSwizzle fSwizzle;
PMConversion fPMConversion;
GR_DECLARE_FRAGMENT_PROCESSOR_TEST;

View File

@ -670,7 +670,9 @@ bool GrGLGpu::onGetWritePixelsInfo(GrSurface* dstSurface, int width, int height,
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
// 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)) {
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
tempDrawInfo->fTempSurfaceDesc.fConfig = dstSurface->config();
tempDrawInfo->fSwapRAndB = true;
tempDrawInfo->fSwizzle = GrSwizzle::BGRA();
tempDrawInfo->fWriteConfig = dstSurface->config();
} else if (this->glCaps().rgba8888PixelsOpsAreSlow() &&
kRGBA_8888_GrPixelConfig == srcConfig) {
ElevateDrawPreference(drawPreference, kGpuPrefersDraw_DrawPreference);
tempDrawInfo->fTempSurfaceDesc.fConfig = dstSurface->config();
tempDrawInfo->fSwapRAndB = true;
tempDrawInfo->fSwizzle = GrSwizzle::BGRA();
tempDrawInfo->fWriteConfig = dstSurface->config();
} else if (kGLES_GrGLStandard == this->glStandard() &&
this->glCaps().bgraIsInternalFormat()) {
// The internal format and external formats must match texture uploads so we can't
// swizzle while uploading when BGRA is a distinct internal format.
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
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);
}
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
// 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) {
tempDrawInfo->fTempSurfaceDesc.fConfig = kBGRA_8888_GrPixelConfig;
tempDrawInfo->fSwapRAndB = true;
tempDrawInfo->fSwizzle = GrSwizzle::BGRA();
tempDrawInfo->fReadConfig = kBGRA_8888_GrPixelConfig;
ElevateDrawPreference(drawPreference, kGpuPrefersDraw_DrawPreference);
} else if (kMesa_GrGLDriver == this->glContext().driver() &&
GrBytesPerPixel(readConfig) == 4 &&
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.
tempDrawInfo->fTempSurfaceDesc.fConfig = srcConfig;
tempDrawInfo->fSwapRAndB = true;
tempDrawInfo->fSwizzle = GrSwizzle::BGRA();
tempDrawInfo->fReadConfig = srcConfig;
ElevateDrawPreference(drawPreference, kGpuPrefersDraw_DrawPreference);
} else if (readConfig == kBGRA_8888_GrPixelConfig &&
!this->glCaps().readPixelsSupported(this->glInterface(), readConfig, srcConfig)) {
tempDrawInfo->fTempSurfaceDesc.fConfig = kRGBA_8888_GrPixelConfig;
tempDrawInfo->fSwapRAndB = true;
tempDrawInfo->fSwizzle = GrSwizzle::BGRA();
tempDrawInfo->fReadConfig = kRGBA_8888_GrPixelConfig;
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
}
@ -2160,8 +2169,7 @@ bool GrGLGpu::onReadPixels(GrSurface* surface,
this->onResolveRenderTarget(tgt);
// we don't track the state of the READ FBO ID.
fStats.incRenderTargetBinds();
GL_CALL(BindFramebuffer(GR_GL_READ_FRAMEBUFFER,
tgt->textureFBOID()));
GL_CALL(BindFramebuffer(GR_GL_READ_FRAMEBUFFER, tgt->textureFBOID()));
break;
default:
SkFAIL("Unknown resolve type");