Make transferability a per-format flag in GrGLCaps

Add workaround for 16 bit unorm on freedreno

Make sure callsites are checking for transfer alignment
of 0 to indicate unsupported.

Bug: skia:11876
Change-Id: Ia1c22a430f675fc57724f220f5dee5b23f325f3c
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/421317
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
diff --git a/src/gpu/GrSurfaceContext.cpp b/src/gpu/GrSurfaceContext.cpp
index 6a6fd2d..c1ad2e8 100644
--- a/src/gpu/GrSurfaceContext.cpp
+++ b/src/gpu/GrSurfaceContext.cpp
@@ -967,7 +967,16 @@
 
     auto texMatrix = SkMatrix::Translate(x, y);
 
-    bool doSynchronousRead = !this->caps()->transferFromSurfaceToBufferSupport();
+    auto [readCT, offsetAlignment] =
+            this->caps()->supportedReadPixelsColorType(yFC->colorInfo().colorType(),
+                                                       yFC->asSurfaceProxy()->backendFormat(),
+                                                       GrColorType::kAlpha_8);
+    if (readCT == GrColorType::kUnknown) {
+        callback(callbackContext, nullptr);
+        return;
+    }
+    bool doSynchronousRead = !this->caps()->transferFromSurfaceToBufferSupport() ||
+                             !offsetAlignment;
     PixelTransferResult yTransfer, uTransfer, vTransfer;
 
     // This matrix generates (r,g,b,a) = (0, 0, 0, y)
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index de85545..936cb17 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -1357,7 +1357,7 @@
         info.fDefaultExternalFormat = GR_GL_RGBA;
         info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
         info.fDefaultColorType = GrColorType::kRGBA_8888;
