[bazel] GaneshVulkanSurfaceManager.cpp: Implement.

This CL defines Vulkan configurations that mimic the DM/nanobench configurations defined in //tools/flags/CommonFlagsConfig.cpp[1]. The only exceptions are vkddl and vktestpersistentcache, which use the GPUDDLSink[2] and GPUPersistentCacheTestingSink[3] GM sinks, respectively. All other configs use the "vanilla" GPUSink[4]. Under BazelGMTestRunner, we currently do not support sinks, but I believe the behaviors in GPUDDLSink and GPUPersistentCacheTestingSink can be implemented as vias. We should discuss this.

One important observation is that GaneshVulkanSurfaceManager.cpp does not currently depend on any Vulkan-specific code or imports. Aside from the "vk*" configurations, it is virtually identical to GaneshGLSurfaceManager.cpp. This suggests it could be possible to merge them and have just one single GaneshSurfaceManager.cpp. We should consider this in the future after things are more settled.

Unlike GaneshGLSurfaceManager.cpp, I decided to have makeVulkanSurfaceManager() take all configuration options as arguments from the get-go, even though some options are always the same across configs. This makes it easy to quickly see all the "ingredients" that go into making a surface, at the expense of slightly more verbose config definitions. I think this is the right tradeoff. In a follow-up CL (https://skia-review.googlesource.com/c/skia/+/811244) I'll rewrite GaneshGLSurfaceManager.cpp's makeGLESSurfaceManager() function to be like makeVulkanSurfaceManager().

This CL also defines one GM and benchmark test for each configuration. I was able to test these targets on my workstation with Bazel invocations such as:

    $ bazel test \
          --config=linux_rbe \
          --config=vulkan_ganesh \
          --nocache_test_results --test_output=streamed \
          --strategy=TestRunner=local \
          --test_env=DISPLAY=:20 \
          --test_env=XDG_RUNTIME_DIR \
          //gm:gpu_vk_test

    $ bazel test \
          --config=linux_rbe \
          --config=vulkan_ganesh \
          --strategy=TestRunner=local \
          --nocache_test_results \
          --test_output=streamed \
          --test_env=DISPLAY=:20 \
          --test_env=XDG_RUNTIME_DIR \
          //bench:gpu_vk_test

[1] https://skia.googlesource.com/skia/+/8da85ea79d1ba2b3f32d25178eb21f2ebda83437/tools/flags/CommonFlagsConfig.cpp#103

[2] https://skia.googlesource.com/skia/+/8da85ea79d1ba2b3f32d25178eb21f2ebda83437/dm/DMSrcSink.h#475

[3] https://skia.googlesource.com/skia/+/8da85ea79d1ba2b3f32d25178eb21f2ebda83437/dm/DMSrcSink.h#435

[4] https://skia.googlesource.com/skia/+/8da85ea79d1ba2b3f32d25178eb21f2ebda83437/dm/DMSrcSink.h#367

Bug: b/40045301
Change-Id: Ia60b759efce61e6c05120579f430a6566d7cec59
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/811033
Reviewed-by: Kevin Lubick <kjlubick@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Leandro Lovisolo <lovisolo@google.com>
diff --git a/bench/BUILD.bazel b/bench/BUILD.bazel
index 0d95d16..0f06821 100644
--- a/bench/BUILD.bazel
+++ b/bench/BUILD.bazel
@@ -71,6 +71,58 @@
     deps = [":benchmarks_base"],
 )
 
+# Vulkan benchmarks.
+[
+    cc_test_with_flags(
+        name = name,
+        srcs = [
+            "GradientBench.cpp",
+            "TextBlobBench.cpp",
+        ],
+        args = [
+            "--surfaceConfig",
+            surfaceConfig,
+            "--autoTuneLoops",
+        ],
+        set_flags = {
+            "include_encoder": [
+                "png_encode_codec",
+            ],
+        },
+        deps = [":benchmarks_base"],
+    )
+    for name, surfaceConfig in [
+        [
+            "ganesh_vk_test",
+            "vk",
+        ],
+        [
+            "ganesh_vk_1010102_test",
+            "vk_1010102",
+        ],
+        [
+            "ganesh_vk_msaa4_test",
+            "vk_msaa4",
+        ],
+        [
+            "ganesh_vk_msaa8_test",
+            "vk_msaa8",
+        ],
+        [
+            "ganesh_vk_dmsaa_test",
+            "vk_dmsaa",
+        ],
+        [
+            "ganesh_vk_betex_test",
+            "vk_betex",
+        ],
+        [
+            "ganesh_vk_bert_test",
+            "vk_bert",
+        ],
+    ]
+]
+
 cc_test_with_flags(
     name = "gpu_gles_test",
     srcs = [
diff --git a/gm/BUILD.bazel b/gm/BUILD.bazel
index 1ad8a1f..23f6639 100644
--- a/gm/BUILD.bazel
+++ b/gm/BUILD.bazel
@@ -605,6 +605,59 @@
     ],
 )
 
