Index: src/gpu/GrContext.cpp |
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp |
index adbde946c55adbc4303af55e95fd12d9058adc47..ba02d60b11ece81231086a890d33214dc03e3601 100755 |
--- a/src/gpu/GrContext.cpp |
+++ b/src/gpu/GrContext.cpp |
@@ -329,96 +329,76 @@ |
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 and because GrGpu::getWritePixelsInfo requires it. |
+ // necessary. |
if (!GrSurfacePriv::AdjustWritePixelParams(surface->width(), surface->height(), |
GrBytesPerPixel(srcConfig), &left, &top, &width, |
&height, &buffer, &rowBytes)) { |
return false; |
} |
- bool applyPremulToSrc = 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) { |
+ 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; |
+ } |
+ |
+ SkAutoTUnref<const GrFragmentProcessor> fp; |
+ SkMatrix textureMatrix; |
+ textureMatrix.setIDiv(texture->width(), texture->height()); |
+ |
+ // allocate a tmp buffer and sw convert the pixels to premul |
+ SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0); |
+ |
+ GrPaint paint; |
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; |
- } |
- |
- if (!(kDontFlush_PixelOpsFlag & pixelOpsFlags) && surface->surfacePriv().hasPendingIO()) { |
- this->flush(); |
- } |
- |
- 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; |
- } |
- } |
- |
- 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 && GrGpu::kCallerPrefersDraw_DrawPreference == drawPreference) { |
- tempTexture.reset(NULL); |
- } |
- } |
- 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 (!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); |
- |
- if (kFlushWrites_PixelOp & pixelOpsFlags) { |
- this->flushSurfaceWrites(surface); |
- } |
- } |
- } |
- if (!tempTexture) { |
- SkASSERT(surface->asTexture()); |
- // allocate a tmp buffer and sw convert the pixels to premul |
- SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0); |
- if (applyPremulToSrc) { |
+ 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) { |
size_t tmpRowBytes = 4 * width; |
tmpPixels.reset(width * height); |
if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer, tmpRowBytes, |
@@ -428,9 +408,45 @@ |
rowBytes = tmpRowBytes; |
buffer = tmpPixels.get(); |
} |
- 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; |
} |