Plumbing through GPU context priority from SF to RE

Test: Run the code. Check logcat.
      atest librenderengine_test
Bug: 168740533
Change-Id: I6e34c4064dfd75ac96b86e0af587a208fc93d975
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 279e648..c88e298 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -222,6 +222,29 @@
     return err;
 }
 
+std::optional<RenderEngine::ContextPriority> GLESRenderEngine::createContextPriority(
+        const RenderEngineCreationArgs& args) {
+    if (!GLExtensions::getInstance().hasContextPriority()) {
+        return std::nullopt;
+    }
+
+    switch (args.contextPriority) {
+        case RenderEngine::ContextPriority::REALTIME:
+            if (gl::GLExtensions::getInstance().hasRealtimePriority()) {
+                return RenderEngine::ContextPriority::REALTIME;
+            } else {
+                ALOGI("Realtime priority unsupported, degrading gracefully to high priority");
+                return RenderEngine::ContextPriority::HIGH;
+            }
+        case RenderEngine::ContextPriority::HIGH:
+        case RenderEngine::ContextPriority::MEDIUM:
+        case RenderEngine::ContextPriority::LOW:
+            return args.contextPriority;
+        default:
+            return std::nullopt;
+    }
+}
+
 std::unique_ptr<GLESRenderEngine> GLESRenderEngine::create(const RenderEngineCreationArgs& args) {
     // initialize EGL for the default display
     EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
@@ -235,6 +258,7 @@
         LOG_ALWAYS_FATAL("eglQueryString(EGL_VERSION) failed");
     }
 
+    // Use the Android impl to grab EGL_NV_context_priority_realtime
     const auto eglExtensions = eglQueryString(display, EGL_EXTENSIONS);
     if (!eglExtensions) {
         checkGlError(__FUNCTION__, __LINE__);
@@ -251,17 +275,16 @@
         config = chooseEglConfig(display, args.pixelFormat, /*logConfig*/ true);
     }
 
-    bool useContextPriority =
-            extensions.hasContextPriority() && args.contextPriority == ContextPriority::HIGH;
+    const std::optional<RenderEngine::ContextPriority> priority = createContextPriority(args);
     EGLContext protectedContext = EGL_NO_CONTEXT;
     if (args.enableProtectedContext && extensions.hasProtectedContent()) {
-        protectedContext = createEglContext(display, config, nullptr, useContextPriority,
-                                            Protection::PROTECTED);
+        protectedContext =
+                createEglContext(display, config, nullptr, priority, Protection::PROTECTED);
         ALOGE_IF(protectedContext == EGL_NO_CONTEXT, "Can't create protected context");
     }
 
-    EGLContext ctxt = createEglContext(display, config, protectedContext, useContextPriority,
-                                       Protection::UNPROTECTED);
+    EGLContext ctxt =
+            createEglContext(display, config, protectedContext, priority, Protection::UNPROTECTED);
 
     // if can't create a GL context, we can only abort.
     LOG_ALWAYS_FATAL_IF(ctxt == EGL_NO_CONTEXT, "EGLContext creation failed");
@@ -311,7 +334,6 @@
     ALOGI("extensions: %s", extensions.getExtensions());
     ALOGI("GL_MAX_TEXTURE_SIZE = %zu", engine->getMaxTextureSize());
     ALOGI("GL_MAX_VIEWPORT_DIMS = %zu", engine->getMaxViewportDims());
-
     return engine;
 }
 
@@ -802,6 +824,12 @@
     ALOGV("Failed to find image for buffer: %" PRIu64, bufferId);
 }
 