+# Vulkan GMs.
+[
+    cc_test_with_flags(
+        name = name,
+        srcs = GPU_GMS,
+        args = [
+            "--surfaceConfig",
+            surfaceConfig,
+        ],
+        data = ["//resources"],
+        set_flags = {
+            "include_decoder": [
+                "gif_decode_codec",
+                "webp_decode_codec",
+            ],
+        },
+        deps = [
+            ":tests_base",
+            "//tools/testrunners/gm:testrunner",
+        ],
+    )
+    for name, surfaceConfig in [
+        [
+            "ganesh_vk_test",
+            "vk",
+        ],
+        [
+            "ganesh_vk_1010102_test",
+            "vk_1010102",
+        ],
+        [
+            "ganesh_vk_msaa4_test",
+            "vk_msaa4",
+        ],
+        [
+            "ganesh_vk_msaa8_test",
+            "vk_msaa8",
+        ],
+        [
+            "ganesh_vk_dmsaa_test",
+            "vk_dmsaa",
+        ],
+        [
+            "ganesh_vk_betex_test",
+            "vk_betex",
+        ],
+        [
+            "ganesh_vk_bert_test",
+            "vk_bert",
+        ],
+    ]
+]
+
 cc_test_with_flags(
     name = "hello_bazel_world_test",
     srcs = ["hello_bazel_world.cpp"],
diff --git a/include/core/SkSurfaceProps.h b/include/core/SkSurfaceProps.h
index dd7698c..1c9df71 100644
--- a/include/core/SkSurfaceProps.h
+++ b/include/core/SkSurfaceProps.h
@@ -53,12 +53,13 @@
 class SK_API SkSurfaceProps {
 public:
     enum Flags {
+        kDefault_Flag = 0,
         kUseDeviceIndependentFonts_Flag = 1 << 0,
         // Use internal MSAA to render to non-MSAA GPU surfaces.
-        kDynamicMSAA_Flag               = 1 << 1,
+        kDynamicMSAA_Flag = 1 << 1,
         // If set, all rendering will have dithering enabled
         // Currently this only impacts GPU backends
-        kAlwaysDither_Flag              = 1 << 2,
+        kAlwaysDither_Flag = 1 << 2,
     };
 
     /** No flags, unknown pixel geometry, platform-default contrast/gamma. */
diff --git a/relnotes/SkSurfaceProps-Flags.md b/relnotes/SkSurfaceProps-Flags.md
new file mode 100644
index 0000000..6394f44
--- /dev/null
+++ b/relnotes/SkSurfaceProps-Flags.md
@@ -0,0 +1,10 @@
+A `kDefault_Flag = 0` value has been added to the `SkSurfaceProps::Flags` enum. This is just a
+self-documenting zero-value that aims to improve code readability, e.g.:
+
+```
+// The two lines below are equivalent.
+
+SkSurfaceProps(/* surfaceFlags= */ 0, kRGB_H_SkPixelGeometry);
+
+SkSurfaceProps(SkSurfaceProps::kDefault_Flag, kRGB_H_SkPixelGeometry);
+```
diff --git a/tools/testrunners/common/surface_manager/GaneshVulkanSurfaceManager.cpp b/tools/testrunners/common/surface_manager/GaneshVulkanSurfaceManager.cpp
index 869414d..7a42a5b 100644
--- a/tools/testrunners/common/surface_manager/GaneshVulkanSurfaceManager.cpp
+++ b/tools/testrunners/common/surface_manager/GaneshVulkanSurfaceManager.cpp
@@ -5,11 +5,195 @@
  * found in the LICENSE file.
  */
 
+#include "include/core/SkColorSpace.h"
+#include "include/gpu/GrContextOptions.h"
+#include "include/gpu/ganesh/SkSurfaceGanesh.h"
+#include "tools/gpu/BackendSurfaceFactory.h"
+#include "tools/gpu/GrContextFactory.h"
 #include "tools/testrunners/common/surface_manager/SurfaceManager.h"
 
 #include <string>
 
+class GaneshVulkanSurfaceManager : public SurfaceManager {
+public:
+    GaneshVulkanSurfaceManager(std::unique_ptr<sk_gpu_test::GrContextFactory> contextFactory,
+                               sk_gpu_test::ContextInfo contextInfo,
+                               GrDirectContext* context,
+                               sk_sp<SkSurface> surface,
+                               std::string config,
+                               SkColorInfo colorInfo)
+            : SurfaceManager(config, colorInfo, CpuOrGpu::kGPU)
+            , fContextFactory(std::move(contextFactory))
+            , fContextInfo(contextInfo)
+            , fContext(context)
+            , fSurface(surface) {}
+
+    sk_sp<SkSurface> getSurface() override { return fSurface; }
+
+    void flush() override { fContext->flushAndSubmit(fSurface.get(), GrSyncCpu::kYes); }
+
+    sk_gpu_test::ContextInfo* getGaneshContextInfo() override { return &fContextInfo; }
+
+private:
+    // The Vulkan context is destroyed when the context factory is destroyed. We prevent early
+    // destruction of the context by grabbing a reference to the context factory. See the
+    // GrContextFactory class documentation for details.
+    std::unique_ptr<sk_gpu_test::GrContextFactory> fContextFactory;
+    sk_gpu_test::ContextInfo fContextInfo;
+    GrDirectContext* fContext;
+    sk_sp<SkSurface> fSurface;
+};
+
+enum class SurfaceType { kDefault, kBackendTexture, kBackendRenderTarget };
+
+std::unique_ptr<SurfaceManager> makeVulkanSurfaceManager(
+        std::string config,
+        SurfaceOptions surfaceOptions,
+        GrContextOptions grContextOptions,
+        sk_gpu_test::GrContextFactory::ContextOverrides contextOverrides,
+        SkColorInfo colorInfo,
+        SurfaceType surfaceType,
+        uint32_t surfaceFlags,
+        int sampleCount) {
+    if (surfaceOptions.modifyGrContextOptions) {
+        surfaceOptions.modifyGrContextOptions(&grContextOptions);
+    }
+
+    // Based on
+    // https://skia.googlesource.com/skia/+/8da85ea79d1ba2b3f32d25178eb21f2ebda83437/dm/DMSrcSink.cpp#1579.
+    auto contextFactory = std::make_unique<sk_gpu_test::GrContextFactory>(grContextOptions);
+    sk_gpu_test::ContextInfo contextInfo =
+            contextFactory.get()->getContextInfo(skgpu::ContextType::kVulkan, contextOverrides);
+    GrDirectContext* context = contextInfo.directContext();
+    SkASSERT_RELEASE(context);
+
+    // Based on
+    // https://skia.googlesource.com/skia/+/8da85ea79d1ba2b3f32d25178eb21f2ebda83437/dm/DMSrcSink.cpp#1524.
+    SkImageInfo imageInfo =
+            SkImageInfo::Make({surfaceOptions.width, surfaceOptions.height}, colorInfo);
+    SkSurfaceProps surfaceProps(surfaceFlags, kRGB_H_SkPixelGeometry);
+    sk_sp<SkSurface> surface;
+    switch (surfaceType) {
+        default:
+        case SurfaceType::kDefault:
+            surface = SkSurfaces::RenderTarget(
+                    context, skgpu::Budgeted::kNo, imageInfo, sampleCount, &surfaceProps);
+            break;
+
+        case SurfaceType::kBackendTexture:
+            surface = sk_gpu_test::MakeBackendTextureSurface(context,
+                                                             imageInfo,
+                                                             kTopLeft_GrSurfaceOrigin,
+                                                             sampleCount,
+                                                             skgpu::Mipmapped::kNo,
+                                                             skgpu::Protected::kNo,
+                                                             &surfaceProps);
+            break;
+
+        case SurfaceType::kBackendRenderTarget:
+            surface = sk_gpu_test::MakeBackendRenderTargetSurface(context,
+                                                                  imageInfo,
+                                                                  kBottomLeft_GrSurfaceOrigin,
+                                                                  sampleCount,
+                                                                  skgpu::Protected::kNo,
+                                                                  &surfaceProps);
+            break;
+    }
+    SkASSERT_RELEASE(surface);
+
+    return std::make_unique<GaneshVulkanSurfaceManager>(
+            std::move(contextFactory), contextInfo, context, surface, config, colorInfo);
+}
+
+// Based on the configurations defined here[1], the configuration parsing logic here[2], and the
+// sink selection logic here[3].
+//
+// [1]
+// https://skia.googlesource.com/skia/+/8da85ea79d1ba2b3f32d25178eb21f2ebda83437/tools/flags/CommonFlagsConfig.cpp#40
+// [2]
+// https://skia.googlesource.com/skia/+/8da85ea79d1ba2b3f32d25178eb21f2ebda83437/tools/flags/CommonFlagsConfig.cpp#610
+// [3]
+// https://skia.googlesource.com/skia/+/8da85ea79d1ba2b3f32d25178eb21f2ebda83437/dm/DM.cpp#1017
 std::unique_ptr<SurfaceManager> SurfaceManager::FromConfig(std::string config,
                                                            SurfaceOptions surfaceOptions) {
-    return nullptr;  // TODO(lovisolo): Implement.
+    if (config == "vk") {
+        return makeVulkanSurfaceManager(
+                config,
+                surfaceOptions,
+                GrContextOptions(),
+                sk_gpu_test::GrContextFactory::ContextOverrides::kNone,
+                SkColorInfo(kRGBA_8888_SkColorType, kPremul_SkAlphaType, SkColorSpace::MakeSRGB()),
+                SurfaceType::kDefault,
+                SkSurfaceProps::kDefault_Flag,
+                /* sampleCount= */ 1);
+    }
+    if (config == "vk_1010102") {
+        return makeVulkanSurfaceManager(
+                config,
+                surfaceOptions,
+                GrContextOptions(),
+                sk_gpu_test::GrContextFactory::ContextOverrides::kNone,
+                SkColorInfo(
+                        kRGBA_1010102_SkColorType, kPremul_SkAlphaType, SkColorSpace::MakeSRGB()),
+                SurfaceType::kDefault,
+                SkSurfaceProps::kDefault_Flag,
+                /* sampleCount= */ 1);
+    }
+    if (config == "vk_msaa4") {
+        return makeVulkanSurfaceManager(
+                config,
+                surfaceOptions,
+                GrContextOptions(),
+                sk_gpu_test::GrContextFactory::ContextOverrides::kNone,
+                SkColorInfo(kRGBA_8888_SkColorType, kPremul_SkAlphaType, SkColorSpace::MakeSRGB()),
+                SurfaceType::kDefault,
+                SkSurfaceProps::kDefault_Flag,
+                /* sampleCount= */ 4);
+    }
+    if (config == "vk_msaa8") {
+        return makeVulkanSurfaceManager(
+                config,
+                surfaceOptions,
+                GrContextOptions(),
+                sk_gpu_test::GrContextFactory::ContextOverrides::kNone,
+                SkColorInfo(kRGBA_8888_SkColorType, kPremul_SkAlphaType, SkColorSpace::MakeSRGB()),
+                SurfaceType::kDefault,
+                SkSurfaceProps::kDefault_Flag,
+                /* sampleCount= */ 8);
+    }
+    if (config == "vk_dmsaa") {
+        return makeVulkanSurfaceManager(
+                config,
+                surfaceOptions,
+                GrContextOptions(),
+                sk_gpu_test::GrContextFactory::ContextOverrides::kNone,
+                SkColorInfo(kRGBA_8888_SkColorType, kPremul_SkAlphaType, SkColorSpace::MakeSRGB()),
+                SurfaceType::kDefault,
+                SkSurfaceProps::kDynamicMSAA_Flag,
+                /* sampleCount= */ 1);
+    }
+    if (config == "vk_betex") {
+        return makeVulkanSurfaceManager(
+                config,
+                surfaceOptions,
+                GrContextOptions(),
+                sk_gpu_test::GrContextFactory::ContextOverrides::kNone,
+                SkColorInfo(kRGBA_8888_SkColorType, kPremul_SkAlphaType, SkColorSpace::MakeSRGB()),
+                SurfaceType::kBackendTexture,
+                SkSurfaceProps::kDefault_Flag,
+                /* sampleCount= */ 1);
+    }
+    if (config == "vk_bert") {
+        return makeVulkanSurfaceManager(
+                config,
+                surfaceOptions,
+                GrContextOptions(),
+                sk_gpu_test::GrContextFactory::ContextOverrides::kNone,
+                SkColorInfo(kRGBA_8888_SkColorType, kPremul_SkAlphaType, SkColorSpace::MakeSRGB()),
+                SurfaceType::kBackendRenderTarget,
+                SkSurfaceProps::kDefault_Flag,
+                /* sampleCount= */ 1);
+    }
+
+    return nullptr;
 }