Merge "Revert "Revert "Make HWUI's surface Reliable^TM"""
This commit is contained in:
@@ -178,6 +178,7 @@ cc_defaults {
|
||||
"renderthread/CanvasContext.cpp",
|
||||
"renderthread/DrawFrameTask.cpp",
|
||||
"renderthread/EglManager.cpp",
|
||||
"renderthread/ReliableSurface.cpp",
|
||||
"renderthread/VulkanManager.cpp",
|
||||
"renderthread/RenderProxy.cpp",
|
||||
"renderthread/RenderTask.cpp",
|
||||
|
||||
@@ -155,7 +155,7 @@ void SkiaOpenGLPipeline::onStop() {
|
||||
}
|
||||
}
|
||||
|
||||
bool SkiaOpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior,
|
||||
bool SkiaOpenGLPipeline::setSurface(ANativeWindow* surface, SwapBehavior swapBehavior,
|
||||
ColorMode colorMode) {
|
||||
if (mEglSurface != EGL_NO_SURFACE) {
|
||||
mEglManager.destroySurface(mEglSurface);
|
||||
|
||||
@@ -42,7 +42,7 @@ public:
|
||||
bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty,
|
||||
FrameInfo* currentFrameInfo, bool* requireSwap) override;
|
||||
DeferredLayerUpdater* createTextureLayer() override;
|
||||
bool setSurface(Surface* window, renderthread::SwapBehavior swapBehavior,
|
||||
bool setSurface(ANativeWindow* surface, renderthread::SwapBehavior swapBehavior,
|
||||
renderthread::ColorMode colorMode) override;
|
||||
void onStop() override;
|
||||
bool isSurfaceReady() override;
|
||||
|
||||
@@ -115,7 +115,7 @@ DeferredLayerUpdater* SkiaVulkanPipeline::createTextureLayer() {
|
||||
|
||||
void SkiaVulkanPipeline::onStop() {}
|
||||
|
||||
bool SkiaVulkanPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior,
|
||||
bool SkiaVulkanPipeline::setSurface(ANativeWindow* surface, SwapBehavior swapBehavior,
|
||||
ColorMode colorMode) {
|
||||
if (mVkSurface) {
|
||||
mVkManager.destroySurface(mVkSurface);
|
||||
|
||||
@@ -38,7 +38,7 @@ public:
|
||||
bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty,
|
||||
FrameInfo* currentFrameInfo, bool* requireSwap) override;
|
||||
DeferredLayerUpdater* createTextureLayer() override;
|
||||
bool setSurface(Surface* window, renderthread::SwapBehavior swapBehavior,
|
||||
bool setSurface(ANativeWindow* surface, renderthread::SwapBehavior swapBehavior,
|
||||
renderthread::ColorMode colorMode) override;
|
||||
void onStop() override;
|
||||
bool isSurfaceReady() override;
|
||||
|
||||
@@ -142,7 +142,12 @@ void CanvasContext::destroy() {
|
||||
void CanvasContext::setSurface(sp<Surface>&& surface) {
|
||||
ATRACE_CALL();
|
||||
|
||||
mNativeSurface = std::move(surface);
|
||||
if (surface) {
|
||||
mNativeSurface = new ReliableSurface{std::move(surface)};
|
||||
mNativeSurface->setDequeueTimeout(500_ms);
|
||||
} else {
|
||||
mNativeSurface = nullptr;
|
||||
}
|
||||
|
||||
ColorMode colorMode = mWideColorGamut ? ColorMode::WideColorGamut : ColorMode::SRGB;
|
||||
bool hasSurface = mRenderPipeline->setSurface(mNativeSurface.get(), mSwapBehavior, colorMode);
|
||||
@@ -285,10 +290,11 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy
|
||||
|
||||
info.damageAccumulator = &mDamageAccumulator;
|
||||
info.layerUpdateQueue = &mLayerUpdateQueue;
|
||||
info.out.canDrawThisFrame = true;
|
||||
|
||||
mAnimationContext->startFrame(info.mode);
|
||||
mRenderPipeline->onPrepareTree();
|
||||
for (const sp<RenderNode>& node : mRenderNodes) {
|
||||
for (const sp<RenderNode> &node : mRenderNodes) {
|
||||
// Only the primary target node will be drawn full - all other nodes would get drawn in
|
||||
// real time mode. In case of a window, the primary node is the window content and the other
|
||||
// node(s) are non client / filler nodes.
|
||||
@@ -304,7 +310,7 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy
|
||||
|
||||
mIsDirty = true;
|
||||
|
||||
if (CC_UNLIKELY(!mNativeSurface.get())) {
|
||||
if (CC_UNLIKELY(!hasSurface())) {
|
||||
mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
|
||||
info.out.canDrawThisFrame = false;
|
||||
return;
|
||||
@@ -312,7 +318,7 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy
|
||||
|
||||
if (CC_LIKELY(mSwapHistory.size() && !Properties::forceDrawFrame)) {
|
||||
nsecs_t latestVsync = mRenderThread.timeLord().latestVsync();
|
||||
SwapHistory& lastSwap = mSwapHistory.back();
|
||||
SwapHistory &lastSwap = mSwapHistory.back();
|
||||
nsecs_t vsyncDelta = std::abs(lastSwap.vsyncTime - latestVsync);
|
||||
// The slight fudge-factor is to deal with cases where
|
||||
// the vsync was estimated due to being slow handling the signal.
|
||||
@@ -333,7 +339,19 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy
|
||||
info.out.canDrawThisFrame = false;
|
||||
}
|
||||
|
||||
if (!info.out.canDrawThisFrame) {
|
||||
if (info.out.canDrawThisFrame) {
|
||||
int err = mNativeSurface->reserveNext();
|
||||
if (err != OK) {
|
||||
mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
|
||||
info.out.canDrawThisFrame = false;
|
||||
ALOGW("reserveNext failed, error = %d (%s)", err, strerror(-err));
|
||||
if (err != TIMED_OUT) {
|
||||
// A timed out surface can still recover, but assume others are permanently dead.
|
||||
setSurface(nullptr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "IRenderPipeline.h"
|
||||
#include "LayerUpdateQueue.h"
|
||||
#include "RenderNode.h"
|
||||
#include "ReliableSurface.h"
|
||||
#include "renderthread/RenderTask.h"
|
||||
#include "renderthread/RenderThread.h"
|
||||
#include "thread/Task.h"
|
||||
@@ -219,7 +220,7 @@ private:
|
||||
EGLint mLastFrameHeight = 0;
|
||||
|
||||
RenderThread& mRenderThread;
|
||||
sp<Surface> mNativeSurface;
|
||||
sp<ReliableSurface> mNativeSurface;
|
||||
// stopped indicates the CanvasContext will reject actual redraw operations,
|
||||
// and defer repaint until it is un-stopped
|
||||
bool mStopped = false;
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <system/window.h>
|
||||
#include <gui/Surface.h>
|
||||
|
||||
#define GLES_VERSION 2
|
||||
|
||||
@@ -106,7 +108,7 @@ void EglManager::initialize() {
|
||||
LOG_ALWAYS_FATAL_IF(eglInitialize(mEglDisplay, &major, &minor) == EGL_FALSE,
|
||||
"Failed to initialize display %p! err=%s", mEglDisplay, eglErrorString());
|
||||
|
||||
ALOGI("Initialized EGL, version %d.%d", (int)major, (int)minor);
|
||||
ALOGV("Initialized EGL, version %d.%d", (int)major, (int)minor);
|
||||
|
||||
initExtensions();
|
||||
|
||||
|
||||
@@ -28,9 +28,9 @@
|
||||
|
||||
class GrContext;
|
||||
|
||||
namespace android {
|
||||
struct ANativeWindow;
|
||||
|
||||
class Surface;
|
||||
namespace android {
|
||||
|
||||
namespace uirenderer {
|
||||
|
||||
@@ -67,7 +67,7 @@ public:
|
||||
virtual bool swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
|
||||
FrameInfo* currentFrameInfo, bool* requireSwap) = 0;
|
||||
virtual DeferredLayerUpdater* createTextureLayer() = 0;
|
||||
virtual bool setSurface(Surface* window, SwapBehavior swapBehavior, ColorMode colorMode) = 0;
|
||||
virtual bool setSurface(ANativeWindow* window, SwapBehavior swapBehavior, ColorMode colorMode) = 0;
|
||||
virtual void onStop() = 0;
|
||||
virtual bool isSurfaceReady() = 0;
|
||||
virtual bool isContextReady() = 0;
|
||||
|
||||
318
libs/hwui/renderthread/ReliableSurface.cpp
Normal file
318
libs/hwui/renderthread/ReliableSurface.cpp
Normal file
@@ -0,0 +1,318 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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 "ReliableSurface.h"
|
||||
|
||||
#include <private/android/AHardwareBufferHelpers.h>
|
||||
|
||||
namespace android::uirenderer::renderthread {
|
||||
|
||||
// TODO: Re-enable after addressing more of the TODO's
|
||||
// With this disabled we won't have a good up-front signal that the surface is no longer valid,
|
||||
// however we can at least handle that reactively post-draw. There's just not a good mechanism
|
||||
// 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::setBufferCount;
|
||||
using Surface::setSwapInterval;
|
||||
using Surface::dequeueBuffer;
|
||||
using Surface::queueBuffer;
|
||||
using Surface::cancelBuffer;
|
||||
using Surface::lockBuffer_DEPRECATED;
|
||||
using Surface::perform;
|
||||
};
|
||||
|
||||
#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();
|
||||
}
|
||||
|
||||
void ReliableSurface::perform(int operation, va_list args) {
|
||||
std::lock_guard _lock{mMutex};
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
int ReliableSurface::reserveNext() {
|
||||
{
|
||||
std::lock_guard _lock{mMutex};
|
||||
if (mReservedBuffer) {
|
||||
ALOGW("reserveNext called but there was already a buffer reserved?");
|
||||
return OK;
|
||||
}
|
||||
if (mInErrorState) {
|
||||
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
|
||||
// Currently the driver does this via query + perform but that's after we've already
|
||||
// reserved a buffer. Should we do that logic instead? Or should we drop
|
||||
// the backing Surface to the ground and go full manual on the IGraphicBufferProducer instead?
|
||||
|
||||
int fenceFd = -1;
|
||||
ANativeWindowBuffer* buffer = nullptr;
|
||||
int result = callProtected(mSurface, dequeueBuffer, &buffer, &fenceFd);
|
||||
|
||||
{
|
||||
std::lock_guard _lock{mMutex};
|
||||
LOG_ALWAYS_FATAL_IF(mReservedBuffer, "race condition in reserveNext");
|
||||
mReservedBuffer = buffer;
|
||||
mReservedFenceFd.reset(fenceFd);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void ReliableSurface::clearReservedBuffer() {
|
||||
ANativeWindowBuffer* buffer = nullptr;
|
||||
int releaseFd = -1;
|
||||
{
|
||||
std::lock_guard _lock{mMutex};
|
||||
if (mReservedBuffer) {
|
||||
ALOGW("Reserved buffer %p was never used", mReservedBuffer);
|
||||
buffer = mReservedBuffer;
|
||||
releaseFd = mReservedFenceFd.release();
|
||||
}
|
||||
mReservedBuffer = nullptr;
|
||||
mReservedFenceFd.reset();
|
||||
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();
|
||||
*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;
|
||||
}
|
||||
|
||||
int result = callProtected(mSurface, queueBuffer, buffer, fenceFd);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ReliableSurface::isFallbackBuffer(const ANativeWindowBuffer* windowBuffer) const {
|
||||
if (!mScratchBuffer || !windowBuffer) {
|
||||
return false;
|
||||
}
|
||||
ANativeWindowBuffer* scratchBuffer =
|
||||
AHardwareBuffer_to_ANativeWindowBuffer(mScratchBuffer.get());
|
||||
return windowBuffer == scratchBuffer;
|
||||
}
|
||||
|
||||
ANativeWindowBuffer* ReliableSurface::acquireFallbackBuffer() {
|
||||
std::lock_guard _lock{mMutex};
|
||||
mInErrorState = true;
|
||||
|
||||
if (mScratchBuffer) {
|
||||
return AHardwareBuffer_to_ANativeWindowBuffer(mScratchBuffer.get());
|
||||
}
|
||||
|
||||
AHardwareBuffer_Desc desc;
|
||||
desc.usage = mUsage;
|
||||
desc.format = mFormat;
|
||||
desc.width = 1;
|
||||
desc.height = 1;
|
||||
desc.layers = 1;
|
||||
desc.rfu0 = 0;
|
||||
desc.rfu1 = 0;
|
||||
AHardwareBuffer* newBuffer = nullptr;
|
||||
int err = AHardwareBuffer_allocate(&desc, &newBuffer);
|
||||
if (err) {
|
||||
// Allocate failed, that sucks
|
||||
ALOGW("Failed to allocate scratch buffer, error=%d", err);
|
||||
return nullptr;
|
||||
}
|
||||
mScratchBuffer.reset(newBuffer);
|
||||
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_DEPRECATED(ANativeWindow* window,
|
||||
ANativeWindowBuffer** buffer) {
|
||||
ANativeWindowBuffer* buf;
|
||||
int fenceFd = -1;
|
||||
int result = window->dequeueBuffer(window, &buf, &fenceFd);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
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;
|
||||
}
|
||||
*buffer = buf;
|
||||
return result;
|
||||
}
|
||||
|
||||
int ReliableSurface::hook_cancelBuffer_DEPRECATED(ANativeWindow* window,
|
||||
ANativeWindowBuffer* buffer) {
|
||||
return window->cancelBuffer(window, buffer, -1);
|
||||
}
|
||||
|
||||
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_DEPRECATED(ANativeWindow* window,
|
||||
ANativeWindowBuffer* buffer) {
|
||||
return window->queueBuffer(window, buffer, -1);
|
||||
}
|
||||
|
||||
int ReliableSurface::hook_query(const ANativeWindow* window, int what, int* value) {
|
||||
return getWrapped(window)->query(what, value);
|
||||
}
|
||||
|
||||
int ReliableSurface::hook_perform(ANativeWindow* window, int operation, ...) {
|
||||
// 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);
|
||||
|
||||
switch (operation) {
|
||||
case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
|
||||
case NATIVE_WINDOW_SET_USAGE:
|
||||
case NATIVE_WINDOW_SET_USAGE64:
|
||||
va_start(args, operation);
|
||||
getSelf(window)->perform(operation, args);
|
||||
va_end(args);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}; // namespace android::uirenderer::renderthread
|
||||
87
libs/hwui/renderthread/ReliableSurface.h
Normal file
87
libs/hwui/renderthread/ReliableSurface.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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 <gui/Surface.h>
|
||||
#include <utils/Macros.h>
|
||||
#include <utils/StrongPointer.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace android::uirenderer::renderthread {
|
||||
|
||||
class ReliableSurface : public ANativeObjectBase<ANativeWindow, ReliableSurface, RefBase> {
|
||||
PREVENT_COPY_AND_ASSIGN(ReliableSurface);
|
||||
|
||||
public:
|
||||
ReliableSurface(sp<Surface>&& surface);
|
||||
~ReliableSurface();
|
||||
|
||||
void setDequeueTimeout(nsecs_t timeout) { mSurface->setDequeueTimeout(timeout); }
|
||||
|
||||
int reserveNext();
|
||||
|
||||
void allocateBuffers() { mSurface->allocateBuffers(); }
|
||||
|
||||
int query(int what, int* value) const { return mSurface->query(what, value); }
|
||||
|
||||
nsecs_t getLastDequeueStartTime() const { return mSurface->getLastDequeueStartTime(); }
|
||||
|
||||
uint64_t getNextFrameNumber() const { return mSurface->getNextFrameNumber(); }
|
||||
|
||||
private:
|
||||
const sp<Surface> mSurface;
|
||||
|
||||
mutable std::mutex mMutex;
|
||||
|
||||
uint64_t mUsage = AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER;
|
||||
PixelFormat mFormat = PIXEL_FORMAT_RGBA_8888;
|
||||
std::unique_ptr<AHardwareBuffer, void (*)(AHardwareBuffer*)> mScratchBuffer{
|
||||
nullptr, AHardwareBuffer_release};
|
||||
ANativeWindowBuffer* mReservedBuffer = nullptr;
|
||||
base::unique_fd mReservedFenceFd;
|
||||
bool mHasDequeuedBuffer = false;
|
||||
bool mInErrorState = false;
|
||||
|
||||
bool isFallbackBuffer(const ANativeWindowBuffer* windowBuffer) const;
|
||||
ANativeWindowBuffer* acquireFallbackBuffer();
|
||||
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);
|
||||
};
|
||||
|
||||
}; // namespace android::uirenderer::renderthread
|
||||
Reference in New Issue
Block a user