Add support for enabling GraphiteVkRenderEngine in SurfaceFlinger

Predicated on just the graphite_renderengine flag (overridable with
the debug.renderengine.graphite sysprops), which inherently implies
GraphicsApi::VK.

As currently implemented, setting the old debug.renderengine.backend
sysprop (e.g. "skiavkthreaded") will fully override this logic,
preventing Graphite from being enabled. This approach is simpler, but
also maintains backwards compatibility, and distances the new approach
from that restrictive terminology.

Note that the approach for actually instantiating a RenderEngine
instance extends the existing RenderEngine::create(args) model, forcing
the caller to know exactly which concrete subclass they wish to
instantiate. This could be reworked in the future.

Test: local validation (sysprops + logs)
Bug: b/293371537
Change-Id: Iff0a8894725fc45e679074ddc2e4af56cca318c6
diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp
index 233134d..1c60563 100644
--- a/libs/renderengine/RenderEngine.cpp
+++ b/libs/renderengine/RenderEngine.cpp
@@ -16,40 +16,45 @@
 
 #include <renderengine/RenderEngine.h>
 
-#include <cutils/properties.h>
-#include <log/log.h>
 #include "renderengine/ExternalTexture.h"
+#include "skia/GaneshVkRenderEngine.h"
+#include "skia/GraphiteVkRenderEngine.h"
+#include "skia/SkiaGLRenderEngine.h"
 #include "threaded/RenderEngineThreaded.h"
 
-#include "skia/SkiaGLRenderEngine.h"
-#include "skia/SkiaVkRenderEngine.h"
+#include <cutils/properties.h>
+#include <log/log.h>
 
 namespace android {
 namespace renderengine {
 
 std::unique_ptr<RenderEngine> RenderEngine::create(const RenderEngineCreationArgs& args) {
-    if (args.threaded == Threaded::YES) {
-        switch (args.graphicsApi) {
-            case GraphicsApi::GL:
-                ALOGD("Threaded RenderEngine with SkiaGL Backend");
-                return renderengine::threaded::RenderEngineThreaded::create([args]() {
-                    return android::renderengine::skia::SkiaGLRenderEngine::create(args);
-                });
-            case GraphicsApi::VK:
-                ALOGD("Threaded RenderEngine with SkiaVK Backend");
-                return renderengine::threaded::RenderEngineThreaded::create([args]() {
-                    return android::renderengine::skia::SkiaVkRenderEngine::create(args);
-                });
+    threaded::CreateInstanceFactory createInstanceFactory;
+
+    ALOGD("%sRenderEngine with %s Backend (%s)", args.threaded == Threaded::YES ? "Threaded " : "",
+          args.graphicsApi == GraphicsApi::GL ? "SkiaGL" : "SkiaVK",
+          args.skiaBackend == SkiaBackend::GANESH ? "Ganesh" : "Graphite");
+
+    if (args.skiaBackend == SkiaBackend::GRAPHITE) {
+        createInstanceFactory = [args]() {
+            return android::renderengine::skia::GraphiteVkRenderEngine::create(args);
+        };
+    } else { // GANESH
+        if (args.graphicsApi == GraphicsApi::VK) {
+            createInstanceFactory = [args]() {
+                return android::renderengine::skia::GaneshVkRenderEngine::create(args);
+            };
+        } else { // GL
+            createInstanceFactory = [args]() {
+                return android::renderengine::skia::SkiaGLRenderEngine::create(args);
+            };
         }
     }
 
-    switch (args.graphicsApi) {
-        case GraphicsApi::GL:
-            ALOGD("RenderEngine with SkiaGL Backend");
-            return renderengine::skia::SkiaGLRenderEngine::create(args);
-        case GraphicsApi::VK:
-            ALOGD("RenderEngine with SkiaVK Backend");
-            return renderengine::skia::SkiaVkRenderEngine::create(args);
+    if (args.threaded == Threaded::YES) {
+        return renderengine::threaded::RenderEngineThreaded::create(createInstanceFactory);
+    } else {
+        return createInstanceFactory();
     }
 }
 
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index de05268..00a6213 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -102,6 +102,11 @@
         VK,
     };
 
+    enum class SkiaBackend {
+        GANESH,
+        GRAPHITE,
+    };
+
     static std::unique_ptr<RenderEngine> create(const RenderEngineCreationArgs& args);
 
     static bool canSupport(GraphicsApi);
@@ -257,6 +262,7 @@
     RenderEngine::ContextPriority contextPriority;
     RenderEngine::Threaded threaded;
     RenderEngine::GraphicsApi graphicsApi;
+    RenderEngine::SkiaBackend skiaBackend;
 
     struct Builder;
 
@@ -267,7 +273,8 @@
                              bool _supportsBackgroundBlur,
                              RenderEngine::ContextPriority _contextPriority,
                              RenderEngine::Threaded _threaded,
-                             RenderEngine::GraphicsApi _graphicsApi)
+                             RenderEngine::GraphicsApi _graphicsApi,
+                             RenderEngine::SkiaBackend _skiaBackend)
           : pixelFormat(_pixelFormat),
             imageCacheSize(_imageCacheSize),
             enableProtectedContext(_enableProtectedContext),
@@ -275,7 +282,8 @@
             supportsBackgroundBlur(_supportsBackgroundBlur),
             contextPriority(_contextPriority),
             threaded(_threaded),
-            graphicsApi(_graphicsApi) {}
+            graphicsApi(_graphicsApi),
+            skiaBackend(_skiaBackend) {}
     RenderEngineCreationArgs() = delete;
 };
 
@@ -314,10 +322,14 @@
         this->graphicsApi = graphicsApi;
         return *this;
     }
