| Index: src/gpu/GrContext.cpp
|
| diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
|
| index 17b4b74a3956d284a5a4592a3f82f1558befd4b6..ba02d60b11ece81231086a890d33214dc03e3601 100755
|
| --- a/src/gpu/GrContext.cpp
|
| +++ b/src/gpu/GrContext.cpp
|
| @@ -450,16 +450,6 @@ bool GrContext::writeSurfacePixels(GrSurface* surface,
|
| return true;
|
| }
|
|
|
| -// toggles between RGBA and BGRA
|
| -static SkColorType toggle_colortype32(SkColorType ct) {
|
| - if (kRGBA_8888_SkColorType == ct) {
|
| - return kBGRA_8888_SkColorType;
|
| - } else {
|
| - SkASSERT(kBGRA_8888_SkColorType == ct);
|
| - return kRGBA_8888_SkColorType;
|
| - }
|
| -}
|
| -
|
| bool GrContext::readSurfacePixels(GrSurface* src,
|
| int left, int top, int width, int height,
|
| GrPixelConfig dstConfig, void* buffer, size_t rowBytes,
|
| @@ -480,126 +470,87 @@ bool GrContext::readSurfacePixels(GrSurface* src,
|
| this->flush();
|
| }
|
|
|
| - // Determine which conversions have to be applied: flipY, swapRAnd, and/or unpremul.
|
| -
|
| - // We ignore the preferred config if it is different than our config unless it is an R/B swap.
|
| - // In that case we'll perform an R and B swap while drawing to a scratch texture of the swapped
|
| - // config. Then we will call readPixels on the scratch with the swapped config. The swaps during
|
| - // the draw cancels out the fact that we call readPixels with a config that is R/B swapped from
|
| - // dstConfig.
|
| - GrPixelConfig readConfig = dstConfig;
|
| - bool swapRAndB = false;
|
| - if (GrPixelConfigSwapRAndB(dstConfig) ==
|
| - fGpu->preferredReadPixelsConfig(dstConfig, src->config())) {
|
| - readConfig = GrPixelConfigSwapRAndB(readConfig);
|
| - swapRAndB = true;
|
| - }
|
| -
|
| - bool flipY = false;
|
| - GrRenderTarget* srcAsRT = src->asRenderTarget();
|
| - if (srcAsRT) {
|
| - // If fGpu->readPixels would incur a y-flip cost then we will read the pixels upside down.
|
| - // We'll either do the flipY by drawing into a scratch with a matrix or on the cpu after the
|
| - // read.
|
| - flipY = fGpu->readPixelsWillPayForYFlip(srcAsRT, left, top,
|
| - width, height, dstConfig,
|
| - rowBytes);
|
| - }
|
| -
|
| bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags);
|
| if (unpremul && !GrPixelConfigIs8888(dstConfig)) {
|
| - // The unpremul flag is only allowed for these two configs.
|
| + // The unpremul flag is only allowed for 8888 configs.
|
| return false;
|
| }
|
|
|
| - SkAutoTUnref<GrTexture> tempTexture;
|
| -
|
| - // If the src is a texture and we would have to do conversions after read pixels, we instead
|
| - // do the conversions by drawing the src to a scratch texture. If we handle any of the
|
| - // conversions in the draw we set the corresponding bool to false so that we don't reapply it
|
| - // on the read back pixels. We also do an intermediate draw if the src is not a render target as
|
| - // GrGpu currently supports reading from render targets but not textures.
|
| - GrTexture* srcAsTex = src->asTexture();
|
| - GrRenderTarget* rtToRead = srcAsRT;
|
| - if (srcAsTex && (swapRAndB || unpremul || flipY || !srcAsRT)) {
|
| - // Make the scratch a render so we can read its pixels.
|
| - GrSurfaceDesc desc;
|
| - desc.fFlags = kRenderTarget_GrSurfaceFlag;
|
| - desc.fWidth = width;
|
| - desc.fHeight = height;
|
| - desc.fConfig = readConfig;
|
| - desc.fOrigin = kTopLeft_GrSurfaceOrigin;
|
| -
|
| - // When a full read back is faster than a partial we could always make the scratch exactly
|
| - // match the passed rect. However, if we see many different size rectangles we will trash
|
| - // our texture cache and pay the cost of creating and destroying many textures. So, we only
|
| - // request an exact match when the caller is reading an entire RT.
|
| + GrGpu::DrawPreference drawPreference = unpremul ? GrGpu::kCallerPrefersDraw_DrawPreference :
|
| + GrGpu::kNoDraw_DrawPreference;
|
| + GrGpu::ReadPixelTempDrawInfo tempDrawInfo;
|
| + if (!fGpu->getReadPixelsInfo(src, width, height, rowBytes, dstConfig, &drawPreference,
|
| + &tempDrawInfo)) {
|
| + return false;
|
| + }
|
| +
|
| + GrRenderTarget* rtToRead = src->asRenderTarget();
|
| + bool didTempDraw = false;
|
| + if (GrGpu::kNoDraw_DrawPreference != drawPreference) {
|
| GrTextureProvider::ScratchTexMatch match = GrTextureProvider::kApprox_ScratchTexMatch;
|
| - if (0 == left &&
|
| - 0 == top &&
|
| - src->width() == width &&
|
| - src->height() == height &&
|
| - fGpu->fullReadPixelsIsFasterThanPartial()) {
|
| - match = GrTextureProvider::kExact_ScratchTexMatch;
|
| + if (tempDrawInfo.fUseExactScratch) {
|
| + // We only respect this when the entire src is being read. Otherwise we can trigger too
|
| + // many odd ball texture sizes and trash the cache.
|
| + if (width == src->width() && height == src->height()) {
|
| + match = GrTextureProvider::kExact_ScratchTexMatch;
|
| + }
|
| }
|
| - tempTexture.reset(this->textureProvider()->refScratchTexture(desc, match));
|
| - if (tempTexture) {
|
| - // compute a matrix to perform the draw
|
| + SkAutoTUnref<GrTexture> temp;
|
| + temp.reset(this->textureProvider()->refScratchTexture(tempDrawInfo.fTempSurfaceDesc, match));
|
| + if (temp) {
|
| SkMatrix textureMatrix;
|
| - textureMatrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
|
| + textureMatrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top));
|
| textureMatrix.postIDiv(src->width(), src->height());
|
| -
|
| GrPaint paint;
|
| SkAutoTUnref<const GrFragmentProcessor> fp;
|
| if (unpremul) {
|
| - fp.reset(this->createPMToUPMEffect(paint.getProcessorDataManager(), srcAsTex,
|
| - swapRAndB, textureMatrix));
|
| + fp.reset(this->createPMToUPMEffect(
|
| + paint.getProcessorDataManager(), src->asTexture(), tempDrawInfo.fSwapRAndB,
|
| + textureMatrix));
|
| if (fp) {
|
| unpremul = false; // we no longer need to do this on CPU after the read back.
|
| + } else if (GrGpu::kCallerPrefersDraw_DrawPreference == drawPreference) {
|
| + // We only wanted to do the draw in order to perform the unpremul so don't
|
| + // bother.
|
| + temp.reset(NULL);
|
| }
|
| }
|
| - // If we failed to create a PM->UPM effect and have no other conversions to perform then
|
| - // there is no longer any point to using the scratch.
|
| - if (fp || flipY || swapRAndB || !srcAsRT) {
|
| - if (!fp) {
|
| - fp.reset(GrConfigConversionEffect::Create(paint.getProcessorDataManager(),
|
| - srcAsTex, swapRAndB, GrConfigConversionEffect::kNone_PMConversion,
|
| - textureMatrix));
|
| - }
|
| - swapRAndB = false; // we will handle the swap in the draw.
|
| -
|
| - // We protect the existing geometry here since it may not be
|
| - // clear to the caller that a draw operation (i.e., drawSimpleRect)
|
| - // can be invoked in this method
|
| - {
|
| - GrDrawContext* drawContext = this->drawContext();
|
| - if (!drawContext) {
|
| - return false;
|
| - }
|
| -
|
| - paint.addColorProcessor(fp);
|
| -
|
| - SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
|
| -
|
| - drawContext->drawRect(tempTexture->asRenderTarget(), GrClip::WideOpen(), paint,
|
| - SkMatrix::I(), rect, NULL);
|
| -
|
| - // we want to read back from the scratch's origin
|
| - left = 0;
|
| - top = 0;
|
| - rtToRead = tempTexture->asRenderTarget();
|
| - }
|
| - this->flushSurfaceWrites(tempTexture);
|
| + if (!fp && temp) {
|
| + fp.reset(GrConfigConversionEffect::Create(
|
| + paint.getProcessorDataManager(), src->asTexture(), tempDrawInfo.fSwapRAndB,
|
| + GrConfigConversionEffect::kNone_PMConversion, textureMatrix));
|
| + }
|
| + if (fp) {
|
| + paint.addColorProcessor(fp);
|
| + SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
|
| + GrDrawContext* drawContext = this->drawContext();
|
| + drawContext->drawRect(temp->asRenderTarget(), GrClip::WideOpen(), paint,
|
| + SkMatrix::I(), rect, NULL);
|
| + rtToRead = temp->asRenderTarget();
|
| + left = 0;
|
| + top = 0;
|
| + didTempDraw = true;
|
| }
|
| }
|
| }
|
|
|
| - if (!rtToRead ||
|
| - !fGpu->readPixels(rtToRead, left, top, width, height, readConfig, buffer, rowBytes)) {
|
| + if (GrGpu::kRequireDraw_DrawPreference == drawPreference && !didTempDraw) {
|
| return false;
|
| }
|
| - // Perform any conversions we weren't able to perform using a scratch texture.
|
| - if (unpremul || swapRAndB) {
|
| + GrPixelConfig configToRead = dstConfig;
|
| + if (didTempDraw) {
|
| + this->flushSurfaceWrites(rtToRead);
|
| + // We swapped R and B while doing the temp draw. Swap back on the read.
|
| + if (tempDrawInfo.fSwapRAndB) {
|
| + configToRead = GrPixelConfigSwapRAndB(dstConfig);
|
| + }
|
| + }
|
| + if (!fGpu->readPixels(rtToRead, left, top, width, height, configToRead, buffer, rowBytes)) {
|
| + return false;
|
| + }
|
| +
|
| + // Perform umpremul conversion if we weren't able to perform it as a draw.
|
| + if (unpremul) {
|
| SkDstPixelInfo dstPI;
|
| if (!GrPixelConfig2ColorAndProfileType(dstConfig, &dstPI.fColorType, NULL)) {
|
| return false;
|
| @@ -609,7 +560,7 @@ bool GrContext::readSurfacePixels(GrSurface* src,
|
| dstPI.fRowBytes = rowBytes;
|
|
|
| SkSrcPixelInfo srcPI;
|
| - srcPI.fColorType = swapRAndB ? toggle_colortype32(dstPI.fColorType) : dstPI.fColorType;
|
| + srcPI.fColorType = dstPI.fColorType;
|
| srcPI.fAlphaType = kPremul_SkAlphaType;
|
| srcPI.fPixels = buffer;
|
| srcPI.fRowBytes = rowBytes;
|
|
|