Reduce use of GrPixelConfig inside of GrVkCaps.

This change removes all internal uses of GrPixelConfig in GrVkCaps, besides
translation of GrPixelConfig in overriden methods, as well as for swizzles
which actually live in shader caps.

Bug: skia:6718
Change-Id: I7a8bf03c9e6a7ed75a74862cb4c99cf610976fe8
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/213641
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Greg Daniel <egdaniel@google.com>
diff --git a/src/gpu/vk/GrVkCaps.cpp b/src/gpu/vk/GrVkCaps.cpp
index bbcd688..7a50e1e 100644
--- a/src/gpu/vk/GrVkCaps.cpp
+++ b/src/gpu/vk/GrVkCaps.cpp
@@ -144,10 +144,15 @@
 bool GrVkCaps::canCopyAsBlit(GrPixelConfig dstConfig, int dstSampleCnt, bool dstIsLinear,
                              bool dstHasYcbcr, GrPixelConfig srcConfig, int srcSampleCnt,
                              bool srcIsLinear, bool srcHasYcbcr) const {
+
+    VkFormat dstFormat;
+    SkAssertResult(GrPixelConfigToVkFormat(dstConfig, &dstFormat));
+    VkFormat srcFormat;
+    SkAssertResult(GrPixelConfigToVkFormat(srcConfig, &srcFormat));
     // We require that all vulkan GrSurfaces have been created with transfer_dst and transfer_src
     // as image usage flags.
-    if (!this->configCanBeDstofBlit(dstConfig, dstIsLinear) ||
-        !this->configCanBeSrcofBlit(srcConfig, srcIsLinear)) {
+    if (!this->formatCanBeDstofBlit(dstFormat, dstIsLinear) ||
+        !this->formatCanBeSrcofBlit(srcFormat, srcIsLinear)) {
         return false;
     }
 
@@ -433,7 +438,7 @@
         fPreferTrianglesOverSampleMask = true;
     }
 
-    this->initConfigTable(vkInterface, physDev, properties);
+    this->initFormatTable(vkInterface, physDev, properties);
     this->initStencilFormat(vkInterface, physDev);
 
     if (!contextOptions.fDisableDriverCorrectnessWorkarounds) {
@@ -688,33 +693,85 @@
     }
 }
 
