Enable RenderEngine context switching to be async.
Also in the case of a threaded RenderEngine we can avoid the
thread hop entirely by quickly returning if the GPU is already
in the correct state.
Bug: 192099706
Test: atest librenderengine_test
Change-Id: I316096ffd89960a1d3742edacdeb442626e9ee3e
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index b5dd8ac..467f848 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -1028,20 +1028,17 @@
return mProtectedEGLContext != EGL_NO_CONTEXT;
}
-bool GLESRenderEngine::useProtectedContext(bool useProtectedContext) {
- if (useProtectedContext == mInProtectedContext) {
- return true;
+void GLESRenderEngine::useProtectedContext(bool useProtectedContext) {
+ if (useProtectedContext == mInProtectedContext ||
+ (useProtectedContext && !supportsProtectedContent())) {
+ return;
}
- if (useProtectedContext && mProtectedEGLContext == EGL_NO_CONTEXT) {
- return false;
- }
+
const EGLSurface surface = useProtectedContext ? mProtectedStubSurface : mStubSurface;
const EGLContext context = useProtectedContext ? mProtectedEGLContext : mEGLContext;
- const bool success = eglMakeCurrent(mEGLDisplay, surface, surface, context) == EGL_TRUE;
- if (success) {
+ if (eglMakeCurrent(mEGLDisplay, surface, surface, context) == EGL_TRUE) {
mInProtectedContext = useProtectedContext;
}
- return success;
}
EGLImageKHR GLESRenderEngine::createFramebufferImageIfNeeded(ANativeWindowBuffer* nativeBuffer,
bool isProtected,
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 915dba3..4cb1b42 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -62,7 +62,7 @@
void deleteTextures(size_t count, uint32_t const* names) override;
bool isProtected() const override { return mInProtectedContext; }
bool supportsProtectedContent() const override;
- bool useProtectedContext(bool useProtectedContext) override;
+ void useProtectedContext(bool useProtectedContext) override;
status_t drawLayers(const DisplaySettings& display,
const std::vector<const LayerSettings*>& layers,
const std::shared_ptr<ExternalTexture>& buffer,
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index ac0affb..5964bc3 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -127,7 +127,7 @@
virtual bool supportsProtectedContent() const = 0;
// Attempt to switch RenderEngine into and out of protectedContext mode
- virtual bool useProtectedContext(bool useProtectedContext) = 0;
+ virtual void useProtectedContext(bool useProtectedContext) = 0;
// Notify RenderEngine of changes to the dimensions of the primary display
// so that it can configure its internal caches accordingly.
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index 0175af3..a4aa9ea 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -44,7 +44,7 @@
MOCK_CONST_METHOD0(getMaxViewportDims, size_t());
MOCK_CONST_METHOD0(isProtected, bool());
MOCK_CONST_METHOD0(supportsProtectedContent, bool());
- MOCK_METHOD1(useProtectedContext, bool(bool));
+ MOCK_METHOD1(useProtectedContext, void(bool));
MOCK_METHOD0(cleanupPostRender, void());
MOCK_CONST_METHOD0(canSkipPostRenderCleanup, bool());
MOCK_METHOD6(drawLayers,
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index c7356ea..3c59f11 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -320,7 +320,8 @@
options.fReducedShaderVariations = true;
options.fPersistentCache = &mSkSLCacheMonitor;
mGrContext = GrDirectContext::MakeGL(glInterface, options);
- if (useProtectedContext(true)) {
+ if (supportsProtectedContent()) {
+ useProtectedContext(true);
mProtectedGrContext = GrDirectContext::MakeGL(glInterface, options);
useProtectedContext(false);
}
@@ -373,12 +374,10 @@
return mInProtectedContext ? mProtectedGrContext.get() : mGrContext.get();
}
-bool SkiaGLRenderEngine::useProtectedContext(bool useProtectedContext) {
- if (useProtectedContext == mInProtectedContext) {
- return true;
- }
- if (useProtectedContext && !supportsProtectedContent()) {
- return false;
+void SkiaGLRenderEngine::useProtectedContext(bool useProtectedContext) {
+ if (useProtectedContext == mInProtectedContext ||
+ (useProtectedContext && !supportsProtectedContent())) {
+ return;
}
// release any scratch resources before switching into a new mode
@@ -389,9 +388,8 @@
const EGLSurface surface =
useProtectedContext ? mProtectedPlaceholderSurface : mPlaceholderSurface;
const EGLContext context = useProtectedContext ? mProtectedEGLContext : mEGLContext;
- const bool success = eglMakeCurrent(mEGLDisplay, surface, surface, context) == EGL_TRUE;
- if (success) {
+ if (eglMakeCurrent(mEGLDisplay, surface, surface, context) == EGL_TRUE) {
mInProtectedContext = useProtectedContext;
// given that we are sharing the same thread between two GrContexts we need to
// make sure that the thread state is reset when switching between the two.
@@ -399,7 +397,6 @@
getActiveGrContext()->resetContext();
}
}
- return success;
}
base::unique_fd SkiaGLRenderEngine::flush() {
@@ -1413,10 +1410,12 @@
getActiveGrContext()->setResourceCacheLimit(maxResourceBytes);
// if it is possible to switch contexts then we will resize the other context
- if (useProtectedContext(!mInProtectedContext)) {
+ const bool originalProtectedState = mInProtectedContext;
+ useProtectedContext(!mInProtectedContext);
+ if (mInProtectedContext != originalProtectedState) {
getActiveGrContext()->setResourceCacheLimit(maxResourceBytes);
// reset back to the initial context that was active when this method was called
- useProtectedContext(!mInProtectedContext);
+ useProtectedContext(originalProtectedState);
}
}
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index b30355b..a852bbc 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -64,7 +64,7 @@
int getContextPriority() override;
bool isProtected() const override { return mInProtectedContext; }
bool supportsProtectedContent() const override;
- bool useProtectedContext(bool useProtectedContext) override;
+ void useProtectedContext(bool useProtectedContext) override;
bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; }
void assertShadersCompiled(int numShaders) override;
void onPrimaryDisplaySizeChanged(ui::Size size) override;
diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h
index 31ad63e..7cd9eca 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.h
+++ b/libs/renderengine/skia/SkiaRenderEngine.h
@@ -44,7 +44,6 @@
virtual void deleteTextures(size_t /*count*/, uint32_t const* /*names*/) override{};
virtual bool isProtected() const override { return false; } // mInProtectedContext; }
virtual bool supportsProtectedContent() const override { return false; };
- virtual bool useProtectedContext(bool /*useProtectedContext*/) override { return false; };
virtual status_t drawLayers(const DisplaySettings& /*display*/,
const std::vector<const LayerSettings*>& /*layers*/,
const std::shared_ptr<ExternalTexture>& /*buffer*/,
diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
index c65e731..830f463 100644
--- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp
+++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
@@ -118,16 +118,26 @@
ASSERT_EQ(true, result);
}
-TEST_F(RenderEngineThreadedTest, useProtectedContext_returnsFalse) {
- EXPECT_CALL(*mRenderEngine, useProtectedContext(false)).WillOnce(Return(false));
- status_t result = mThreadedRE->useProtectedContext(false);
- ASSERT_EQ(false, result);
+TEST_F(RenderEngineThreadedTest, useProtectedContext) {
+ EXPECT_CALL(*mRenderEngine, useProtectedContext(true));
+ auto& ipExpect = EXPECT_CALL(*mRenderEngine, isProtected()).WillOnce(Return(false));
+ EXPECT_CALL(*mRenderEngine, supportsProtectedContent()).WillOnce(Return(true));
+ EXPECT_CALL(*mRenderEngine, isProtected()).After(ipExpect).WillOnce(Return(true));
+
+ mThreadedRE->useProtectedContext(true);
+ ASSERT_EQ(true, mThreadedRE->isProtected());
+
+ // call ANY synchronous function to ensure that useProtectedContext has completed.
+ mThreadedRE->getContextPriority();
+ ASSERT_EQ(true, mThreadedRE->isProtected());
}
-TEST_F(RenderEngineThreadedTest, useProtectedContext_returnsTrue) {
- EXPECT_CALL(*mRenderEngine, useProtectedContext(false)).WillOnce(Return(true));
- status_t result = mThreadedRE->useProtectedContext(false);
- ASSERT_EQ(true, result);
+TEST_F(RenderEngineThreadedTest, useProtectedContext_quickReject) {
+ EXPECT_CALL(*mRenderEngine, useProtectedContext(false)).Times(0);
+ EXPECT_CALL(*mRenderEngine, isProtected()).WillOnce(Return(false));
+ mThreadedRE->useProtectedContext(false);
+ // call ANY synchronous function to ensure that useProtectedContext has completed.
+ mThreadedRE->getContextPriority();
}
TEST_F(RenderEngineThreadedTest, PostRenderCleanup_skipped) {
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp
index ea3871f..b9dabc1 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.cpp
+++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp
@@ -90,6 +90,7 @@
}
mRenderEngine = factory();
+ mIsProtected = mRenderEngine->isProtected();
pthread_setname_np(pthread_self(), mThreadName);
@@ -248,10 +249,8 @@
bool RenderEngineThreaded::isProtected() const {
waitUntilInitialized();
- // ensure that useProtectedContext is not currently being changed by some
- // other thread.
std::lock_guard lock(mThreadMutex);
- return mRenderEngine->isProtected();
+ return mIsProtected;
}
bool RenderEngineThreaded::supportsProtectedContent() const {
@@ -259,20 +258,28 @@
return mRenderEngine->supportsProtectedContent();
}
-bool RenderEngineThreaded::useProtectedContext(bool useProtectedContext) {
- std::promise<bool> resultPromise;
- std::future<bool> resultFuture = resultPromise.get_future();
+void RenderEngineThreaded::useProtectedContext(bool useProtectedContext) {
+ if (isProtected() == useProtectedContext ||
+ (useProtectedContext && !supportsProtectedContent())) {
+ return;
+ }
+
{
std::lock_guard lock(mThreadMutex);
- mFunctionCalls.push(
- [&resultPromise, useProtectedContext](renderengine::RenderEngine& instance) {
- ATRACE_NAME("REThreaded::useProtectedContext");
- bool returnValue = instance.useProtectedContext(useProtectedContext);
- resultPromise.set_value(returnValue);
- });
+ mFunctionCalls.push([useProtectedContext, this](renderengine::RenderEngine& instance) {
+ ATRACE_NAME("REThreaded::useProtectedContext");
+ instance.useProtectedContext(useProtectedContext);
+ if (instance.isProtected() != useProtectedContext) {
+ ALOGE("Failed to switch RenderEngine context.");
+ // reset the cached mIsProtected value to a good state, but this does not
+ // prevent other callers of this method and isProtected from reading the
+ // invalid cached value.
+ mIsProtected = instance.isProtected();
+ }
+ });
+ mIsProtected = useProtectedContext;
}
mCondition.notify_one();
- return resultFuture.get();
}
void RenderEngineThreaded::cleanupPostRender() {
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h
index 9b523b2..f2f5c0f 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.h
+++ b/libs/renderengine/threaded/RenderEngineThreaded.h
@@ -53,7 +53,7 @@
bool isProtected() const override;
bool supportsProtectedContent() const override;
- bool useProtectedContext(bool useProtectedContext) override;
+ void useProtectedContext(bool useProtectedContext) override;
void cleanupPostRender() override;
status_t drawLayers(const DisplaySettings& display,
@@ -100,6 +100,7 @@
* Render Engine
*/
std::unique_ptr<renderengine::RenderEngine> mRenderEngine;
+ std::atomic<bool> mIsProtected = false;
};
} // namespace threaded
} // namespace renderengine