+int GLESRenderEngine::getContextPriority() {
+    int value;
+    eglQueryContext(mEGLDisplay, mEGLContext, EGL_CONTEXT_PRIORITY_LEVEL_IMG, &value);
+    return value;
+}
+
 FloatRect GLESRenderEngine::setupLayerCropping(const LayerSettings& layer, Mesh& mesh) {
     // Translate win by the rounded corners rect coordinates, to have all values in
     // layer coordinate space.
@@ -1617,7 +1645,8 @@
 }
 
 EGLContext GLESRenderEngine::createEglContext(EGLDisplay display, EGLConfig config,
-                                              EGLContext shareContext, bool useContextPriority,
+                                              EGLContext shareContext,
+                                              std::optional<ContextPriority> contextPriority,
                                               Protection protection) {
     EGLint renderableType = 0;
     if (config == EGL_NO_CONFIG) {
@@ -1640,9 +1669,23 @@
     contextAttributes.reserve(7);
     contextAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION);
     contextAttributes.push_back(contextClientVersion);
-    if (useContextPriority) {
+    if (contextPriority) {
         contextAttributes.push_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG);
-        contextAttributes.push_back(EGL_CONTEXT_PRIORITY_HIGH_IMG);
+        switch (*contextPriority) {
+            case ContextPriority::REALTIME:
+                contextAttributes.push_back(EGL_CONTEXT_PRIORITY_REALTIME_NV);
+                break;
+            case ContextPriority::MEDIUM:
+                contextAttributes.push_back(EGL_CONTEXT_PRIORITY_MEDIUM_IMG);
+                break;
+            case ContextPriority::LOW:
+                contextAttributes.push_back(EGL_CONTEXT_PRIORITY_LOW_IMG);
+                break;
+            case ContextPriority::HIGH:
+            default:
+                contextAttributes.push_back(EGL_CONTEXT_PRIORITY_HIGH_IMG);
+                break;
+        }
     }
     if (protection == Protection::PROTECTED) {
         contextAttributes.push_back(EGL_PROTECTED_CONTENT_EXT);
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 92e1529..64d6c6b 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -71,6 +71,7 @@
                         const sp<GraphicBuffer>& buffer, const bool useFramebufferCache,
                         base::unique_fd&& bufferFence, base::unique_fd* drawFence) override;
     bool cleanupPostRender(CleanupMode mode) override;
+    int getContextPriority() override;
 
     EGLDisplay getEGLDisplay() const { return mEGLDisplay; }
     // Creates an output image for rendering to
@@ -116,8 +117,11 @@
     static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig);
     static GlesVersion parseGlesVersion(const char* str);
     static EGLContext createEglContext(EGLDisplay display, EGLConfig config,
-                                       EGLContext shareContext, bool useContextPriority,
+                                       EGLContext shareContext,
+                                       std::optional<ContextPriority> contextPriority,
                                        Protection protection);
+    static std::optional<RenderEngine::ContextPriority> createContextPriority(
+            const RenderEngineCreationArgs& args);
     static EGLSurface createStubEglPbufferSurface(EGLDisplay display, EGLConfig config,
                                                   int hwcFormat, Protection protection);
     std::unique_ptr<Framebuffer> createFramebuffer();
diff --git a/libs/renderengine/gl/GLExtensions.cpp b/libs/renderengine/gl/GLExtensions.cpp
index 2924b0e..3dd534e 100644
--- a/libs/renderengine/gl/GLExtensions.cpp
+++ b/libs/renderengine/gl/GLExtensions.cpp
@@ -120,6 +120,10 @@
     if (extensionSet.hasExtension("EGL_KHR_surfaceless_context")) {
         mHasSurfacelessContext = true;
     }
+
+    if (extensionSet.hasExtension("EGL_NV_context_priority_realtime")) {
+        mHasRealtimePriority = true;
+    }
 }
 
 char const* GLExtensions::getEGLVersion() const {
diff --git a/libs/renderengine/gl/GLExtensions.h b/libs/renderengine/gl/GLExtensions.h
index ef00009..e415ff3 100644
--- a/libs/renderengine/gl/GLExtensions.h
+++ b/libs/renderengine/gl/GLExtensions.h
@@ -41,6 +41,7 @@
     bool hasContextPriority() const { return mHasContextPriority; }
     bool hasSurfacelessContext() const { return mHasSurfacelessContext; }
     bool hasProtectedTexture() const { return mHasProtectedTexture; }
+    bool hasRealtimePriority() const { return mHasRealtimePriority; }
 
     void initWithGLStrings(GLubyte const* vendor, GLubyte const* renderer, GLubyte const* version,
                            GLubyte const* extensions);
@@ -67,6 +68,7 @@
     bool mHasContextPriority = false;
     bool mHasSurfacelessContext = false;
     bool mHasProtectedTexture = false;
+    bool mHasRealtimePriority = false;
 
     String8 mVendor;
     String8 mRenderer;
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index ef12fd2..9157066 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -75,6 +75,7 @@
         LOW = 1,
         MEDIUM = 2,
         HIGH = 3,
+        REALTIME = 4,
     };
 
     enum class RenderEngineType {
@@ -181,6 +182,10 @@
                                 const sp<GraphicBuffer>& buffer, const bool useFramebufferCache,
                                 base::unique_fd&& bufferFence, base::unique_fd* drawFence) = 0;
     virtual void cleanFramebufferCache() = 0;
