1 /* 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 21 namespace 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 27 constexpr 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 33 struct SurfaceExposer : Surface { 34 // Make warnings happy 35 SurfaceExposer() = delete; 36 37 using Surface::cancelBuffer; 38 using Surface::dequeueBuffer; 39 using Surface::lockBuffer_DEPRECATED; 40 using Surface::perform; 41 using Surface::queueBuffer; 42 using Surface::setBufferCount; 43 using Surface::setSwapInterval; 44 }; 45 46 #define callProtected(surface, func, ...) ((*surface).*&SurfaceExposer::func)(__VA_ARGS__) 47 48 ReliableSurface::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 64 ReliableSurface::~ReliableSurface() { 65 clearReservedBuffer(); 66 } 67 68 void 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 89 int ReliableSurface::reserveNext() { 90 { 91 std::lock_guard _lock{mMutex}; 92 if (mReservedBuffer) { 93 ALOGW("reserveNext called but there was already a buffer reserved?"); 94 return OK; 95 } 96 if (mInErrorState) { 97 return UNKNOWN_ERROR; 98 } 99 if (mHasDequeuedBuffer) { 100 return OK; 101 } 102 if constexpr (DISABLE_BUFFER_PREFETCH) { 103 return OK; 104 } 105 } 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 126 void 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 145 int 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 157 int 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 168 int result = callProtected(mSurface, dequeueBuffer, buffer, fenceFd); 169 if (result != OK) { 170 ALOGW("dequeueBuffer failed, error = %d; switching to fallback", result); 171 *buffer = acquireFallbackBuffer(); 172 *fenceFd = -1; 173 return *buffer ? OK : INVALID_OPERATION; 174 } else { 175 std::lock_guard _lock{mMutex}; 176 mHasDequeuedBuffer = true; 177 } 178 return OK; 179 } 180 181 int ReliableSurface::queueBuffer(ANativeWindowBuffer* buffer, int fenceFd) { 182 clearReservedBuffer(); 183 184 if (isFallbackBuffer(buffer)) { 185 if (fenceFd > 0) { 186 close(fenceFd); 187 } 188 return OK; 189 } 190 191 int result = callProtected(mSurface, queueBuffer, buffer, fenceFd); 192 return result; 193 } 194 195 bool ReliableSurface::isFallbackBuffer(const ANativeWindowBuffer* windowBuffer) const { 196 if (!mScratchBuffer || !windowBuffer) { 197 return false; 198 } 199 ANativeWindowBuffer* scratchBuffer = 200 AHardwareBuffer_to_ANativeWindowBuffer(mScratchBuffer.get()); 201 return windowBuffer == scratchBuffer; 202 } 203 204 ANativeWindowBuffer* ReliableSurface::acquireFallbackBuffer() { 205 std::lock_guard _lock{mMutex}; 206 mInErrorState = true; 207 208 if (mScratchBuffer) { 209 return AHardwareBuffer_to_ANativeWindowBuffer(mScratchBuffer.get()); 210 } 211 212 AHardwareBuffer_Desc desc; 213 desc.usage = mUsage; 214 desc.format = mFormat; 215 desc.width = 1; 216 desc.height = 1; 217 desc.layers = 1; 218 desc.rfu0 = 0; 219 desc.rfu1 = 0; 220 AHardwareBuffer* newBuffer = nullptr; 221 int err = AHardwareBuffer_allocate(&desc, &newBuffer); 222 if (err) { 223 // Allocate failed, that sucks 224 ALOGW("Failed to allocate scratch buffer, error=%d", err); 225 return nullptr; 226 } 227 mScratchBuffer.reset(newBuffer); 228 return AHardwareBuffer_to_ANativeWindowBuffer(newBuffer); 229 } 230 231 Surface* ReliableSurface::getWrapped(const ANativeWindow* window) { 232 return getSelf(window)->mSurface.get(); 233 } 234 235 int ReliableSurface::hook_setSwapInterval(ANativeWindow* window, int interval) { 236 return callProtected(getWrapped(window), setSwapInterval, interval); 237 } 238 239 int ReliableSurface::hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer, 240 int* fenceFd) { 241 return getSelf(window)->dequeueBuffer(buffer, fenceFd); 242 } 243 244 int ReliableSurface::hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, 245 int fenceFd) { 246 return getSelf(window)->cancelBuffer(buffer, fenceFd); 247 } 248 249 int ReliableSurface::hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, 250 int fenceFd) { 251 return getSelf(window)->queueBuffer(buffer, fenceFd); 252 } 253 254 int ReliableSurface::hook_dequeueBuffer_DEPRECATED(ANativeWindow* window, 255 ANativeWindowBuffer** buffer) { 256 ANativeWindowBuffer* buf; 257 int fenceFd = -1; 258 int result = window->dequeueBuffer(window, &buf, &fenceFd); 259 if (result != OK) { 260 return result; 261 } 262 sp<Fence> fence(new Fence(fenceFd)); 263 int waitResult = fence->waitForever("dequeueBuffer_DEPRECATED"); 264 if (waitResult != OK) { 265 ALOGE("dequeueBuffer_DEPRECATED: Fence::wait returned an error: %d", waitResult); 266 window->cancelBuffer(window, buf, -1); 267 return waitResult; 268 } 269 *buffer = buf; 270 return result; 271 } 272 273 int ReliableSurface::hook_cancelBuffer_DEPRECATED(ANativeWindow* window, 274 ANativeWindowBuffer* buffer) { 275 return window->cancelBuffer(window, buffer, -1); 276 } 277 278 int ReliableSurface::hook_lockBuffer_DEPRECATED(ANativeWindow* window, 279 ANativeWindowBuffer* buffer) { 280 // This method is a no-op in Surface as well 281 return OK; 282 } 283 284 int ReliableSurface::hook_queueBuffer_DEPRECATED(ANativeWindow* window, 285 ANativeWindowBuffer* buffer) { 286 return window->queueBuffer(window, buffer, -1); 287 } 288 289 int ReliableSurface::hook_query(const ANativeWindow* window, int what, int* value) { 290 return getWrapped(window)->query(what, value); 291 } 292 293 int ReliableSurface::hook_perform(ANativeWindow* window, int operation, ...) { 294 // Drop the reserved buffer if there is one since this (probably) mutated buffer dimensions 295 // TODO: Filter to things that only affect the reserved buffer 296 // TODO: Can we mutate the reserved buffer in some cases? 297 getSelf(window)->clearReservedBuffer(); 298 va_list args; 299 va_start(args, operation); 300 int result = callProtected(getWrapped(window), perform, operation, args); 301 va_end(args); 302 303 va_start(args, operation); 304 getSelf(window)->perform(operation, args); 305 va_end(args); 306 307 return result; 308 } 309 310 }; // namespace android::uirenderer::renderthread