diff options
-rw-r--r-- | include/gpu/GrGLConfig.h | 10 | ||||
-rw-r--r-- | include/gpu/GrGLConfig_chrome.h | 4 | ||||
-rw-r--r-- | src/gpu/GrContext.cpp | 20 | ||||
-rw-r--r-- | src/gpu/GrGpu.h | 8 | ||||
-rw-r--r-- | src/gpu/GrGpuGL.cpp | 85 | ||||
-rw-r--r-- | src/gpu/GrGpuGL.h | 2 |
6 files changed, 102 insertions, 27 deletions
diff --git a/include/gpu/GrGLConfig.h b/include/gpu/GrGLConfig.h index ea7bcf341c..cfb5141a18 100644 --- a/include/gpu/GrGLConfig.h +++ b/include/gpu/GrGLConfig.h @@ -78,9 +78,9 @@ * The GrGLInterface field fCallback specifies the function ptr and there is an * additional field fCallbackData of type intptr_t for client data. * - * GR_GL_RGBA_8888_READBACK_SLOW: Set this to 1 if it is known that performing - * glReadPixels with format=GL_RGBA, type=GL_UNISIGNED_BYTE is significantly - * slower than format=GL_BGRA, type=GL_UNISIGNED_BYTE. + * GR_GL_RGBA_8888_PIXEL_OPS_SLOW: Set this to 1 if it is known that performing + * glReadPixels / glTex(Sub)Image with format=GL_RGBA, type=GL_UNISIGNED_BYTE is + * significantly slower than format=GL_BGRA, type=GL_UNISIGNED_BYTE. */ #if !defined(GR_GL_LOG_CALLS) @@ -115,8 +115,8 @@ #define GR_GL_PER_GL_FUNC_CALLBACK 0 #endif -#if !defined(GR_GL_RGBA_8888_READBACK_SLOW) - #define GR_GL_RGBA_8888_READBACK_SLOW 0 +#if !defined(GR_GL_RGBA_8888_PIXEL_OPS_SLOW) + #define GR_GL_RGBA_8888_PIXEL_OPS_SLOW 0 #endif #if(GR_GL_NO_CONSTANT_ATTRIBUTES) && (GR_GL_ATTRIBUTE_MATRICES) diff --git a/include/gpu/GrGLConfig_chrome.h b/include/gpu/GrGLConfig_chrome.h index 79324ab511..72d330acc5 100644 --- a/include/gpu/GrGLConfig_chrome.h +++ b/include/gpu/GrGLConfig_chrome.h @@ -14,8 +14,8 @@ // ANGLE creates a temp VB for vertex attributes not specified per-vertex. #define GR_GL_NO_CONSTANT_ATTRIBUTES GR_WIN32_BUILD -// RGBA Readbacks are a slow path in ANGLE -#define GR_GL_RGBA_8888_READBACK_SLOW GR_WIN32_BUILD +// For RGBA teximage/readpixels ANGLE will sw-convert to/from BGRA. +#define GR_GL_RGBA_8888_PIXEL_OPS_SLOW GR_WIN32_BUILD // cmd buffer allocates memory and memsets it to zero when it sees glBufferData // with NULL. diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index fe85b97b92..3a26d2f609 100644 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -1803,6 +1803,25 @@ void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target, // TODO: when underlying api has a direct way to do this we should use it // (e.g. glDrawPixels on desktop GL). + // If the RT is also a texture and we don't have to do PM/UPM conversion + // then take the texture path, which we expect to be at least as fast or + // faster since it doesn't use an intermediate texture as we do below. + if (NULL != target->asTexture() && + GrPixelConfigIsUnpremultiplied(target->config()) == + GrPixelConfigIsUnpremultiplied(config)) { + + this->internalWriteTexturePixels(target->asTexture(), + left, top, width, height, + config, buffer, rowBytes, flags); + return; + } + + bool swapRAndB = fGpu->preferredReadPixelsConfig(config) == + GrPixelConfigSwapRAndB(config); + if (swapRAndB) { + config = GrPixelConfigSwapRAndB(config); + } + const GrTextureDesc desc = { kNone_GrTextureFlags, kNone_GrAALevel, width, height, { config } }; @@ -1827,6 +1846,7 @@ void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target, sampler.setClampNoFilter(); matrix.setIDiv(texture->width(), texture->height()); sampler.setMatrix(matrix); + sampler.setRAndBSwap(swapRAndB); fGpu->setSamplerState(0, sampler); GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0); diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h index 9b39319f4f..6741aec513 100644 --- a/src/gpu/GrGpu.h +++ b/src/gpu/GrGpu.h @@ -195,6 +195,13 @@ public: } /** + * Same as above but applies to writeTexturePixels + */ + virtual GrPixelConfig preferredWritePixelsConfig(GrPixelConfig config) { + return config; + } + + /** * OpenGL's readPixels returns the result bottom-to-top while the skia * API is top-to-bottom. Thus we have to do a y-axis flip. The obvious * solution is to have the subclass do the flip using either the CPU or GPU. @@ -247,6 +254,7 @@ public: /** * Updates the pixels in a rectangle of a texture. + * * @param left left edge of the rectangle to write (inclusive) * @param top top edge of the rectangle to write (inclusive) * @param width width of rectangle to write in pixels. diff --git a/src/gpu/GrGpuGL.cpp b/src/gpu/GrGpuGL.cpp index facfac914a..cd37a54e9a 100644 --- a/src/gpu/GrGpuGL.cpp +++ b/src/gpu/GrGpuGL.cpp @@ -439,7 +439,15 @@ void GrGpuGL::initStencilFormats() { } GrPixelConfig GrGpuGL::preferredReadPixelsConfig(GrPixelConfig config) { - if (GR_GL_RGBA_8888_READBACK_SLOW && GrPixelConfigIsRGBA8888(config)) { + if (GR_GL_RGBA_8888_PIXEL_OPS_SLOW && GrPixelConfigIsRGBA8888(config)) { + return GrPixelConfigSwapRAndB(config); + } else { + return config; + } +} + +GrPixelConfig GrGpuGL::preferredWritePixelsConfig(GrPixelConfig config) { + if (GR_GL_RGBA_8888_PIXEL_OPS_SLOW && GrPixelConfigIsRGBA8888(config)) { return GrPixelConfigSwapRAndB(config); } else { return config; @@ -693,21 +701,46 @@ void GrGpuGL::onWriteTexturePixels(GrTexture* texture, this->uploadTexData(desc, left, top, width, height, config, buffer, rowBytes); } +namespace { +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; + } + + GrIRect subRect = GrIRect::MakeXYWH(*left, *top, *width, *height); + GrIRect bounds = GrIRect::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; +} +} + void GrGpuGL::uploadTexData(const GrGLTexture::Desc& desc, int left, int top, int width, int height, GrPixelConfig dataConfig, const void* data, size_t rowBytes) { - GrIRect bounds = GrIRect::MakeWH(desc.fWidth, desc.fHeight); - GrIRect subrect = GrIRect::MakeXYWH(left, top, width, height); - if (!bounds.contains(subrect)) { + + size_t bpp = GrBytesPerPixel(dataConfig); + if (!adjust_pixel_ops_params(desc.fWidth, desc.fHeight, bpp, &left, &top, + &width, &height, &data, &rowBytes)) { return; } - - // ES2 glCompressedTexSubImage2D doesn't support any formats - // (at least without extensions) - GrAssert(desc.fInternalFormat != GR_GL_PALETTE8_RGBA8 || - bounds == subrect); + size_t trimRowBytes = width * bpp; // in case we need a temporary, trimmed copy of the src pixels SkAutoSMalloc<128 * 128> tempStorage; @@ -720,11 +753,6 @@ void GrGpuGL::uploadTexData(const GrGLTexture::Desc& desc, return; } - size_t bpp = GrBytesPerPixel(dataConfig); - size_t trimRowBytes = width * bpp; - if (!rowBytes) { - rowBytes = trimRowBytes; - } /* * check whether to allocate a temporary buffer for flipping y or * because our srcData has extra bytes past each row. If so, we need @@ -758,13 +786,14 @@ void GrGpuGL::uploadTexData(const GrGLTexture::Desc& desc, } dst += trimRowBytes; } - // now point dat to our copied version + // now point data to our copied version data = tempStorage.get(); } } GL_CALL(PixelStorei(GR_GL_UNPACK_ALIGNMENT, static_cast<GrGLint>(bpp))); - if (bounds == subrect) { + if (0 == left && 0 == top && + desc.fWidth == width && desc.fHeight == height) { GL_CALL(TexImage2D(GR_GL_TEXTURE_2D, 0, desc.fInternalFormat, desc.fWidth, desc.fHeight, 0, externalFormat, externalType, data)); @@ -1320,9 +1349,18 @@ bool GrGpuGL::readPixelsWillPayForYFlip(GrRenderTarget* renderTarget, size_t rowBytes) { // if we have to do memcpy to handle non-trim rowBytes then we // get the flip for free. Otherwise it costs. - return this->glCaps().fPackRowLengthSupport || - 0 == rowBytes || - GrBytesPerPixel(config) * width == rowBytes; + if (this->glCaps().fPackRowLengthSupport) { + return true; + } + // If we have to do memcpys to handle rowBytes then y-flip is free + // Note the rowBytes might be tight to the passed in data, but if data + // gets clipped in x to the target the rowBytes will no longer be tight. + if (left >= 0 && (left + width) < renderTarget->width()) { + return 0 == rowBytes || + GrBytesPerPixel(config) * width == rowBytes; + } else { + return false; + } } bool GrGpuGL::onReadPixels(GrRenderTarget* target, @@ -1338,6 +1376,13 @@ bool GrGpuGL::onReadPixels(GrRenderTarget* target, if (!this->canBeTexture(config, &internalFormat, &format, &type)) { 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)) { + return false; + } // resolve the render target if necessary GrGLRenderTarget* tgt = static_cast<GrGLRenderTarget*>(target); @@ -1366,7 +1411,7 @@ bool GrGpuGL::onReadPixels(GrRenderTarget* target, GrGLIRect readRect; readRect.setRelativeTo(glvp, left, top, width, height); - size_t tightRowBytes = GrBytesPerPixel(config) * width; + size_t tightRowBytes = bpp * width; if (0 == rowBytes) { rowBytes = tightRowBytes; } diff --git a/src/gpu/GrGpuGL.h b/src/gpu/GrGpuGL.h index 18baedf968..3b8e6d74af 100644 --- a/src/gpu/GrGpuGL.h +++ b/src/gpu/GrGpuGL.h @@ -31,6 +31,8 @@ public: virtual GrPixelConfig preferredReadPixelsConfig(GrPixelConfig config) SK_OVERRIDE; + virtual GrPixelConfig preferredWritePixelsConfig(GrPixelConfig config) + SK_OVERRIDE; virtual bool readPixelsWillPayForYFlip( GrRenderTarget* renderTarget, |