1 /* 2 * Copyright (C) 2022 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 "EvsGlDisplay.h" 18 19 #include <aidl/android/hardware/automotive/evs/EvsResult.h> 20 #include <aidl/android/hardware/graphics/common/BufferUsage.h> 21 #include <aidl/android/hardware/graphics/common/PixelFormat.h> 22 #include <aidlcommonsupport/NativeHandle.h> 23 #include <android-base/thread_annotations.h> 24 #include <linux/time.h> 25 #include <ui/DisplayMode.h> 26 #include <ui/DisplayState.h> 27 #include <ui/GraphicBufferAllocator.h> 28 #include <ui/GraphicBufferMapper.h> 29 #include <utils/SystemClock.h> 30 31 #include <chrono> 32 33 namespace { 34 35 using ::aidl::android::frameworks::automotive::display::ICarDisplayProxy; 36 using ::aidl::android::hardware::automotive::evs::BufferDesc; 37 using ::aidl::android::hardware::automotive::evs::DisplayDesc; 38 using ::aidl::android::hardware::automotive::evs::DisplayState; 39 using ::aidl::android::hardware::automotive::evs::EvsResult; 40 using ::aidl::android::hardware::graphics::common::BufferUsage; 41 using ::aidl::android::hardware::graphics::common::PixelFormat; 42 using ::android::base::ScopedLockAssertion; 43 using ::ndk::ScopedAStatus; 44 45 constexpr auto kTimeout = std::chrono::seconds(1); 46 47 bool debugFirstFrameDisplayed = false; 48 generateFingerPrint(buffer_handle_t handle)49 int generateFingerPrint(buffer_handle_t handle) { 50 return static_cast<int>(reinterpret_cast<long>(handle) & 0xFFFFFFFF); 51 } 52 53 } // namespace 54 55 namespace aidl::android::hardware::automotive::evs::implementation { 56 EvsGlDisplay(const std::shared_ptr<ICarDisplayProxy> & pDisplayProxy,uint64_t displayId)57 EvsGlDisplay::EvsGlDisplay(const std::shared_ptr<ICarDisplayProxy>& pDisplayProxy, 58 uint64_t displayId) : 59 mDisplayId(displayId), mDisplayProxy(pDisplayProxy) { 60 LOG(DEBUG) << "EvsGlDisplay instantiated"; 61 62 // Set up our self description 63 // NOTE: These are arbitrary values chosen for testing 64 mInfo.id = std::to_string(displayId); 65 mInfo.vendorFlags = 3870; 66 67 // Start a thread to render images on this display 68 { 69 std::lock_guard lock(mLock); 70 mState = RUN; 71 } 72 mRenderThread = std::thread([this]() { renderFrames(); }); 73 } 74 ~EvsGlDisplay()75 EvsGlDisplay::~EvsGlDisplay() { 76 LOG(DEBUG) << "EvsGlDisplay being destroyed"; 77 forceShutdown(); 78 } 79 80 /** 81 * This gets called if another caller "steals" ownership of the display 82 */ forceShutdown()83 void EvsGlDisplay::forceShutdown() { 84 LOG(DEBUG) << "EvsGlDisplay forceShutdown"; 85 { 86 std::lock_guard lock(mLock); 87 88 // If the buffer isn't being held by a remote client, release it now as an 89 // optimization to release the resources more quickly than the destructor might 90 // get called. 91 if (mBuffer.handle != nullptr) { 92 // Report if we're going away while a buffer is outstanding 93 if (mBufferBusy || mState == RUN) { 94 LOG(ERROR) << "EvsGlDisplay going down while client is holding a buffer"; 95 } 96 mState = STOPPING; 97 } 98 99 // Put this object into an unrecoverable error state since somebody else 100 // is going to own the display now. 101 mRequestedState = DisplayState::DEAD; 102 } 103 mBufferReadyToRender.notify_all(); 104 105 if (mRenderThread.joinable()) { 106 mRenderThread.join(); 107 } 108 } 109 110 /** 111 * Initialize GL in the context of a caller's thread and prepare a graphic 112 * buffer to use. 113 */ initializeGlContextLocked()114 bool EvsGlDisplay::initializeGlContextLocked() { 115 // Initialize our display window 116 // NOTE: This will cause the display to become "VISIBLE" before a frame is actually 117 // returned, which is contrary to the spec and will likely result in a black frame being 118 // (briefly) shown. 119 if (!mGlWrapper.initialize(mDisplayProxy, mDisplayId)) { 120 // Report the failure 121 LOG(ERROR) << "Failed to initialize GL display"; 122 return false; 123 } 124 125 // Assemble the buffer description we'll use for our render target 126 static_assert(::aidl::android::hardware::graphics::common::PixelFormat::RGBA_8888 == 127 static_cast<::aidl::android::hardware::graphics::common::PixelFormat>( 128 HAL_PIXEL_FORMAT_RGBA_8888)); 129 mBuffer.description = { 130 .width = static_cast<int>(mGlWrapper.getWidth()), 131 .height = static_cast<int>(mGlWrapper.getHeight()), 132 .layers = 1, 133 .format = PixelFormat::RGBA_8888, 134 // FIXME: Below line is not using 135 // ::aidl::android::hardware::graphics::common::BufferUsage because 136 // BufferUsage enum does not support a bitwise-OR operation; they 137 // should be BufferUsage::GPU_RENDER_TARGET | 138 // BufferUsage::COMPOSER_OVERLAY 139 .usage = static_cast<BufferUsage>(GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER), 140 }; 141 142 ::android::GraphicBufferAllocator& alloc(::android::GraphicBufferAllocator::get()); 143 uint32_t stride = static_cast<uint32_t>(mBuffer.description.stride); 144 buffer_handle_t handle = nullptr; 145 const ::android::status_t result = 146 alloc.allocate(mBuffer.description.width, mBuffer.description.height, 147 static_cast<::android::PixelFormat>(mBuffer.description.format), 148 mBuffer.description.layers, 149 static_cast<uint64_t>(mBuffer.description.usage), &handle, &stride, 150 /* requestorName= */ "EvsGlDisplay"); 151 mBuffer.description.stride = stride; 152 mBuffer.fingerprint = generateFingerPrint(mBuffer.handle); 153 if (result != ::android::NO_ERROR) { 154 LOG(ERROR) << "Error " << result << " allocating " << mBuffer.description.width << " x " 155 << mBuffer.description.height << " graphics buffer."; 156 mGlWrapper.shutdown(); 157 return false; 158 } 159 160 mBuffer.handle = handle; 161 if (mBuffer.handle == nullptr) { 162 LOG(ERROR) << "We didn't get a buffer handle back from the allocator"; 163 mGlWrapper.shutdown(); 164 return false; 165 } 166 167 LOG(DEBUG) << "Allocated new buffer " << mBuffer.handle << " with stride " 168 << mBuffer.description.stride; 169 return true; 170 } 171 172 /** 173 * This method runs in a separate thread and renders the contents of the buffer. 174 */ renderFrames()175 void EvsGlDisplay::renderFrames() { 176 { 177 std::lock_guard lock(mLock); 178 179 if (!initializeGlContextLocked()) { 180 LOG(ERROR) << "Failed to initialize GL context"; 181 return; 182 } 183 184 // Display buffer is ready. 185 mBufferBusy = false; 186 } 187 mBufferReadyToUse.notify_all(); 188 189 while (true) { 190 { 191 std::unique_lock lock(mLock); 192 ScopedLockAssertion lock_assertion(mLock); 193 mBufferReadyToRender.wait(lock, [this]() REQUIRES(mLock) { 194 return mBufferReady || mState != RUN; 195 }); 196 if (mState != RUN) { 197 LOG(DEBUG) << "A rendering thread is stopping"; 198 break; 199 } 200 mBufferReady = false; 201 } 202 203 // Update the texture contents with the provided data 204 if (!mGlWrapper.updateImageTexture(mBuffer.handle, mBuffer.description)) { 205 LOG(WARNING) << "Failed to update the image texture"; 206 continue; 207 } 208 209 // Put the image on the screen 210 mGlWrapper.renderImageToScreen(); 211 if (!debugFirstFrameDisplayed) { 212 LOG(DEBUG) << "EvsFirstFrameDisplayTiming start time: " << ::android::elapsedRealtime() 213 << " ms."; 214 debugFirstFrameDisplayed = true; 215 } 216 217 // Mark current frame is consumed. 218 { 219 std::lock_guard lock(mLock); 220 mBufferBusy = false; 221 } 222 mBufferDone.notify_all(); 223 } 224 225 LOG(DEBUG) << "A rendering thread is stopped."; 226 227 // Drop the graphics buffer we've been using 228 ::android::GraphicBufferAllocator& alloc(::android::GraphicBufferAllocator::get()); 229 alloc.free(mBuffer.handle); 230 mBuffer.handle = nullptr; 231 232 mGlWrapper.hideWindow(mDisplayProxy, mDisplayId); 233 mGlWrapper.shutdown(); 234 235 std::lock_guard lock(mLock); 236 mState = STOPPED; 237 } 238 239 /** 240 * Returns basic information about the EVS display provided by the system. 241 * See the description of the DisplayDesc structure for details. 242 */ getDisplayInfo(DisplayDesc * _aidl_return)243 ScopedAStatus EvsGlDisplay::getDisplayInfo(DisplayDesc* _aidl_return) { 244 if (!mDisplayProxy) { 245 return ::ndk::ScopedAStatus::fromServiceSpecificError( 246 static_cast<int>(EvsResult::UNDERLYING_SERVICE_ERROR)); 247 } 248 249 ::aidl::android::frameworks::automotive::display::DisplayDesc proxyDisplay; 250 auto status = mDisplayProxy->getDisplayInfo(mDisplayId, &proxyDisplay); 251 if (!status.isOk()) { 252 return ::ndk::ScopedAStatus::fromServiceSpecificError( 253 static_cast<int>(EvsResult::UNDERLYING_SERVICE_ERROR)); 254 } 255 256 _aidl_return->width = proxyDisplay.width; 257 _aidl_return->height = proxyDisplay.height; 258 _aidl_return->orientation = static_cast<Rotation>(proxyDisplay.orientation); 259 _aidl_return->id = mInfo.id; // FIXME: what should be ID here? 260 _aidl_return->vendorFlags = mInfo.vendorFlags; 261 return ::ndk::ScopedAStatus::ok(); 262 } 263 264 /** 265 * Clients may set the display state to express their desired state. 266 * The HAL implementation must gracefully accept a request for any state 267 * while in any other state, although the response may be to ignore the request. 268 * The display is defined to start in the NOT_VISIBLE state upon initialization. 269 * The client is then expected to request the VISIBLE_ON_NEXT_FRAME state, and 270 * then begin providing video. When the display is no longer required, the client 271 * is expected to request the NOT_VISIBLE state after passing the last video frame. 272 */ setDisplayState(DisplayState state)273 ScopedAStatus EvsGlDisplay::setDisplayState(DisplayState state) { 274 LOG(DEBUG) << __FUNCTION__; 275 std::lock_guard lock(mLock); 276 277 if (mRequestedState == DisplayState::DEAD) { 278 // This object no longer owns the display -- it's been superceeded! 279 return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::OWNERSHIP_LOST)); 280 } 281 282 // Ensure we recognize the requested state so we don't go off the rails 283 static constexpr ::ndk::enum_range<DisplayState> kDisplayStateRange; 284 if (std::find(kDisplayStateRange.begin(), kDisplayStateRange.end(), state) == 285 kDisplayStateRange.end()) { 286 return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::INVALID_ARG)); 287 } 288 289 switch (state) { 290 case DisplayState::NOT_VISIBLE: 291 mGlWrapper.hideWindow(mDisplayProxy, mDisplayId); 292 break; 293 case DisplayState::VISIBLE: 294 mGlWrapper.showWindow(mDisplayProxy, mDisplayId); 295 break; 296 default: 297 break; 298 } 299 300 // Record the requested state 301 mRequestedState = state; 302 303 return ScopedAStatus::ok(); 304 } 305 306 /** 307 * The HAL implementation should report the actual current state, which might 308 * transiently differ from the most recently requested state. Note, however, that 309 * the logic responsible for changing display states should generally live above 310 * the device layer, making it undesirable for the HAL implementation to 311 * spontaneously change display states. 312 */ getDisplayState(DisplayState * _aidl_return)313 ScopedAStatus EvsGlDisplay::getDisplayState(DisplayState* _aidl_return) { 314 LOG(DEBUG) << __FUNCTION__; 315 std::lock_guard lock(mLock); 316 *_aidl_return = mRequestedState; 317 return ScopedAStatus::ok(); 318 } 319 320 /** 321 * This call returns a handle to a frame buffer associated with the display. 322 * This buffer may be locked and written to by software and/or GL. This buffer 323 * must be returned via a call to returnTargetBufferForDisplay() even if the 324 * display is no longer visible. 325 */ getTargetBuffer(BufferDesc * _aidl_return)326 ScopedAStatus EvsGlDisplay::getTargetBuffer(BufferDesc* _aidl_return) { 327 LOG(DEBUG) << __FUNCTION__; 328 std::unique_lock lock(mLock); 329 ScopedLockAssertion lock_assertion(mLock); 330 if (mRequestedState == DisplayState::DEAD) { 331 LOG(ERROR) << "Rejecting buffer request from object that lost ownership of the display."; 332 return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::OWNERSHIP_LOST)); 333 } 334 335 // If we don't already have a buffer, allocate one now 336 // mBuffer.memHandle is a type of buffer_handle_t, which is equal to 337 // native_handle_t*. 338 mBufferReadyToUse.wait(lock, [this]() REQUIRES(mLock) { return !mBufferBusy; }); 339 340 // Do we have a frame available? 341 if (mBufferBusy) { 342 // This means either we have a 2nd client trying to compete for buffers 343 // (an unsupported mode of operation) or else the client hasn't returned 344 // a previously issued buffer yet (they're behaving badly). 345 // NOTE: We have to make the callback even if we have nothing to provide 346 LOG(ERROR) << "getTargetBuffer called while no buffers available."; 347 return ScopedAStatus::fromServiceSpecificError( 348 static_cast<int>(EvsResult::BUFFER_NOT_AVAILABLE)); 349 } 350 351 // Mark our buffer as busy 352 mBufferBusy = true; 353 354 // Send the buffer to the client 355 LOG(VERBOSE) << "Providing display buffer handle " << mBuffer.handle; 356 357 BufferDesc bufferDescToSend = { 358 .buffer = 359 { 360 .handle = ::android::dupToAidl(mBuffer.handle), 361 .description = mBuffer.description, 362 }, 363 .pixelSizeBytes = 4, // RGBA_8888 is 4-byte-per-pixel format 364 .bufferId = mBuffer.fingerprint, 365 }; 366 *_aidl_return = std::move(bufferDescToSend); 367 368 return ScopedAStatus::ok(); 369 } 370 371 /** 372 * This call tells the display that the buffer is ready for display. 373 * The buffer is no longer valid for use by the client after this call. 374 */ returnTargetBufferForDisplay(const BufferDesc & buffer)375 ScopedAStatus EvsGlDisplay::returnTargetBufferForDisplay(const BufferDesc& buffer) { 376 LOG(VERBOSE) << __FUNCTION__; 377 std::unique_lock lock(mLock); 378 ScopedLockAssertion lock_assertion(mLock); 379 380 // Nobody should call us with a null handle 381 if (buffer.buffer.handle.fds.size() < 1) { 382 LOG(ERROR) << __FUNCTION__ << " called without a valid buffer handle."; 383 return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::INVALID_ARG)); 384 } 385 if (buffer.bufferId != mBuffer.fingerprint) { 386 LOG(ERROR) << "Got an unrecognized frame returned."; 387 return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::INVALID_ARG)); 388 } 389 if (!mBufferBusy) { 390 LOG(ERROR) << "A frame was returned with no outstanding frames."; 391 return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::INVALID_ARG)); 392 } 393 394 // If we've been displaced by another owner of the display, then we can't do anything else 395 if (mRequestedState == DisplayState::DEAD) { 396 return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::OWNERSHIP_LOST)); 397 } 398 399 // If we were waiting for a new frame, this is it! 400 if (mRequestedState == DisplayState::VISIBLE_ON_NEXT_FRAME) { 401 mRequestedState = DisplayState::VISIBLE; 402 mGlWrapper.showWindow(mDisplayProxy, mDisplayId); 403 } 404 405 // Validate we're in an expected state 406 if (mRequestedState != DisplayState::VISIBLE) { 407 // Not sure why a client would send frames back when we're not visible. 408 LOG(WARNING) << "Got a frame returned while not visible - ignoring."; 409 return ScopedAStatus::ok(); 410 } 411 mBufferReady = true; 412 mBufferReadyToRender.notify_all(); 413 414 if (!mBufferDone.wait_for(lock, kTimeout, [this]() REQUIRES(mLock) { return !mBufferBusy; })) { 415 return ScopedAStatus::fromServiceSpecificError( 416 static_cast<int>(EvsResult::UNDERLYING_SERVICE_ERROR)); 417 } 418 419 return ScopedAStatus::ok(); 420 } 421 422 } // namespace aidl::android::hardware::automotive::evs::implementation 423