Add ability to query read pixels support without a render target.
Add more checks to onGetReadPixelsInfo.
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1615023003
Review URL: https://codereview.chromium.org/1615023003
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index ae6e613..5c6d59f 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -10,6 +10,7 @@
#include "GrContextOptions.h"
#include "GrGLContext.h"
+#include "GrGLRenderTarget.h"
#include "glsl/GrGLSLCaps.h"
#include "SkTSearch.h"
#include "SkTSort.h"
@@ -17,6 +18,8 @@
GrGLCaps::GrGLCaps(const GrContextOptions& contextOptions,
const GrGLContextInfo& ctxInfo,
const GrGLInterface* glInterface) : INHERITED(contextOptions) {
+ fStandard = ctxInfo.standard();
+
fStencilFormats.reset();
fMSFBOType = kNone_MSFBOType;
fInvalidateFBType = kNone_InvalidateFBType;
@@ -648,47 +651,52 @@
}
return true;
}
-bool GrGLCaps::readPixelsSupported(const GrGLInterface* intf,
+
+bool GrGLCaps::readPixelsSupported(GrPixelConfig rtConfig,
GrPixelConfig readConfig,
- GrPixelConfig currFBOConfig) const {
- SkASSERT(this->isConfigRenderable(currFBOConfig, false));
+ std::function<void (GrGLenum, GrGLint*)> getIntegerv,
+ std::function<bool ()> bindRenderTarget) const {
+ SkASSERT(this->isConfigRenderable(rtConfig, false));
GrGLenum readFormat;
GrGLenum readType;
- if (!this->getReadPixelsFormat(currFBOConfig, readConfig, &readFormat, &readType)) {
+ if (!this->getReadPixelsFormat(rtConfig, readConfig, &readFormat, &readType)) {
return false;
}
- if (kGL_GrGLStandard == intf->fStandard) {
+ if (kGL_GrGLStandard == fStandard) {
// All of our renderable configs can be converted to each other by glReadPixels in OpenGL.
return true;
}
// See Section 16.1.2 in the ES 3.2 specification.
- if (kNormalizedFixedPoint_FormatType == fConfigTable[currFBOConfig].fFormatType) {
+ if (kNormalizedFixedPoint_FormatType == fConfigTable[rtConfig].fFormatType) {
if (GR_GL_RGBA == readFormat && GR_GL_UNSIGNED_BYTE == readType) {
return true;
}
} else {
- SkASSERT(kFloat_FormatType == fConfigTable[currFBOConfig].fFormatType);
+ SkASSERT(kFloat_FormatType == fConfigTable[rtConfig].fFormatType);
if (GR_GL_RGBA == readFormat && GR_GL_FLOAT == readType) {
return true;
}
}
- if (0 == fConfigTable[currFBOConfig].fSecondReadPixelsFormat.fFormat) {
+ if (0 == fConfigTable[rtConfig].fSecondReadPixelsFormat.fFormat) {
ReadPixelsFormat* rpFormat =
- const_cast<ReadPixelsFormat*>(&fConfigTable[currFBOConfig].fSecondReadPixelsFormat);
+ const_cast<ReadPixelsFormat*>(&fConfigTable[rtConfig].fSecondReadPixelsFormat);
GrGLint format = 0, type = 0;
- GR_GL_GetIntegerv(intf, GR_GL_IMPLEMENTATION_COLOR_READ_FORMAT, &format);
- GR_GL_GetIntegerv(intf, GR_GL_IMPLEMENTATION_COLOR_READ_TYPE, &type);
+ if (!bindRenderTarget()) {
+ return false;
+ }
+ getIntegerv(GR_GL_IMPLEMENTATION_COLOR_READ_FORMAT, &format);
+ getIntegerv(GR_GL_IMPLEMENTATION_COLOR_READ_TYPE, &type);
rpFormat->fFormat = format;
rpFormat->fType = type;
}
- return fConfigTable[currFBOConfig].fSecondReadPixelsFormat.fFormat == readFormat &&
- fConfigTable[currFBOConfig].fSecondReadPixelsFormat.fType == readType;
+ return fConfigTable[rtConfig].fSecondReadPixelsFormat.fFormat == readFormat &&
+ fConfigTable[rtConfig].fSecondReadPixelsFormat.fType == readType;
}
void GrGLCaps::initFSAASupport(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli) {
diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h
index c4f4270..044ecce 100644
--- a/src/gpu/gl/GrGLCaps.h
+++ b/src/gpu/gl/GrGLCaps.h
@@ -9,6 +9,8 @@
#ifndef GrGLCaps_DEFINED
#define GrGLCaps_DEFINED
+#include <functional>
+
#include "glsl/GrGLSL.h"
#include "GrCaps.h"
#include "GrGLStencilAttachment.h"
@@ -19,6 +21,7 @@
class GrGLContextInfo;
class GrGLSLCaps;
+class GrGLRenderTarget;
/**
* Stores some capabilities of a GL context. Most are determined by the GL
@@ -283,10 +286,11 @@
/// Use indices or vertices in CPU arrays rather than VBOs for dynamic content.
bool useNonVBOVertexAndIndexDynamicData() const { return fUseNonVBOVertexAndIndexDynamicData; }
- /// Does ReadPixels support the provided format/type combo?
- bool readPixelsSupported(const GrGLInterface* intf,
+ /// Does ReadPixels support reading readConfig pixels from a FBO that is renderTargetConfig?
+ bool readPixelsSupported(GrPixelConfig renderTargetConfig,
GrPixelConfig readConfig,
- GrPixelConfig currFBOConfig) const;
+ std::function<void (GrGLenum, GrGLint*)> getIntegerv,
+ std::function<bool ()> bindRenderTarget) const;
bool isCoreProfile() const { return fIsCoreProfile; }
@@ -348,6 +352,8 @@
const GrGLInterface* intf,
GrGLSLCaps* glslCaps);
+ GrGLStandard fStandard;
+
SkTArray<StencilFormat, true> fStencilFormats;
int fMaxFragmentUniformVectors;
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index 8fffc4d..d7a0600 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -2069,12 +2069,55 @@
return caps.packRowLengthSupport() || GrBytesPerPixel(config) * width == rowBytes;
}
+bool GrGLGpu::readPixelsSupported(GrRenderTarget* target, GrPixelConfig readConfig) {
+ auto bindRenderTarget = [this, target]() -> bool {
+ this->flushRenderTarget(static_cast<GrGLRenderTarget*>(target), &SkIRect::EmptyIRect());
+ return true;
+ };
+ auto getIntegerv = [this](GrGLenum query, GrGLint* value) {
+ GR_GL_GetIntegerv(this->glInterface(), query, value);
+ };
+ GrPixelConfig rtConfig = target->config();
+ return this->glCaps().readPixelsSupported(rtConfig, readConfig, getIntegerv, bindRenderTarget);
+}
+
+bool GrGLGpu::readPixelsSupported(GrPixelConfig rtConfig, GrPixelConfig readConfig) {
+ auto bindRenderTarget = [this, rtConfig]() -> bool {
+ GrTextureDesc desc;
+ desc.fConfig = rtConfig;
+ desc.fWidth = desc.fHeight = 16;
+ desc.fFlags = kRenderTarget_GrSurfaceFlag;
+ SkAutoTUnref<GrTexture> temp(this->createTexture(desc, false, nullptr, 0));
+ if (!temp) {
+ return false;
+ }
+ GrGLRenderTarget* glrt = static_cast<GrGLRenderTarget*>(temp->asRenderTarget());
+ this->flushRenderTarget(glrt, &SkIRect::EmptyIRect());
+ return true;
+ };
+ auto getIntegerv = [this](GrGLenum query, GrGLint* value) {
+ GR_GL_GetIntegerv(this->glInterface(), query, value);
+ };
+ return this->glCaps().readPixelsSupported(rtConfig, readConfig, getIntegerv, bindRenderTarget);
+}
+
+bool GrGLGpu::readPixelsSupported(GrSurface* surfaceForConfig, GrPixelConfig readConfig) {
+ if (GrRenderTarget* rt = surfaceForConfig->asRenderTarget()) {
+ return this->readPixelsSupported(rt, readConfig);
+ } else {
+ GrPixelConfig config = surfaceForConfig->config();
+ return this->readPixelsSupported(config, readConfig);
+ }
+}
+
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 (!srcSurface->asRenderTarget()) {
+ if (!srcAsRT) {
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
}
@@ -2099,33 +2142,38 @@
GrPixelConfig srcConfig = srcSurface->config();
tempDrawInfo->fTempSurfaceDesc.fConfig = readConfig;
- if (this->glCaps().rgba8888PixelsOpsAreSlow() && kRGBA_8888_GrPixelConfig == readConfig) {
+ if (this->glCaps().rgba8888PixelsOpsAreSlow() && kRGBA_8888_GrPixelConfig == readConfig &&
+ this->readPixelsSupported(kBGRA_8888_GrPixelConfig, kBGRA_8888_GrPixelConfig)) {
tempDrawInfo->fTempSurfaceDesc.fConfig = kBGRA_8888_GrPixelConfig;
tempDrawInfo->fSwizzle = GrSwizzle::BGRA();
tempDrawInfo->fReadConfig = kBGRA_8888_GrPixelConfig;
ElevateDrawPreference(drawPreference, kGpuPrefersDraw_DrawPreference);
} else if (kMesa_GrGLDriver == this->glContext().driver() &&
GrBytesPerPixel(readConfig) == 4 &&
- GrPixelConfigSwapRAndB(readConfig) == srcConfig) {
+ GrPixelConfigSwapRAndB(readConfig) == srcConfig &&
+ this->readPixelsSupported(srcSurface, srcConfig)) {
// Mesa 3D takes a slow path on when reading back BGRA from an RGBA surface and vice-versa.
// Better to do a draw with a R/B swap and then read as the original config.
tempDrawInfo->fTempSurfaceDesc.fConfig = srcConfig;
tempDrawInfo->fSwizzle = GrSwizzle::BGRA();
tempDrawInfo->fReadConfig = srcConfig;
ElevateDrawPreference(drawPreference, kGpuPrefersDraw_DrawPreference);
- } else if (readConfig == kBGRA_8888_GrPixelConfig &&
- !this->glCaps().readPixelsSupported(this->glInterface(), readConfig, srcConfig)) {
- tempDrawInfo->fTempSurfaceDesc.fConfig = kRGBA_8888_GrPixelConfig;
- tempDrawInfo->fSwizzle = GrSwizzle::BGRA();
- tempDrawInfo->fReadConfig = kRGBA_8888_GrPixelConfig;
- ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
+ } else if (!this->readPixelsSupported(srcSurface, readConfig)) {
+ if (readConfig == kBGRA_8888_GrPixelConfig &&
+ this->glCaps().isConfigRenderable(kRGBA_8888_GrPixelConfig, false) &&
+ this->readPixelsSupported(kRGBA_8888_GrPixelConfig, kRGBA_8888_GrPixelConfig)) {
+
+ tempDrawInfo->fTempSurfaceDesc.fConfig = kRGBA_8888_GrPixelConfig;
+ tempDrawInfo->fSwizzle = GrSwizzle::BGRA();
+ tempDrawInfo->fReadConfig = kRGBA_8888_GrPixelConfig;
+ ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
+ } else {
+ return false;
+ }
}
- GrRenderTarget* srcAsRT = srcSurface->asRenderTarget();
- if (!srcAsRT) {
- ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
- } else if (read_pixels_pays_for_y_flip(srcAsRT, this->glCaps(), width, height, readConfig,
- rowBytes)) {
+ if (srcAsRT &&
+ read_pixels_pays_for_y_flip(srcAsRT, this->glCaps(), width, height, readConfig, rowBytes)) {
ElevateDrawPreference(drawPreference, kGpuPrefersDraw_DrawPreference);
}
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index 4e7e4d6..6f194dc 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -166,6 +166,20 @@
bool onMakeCopyForTextureParams(GrTexture*, const GrTextureParams&,
GrTextureProducer::CopyParams*) const override;
+ // Checks whether glReadPixels can be called to get pixel values in readConfig from the
+ // render target.
+ bool readPixelsSupported(GrRenderTarget* target, GrPixelConfig readConfig);
+
+ // Checks whether glReadPixels can be called to get pixel values in readConfig from a
+ // render target that has renderTargetConfig. This may have to create a temporary
+ // render target and thus is less preferable than the variant that takes a render target.
+ bool readPixelsSupported(GrPixelConfig renderTargetConfig, GrPixelConfig readConfig);
+
+ // Checks whether glReadPixels can be called to get pixel values in readConfig from a
+ // render target that has the same config as surfaceForConfig. Calls one of the the two
+ // variations above, depending on whether the surface is a render target or not.
+ bool readPixelsSupported(GrSurface* surfaceForConfig, GrPixelConfig readConfig);
+
bool onReadPixels(GrSurface*,
int left, int top,
int width, int height,