aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar bsalomon <bsalomon@google.com>2015-07-16 08:23:13 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-07-16 08:23:13 -0700
commite8d21e8f24aa676765d0ff8f433228665c75cdc2 (patch)
treeaafa1819213283a04e2f04a3415da4a899471cfc /src
parentdbe1e6f0c32bd07b7669b1b1ac3c7f58c9b8d773 (diff)
Make readpixels work on GrTextures
Diffstat (limited to 'src')
-rwxr-xr-xsrc/gpu/GrContext.cpp78
-rw-r--r--src/gpu/GrSurface.cpp57
-rw-r--r--src/gpu/GrSurfacePriv.h15
-rw-r--r--src/gpu/gl/GrGLGpu.cpp38
-rw-r--r--src/image/SkImage_Gpu.cpp2
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;