+    // Returns the priority this context was actually created with. Note: this may not be
+    // the same as specified at context creation time, due to implementation limits on the
+    // number of contexts that can be created at a specific priority level in the system.
+    virtual int getContextPriority() = 0;
 
 protected:
     friend class threaded::RenderEngineThreaded;
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index 95ee925..2c34da4 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -53,6 +53,7 @@
                           const sp<GraphicBuffer>&, const bool, base::unique_fd&&,
                           base::unique_fd*));
     MOCK_METHOD0(cleanFramebufferCache, void());
+    MOCK_METHOD0(getContextPriority, int());
 };
 
 } // namespace mock
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 1f98a46..3d6b7af 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -169,17 +169,16 @@
         config = chooseEglConfig(display, args.pixelFormat, /*logConfig*/ true);
     }
 
-    bool useContextPriority =
-            extensions.hasContextPriority() && args.contextPriority == ContextPriority::HIGH;
     EGLContext protectedContext = EGL_NO_CONTEXT;
+    const std::optional<RenderEngine::ContextPriority> priority = createContextPriority(args);
     if (args.enableProtectedContext && extensions.hasProtectedContent()) {
-        protectedContext = createEglContext(display, config, nullptr, useContextPriority,
-                                            Protection::PROTECTED);
+        protectedContext =
+                createEglContext(display, config, nullptr, priority, Protection::PROTECTED);
         ALOGE_IF(protectedContext == EGL_NO_CONTEXT, "Can't create protected context");
     }
 
-    EGLContext ctxt = createEglContext(display, config, protectedContext, useContextPriority,
-                                       Protection::UNPROTECTED);
+    EGLContext ctxt =
+            createEglContext(display, config, protectedContext, priority, Protection::UNPROTECTED);
 
     // if can't create a GL context, we can only abort.
     LOG_ALWAYS_FATAL_IF(ctxt == EGL_NO_CONTEXT, "EGLContext creation failed");
