| Index: src/gpu/gl/GrGLGpu.cpp
|
| diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
|
| index bf0b297c8cf064620b4ac55586c9672ff969f75c..94307a67a458530f9b872daf89f43ec28a7bcb55 100644
|
| --- a/src/gpu/gl/GrGLGpu.cpp
|
| +++ b/src/gpu/gl/GrGLGpu.cpp
|
| @@ -2004,26 +2004,21 @@ bool GrGLGpu::readPixelsSupported(GrSurface* surfaceForConfig, GrPixelConfig rea
|
| }
|
| }
|
|
|
| +static bool requires_srgb_conversion(GrPixelConfig a, GrPixelConfig b) {
|
| + if (GrPixelConfigIsSRGB(a)) {
|
| + return !GrPixelConfigIsSRGB(b) && !GrPixelConfigIsAlphaOnly(b);
|
| + } else if (GrPixelConfigIsSRGB(b)) {
|
| + return !GrPixelConfigIsSRGB(a) && !GrPixelConfigIsAlphaOnly(a);
|
| + }
|
| + return false;
|
| +}
|
| +
|
| bool GrGLGpu::onGetReadPixelsInfo(GrSurface* srcSurface, int width, int height, size_t rowBytes,
|
| GrPixelConfig readConfig, DrawPreference* drawPreference,
|
| ReadPixelTempDrawInfo* tempDrawInfo) {
|
| - GrRenderTarget* srcAsRT = srcSurface->asRenderTarget();
|
| -
|
| - // This subclass can only read pixels from a render target. We could use glTexSubImage2D on
|
| - // GL versions that support it but we don't today.
|
| - if (!srcAsRT) {
|
| - ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
|
| - }
|
| -
|
| - if (GrPixelConfigIsSRGB(srcSurface->config()) != GrPixelConfigIsSRGB(readConfig)) {
|
| - ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
|
| - }
|
| -
|
| - tempDrawInfo->fSwizzle = GrSwizzle::RGBA();
|
| - tempDrawInfo->fReadConfig = readConfig;
|
| + GrPixelConfig srcConfig = srcSurface->config();
|
|
|
| - // These settings we will always want if a temp draw is performed. The config is set below
|
| - // depending on whether we want to do a R/B swap or not.
|
| + // These settings we will always want if a temp draw is performed.
|
| tempDrawInfo->fTempSurfaceDesc.fFlags = kRenderTarget_GrSurfaceFlag;
|
| tempDrawInfo->fTempSurfaceDesc.fWidth = width;
|
| tempDrawInfo->fTempSurfaceDesc.fHeight = height;
|
| @@ -2031,10 +2026,33 @@ bool GrGLGpu::onGetReadPixelsInfo(GrSurface* srcSurface, int width, int height,
|
| tempDrawInfo->fTempSurfaceDesc.fOrigin = kTopLeft_GrSurfaceOrigin; // no CPU y-flip for TL.
|
| tempDrawInfo->fUseExactScratch = this->glCaps().partialFBOReadIsSlow();
|
|
|
| - // Start off assuming that any temp draw should be to the readConfig, then check if that will
|
| - // be inefficient.
|
| - GrPixelConfig srcConfig = srcSurface->config();
|
| - tempDrawInfo->fTempSurfaceDesc.fConfig = readConfig;
|
| + // For now assume no swizzling, we may change that below.
|
| + tempDrawInfo->fSwizzle = GrSwizzle::RGBA();
|
| +
|
| + // Depends on why we need/want a temp draw. Start off assuming no change, the surface we read
|
| + // from will be srcConfig and we will read readConfig pixels from it.
|
| + // Not that if we require a draw and return a non-renderable format for the temp surface the
|
| + // base class will fail for us.
|
| + tempDrawInfo->fTempSurfaceDesc.fConfig = srcConfig;
|
| + tempDrawInfo->fReadConfig = readConfig;
|
| +
|
| + if (requires_srgb_conversion(srcConfig, readConfig)) {
|
| + if (!this->readPixelsSupported(readConfig, readConfig)) {
|
| + return false;
|
| + }
|
| + // Draw to do srgb to linear conversion or vice versa.
|
| + ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
|
| + tempDrawInfo->fTempSurfaceDesc.fConfig = readConfig;
|
| + tempDrawInfo->fReadConfig = readConfig;
|
| + return true;
|
| + }
|
| +
|
| + GrRenderTarget* srcAsRT = srcSurface->asRenderTarget();
|
| + if (!srcAsRT) {
|
| + // For now keep assuming the draw is not a format transformation, just a draw to get to a
|
| + // RT. We may add additional transformations below.
|
| + ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
|
| + }
|
|
|
| if (this->glCaps().rgba8888PixelsOpsAreSlow() && kRGBA_8888_GrPixelConfig == readConfig &&
|
| this->readPixelsSupported(kBGRA_8888_GrPixelConfig, kBGRA_8888_GrPixelConfig)) {
|
| @@ -2056,11 +2074,35 @@ bool GrGLGpu::onGetReadPixelsInfo(GrSurface* srcSurface, int width, int height,
|
| if (readConfig == kBGRA_8888_GrPixelConfig &&
|
| this->glCaps().isConfigRenderable(kRGBA_8888_GrPixelConfig, false) &&
|
| this->readPixelsSupported(kRGBA_8888_GrPixelConfig, kRGBA_8888_GrPixelConfig)) {
|
| -
|
| + // We're trying to read BGRA but it's not supported. If RGBA is renderable and
|
| + // we can read it back, then do a swizzling draw to a RGBA and read it back (which
|
| + // will effectively be BGRA).
|
| tempDrawInfo->fTempSurfaceDesc.fConfig = kRGBA_8888_GrPixelConfig;
|
| tempDrawInfo->fSwizzle = GrSwizzle::BGRA();
|
| tempDrawInfo->fReadConfig = kRGBA_8888_GrPixelConfig;
|
| ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
|
| + } else if (readConfig == kAlpha_8_GrPixelConfig) {
|
| + // onReadPixels implements a fallback for cases where we are want to read kAlpha_8,
|
| + // it's unsupported, but 32bit RGBA reads are supported.
|
| + // Don't attempt to do any srgb conversions since we only care about alpha.
|
| + GrPixelConfig cpuTempConfig = kRGBA_8888_GrPixelConfig;
|
| + if (GrPixelConfigIsSRGB(srcSurface->config())) {
|
| + cpuTempConfig = kSRGBA_8888_GrPixelConfig;
|
| + }
|
| + if (!this->readPixelsSupported(srcSurface, cpuTempConfig)) {
|
| + // If we can't read RGBA from the src try to draw to a kRGBA_8888 (or kSRGBA_8888)
|
| + // first and then onReadPixels will read that to a 32bit temporary buffer.
|
| + if (this->caps()->isConfigRenderable(cpuTempConfig, false)) {
|
| + ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
|
| + tempDrawInfo->fTempSurfaceDesc.fConfig = cpuTempConfig;
|
| + tempDrawInfo->fReadConfig = kAlpha_8_GrPixelConfig;
|
| + } else {
|
| + return false;
|
| + }
|
| + } else {
|
| + SkASSERT(tempDrawInfo->fTempSurfaceDesc.fConfig == srcConfig);
|
| + SkASSERT(tempDrawInfo->fReadConfig == kAlpha_8_GrPixelConfig);
|
| + }
|
| } else {
|
| return false;
|
| }
|
| @@ -2082,46 +2124,71 @@ bool GrGLGpu::onReadPixels(GrSurface* surface,
|
| size_t rowBytes) {
|
| SkASSERT(surface);
|
|
|
| - GrGLRenderTarget* tgt = static_cast<GrGLRenderTarget*>(surface->asRenderTarget());
|
| - if (!tgt) {
|
| + GrGLRenderTarget* renderTarget = static_cast<GrGLRenderTarget*>(surface->asRenderTarget());
|
| + if (!renderTarget) {
|
| return false;
|
| }
|
|
|
| // OpenGL doesn't do sRGB <-> linear conversions when reading and writing pixels.
|
| - if (GrPixelConfigIsSRGB(surface->config()) != GrPixelConfigIsSRGB(config)) {
|
| + if (requires_srgb_conversion(surface->config(), config)) {
|
| + return false;
|
| + }
|
| +
|
| + // We have a special case fallback for reading eight bit alpha. We will read back all four 8
|
| + // bit channels as RGBA and then extract A.
|
| + if (!this->readPixelsSupported(renderTarget, config)) {
|
| + // Don't attempt to do any srgb conversions since we only care about alpha.
|
| + GrPixelConfig tempConfig = kRGBA_8888_GrPixelConfig;
|
| + if (GrPixelConfigIsSRGB(renderTarget->config())) {
|
| + tempConfig = kSRGBA_8888_GrPixelConfig;
|
| + }
|
| + if (kAlpha_8_GrPixelConfig == config &&
|
| + this->readPixelsSupported(renderTarget, tempConfig)) {
|
| + SkAutoTDeleteArray<uint32_t> temp(new uint32_t[width * height * 4]);
|
| + if (this->onReadPixels(renderTarget, left, top, width, height, tempConfig, temp.get(),
|
| + width*4)) {
|
| + uint8_t* dst = reinterpret_cast<uint8_t*>(buffer);
|
| + for (int j = 0; j < height; ++j) {
|
| + for (int i = 0; i < width; ++i) {
|
| + dst[j*rowBytes + i] = (0xFF000000U & temp[j*width+i]) >> 24;
|
| + }
|
| + }
|
| + return true;
|
| + }
|
| + }
|
| return false;
|
| }
|
|
|
| GrGLenum externalFormat;
|
| GrGLenum externalType;
|
| - if (!this->glCaps().getReadPixelsFormat(surface->config(), config, &externalFormat,
|
| + if (!this->glCaps().getReadPixelsFormat(renderTarget->config(), config, &externalFormat,
|
| &externalType)) {
|
| return false;
|
| }
|
| bool flipY = kBottomLeft_GrSurfaceOrigin == surface->origin();
|
|
|
| // resolve the render target if necessary
|
| - switch (tgt->getResolveType()) {
|
| + switch (renderTarget->getResolveType()) {
|
| case GrGLRenderTarget::kCantResolve_ResolveType:
|
| return false;
|
| case GrGLRenderTarget::kAutoResolves_ResolveType:
|
| - this->flushRenderTarget(tgt, &SkIRect::EmptyIRect());
|
| + this->flushRenderTarget(renderTarget, &SkIRect::EmptyIRect());
|
| break;
|
| case GrGLRenderTarget::kCanResolve_ResolveType:
|
| - this->onResolveRenderTarget(tgt);
|
| + this->onResolveRenderTarget(renderTarget);
|
| // we don't track the state of the READ FBO ID.
|
| fStats.incRenderTargetBinds();
|
| - GL_CALL(BindFramebuffer(GR_GL_READ_FRAMEBUFFER, tgt->textureFBOID()));
|
| + GL_CALL(BindFramebuffer(GR_GL_READ_FRAMEBUFFER, renderTarget->textureFBOID()));
|
| break;
|
| default:
|
| SkFAIL("Unknown resolve type");
|
| }
|
|
|
| - const GrGLIRect& glvp = tgt->getViewport();
|
| + const GrGLIRect& glvp = renderTarget->getViewport();
|
|
|
| // the read rect is viewport-relative
|
| GrGLIRect readRect;
|
| - readRect.setRelativeTo(glvp, left, top, width, height, tgt->origin());
|
| + readRect.setRelativeTo(glvp, left, top, width, height, renderTarget->origin());
|
|
|
| size_t tightRowBytes = GrBytesPerPixel(config) * width;
|
|
|
|
|