Index: src/gpu/GrContext.cpp |
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp |
index 6ece67fd10a19beb1e00fa8debfa1ad4d63878a8..d5b211678b3087920f8ca25d13d6f43be2019970 100755 |
--- a/src/gpu/GrContext.cpp |
+++ b/src/gpu/GrContext.cpp |
@@ -35,6 +35,7 @@ |
#include "GrTraceMarker.h" |
#include "GrTracing.h" |
#include "SkDashPathPriv.h" |
+#include "SkConfig8888.h" |
#include "SkGr.h" |
#include "SkRTConf.h" |
#include "SkRRect.h" |
@@ -1244,72 +1245,140 @@ void GrContext::flush(int flagsBitfield) { |
fFlushToReduceCacheSize = false; |
} |
-bool GrContext::writeTexturePixels(GrTexture* texture, |
+bool sw_convert_to_premul(GrPixelConfig srcConfig, int width, int height, size_t inRowBytes, |
+ const void* inPixels, size_t outRowBytes, void* outPixels) { |
+ SkSrcPixelInfo srcPI; |
+ if (!GrPixelConfig2ColorType(srcConfig, &srcPI.fColorType)) { |
+ return false; |
+ } |
+ srcPI.fAlphaType = kUnpremul_SkAlphaType; |
+ srcPI.fPixels = inPixels; |
+ srcPI.fRowBytes = inRowBytes; |
+ |
+ SkDstPixelInfo dstPI; |
+ dstPI.fColorType = srcPI.fColorType; |
+ dstPI.fAlphaType = kPremul_SkAlphaType; |
+ dstPI.fPixels = outPixels; |
+ dstPI.fRowBytes = outRowBytes; |
+ |
+ return srcPI.convertPixelsTo(&dstPI, width, height); |
+} |
+ |
+bool GrContext::writeSurfacePixels(GrSurface* surface, |
int left, int top, int width, int height, |
- GrPixelConfig config, const void* buffer, size_t rowBytes, |
- uint32_t flags) { |
- ASSERT_OWNED_RESOURCE(texture); |
- |
- if ((kUnpremul_PixelOpsFlag & flags) || !fGpu->canWriteTexturePixels(texture, config)) { |
- if (texture->asRenderTarget()) { |
- return this->writeRenderTargetPixels(texture->asRenderTarget(), |
- left, top, width, height, |
- config, buffer, rowBytes, flags); |
- } else { |
- return false; |
+ GrPixelConfig srcConfig, const void* buffer, size_t rowBytes, |
+ uint32_t pixelOpsFlags) { |
+ |
+ { |
+ GrTexture* texture = NULL; |
+ if (!(kUnpremul_PixelOpsFlag & pixelOpsFlags) && (texture = surface->asTexture()) && |
+ fGpu->canWriteTexturePixels(texture, srcConfig)) { |
+ |
+ 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. |
} |
} |
- if (!(kDontFlush_PixelOpsFlag & flags) && texture->surfacePriv().hasPendingIO()) { |
- this->flush(); |
+ // If we didn't do a direct texture write then we upload the pixels to a texture and draw. |
+ GrRenderTarget* renderTarget = surface->asRenderTarget(); |
+ if (NULL == renderTarget) { |
+ return false; |
} |
- return fGpu->writeTexturePixels(texture, left, top, width, height, |
- config, buffer, rowBytes); |
+ // 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; |
+ } |
- // No need to check the kFlushWrites flag here since we issued the write directly to fGpu. |
-} |
+ GrTextureDesc desc; |
+ desc.fWidth = width; |
+ desc.fHeight = height; |
+ desc.fConfig = writeConfig; |
+ GrAutoScratchTexture ast(this, desc); |
+ GrTexture* texture = ast.texture(); |
+ if (NULL == texture) { |
+ return false; |
+ } |
-bool GrContext::readTexturePixels(GrTexture* texture, |
- int left, int top, int width, int height, |
- GrPixelConfig config, void* buffer, size_t rowBytes, |
- uint32_t flags) { |
- ASSERT_OWNED_RESOURCE(texture); |
+ SkAutoTUnref<const GrFragmentProcessor> fp; |
+ SkMatrix textureMatrix; |
+ textureMatrix.setIDiv(texture->width(), texture->height()); |
- GrRenderTarget* target = texture->asRenderTarget(); |
- if (target) { |
- return this->readRenderTargetPixels(target, |
- left, top, width, height, |
- config, buffer, rowBytes, |
- flags); |
- } else { |
- // TODO: make this more efficient for cases where we're reading the entire |
- // texture, i.e., use GetTexImage() instead |
+ // allocate a tmp buffer and sw convert the pixels to premul |
+ SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0); |
- // create scratch rendertarget and read from that |
- GrAutoScratchTexture ast; |
- GrTextureDesc desc; |
- desc.fFlags = kRenderTarget_GrTextureFlagBit; |
- desc.fWidth = width; |
- desc.fHeight = height; |
- desc.fConfig = config; |
- desc.fOrigin = kTopLeft_GrSurfaceOrigin; |
- ast.set(this, desc, kExact_ScratchTexMatch); |
- GrTexture* dst = ast.texture(); |
- if (dst && (target = dst->asRenderTarget())) { |
- this->copySurface(target, texture, SkIRect::MakeXYWH(top, left, width, height), |
- SkIPoint::Make(0,0)); |
- return this->readRenderTargetPixels(target, |
- left, top, width, height, |
- config, buffer, rowBytes, |
- flags); |
+ if (kUnpremul_PixelOpsFlag & pixelOpsFlags) { |
+ if (!GrPixelConfigIs8888(srcConfig)) { |
+ return false; |
+ } |
+ fp.reset(this->createUPMToPMEffect(texture, swapRAndB, textureMatrix)); |
+ // handle the unpremul step on the CPU if we couldn't create an effect to do it. |
+ if (NULL == fp) { |
+ 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(); |
} |
+ } |
+ if (NULL == fp) { |
+ fp.reset(GrConfigConversionEffect::Create(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; |
} |
-} |
-#include "SkConfig8888.h" |
+ SkMatrix matrix; |
+ matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top)); |
+ |
+ // This function can be called in the midst of drawing another object (e.g., when uploading a |
+ // SW-rasterized clip while issuing a draw). So we push the current geometry state before |
+ // drawing a rect to the render target. |
+ // The bracket ensures we pop the stack if we wind up flushing below. |
+ { |
+ GrDrawTarget* drawTarget = this->prepareToDraw(NULL, kYes_BufferedDraw, NULL, NULL); |
+ GrDrawTarget::AutoGeometryAndStatePush agasp(drawTarget, GrDrawTarget::kReset_ASRInit, |
+ &matrix); |
+ GrDrawState* drawState = drawTarget->drawState(); |
+ drawState->addColorProcessor(fp); |
+ drawState->setRenderTarget(renderTarget); |
+ drawState->disableState(GrDrawState::kClip_StateBit); |
+ drawTarget->drawSimpleRect(SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height))); |
+ } |
+ |
+ if (kFlushWrites_PixelOp & pixelOpsFlags) { |
+ this->flushSurfaceWrites(surface); |
+ } |
+ |
+ return true; |
+} |
// toggles between RGBA and BGRA |
static SkColorType toggle_colortype32(SkColorType ct) { |
@@ -1372,8 +1441,7 @@ bool GrContext::readRenderTargetPixels(GrRenderTarget* target, |
GrTexture* src = target->asTexture(); |
GrAutoScratchTexture ast; |
if (src && (swapRAndB || unpremul || flipY)) { |
- // Make the scratch a render target because we don't have a robust readTexturePixels as of |
- // yet. It calls this function. |
+ // Make the scratch a render so we can read its pixels. |
GrTextureDesc desc; |
desc.fFlags = kRenderTarget_GrTextureFlagBit; |
desc.fWidth = width; |
@@ -1508,144 +1576,6 @@ void GrContext::copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRe |
} |
} |
-bool GrContext::writeRenderTargetPixels(GrRenderTarget* renderTarget, |
- int left, int top, int width, int height, |
- GrPixelConfig srcConfig, |
- const void* buffer, |
- size_t rowBytes, |
- uint32_t pixelOpsFlags) { |
- ASSERT_OWNED_RESOURCE(renderTarget); |
- |
- if (NULL == renderTarget) { |
- renderTarget = fRenderTarget.get(); |
- if (NULL == renderTarget) { |
- return false; |
- } |
- } |
- |
- // TODO: when underlying api has a direct way to do this we should use it (e.g. glDrawPixels on |
- // desktop GL). |
- |
- // We will always call some form of writeTexturePixels and we will pass our flags on to it. |
- // Thus, we don't perform a flush here since that call will do it (if the kNoFlush flag isn't |
- // set.) |
- |
- // If the RT is also a texture and we don't have to premultiply then take the texture path. |
- // We expect to be at least as fast or faster since it doesn't use an intermediate texture as |
- // we do below. |
- |
-#if !defined(SK_BUILD_FOR_MAC) |
- // At least some drivers on the Mac get confused when glTexImage2D is called on a texture |
- // attached to an FBO. The FBO still sees the old image. TODO: determine what OS versions and/or |
- // HW is affected. |
- if (renderTarget->asTexture() && !(kUnpremul_PixelOpsFlag & pixelOpsFlags) && |
- fGpu->canWriteTexturePixels(renderTarget->asTexture(), srcConfig)) { |
- return this->writeTexturePixels(renderTarget->asTexture(), |
- left, top, width, height, |
- srcConfig, buffer, rowBytes, pixelOpsFlags); |
- } |
-#endif |
- |
- // 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; |
- } |
- |
- GrTextureDesc desc; |
- desc.fWidth = width; |
- desc.fHeight = height; |
- desc.fConfig = writeConfig; |
- GrAutoScratchTexture ast(this, desc); |
- GrTexture* texture = ast.texture(); |
- if (NULL == 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); |
- |
- if (kUnpremul_PixelOpsFlag & pixelOpsFlags) { |
- if (!GrPixelConfigIs8888(srcConfig)) { |
- return false; |
- } |
- fp.reset(this->createUPMToPMEffect(texture, swapRAndB, textureMatrix)); |
- // handle the unpremul step on the CPU if we couldn't create an effect to do it. |
- if (NULL == fp) { |
- SkSrcPixelInfo srcPI; |
- if (!GrPixelConfig2ColorType(srcConfig, &srcPI.fColorType)) { |
- return false; |
- } |
- srcPI.fAlphaType = kUnpremul_SkAlphaType; |
- srcPI.fPixels = buffer; |
- srcPI.fRowBytes = rowBytes; |
- |
- tmpPixels.reset(width * height); |
- |
- SkDstPixelInfo dstPI; |
- dstPI.fColorType = srcPI.fColorType; |
- dstPI.fAlphaType = kPremul_SkAlphaType; |
- dstPI.fPixels = tmpPixels.get(); |
- dstPI.fRowBytes = 4 * width; |
- |
- if (!srcPI.convertPixelsTo(&dstPI, width, height)) { |
- return false; |
- } |
- |
- buffer = tmpPixels.get(); |
- rowBytes = 4 * width; |
- } |
- } |
- if (NULL == fp) { |
- fp.reset(GrConfigConversionEffect::Create(texture, |
- swapRAndB, |
- GrConfigConversionEffect::kNone_PMConversion, |
- textureMatrix)); |
- } |
- |
- if (!this->writeTexturePixels(texture, |
- 0, 0, width, height, |
- writeConfig, buffer, rowBytes, |
- pixelOpsFlags & ~kUnpremul_PixelOpsFlag)) { |
- return false; |
- } |
- |
- SkMatrix matrix; |
- matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top)); |
- |
- |
- // This function can be called in the midst of drawing another object (e.g., when uploading a |
- // SW-rasterized clip while issuing a draw). So we push the current geometry state before |
- // drawing a rect to the render target. |
- // The bracket ensures we pop the stack if we wind up flushing below. |
- { |
- GrDrawTarget* drawTarget = this->prepareToDraw(NULL, kYes_BufferedDraw, NULL, NULL); |
- GrDrawTarget::AutoGeometryAndStatePush agasp(drawTarget, GrDrawTarget::kReset_ASRInit, |
- &matrix); |
- GrDrawState* drawState = drawTarget->drawState(); |
- drawState->addColorProcessor(fp); |
- drawState->setRenderTarget(renderTarget); |
- drawState->disableState(GrDrawState::kClip_StateBit); |
- drawTarget->drawSimpleRect(SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height))); |
- } |
- |
- if (kFlushWrites_PixelOp & pixelOpsFlags) { |
- this->flush(); |
- } |
- |
- return true; |
-} |
- |
void GrContext::flushSurfaceWrites(GrSurface* surface) { |
if (surface->surfacePriv().hasPendingWrite()) { |
this->flush(); |