Detect implementation read formats on ES.
This can allow for more efficient glReadPixels (e.g. read back of GL_R8
as GL_RED, GL_UNSIGNED_BYTE rather than GL_RGBA, GL_UNSIGNED_BYTE).
skia:8962
Change-Id: Ifa219517f1ce14b79e8af88c799cd5ef35f3a24c
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/266567
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index 95c5e61..072a8ce 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -1417,7 +1417,10 @@
ioFormat.fColorType = GrColorType::kBGRA_8888;
ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
ioFormat.fExternalTexImageFormat = 0; // TODO: Enable this on non-ES GL
- ioFormat.fExternalReadFormat = GR_IS_GR_GL(standard) ? GR_GL_BGRA : 0;
+ ioFormat.fExternalReadFormat =
+ formatWorkarounds.fDisallowBGRA8ReadPixels ? 0 : GR_GL_BGRA;
+ // Not guaranteed by ES/WebGL.
+ ioFormat.fRequiresImplementationReadQuery = !GR_IS_GR_GL(standard);
}
}
@@ -1439,7 +1442,10 @@
ioFormat.fColorType = GrColorType::kBGRA_8888;
ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
ioFormat.fExternalTexImageFormat = GR_GL_BGRA;
- ioFormat.fExternalReadFormat = GR_IS_GR_GL(standard) ? GR_GL_BGRA : 0;
+ ioFormat.fExternalReadFormat =
+ formatWorkarounds.fDisallowBGRA8ReadPixels ? 0 : GR_GL_BGRA;
+ // Not guaranteed by ES/WebGL.
+ ioFormat.fRequiresImplementationReadQuery = !GR_IS_GR_GL(standard);
}
// Format: RGBA8, Surface: kBGRA_8888, Data: kRGBA_8888
@@ -1529,7 +1535,9 @@
ioFormat.fColorType = GrColorType::kAlpha_8;
ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
ioFormat.fExternalTexImageFormat = GR_GL_RED;
- ioFormat.fExternalReadFormat = GR_IS_GR_GL(standard) ? GR_GL_RED : 0;
+ ioFormat.fExternalReadFormat = GR_GL_RED;
+ // Not guaranteed by ES/WebGL.
+ ioFormat.fRequiresImplementationReadQuery = !GR_IS_GR_GL(standard);
}
// Format: R8, Surface: kAlpha_8, Data: kAlpha_8xxx
@@ -1561,7 +1569,9 @@
ioFormat.fColorType = GrColorType::kGray_8;
ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
ioFormat.fExternalTexImageFormat = GR_GL_RED;
- ioFormat.fExternalReadFormat = GR_IS_GR_GL(standard) ? GR_GL_RED : 0;
+ ioFormat.fExternalReadFormat = GR_GL_RED;
+ // Not guaranteed by ES/WebGL.
+ ioFormat.fRequiresImplementationReadQuery = !GR_IS_GR_GL(standard);
}
// Format: R8, Surface: kGray_8, Data: kGray_8xxx
@@ -1655,7 +1665,9 @@
ioFormat.fColorType = GrColorType::kAlpha_8;
ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
ioFormat.fExternalTexImageFormat = GR_GL_ALPHA;
- ioFormat.fExternalReadFormat = GR_IS_GR_GL(standard) ? GR_GL_ALPHA : 0;
+ ioFormat.fExternalReadFormat = GR_GL_ALPHA;
+ // Not guaranteed by ES/WebGL.
+ ioFormat.fRequiresImplementationReadQuery = !GR_IS_GR_GL(standard);
}
// Format: ALPHA8, Surface: kAlpha_8, Data: kRGBA_8888
@@ -1863,7 +1875,10 @@
ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
ioFormat.fExternalTexImageFormat = GR_GL_BGRA;
ioFormat.fExternalReadFormat = 0;
- ioFormat.fExternalReadFormat = GR_IS_GR_GL(standard) ? GR_GL_BGRA : 0;
+ ioFormat.fExternalReadFormat =
+ formatWorkarounds.fDisallowBGRA8ReadPixels ? 0 : GR_GL_BGRA;
+ // Not guaranteed by ES/WebGL.
+ ioFormat.fRequiresImplementationReadQuery = !GR_IS_GR_GL(standard);
}
// Format: BGRA8, Surface: kBGRA_8888, Data: kRGBA_8888
@@ -1933,7 +1948,9 @@
ioFormat.fColorType = GrColorType::kBGR_565;
ioFormat.fExternalType = GR_GL_UNSIGNED_SHORT_5_6_5;
ioFormat.fExternalTexImageFormat = GR_GL_RGB;
- ioFormat.fExternalReadFormat = GR_IS_GR_GL(standard) ? GR_GL_RGB : 0;
+ ioFormat.fExternalReadFormat = GR_GL_RGB;
+ // Not guaranteed by ES/WebGL.
+ ioFormat.fRequiresImplementationReadQuery = !GR_IS_GR_GL(standard);
}
// Format: RGB565, Surface: kBGR_565, Data: kRGBA_8888
@@ -2037,7 +2054,9 @@
ioFormat.fColorType = GrColorType::kRGBA_F16;
ioFormat.fExternalType = halfFloatType;
ioFormat.fExternalTexImageFormat = GR_GL_RGBA;
- ioFormat.fExternalReadFormat = GR_IS_GR_GL(standard) ? GR_GL_RGBA : 0;
+ ioFormat.fExternalReadFormat = GR_GL_RGBA;
+ // Not guaranteed by ES/WebGL.
+ ioFormat.fRequiresImplementationReadQuery = !GR_IS_GR_GL(standard);
}
// Format: RGBA16F, Surface: kRGBA_F16, Data: kRGBA_F32
@@ -2068,7 +2087,9 @@
ioFormat.fColorType = GrColorType::kRGBA_F16_Clamped;
ioFormat.fExternalType = halfFloatType;
ioFormat.fExternalTexImageFormat = GR_GL_RGBA;
- ioFormat.fExternalReadFormat = GR_IS_GR_GL(standard) ? GR_GL_RGBA : 0;
+ ioFormat.fExternalReadFormat = GR_GL_RGBA;
+ // Not guaranteed by ES/WebGL.
+ ioFormat.fRequiresImplementationReadQuery = !GR_IS_GR_GL(standard);
}
// Format: RGBA16F, Surface: kRGBA_F16_Clamped, Data: kRGBA_F32
@@ -2158,7 +2179,9 @@
ioFormat.fColorType = GrColorType::kAlpha_F16;
ioFormat.fExternalType = halfFloatType;
ioFormat.fExternalTexImageFormat = GR_GL_RED;
- ioFormat.fExternalReadFormat = GR_IS_GR_GL(standard) ? GR_GL_RED : 0;
+ ioFormat.fExternalReadFormat = GR_GL_RED;
+ // Not guaranteed by ES/WebGL.
+ ioFormat.fRequiresImplementationReadQuery = !GR_IS_GR_GL(standard);
}
// Format: R16F, Surface: kAlpha_F16, Data: kAlpha_F32xxx
@@ -2453,7 +2476,9 @@
ioFormat.fColorType = GrColorType::kRGBA_1010102;
ioFormat.fExternalType = GR_GL_UNSIGNED_INT_2_10_10_10_REV;
ioFormat.fExternalTexImageFormat = GR_GL_RGBA;
- ioFormat.fExternalReadFormat = GR_IS_GR_GL(standard) ? GR_GL_RGBA : 0;
+ ioFormat.fExternalReadFormat = GR_GL_RGBA;
+ // Not guaranteed by ES/WebGL.
+ ioFormat.fRequiresImplementationReadQuery = !GR_IS_GR_GL(standard);
}
// Format: RGB10_A2, Surface: kRGBA_1010102, Data: kRGBA_8888
@@ -2516,7 +2541,9 @@
ioFormat.fColorType = GrColorType::kABGR_4444;
ioFormat.fExternalType = GR_GL_UNSIGNED_SHORT_4_4_4_4;
ioFormat.fExternalTexImageFormat = GR_GL_RGBA;
- ioFormat.fExternalReadFormat = GR_IS_GR_GL(standard) ? GR_GL_RGBA : 0;
+ ioFormat.fExternalReadFormat = GR_GL_RGBA;
+ // Not guaranteed by ES/WebGL.
+ ioFormat.fRequiresImplementationReadQuery = !GR_IS_GR_GL(standard);
}
// Format: RGBA4, Surface: kABGR_4444, Data: kRGBA_8888
@@ -2753,7 +2780,9 @@
ioFormat.fColorType = GrColorType::kAlpha_16;
ioFormat.fExternalType = GR_GL_UNSIGNED_SHORT;
ioFormat.fExternalTexImageFormat = GR_GL_RED;
- ioFormat.fExternalReadFormat = GR_IS_GR_GL(standard) ? GR_GL_RED : 0;
+ ioFormat.fExternalReadFormat = GR_GL_RED;
+ // Not guaranteed by ES/WebGL.
+ ioFormat.fRequiresImplementationReadQuery = !GR_IS_GR_GL(standard);
}
// Format: R16, Surface: kAlpha_16, Data: kAlpha_8xxx
@@ -2820,7 +2849,9 @@
ioFormat.fColorType = GrColorType::kRG_1616;
ioFormat.fExternalType = GR_GL_UNSIGNED_SHORT;
ioFormat.fExternalTexImageFormat = GR_GL_RG;
- ioFormat.fExternalReadFormat = GR_IS_GR_GL(standard) ? GR_GL_RG : 0;
+ ioFormat.fExternalReadFormat = GR_GL_RG;
+ // Not guaranteed by ES/WebGL.
+ ioFormat.fRequiresImplementationReadQuery = !GR_IS_GR_GL(standard);
}
// Format: GR_GL_RG16, Surface: kRG_1616, Data: kRGBA_8888
@@ -2886,7 +2917,9 @@
ioFormat.fColorType = GrColorType::kRGBA_16161616;
ioFormat.fExternalType = GR_GL_UNSIGNED_SHORT;
ioFormat.fExternalTexImageFormat = GR_GL_RGBA;
- ioFormat.fExternalReadFormat = GR_IS_GR_GL(standard) ? GR_GL_RGBA : 0;
+ ioFormat.fExternalReadFormat = GR_GL_RGBA;
+ // Not guaranteed by ES/WebGL.
+ ioFormat.fRequiresImplementationReadQuery = !GR_IS_GR_GL(standard);
}
// Format: GR_GL_RGBA16, Surface: kRGBA_16161616, Data: kRGBA_8888
@@ -2976,7 +3009,9 @@
ioFormat.fColorType = GrColorType::kRG_F16;
ioFormat.fExternalType = halfFloatType;
ioFormat.fExternalTexImageFormat = GR_GL_RG;
- ioFormat.fExternalReadFormat = GR_IS_GR_GL(standard) ? GR_GL_RG : 0;
+ ioFormat.fExternalReadFormat = GR_GL_RG;
+ // Not guaranteed by ES/WebGL.
+ ioFormat.fRequiresImplementationReadQuery = !GR_IS_GR_GL(standard);
}
// Format: GR_GL_RG16F, Surface: kRG_F16, Data: kRGBA_F32
@@ -3847,6 +3882,10 @@
// http://skbug.com/8921
shaderCaps->fCanOnlyUseSampleMaskWithStencil = true;
}
+
+ if (ctxInfo.angleBackend() == GrGLANGLEBackend::kD3D9) {
+ formatWorkarounds->fDisallowBGRA8ReadPixels = true;
+ }
}
void GrGLCaps::onApplyOptionsOverrides(const GrContextOptions& options) {
@@ -3962,15 +4001,18 @@
for (int j = 0; j < ctInfo.fExternalIOFormatCount; ++j) {
const auto& ioInfo = ctInfo.fExternalIOFormats[j];
if (ioInfo.fExternalReadFormat != 0) {
- GrGLenum transferOffsetAlignment =
- offset_alignment_for_transfer_buffer(ioInfo.fExternalType);
- if (ioInfo.fColorType == dstColorType) {
- return {dstColorType, transferOffsetAlignment};
- }
- // Currently we just pick the first supported format that we find as our
- // fallback.
- if (fallbackRead.fColorType == GrColorType::kUnknown) {
- fallbackRead = {ioInfo.fColorType, transferOffsetAlignment};
+ if (formatInfo.fHaveQueriedImplementationReadSupport ||
+ !ioInfo.fRequiresImplementationReadQuery) {
+ GrGLenum transferOffsetAlignment =
+ offset_alignment_for_transfer_buffer(ioInfo.fExternalType);
+ if (ioInfo.fColorType == dstColorType) {
+ return {dstColorType, transferOffsetAlignment};
+ }
+ // Currently we just pick the first supported format that we find as our
+ // fallback.
+ if (fallbackRead.fColorType == GrColorType::kUnknown) {
+ fallbackRead = {ioInfo.fColorType, transferOffsetAlignment};
+ }
}
}
}
@@ -4134,6 +4176,48 @@
return SkToBool(this->getFormatInfo(format).fFlags & FormatInfo::kUseTexStorage_Flag);
}
+bool GrGLCaps::shouldQueryImplementationReadSupport(GrGLFormat format) const {
+ const auto& formatInfo = const_cast<GrGLCaps*>(this)->getFormatInfo(format);
+ if (!formatInfo.fHaveQueriedImplementationReadSupport) {
+ // Check whether we will actually learn anything useful.
+ bool needQuery = false;
+ for (int i = 0; i < formatInfo.fColorTypeInfoCount && !needQuery; ++i) {
+ const auto& surfCTInfo = formatInfo.fColorTypeInfos[i];
+ for (int j = 0; j < surfCTInfo.fExternalIOFormatCount; ++j) {
+ if (surfCTInfo.fExternalIOFormats[j].fRequiresImplementationReadQuery) {
+ needQuery = true;
+ break;
+ }
+ }
+ }
+ if (!needQuery) {
+ // Pretend we already checked it.
+ const_cast<FormatInfo&>(formatInfo).fHaveQueriedImplementationReadSupport = true;
+ }
+ }
+ return !formatInfo.fHaveQueriedImplementationReadSupport;
+}
+
+void GrGLCaps::didQueryImplementationReadSupport(GrGLFormat format,
+ GrGLenum readFormat,
+ GrGLenum readType) const {
+ auto& formatInfo = const_cast<GrGLCaps*>(this)->getFormatInfo(format);
+ for (int i = 0; i < formatInfo.fColorTypeInfoCount; ++i) {
+ auto& surfCTInfo = formatInfo.fColorTypeInfos[i];
+ for (int j = 0; j < surfCTInfo.fExternalIOFormatCount; ++j) {
+ auto& readCTInfo = surfCTInfo.fExternalIOFormats[j];
+ if (readCTInfo.fRequiresImplementationReadQuery) {
+ if (readCTInfo.fExternalReadFormat != readFormat ||
+ readCTInfo.fExternalType != readType) {
+ // Don't zero out fExternalType. It's also used for writing data to the texture!
+ readCTInfo.fExternalReadFormat = 0;
+ }
+ }
+ }
+ }
+ formatInfo.fHaveQueriedImplementationReadSupport = true;
+}
+
bool GrGLCaps::onAreColorTypeAndFormatCompatible(GrColorType ct,
const GrBackendFormat& format) const {
GrGLFormat glFormat = format.asGLFormat();
diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h
index 59818dd..0e87ba1 100644
--- a/src/gpu/gl/GrGLCaps.h
+++ b/src/gpu/gl/GrGLCaps.h
@@ -199,6 +199,20 @@
bool formatSupportsTexStorage(GrGLFormat) const;
/**
+ * Would it be useful to check GL_IMPLEMENTATION_READ_FORMAT and _TYPE for this format to
+ * detect more efficient glReadPixels arguments?
+ */
+ bool shouldQueryImplementationReadSupport(GrGLFormat format) const;
+
+ /**
+ * Let caps know the result of GL_IMPLEMENTATION_READ_FORMAT and _TYPE query for a format
+ * to update supported glReadPixels arguments.
+ */
+ void didQueryImplementationReadSupport(GrGLFormat format,
+ GrGLenum readFormat,
+ GrGLenum readType) const;
+
+ /**
* Gets the internal format to use with glRenderbufferStorageMultisample...(). May be sized or
* base depending upon the GL. Not applicable to compressed textures.
*/
@@ -463,6 +477,7 @@
bool fDisableLuminance16F = false;
bool fDontDisableTexStorageOnAndroid = false;
bool fDisallowDirectRG8ReadPixels = false;
+ bool fDisallowBGRA8ReadPixels = false;
};
void applyDriverCorrectnessWorkarounds(const GrGLContextInfo&, const GrContextOptions&,
@@ -583,15 +598,25 @@
GrGLenum fExternalType = 0;
GrGLenum fExternalTexImageFormat = 0;
GrGLenum fExternalReadFormat = 0;
+ /**
+ * Must check whether GL_IMPLEMENTATION_COLOR_READ_FORMAT and _TYPE match
+ * fExternalReadFormat and fExternalType before using with glReadPixels.
+ */
+ bool fRequiresImplementationReadQuery = false;
};
- GrGLenum externalFormat(GrColorType externalColorType, ExternalFormatUsage usage) const {
+ GrGLenum externalFormat(GrColorType externalColorType, ExternalFormatUsage usage,
+ bool haveQueriedImplementationReadFormat) const {
for (int i = 0; i < fExternalIOFormatCount; ++i) {
if (fExternalIOFormats[i].fColorType == externalColorType) {
if (usage == kTexImage_ExternalFormatUsage) {
return fExternalIOFormats[i].fExternalTexImageFormat;
} else {
SkASSERT(usage == kReadPixels_ExternalFormatUsage);
+ if (!haveQueriedImplementationReadFormat &&
+ fExternalIOFormats[i].fRequiresImplementationReadQuery) {
+ return 0;
+ }
return fExternalIOFormats[i].fExternalReadFormat;
}
}
@@ -626,7 +651,8 @@
ExternalFormatUsage usage) const {
for (int i = 0; i < fColorTypeInfoCount; ++i) {
if (fColorTypeInfos[i].fColorType == surfaceColorType) {
- return fColorTypeInfos[i].externalFormat(externalColorType, usage);
+ return fColorTypeInfos[i].externalFormat(externalColorType, usage,
+ fHaveQueriedImplementationReadSupport);
}
}
return 0;
@@ -676,6 +702,8 @@
// This value is only valid for regular formats. Compressed formats will be 0.
GrGLenum fBytesPerPixel = 0;
+ bool fHaveQueriedImplementationReadSupport = false;
+
enum {
// This indicates that a stencil format has not yet been determined for the config.
kUnknown_StencilIndex = -1,
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index 313aaef..f797b6c 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -2302,6 +2302,14 @@
if (this->glCaps().srgbWriteControl()) {
this->flushFramebufferSRGB(this->caps()->isFormatSRGB(target->backendFormat()));
}
+
+ if (this->glCaps().shouldQueryImplementationReadSupport(target->format())) {
+ GrGLint format;
+ GrGLint type;
+ GR_GL_GetIntegerv(this->glInterface(), GR_GL_IMPLEMENTATION_COLOR_READ_FORMAT, &format);
+ GR_GL_GetIntegerv(this->glInterface(), GR_GL_IMPLEMENTATION_COLOR_READ_TYPE, &type);
+ this->glCaps().didQueryImplementationReadSupport(target->format(), format, type);
+ }
}
void GrGLGpu::flushFramebufferSRGB(bool enable) {