blob: 0ab4cd29f1cd31b4decd6de8065e70528f25df84 [file] [log] [blame]
John Reck650bd9a2018-11-26 09:52:20 -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: Make surface less protected
24// This exists because perform is a varargs, and ANativeWindow has no va_list perform.
25// So wrapping/chaining that is hard. Telling the compiler to ignore protected is easy, so we do
26// that instead
27struct SurfaceExposer : Surface {
28 // Make warnings happy
29 SurfaceExposer() = delete;
30
31 using Surface::setBufferCount;
32 using Surface::setSwapInterval;
33 using Surface::dequeueBuffer;
34 using Surface::queueBuffer;
35 using Surface::cancelBuffer;
36 using Surface::lockBuffer_DEPRECATED;
37 using Surface::perform;
38};
39
40#define callProtected(surface, func, ...) ((*surface).*&SurfaceExposer::func)(__VA_ARGS__)
41
42ReliableSurface::ReliableSurface(sp<Surface>&& surface) : mSurface(std::move(surface)) {
43 LOG_ALWAYS_FATAL_IF(!mSurface, "Error, unable to wrap a nullptr");
44
45 ANativeWindow::setSwapInterval = hook_setSwapInterval;
46 ANativeWindow::dequeueBuffer = hook_dequeueBuffer;
47 ANativeWindow::cancelBuffer = hook_cancelBuffer;
48 ANativeWindow::queueBuffer = hook_queueBuffer;
49 ANativeWindow::query = hook_query;
50 ANativeWindow::perform = hook_perform;
51
52 ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED;
53 ANativeWindow::cancelBuffer_DEPRECATED = hook_cancelBuffer_DEPRECATED;
54 ANativeWindow::lockBuffer_DEPRECATED = hook_lockBuffer_DEPRECATED;
55 ANativeWindow::queueBuffer_DEPRECATED = hook_queueBuffer_DEPRECATED;
56}
57
58void ReliableSurface::perform(int operation, va_list args) {
59 std::lock_guard _lock{mMutex};
60
61 switch (operation) {
62 case NATIVE_WINDOW_SET_USAGE:
63 mUsage = va_arg(args, uint32_t);
64 break;
65 case NATIVE_WINDOW_SET_USAGE64:
66 mUsage = va_arg(args, uint64_t);
67 break;
68 case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
69 /* width */ va_arg(args, uint32_t);
70 /* height */ va_arg(args, uint32_t);
71 mFormat = va_arg(args, PixelFormat);
72 break;
73 case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
74 mFormat = va_arg(args, PixelFormat);
75 break;
76 }
77}
78
79int ReliableSurface::reserveNext() {
80 {
81 std::lock_guard _lock{mMutex};
82 if (mReservedBuffer) {
83 ALOGW("reserveNext called but there was already a buffer reserved?");
84 return OK;
85 }
86 if (mInErrorState) {
87 return UNKNOWN_ERROR;
88 }
89 }
90
91 int fenceFd = -1;
92 ANativeWindowBuffer* buffer = nullptr;
93 int result = callProtected(mSurface, dequeueBuffer, &buffer, &fenceFd);
94
95 {
96 std::lock_guard _lock{mMutex};
97 LOG_ALWAYS_FATAL_IF(mReservedBuffer, "race condition in reserveNext");
98 mReservedBuffer = buffer;
99 mReservedFenceFd.reset(fenceFd);
100 if (result != OK) {
101 ALOGW("reserveNext failed, error %d", result);
102 }
103 }
104
105 return result;
106}
107
108void ReliableSurface::clearReservedBuffer() {
109 std::lock_guard _lock{mMutex};
110 if (mReservedBuffer) {
111 ALOGW("Reserved buffer %p was never used", mReservedBuffer);
112 }
113 mReservedBuffer = nullptr;
114 mReservedFenceFd.reset();
115}
116
117int ReliableSurface::cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd) {
118 clearReservedBuffer();
119 if (isFallbackBuffer(buffer)) {
120 if (fenceFd > 0) {
121 close(fenceFd);
122 }
123 return OK;
124 }
125 int result = callProtected(mSurface, cancelBuffer, buffer, fenceFd);
126 return result;
127}
128
129int ReliableSurface::dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd) {
130 {
131 std::lock_guard _lock{mMutex};
132 if (mReservedBuffer) {
133 *buffer = mReservedBuffer;
134 *fenceFd = mReservedFenceFd.release();
135 mReservedBuffer = nullptr;
136 return OK;
137 }
138 }
139
140 int result = callProtected(mSurface, dequeueBuffer, buffer, fenceFd);
141 if (result != OK) {
142 ALOGW("dequeueBuffer failed, error = %d; switching to fallback", result);
143 *buffer = acquireFallbackBuffer();
144 *fenceFd = -1;
145 return *buffer ? OK : INVALID_OPERATION;
146 }
147 return OK;
148}
149
150int ReliableSurface::queueBuffer(ANativeWindowBuffer* buffer, int fenceFd) {
151 clearReservedBuffer();
152
153 if (isFallbackBuffer(buffer)) {
154 if (fenceFd > 0) {
155 close(fenceFd);
156 }
157 return OK;
158 }
159
160 int result = callProtected(mSurface, queueBuffer, buffer, fenceFd);
161 return result;
162}
163
164bool ReliableSurface::isFallbackBuffer(const ANativeWindowBuffer* windowBuffer) const {
165 if (!mScratchBuffer || !windowBuffer) {
166 return false;
167 }
168 ANativeWindowBuffer* scratchBuffer =
169 AHardwareBuffer_to_ANativeWindowBuffer(mScratchBuffer.get());
170 return windowBuffer == scratchBuffer;
171}
172
173ANativeWindowBuffer* ReliableSurface::acquireFallbackBuffer() {
174 std::lock_guard _lock{mMutex};
175 mInErrorState = true;
176
177 if (mScratchBuffer) {
178 return AHardwareBuffer_to_ANativeWindowBuffer(mScratchBuffer.get());
179 }
180
181 AHardwareBuffer_Desc desc;
182 desc.usage = mUsage;
183 desc.format = mFormat;
184 desc.width = 1;
185 desc.height = 1;
186 desc.layers = 1;
187 desc.rfu0 = 0;
188 desc.rfu1 = 0;
189 AHardwareBuffer* newBuffer = nullptr;
190 int err = AHardwareBuffer_allocate(&desc, &newBuffer);
191 if (err) {
192 // Allocate failed, that sucks
193 ALOGW("Failed to allocate scratch buffer, error=%d", err);
194 return nullptr;
195 }
196 mScratchBuffer.reset(newBuffer);
197 return AHardwareBuffer_to_ANativeWindowBuffer(newBuffer);
198}
199
200Surface* ReliableSurface::getWrapped(const ANativeWindow* window) {
201 return getSelf(window)->mSurface.get();
202}
203
204int ReliableSurface::hook_setSwapInterval(ANativeWindow* window, int interval) {
205 return callProtected(getWrapped(window), setSwapInterval, interval);
206}
207
208int ReliableSurface::hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer,
209 int* fenceFd) {
210 return getSelf(window)->dequeueBuffer(buffer, fenceFd);
211}
212
213int ReliableSurface::hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer,
214 int fenceFd) {
215 return getSelf(window)->cancelBuffer(buffer, fenceFd);
216}
217
218int ReliableSurface::hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer,
219 int fenceFd) {
220 return getSelf(window)->queueBuffer(buffer, fenceFd);
221}
222
223int ReliableSurface::hook_dequeueBuffer_DEPRECATED(ANativeWindow* window,
224 ANativeWindowBuffer** buffer) {
225 ANativeWindowBuffer* buf;
226 int fenceFd = -1;
227 int result = window->dequeueBuffer(window, &buf, &fenceFd);
228 if (result != OK) {
229 return result;
230 }
231 sp<Fence> fence(new Fence(fenceFd));
232 int waitResult = fence->waitForever("dequeueBuffer_DEPRECATED");
233 if (waitResult != OK) {
234 ALOGE("dequeueBuffer_DEPRECATED: Fence::wait returned an error: %d", waitResult);
235 window->cancelBuffer(window, buf, -1);
236 return waitResult;
237 }
238 *buffer = buf;
239 return result;
240}
241
242int ReliableSurface::hook_cancelBuffer_DEPRECATED(ANativeWindow* window,
243 ANativeWindowBuffer* buffer) {
244 return window->cancelBuffer(window, buffer, -1);
245}
246
247int ReliableSurface::hook_lockBuffer_DEPRECATED(ANativeWindow* window,
248 ANativeWindowBuffer* buffer) {
249 // This method is a no-op in Surface as well
250 return OK;
251}
252
253int ReliableSurface::hook_queueBuffer_DEPRECATED(ANativeWindow* window,
254 ANativeWindowBuffer* buffer) {
255 return window->queueBuffer(window, buffer, -1);
256}
257
258int ReliableSurface::hook_query(const ANativeWindow* window, int what, int* value) {
259 return getWrapped(window)->query(what, value);
260}
261
262int ReliableSurface::hook_perform(ANativeWindow* window, int operation, ...) {
263 va_list args;
264 va_start(args, operation);
265 int result = callProtected(getWrapped(window), perform, operation, args);
266 va_end(args);
267
268 switch (operation) {
269 case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
270 case NATIVE_WINDOW_SET_USAGE:
271 case NATIVE_WINDOW_SET_USAGE64:
272 va_start(args, operation);
273 getSelf(window)->perform(operation, args);
274 va_end(args);
275 break;
276 default:
277 break;
278 }
279
280 return result;
281}
282
283}; // namespace android::uirenderer::renderthread