Index: src/gpu/GrContext.cpp |
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp |
index 1db2cbe627c0c82f388a048fe30333d858e010b7..9077bc0d054c86a19ed09036b643688700905a74 100755 |
--- a/src/gpu/GrContext.cpp |
+++ b/src/gpu/GrContext.cpp |
@@ -329,76 +329,111 @@ bool GrContext::writeSurfacePixels(GrSurface* surface, |
GrPixelConfig srcConfig, const void* buffer, size_t rowBytes, |
uint32_t pixelOpsFlags) { |
RETURN_FALSE_IF_ABANDONED |
- { |
- GrTexture* texture = NULL; |
- if (!(kUnpremul_PixelOpsFlag & pixelOpsFlags) && (texture = surface->asTexture()) && |
- fGpu->canWriteTexturePixels(texture, srcConfig) && |
- (!fCaps->useDrawInsteadOfPartialRenderTargetWrite() || !surface->asRenderTarget() || |
- (width == texture->width() && height == texture->height()))) { |
- |
- if (!(kDontFlush_PixelOpsFlag & pixelOpsFlags) && |
- surface->surfacePriv().hasPendingIO()) { |
- this->flush(); |
- } |
- return fGpu->writeTexturePixels(texture, left, top, width, height, |
- srcConfig, buffer, rowBytes); |
- // Don't need to check kFlushWrites_PixelOp here, we just did a direct write so the |
- // upload is already flushed. |
- } |
- } |
// Trim the params here so that if we wind up making a temporary surface it can be as small as |
- // necessary. |
+ // necessary and because GrGpu::getWritePixelsInfo requires it. |
if (!GrSurfacePriv::AdjustWritePixelParams(surface->width(), surface->height(), |
GrBytesPerPixel(srcConfig), &left, &top, &width, |
&height, &buffer, &rowBytes)) { |
return false; |
} |
- // If we didn't do a direct texture write then we upload the pixels to a texture and draw. |
- GrRenderTarget* renderTarget = surface->asRenderTarget(); |
- if (!renderTarget) { |
+ bool applyPremulToSrc = false; |
+ if (kUnpremul_PixelOpsFlag & pixelOpsFlags) { |
+ if (!GrPixelConfigIs8888(srcConfig)) { |
+ return false; |
+ } |
+ applyPremulToSrc = true; |
+ } |
+ GrGpu::DrawPreference drawPreference = applyPremulToSrc ? |
+ GrGpu::kCallerPrefersDraw_DrawPreference : |
+ GrGpu::kNoDraw_DrawPreference; |
+ GrGpu::WritePixelTempDrawInfo tempDrawInfo; |
+ if (!fGpu->getWritePixelsInfo(surface, width, height, rowBytes, srcConfig, &drawPreference, |
+ &tempDrawInfo)) { |
return false; |
} |
- // We ignore the preferred config unless it is a R/B swap of the src config. In that case |
- // we will upload the original src data to a scratch texture but we will spoof it as the swapped |
- // config. This scratch will then have R and B swapped. We correct for this by swapping again |
- // when drawing the scratch to the dst using a conversion effect. |
- bool swapRAndB = false; |
- GrPixelConfig writeConfig = srcConfig; |
- if (GrPixelConfigSwapRAndB(srcConfig) == |
- fGpu->preferredWritePixelsConfig(srcConfig, renderTarget->config())) { |
- writeConfig = GrPixelConfigSwapRAndB(srcConfig); |
- swapRAndB = true; |
- } |
- |
- GrSurfaceDesc desc; |
- desc.fWidth = width; |
- desc.fHeight = height; |
- desc.fConfig = writeConfig; |
- SkAutoTUnref<GrTexture> texture(this->textureProvider()->refScratchTexture(desc, |
- GrTextureProvider::kApprox_ScratchTexMatch)); |
- if (!texture) { |
- return false; |
+ if (!(kDontFlush_PixelOpsFlag & pixelOpsFlags) && surface->surfacePriv().hasPendingIO()) { |
+ this->flush(); |
} |
- SkAutoTUnref<const GrFragmentProcessor> fp; |
- SkMatrix textureMatrix; |
- textureMatrix.setIDiv(texture->width(), texture->height()); |
+ SkAutoTUnref<GrTexture> tempTexture; |
+ if (GrGpu::kNoDraw_DrawPreference != drawPreference) { |
+ tempTexture.reset(this->textureProvider()->refScratchTexture( |
+ tempDrawInfo.fTempSurfaceDesc, GrTextureProvider::kApprox_ScratchTexMatch)); |
+ if (!tempTexture && GrGpu::kRequireDraw_DrawPreference == drawPreference) { |
+ return false; |
+ } |
+ } |
- // allocate a tmp buffer and sw convert the pixels to premul |
+ // temp buffer for doing sw premul conversion, if needed. |
SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0); |
+ if (tempTexture) { |
+ SkAutoTUnref<const GrFragmentProcessor> fp; |
+ SkMatrix textureMatrix; |
+ textureMatrix.setIDiv(tempTexture->width(), tempTexture->height()); |
+ GrPaint paint; |
+ if (applyPremulToSrc) { |
+ fp.reset(this->createUPMToPMEffect(paint.getProcessorDataManager(), tempTexture, |
+ tempDrawInfo.fSwapRAndB, textureMatrix)); |
+ // If premultiplying was the only reason for the draw, fall back to a straight write. |
+ if (!fp) { |
+ if (GrGpu::kCallerPrefersDraw_DrawPreference == drawPreference) { |
+ tempTexture.reset(NULL); |
+ } |
+ } else { |
+ applyPremulToSrc = false; |
+ } |
+ } |
+ if (tempTexture) { |
+ if (!fp) { |
+ fp.reset(GrConfigConversionEffect::Create( |
+ paint.getProcessorDataManager(), tempTexture, tempDrawInfo.fSwapRAndB, |
+ GrConfigConversionEffect::kNone_PMConversion, textureMatrix)); |
+ if (!fp) { |
+ return false; |
+ } |
+ } |
+ GrRenderTarget* renderTarget = surface->asRenderTarget(); |
+ SkASSERT(renderTarget); |
+ if (tempTexture->surfacePriv().hasPendingIO()) { |
+ this->flush(); |
+ } |
+ if (applyPremulToSrc) { |
+ size_t tmpRowBytes = 4 * width; |
+ tmpPixels.reset(width * height); |
+ if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer, tmpRowBytes, |
+ tmpPixels.get())) { |
+ return false; |
+ } |
+ rowBytes = tmpRowBytes; |
+ buffer = tmpPixels.get(); |
+ applyPremulToSrc = false; |
+ } |
+ if (!fGpu->writeTexturePixels(tempTexture, 0, 0, width, height, |
+ tempDrawInfo.fTempSurfaceDesc.fConfig, buffer, |
+ rowBytes)) { |
+ return false; |
+ } |
+ SkMatrix matrix; |
+ matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top)); |
+ GrDrawContext* drawContext = this->drawContext(); |
+ if (!drawContext) { |
+ return false; |
+ } |
+ paint.addColorProcessor(fp); |
+ SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)); |
+ drawContext->drawRect(renderTarget, GrClip::WideOpen(), paint, matrix, rect, NULL); |
- GrPaint paint; |
- if (kUnpremul_PixelOpsFlag & pixelOpsFlags) { |
- if (!GrPixelConfigIs8888(srcConfig)) { |
- return false; |
+ if (kFlushWrites_PixelOp & pixelOpsFlags) { |
+ this->flushSurfaceWrites(surface); |
+ } |
} |
- fp.reset(this->createUPMToPMEffect(paint.getProcessorDataManager(), texture, swapRAndB, |
- textureMatrix)); |
- // handle the unpremul step on the CPU if we couldn't create an effect to do it. |
- if (!fp) { |
+ } |
+ if (!tempTexture) { |
+ SkASSERT(surface->asTexture()); |
+ if (applyPremulToSrc) { |
size_t tmpRowBytes = 4 * width; |
tmpPixels.reset(width * height); |
if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer, tmpRowBytes, |
@@ -407,46 +442,11 @@ bool GrContext::writeSurfacePixels(GrSurface* surface, |
} |
rowBytes = tmpRowBytes; |
buffer = tmpPixels.get(); |
+ applyPremulToSrc = false; |
} |
+ return fGpu->writeTexturePixels(surface->asTexture(), left, top, width, height, srcConfig, |
+ buffer, rowBytes); |
} |
- |
- if (!fp) { |
- fp.reset(GrConfigConversionEffect::Create(paint.getProcessorDataManager(), |
- texture, |
- swapRAndB, |
- GrConfigConversionEffect::kNone_PMConversion, |
- textureMatrix)); |
- } |
- |
- // Even if the client told us not to flush, we still flush here. The client may have known that |
- // writes to the original surface caused no data hazards, but they can't know that the scratch |
- // we just got is safe. |
- if (texture->surfacePriv().hasPendingIO()) { |
- this->flush(); |
- } |
- if (!fGpu->writeTexturePixels(texture, 0, 0, width, height, |
- writeConfig, buffer, rowBytes)) { |
- return false; |
- } |
- |
- SkMatrix matrix; |
- matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top)); |
- |
- GrDrawContext* drawContext = this->drawContext(); |
- if (!drawContext) { |
- return false; |
- } |
- |
- paint.addColorProcessor(fp); |
- |
- SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)); |
- |
- drawContext->drawRect(renderTarget, GrClip::WideOpen(), paint, matrix, rect, NULL); |
- |
- if (kFlushWrites_PixelOp & pixelOpsFlags) { |
- this->flushSurfaceWrites(surface); |
- } |
- |
return true; |
} |