@@ -832,7 +831,8 @@
 }
 
 EGLContext SkiaGLRenderEngine::createEglContext(EGLDisplay display, EGLConfig config,
-                                                EGLContext shareContext, bool useContextPriority,
+                                                EGLContext shareContext,
+                                                std::optional<ContextPriority> contextPriority,
                                                 Protection protection) {
     EGLint renderableType = 0;
     if (config == EGL_NO_CONFIG_KHR) {
@@ -855,9 +855,23 @@
     contextAttributes.reserve(7);
     contextAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION);
     contextAttributes.push_back(contextClientVersion);
-    if (useContextPriority) {
+    if (contextPriority) {
         contextAttributes.push_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG);
-        contextAttributes.push_back(EGL_CONTEXT_PRIORITY_HIGH_IMG);
+        switch (*contextPriority) {
+            case ContextPriority::REALTIME:
+                contextAttributes.push_back(EGL_CONTEXT_PRIORITY_REALTIME_NV);
+                break;
+            case ContextPriority::MEDIUM:
+                contextAttributes.push_back(EGL_CONTEXT_PRIORITY_MEDIUM_IMG);
+                break;
+            case ContextPriority::LOW:
+                contextAttributes.push_back(EGL_CONTEXT_PRIORITY_LOW_IMG);
+                break;
+            case ContextPriority::HIGH:
+            default:
+                contextAttributes.push_back(EGL_CONTEXT_PRIORITY_HIGH_IMG);
+                break;
+        }
     }
     if (protection == Protection::PROTECTED) {
         contextAttributes.push_back(EGL_PROTECTED_CONTENT_EXT);
@@ -882,6 +896,29 @@
     return context;
 }
 
+std::optional<RenderEngine::ContextPriority> SkiaGLRenderEngine::createContextPriority(
+        const RenderEngineCreationArgs& args) {
+    if (!gl::GLExtensions::getInstance().hasContextPriority()) {
+        return std::nullopt;
+    }
+
+    switch (args.contextPriority) {
+        case RenderEngine::ContextPriority::REALTIME:
+            if (gl::GLExtensions::getInstance().hasRealtimePriority()) {
+                return RenderEngine::ContextPriority::REALTIME;
+            } else {
+                ALOGI("Realtime priority unsupported, degrading gracefully to high priority");
+                return RenderEngine::ContextPriority::HIGH;
+            }
+        case RenderEngine::ContextPriority::HIGH:
+        case RenderEngine::ContextPriority::MEDIUM:
+        case RenderEngine::ContextPriority::LOW:
+            return args.contextPriority;
+        default:
+            return std::nullopt;
+    }
+}
+
 EGLSurface SkiaGLRenderEngine::createPlaceholderEglPbufferSurface(EGLDisplay display,
                                                                   EGLConfig config, int hwcFormat,
                                                                   Protection protection) {
@@ -906,6 +943,12 @@
 
 void SkiaGLRenderEngine::cleanFramebufferCache() {}
 
+int SkiaGLRenderEngine::getContextPriority() {
+    int value;
+    eglQueryContext(mEGLDisplay, mEGLContext, EGL_CONTEXT_PRIORITY_LEVEL_IMG, &value);
+    return value;
+}
+
 } // namespace skia
 } // namespace renderengine
 } // namespace android
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index b53250e..3d8c693 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -56,6 +56,7 @@
                         const sp<GraphicBuffer>& buffer, const bool useFramebufferCache,
                         base::unique_fd&& bufferFence, base::unique_fd* drawFence) override;
     void cleanFramebufferCache() override;
+    int getContextPriority() override;
     bool isProtected() const override { return mInProtectedContext; }
     bool supportsProtectedContent() const override;
     bool useProtectedContext(bool useProtectedContext) override;
@@ -68,8 +69,11 @@
 private:
     static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig);
     static EGLContext createEglContext(EGLDisplay display, EGLConfig config,
-                                       EGLContext shareContext, bool useContextPriority,
+                                       EGLContext shareContext,
+                                       std::optional<ContextPriority> contextPriority,
                                        Protection protection);
+    static std::optional<RenderEngine::ContextPriority> createContextPriority(
+            const RenderEngineCreationArgs& args);
     static EGLSurface createPlaceholderEglPbufferSurface(EGLDisplay display, EGLConfig config,
                                                          int hwcFormat, Protection protection);
     inline SkRect getSkRect(const FloatRect& layer);
diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h
index 2352c7e..12b8586 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.h
+++ b/libs/renderengine/skia/SkiaRenderEngine.h
@@ -56,6 +56,7 @@
         return 0;
     };
     virtual bool cleanupPostRender(CleanupMode) override { return true; };
+    virtual int getContextPriority() override { return 0; }
 };
 
 } // namespace skia
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp
index 5453302..08f2949 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.cpp
+++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp
@@ -304,6 +304,21 @@
     resultFuture.wait();
 }
 
+int RenderEngineThreaded::getContextPriority() {
+    std::promise<int> resultPromise;
+    std::future<int> resultFuture = resultPromise.get_future();
+    {
+        std::lock_guard lock(mThreadMutex);
+        mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& instance) {
+            ATRACE_NAME("REThreaded::getContextPriority");
+            int priority = instance.getContextPriority();
+            resultPromise.set_value(priority);
+        });
+    }
+    mCondition.notify_one();
+    return resultFuture.get();
+}
+
 } // namespace threaded
 } // namespace renderengine
 } // namespace android
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h
index cdfbd04..8b1e2de 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.h
+++ b/libs/renderengine/threaded/RenderEngineThreaded.h
@@ -63,6 +63,7 @@
                         base::unique_fd&& bufferFence, base::unique_fd* drawFence) override;
 
     void cleanFramebufferCache() override;
+    int getContextPriority() override;
 
 private:
     void threadMain(CreateInstanceFactory factory);