-        info.fFlags = FormatInfo::kTexturable_Flag;
+        info.fFlags = FormatInfo::kTexturable_Flag | FormatInfo::kTransfers_Flag;
         if (GR_IS_GR_GL(standard)) {
             info.fFlags |= msaaRenderFlags;
         } else if (GR_IS_GR_GL_ES(standard)) {
@@ -1493,7 +1493,9 @@
         }
 
         if (r8Support) {
-            info.fFlags |= FormatInfo::kTexturable_Flag | msaaRenderFlags;
+            info.fFlags |= FormatInfo::kTexturable_Flag
+                        |  FormatInfo::kTransfers_Flag
+                        |  msaaRenderFlags;
         }
 
         if (texStorageSupported) {
@@ -1608,7 +1610,7 @@
         info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
         info.fDefaultColorType = GrColorType::kAlpha_8;
         if (alpha8IsValidForGL || alpha8IsValidForGLES || alpha8IsValidForWebGL) {
-            info.fFlags = FormatInfo::kTexturable_Flag;
+            info.fFlags = FormatInfo::kTexturable_Flag | FormatInfo::kTransfers_Flag;
         }
         if (alpha8IsRenderable && alpha8IsValidForGL) {
             // We will use ALPHA8 to create MSAA renderbuffers.
@@ -1695,7 +1697,7 @@
             lum8Supported = true;
         }
         if (lum8Supported) {
-            info.fFlags = FormatInfo::kTexturable_Flag;
+            info.fFlags = FormatInfo::kTexturable_Flag | FormatInfo::kTransfers_Flag;
         }
         if (texStorageSupported && lum8SizedFormatSupported) {
             info.fFlags |= FormatInfo::kUseTexStorage_Flag;
@@ -1775,7 +1777,7 @@
             la8Supported = true;
         }
         if (la8Supported) {
-            info.fFlags = FormatInfo::kTexturable_Flag;
+            info.fFlags = FormatInfo::kTexturable_Flag | FormatInfo::kTransfers_Flag;
         }
         if (texStorageSupported && la8SizedFormatSupported) {
             info.fFlags |= FormatInfo::kUseTexStorage_Flag;
@@ -1879,7 +1881,9 @@
 
         if (GR_IS_GR_GL_ES(standard)) {
             if (ctxInfo.hasExtension("GL_EXT_texture_format_BGRA8888")) {
-                info.fFlags = FormatInfo::kTexturable_Flag | nonMSAARenderFlags;
+                info.fFlags = FormatInfo::kTexturable_Flag
+                            | FormatInfo::kTransfers_Flag
+                            | nonMSAARenderFlags;
                 // GL_EXT_texture storage has defined interactions with
                 // GL_EXT_texture_format_BGRA8888. However, ES3 supports glTexStorage but
                 // without GL_EXT_texture_storage it does not allow the BGRA8 sized internal format.
@@ -1899,7 +1903,9 @@
                 if (version >= GR_GL_VER(3,0)) {
                     // The APPLE extension doesn't explicitly make this renderable, but
                     // internally it appears to use RGBA8, which we'll patch up below.
-                    info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags;
+                    info.fFlags = FormatInfo::kTexturable_Flag
+                                | FormatInfo::kTransfers_Flag
+                                | msaaRenderFlags;
                     supportsBGRATexStorage = true;
                 }
             }
@@ -1962,12 +1968,18 @@
         info.fDefaultColorType = GrColorType::kBGR_565;
         if (GR_IS_GR_GL(standard)) {
             if (version >= GR_GL_VER(4, 2) || ctxInfo.hasExtension("GL_ARB_ES2_compatibility")) {
-                info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags;
+                info.fFlags = FormatInfo::kTexturable_Flag
+                            | FormatInfo::kTransfers_Flag
+                            | msaaRenderFlags;
             }
         } else if (GR_IS_GR_GL_ES(standard)) {
-            info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags;
+            info.fFlags = FormatInfo::kTexturable_Flag
+                        | FormatInfo::kTransfers_Flag
+                        | msaaRenderFlags;
         } else if (GR_IS_GR_WEBGL(standard)) {
-            info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags;
+            info.fFlags = FormatInfo::kTexturable_Flag
+                        | FormatInfo::kTransfers_Flag
+                        | msaaRenderFlags;
         }
         // 565 is not a sized internal format on desktop GL. So on desktop with
         // 565 we always use an unsized internal format to let the system pick
@@ -2074,7 +2086,7 @@
         }
 
         if (rgba16FTextureSupport) {
-            info.fFlags = FormatInfo::kTexturable_Flag;
+            info.fFlags = FormatInfo::kTexturable_Flag | FormatInfo::kTransfers_Flag;
             if (rgba16FRenderTargetSupport) {
                 info.fFlags |= fpRenderFlags;
             }
@@ -2198,7 +2210,7 @@
         }
 
         if (r16FTextureSupport) {
-            info.fFlags = FormatInfo::kTexturable_Flag;
+            info.fFlags = FormatInfo::kTexturable_Flag | FormatInfo::kTransfers_Flag;
             if (r16FRenderTargetSupport) {
                 info.fFlags |= fpRenderFlags;
             }
@@ -2284,7 +2296,7 @@
         info.fDefaultColorType = GrColorType::kGray_F16;
 
         if (lum16FSupported) {
-            info.fFlags = FormatInfo::kTexturable_Flag;
+            info.fFlags = FormatInfo::kTexturable_Flag | FormatInfo::kTransfers_Flag;
 
             if (texStorageSupported && lum16FSizedFormatSupported) {
                 info.fFlags |= FormatInfo::kUseTexStorage_Flag;
@@ -2345,7 +2357,7 @@
         info.fDefaultExternalFormat = GR_GL_RGB;
         info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
         info.fDefaultColorType = GrColorType::kRGB_888;
-        info.fFlags = FormatInfo::kTexturable_Flag;
+        info.fFlags = FormatInfo::kTexturable_Flag | FormatInfo::kTransfers_Flag;
         if (GR_IS_GR_GL(standard)) {
             // Even in OpenGL 4.6 GL_RGB8 is required to be color renderable but not required to be
             // a supported render buffer format. Since we usually use render buffers for MSAA on
@@ -2422,7 +2434,9 @@
             rg8Support = version >= GR_GL_VER(2, 0);
         }
         if (rg8Support) {
-            info.fFlags |= FormatInfo::kTexturable_Flag | msaaRenderFlags;
+            info.fFlags |= FormatInfo::kTexturable_Flag
+                        |  FormatInfo::kTransfers_Flag
+                        |  msaaRenderFlags;
             if (texStorageSupported) {
                 info.fFlags |= FormatInfo::kUseTexStorage_Flag;
                 info.fInternalFormatForTexImageOrStorage = GR_GL_RG8;
@@ -2482,10 +2496,12 @@
         info.fDefaultColorType = GrColorType::kRGBA_1010102;
         if (GR_IS_GR_GL(standard) ||
            (GR_IS_GR_GL_ES(standard) && version >= GR_GL_VER(3, 0))) {
-            info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags;
+            info.fFlags = FormatInfo::kTexturable_Flag
+                        | FormatInfo::kTransfers_Flag
+                        | msaaRenderFlags;
         } else if (GR_IS_GR_GL_ES(standard) &&
                    ctxInfo.hasExtension("GL_EXT_texture_type_2_10_10_10_REV")) {
-            info.fFlags = FormatInfo::kTexturable_Flag;
+            info.fFlags = FormatInfo::kTexturable_Flag | FormatInfo::kTransfers_Flag;
         } // No WebGL support
 
         if (texStorageSupported) {
@@ -2580,7 +2596,7 @@
         info.fDefaultExternalFormat = GR_GL_RGBA;
         info.fDefaultExternalType = GR_GL_UNSIGNED_SHORT_4_4_4_4;
         info.fDefaultColorType = GrColorType::kABGR_4444;
-        info.fFlags = FormatInfo::kTexturable_Flag;
+        info.fFlags = FormatInfo::kTexturable_Flag | FormatInfo::kTransfers_Flag;
         if (GR_IS_GR_GL(standard)) {
             if (version >= GR_GL_VER(4, 2)) {
                 info.fFlags |= msaaRenderFlags;
@@ -2687,7 +2703,7 @@
         }
 
         if (srgb8Alpha8TextureSupport) {
-            info.fFlags = FormatInfo::kTexturable_Flag;
+            info.fFlags = FormatInfo::kTexturable_Flag | FormatInfo::kTransfers_Flag;
             if (srgb8Alpha8RenderTargetSupport) {
                 info.fFlags |= formatWorkarounds.fDisableSRGBRenderWithMSAAForMacAMD
                                        ? nonMSAARenderFlags
@@ -2822,6 +2838,9 @@
 
         if (r16Supported) {
             info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags;
+            if (!formatWorkarounds.fDisallowUnorm16Transfers) {
+                info.fFlags |= FormatInfo::kTransfers_Flag;
+            }
         }
 
         if (texStorageSupported) {
@@ -2892,6 +2911,9 @@
 
         if (rg16Supported) {
             info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags;
+            if (!formatWorkarounds.fDisallowUnorm16Transfers) {
+                info.fFlags |= FormatInfo::kTransfers_Flag;
+            }
         }
 
         if (texStorageSupported) {
@@ -2959,6 +2981,9 @@
         info.fDefaultColorType = GrColorType::kRGBA_16161616;
         if (rgba16Support) {
             info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags;
+            if (!formatWorkarounds.fDisallowUnorm16Transfers) {
+                info.fFlags |= FormatInfo::kTransfers_Flag;
+            }
         }
 
         if (texStorageSupported) {
@@ -3046,7 +3071,7 @@
         info.fDefaultExternalType = halfFloatType;
         info.fDefaultColorType = GrColorType::kRG_F16;
         if (rg16FTextureSupport) {
-            info.fFlags |= FormatInfo::kTexturable_Flag;
+            info.fFlags |= FormatInfo::kTexturable_Flag | FormatInfo::kTransfers_Flag;
             if (rg16FRenderTargetSupport) {
                 info.fFlags |= fpRenderFlags;
             }
@@ -4171,6 +4196,10 @@
         // crbug.com/1203652
         fAlwaysDrawQuadsIndexed = true;
     }
+
+    if (ctxInfo.driver() == GrGLDriver::kFreedreno) {
+        formatWorkarounds->fDisallowUnorm16Transfers = true;
+    }
 }
 
 void GrGLCaps::onApplyOptionsOverrides(const GrContextOptions& options) {
@@ -4283,9 +4312,9 @@
 
     SkImage::CompressionType compression = GrBackendFormatToCompressionType(srcBackendFormat);
     if (compression != SkImage::CompressionType::kNone) {
-        return { SkCompressionTypeIsOpaque(compression) ? GrColorType::kRGB_888x
-                                                        : GrColorType::kRGBA_8888,
-                 offset_alignment_for_transfer_buffer(GR_GL_UNSIGNED_BYTE) };
+        return {SkCompressionTypeIsOpaque(compression) ? GrColorType::kRGB_888x
+                                                       : GrColorType::kRGBA_8888,
+                0};
     }
 
     // We first try to find a supported read pixels GrColorType that matches the requested
@@ -4302,8 +4331,11 @@
                 if (ioInfo.fExternalReadFormat != 0) {
                     if (formatInfo.fHaveQueriedImplementationReadSupport ||
                         !ioInfo.fRequiresImplementationReadQuery) {
-                        GrGLenum transferOffsetAlignment =
-                                offset_alignment_for_transfer_buffer(ioInfo.fExternalType);
+                        GrGLenum transferOffsetAlignment = 0;
+                        if (formatInfo.fFlags & FormatInfo::kTransfers_Flag) {
+                            transferOffsetAlignment =
+                                    offset_alignment_for_transfer_buffer(ioInfo.fExternalType);
+                        }
                         if (ioInfo.fColorType == dstColorType) {
                             return {dstColorType, transferOffsetAlignment};
                         }
@@ -4328,6 +4360,10 @@
     GrColorType fallbackCT = GrColorType::kUnknown;
     const auto& formatInfo = this->getFormatInfo(surfaceFormat.asGLFormat());
     bool foundSurfaceCT = false;
+    size_t transferOffsetAlignment = 0;
+    if (formatInfo.fFlags & FormatInfo::kTransfers_Flag) {
+        transferOffsetAlignment = 1;
+    }
     for (int i = 0; !foundSurfaceCT && i < formatInfo.fColorTypeInfoCount; ++i) {
         if (formatInfo.fColorTypeInfos[i].fColorType == surfaceColorType) {
             const ColorTypeInfo& ctInfo = formatInfo.fColorTypeInfos[i];
@@ -4336,7 +4372,7 @@
                 const auto& ioInfo = ctInfo.fExternalIOFormats[j];
                 if (ioInfo.fExternalTexImageFormat != 0) {
                     if (ioInfo.fColorType == srcColorType) {
-                        return {srcColorType, 1};
+                        return {srcColorType, transferOffsetAlignment};
                     }
                     // Currently we just pick the first supported format that we find as our
                     // fallback.
@@ -4347,7 +4383,7 @@
             }
         }
     }
-    return {fallbackCT, 1};
+    return {fallbackCT, transferOffsetAlignment};
 }
 
 bool GrGLCaps::onIsWindowRectanglesSupportedForRT(const GrBackendRenderTarget& backendRT) const {
diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h
index 84cd3a5..7b11851 100644
--- a/src/gpu/gl/GrGLCaps.h
+++ b/src/gpu/gl/GrGLCaps.h
@@ -475,6 +475,7 @@
         bool fDisallowDirectRG8ReadPixels = false;
         bool fDisallowBGRA8ReadPixels = false;
         bool fDisallowR8ForPowerVRSGX54x = false;
+        bool fDisallowUnorm16Transfers = false;
     };
 
     void applyDriverCorrectnessWorkarounds(const GrGLContextInfo&, const GrContextOptions&,
@@ -673,12 +674,17 @@
         }
 
         enum {
-            kTexturable_Flag                 = 0x1,
+            kTexturable_Flag                 = 0x01,
             /** kFBOColorAttachment means that even if the format cannot be a GrRenderTarget, we can
                 still attach it to a FBO for blitting or reading pixels. */
-            kFBOColorAttachment_Flag         = 0x2,
-            kFBOColorAttachmentWithMSAA_Flag = 0x4,
-            kUseTexStorage_Flag              = 0x8,
+            kFBOColorAttachment_Flag         = 0x02,
+            kFBOColorAttachmentWithMSAA_Flag = 0x04,
+            kUseTexStorage_Flag              = 0x08,
+            /**
+             * Are pixel buffer objects supported in/out of this format? Ignored if PBOs are not
+             * supported at all.
+             */
+            kTransfers_Flag                  = 0x10,
         };
         uint32_t fFlags = 0;
 
diff --git a/src/gpu/gl/GrGLUtil.cpp b/src/gpu/gl/GrGLUtil.cpp
index 353a390..8d04068 100644
--- a/src/gpu/gl/GrGLUtil.cpp
+++ b/src/gpu/gl/GrGLUtil.cpp
@@ -369,6 +369,7 @@
 
 static std::tuple<GrGLDriver, GrGLDriverVersion> get_driver_and_version(GrGLStandard standard,
                                                                         GrGLVendor vendor,
+                                                                        const char* vendorString,
                                                                         const char* rendererString,
                                                                         const char* versionString) {
     SkASSERT(rendererString);
@@ -378,7 +379,10 @@
     GrGLDriverVersion driverVersion = GR_GL_DRIVER_UNKNOWN_VER;
 
     int major, minor, rev, driverMajor, driverMinor, driverPoint;
-    if (GR_IS_GR_GL(standard)) {
+    // This is the same on ES and regular GL.
+    if (!strcmp(vendorString, "freedreno")) {
+        driver = GrGLDriver::kFreedreno;
+    } else if (GR_IS_GR_GL(standard)) {
         if (vendor == GrGLVendor::kNVIDIA) {
             driver = GrGLDriver::kNVIDIA;
             int n = sscanf(versionString,
@@ -554,6 +558,7 @@
 
     auto [angleDriver, angleDriverVersion] = get_driver_and_version(kGLES_GrGLStandard,
                                                                     angleVendor,
+                                                                    angleVendorString,
                                                                     angleRendererString,
                                                                     angleVersionString);
 
@@ -629,10 +634,10 @@
         return reinterpret_cast<const char*>(bytes);
     };
 
-    const char* const version    = getString(GR_GL_VERSION);
-    const char* const slversion  = getString(GR_GL_SHADING_LANGUAGE_VERSION);
-    const char* const renderer   = getString(GR_GL_RENDERER);
-    const char* const vendor     = getString(GR_GL_VENDOR);
+    const char* const version   = getString(GR_GL_VERSION);
+    const char* const slversion = getString(GR_GL_SHADING_LANGUAGE_VERSION);
+    const char* const renderer  = getString(GR_GL_RENDERER);
+    const char* const vendor    = getString(GR_GL_VENDOR);
 
     info.fVersion     = GrGLGetVersionFromString(version);
     info.fGLSLVersion = get_glsl_version(slversion);
@@ -641,6 +646,7 @@
 
     std::tie(info.fDriver, info.fDriverVersion) = get_driver_and_version(interface->fStandard,
                                                                          info.fVendor,
+                                                                         vendor,
                                                                          renderer,
                                                                          version);
 
diff --git a/src/gpu/gl/GrGLUtil.h b/src/gpu/gl/GrGLUtil.h
index b6f7e37..0f6bb78 100644
--- a/src/gpu/gl/GrGLUtil.h
+++ b/src/gpu/gl/GrGLUtil.h
@@ -209,6 +209,7 @@
     kIntel,
     kSwiftShader,
     kQualcomm,
+    kFreedreno,
     kAndroidEmulator,
     kUnknown
 };
diff --git a/tests/TransferPixelsTest.cpp b/tests/TransferPixelsTest.cpp
index 03b96be..269e483 100644
--- a/tests/TransferPixelsTest.cpp
+++ b/tests/TransferPixelsTest.cpp
@@ -152,6 +152,9 @@
     // either of which may differ from 'colorType'.
     GrCaps::SupportedWrite allowedSrc =
             caps->supportedWritePixelsColorType(colorType, tex->backendFormat(), colorType);
+    if (!allowedSrc.fOffsetAlignmentForTransferBuffer) {
+        return;
+    }
     size_t srcRowBytes = GrAlignTo(GrColorTypeBytesPerPixel(allowedSrc.fColorType) * srcBufferWidth,
                                    caps->transferBufferAlignment());
 
@@ -331,6 +334,9 @@
     // Create the transfer buffer.
     auto allowedRead =
             caps->supportedReadPixelsColorType(colorType, tex->backendFormat(), colorType);
+    if (!allowedRead.fOffsetAlignmentForTransferBuffer) {
+        return;
+    }
     GrImageInfo readInfo(allowedRead.fColorType, kUnpremul_SkAlphaType, nullptr, kTexDims);
 
     size_t bpp = GrColorTypeBytesPerPixel(allowedRead.fColorType);