+    Builder& setSkiaBackend(RenderEngine::SkiaBackend skiaBackend) {
+        this->skiaBackend = skiaBackend;
+        return *this;
+    }
     RenderEngineCreationArgs build() const {
         return RenderEngineCreationArgs(pixelFormat, imageCacheSize, enableProtectedContext,
                                         precacheToneMapperShaderOnly, supportsBackgroundBlur,
-                                        contextPriority, threaded, graphicsApi);
+                                        contextPriority, threaded, graphicsApi, skiaBackend);
     }
 
 private:
@@ -330,6 +342,7 @@
     RenderEngine::ContextPriority contextPriority = RenderEngine::ContextPriority::MEDIUM;
     RenderEngine::Threaded threaded = RenderEngine::Threaded::YES;
     RenderEngine::GraphicsApi graphicsApi = RenderEngine::GraphicsApi::GL;
+    RenderEngine::SkiaBackend skiaBackend = RenderEngine::SkiaBackend::GANESH;
 };
 
 } // namespace renderengine
diff --git a/libs/renderengine/skia/GaneshVkRenderEngine.cpp b/libs/renderengine/skia/GaneshVkRenderEngine.cpp
index aa18713..68798bf 100644
--- a/libs/renderengine/skia/GaneshVkRenderEngine.cpp
+++ b/libs/renderengine/skia/GaneshVkRenderEngine.cpp
@@ -27,6 +27,22 @@
 
 namespace android::renderengine::skia {
 
+std::unique_ptr<GaneshVkRenderEngine> GaneshVkRenderEngine::create(
+        const RenderEngineCreationArgs& args) {
+    std::unique_ptr<GaneshVkRenderEngine> engine(new GaneshVkRenderEngine(args));
+    engine->ensureContextsCreated();
+
+    if (getVulkanInterface(false).isInitialized()) {
+        ALOGD("GaneshVkRenderEngine::%s: successfully initialized GaneshVkRenderEngine", __func__);
+        return engine;
+    } else {
+        ALOGE("GaneshVkRenderEngine::%s: could not create GaneshVkRenderEngine. "
+              "Likely insufficient Vulkan support",
+              __func__);
+        return {};
+    }
+}
+
 // Ganesh-specific function signature for fFinishedProc callback.
 static void unref_semaphore(void* semaphore) {
     SkiaVkRenderEngine::DestroySemaphoreInfo* info =
diff --git a/libs/renderengine/skia/GaneshVkRenderEngine.h b/libs/renderengine/skia/GaneshVkRenderEngine.h
index 5940d04..e6123c2 100644
--- a/libs/renderengine/skia/GaneshVkRenderEngine.h
+++ b/libs/renderengine/skia/GaneshVkRenderEngine.h
@@ -21,15 +21,16 @@
 namespace android::renderengine::skia {
 
 class GaneshVkRenderEngine : public SkiaVkRenderEngine {
-    friend std::unique_ptr<SkiaVkRenderEngine> SkiaVkRenderEngine::create(
-            const RenderEngineCreationArgs& args);
+public:
+    static std::unique_ptr<GaneshVkRenderEngine> create(const RenderEngineCreationArgs& args);
 
 protected:
-    GaneshVkRenderEngine(const RenderEngineCreationArgs& args) : SkiaVkRenderEngine(args) {}
-
     std::unique_ptr<SkiaGpuContext> createContext(VulkanInterface& vulkanInterface) override;
     void waitFence(SkiaGpuContext* context, base::borrowed_fd fenceFd) override;
     base::unique_fd flushAndSubmit(SkiaGpuContext* context, sk_sp<SkSurface> dstSurface) override;
+
+private:
+    GaneshVkRenderEngine(const RenderEngineCreationArgs& args) : SkiaVkRenderEngine(args) {}
 };
 
 } // namespace android::renderengine::skia
diff --git a/libs/renderengine/skia/GraphiteVkRenderEngine.cpp b/libs/renderengine/skia/GraphiteVkRenderEngine.cpp
index 3d2c4b4..b5cb21b 100644
--- a/libs/renderengine/skia/GraphiteVkRenderEngine.cpp
+++ b/libs/renderengine/skia/GraphiteVkRenderEngine.cpp
@@ -32,6 +32,23 @@
 
 namespace android::renderengine::skia {
 
+std::unique_ptr<GraphiteVkRenderEngine> GraphiteVkRenderEngine::create(
+        const RenderEngineCreationArgs& args) {
+    std::unique_ptr<GraphiteVkRenderEngine> engine(new GraphiteVkRenderEngine(args));
+    engine->ensureContextsCreated();
+
+    if (getVulkanInterface(false).isInitialized()) {
+        ALOGD("GraphiteVkRenderEngine::%s: successfully initialized GraphiteVkRenderEngine",
+              __func__);
+        return engine;
+    } else {
+        ALOGE("GraphiteVkRenderEngine::%s: could not create GraphiteVkRenderEngine. "
+              "Likely insufficient Vulkan support",
+              __func__);
+        return {};
+    }
+}
+
 // Graphite-specific function signature for fFinishedProc callback.
 static void unref_semaphore(void* semaphore, skgpu::CallbackResult result) {
     if (result != skgpu::CallbackResult::kSuccess) {
diff --git a/libs/renderengine/skia/GraphiteVkRenderEngine.h b/libs/renderengine/skia/GraphiteVkRenderEngine.h
index 90933ab..cf24a3b 100644
--- a/libs/renderengine/skia/GraphiteVkRenderEngine.h
+++ b/libs/renderengine/skia/GraphiteVkRenderEngine.h
@@ -23,17 +23,17 @@
 namespace android::renderengine::skia {
 
 class GraphiteVkRenderEngine : public SkiaVkRenderEngine {
-    friend std::unique_ptr<SkiaVkRenderEngine> SkiaVkRenderEngine::create(
-            const RenderEngineCreationArgs& args);
+public:
+    static std::unique_ptr<GraphiteVkRenderEngine> create(const RenderEngineCreationArgs& args);
 
 protected:
-    GraphiteVkRenderEngine(const RenderEngineCreationArgs& args) : SkiaVkRenderEngine(args) {}
-
     std::unique_ptr<SkiaGpuContext> createContext(VulkanInterface& vulkanInterface) override;
     void waitFence(SkiaGpuContext* context, base::borrowed_fd fenceFd) override;
     base::unique_fd flushAndSubmit(SkiaGpuContext* context, sk_sp<SkSurface> dstSurface) override;
 
 private:
+    GraphiteVkRenderEngine(const RenderEngineCreationArgs& args) : SkiaVkRenderEngine(args) {}
+
     std::vector<graphite::BackendSemaphore> mStagedWaitSemaphores;
 };
 
diff --git a/libs/renderengine/skia/SkiaVkRenderEngine.cpp b/libs/renderengine/skia/SkiaVkRenderEngine.cpp
index 3715859..fd71332 100644
--- a/libs/renderengine/skia/SkiaVkRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaVkRenderEngine.cpp
@@ -83,23 +83,6 @@
 
 using base::StringAppendF;
 
-std::unique_ptr<SkiaVkRenderEngine> SkiaVkRenderEngine::create(
-        const RenderEngineCreationArgs& args) {
-    // TODO: b/293371537 - Ganesh vs. Graphite subclass based on flag in RenderEngineCreationArgs
-    std::unique_ptr<SkiaVkRenderEngine> engine(new GaneshVkRenderEngine(args));
-    engine->ensureContextsCreated();
-
-    if (sVulkanInterface.isInitialized()) {
-        ALOGD("SkiaVkRenderEngine::%s: successfully initialized SkiaVkRenderEngine", __func__);
-        return engine;
-    } else {
-        ALOGD("SkiaVkRenderEngine::%s: could not create SkiaVkRenderEngine. "
-              "Likely insufficient Vulkan support",
-              __func__);
-        return {};
-    }
-}
-
 SkiaVkRenderEngine::SkiaVkRenderEngine(const RenderEngineCreationArgs& args)
       : SkiaRenderEngine(args.threaded, static_cast<PixelFormat>(args.pixelFormat),
                          args.supportsBackgroundBlur) {}
diff --git a/libs/renderengine/skia/SkiaVkRenderEngine.h b/libs/renderengine/skia/SkiaVkRenderEngine.h
index 371b812..0a2f9b2 100644
--- a/libs/renderengine/skia/SkiaVkRenderEngine.h
+++ b/libs/renderengine/skia/SkiaVkRenderEngine.h
@@ -29,7 +29,6 @@
 
 class SkiaVkRenderEngine : public SkiaRenderEngine {
 public:
-    static std::unique_ptr<SkiaVkRenderEngine> create(const RenderEngineCreationArgs& args);
     ~SkiaVkRenderEngine() override;
 
     int getContextPriority() override;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index cf94f94..4164dc5 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -793,6 +793,8 @@
     char prop[PROPERTY_VALUE_MAX];
     property_get(PROPERTY_DEBUG_RENDERENGINE_BACKEND, prop, "");
 
+    // TODO: b/293371537 - Once GraphiteVk is deemed relatively stable, log a warning that
+    // PROPERTY_DEBUG_RENDERENGINE_BACKEND is deprecated
     if (strcmp(prop, "skiagl") == 0) {
         builder.setThreaded(renderengine::RenderEngine::Threaded::NO)
                 .setGraphicsApi(renderengine::RenderEngine::GraphicsApi::GL);
@@ -807,8 +809,14 @@
                 .setGraphicsApi(renderengine::RenderEngine::GraphicsApi::VK);
     } else {
         const auto kVulkan = renderengine::RenderEngine::GraphicsApi::VK;
-        const bool useVulkan = FlagManager::getInstance().vulkan_renderengine() &&
-                renderengine::RenderEngine::canSupport(kVulkan);
+        const bool canSupportVulkan = renderengine::RenderEngine::canSupport(kVulkan);
+        const bool useGraphite =
+                canSupportVulkan && FlagManager::getInstance().graphite_renderengine();
+        const bool useVulkan = useGraphite ||
+                (canSupportVulkan && FlagManager::getInstance().vulkan_renderengine());
+
+        builder.setSkiaBackend(useGraphite ? renderengine::RenderEngine::SkiaBackend::GRAPHITE
+                                           : renderengine::RenderEngine::SkiaBackend::GANESH);
         builder.setGraphicsApi(useVulkan ? kVulkan : renderengine::RenderEngine::GraphicsApi::GL);
     }
 }
diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp
index 6507aba..d9334d6 100644
--- a/services/surfaceflinger/common/FlagManager.cpp
+++ b/services/surfaceflinger/common/FlagManager.cpp
@@ -139,6 +139,7 @@
     DUMP_READ_ONLY_FLAG(protected_if_client);
     DUMP_READ_ONLY_FLAG(ce_fence_promise);
     DUMP_READ_ONLY_FLAG(idle_screen_refresh_rate_timeout);
+    DUMP_READ_ONLY_FLAG(graphite_renderengine);
 #undef DUMP_READ_ONLY_FLAG
 #undef DUMP_SERVER_FLAG
 #undef DUMP_FLAG_INTERVAL
@@ -227,6 +228,7 @@
 FLAG_MANAGER_READ_ONLY_FLAG(dont_skip_on_early_ro, "")
 FLAG_MANAGER_READ_ONLY_FLAG(protected_if_client, "")
 FLAG_MANAGER_READ_ONLY_FLAG(ce_fence_promise, "");
+FLAG_MANAGER_READ_ONLY_FLAG(graphite_renderengine, "debug.renderengine.graphite")
 
 /// Trunk stable server flags ///
 FLAG_MANAGER_SERVER_FLAG(refresh_rate_overlay_on_external_display, "")
diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h
index 964943c..819e587 100644
--- a/services/surfaceflinger/common/include/common/FlagManager.h
+++ b/services/surfaceflinger/common/include/common/FlagManager.h
@@ -77,6 +77,7 @@
     bool protected_if_client() const;
     bool ce_fence_promise() const;
     bool idle_screen_refresh_rate_timeout() const;
+    bool graphite_renderengine() const;
 
 protected:
     // overridden for unit tests