From 59dd2ea974a7f2abfcf6aced764b1e1dc695760b Mon Sep 17 00:00:00 2001 From: John Reck Date: Fri, 26 Jul 2019 16:51:08 -0700 Subject: Fix ReliableSurface to be more reliable Handle TIMED_OUT better by rescheduling (TODO: give up after N attempts?) Fix SYNC_SURFACE_LOST_REWARD_IF_FOUND path to actually go fetch a new surface. Bug: 137509524 Test: Injected errors randomly, verified nothing got permanently dead. Change-Id: Id30f8ad1dd7196041ee84c16c8cf5c814002a6ce --- libs/hwui/renderthread/ReliableSurface.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'libs/hwui/renderthread/ReliableSurface.cpp') diff --git a/libs/hwui/renderthread/ReliableSurface.cpp b/libs/hwui/renderthread/ReliableSurface.cpp index ad1fc4921781..a44b80457218 100644 --- a/libs/hwui/renderthread/ReliableSurface.cpp +++ b/libs/hwui/renderthread/ReliableSurface.cpp @@ -87,21 +87,21 @@ void ReliableSurface::perform(int operation, va_list args) { } int ReliableSurface::reserveNext() { + if constexpr (DISABLE_BUFFER_PREFETCH) { + return OK; + } { std::lock_guard _lock{mMutex}; if (mReservedBuffer) { ALOGW("reserveNext called but there was already a buffer reserved?"); return OK; } - if (mInErrorState) { + if (mBufferQueueState != OK) { return UNKNOWN_ERROR; } if (mHasDequeuedBuffer) { return OK; } - if constexpr (DISABLE_BUFFER_PREFETCH) { - return OK; - } } // TODO: Update this to better handle when requested dimensions have changed @@ -165,10 +165,11 @@ int ReliableSurface::dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd) { } } + int result = callProtected(mSurface, dequeueBuffer, buffer, fenceFd); if (result != OK) { ALOGW("dequeueBuffer failed, error = %d; switching to fallback", result); - *buffer = acquireFallbackBuffer(); + *buffer = acquireFallbackBuffer(result); *fenceFd = -1; return *buffer ? OK : INVALID_OPERATION; } else { @@ -201,9 +202,9 @@ bool ReliableSurface::isFallbackBuffer(const ANativeWindowBuffer* windowBuffer) return windowBuffer == scratchBuffer; } -ANativeWindowBuffer* ReliableSurface::acquireFallbackBuffer() { +ANativeWindowBuffer* ReliableSurface::acquireFallbackBuffer(int error) { std::lock_guard _lock{mMutex}; - mInErrorState = true; + mBufferQueueState = error; if (mScratchBuffer) { return AHardwareBuffer_to_ANativeWindowBuffer(mScratchBuffer.get()); -- cgit v1.2.3 From 8d0c5bd2006118af9d27813b608f35ce901695c9 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Thu, 22 Aug 2019 19:20:41 -0700 Subject: [HWUI] hook in ANativeWindow_getLastDequeueStartTime Bug: 137012798 Test: builds Change-Id: I37fd2a7c40398053082f606f0a085db0a239e2e0 --- libs/hwui/renderthread/ReliableSurface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libs/hwui/renderthread/ReliableSurface.cpp') diff --git a/libs/hwui/renderthread/ReliableSurface.cpp b/libs/hwui/renderthread/ReliableSurface.cpp index a44b80457218..864780fb6ae8 100644 --- a/libs/hwui/renderthread/ReliableSurface.cpp +++ b/libs/hwui/renderthread/ReliableSurface.cpp @@ -308,4 +308,4 @@ int ReliableSurface::hook_perform(ANativeWindow* window, int operation, ...) { return result; } -}; // namespace android::uirenderer::renderthread \ No newline at end of file +}; // namespace android::uirenderer::renderthread -- cgit v1.2.3 From f023a323de7629a9ccd50685a55c70494f907c75 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Mon, 25 Nov 2019 10:02:21 -0800 Subject: [HWUI] Use ANativeWindow inteception methods in ReliableSurface Test: boots Test: manually test with opening and scrolling through settings app Change-Id: I8d7a44d3ead0b2350318e1514153e256f97ccca5 --- libs/hwui/renderthread/ReliableSurface.cpp | 265 +++++++++++------------------ 1 file changed, 103 insertions(+), 162 deletions(-) (limited to 'libs/hwui/renderthread/ReliableSurface.cpp') diff --git a/libs/hwui/renderthread/ReliableSurface.cpp b/libs/hwui/renderthread/ReliableSurface.cpp index 864780fb6ae8..e92500f5be51 100644 --- a/libs/hwui/renderthread/ReliableSurface.cpp +++ b/libs/hwui/renderthread/ReliableSurface.cpp @@ -26,64 +26,38 @@ namespace android::uirenderer::renderthread { // to propagate this error back to the caller constexpr bool DISABLE_BUFFER_PREFETCH = true; -// TODO: Make surface less protected -// This exists because perform is a varargs, and ANativeWindow has no va_list perform. -// So wrapping/chaining that is hard. Telling the compiler to ignore protected is easy, so we do -// that instead -struct SurfaceExposer : Surface { - // Make warnings happy - SurfaceExposer() = delete; - - using Surface::cancelBuffer; - using Surface::dequeueBuffer; - using Surface::lockBuffer_DEPRECATED; - using Surface::perform; - using Surface::queueBuffer; - using Surface::setBufferCount; - using Surface::setSwapInterval; -}; - -#define callProtected(surface, func, ...) ((*surface).*&SurfaceExposer::func)(__VA_ARGS__) - ReliableSurface::ReliableSurface(sp&& surface) : mSurface(std::move(surface)) { LOG_ALWAYS_FATAL_IF(!mSurface, "Error, unable to wrap a nullptr"); - - ANativeWindow::setSwapInterval = hook_setSwapInterval; - ANativeWindow::dequeueBuffer = hook_dequeueBuffer; - ANativeWindow::cancelBuffer = hook_cancelBuffer; - ANativeWindow::queueBuffer = hook_queueBuffer; - ANativeWindow::query = hook_query; - ANativeWindow::perform = hook_perform; - - ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED; - ANativeWindow::cancelBuffer_DEPRECATED = hook_cancelBuffer_DEPRECATED; - ANativeWindow::lockBuffer_DEPRECATED = hook_lockBuffer_DEPRECATED; - ANativeWindow::queueBuffer_DEPRECATED = hook_queueBuffer_DEPRECATED; } ReliableSurface::~ReliableSurface() { clearReservedBuffer(); + // Clear out the interceptors for proper hygiene. + // As a concrete example, if the underlying ANativeWindow is associated with + // an EGLSurface that is still in use, then if we don't clear out the + // interceptors then we walk into undefined behavior. + ANativeWindow_setCancelBufferInterceptor(mSurface.get(), nullptr, nullptr); + ANativeWindow_setDequeueBufferInterceptor(mSurface.get(), nullptr, nullptr); + ANativeWindow_setQueueBufferInterceptor(mSurface.get(), nullptr, nullptr); + ANativeWindow_setPerformInterceptor(mSurface.get(), nullptr, nullptr); } -void ReliableSurface::perform(int operation, va_list args) { - std::lock_guard _lock{mMutex}; +void ReliableSurface::init() { + int result = ANativeWindow_setCancelBufferInterceptor(mSurface.get(), hook_cancelBuffer, this); + LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set cancelBuffer interceptor: error = %d", + result); - switch (operation) { - case NATIVE_WINDOW_SET_USAGE: - mUsage = va_arg(args, uint32_t); - break; - case NATIVE_WINDOW_SET_USAGE64: - mUsage = va_arg(args, uint64_t); - break; - case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY: - /* width */ va_arg(args, uint32_t); - /* height */ va_arg(args, uint32_t); - mFormat = va_arg(args, PixelFormat); - break; - case NATIVE_WINDOW_SET_BUFFERS_FORMAT: - mFormat = va_arg(args, PixelFormat); - break; - } + result = ANativeWindow_setDequeueBufferInterceptor(mSurface.get(), hook_dequeueBuffer, this); + LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set dequeueBuffer interceptor: error = %d", + result); + + result = ANativeWindow_setQueueBufferInterceptor(mSurface.get(), hook_queueBuffer, this); + LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set queueBuffer interceptor: error = %d", + result); + + result = ANativeWindow_setPerformInterceptor(mSurface.get(), hook_perform, this); + LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set perform interceptor: error = %d", + result); } int ReliableSurface::reserveNext() { @@ -111,7 +85,9 @@ int ReliableSurface::reserveNext() { int fenceFd = -1; ANativeWindowBuffer* buffer = nullptr; - int result = callProtected(mSurface, dequeueBuffer, &buffer, &fenceFd); + + // Note that this calls back into our own hooked method. + int result = ANativeWindow_dequeueBuffer(mSurface.get(), &buffer, &fenceFd); { std::lock_guard _lock{mMutex}; @@ -138,59 +114,11 @@ void ReliableSurface::clearReservedBuffer() { mHasDequeuedBuffer = false; } if (buffer) { - callProtected(mSurface, cancelBuffer, buffer, releaseFd); - } -} - -int ReliableSurface::cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd) { - clearReservedBuffer(); - if (isFallbackBuffer(buffer)) { - if (fenceFd > 0) { - close(fenceFd); - } - return OK; - } - int result = callProtected(mSurface, cancelBuffer, buffer, fenceFd); - return result; -} - -int ReliableSurface::dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd) { - { - std::lock_guard _lock{mMutex}; - if (mReservedBuffer) { - *buffer = mReservedBuffer; - *fenceFd = mReservedFenceFd.release(); - mReservedBuffer = nullptr; - return OK; - } - } - - - int result = callProtected(mSurface, dequeueBuffer, buffer, fenceFd); - if (result != OK) { - ALOGW("dequeueBuffer failed, error = %d; switching to fallback", result); - *buffer = acquireFallbackBuffer(result); - *fenceFd = -1; - return *buffer ? OK : INVALID_OPERATION; - } else { - std::lock_guard _lock{mMutex}; - mHasDequeuedBuffer = true; - } - return OK; -} - -int ReliableSurface::queueBuffer(ANativeWindowBuffer* buffer, int fenceFd) { - clearReservedBuffer(); - - if (isFallbackBuffer(buffer)) { - if (fenceFd > 0) { - close(fenceFd); - } - return OK; + // Note that clearReservedBuffer may be reentrant here, so + // mReservedBuffer must be cleared once we reach here to avoid recursing + // forever. + ANativeWindow_cancelBuffer(mSurface.get(), buffer, releaseFd); } - - int result = callProtected(mSurface, queueBuffer, buffer, fenceFd); - return result; } bool ReliableSurface::isFallbackBuffer(const ANativeWindowBuffer* windowBuffer) const { @@ -229,82 +157,95 @@ ANativeWindowBuffer* ReliableSurface::acquireFallbackBuffer(int error) { return AHardwareBuffer_to_ANativeWindowBuffer(newBuffer); } -Surface* ReliableSurface::getWrapped(const ANativeWindow* window) { - return getSelf(window)->mSurface.get(); -} - -int ReliableSurface::hook_setSwapInterval(ANativeWindow* window, int interval) { - return callProtected(getWrapped(window), setSwapInterval, interval); -} - -int ReliableSurface::hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer, - int* fenceFd) { - return getSelf(window)->dequeueBuffer(buffer, fenceFd); -} - -int ReliableSurface::hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, - int fenceFd) { - return getSelf(window)->cancelBuffer(buffer, fenceFd); -} - -int ReliableSurface::hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, - int fenceFd) { - return getSelf(window)->queueBuffer(buffer, fenceFd); -} +int ReliableSurface::hook_dequeueBuffer(ANativeWindow* window, + ANativeWindow_dequeueBufferFn dequeueBuffer, void* data, + ANativeWindowBuffer** buffer, int* fenceFd) { + ReliableSurface* rs = reinterpret_cast(data); + { + std::lock_guard _lock{rs->mMutex}; + if (rs->mReservedBuffer) { + *buffer = rs->mReservedBuffer; + *fenceFd = rs->mReservedFenceFd.release(); + rs->mReservedBuffer = nullptr; + return OK; + } + } -int ReliableSurface::hook_dequeueBuffer_DEPRECATED(ANativeWindow* window, - ANativeWindowBuffer** buffer) { - ANativeWindowBuffer* buf; - int fenceFd = -1; - int result = window->dequeueBuffer(window, &buf, &fenceFd); + int result = dequeueBuffer(window, buffer, fenceFd); if (result != OK) { - return result; - } - sp fence(new Fence(fenceFd)); - int waitResult = fence->waitForever("dequeueBuffer_DEPRECATED"); - if (waitResult != OK) { - ALOGE("dequeueBuffer_DEPRECATED: Fence::wait returned an error: %d", waitResult); - window->cancelBuffer(window, buf, -1); - return waitResult; + ALOGW("dequeueBuffer failed, error = %d; switching to fallback", result); + *buffer = rs->acquireFallbackBuffer(result); + *fenceFd = -1; + return *buffer ? OK : INVALID_OPERATION; + } else { + std::lock_guard _lock{rs->mMutex}; + rs->mHasDequeuedBuffer = true; } - *buffer = buf; - return result; + return OK; } -int ReliableSurface::hook_cancelBuffer_DEPRECATED(ANativeWindow* window, - ANativeWindowBuffer* buffer) { - return window->cancelBuffer(window, buffer, -1); +int ReliableSurface::hook_cancelBuffer(ANativeWindow* window, + ANativeWindow_cancelBufferFn cancelBuffer, void* data, + ANativeWindowBuffer* buffer, int fenceFd) { + ReliableSurface* rs = reinterpret_cast(data); + rs->clearReservedBuffer(); + if (rs->isFallbackBuffer(buffer)) { + if (fenceFd > 0) { + close(fenceFd); + } + return OK; + } + return cancelBuffer(window, buffer, fenceFd); } -int ReliableSurface::hook_lockBuffer_DEPRECATED(ANativeWindow* window, - ANativeWindowBuffer* buffer) { - // This method is a no-op in Surface as well - return OK; -} +int ReliableSurface::hook_queueBuffer(ANativeWindow* window, + ANativeWindow_queueBufferFn queueBuffer, void* data, + ANativeWindowBuffer* buffer, int fenceFd) { + ReliableSurface* rs = reinterpret_cast(data); + rs->clearReservedBuffer(); -int ReliableSurface::hook_queueBuffer_DEPRECATED(ANativeWindow* window, - ANativeWindowBuffer* buffer) { - return window->queueBuffer(window, buffer, -1); -} + if (rs->isFallbackBuffer(buffer)) { + if (fenceFd > 0) { + close(fenceFd); + } + return OK; + } -int ReliableSurface::hook_query(const ANativeWindow* window, int what, int* value) { - return getWrapped(window)->query(what, value); + return queueBuffer(window, buffer, fenceFd); } -int ReliableSurface::hook_perform(ANativeWindow* window, int operation, ...) { +int ReliableSurface::hook_perform(ANativeWindow* window, ANativeWindow_performFn perform, + void* data, int operation, va_list args) { // Drop the reserved buffer if there is one since this (probably) mutated buffer dimensions // TODO: Filter to things that only affect the reserved buffer // TODO: Can we mutate the reserved buffer in some cases? - getSelf(window)->clearReservedBuffer(); - va_list args; - va_start(args, operation); - int result = callProtected(getWrapped(window), perform, operation, args); - va_end(args); + ReliableSurface* rs = reinterpret_cast(data); + rs->clearReservedBuffer(); - va_start(args, operation); - getSelf(window)->perform(operation, args); - va_end(args); + va_list argsCopy; + va_copy(argsCopy, args); + int result = perform(window, operation, argsCopy); + { + std::lock_guard _lock{rs->mMutex}; + + switch (operation) { + case ANATIVEWINDOW_PERFORM_SET_USAGE: + rs->mUsage = va_arg(args, uint32_t); + break; + case ANATIVEWINDOW_PERFORM_SET_USAGE64: + rs->mUsage = va_arg(args, uint64_t); + break; + case ANATIVEWINDOW_PERFORM_SET_BUFFERS_GEOMETRY: + /* width */ va_arg(args, uint32_t); + /* height */ va_arg(args, uint32_t); + rs->mFormat = va_arg(args, PixelFormat); + break; + case ANATIVEWINDOW_PERFORM_SET_BUFFERS_FORMAT: + rs->mFormat = va_arg(args, PixelFormat); + break; + } + } return result; } -- cgit v1.2.3 From 43fe6fcde5cb2630a8d1ffa47d3e6e58e11999ae Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Mon, 23 Dec 2019 07:46:19 -0800 Subject: [HWUI] Remove references to gui/Surface. ANativeWindow usage now has enough feature parity so that we can use that instead. Bug: 137012798 Test: builds Test: Scroll through settings Change-Id: I0054315058b28bcb5e779a6f71a3cfb164625a5f --- libs/hwui/renderthread/ReliableSurface.cpp | 33 +++++++++++++++++------------- 1 file changed, 19 insertions(+), 14 deletions(-) (limited to 'libs/hwui/renderthread/ReliableSurface.cpp') diff --git a/libs/hwui/renderthread/ReliableSurface.cpp b/libs/hwui/renderthread/ReliableSurface.cpp index e92500f5be51..8a0b4e8455bd 100644 --- a/libs/hwui/renderthread/ReliableSurface.cpp +++ b/libs/hwui/renderthread/ReliableSurface.cpp @@ -16,7 +16,10 @@ #include "ReliableSurface.h" +#include #include +// TODO: this should be including apex instead. +#include namespace android::uirenderer::renderthread { @@ -26,8 +29,9 @@ namespace android::uirenderer::renderthread { // to propagate this error back to the caller constexpr bool DISABLE_BUFFER_PREFETCH = true; -ReliableSurface::ReliableSurface(sp&& surface) : mSurface(std::move(surface)) { - LOG_ALWAYS_FATAL_IF(!mSurface, "Error, unable to wrap a nullptr"); +ReliableSurface::ReliableSurface(ANativeWindow* window) : mWindow(window) { + LOG_ALWAYS_FATAL_IF(!mWindow, "Error, unable to wrap a nullptr"); + ANativeWindow_acquire(mWindow); } ReliableSurface::~ReliableSurface() { @@ -36,26 +40,27 @@ ReliableSurface::~ReliableSurface() { // As a concrete example, if the underlying ANativeWindow is associated with // an EGLSurface that is still in use, then if we don't clear out the // interceptors then we walk into undefined behavior. - ANativeWindow_setCancelBufferInterceptor(mSurface.get(), nullptr, nullptr); - ANativeWindow_setDequeueBufferInterceptor(mSurface.get(), nullptr, nullptr); - ANativeWindow_setQueueBufferInterceptor(mSurface.get(), nullptr, nullptr); - ANativeWindow_setPerformInterceptor(mSurface.get(), nullptr, nullptr); + ANativeWindow_setCancelBufferInterceptor(mWindow, nullptr, nullptr); + ANativeWindow_setDequeueBufferInterceptor(mWindow, nullptr, nullptr); + ANativeWindow_setQueueBufferInterceptor(mWindow, nullptr, nullptr); + ANativeWindow_setPerformInterceptor(mWindow, nullptr, nullptr); + ANativeWindow_release(mWindow); } void ReliableSurface::init() { - int result = ANativeWindow_setCancelBufferInterceptor(mSurface.get(), hook_cancelBuffer, this); + int result = ANativeWindow_setCancelBufferInterceptor(mWindow, hook_cancelBuffer, this); LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set cancelBuffer interceptor: error = %d", result); - result = ANativeWindow_setDequeueBufferInterceptor(mSurface.get(), hook_dequeueBuffer, this); + result = ANativeWindow_setDequeueBufferInterceptor(mWindow, hook_dequeueBuffer, this); LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set dequeueBuffer interceptor: error = %d", result); - result = ANativeWindow_setQueueBufferInterceptor(mSurface.get(), hook_queueBuffer, this); + result = ANativeWindow_setQueueBufferInterceptor(mWindow, hook_queueBuffer, this); LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set queueBuffer interceptor: error = %d", result); - result = ANativeWindow_setPerformInterceptor(mSurface.get(), hook_perform, this); + result = ANativeWindow_setPerformInterceptor(mWindow, hook_perform, this); LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set perform interceptor: error = %d", result); } @@ -87,7 +92,7 @@ int ReliableSurface::reserveNext() { ANativeWindowBuffer* buffer = nullptr; // Note that this calls back into our own hooked method. - int result = ANativeWindow_dequeueBuffer(mSurface.get(), &buffer, &fenceFd); + int result = ANativeWindow_dequeueBuffer(mWindow, &buffer, &fenceFd); { std::lock_guard _lock{mMutex}; @@ -117,7 +122,7 @@ void ReliableSurface::clearReservedBuffer() { // Note that clearReservedBuffer may be reentrant here, so // mReservedBuffer must be cleared once we reach here to avoid recursing // forever. - ANativeWindow_cancelBuffer(mSurface.get(), buffer, releaseFd); + ANativeWindow_cancelBuffer(mWindow, buffer, releaseFd); } } @@ -239,10 +244,10 @@ int ReliableSurface::hook_perform(ANativeWindow* window, ANativeWindow_performFn case ANATIVEWINDOW_PERFORM_SET_BUFFERS_GEOMETRY: /* width */ va_arg(args, uint32_t); /* height */ va_arg(args, uint32_t); - rs->mFormat = va_arg(args, PixelFormat); + rs->mFormat = static_cast(va_arg(args, int32_t)); break; case ANATIVEWINDOW_PERFORM_SET_BUFFERS_FORMAT: - rs->mFormat = va_arg(args, PixelFormat); + rs->mFormat = static_cast(va_arg(args, int32_t)); break; } } -- cgit v1.2.3 From 8ddbc59d55881b1595f48facd6f91a4bd2d2453a Mon Sep 17 00:00:00 2001 From: John Reck Date: Thu, 7 May 2020 16:11:18 -0700 Subject: Avoid excessive KGSL maps Hook MIN_UNDEQUEUED_BUFFERS if possible to avoid thrashing kgsl maps when render_ahead is being used Bug: 143555869 Test: verified kgsl maps only happened once per buffer Change-Id: I985fae0a9a7635be3a1cf6177186e5541a1169df --- libs/hwui/renderthread/ReliableSurface.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'libs/hwui/renderthread/ReliableSurface.cpp') diff --git a/libs/hwui/renderthread/ReliableSurface.cpp b/libs/hwui/renderthread/ReliableSurface.cpp index 8a0b4e8455bd..dcf1fc189588 100644 --- a/libs/hwui/renderthread/ReliableSurface.cpp +++ b/libs/hwui/renderthread/ReliableSurface.cpp @@ -19,6 +19,7 @@ #include #include // TODO: this should be including apex instead. +#include #include namespace android::uirenderer::renderthread { @@ -44,6 +45,7 @@ ReliableSurface::~ReliableSurface() { ANativeWindow_setDequeueBufferInterceptor(mWindow, nullptr, nullptr); ANativeWindow_setQueueBufferInterceptor(mWindow, nullptr, nullptr); ANativeWindow_setPerformInterceptor(mWindow, nullptr, nullptr); + ANativeWindow_setQueryInterceptor(mWindow, nullptr, nullptr); ANativeWindow_release(mWindow); } @@ -63,6 +65,10 @@ void ReliableSurface::init() { result = ANativeWindow_setPerformInterceptor(mWindow, hook_perform, this); LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set perform interceptor: error = %d", result); + + result = ANativeWindow_setQueryInterceptor(mWindow, hook_query, this); + LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set query interceptor: error = %d", + result); } int ReliableSurface::reserveNext() { @@ -249,9 +255,29 @@ int ReliableSurface::hook_perform(ANativeWindow* window, ANativeWindow_performFn case ANATIVEWINDOW_PERFORM_SET_BUFFERS_FORMAT: rs->mFormat = static_cast(va_arg(args, int32_t)); break; + case NATIVE_WINDOW_SET_BUFFER_COUNT: + size_t bufferCount = va_arg(args, size_t); + if (bufferCount >= rs->mExpectedBufferCount) { + rs->mDidSetExtraBuffers = true; + } else { + ALOGD("HOOK FAILED! Expected %zd got = %zd", rs->mExpectedBufferCount, bufferCount); + } + break; } } return result; } +int ReliableSurface::hook_query(const ANativeWindow *window, ANativeWindow_queryFn query, + void *data, int what, int *value) { + ReliableSurface* rs = reinterpret_cast(data); + int result = query(window, what, value); + if (what == ANATIVEWINDOW_QUERY_MIN_UNDEQUEUED_BUFFERS && result == OK) { + std::lock_guard _lock{rs->mMutex}; + *value += rs->mExtraBuffers; + rs->mExpectedBufferCount = *value + 2; + } + return result; +} + }; // namespace android::uirenderer::renderthread -- cgit v1.2.3