Loading libs/hwui/renderthread/CanvasContext.cpp +24 −20 Original line number Diff line number Diff line Loading @@ -143,10 +143,11 @@ void CanvasContext::setSurface(sp<Surface>&& surface, bool enableTimeout) { ATRACE_CALL(); if (surface) { mNativeSurface = new ReliableSurface{std::move(surface)}; mNativeSurface = std::make_unique<ReliableSurface>(std::move(surface)); mNativeSurface->init(); if (enableTimeout) { // TODO: Fix error handling & re-shorten timeout ANativeWindow_setDequeueTimeout(mNativeSurface.get(), 4000_ms); ANativeWindow_setDequeueTimeout(mNativeSurface->getNativeWindow(), 4000_ms); } } else { mNativeSurface = nullptr; Loading @@ -161,7 +162,8 @@ void CanvasContext::setSurface(sp<Surface>&& surface, bool enableTimeout) { } ColorMode colorMode = mWideColorGamut ? ColorMode::WideColorGamut : ColorMode::SRGB; bool hasSurface = mRenderPipeline->setSurface(mNativeSurface.get(), mSwapBehavior, colorMode, bool hasSurface = mRenderPipeline->setSurface( mNativeSurface ? mNativeSurface->getNativeWindow() : nullptr, mSwapBehavior, colorMode, mRenderAheadCapacity); mFrameNumber = -1; Loading Loading @@ -428,7 +430,7 @@ void CanvasContext::setPresentTime() { presentTime = mCurrentFrameInfo->get(FrameInfoIndex::Vsync) + (frameIntervalNanos * (renderAhead + 1)); } native_window_set_buffers_timestamp(mNativeSurface.get(), presentTime); native_window_set_buffers_timestamp(mNativeSurface->getNativeWindow(), presentTime); } void CanvasContext::draw() { Loading Loading @@ -489,16 +491,18 @@ void CanvasContext::draw() { swap.swapCompletedTime = systemTime(SYSTEM_TIME_MONOTONIC); swap.vsyncTime = mRenderThread.timeLord().latestVsync(); if (didDraw) { nsecs_t dequeueStart = ANativeWindow_getLastDequeueStartTime(mNativeSurface.get()); nsecs_t dequeueStart = ANativeWindow_getLastDequeueStartTime(mNativeSurface->getNativeWindow()); if (dequeueStart < mCurrentFrameInfo->get(FrameInfoIndex::SyncStart)) { // Ignoring dequeue duration as it happened prior to frame render start // and thus is not part of the frame. swap.dequeueDuration = 0; } else { swap.dequeueDuration = ANativeWindow_getLastDequeueDuration(mNativeSurface.get()); ANativeWindow_getLastDequeueDuration(mNativeSurface->getNativeWindow()); } swap.queueDuration = ANativeWindow_getLastQueueDuration(mNativeSurface.get()); swap.queueDuration = ANativeWindow_getLastQueueDuration(mNativeSurface->getNativeWindow()); } else { swap.dequeueDuration = 0; swap.queueDuration = 0; Loading Loading @@ -567,15 +571,17 @@ void CanvasContext::doFrame() { } SkISize CanvasContext::getNextFrameSize() const { ReliableSurface* surface = mNativeSurface.get(); if (surface) { static constexpr SkISize defaultFrameSize = {INT32_MAX, INT32_MAX}; if (mNativeSurface == nullptr) { return defaultFrameSize; } ANativeWindow* anw = mNativeSurface->getNativeWindow(); SkISize size; size.fWidth = ANativeWindow_getWidth(surface); size.fHeight = ANativeWindow_getHeight(surface); size.fWidth = ANativeWindow_getWidth(anw); size.fHeight = ANativeWindow_getHeight(anw); return size; } return {INT32_MAX, INT32_MAX}; } void CanvasContext::prepareAndDraw(RenderNode* node) { ATRACE_CALL(); Loading Loading @@ -702,11 +708,9 @@ bool CanvasContext::surfaceRequiresRedraw() { if (!mNativeSurface) return false; if (mHaveNewSurface) return true; int width = -1; int height = -1; ReliableSurface* surface = mNativeSurface.get(); surface->query(NATIVE_WINDOW_WIDTH, &width); surface->query(NATIVE_WINDOW_HEIGHT, &height); ANativeWindow* anw = mNativeSurface->getNativeWindow(); const int width = ANativeWindow_getWidth(anw); const int height = ANativeWindow_getHeight(anw); return width != mLastFrameWidth || height != mLastFrameHeight; } Loading libs/hwui/renderthread/CanvasContext.h +1 −1 Original line number Diff line number Diff line Loading @@ -220,7 +220,7 @@ private: int32_t mLastFrameHeight = 0; RenderThread& mRenderThread; sp<ReliableSurface> mNativeSurface; std::unique_ptr<ReliableSurface> mNativeSurface; // stopped indicates the CanvasContext will reject actual redraw operations, // and defer repaint until it is un-stopped bool mStopped = false; Loading libs/hwui/renderthread/ReliableSurface.cpp +103 −162 Original line number Diff line number Diff line Loading @@ -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>&& 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() { Loading Loading @@ -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}; Loading @@ -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 { Loading Loading @@ -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, ANativeWindow_dequeueBufferFn dequeueBuffer, void* data, ANativeWindowBuffer** buffer, int* fenceFd) { ReliableSurface* rs = reinterpret_cast<ReliableSurface*>(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(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 result = dequeueBuffer(window, buffer, fenceFd); if (result != OK) { 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; } int ReliableSurface::hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd) { return getSelf(window)->queueBuffer(buffer, fenceFd); return OK; } int ReliableSurface::hook_dequeueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer** buffer) { ANativeWindowBuffer* buf; int fenceFd = -1; int result = window->dequeueBuffer(window, &buf, &fenceFd); if (result != OK) { return result; int ReliableSurface::hook_cancelBuffer(ANativeWindow* window, ANativeWindow_cancelBufferFn cancelBuffer, void* data, ANativeWindowBuffer* buffer, int fenceFd) { ReliableSurface* rs = reinterpret_cast<ReliableSurface*>(data); rs->clearReservedBuffer(); if (rs->isFallbackBuffer(buffer)) { if (fenceFd > 0) { close(fenceFd); } sp<Fence> 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; return OK; } *buffer = buf; return result; return cancelBuffer(window, buffer, fenceFd); } int ReliableSurface::hook_cancelBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer) { return window->cancelBuffer(window, buffer, -1); } int ReliableSurface::hook_queueBuffer(ANativeWindow* window, ANativeWindow_queueBufferFn queueBuffer, void* data, ANativeWindowBuffer* buffer, int fenceFd) { ReliableSurface* rs = reinterpret_cast<ReliableSurface*>(data); rs->clearReservedBuffer(); int ReliableSurface::hook_lockBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer) { // This method is a no-op in Surface as well return OK; if (rs->isFallbackBuffer(buffer)) { if (fenceFd > 0) { close(fenceFd); } int ReliableSurface::hook_queueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer) { return window->queueBuffer(window, buffer, -1); 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<ReliableSurface*>(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; } Loading libs/hwui/renderthread/ReliableSurface.h +24 −23 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #pragma once #include <apex/window.h> #include <gui/Surface.h> #include <utils/Macros.h> #include <utils/StrongPointer.h> Loading @@ -24,13 +25,20 @@ namespace android::uirenderer::renderthread { class ReliableSurface : public ANativeObjectBase<ANativeWindow, ReliableSurface, RefBase> { class ReliableSurface { PREVENT_COPY_AND_ASSIGN(ReliableSurface); public: ReliableSurface(sp<Surface>&& surface); ~ReliableSurface(); // Performs initialization that is not safe to do in the constructor. // For instance, registering ANativeWindow interceptors with ReliableSurface // passed as the data pointer is not safe. void init(); ANativeWindow* getNativeWindow() { return mSurface.get(); } int reserveNext(); void allocateBuffers() { mSurface->allocateBuffers(); } Loading Loading @@ -61,7 +69,7 @@ public: } private: const sp<Surface> mSurface; sp<Surface> mSurface; mutable std::mutex mMutex; Loading @@ -78,27 +86,20 @@ private: ANativeWindowBuffer* acquireFallbackBuffer(int error); void clearReservedBuffer(); void perform(int operation, va_list args); int cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd); int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd); int queueBuffer(ANativeWindowBuffer* buffer, int fenceFd); static Surface* getWrapped(const ANativeWindow*); // ANativeWindow hooks static int hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd); static int hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer, int* fenceFd); static int hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd); static int hook_perform(ANativeWindow* window, int operation, ...); static int hook_query(const ANativeWindow* window, int what, int* value); static int hook_setSwapInterval(ANativeWindow* window, int interval); static int hook_cancelBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer); static int hook_dequeueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer** buffer); static int hook_lockBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer); static int hook_queueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer); // ANativeWindow hooks. When an ANativeWindow_* method is called on the // underlying ANativeWindow, these methods will intercept the original call. // For example, an EGL driver would call into these hooks instead of the // original methods. static int hook_cancelBuffer(ANativeWindow* window, ANativeWindow_cancelBufferFn cancelBuffer, void* data, ANativeWindowBuffer* buffer, int fenceFd); static int hook_dequeueBuffer(ANativeWindow* window, ANativeWindow_dequeueBufferFn dequeueBuffer, void* data, ANativeWindowBuffer** buffer, int* fenceFd); static int hook_queueBuffer(ANativeWindow* window, ANativeWindow_queueBufferFn queueBuffer, void* data, ANativeWindowBuffer* buffer, int fenceFd); static int hook_perform(ANativeWindow* window, ANativeWindow_performFn perform, void* data, int operation, va_list args); }; }; // namespace android::uirenderer::renderthread Loading
libs/hwui/renderthread/CanvasContext.cpp +24 −20 Original line number Diff line number Diff line Loading @@ -143,10 +143,11 @@ void CanvasContext::setSurface(sp<Surface>&& surface, bool enableTimeout) { ATRACE_CALL(); if (surface) { mNativeSurface = new ReliableSurface{std::move(surface)}; mNativeSurface = std::make_unique<ReliableSurface>(std::move(surface)); mNativeSurface->init(); if (enableTimeout) { // TODO: Fix error handling & re-shorten timeout ANativeWindow_setDequeueTimeout(mNativeSurface.get(), 4000_ms); ANativeWindow_setDequeueTimeout(mNativeSurface->getNativeWindow(), 4000_ms); } } else { mNativeSurface = nullptr; Loading @@ -161,7 +162,8 @@ void CanvasContext::setSurface(sp<Surface>&& surface, bool enableTimeout) { } ColorMode colorMode = mWideColorGamut ? ColorMode::WideColorGamut : ColorMode::SRGB; bool hasSurface = mRenderPipeline->setSurface(mNativeSurface.get(), mSwapBehavior, colorMode, bool hasSurface = mRenderPipeline->setSurface( mNativeSurface ? mNativeSurface->getNativeWindow() : nullptr, mSwapBehavior, colorMode, mRenderAheadCapacity); mFrameNumber = -1; Loading Loading @@ -428,7 +430,7 @@ void CanvasContext::setPresentTime() { presentTime = mCurrentFrameInfo->get(FrameInfoIndex::Vsync) + (frameIntervalNanos * (renderAhead + 1)); } native_window_set_buffers_timestamp(mNativeSurface.get(), presentTime); native_window_set_buffers_timestamp(mNativeSurface->getNativeWindow(), presentTime); } void CanvasContext::draw() { Loading Loading @@ -489,16 +491,18 @@ void CanvasContext::draw() { swap.swapCompletedTime = systemTime(SYSTEM_TIME_MONOTONIC); swap.vsyncTime = mRenderThread.timeLord().latestVsync(); if (didDraw) { nsecs_t dequeueStart = ANativeWindow_getLastDequeueStartTime(mNativeSurface.get()); nsecs_t dequeueStart = ANativeWindow_getLastDequeueStartTime(mNativeSurface->getNativeWindow()); if (dequeueStart < mCurrentFrameInfo->get(FrameInfoIndex::SyncStart)) { // Ignoring dequeue duration as it happened prior to frame render start // and thus is not part of the frame. swap.dequeueDuration = 0; } else { swap.dequeueDuration = ANativeWindow_getLastDequeueDuration(mNativeSurface.get()); ANativeWindow_getLastDequeueDuration(mNativeSurface->getNativeWindow()); } swap.queueDuration = ANativeWindow_getLastQueueDuration(mNativeSurface.get()); swap.queueDuration = ANativeWindow_getLastQueueDuration(mNativeSurface->getNativeWindow()); } else { swap.dequeueDuration = 0; swap.queueDuration = 0; Loading Loading @@ -567,15 +571,17 @@ void CanvasContext::doFrame() { } SkISize CanvasContext::getNextFrameSize() const { ReliableSurface* surface = mNativeSurface.get(); if (surface) { static constexpr SkISize defaultFrameSize = {INT32_MAX, INT32_MAX}; if (mNativeSurface == nullptr) { return defaultFrameSize; } ANativeWindow* anw = mNativeSurface->getNativeWindow(); SkISize size; size.fWidth = ANativeWindow_getWidth(surface); size.fHeight = ANativeWindow_getHeight(surface); size.fWidth = ANativeWindow_getWidth(anw); size.fHeight = ANativeWindow_getHeight(anw); return size; } return {INT32_MAX, INT32_MAX}; } void CanvasContext::prepareAndDraw(RenderNode* node) { ATRACE_CALL(); Loading Loading @@ -702,11 +708,9 @@ bool CanvasContext::surfaceRequiresRedraw() { if (!mNativeSurface) return false; if (mHaveNewSurface) return true; int width = -1; int height = -1; ReliableSurface* surface = mNativeSurface.get(); surface->query(NATIVE_WINDOW_WIDTH, &width); surface->query(NATIVE_WINDOW_HEIGHT, &height); ANativeWindow* anw = mNativeSurface->getNativeWindow(); const int width = ANativeWindow_getWidth(anw); const int height = ANativeWindow_getHeight(anw); return width != mLastFrameWidth || height != mLastFrameHeight; } Loading
libs/hwui/renderthread/CanvasContext.h +1 −1 Original line number Diff line number Diff line Loading @@ -220,7 +220,7 @@ private: int32_t mLastFrameHeight = 0; RenderThread& mRenderThread; sp<ReliableSurface> mNativeSurface; std::unique_ptr<ReliableSurface> mNativeSurface; // stopped indicates the CanvasContext will reject actual redraw operations, // and defer repaint until it is un-stopped bool mStopped = false; Loading
libs/hwui/renderthread/ReliableSurface.cpp +103 −162 Original line number Diff line number Diff line Loading @@ -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>&& 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() { Loading Loading @@ -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}; Loading @@ -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 { Loading Loading @@ -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, ANativeWindow_dequeueBufferFn dequeueBuffer, void* data, ANativeWindowBuffer** buffer, int* fenceFd) { ReliableSurface* rs = reinterpret_cast<ReliableSurface*>(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(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 result = dequeueBuffer(window, buffer, fenceFd); if (result != OK) { 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; } int ReliableSurface::hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd) { return getSelf(window)->queueBuffer(buffer, fenceFd); return OK; } int ReliableSurface::hook_dequeueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer** buffer) { ANativeWindowBuffer* buf; int fenceFd = -1; int result = window->dequeueBuffer(window, &buf, &fenceFd); if (result != OK) { return result; int ReliableSurface::hook_cancelBuffer(ANativeWindow* window, ANativeWindow_cancelBufferFn cancelBuffer, void* data, ANativeWindowBuffer* buffer, int fenceFd) { ReliableSurface* rs = reinterpret_cast<ReliableSurface*>(data); rs->clearReservedBuffer(); if (rs->isFallbackBuffer(buffer)) { if (fenceFd > 0) { close(fenceFd); } sp<Fence> 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; return OK; } *buffer = buf; return result; return cancelBuffer(window, buffer, fenceFd); } int ReliableSurface::hook_cancelBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer) { return window->cancelBuffer(window, buffer, -1); } int ReliableSurface::hook_queueBuffer(ANativeWindow* window, ANativeWindow_queueBufferFn queueBuffer, void* data, ANativeWindowBuffer* buffer, int fenceFd) { ReliableSurface* rs = reinterpret_cast<ReliableSurface*>(data); rs->clearReservedBuffer(); int ReliableSurface::hook_lockBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer) { // This method is a no-op in Surface as well return OK; if (rs->isFallbackBuffer(buffer)) { if (fenceFd > 0) { close(fenceFd); } int ReliableSurface::hook_queueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer) { return window->queueBuffer(window, buffer, -1); 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<ReliableSurface*>(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; } Loading
libs/hwui/renderthread/ReliableSurface.h +24 −23 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #pragma once #include <apex/window.h> #include <gui/Surface.h> #include <utils/Macros.h> #include <utils/StrongPointer.h> Loading @@ -24,13 +25,20 @@ namespace android::uirenderer::renderthread { class ReliableSurface : public ANativeObjectBase<ANativeWindow, ReliableSurface, RefBase> { class ReliableSurface { PREVENT_COPY_AND_ASSIGN(ReliableSurface); public: ReliableSurface(sp<Surface>&& surface); ~ReliableSurface(); // Performs initialization that is not safe to do in the constructor. // For instance, registering ANativeWindow interceptors with ReliableSurface // passed as the data pointer is not safe. void init(); ANativeWindow* getNativeWindow() { return mSurface.get(); } int reserveNext(); void allocateBuffers() { mSurface->allocateBuffers(); } Loading Loading @@ -61,7 +69,7 @@ public: } private: const sp<Surface> mSurface; sp<Surface> mSurface; mutable std::mutex mMutex; Loading @@ -78,27 +86,20 @@ private: ANativeWindowBuffer* acquireFallbackBuffer(int error); void clearReservedBuffer(); void perform(int operation, va_list args); int cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd); int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd); int queueBuffer(ANativeWindowBuffer* buffer, int fenceFd); static Surface* getWrapped(const ANativeWindow*); // ANativeWindow hooks static int hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd); static int hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer, int* fenceFd); static int hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd); static int hook_perform(ANativeWindow* window, int operation, ...); static int hook_query(const ANativeWindow* window, int what, int* value); static int hook_setSwapInterval(ANativeWindow* window, int interval); static int hook_cancelBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer); static int hook_dequeueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer** buffer); static int hook_lockBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer); static int hook_queueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer); // ANativeWindow hooks. When an ANativeWindow_* method is called on the // underlying ANativeWindow, these methods will intercept the original call. // For example, an EGL driver would call into these hooks instead of the // original methods. static int hook_cancelBuffer(ANativeWindow* window, ANativeWindow_cancelBufferFn cancelBuffer, void* data, ANativeWindowBuffer* buffer, int fenceFd); static int hook_dequeueBuffer(ANativeWindow* window, ANativeWindow_dequeueBufferFn dequeueBuffer, void* data, ANativeWindowBuffer** buffer, int* fenceFd); static int hook_queueBuffer(ANativeWindow* window, ANativeWindow_queueBufferFn queueBuffer, void* data, ANativeWindowBuffer* buffer, int fenceFd); static int hook_perform(ANativeWindow* window, ANativeWindow_performFn perform, void* data, int operation, va_list args); }; }; // namespace android::uirenderer::renderthread