diff options
author | bsalomon <bsalomon@google.com> | 2015-07-16 08:23:13 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-07-16 08:23:13 -0700 |
commit | e8d21e8f24aa676765d0ff8f433228665c75cdc2 (patch) | |
tree | aafa1819213283a04e2f04a3415da4a899471cfc /src | |
parent | dbe1e6f0c32bd07b7669b1b1ac3c7f58c9b8d773 (diff) |
Make readpixels work on GrTextures
Review URL: https://codereview.chromium.org/1234313002
Diffstat (limited to 'src')
-rwxr-xr-x | src/gpu/GrContext.cpp | 78 | ||||
-rw-r--r-- | src/gpu/GrSurface.cpp | 57 | ||||
-rw-r--r-- | src/gpu/GrSurfacePriv.h | 15 | ||||
-rw-r--r-- | src/gpu/gl/GrGLGpu.cpp | 38 | ||||
-rw-r--r-- | src/image/SkImage_Gpu.cpp | 2 |
5 files changed, 122 insertions, 68 deletions
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index 1c60074143..17b4b74a39 100755 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -347,6 +347,14 @@ bool GrContext::writeSurfacePixels(GrSurface* surface, } } + // Trim the params here so that if we wind up making a temporary surface it can be as small as + // necessary. + 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) { @@ -452,25 +460,28 @@ static SkColorType toggle_colortype32(SkColorType ct) { } } -bool GrContext::readRenderTargetPixels(GrRenderTarget* target, - int left, int top, int width, int height, - GrPixelConfig dstConfig, void* buffer, size_t rowBytes, - uint32_t flags) { +bool GrContext::readSurfacePixels(GrSurface* src, + int left, int top, int width, int height, + GrPixelConfig dstConfig, void* buffer, size_t rowBytes, + uint32_t flags) { RETURN_FALSE_IF_ABANDONED - ASSERT_OWNED_RESOURCE(target); - SkASSERT(target); + ASSERT_OWNED_RESOURCE(src); + SkASSERT(src); + + // Adjust the params so that if we wind up using an intermediate surface we've already done + // all the trimming and the temporary can be the min size required. + if (!GrSurfacePriv::AdjustReadPixelParams(src->width(), src->height(), + GrBytesPerPixel(dstConfig), &left, + &top, &width, &height, &buffer, &rowBytes)) { + return false; + } - if (!(kDontFlush_PixelOpsFlag & flags) && target->surfacePriv().hasPendingWrite()) { + if (!(kDontFlush_PixelOpsFlag & flags) && src->surfacePriv().hasPendingWrite()) { this->flush(); } // Determine which conversions have to be applied: flipY, swapRAnd, and/or unpremul. - // 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. - bool flipY = fGpu->readPixelsWillPayForYFlip(target, left, top, - width, height, dstConfig, - rowBytes); // 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 @@ -479,13 +490,23 @@ bool GrContext::readRenderTargetPixels(GrRenderTarget* target, GrPixelConfig readConfig = dstConfig; bool swapRAndB = false; if (GrPixelConfigSwapRAndB(dstConfig) == - fGpu->preferredReadPixelsConfig(dstConfig, target->config())) { + fGpu->preferredReadPixelsConfig(dstConfig, src->config())) { readConfig = GrPixelConfigSwapRAndB(readConfig); swapRAndB = true; } - bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags); + 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. return false; @@ -496,9 +517,11 @@ bool GrContext::readRenderTargetPixels(GrRenderTarget* target, // 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. - GrTexture* src = target->asTexture(); - if (src && (swapRAndB || unpremul || flipY)) { + // 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; @@ -514,8 +537,8 @@ bool GrContext::readRenderTargetPixels(GrRenderTarget* target, GrTextureProvider::ScratchTexMatch match = GrTextureProvider::kApprox_ScratchTexMatch; if (0 == left && 0 == top && - target->width() == width && - target->height() == height && + src->width() == width && + src->height() == height && fGpu->fullReadPixelsIsFasterThanPartial()) { match = GrTextureProvider::kExact_ScratchTexMatch; } @@ -529,18 +552,18 @@ bool GrContext::readRenderTargetPixels(GrRenderTarget* target, GrPaint paint; SkAutoTUnref<const GrFragmentProcessor> fp; if (unpremul) { - fp.reset(this->createPMToUPMEffect(paint.getProcessorDataManager(), src, swapRAndB, - textureMatrix)); + fp.reset(this->createPMToUPMEffect(paint.getProcessorDataManager(), srcAsTex, + swapRAndB, textureMatrix)); if (fp) { unpremul = false; // we no longer need to do this on CPU after the read back. } } // 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) { + if (fp || flipY || swapRAndB || !srcAsRT) { if (!fp) { fp.reset(GrConfigConversionEffect::Create(paint.getProcessorDataManager(), - src, swapRAndB, GrConfigConversionEffect::kNone_PMConversion, + srcAsTex, swapRAndB, GrConfigConversionEffect::kNone_PMConversion, textureMatrix)); } swapRAndB = false; // we will handle the swap in the draw. @@ -564,16 +587,15 @@ bool GrContext::readRenderTargetPixels(GrRenderTarget* target, // we want to read back from the scratch's origin left = 0; top = 0; - target = tempTexture->asRenderTarget(); + rtToRead = tempTexture->asRenderTarget(); } - this->flushSurfaceWrites(target); + this->flushSurfaceWrites(tempTexture); } } } - if (!fGpu->readPixels(target, - left, top, width, height, - readConfig, buffer, rowBytes)) { + if (!rtToRead || + !fGpu->readPixels(rtToRead, left, top, width, height, readConfig, buffer, rowBytes)) { return false; } // Perform any conversions we weren't able to perform using a scratch texture. diff --git a/src/gpu/GrSurface.cpp b/src/gpu/GrSurface.cpp index 9685c56275..9bd9e8b5ef 100644 --- a/src/gpu/GrSurface.cpp +++ b/src/gpu/GrSurface.cpp @@ -13,6 +13,55 @@ #include "SkImageEncoder.h" #include <stdio.h> +template<typename T> static bool adjust_params(int surfaceWidth, + int surfaceHeight, + size_t bpp, + int* left, int* top, int* width, int* height, + T** data, + size_t* rowBytes) { + if (!*rowBytes) { + *rowBytes = *width * bpp; + } + + SkIRect subRect = SkIRect::MakeXYWH(*left, *top, *width, *height); + SkIRect bounds = SkIRect::MakeWH(surfaceWidth, surfaceHeight); + + if (!subRect.intersect(bounds)) { + return false; + } + *data = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(*data) + + (subRect.fTop - *top) * *rowBytes + (subRect.fLeft - *left) * bpp); + + *left = subRect.fLeft; + *top = subRect.fTop; + *width = subRect.width(); + *height = subRect.height(); + return true; +} + +bool GrSurfacePriv::AdjustReadPixelParams(int surfaceWidth, + int surfaceHeight, + size_t bpp, + int* left, int* top, int* width, int* height, + void** data, + size_t* rowBytes) { + return adjust_params<void>(surfaceWidth, surfaceHeight, bpp, left, top, width, height, data, + rowBytes); +} + +bool GrSurfacePriv::AdjustWritePixelParams(int surfaceWidth, + int surfaceHeight, + size_t bpp, + int* left, int* top, int* width, int* height, + const void** data, + size_t* rowBytes) { + return adjust_params<const void>(surfaceWidth, surfaceHeight, bpp, left, top, width, height, + data, rowBytes); +} + + +////////////////////////////////////////////////////////////////////////////// + bool GrSurface::writePixels(int left, int top, int width, int height, GrPixelConfig config, const void* buffer, size_t rowBytes, uint32_t pixelOpsFlags) { @@ -33,12 +82,8 @@ bool GrSurface::readPixels(int left, int top, int width, int height, if (NULL == context) { return false; } - GrRenderTarget* target = this->asRenderTarget(); - if (target) { - return context->readRenderTargetPixels(target, left, top, width, height, config, buffer, - rowBytes, pixelOpsFlags); - } - return false; + return context->readSurfacePixels(this, left, top, width, height, config, buffer, + rowBytes, pixelOpsFlags); } SkImageInfo GrSurface::info(SkAlphaType alphaType) const { diff --git a/src/gpu/GrSurfacePriv.h b/src/gpu/GrSurfacePriv.h index 47bd44f4ef..bff411edf3 100644 --- a/src/gpu/GrSurfacePriv.h +++ b/src/gpu/GrSurfacePriv.h @@ -17,6 +17,21 @@ implemented privately in GrSurface with a inline public method here). */ class GrSurfacePriv { public: + /** Helpers used in read/write pixels implementations. The paramters are adjusted so that the + read/write respects the bounds of a surface. If the input *rowBytes is 0 it will be + the tight row bytes (based on width and bpp) on output. */ + static bool AdjustReadPixelParams(int surfaceWidth, + int surfaceHeight, + size_t bpp, + int* left, int* top, int* width, int* height, + void** data, + size_t* rowBytes); + static bool AdjustWritePixelParams(int surfaceWidth, + int surfaceHeight, + size_t bpp, + int* left, int* top, int* width, int* height, + const void** data, + size_t* rowBytes); /** * Derive a SkImageInfo from the surface's descriptor. The caller must provide the alpha type as * GrSurface has no equivalent. diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp index 5c03ab57d2..1a9566ae38 100644 --- a/src/gpu/gl/GrGLGpu.cpp +++ b/src/gpu/gl/GrGLGpu.cpp @@ -596,32 +596,6 @@ bool GrGLGpu::onWriteTexturePixels(GrTexture* texture, return false; } -static bool adjust_pixel_ops_params(int surfaceWidth, - int surfaceHeight, - size_t bpp, - int* left, int* top, int* width, int* height, - const void** data, - size_t* rowBytes) { - if (!*rowBytes) { - *rowBytes = *width * bpp; - } - - SkIRect subRect = SkIRect::MakeXYWH(*left, *top, *width, *height); - SkIRect bounds = SkIRect::MakeWH(surfaceWidth, surfaceHeight); - - if (!subRect.intersect(bounds)) { - return false; - } - *data = reinterpret_cast<const void*>(reinterpret_cast<intptr_t>(*data) + - (subRect.fTop - *top) * *rowBytes + (subRect.fLeft - *left) * bpp); - - *left = subRect.fLeft; - *top = subRect.fTop; - *width = subRect.width(); - *height = subRect.height(); - return true; -} - static inline GrGLenum check_alloc_error(const GrSurfaceDesc& desc, const GrGLInterface* interface) { if (SkToBool(desc.fFlags & kCheckAllocation_GrSurfaceFlag)) { @@ -643,8 +617,8 @@ bool GrGLGpu::uploadTexData(const GrSurfaceDesc& desc, SkASSERT(!GrPixelConfigIsCompressed(dataConfig)); size_t bpp = GrBytesPerPixel(dataConfig); - if (!adjust_pixel_ops_params(desc.fWidth, desc.fHeight, bpp, &left, &top, - &width, &height, &data, &rowBytes)) { + if (!GrSurfacePriv::AdjustWritePixelParams(desc.fWidth, desc.fHeight, bpp, &left, &top, + &width, &height, &data, &rowBytes)) { return false; } size_t trimRowBytes = width * bpp; @@ -1781,10 +1755,10 @@ bool GrGLGpu::onReadPixels(GrRenderTarget* target, return false; } size_t bpp = GrBytesPerPixel(config); - if (!adjust_pixel_ops_params(target->width(), target->height(), bpp, - &left, &top, &width, &height, - const_cast<const void**>(&buffer), - &rowBytes)) { + if (!GrSurfacePriv::AdjustReadPixelParams(target->width(), target->height(), bpp, + &left, &top, &width, &height, + &buffer, + &rowBytes)) { return false; } diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp index a3fe022b43..31ae5a90fd 100644 --- a/src/image/SkImage_Gpu.cpp +++ b/src/image/SkImage_Gpu.cpp @@ -248,8 +248,6 @@ GrTexture* GrDeepCopyTexture(GrTexture* src, bool budgeted) { GrContext* ctx = src->getContext(); GrSurfaceDesc desc = src->desc(); - // need to be a rendertarget for readpixels to work, instead of kNone_GrSurfaceFlags - desc.fFlags = kRenderTarget_GrSurfaceFlag; GrTexture* dst = ctx->textureProvider()->createTexture(desc, budgeted, NULL, 0); if (!dst) { return NULL; |