Add and plumb abstraction layer over GrDirectContext

Also changed GaussianBlurFilter's surface origin from
kBottomLeft_GrSurfaceOrigin to kTopLeft_GrSurfaceOrigin. This doesn't
seem to have an effect in practice, but aligns it with KawaseBlurFilter.

Additionally, both blur filters now set the protected bit on the
surfaces they create to reflect the protection status of the active
context, as opposed to either the protection status of the input SkImage
that is being blurred (Kawase) or always false (Gaussian). This should
be equivalent behavior in the case of Kawase (and aligns with Graphite),
and is likely a bug fix for Gaussian.

Test: manual validation (GL+VK) & existing tests (refactor)
Bug: b/293371537
Change-Id: I19b0258035ea5f319d04207ceb266f2cd1e87674
diff --git a/libs/renderengine/skia/compat/GaneshGpuContext.cpp b/libs/renderengine/skia/compat/GaneshGpuContext.cpp
new file mode 100644
index 0000000..51c6a6c
--- /dev/null
+++ b/libs/renderengine/skia/compat/GaneshGpuContext.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "GaneshGpuContext.h"
+
+#include <include/core/SkImageInfo.h>
+#include <include/core/SkSurface.h>
+#include <include/core/SkTraceMemoryDump.h>
+#include <include/gpu/GrDirectContext.h>
+#include <include/gpu/GrTypes.h>
+#include <include/gpu/ganesh/SkSurfaceGanesh.h>
+#include <include/gpu/ganesh/gl/GrGLDirectContext.h>
+#include <include/gpu/ganesh/vk/GrVkDirectContext.h>
+#include <include/gpu/gl/GrGLInterface.h>
+#include <include/gpu/vk/GrVkBackendContext.h>
+
+#include <android-base/macros.h>
+#include <log/log_main.h>
+
+namespace android::renderengine::skia {
+
+namespace {
+// TODO: b/293371537 - Graphite variant.
+static GrContextOptions ganeshOptions(GrContextOptions::PersistentCache& skSLCacheMonitor) {
+    GrContextOptions options;
+    options.fDisableDriverCorrectnessWorkarounds = true;
+    options.fDisableDistanceFieldPaths = true;
+    options.fReducedShaderVariations = true;
+    options.fPersistentCache = &skSLCacheMonitor;
+    return options;
+}
+} // namespace
+
+std::unique_ptr<SkiaGpuContext> SkiaGpuContext::MakeGL_Ganesh(
+        sk_sp<const GrGLInterface> glInterface,
+        GrContextOptions::PersistentCache& skSLCacheMonitor) {
+    return std::make_unique<GaneshGpuContext>(
+            GrDirectContexts::MakeGL(glInterface, ganeshOptions(skSLCacheMonitor)));
+}
+
+std::unique_ptr<SkiaGpuContext> SkiaGpuContext::MakeVulkan_Ganesh(
+        const GrVkBackendContext& grVkBackendContext,
+        GrContextOptions::PersistentCache& skSLCacheMonitor) {
+    return std::make_unique<GaneshGpuContext>(
+            GrDirectContexts::MakeVulkan(grVkBackendContext, ganeshOptions(skSLCacheMonitor)));
+}
+
+GaneshGpuContext::GaneshGpuContext(sk_sp<GrDirectContext> grContext) : mGrContext(grContext) {
+    LOG_ALWAYS_FATAL_IF(mGrContext.get() == nullptr, "GrDirectContext creation failed");
+}
+
+sk_sp<GrDirectContext> GaneshGpuContext::grDirectContext() {
+    return mGrContext;
+}
+
+sk_sp<SkSurface> GaneshGpuContext::createRenderTarget(SkImageInfo imageInfo) {
+    constexpr int kSampleCount = 1; // enable AA
+    constexpr SkSurfaceProps* kProps = nullptr;
+    constexpr bool kMipmapped = false;
+    return SkSurfaces::RenderTarget(mGrContext.get(), skgpu::Budgeted::kNo, imageInfo, kSampleCount,
+                                    kTopLeft_GrSurfaceOrigin, kProps, kMipmapped,
+                                    mGrContext->supportsProtectedContent());
+}
+
+size_t GaneshGpuContext::getMaxRenderTargetSize() const {
+    return mGrContext->maxRenderTargetSize();
+};
+
+size_t GaneshGpuContext::getMaxTextureSize() const {
+    return mGrContext->maxTextureSize();
+};
+
+bool GaneshGpuContext::isAbandoned() {
+    return mGrContext->abandoned();
+}
+
+void GaneshGpuContext::setResourceCacheLimit(size_t maxResourceBytes) {
+    mGrContext->setResourceCacheLimit(maxResourceBytes);
+}
+
+void GaneshGpuContext::finishRenderingAndAbandonContext() {
+    mGrContext->flushAndSubmit(GrSyncCpu::kYes);
+    mGrContext->abandonContext();
+};
+
+void GaneshGpuContext::purgeUnlockedScratchResources() {
+    mGrContext->purgeUnlockedResources(GrPurgeResourceOptions::kScratchResourcesOnly);
+}
+
+void GaneshGpuContext::resetContextIfApplicable() {
+    mGrContext->resetContext(); // Only applicable to GL
+};
+
+void GaneshGpuContext::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
+    mGrContext->dumpMemoryStatistics(traceMemoryDump);
+}
+
+} // namespace android::renderengine::skia
diff --git a/libs/renderengine/skia/compat/GaneshGpuContext.h b/libs/renderengine/skia/compat/GaneshGpuContext.h
new file mode 100644
index 0000000..59001ec
--- /dev/null
+++ b/libs/renderengine/skia/compat/GaneshGpuContext.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "SkiaGpuContext.h"
+
+#include <android-base/macros.h>
+
+namespace android::renderengine::skia {
+
+class GaneshGpuContext : public SkiaGpuContext {
+public:
+    GaneshGpuContext(sk_sp<GrDirectContext> grContext);
+    ~GaneshGpuContext() override = default;
+
+    sk_sp<GrDirectContext> grDirectContext() override;
+
+    sk_sp<SkSurface> createRenderTarget(SkImageInfo imageInfo) override;
+
+    size_t getMaxRenderTargetSize() const override;
+    size_t getMaxTextureSize() const override;
+    bool isAbandoned() override;
+    void setResourceCacheLimit(size_t maxResourceBytes) override;
+
+    void finishRenderingAndAbandonContext() override;
+    void purgeUnlockedScratchResources() override;
+    void resetContextIfApplicable() override;
+
+    void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const override;
+
+private:
+    DISALLOW_COPY_AND_ASSIGN(GaneshGpuContext);
+
+    const sk_sp<GrDirectContext> mGrContext;
+};
+
+} // namespace android::renderengine::skia
diff --git a/libs/renderengine/skia/compat/SkiaGpuContext.h b/libs/renderengine/skia/compat/SkiaGpuContext.h
new file mode 100644
index 0000000..ba167f3
--- /dev/null
+++ b/libs/renderengine/skia/compat/SkiaGpuContext.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#undef LOG_TAG
+#define LOG_TAG "RenderEngine"
+
+#include <include/core/SkSurface.h>
+#include <include/gpu/GrDirectContext.h>
+#include <include/gpu/gl/GrGLInterface.h>
+#include <include/gpu/vk/GrVkBackendContext.h>
+
+#include <log/log.h>
+
+namespace android::renderengine::skia {
+
+/**
+ * Abstraction over Ganesh and Graphite's underlying context-like objects.
+ */
+class SkiaGpuContext {
+public:
+    static std::unique_ptr<SkiaGpuContext> MakeGL_Ganesh(
+            sk_sp<const GrGLInterface> glInterface,
+            GrContextOptions::PersistentCache& skSLCacheMonitor);
+
+    // TODO: b/293371537 - Graphite variant.
+    static std::unique_ptr<SkiaGpuContext> MakeVulkan_Ganesh(
+            const GrVkBackendContext& grVkBackendContext,
+            GrContextOptions::PersistentCache& skSLCacheMonitor);
+
+    virtual ~SkiaGpuContext() = default;
+
+    // TODO: b/293371537 - Maybe expose whether this SkiaGpuContext is using Ganesh or Graphite?
+    /**
+     * Only callable on Ganesh-backed instances of SkiaGpuContext, otherwise fatal.
+     */
+    virtual sk_sp<GrDirectContext> grDirectContext() {
+        LOG_ALWAYS_FATAL("grDirectContext() called on a non-Ganesh instance of SkiaGpuContext!");
+    }
+
+    /**
+     * Notes:
+     * - The surface doesn't count against Skia's caching budgets.
+     * - Protected status is set to match the implementation's underlying context.
+     * - The origin of the surface in texture space corresponds to the top-left content pixel.
+     * - AA is always enabled.
+     */
+    virtual sk_sp<SkSurface> createRenderTarget(SkImageInfo imageInfo) = 0;
+
+    virtual bool isAbandoned() = 0;
+    virtual size_t getMaxRenderTargetSize() const = 0;
+    virtual size_t getMaxTextureSize() const = 0;
+    virtual void setResourceCacheLimit(size_t maxResourceBytes) = 0;
+
+    virtual void finishRenderingAndAbandonContext() = 0;
+    virtual void purgeUnlockedScratchResources() = 0;
+    virtual void resetContextIfApplicable() = 0; // No-op outside of GL (&& Ganesh at this point.)
+
+    virtual void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const = 0;
+};
+
+} // namespace android::renderengine::skia