Add sample count to GrVkImageInfo.

Pre-req for allowing rendering to an externally created MSSA VkImage.


Bug: skia:9832

Cq-Include-Trybots: luci.skia.skia.primary:Test-Debian10-Clang-NUC7i5BNK-GPU-IntelIris640-x86_64-Release-All-Vulkan,Test-Win10-Clang-NUC8i5BEK-GPU-IntelIris655-x86_64-Release-All-Vulkan,Test-Win10-Clang-ShuttleA-GPU-RadeonHD7770-x86_64-Release-All-Vulkan,Test-Android-Clang-GalaxyS9-GPU-MaliG72-arm64-Release-All-Android_Vulkan,Test-Android-Clang-GalaxyS7_G930FD-GPU-MaliT880-arm64-Release-All-Android_Vulkan,Test-Android-Clang-GalaxyS20-GPU-MaliG77-arm64-Release-All-Android_Vulkan,Test-Android-Clang-Pixel4XL-GPU-Adreno640-arm64-Release-All-Android_Vulkan,Test-Android-Clang-P30-GPU-MaliG76-arm64-Release-All-Android_Vulkan
Change-Id: Ibf41944c6946dda7e27bdcd509ecd04976fc9ade
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/320262
Reviewed-by: Jim Van Verth <jvanverth@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt
index 2ec3c34..54e50a2 100644
--- a/RELEASE_NOTES.txt
+++ b/RELEASE_NOTES.txt
@@ -9,9 +9,17 @@
 
   * <insert new release notes here>
 
+  * GrVkImageInfo now has a field for sample count. GrBackendRenderTarget constructor
+    that took both a GrVkImageInfo and separate sample count is deprecated. Use the
+    version without sample count instead.
+
   * Added deprecation warning for Metal support on MacOS 10.13, iOS 8.3, and older.
     https://review.skia.org/320260
 
+  * GrVkImageInfo now has a field for sample count. GrBackendRenderTarget constructor
+    that took both a GrVkImageInfo and separate sample count is deprecated. Use the
+    version without sample count instead.
+
   * Update SkClipOp::kMax_EnumValue to include only intersect and difference when
     SK_SUPPORT_DEPRECATED_CLIPOPS is not defined.
     https://review.skia.org/320064
diff --git a/include/gpu/GrBackendSurface.h b/include/gpu/GrBackendSurface.h
index fa5141a..9fe6fc0 100644
--- a/include/gpu/GrBackendSurface.h
+++ b/include/gpu/GrBackendSurface.h
@@ -428,7 +428,10 @@
 #endif
 
 #ifdef SK_VULKAN
+    /** Deprecated. Sample count is now part of GrVkImageInfo. */
     GrBackendRenderTarget(int width, int height, int sampleCnt, const GrVkImageInfo& vkInfo);
+
+    GrBackendRenderTarget(int width, int height, const GrVkImageInfo& vkInfo);
 #endif
 
 #ifdef SK_METAL
@@ -530,7 +533,9 @@
 
 #ifdef SK_VULKAN
     friend class GrVkRenderTarget;
