diff options
Diffstat (limited to 'src/gpu')
-rw-r--r-- | src/gpu/GrContext.cpp | 9 | ||||
-rw-r--r-- | src/gpu/GrGpu.cpp | 6 | ||||
-rw-r--r-- | src/gpu/GrGpu.h | 6 | ||||
-rw-r--r-- | src/gpu/GrGpuGL.cpp | 72 | ||||
-rw-r--r-- | src/gpu/GrGpuGL.h | 6 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice.cpp | 43 |
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) { |