blob: a44b804572188a49eb5852fb7788913dd89d75d8 [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
19#include <private/android/AHardwareBufferHelpers.h>
20
21namespace android::uirenderer::renderthread {
22
23// TODO: Re-enable after addressing more of the TODO's
24// With this disabled we won't have a good up-front signal that the surface is no longer valid,
25// however we can at least handle that reactively post-draw. There's just not a good mechanism
26// to propagate this error back to the caller
27constexpr bool DISABLE_BUFFER_PREFETCH = true;
28
29// TODO: Make surface less protected
30// This exists because perform is a varargs, and ANativeWindow has no va_list perform.
31// So wrapping/chaining that is hard. Telling the compiler to ignore protected is easy, so we do
32// that instead
33struct SurfaceExposer : Surface {
34 // Make warnings happy
35 SurfaceExposer() = delete;
36
John Reck848f6512018-12-03 13:26:43 -080037 using Surface::cancelBuffer;
John Reck0fa0cbc2019-04-05 16:57:46 -070038 using Surface::dequeueBuffer;
John Reck848f6512018-12-03 13:26:43 -080039 using Surface::lockBuffer_DEPRECATED;
40 using Surface::perform;
John Reck0fa0cbc2019-04-05 16:57:46 -070041 using Surface::queueBuffer;
42 using Surface::setBufferCount;
43 using Surface::setSwapInterval;
John Reck848f6512018-12-03 13:26:43 -080044};
45
46#define callProtected(surface, func, ...) ((*surface).*&SurfaceExposer::func)(__VA_ARGS__)
47
48ReliableSurface::ReliableSurface(sp<Surface>&& surface) : mSurface(std::move(surface)) {
49 LOG_ALWAYS_FATAL_IF(!mSurface, "Error, unable to wrap a nullptr");
50
51 ANativeWindow::setSwapInterval = hook_setSwapInterval;
52 ANativeWindow::dequeueBuffer = hook_dequeueBuffer;
53 ANativeWindow::cancelBuffer = hook_cancelBuffer;
54 ANativeWindow::queueBuffer = hook_queueBuffer;
55 ANativeWindow::query = hook_query;
56 ANativeWindow::perform = hook_perform;
57
58 ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED;
59 ANativeWindow::cancelBuffer_DEPRECATED = hook_cancelBuffer_DEPRECATED;
60 ANativeWindow::lockBuffer_DEPRECATED = hook_lockBuffer_DEPRECATED;
61 ANativeWindow::queueBuffer_DEPRECATED = hook_queueBuffer_DEPRECATED;
62}
63
64ReliableSurface::~ReliableSurface() {
65 clearReservedBuffer();
66}
67
68void ReliableSurface::perform(int operation, va_list args) {
69 std::lock_guard _lock{mMutex};
70
71 switch (operation) {
72 case NATIVE_WINDOW_SET_USAGE:
73 mUsage = va_arg(args, uint32_t);
74 break;
75 case NATIVE_WINDOW_SET_USAGE64:
76 mUsage = va_arg(args, uint64_t);
77 break;
78 case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
79 /* width */ va_arg(args, uint32_t);
80 /* height */ va_arg(args, uint32_t);
81 mFormat = va_arg(args, PixelFormat);
82 break;
83 case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
84 mFormat = va_arg(args, PixelFormat);
85 break;
86 }
87}
88
89int ReliableSurface::reserveNext() {
John Reck59dd2ea2019-07-26 16:51:08 -070090 if constexpr (DISABLE_BUFFER_PREFETCH) {
91 return OK;
92 }
John Reck848f6512018-12-03 13:26:43 -080093 {
94 std::lock_guard _lock{mMutex};
95 if (mReservedBuffer) {
96 ALOGW("reserveNext called but there was already a buffer reserved?");
97 return OK;
98 }
John Reck59dd2ea2019-07-26 16:51:08 -070099 if (mBufferQueueState != OK) {
John Reck848f6512018-12-03 13:26:43 -0800100 return UNKNOWN_ERROR;
101 }
102 if (mHasDequeuedBuffer) {
103 return OK;
104 }
John Reck848f6512018-12-03 13:26:43 -0800105 }
106
107 // TODO: Update this to better handle when requested dimensions have changed
108 // Currently the driver does this via query + perform but that's after we've already
109 // reserved a buffer. Should we do that logic instead? Or should we drop
110 // the backing Surface to the ground and go full manual on the IGraphicBufferProducer instead?
111
112 int fenceFd = -1;
113 ANativeWindowBuffer* buffer = nullptr;
114 int result = callProtected(mSurface, dequeueBuffer, &buffer, &fenceFd);
115
116 {
117 std::lock_guard _lock{mMutex};
118 LOG_ALWAYS_FATAL_IF(mReservedBuffer, "race condition in reserveNext");
119 mReservedBuffer = buffer;
120 mReservedFenceFd.reset(fenceFd);
121 }
122
123 return result;
124}
125
126void ReliableSurface::clearReservedBuffer() {
127 ANativeWindowBuffer* buffer = nullptr;
128 int releaseFd = -1;
129 {
130 std::lock_guard _lock{mMutex};
131 if (mReservedBuffer) {
132 ALOGW("Reserved buffer %p was never used", mReservedBuffer);
133 buffer = mReservedBuffer;
134 releaseFd = mReservedFenceFd.release();
135 }
136 mReservedBuffer = nullptr;
137 mReservedFenceFd.reset();
138 mHasDequeuedBuffer = false;
139 }
140 if (buffer) {
141 callProtected(mSurface, cancelBuffer, buffer, releaseFd);
142 }
143}
144
145int ReliableSurface::cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd) {
146 clearReservedBuffer();
147 if (isFallbackBuffer(buffer)) {
148 if (fenceFd > 0) {
149 close(fenceFd);
150 }
151 return OK;
152 }
153 int result = callProtected(mSurface, cancelBuffer, buffer, fenceFd);
154 return result;
155}
156
157int ReliableSurface::dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd) {
158 {
159 std::lock_guard _lock{mMutex};
160 if (mReservedBuffer) {
161 *buffer = mReservedBuffer;
162 *fenceFd = mReservedFenceFd.release();
163 mReservedBuffer = nullptr;
164 return OK;
165 }
166 }
167
John Reck59dd2ea2019-07-26 16:51:08 -0700168
John Reck848f6512018-12-03 13:26:43 -0800169 int result = callProtected(mSurface, dequeueBuffer, buffer, fenceFd);
170 if (result != OK) {
171 ALOGW("dequeueBuffer failed, error = %d; switching to fallback", result);
John Reck59dd2ea2019-07-26 16:51:08 -0700172 *buffer = acquireFallbackBuffer(result);
John Reck848f6512018-12-03 13:26:43 -0800173 *fenceFd = -1;
174 return *buffer ? OK : INVALID_OPERATION;
175 } else {
176 std::lock_guard _lock{mMutex};
177 mHasDequeuedBuffer = true;
178 }
179 return OK;
180}
181
182int ReliableSurface::queueBuffer(ANativeWindowBuffer* buffer, int fenceFd) {
183 clearReservedBuffer();
184
185 if (isFallbackBuffer(buffer)) {
186 if (fenceFd > 0) {
187 close(fenceFd);
188 }
189 return OK;
190 }
191
192 int result = callProtected(mSurface, queueBuffer, buffer, fenceFd);
193 return result;
194}
195
196bool ReliableSurface::isFallbackBuffer(const ANativeWindowBuffer* windowBuffer) const {
197 if (!mScratchBuffer || !windowBuffer) {
198 return false;
199 }
200 ANativeWindowBuffer* scratchBuffer =
201 AHardwareBuffer_to_ANativeWindowBuffer(mScratchBuffer.get());
202 return windowBuffer == scratchBuffer;
203}
204
John Reck59dd2ea2019-07-26 16:51:08 -0700205ANativeWindowBuffer* ReliableSurface::acquireFallbackBuffer(int error) {
John Reck848f6512018-12-03 13:26:43 -0800206 std::lock_guard _lock{mMutex};
John Reck59dd2ea2019-07-26 16:51:08 -0700207 mBufferQueueState = error;
John Reck848f6512018-12-03 13:26:43 -0800208
209 if (mScratchBuffer) {
210 return AHardwareBuffer_to_ANativeWindowBuffer(mScratchBuffer.get());
211 }
212
213 AHardwareBuffer_Desc desc;
214 desc.usage = mUsage;
215 desc.format = mFormat;
216 desc.width = 1;
217 desc.height = 1;
218 desc.layers = 1;
219 desc.rfu0 = 0;
220 desc.rfu1 = 0;
221 AHardwareBuffer* newBuffer = nullptr;
222 int err = AHardwareBuffer_allocate(&desc, &newBuffer);
223 if (err) {
224 // Allocate failed, that sucks
225 ALOGW("Failed to allocate scratch buffer, error=%d", err);
226 return nullptr;
227 }
228 mScratchBuffer.reset(newBuffer);
229 return AHardwareBuffer_to_ANativeWindowBuffer(newBuffer);
230}
231
232Surface* ReliableSurface::getWrapped(const ANativeWindow* window) {
233 return getSelf(window)->mSurface.get();
234}
235
236int ReliableSurface::hook_setSwapInterval(ANativeWindow* window, int interval) {
237 return callProtected(getWrapped(window), setSwapInterval, interval);
238}
239
240int ReliableSurface::hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer,
241 int* fenceFd) {
242 return getSelf(window)->dequeueBuffer(buffer, fenceFd);
243}
244
245int ReliableSurface::hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer,
246 int fenceFd) {
247 return getSelf(window)->cancelBuffer(buffer, fenceFd);
248}
249
250int ReliableSurface::hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer,
251 int fenceFd) {
252 return getSelf(window)->queueBuffer(buffer, fenceFd);
253}
254
255int ReliableSurface::hook_dequeueBuffer_DEPRECATED(ANativeWindow* window,
256 ANativeWindowBuffer** buffer) {
257 ANativeWindowBuffer* buf;
258 int fenceFd = -1;
259 int result = window->dequeueBuffer(window, &buf, &fenceFd);
260 if (result != OK) {
261 return result;
262 }
263 sp<Fence> fence(new Fence(fenceFd));
264 int waitResult = fence->waitForever("dequeueBuffer_DEPRECATED");
265 if (waitResult != OK) {
266 ALOGE("dequeueBuffer_DEPRECATED: Fence::wait returned an error: %d", waitResult);
267 window->cancelBuffer(window, buf, -1);
268 return waitResult;
269 }
270 *buffer = buf;
271 return result;
272}
273
274int ReliableSurface::hook_cancelBuffer_DEPRECATED(ANativeWindow* window,
275 ANativeWindowBuffer* buffer) {
276 return window->cancelBuffer(window, buffer, -1);
277}
278
279int ReliableSurface::hook_lockBuffer_DEPRECATED(ANativeWindow* window,
280 ANativeWindowBuffer* buffer) {
281 // This method is a no-op in Surface as well
282 return OK;
283}
284
285int ReliableSurface::hook_queueBuffer_DEPRECATED(ANativeWindow* window,
286 ANativeWindowBuffer* buffer) {
287 return window->queueBuffer(window, buffer, -1);
288}
289
290int ReliableSurface::hook_query(const ANativeWindow* window, int what, int* value) {
291 return getWrapped(window)->query(what, value);
292}
293
294int ReliableSurface::hook_perform(ANativeWindow* window, int operation, ...) {
295 // Drop the reserved buffer if there is one since this (probably) mutated buffer dimensions
296 // TODO: Filter to things that only affect the reserved buffer
297 // TODO: Can we mutate the reserved buffer in some cases?
298 getSelf(window)->clearReservedBuffer();
299 va_list args;
300 va_start(args, operation);
301 int result = callProtected(getWrapped(window), perform, operation, args);
302 va_end(args);
303
John Reck321d8e52019-04-12 13:06:11 -0700304 va_start(args, operation);
305 getSelf(window)->perform(operation, args);
306 va_end(args);
John Reck848f6512018-12-03 13:26:43 -0800307
308 return result;
309}
310
311}; // namespace android::uirenderer::renderthread