-    GrBackendRenderTarget(int width, int height, int sampleCnt, const GrVkImageInfo& vkInfo,
+    GrBackendRenderTarget(int width,
+                          int height,
+                          const GrVkImageInfo& vkInfo,
                           sk_sp<GrBackendSurfaceMutableStateImpl> mutableState);
 #endif
 
diff --git a/include/gpu/vk/GrVkTypes.h b/include/gpu/vk/GrVkTypes.h
index 300ff4d..954753b 100644
--- a/include/gpu/vk/GrVkTypes.h
+++ b/include/gpu/vk/GrVkTypes.h
@@ -102,6 +102,7 @@
     VkImageLayout            fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
     VkFormat                 fFormat = VK_FORMAT_UNDEFINED;
     VkImageUsageFlags        fImageUsageFlags = 0;
+    uint32_t                 fSampleCount = 1;
     uint32_t                 fLevelCount = 0;
     uint32_t                 fCurrentQueueFamily = VK_QUEUE_FAMILY_IGNORED;
     GrProtected              fProtected = GrProtected::kNo;
@@ -113,8 +114,9 @@
         return fImage == that.fImage && fAlloc == that.fAlloc &&
                fImageTiling == that.fImageTiling && fImageLayout == that.fImageLayout &&
                fFormat == that.fFormat && fImageUsageFlags == that.fImageUsageFlags &&
-               fLevelCount == that.fLevelCount && fCurrentQueueFamily == that.fCurrentQueueFamily &&
-               fProtected == that.fProtected && fYcbcrConversionInfo == that.fYcbcrConversionInfo &&
+               fSampleCount == that.fSampleCount && fLevelCount == that.fLevelCount &&
+               fCurrentQueueFamily == that.fCurrentQueueFamily && fProtected == that.fProtected &&
+               fYcbcrConversionInfo == that.fYcbcrConversionInfo &&
                fSharingMode == that.fSharingMode;
     }
 #endif
diff --git a/src/gpu/GrBackendSurface.cpp b/src/gpu/GrBackendSurface.cpp
index 28bcdd8..22d2f23 100644
--- a/src/gpu/GrBackendSurface.cpp
+++ b/src/gpu/GrBackendSurface.cpp
@@ -852,32 +852,43 @@
 #endif
 
 #ifdef SK_VULKAN
+static GrVkImageInfo resolve_vkii_sample_count(const GrVkImageInfo& vkII, int sidebandSampleCnt) {
+    auto result = vkII;
+    result.fSampleCount = std::max({vkII.fSampleCount,
+                                    static_cast<uint32_t>(sidebandSampleCnt),
+                                    1U});
+    return result;
+}
+
 GrBackendRenderTarget::GrBackendRenderTarget(int width,
                                              int height,
                                              int sampleCnt,
                                              const GrVkImageInfo& vkInfo)
-        : GrBackendRenderTarget(width, height, sampleCnt, vkInfo,
+        : GrBackendRenderTarget(width, height, resolve_vkii_sample_count(vkInfo, sampleCnt)) {}
+
+GrBackendRenderTarget::GrBackendRenderTarget(int width,
+                                             int height,
+                                             const GrVkImageInfo& vkInfo)
+        : GrBackendRenderTarget(width, height, vkInfo,
                                 sk_sp<GrBackendSurfaceMutableStateImpl>(
                                         new GrBackendSurfaceMutableStateImpl(
-                                               vkInfo.fImageLayout, vkInfo.fCurrentQueueFamily))) {}
+                                                vkInfo.fImageLayout, vkInfo.fCurrentQueueFamily))) {}
 
 static const VkImageUsageFlags kDefaultRTUsageFlags =
         kDefaultUsageFlags | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
 
 GrBackendRenderTarget::GrBackendRenderTarget(int width,
                                              int height,
-                                             int sampleCnt,
                                              const GrVkImageInfo& vkInfo,
                                              sk_sp<GrBackendSurfaceMutableStateImpl> mutableState)
         : fIsValid(true)
         , fWidth(width)
         , fHeight(height)
-        , fSampleCnt(std::max(1, sampleCnt))
+        , fSampleCnt(std::max(1U, vkInfo.fSampleCount))
         , fStencilBits(0)  // We always create stencil buffers internally for vulkan
         , fBackend(GrBackendApi::kVulkan)
         , fVkInfo(apply_default_usage_flags(vkInfo, kDefaultRTUsageFlags))
