blob: 8a0b4e8455bd9ecfc58b7a1dc1857a8c56ec3f80 [file] [log] [blame]
John Reck848f6512018-12-03 13:26:43 -08001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "ReliableSurface.h"
18
Alec Mouri43fe6fc2019-12-23 07:46:19 -080019#include <log/log_main.h>
John Reck848f6512018-12-03 13:26:43 -080020#include <private/android/AHardwareBufferHelpers.h>
Alec Mouri43fe6fc2019-12-23 07:46:19 -080021// TODO: this should be including apex instead.
22#include <vndk/window.h>
John Reck848f6512018-12-03 13:26:43 -080023
24namespace android::uirenderer::renderthread {
25
26// TODO: Re-enable after addressing more of the TODO's
27// With this disabled we won't have a good up-front signal that the surface is no longer valid,
28// however we can at least handle that reactively post-draw. There's just not a good mechanism
29// to propagate this error back to the caller
30constexpr bool DISABLE_BUFFER_PREFETCH = true;
31
Alec Mouri43fe6fc2019-12-23 07:46:19 -080032ReliableSurface::ReliableSurface(ANativeWindow* window) : mWindow(window) {
33 LOG_ALWAYS_FATAL_IF(!mWindow, "Error, unable to wrap a nullptr");
34 ANativeWindow_acquire(mWindow);
John Reck848f6512018-12-03 13:26:43 -080035}
36
37ReliableSurface::~ReliableSurface() {
38 clearReservedBuffer();
Alec Mourif023a322019-11-25 10:02:21 -080039 // Clear out the interceptors for proper hygiene.
40 // As a concrete example, if the underlying ANativeWindow is associated with
41 // an EGLSurface that is still in use, then if we don't clear out the
42 // interceptors then we walk into undefined behavior.
Alec Mouri43fe6fc2019-12-23 07:46:19 -080043 ANativeWindow_setCancelBufferInterceptor(mWindow, nullptr, nullptr);
44 ANativeWindow_setDequeueBufferInterceptor(mWindow, nullptr, nullptr);
45 ANativeWindow_setQueueBufferInterceptor(mWindow, nullptr, nullptr);
46 ANativeWindow_setPerformInterceptor(mWindow, nullptr, nullptr);
47 ANativeWindow_release(mWindow);
John Reck848f6512018-12-03 13:26:43 -080048}
49
Alec Mourif023a322019-11-25 10:02:21 -080050void ReliableSurface::init() {
Alec Mouri43fe6fc2019-12-23 07:46:19 -080051 int result = ANativeWindow_setCancelBufferInterceptor(mWindow, hook_cancelBuffer, this);
Alec Mourif023a322019-11-25 10:02:21 -080052 LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set cancelBuffer interceptor: error = %d",
53 result);
John Reck848f6512018-12-03 13:26:43 -080054
Alec Mouri43fe6fc2019-12-23 07:46:19 -080055 result = ANativeWindow_setDequeueBufferInterceptor(mWindow, hook_dequeueBuffer, this);
Alec Mourif023a322019-11-25 10:02:21 -080056 LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set dequeueBuffer interceptor: error = %d",
57 result);
58
Alec Mouri43fe6fc2019-12-23 07:46:19 -080059 result = ANativeWindow_setQueueBufferInterceptor(mWindow, hook_queueBuffer, this);
Alec Mourif023a322019-11-25 10:02:21 -080060 LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set queueBuffer interceptor: error = %d",
61 result);
62
Alec Mouri43fe6fc2019-12-23 07:46:19 -080063 result = ANativeWindow_setPerformInterceptor(mWindow, hook_perform, this);
Alec Mourif023a322019-11-25 10:02:21 -080064 LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set perform interceptor: error = %d",
65 result);
John Reck848f6512018-12-03 13:26:43 -080066}
67
68int ReliableSurface::reserveNext() {
John Reck59dd2ea2019-07-26 16:51:08 -070069 if constexpr (DISABLE_BUFFER_PREFETCH) {
70 return OK;
71 }
John Reck848f6512018-12-03 13:26:43 -080072 {
73 std::lock_guard _lock{mMutex};
74 if (mReservedBuffer) {
75 ALOGW("reserveNext called but there was already a buffer reserved?");
76 return OK;
77 }
John Reck59dd2ea2019-07-26 16:51:08 -070078 if (mBufferQueueState != OK) {
John Reck848f6512018-12-03 13:26:43 -080079 return UNKNOWN_ERROR;
80 }
81 if (mHasDequeuedBuffer) {
82 return OK;
83 }
John Reck848f6512018-12-03 13:26:43 -080084 }
85
86 // TODO: Update this to better handle when requested dimensions have changed
87 // Currently the driver does this via query + perform but that's after we've already
88 // reserved a buffer. Should we do that logic instead? Or should we drop
89 // the backing Surface to the ground and go full manual on the IGraphicBufferProducer instead?
90
91 int fenceFd = -1;
92 ANativeWindowBuffer* buffer = nullptr;
Alec Mourif023a322019-11-25 10:02:21 -080093
94 // Note that this calls back into our own hooked method.
Alec Mouri43fe6fc2019-12-23 07:46:19 -080095 int result = ANativeWindow_dequeueBuffer(mWindow, &buffer, &fenceFd);
John Reck848f6512018-12-03 13:26:43 -080096
97 {
98 std::lock_guard _lock{mMutex};
99 LOG_ALWAYS_FATAL_IF(mReservedBuffer, "race condition in reserveNext");
100 mReservedBuffer = buffer;
101 mReservedFenceFd.reset(fenceFd);
102 }
103
104 return result;
105}
106
107void ReliableSurface::clearReservedBuffer() {
108 ANativeWindowBuffer* buffer = nullptr;
109 int releaseFd = -1;
110 {
111 std::lock_guard _lock{mMutex};
112 if (mReservedBuffer) {
113 ALOGW("Reserved buffer %p was never used", mReservedBuffer);
114 buffer = mReservedBuffer;
115 releaseFd = mReservedFenceFd.release();
116 }
117 mReservedBuffer = nullptr;
118 mReservedFenceFd.reset();
119 mHasDequeuedBuffer = false;
120 }
121 if (buffer) {
Alec Mourif023a322019-11-25 10:02:21 -0800122 // Note that clearReservedBuffer may be reentrant here, so
123 // mReservedBuffer must be cleared once we reach here to avoid recursing
124 // forever.
Alec Mouri43fe6fc2019-12-23 07:46:19 -0800125 ANativeWindow_cancelBuffer(mWindow, buffer, releaseFd);
John Reck848f6512018-12-03 13:26:43 -0800126 }
127}
128
John Reck848f6512018-12-03 13:26:43 -0800129bool ReliableSurface::isFallbackBuffer(const ANativeWindowBuffer* windowBuffer) const {
130 if (!mScratchBuffer || !windowBuffer) {
131 return false;
132 }
133 ANativeWindowBuffer* scratchBuffer =
134 AHardwareBuffer_to_ANativeWindowBuffer(mScratchBuffer.get());
135 return windowBuffer == scratchBuffer;
136}
137
John Reck59dd2ea2019-07-26 16:51:08 -0700138ANativeWindowBuffer* ReliableSurface::acquireFallbackBuffer(int error) {
John Reck848f6512018-12-03 13:26:43 -0800139 std::lock_guard _lock{mMutex};
John Reck59dd2ea2019-07-26 16:51:08 -0700140 mBufferQueueState = error;
John Reck848f6512018-12-03 13:26:43 -0800141
142 if (mScratchBuffer) {
143 return AHardwareBuffer_to_ANativeWindowBuffer(mScratchBuffer.get());
144 }
145
146 AHardwareBuffer_Desc desc;
147 desc.usage = mUsage;
148 desc.format = mFormat;
149 desc.width = 1;
150 desc.height = 1;
151 desc.layers = 1;
152 desc.rfu0 = 0;
153 desc.rfu1 = 0;
154 AHardwareBuffer* newBuffer = nullptr;
155 int err = AHardwareBuffer_allocate(&desc, &newBuffer);
156 if (err) {
157 // Allocate failed, that sucks
158 ALOGW("Failed to allocate scratch buffer, error=%d", err);
159 return nullptr;
160 }
161 mScratchBuffer.reset(newBuffer);
162 return AHardwareBuffer_to_ANativeWindowBuffer(newBuffer);
163}
164
Alec Mourif023a322019-11-25 10:02:21 -0800165int ReliableSurface::hook_dequeueBuffer(ANativeWindow* window,
166 ANativeWindow_dequeueBufferFn dequeueBuffer, void* data,
167 ANativeWindowBuffer** buffer, int* fenceFd) {
168 ReliableSurface* rs = reinterpret_cast<ReliableSurface*>(data);
169 {
170 std::lock_guard _lock{rs->mMutex};
171 if (rs->mReservedBuffer) {
172 *buffer = rs->mReservedBuffer;
173 *fenceFd = rs->mReservedFenceFd.release();
174 rs->mReservedBuffer = nullptr;
175 return OK;
176 }
177 }
John Reck848f6512018-12-03 13:26:43 -0800178
Alec Mourif023a322019-11-25 10:02:21 -0800179 int result = dequeueBuffer(window, buffer, fenceFd);
John Reck848f6512018-12-03 13:26:43 -0800180 if (result != OK) {
Alec Mourif023a322019-11-25 10:02:21 -0800181 ALOGW("dequeueBuffer failed, error = %d; switching to fallback", result);
182 *buffer = rs->acquireFallbackBuffer(result);
183 *fenceFd = -1;
184 return *buffer ? OK : INVALID_OPERATION;
185 } else {
186 std::lock_guard _lock{rs->mMutex};
187 rs->mHasDequeuedBuffer = true;
John Reck848f6512018-12-03 13:26:43 -0800188 }
John Reck848f6512018-12-03 13:26:43 -0800189 return OK;
190}
191
Alec Mourif023a322019-11-25 10:02:21 -0800192int ReliableSurface::hook_cancelBuffer(ANativeWindow* window,
193 ANativeWindow_cancelBufferFn cancelBuffer, void* data,
194 ANativeWindowBuffer* buffer, int fenceFd) {
195 ReliableSurface* rs = reinterpret_cast<ReliableSurface*>(data);
196 rs->clearReservedBuffer();
197 if (rs->isFallbackBuffer(buffer)) {
198 if (fenceFd > 0) {
199 close(fenceFd);
200 }
201 return OK;
202 }
203 return cancelBuffer(window, buffer, fenceFd);
John Reck848f6512018-12-03 13:26:43 -0800204}
205
Alec Mourif023a322019-11-25 10:02:21 -0800206int ReliableSurface::hook_queueBuffer(ANativeWindow* window,
207 ANativeWindow_queueBufferFn queueBuffer, void* data,
208 ANativeWindowBuffer* buffer, int fenceFd) {
209 ReliableSurface* rs = reinterpret_cast<ReliableSurface*>(data);
210 rs->clearReservedBuffer();
211
212 if (rs->isFallbackBuffer(buffer)) {
213 if (fenceFd > 0) {
214 close(fenceFd);
215 }
216 return OK;
217 }
218
219 return queueBuffer(window, buffer, fenceFd);
John Reck848f6512018-12-03 13:26:43 -0800220}
221
Alec Mourif023a322019-11-25 10:02:21 -0800222int ReliableSurface::hook_perform(ANativeWindow* window, ANativeWindow_performFn perform,
223 void* data, int operation, va_list args) {
John Reck848f6512018-12-03 13:26:43 -0800224 // Drop the reserved buffer if there is one since this (probably) mutated buffer dimensions
225 // TODO: Filter to things that only affect the reserved buffer
226 // TODO: Can we mutate the reserved buffer in some cases?
Alec Mourif023a322019-11-25 10:02:21 -0800227 ReliableSurface* rs = reinterpret_cast<ReliableSurface*>(data);
228 rs->clearReservedBuffer();
John Reck848f6512018-12-03 13:26:43 -0800229
Alec Mourif023a322019-11-25 10:02:21 -0800230 va_list argsCopy;
231 va_copy(argsCopy, args);
232 int result = perform(window, operation, argsCopy);
John Reck848f6512018-12-03 13:26:43 -0800233
Alec Mourif023a322019-11-25 10:02:21 -0800234 {
235 std::lock_guard _lock{rs->mMutex};
236
237 switch (operation) {
238 case ANATIVEWINDOW_PERFORM_SET_USAGE:
239 rs->mUsage = va_arg(args, uint32_t);
240 break;
241 case ANATIVEWINDOW_PERFORM_SET_USAGE64:
242 rs->mUsage = va_arg(args, uint64_t);
243 break;
244 case ANATIVEWINDOW_PERFORM_SET_BUFFERS_GEOMETRY:
245 /* width */ va_arg(args, uint32_t);
246 /* height */ va_arg(args, uint32_t);
Alec Mouri43fe6fc2019-12-23 07:46:19 -0800247 rs->mFormat = static_cast<AHardwareBuffer_Format>(va_arg(args, int32_t));
Alec Mourif023a322019-11-25 10:02:21 -0800248 break;
249 case ANATIVEWINDOW_PERFORM_SET_BUFFERS_FORMAT:
Alec Mouri43fe6fc2019-12-23 07:46:19 -0800250 rs->mFormat = static_cast<AHardwareBuffer_Format>(va_arg(args, int32_t));
Alec Mourif023a322019-11-25 10:02:21 -0800251 break;
252 }
253 }
John Reck848f6512018-12-03 13:26:43 -0800254 return result;
255}
256
Alec Mouri8d0c5bd22019-08-22 19:20:41 -0700257}; // namespace android::uirenderer::renderthread