aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu
diff options
context:
space:
mode:
Diffstat (limited to 'src/gpu')
-rw-r--r--src/gpu/GrContext.cpp9
-rw-r--r--src/gpu/GrGpu.cpp6
-rw-r--r--src/gpu/GrGpu.h6
-rw-r--r--src/gpu/GrGpuGL.cpp72
-rw-r--r--src/gpu/GrGpuGL.h6
-rw-r--r--src/gpu/SkGpuDevice.cpp43
6 files changed, 86 insertions, 56 deletions
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 7028c91147..3fc5d7d773 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -1637,15 +1637,16 @@ bool GrContext::readTexturePixels(GrTexture* texture,
if (NULL != target) {
return fGpu->readPixels(target,
left, top, width, height,
- config, buffer);
+ config, buffer, 0);
} else {
return false;
}
}
bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
- int left, int top, int width, int height,
- GrPixelConfig config, void* buffer) {
+ int left, int top, int width, int height,
+ GrPixelConfig config, void* buffer,
+ size_t rowBytes) {
SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
uint32_t flushFlags = 0;
if (NULL == target) {
@@ -1655,7 +1656,7 @@ bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
this->flush(flushFlags);
return fGpu->readPixels(target,
left, top, width, height,
- config, buffer);
+ config, buffer, rowBytes);
}
void GrContext::writePixels(int left, int top, int width, int height,
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index f0808d394f..1fc8d47339 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -221,10 +221,12 @@ void GrGpu::forceRenderTargetFlush() {
bool GrGpu::readPixels(GrRenderTarget* target,
int left, int top, int width, int height,
- GrPixelConfig config, void* buffer) {
+ GrPixelConfig config, void* buffer,
+ size_t rowBytes) {
this->handleDirtyContext();
- return this->onReadPixels(target, left, top, width, height, config, buffer);
+ return this->onReadPixels(target, left, top, width, height,
+ config, buffer, rowBytes);
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index 9107554cd6..cf29ed7555 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -180,6 +180,8 @@ public:
* @param height height of rectangle to read in pixels.
* @param config the pixel config of the destination buffer
* @param buffer memory to read the rectangle into.
+ * @param rowBytes the number of bytes between consecutive rows. Zero
+ * means rows are tightly packed.
*
* @return true if the read succeeded, false if not. The read can fail
* because of a unsupported pixel config or because no render
@@ -187,7 +189,7 @@ public:
*/
bool readPixels(GrRenderTarget* renderTarget,
int left, int top, int width, int height,
- GrPixelConfig config, void* buffer);
+ GrPixelConfig config, void* buffer, size_t rowBytes);
const GrGpuStats& getStats() const;
void resetStats();
@@ -321,7 +323,7 @@ protected:
// overridden by API-specific derived class to perform the read pixels.
virtual bool onReadPixels(GrRenderTarget* target,
int left, int top, int width, int height,
- GrPixelConfig, void* buffer) = 0;
+ GrPixelConfig, void* buffer, size_t rowBytes) = 0;
// called to program the vertex data, indexCount will be 0 if drawing non-
// indexed geometry. The subclass may adjust the startVertex and/or
diff --git a/src/gpu/GrGpuGL.cpp b/src/gpu/GrGpuGL.cpp
index 78655929f3..dc4d78ac43 100644
--- a/src/gpu/GrGpuGL.cpp
+++ b/src/gpu/GrGpuGL.cpp
@@ -1384,14 +1384,18 @@ void GrGpuGL::onForceRenderTargetFlush() {
}
bool GrGpuGL::onReadPixels(GrRenderTarget* target,
- int left, int top, int width, int height,
- GrPixelConfig config, void* buffer) {
+ int left, int top,
+ int width, int height,
+ GrPixelConfig config,
+ void* buffer, size_t rowBytes) {
GrGLenum internalFormat; // we don't use this for glReadPixels
GrGLenum format;
GrGLenum type;
if (!this->canBeTexture(config, &internalFormat, &format, &type)) {
return false;
- }
+ }
+
+ // resolve the render target if necessary
GrGLRenderTarget* tgt = static_cast<GrGLRenderTarget*>(target);
GrAutoTPtrValueRestore<GrRenderTarget*> autoTargetRestore;
switch (tgt->getResolveType()) {
@@ -1417,26 +1421,62 @@ bool GrGpuGL::onReadPixels(GrRenderTarget* target,
// the read rect is viewport-relative
GrGLIRect readRect;
readRect.setRelativeTo(glvp, left, top, width, height);
+
+ size_t tightRowBytes = GrBytesPerPixel(config) * width;
+ if (0 == rowBytes) {
+ rowBytes = tightRowBytes;
+ }
+ size_t readDstRowBytes = tightRowBytes;
+ void* readDst = buffer;
+
+ // determine if GL can read using the passed rowBytes or if we need
+ // a scratch buffer.
+ SkAutoSMalloc<32 * sizeof(GrColor)> scratch;
+ if (rowBytes != tightRowBytes) {
+ if (kDesktop_GrGLBinding == this->glBinding()) {
+ GrAssert(!(rowBytes % sizeof(GrColor)));
+ GL_CALL(PixelStorei(GR_GL_PACK_ROW_LENGTH, rowBytes / sizeof(GrColor)));
+ readDstRowBytes = rowBytes;
+ } else {
+ scratch.reset(tightRowBytes * height);
+ readDst = scratch.get();
+ }
+ }
GL_CALL(ReadPixels(readRect.fLeft, readRect.fBottom,
readRect.fWidth, readRect.fHeight,
- format, type, buffer));
+ format, type, readDst));
+ if (readDstRowBytes != tightRowBytes) {
+ GL_CALL(PixelStorei(GR_GL_PACK_ROW_LENGTH, 0));
+ }
// now reverse the order of the rows, since GL's are bottom-to-top, but our
- // API presents top-to-bottom
- {
- size_t stride = width * GrBytesPerPixel(config);
- SkAutoMalloc rowStorage(stride);
- void* tmp = rowStorage.get();
-
+ // API presents top-to-bottom. We must preserve the padding contents. Note
+ // that the above readPixels did not overwrite the padding.
+ if (readDst == buffer) {
+ GrAssert(rowBytes == readDstRowBytes);
+ scratch.reset(tightRowBytes);
+ void* tmpRow = scratch.get();
+ // flip y in-place by rows
const int halfY = height >> 1;
char* top = reinterpret_cast<char*>(buffer);
- char* bottom = top + (height - 1) * stride;
+ char* bottom = top + (height - 1) * rowBytes;
for (int y = 0; y < halfY; y++) {
- memcpy(tmp, top, stride);
- memcpy(top, bottom, stride);
- memcpy(bottom, tmp, stride);
- top += stride;
- bottom -= stride;
+ memcpy(tmpRow, top, tightRowBytes);
+ memcpy(top, bottom, tightRowBytes);
+ memcpy(bottom, tmpRow, tightRowBytes);
+ top += rowBytes;
+ bottom -= rowBytes;
+ }
+ } else {
+ GrAssert(readDst != buffer);
+ // copy from readDst to buffer while flipping y
+ const int halfY = height >> 1;
+ const char* src = reinterpret_cast<const char*>(readDst);
+ char* dst = reinterpret_cast<char*>(buffer) + (height-1) * rowBytes;
+ for (int y = 0; y < height; y++) {
+ memcpy(dst, src, tightRowBytes);
+ src += readDstRowBytes;
+ dst -= rowBytes;
}
}
return true;
diff --git a/src/gpu/GrGpuGL.h b/src/gpu/GrGpuGL.h
index 2d246e8479..51eb4aed02 100644
--- a/src/gpu/GrGpuGL.h
+++ b/src/gpu/GrGpuGL.h
@@ -90,8 +90,10 @@ protected:
virtual void onForceRenderTargetFlush();
virtual bool onReadPixels(GrRenderTarget* target,
- int left, int top, int width, int height,
- GrPixelConfig, void* buffer);
+ int left, int top,
+ int width, int height,
+ GrPixelConfig,
+ void* buffer, size_t rowBytes) SK_OVERRIDE;
virtual void onGpuDrawIndexed(GrPrimitiveType type,
uint32_t startVertex,
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index d75838350e..790cf6d09e 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -256,36 +256,19 @@ void SkGpuDevice::makeRenderTargetCurrent() {
///////////////////////////////////////////////////////////////////////////////
-bool SkGpuDevice::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
- SkIRect bounds;
- bounds.set(0, 0, this->width(), this->height());
- if (!bounds.intersect(srcRect)) {
- return false;
- }
-
- const int w = bounds.width();
- const int h = bounds.height();
- SkBitmap tmp;
- // note we explicitly specify our rowBytes to be snug (no gap between rows)
- tmp.setConfig(SkBitmap::kARGB_8888_Config, w, h, w * 4);
- if (!tmp.allocPixels()) {
- return false;
- }
-
- tmp.lockPixels();
-
- bool read = fContext->readRenderTargetPixels(fRenderTarget,
- bounds.fLeft, bounds.fTop,
- bounds.width(), bounds.height(),
- kRGBA_8888_GrPixelConfig,
- tmp.getPixels());
- tmp.unlockPixels();
- if (!read) {
- return false;
- }
-
- tmp.swap(*bitmap);
- return true;
+bool SkGpuDevice::onReadPixels(const SkBitmap* bitmap, int x, int y) {
+ SkASSERT(SkBitmap::kARGB_8888_Config == bitmap->config());
+ SkASSERT(!bitmap->isNull());
+ SkASSERT(SkIRect::MakeWH(this->width(), this->height()).contains(SkIRect::MakeXYWH(x, y, bitmap->width(), bitmap->height())));
+
+ SkAutoLockPixels alp(*bitmap);
+ return fContext->readRenderTargetPixels(fRenderTarget,
+ x, y,
+ bitmap->width(),
+ bitmap->height(),
+ kRGBA_8888_GrPixelConfig,
+ bitmap->getPixels(),
+ bitmap->rowBytes());
}
void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y) {