-void GrVkCaps::initConfigTable(const GrVkInterface* interface, VkPhysicalDevice physDev,
+static bool format_is_srgb(VkFormat format) {
+    switch (format) {
+        case VK_FORMAT_R8G8B8A8_SRGB:
+        case VK_FORMAT_B8G8R8A8_SRGB:
+            return true;
+        case VK_FORMAT_R8G8B8A8_UNORM:
+        case VK_FORMAT_B8G8R8A8_UNORM:
+        case VK_FORMAT_R8G8B8A8_SINT:
+        case VK_FORMAT_R8G8B8_UNORM:
+        case VK_FORMAT_R8G8_UNORM:
+        case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
+        case VK_FORMAT_R5G6B5_UNORM_PACK16:
+        case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
+        case VK_FORMAT_R8_UNORM:
+        case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
+        case VK_FORMAT_R32G32B32A32_SFLOAT:
+        case VK_FORMAT_R32G32_SFLOAT:
+        case VK_FORMAT_R16G16B16A16_SFLOAT:
+        case VK_FORMAT_R16_SFLOAT:
+            return false;
+        default:
+            SK_ABORT("Unsupported VkFormat");
+            return false;
+    }
+}
+
+// These are all the valid VkFormats that we support in Skia. They are roughly order from most
+// frequently used to least to improve look up times in arrays.
+static constexpr VkFormat kVkFormats[] = {
+    VK_FORMAT_R8G8B8A8_UNORM,
+    VK_FORMAT_R8_UNORM,
+    VK_FORMAT_B8G8R8A8_UNORM,
+    VK_FORMAT_R5G6B5_UNORM_PACK16,
+    VK_FORMAT_R16G16B16A16_SFLOAT,
+    VK_FORMAT_R16_SFLOAT,
+    VK_FORMAT_R8G8B8A8_SINT,
+    VK_FORMAT_R8G8B8_UNORM,
+    VK_FORMAT_R8G8_UNORM,
+    VK_FORMAT_A2B10G10R10_UNORM_PACK32,
+    VK_FORMAT_B4G4R4A4_UNORM_PACK16,
+    VK_FORMAT_R32G32B32A32_SFLOAT,
+    VK_FORMAT_R32G32_SFLOAT,
+    VK_FORMAT_R8G8B8A8_SRGB,
+    VK_FORMAT_B8G8R8A8_SRGB,
+    VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK
+};
+
+const GrVkCaps::FormatInfo& GrVkCaps::getFormatInfo(VkFormat format) const {
+    static_assert(SK_ARRAY_COUNT(kVkFormats) == GrVkCaps::kNumVkFormats,
+                  "Size of VkFormats array must match static value in header");
+    for (size_t i = 0; i < SK_ARRAY_COUNT(kVkFormats); ++i) {
+        if (kVkFormats[i] == format) {
+            return fFormatTable[i];
+        }
+    }
+    SK_ABORT("Invalid VkFormat");
+    static const FormatInfo kInvalidConfig;
+    return kInvalidConfig;
+}
+
+void GrVkCaps::initFormatTable(const GrVkInterface* interface, VkPhysicalDevice physDev,
                                const VkPhysicalDeviceProperties& properties) {
-    for (int i = 0; i < kGrPixelConfigCnt; ++i) {
-        VkFormat format;
-        if (GrPixelConfigToVkFormat(static_cast<GrPixelConfig>(i), &format)) {
-            if (!GrPixelConfigIsSRGB(static_cast<GrPixelConfig>(i)) || fSRGBSupport) {
-                bool disableRendering = false;
-                if (static_cast<GrPixelConfig>(i) == kRGB_888X_GrPixelConfig) {
-                    // Currently we don't allow RGB_888X to be renderable because we don't have a
-                    // way to handle blends that reference dst alpha when the values in the dst
-                    // alpha channel are uninitialized.
-                    disableRendering = true;
-                }
-                fConfigTable[i].init(interface, physDev, properties, format, disableRendering);
-            }
+    static_assert(SK_ARRAY_COUNT(kVkFormats) == GrVkCaps::kNumVkFormats,
+                  "Size of VkFormats array must match static value in header");
+    for (size_t i = 0; i < SK_ARRAY_COUNT(kVkFormats); ++i) {
+        VkFormat format = kVkFormats[i];
+        if (!format_is_srgb(format) || fSRGBSupport) {
+            fFormatTable[i].init(interface, physDev, properties, format);
         }
     }
 }
 
-void GrVkCaps::ConfigInfo::InitConfigFlags(VkFormatFeatureFlags vkFlags, uint16_t* flags,
-                                           bool disableRendering) {
+void GrVkCaps::FormatInfo::InitConfigFlags(VkFormatFeatureFlags vkFlags, uint16_t* flags) {
     if (SkToBool(VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT & vkFlags) &&
         SkToBool(VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT & vkFlags)) {
         *flags = *flags | kTextureable_Flag;
 
         // Ganesh assumes that all renderable surfaces are also texturable
-        if (SkToBool(VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT & vkFlags) & !disableRendering) {
+        if (SkToBool(VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT & vkFlags)) {
             *flags = *flags | kRenderable_Flag;
         }
     }
@@ -728,7 +785,7 @@
     }
 }
 
-void GrVkCaps::ConfigInfo::initSampleCounts(const GrVkInterface* interface,
+void GrVkCaps::FormatInfo::initSampleCounts(const GrVkInterface* interface,
                                             VkPhysicalDevice physDev,
                                             const VkPhysicalDeviceProperties& physProps,
                                             VkFormat format) {
@@ -772,45 +829,94 @@
     }
 }
 
-void GrVkCaps::ConfigInfo::init(const GrVkInterface* interface,
+void GrVkCaps::FormatInfo::init(const GrVkInterface* interface,
                                 VkPhysicalDevice physDev,
                                 const VkPhysicalDeviceProperties& properties,
-                                VkFormat format,
-                                bool disableRendering) {
+                                VkFormat format) {
     VkFormatProperties props;
     memset(&props, 0, sizeof(VkFormatProperties));
     GR_VK_CALL(interface, GetPhysicalDeviceFormatProperties(physDev, format, &props));
-    InitConfigFlags(props.linearTilingFeatures, &fLinearFlags, disableRendering);
-    InitConfigFlags(props.optimalTilingFeatures, &fOptimalFlags, disableRendering);
+    InitConfigFlags(props.linearTilingFeatures, &fLinearFlags);
+    InitConfigFlags(props.optimalTilingFeatures, &fOptimalFlags);
     if (fOptimalFlags & kRenderable_Flag) {
         this->initSampleCounts(interface, physDev, properties, format);
     }
 }
 
+bool GrVkCaps::isConfigTexturable(VkFormat format) const {
+    if (!GrVkFormatIsSupported(format)) {
+        return false;
+    }
+
+    const FormatInfo& info = this->getFormatInfo(format);
+    return SkToBool(FormatInfo::kTextureable_Flag & info.fOptimalFlags);
+}
+
+bool GrVkCaps::isConfigTexturable(GrPixelConfig config) const {
+    VkFormat format;
+    if (!GrPixelConfigToVkFormat(config, &format)) {
+        return false;
+    }
+    return this->isConfigTexturable(format);
+}
+
 int GrVkCaps::getRenderTargetSampleCount(int requestedCount, GrPixelConfig config) const {
+    // Currently we don't allow RGB_888X to be renderable because we don't have a way to handle
+    // blends that reference dst alpha when the values in the dst alpha channel are uninitialized.
+    if (config == kRGB_888X_GrPixelConfig) {
+        return 0;
+    }
+
+    VkFormat format;
+    if (!GrPixelConfigToVkFormat(config, &format)) {
+        return 0;
+    }
+
+    return this->getRenderTargetSampleCount(requestedCount, format);
+}
+
+int GrVkCaps::getRenderTargetSampleCount(int requestedCount, VkFormat format) const {
     requestedCount = SkTMax(1, requestedCount);
-    int count = fConfigTable[config].fColorSampleCounts.count();
+
+    const FormatInfo& info = this->getFormatInfo(format);
+
+    int count = info.fColorSampleCounts.count();
 
     if (!count) {
         return 0;
     }
 
     if (1 == requestedCount) {
-        SkASSERT(fConfigTable[config].fColorSampleCounts.count() &&
-                 fConfigTable[config].fColorSampleCounts[0] == 1);
+        SkASSERT(info.fColorSampleCounts.count() && info.fColorSampleCounts[0] == 1);
         return 1;
     }
 
     for (int i = 0; i < count; ++i) {
-        if (fConfigTable[config].fColorSampleCounts[i] >= requestedCount) {
-            return fConfigTable[config].fColorSampleCounts[i];
+        if (info.fColorSampleCounts[i] >= requestedCount) {
+            return info.fColorSampleCounts[i];
         }
     }
     return 0;
 }
 
 int GrVkCaps::maxRenderTargetSampleCount(GrPixelConfig config) const {
-    const auto& table = fConfigTable[config].fColorSampleCounts;
+    // Currently we don't allow RGB_888X to be renderable because we don't have a way to handle
+    // blends that reference dst alpha when the values in the dst alpha channel are uninitialized.
+    if (config == kRGB_888X_GrPixelConfig) {
+        return 0;
+    }
+
+    VkFormat format;
+    if (!GrPixelConfigToVkFormat(config, &format)) {
+        return 0;
+    }
+    return this->maxRenderTargetSampleCount(format);
+}
+
+int GrVkCaps::maxRenderTargetSampleCount(VkFormat format) const {
+    const FormatInfo& info = this->getFormatInfo(format);
+
+    const auto& table = info.fColorSampleCounts;
     if (!table.count()) {
         return 0;
     }
diff --git a/src/gpu/vk/GrVkCaps.h b/src/gpu/vk/GrVkCaps.h
index c7f501c..7a4656d 100644
--- a/src/gpu/vk/GrVkCaps.h
+++ b/src/gpu/vk/GrVkCaps.h
@@ -32,38 +32,34 @@
              uint32_t instanceVersion, uint32_t physicalDeviceVersion,
              const GrVkExtensions& extensions);
 
-    bool isConfigTexturable(GrPixelConfig config) const override {
-        return SkToBool(ConfigInfo::kTextureable_Flag & fConfigTable[config].fOptimalFlags);
-    }
+    bool isConfigTexturable(VkFormat) const;
+    bool isConfigTexturable(GrPixelConfig config) const override;
 
     bool isConfigCopyable(GrPixelConfig config) const override {
         return true;
     }
 
     int getRenderTargetSampleCount(int requestedCount, GrPixelConfig config) const override;
+    int getRenderTargetSampleCount(int requestedCount, VkFormat) const;
     int maxRenderTargetSampleCount(GrPixelConfig config) const override;
+    int maxRenderTargetSampleCount(VkFormat format) const;
 
     bool surfaceSupportsReadPixels(const GrSurface*) const override;
 
-    bool isConfigTexturableLinearly(GrPixelConfig config) const {
-        return SkToBool(ConfigInfo::kTextureable_Flag & fConfigTable[config].fLinearFlags);
+    bool isConfigTexturableLinearly(VkFormat format) const {
+        return SkToBool(FormatInfo::kTextureable_Flag & this->getFormatInfo(format).fLinearFlags);
     }
 
-    bool isConfigRenderableLinearly(GrPixelConfig config, bool withMSAA) const {
-        return !withMSAA && SkToBool(ConfigInfo::kRenderable_Flag &
-                                     fConfigTable[config].fLinearFlags);
+    bool formatCanBeDstofBlit(VkFormat format, bool linearTiled) const {
+        const FormatInfo& info = this->getFormatInfo(format);
+        const uint16_t& flags = linearTiled ? info.fLinearFlags : info.fOptimalFlags;
+        return SkToBool(FormatInfo::kBlitDst_Flag & flags);
     }
 
-    bool configCanBeDstofBlit(GrPixelConfig config, bool linearTiled) const {
-        const uint16_t& flags = linearTiled ? fConfigTable[config].fLinearFlags :
-                                              fConfigTable[config].fOptimalFlags;
-        return SkToBool(ConfigInfo::kBlitDst_Flag & flags);
-    }
-
-    bool configCanBeSrcofBlit(GrPixelConfig config, bool linearTiled) const {
-        const uint16_t& flags = linearTiled ? fConfigTable[config].fLinearFlags :
-                                              fConfigTable[config].fOptimalFlags;
-        return SkToBool(ConfigInfo::kBlitSrc_Flag & flags);
+    bool formatCanBeSrcofBlit(VkFormat format, bool linearTiled) const {
+        const FormatInfo& info = this->getFormatInfo(format);
+        const uint16_t& flags = linearTiled ? info.fLinearFlags : info.fOptimalFlags;
+        return SkToBool(FormatInfo::kBlitSrc_Flag & flags);
     }
 
     // On Adreno vulkan, they do not respect the imageOffset parameter at least in
@@ -189,7 +185,7 @@
                     const GrVkExtensions&);
     void initShaderCaps(const VkPhysicalDeviceProperties&, const VkPhysicalDeviceFeatures2&);
 
-    void initConfigTable(const GrVkInterface*, VkPhysicalDevice, const VkPhysicalDeviceProperties&);
+    void initFormatTable(const GrVkInterface*, VkPhysicalDevice, const VkPhysicalDeviceProperties&);
     void initStencilFormat(const GrVkInterface* iface, VkPhysicalDevice physDev);
 
     uint8_t getYcbcrKeyFromYcbcrInfo(const GrVkYcbcrConversionInfo& info);
@@ -201,12 +197,12 @@
                           const SkIRect& srcRect, const SkIPoint& dstPoint) const override;
     size_t onTransferFromOffsetAlignment(GrColorType bufferColorType) const override;
 
-    struct ConfigInfo {
-        ConfigInfo() : fOptimalFlags(0), fLinearFlags(0) {}
+    struct FormatInfo {
+        FormatInfo() : fOptimalFlags(0), fLinearFlags(0) {}
 
         void init(const GrVkInterface*, VkPhysicalDevice, const VkPhysicalDeviceProperties&,
-                  VkFormat, bool disableRendering);
-        static void InitConfigFlags(VkFormatFeatureFlags, uint16_t* flags, bool disableRendering);
+                  VkFormat);
+        static void InitConfigFlags(VkFormatFeatureFlags, uint16_t* flags);
         void initSampleCounts(const GrVkInterface*, VkPhysicalDevice,
                               const VkPhysicalDeviceProperties&, VkFormat);
 
@@ -222,7 +218,10 @@
 
         SkTDArray<int> fColorSampleCounts;
     };
-    ConfigInfo fConfigTable[kGrPixelConfigCnt];
+    static const size_t kNumVkFormats = 16;
+    FormatInfo fFormatTable[kNumVkFormats];
+
+    const FormatInfo& getFormatInfo(VkFormat) const;
 
     StencilFormat fPreferredStencilFormat;
 
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index 1e04813..5bc05df 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -717,7 +717,7 @@
         SkASSERT(tex->config() == kRGB_888_GrPixelConfig);
         // First check that we'll be able to do the copy to the to the R8G8B8 image in the end via a
         // blit or draw.
-        if (!this->vkCaps().configCanBeDstofBlit(kRGB_888_GrPixelConfig, tex->isLinearTiled()) &&
+        if (!this->vkCaps().formatCanBeDstofBlit(VK_FORMAT_R8G8B8_UNORM, tex->isLinearTiled()) &&
             !this->vkCaps().maxRenderTargetSampleCount(kRGB_888_GrPixelConfig)) {
             return false;
         }
@@ -1159,6 +1159,27 @@
     return true;
 }
 
+static bool check_tex_image_info(const GrVkCaps& caps, const GrVkImageInfo& info) {
+    if (info.fImageTiling == VK_IMAGE_TILING_OPTIMAL) {
+        if (!caps.isConfigTexturable(info.fFormat)) {
+            return false;
+        }
+    } else {
+        SkASSERT(info.fImageTiling == VK_IMAGE_TILING_LINEAR);
+        if (!caps.isConfigTexturableLinearly(info.fFormat)) {
+            return false;
+        }
+    }
+    return true;
+}
+
+static bool check_rt_image_info(const GrVkCaps& caps, const GrVkImageInfo& info) {
+    if (!caps.maxRenderTargetSampleCount(info.fFormat)) {
+        return false;
+    }
+    return true;
+}
+
 sk_sp<GrTexture> GrVkGpu::onWrapBackendTexture(const GrBackendTexture& backendTex,
                                                GrWrapOwnership ownership, GrWrapCacheable cacheable,
                                                GrIOType ioType) {
@@ -1170,6 +1191,9 @@
     if (!check_image_info(this->vkCaps(), imageInfo, backendTex.config(), false)) {
         return nullptr;
     }
+    if (!check_tex_image_info(this->vkCaps(), imageInfo)) {
+        return nullptr;
+    }
 
     GrSurfaceDesc surfDesc;
     surfDesc.fFlags = kNone_GrSurfaceFlags;
@@ -1196,6 +1220,12 @@
     if (!check_image_info(this->vkCaps(), imageInfo, backendTex.config(), false)) {
         return nullptr;
     }
+    if (!check_tex_image_info(this->vkCaps(), imageInfo)) {
+        return nullptr;
+    }
+    if (!check_rt_image_info(this->vkCaps(), imageInfo)) {
+        return nullptr;
+    }
 
     GrSurfaceDesc surfDesc;
     surfDesc.fFlags = kRenderTarget_GrSurfaceFlag;
@@ -1228,6 +1258,10 @@
     if (!check_image_info(this->vkCaps(), info, backendRT.config(), true)) {
         return nullptr;
     }
+    if (!check_rt_image_info(this->vkCaps(), info)) {
+        return nullptr;
+    }
+
 
     GrSurfaceDesc desc;
     desc.fFlags = kRenderTarget_GrSurfaceFlag;
@@ -1260,7 +1294,9 @@
     if (!check_image_info(this->vkCaps(), imageInfo, tex.config(), false)) {
         return nullptr;
     }
-
+    if (!check_rt_image_info(this->vkCaps(), imageInfo)) {
+        return nullptr;
+    }
 
     GrSurfaceDesc desc;
     desc.fFlags = kRenderTarget_GrSurfaceFlag;
@@ -1318,8 +1354,8 @@
 
     // determine if we can blit to and from this format
     const GrVkCaps& caps = this->vkCaps();
-    if (!caps.configCanBeDstofBlit(tex->config(), false) ||
-        !caps.configCanBeSrcofBlit(tex->config(), false) ||
+    if (!caps.formatCanBeDstofBlit(vkTex->imageFormat(), false) ||
+        !caps.formatCanBeSrcofBlit(vkTex->imageFormat(), false) ||
         !caps.mipMapSupport()) {
         return false;
     }