blob: e92500f5be514e9cf4e67ab7dd9b1ef1d46d6c6e [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
John Reck848f6512018-12-03 13:26:43 -080029ReliableSurface::ReliableSurface(sp<Surface>&& surface) : mSurface(std::move(surface)) {
30 LOG_ALWAYS_FATAL_IF(!mSurface, "Error, unable to wrap a nullptr");
John Reck848f6512018-12-03 13:26:43 -080031}
32
33ReliableSurface::~ReliableSurface() {
34 clearReservedBuffer();
Alec Mourif023a322019-11-25 10:02:21 -080035 // Clear out the interceptors for proper hygiene.
36 // As a concrete example, if the underlying ANativeWindow is associated with
37 // an EGLSurface that is still in use, then if we don't clear out the
38 // interceptors then we walk into undefined behavior.
39 ANativeWindow_setCancelBufferInterceptor(mSurface.get(), nullptr, nullptr);
40 ANativeWindow_setDequeueBufferInterceptor(mSurface.get(), nullptr, nullptr);
41 ANativeWindow_setQueueBufferInterceptor(mSurface.get(), nullptr, nullptr);
42 ANativeWindow_setPerformInterceptor(mSurface.get(), nullptr, nullptr);
John Reck848f6512018-12-03 13:26:43 -080043}
44
Alec Mourif023a322019-11-25 10:02:21 -080045void ReliableSurface::init() {
46 int result = ANativeWindow_setCancelBufferInterceptor(mSurface.get(), hook_cancelBuffer, this);
47 LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set cancelBuffer interceptor: error = %d",
48 result);
John Reck848f6512018-12-03 13:26:43 -080049
Alec Mourif023a322019-11-25 10:02:21 -080050 result = ANativeWindow_setDequeueBufferInterceptor(mSurface.get(), hook_dequeueBuffer, this);
51 LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set dequeueBuffer interceptor: error = %d",
52 result);
53
54 result = ANativeWindow_setQueueBufferInterceptor(mSurface.get(), hook_queueBuffer, this);
55 LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set queueBuffer interceptor: error = %d",
56 result);
57
58 result = ANativeWindow_setPerformInterceptor(mSurface.get(), hook_perform, this);
59 LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set perform interceptor: error = %d",
60 result);
John Reck848f6512018-12-03 13:26:43 -080061}
62
63int ReliableSurface::reserveNext() {
John Reck59dd2ea2019-07-26 16:51:08 -070064 if constexpr (DISABLE_BUFFER_PREFETCH) {
65 return OK;
66 }
John Reck848f6512018-12-03 13:26:43 -080067 {
68 std::lock_guard _lock{mMutex};
69 if (mReservedBuffer) {
70 ALOGW("reserveNext called but there was already a buffer reserved?");
71 return OK;
72 }
John Reck59dd2ea2019-07-26 16:51:08 -070073 if (mBufferQueueState != OK) {
John Reck848f6512018-12-03 13:26:43 -080074 return UNKNOWN_ERROR;
75 }
76 if (mHasDequeuedBuffer) {
77 return OK;
78 }
John Reck848f6512018-12-03 13:26:43 -080079 }
80
81 // TODO: Update this to better handle when requested dimensions have changed
82 // Currently the driver does this via query + perform but that's after we've already
83 // reserved a buffer. Should we do that logic instead? Or should we drop
84 // the backing Surface to the ground and go full manual on the IGraphicBufferProducer instead?
85
86 int fenceFd = -1;
87 ANativeWindowBuffer* buffer = nullptr;
Alec Mourif023a322019-11-25 10:02:21 -080088
89 // Note that this calls back into our own hooked method.
90 int result = ANativeWindow_dequeueBuffer(mSurface.get(), &buffer, &fenceFd);
John Reck848f6512018-12-03 13:26:43 -080091
92 {
93 std::lock_guard _lock{mMutex};
94 LOG_ALWAYS_FATAL_IF(mReservedBuffer, "race condition in reserveNext");
95 mReservedBuffer = buffer;
96 mReservedFenceFd.reset(fenceFd);
97 }
98
99 return result;
100}
101
102void ReliableSurface::clearReservedBuffer() {
103 ANativeWindowBuffer* buffer = nullptr;
104 int releaseFd = -1;
105 {
106 std::lock_guard _lock{mMutex};
107 if (mReservedBuffer) {
108 ALOGW("Reserved buffer %p was never used", mReservedBuffer);
109 buffer = mReservedBuffer;
110 releaseFd = mReservedFenceFd.release();
111 }
112 mReservedBuffer = nullptr;
113 mReservedFenceFd.reset();
114 mHasDequeuedBuffer = false;
115 }
116 if (buffer) {
Alec Mourif023a322019-11-25 10:02:21 -0800117 // Note that clearReservedBuffer may be reentrant here, so
118 // mReservedBuffer must be cleared once we reach here to avoid recursing
119 // forever.
120 ANativeWindow_cancelBuffer(mSurface.get(), buffer, releaseFd);
John Reck848f6512018-12-03 13:26:43 -0800121 }
122}
123
John Reck848f6512018-12-03 13:26:43 -0800124bool ReliableSurface::isFallbackBuffer(const ANativeWindowBuffer* windowBuffer) const {
125 if (!mScratchBuffer || !windowBuffer) {
126 return false;
127 }
128 ANativeWindowBuffer* scratchBuffer =
129 AHardwareBuffer_to_ANativeWindowBuffer(mScratchBuffer.get());
130 return windowBuffer == scratchBuffer;
131}
132
John Reck59dd2ea2019-07-26 16:51:08 -0700133ANativeWindowBuffer* ReliableSurface::acquireFallbackBuffer(int error) {
John Reck848f6512018-12-03 13:26:43 -0800134 std::lock_guard _lock{mMutex};
John Reck59dd2ea2019-07-26 16:51:08 -0700135 mBufferQueueState = error;
John Reck848f6512018-12-03 13:26:43 -0800136
137 if (mScratchBuffer) {
138 return AHardwareBuffer_to_ANativeWindowBuffer(mScratchBuffer.get());
139 }
140
141 AHardwareBuffer_Desc desc;
142 desc.usage = mUsage;
143 desc.format = mFormat;
144 desc.width = 1;
145 desc.height = 1;
146 desc.layers = 1;
147 desc.rfu0 = 0;
148 desc.rfu1 = 0;
149 AHardwareBuffer* newBuffer = nullptr;
150 int err = AHardwareBuffer_allocate(&desc, &newBuffer);
151 if (err) {
152 // Allocate failed, that sucks
153 ALOGW("Failed to allocate scratch buffer, error=%d", err);
154 return nullptr;
155 }
156 mScratchBuffer.reset(newBuffer);
157 return AHardwareBuffer_to_ANativeWindowBuffer(newBuffer);
158}
159
Alec Mourif023a322019-11-25 10:02:21 -0800160int ReliableSurface::hook_dequeueBuffer(ANativeWindow* window,
161 ANativeWindow_dequeueBufferFn dequeueBuffer, void* data,
162 ANativeWindowBuffer** buffer, int* fenceFd) {
163 ReliableSurface* rs = reinterpret_cast<ReliableSurface*>(data);
164 {
165 std::lock_guard _lock{rs->mMutex};
166 if (rs->mReservedBuffer) {
167 *buffer = rs->mReservedBuffer;
168 *fenceFd = rs->mReservedFenceFd.release();
169 rs->mReservedBuffer = nullptr;
170 return OK;
171 }
172 }
John Reck848f6512018-12-03 13:26:43 -0800173
Alec Mourif023a322019-11-25 10:02:21 -0800174 int result = dequeueBuffer(window, buffer, fenceFd);
John Reck848f6512018-12-03 13:26:43 -0800175 if (result != OK) {
Alec Mourif023a322019-11-25 10:02:21 -0800176 ALOGW("dequeueBuffer failed, error = %d; switching to fallback", result);
177 *buffer = rs->acquireFallbackBuffer(result);
178 *fenceFd = -1;
179 return *buffer ? OK : INVALID_OPERATION;
180 } else {
181 std::lock_guard _lock{rs->mMutex};
182 rs->mHasDequeuedBuffer = true;
John Reck848f6512018-12-03 13:26:43 -0800183 }
John Reck848f6512018-12-03 13:26:43 -0800184 return OK;
185}
186
Alec Mourif023a322019-11-25 10:02:21 -0800187int ReliableSurface::hook_cancelBuffer(ANativeWindow* window,
188 ANativeWindow_cancelBufferFn cancelBuffer, void* data,
189 ANativeWindowBuffer* buffer, int fenceFd) {
190 ReliableSurface* rs = reinterpret_cast<ReliableSurface*>(data);
191 rs->clearReservedBuffer();
192 if (rs->isFallbackBuffer(buffer)) {
193 if (fenceFd > 0) {
194 close(fenceFd);
195 }
196 return OK;
197 }
198 return cancelBuffer(window, buffer, fenceFd);
John Reck848f6512018-12-03 13:26:43 -0800199}
200
Alec Mourif023a322019-11-25 10:02:21 -0800201int ReliableSurface::hook_queueBuffer(ANativeWindow* window,
202 ANativeWindow_queueBufferFn queueBuffer, void* data,
203 ANativeWindowBuffer* buffer, int fenceFd) {
204 ReliableSurface* rs = reinterpret_cast<ReliableSurface*>(data);
205 rs->clearReservedBuffer();
206
207 if (rs->isFallbackBuffer(buffer)) {
208 if (fenceFd > 0) {
209 close(fenceFd);
210 }
211 return OK;
212 }
213
214 return queueBuffer(window, buffer, fenceFd);
John Reck848f6512018-12-03 13:26:43 -0800215}
216
Alec Mourif023a322019-11-25 10:02:21 -0800217int ReliableSurface::hook_perform(ANativeWindow* window, ANativeWindow_performFn perform,
218 void* data, int operation, va_list args) {
John Reck848f6512018-12-03 13:26:43 -0800219 // Drop the reserved buffer if there is one since this (probably) mutated buffer dimensions
220 // TODO: Filter to things that only affect the reserved buffer
221 // TODO: Can we mutate the reserved buffer in some cases?
Alec Mourif023a322019-11-25 10:02:21 -0800222 ReliableSurface* rs = reinterpret_cast<ReliableSurface*>(data);
223 rs->clearReservedBuffer();
John Reck848f6512018-12-03 13:26:43 -0800224
Alec Mourif023a322019-11-25 10:02:21 -0800225 va_list argsCopy;
226 va_copy(argsCopy, args);
227 int result = perform(window, operation, argsCopy);
John Reck848f6512018-12-03 13:26:43 -0800228
Alec Mourif023a322019-11-25 10:02:21 -0800229 {
230 std::lock_guard _lock{rs->mMutex};
231
232 switch (operation) {
233 case ANATIVEWINDOW_PERFORM_SET_USAGE:
234 rs->mUsage = va_arg(args, uint32_t);
235 break;
236 case ANATIVEWINDOW_PERFORM_SET_USAGE64:
237 rs->mUsage = va_arg(args, uint64_t);
238 break;
239 case ANATIVEWINDOW_PERFORM_SET_BUFFERS_GEOMETRY:
240 /* width */ va_arg(args, uint32_t);
241 /* height */ va_arg(args, uint32_t);
242 rs->mFormat = va_arg(args, PixelFormat);
243 break;
244 case ANATIVEWINDOW_PERFORM_SET_BUFFERS_FORMAT:
245 rs->mFormat = va_arg(args, PixelFormat);
246 break;
247 }
248 }
John Reck848f6512018-12-03 13:26:43 -0800249 return result;
250}
251
Alec Mouri8d0c5bd22019-08-22 19:20:41 -0700252}; // namespace android::uirenderer::renderthread