-        , fMutableState(mutableState) {
-}
+        , fMutableState(mutableState) {}
 #endif
 
 #ifdef SK_METAL
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index 642acad..a5ec36a 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -1246,6 +1246,11 @@
 }
 
 static bool check_tex_image_info(const GrVkCaps& caps, const GrVkImageInfo& info) {
+    // We don't support directly importing multisampled textures for sampling from shaders.
+    if (info.fSampleCount != 1) {
+        return false;
+    }
+
     if (info.fYcbcrConversionInfo.isValid() && info.fYcbcrConversionInfo.fExternalFormat != 0) {
         return true;
     }
@@ -1268,12 +1273,11 @@
     return true;
 }
 
-static bool check_rt_image_info(const GrVkCaps& caps, const GrVkImageInfo& info, int sampleCnt) {
-    if (!caps.isFormatRenderable(info.fFormat, sampleCnt)) {
+static bool check_rt_image_info(const GrVkCaps& caps, const GrVkImageInfo& info, bool resolveOnly) {
+    if (!caps.isFormatRenderable(info.fFormat, info.fSampleCount)) {
         return false;
     }
-    // We currently require all render targets to be made with color attachment support
-    if (!SkToBool(info.fImageUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)) {
+    if (!resolveOnly && !SkToBool(info.fImageUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)) {
         return false;
     }
     return true;
@@ -1330,7 +1334,10 @@
     if (!check_tex_image_info(this->vkCaps(), imageInfo)) {
         return nullptr;
     }
-    if (!check_rt_image_info(this->vkCaps(), imageInfo, sampleCnt)) {
+    // If sampleCnt is > 1 we will create an intermediate MSAA VkImage and then resolve into
+    // the wrapped VkImage.
+    bool resolveOnly = sampleCnt > 1;
+    if (!check_rt_image_info(this->vkCaps(), imageInfo, resolveOnly)) {
         return nullptr;
     }
 
@@ -1367,7 +1374,9 @@
         return nullptr;
     }
 
-    if (!check_rt_image_info(this->vkCaps(), info, backendRT.sampleCnt())) {
+    // We will always render directly to this VkImage.
+    static bool kResolveOnly = false;
+    if (!check_rt_image_info(this->vkCaps(), info, kResolveOnly)) {
         return nullptr;
     }
 
@@ -1379,7 +1388,7 @@
     SkASSERT(mutableState);
 
     sk_sp<GrVkRenderTarget> tgt = GrVkRenderTarget::MakeWrappedRenderTarget(
-            this, backendRT.dimensions(), 1, info, std::move(mutableState));
+            this, backendRT.dimensions(), backendRT.sampleCnt(), info, std::move(mutableState));
 
     // We don't allow the client to supply a premade stencil buffer. We always create one if needed.
     SkASSERT(!backendRT.stencilBits());
@@ -1399,8 +1408,15 @@
     if (!check_image_info(this->vkCaps(), imageInfo, false, this->queueIndex())) {
         return nullptr;
     }
+    // See comment below about intermediate MSAA buffer.
+    if (imageInfo.fSampleCount > 1) {
+        return nullptr;
+    }
 
-    if (!check_rt_image_info(this->vkCaps(), imageInfo, sampleCnt)) {
+    // If sampleCnt is > 1 we will create an intermediate MSAA VkImage and then resolve into
+    // the wrapped VkImage.
+    bool resolveOnly = sampleCnt > 1;
+    if (!check_rt_image_info(this->vkCaps(), imageInfo, resolveOnly)) {
         return nullptr;
     }
 
diff --git a/src/gpu/vk/GrVkRenderTarget.cpp b/src/gpu/vk/GrVkRenderTarget.cpp
index c2c396b..ea23573 100644
--- a/src/gpu/vk/GrVkRenderTarget.cpp
+++ b/src/gpu/vk/GrVkRenderTarget.cpp
@@ -528,8 +528,7 @@
 
 GrBackendRenderTarget GrVkRenderTarget::getBackendRenderTarget() const {
     SkASSERT(!this->wrapsSecondaryCommandBuffer());
-    return GrBackendRenderTarget(this->width(), this->height(), this->numSamples(), fInfo,
-                                 this->getMutableState());
+    return GrBackendRenderTarget(this->width(), this->height(), fInfo, this->getMutableState());
 }
 
 const GrManagedResource* GrVkRenderTarget::stencilImageResource() const {
diff --git a/tests/VkWrapTests.cpp b/tests/VkWrapTests.cpp
index 98353ef..24085a4 100644
--- a/tests/VkWrapTests.cpp
+++ b/tests/VkWrapTests.cpp
@@ -83,6 +83,19 @@
 
         REPORTER_ASSERT(reporter, tex);
     }
+
+    // image has MSAA
+    {
+        GrVkImageInfo backendCopy = imageInfo;
+        backendCopy.fSampleCount = 4;
+        GrBackendTexture backendTex = GrBackendTexture(kW, kH, backendCopy);
+        tex = gpu->wrapBackendTexture(backendTex, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo,
+                                      kRead_GrIOType);
+        REPORTER_ASSERT(reporter, !tex);
+        tex = gpu->wrapBackendTexture(backendTex, kAdopt_GrWrapOwnership, GrWrapCacheable::kNo,
+                                      kRead_GrIOType);
+        REPORTER_ASSERT(reporter, !tex);
+    }
 }
 
 void wrap_rt_test(skiatest::Reporter* reporter, GrDirectContext* dContext) {
@@ -119,6 +132,15 @@
         REPORTER_ASSERT(reporter, rt);
     }
 
+    // Image has MSAA
+    {
+        GrVkImageInfo backendCopy = imageInfo;
+        backendCopy.fSampleCount = 4;
+        GrBackendRenderTarget backendRT(kW, kH, backendCopy);
+        rt = gpu->wrapBackendRenderTarget(backendRT);
+        REPORTER_ASSERT(reporter, !rt);
+    }
+
     // When we wrapBackendRenderTarget it is always borrowed, so we must make sure to free the
     // resource when we're done.
     dContext->deleteBackendTexture(origBackendTex);
@@ -172,6 +194,26 @@
                                                 GrWrapCacheable::kNo);
         REPORTER_ASSERT(reporter, tex);
     }
+
+    // check rendering with MSAA
+    {
+        int maxSamples = dContext->priv().caps()->maxRenderTargetSampleCount(
+                origBackendTex.getBackendFormat());
+        bool shouldSucceed = maxSamples > 1;
+        tex = gpu->wrapRenderableBackendTexture(origBackendTex, 2, kBorrow_GrWrapOwnership,
+                                                GrWrapCacheable::kNo);
+        REPORTER_ASSERT(reporter, SkToBool(tex) == shouldSucceed);
+    }
+
+    // Image has MSAA
+    {
+        GrVkImageInfo backendCopy = imageInfo;
+        backendCopy.fSampleCount = 4;
+        GrBackendTexture backendTex = GrBackendTexture(kW, kH, backendCopy);
+        tex = gpu->wrapRenderableBackendTexture(backendTex, 1, kAdopt_GrWrapOwnership,
+                                                GrWrapCacheable::kNo);
+        REPORTER_ASSERT(reporter, !tex);
+    }
 }
 
 DEF_GPUTEST_FOR_VULKAN_CONTEXT(VkWrapTests, reporter, ctxInfo) {
diff --git a/tools/gpu/vk/VkYcbcrSamplerHelper.cpp b/tools/gpu/vk/VkYcbcrSamplerHelper.cpp
index de8d0d1..f083245 100644
--- a/tools/gpu/vk/VkYcbcrSamplerHelper.cpp
+++ b/tools/gpu/vk/VkYcbcrSamplerHelper.cpp
@@ -196,6 +196,7 @@
                                VK_IMAGE_LAYOUT_UNDEFINED,
                                vkImageInfo.format,
                                vkImageInfo.usage,
+                               1 /* sample count */,
                                1 /* levelCount */,
                                VK_QUEUE_FAMILY_IGNORED,
                                GrProtected::kNo,