1/* 2 * Copyright (C) 2016 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 <ui/GraphicBufferAllocator.h> 20#include <ui/GraphicBufferMapper.h> 21 22 23namespace android { 24namespace hardware { 25namespace automotive { 26namespace evs { 27namespace V1_0 { 28namespace implementation { 29 30 31EvsGlDisplay::EvsGlDisplay() { 32 ALOGD("EvsGlDisplay instantiated"); 33 34 // Set up our self description 35 // NOTE: These are arbitrary values chosen for testing 36 mInfo.displayId = "Mock Display"; 37 mInfo.vendorFlags = 3870; 38} 39 40 41EvsGlDisplay::~EvsGlDisplay() { 42 ALOGD("EvsGlDisplay being destroyed"); 43 forceShutdown(); 44} 45 46 47/** 48 * This gets called if another caller "steals" ownership of the display 49 */ 50void EvsGlDisplay::forceShutdown() 51{ 52 ALOGD("EvsGlDisplay forceShutdown"); 53 std::lock_guard<std::mutex> lock(mAccessLock); 54 55 // If the buffer isn't being held by a remote client, release it now as an 56 // optimization to release the resources more quickly than the destructor might 57 // get called. 58 if (mBuffer.memHandle) { 59 // Report if we're going away while a buffer is outstanding 60 if (mFrameBusy) { 61 ALOGE("EvsGlDisplay going down while client is holding a buffer"); 62 } 63 64 // Drop the graphics buffer we've been using 65 GraphicBufferAllocator& alloc(GraphicBufferAllocator::get()); 66 alloc.free(mBuffer.memHandle); 67 mBuffer.memHandle = nullptr; 68 69 mGlWrapper.shutdown(); 70 } 71 72 // Put this object into an unrecoverable error state since somebody else 73 // is going to own the display now. 74 mRequestedState = DisplayState::DEAD; 75} 76 77 78/** 79 * Returns basic information about the EVS display provided by the system. 80 * See the description of the DisplayDesc structure for details. 81 */ 82Return<void> EvsGlDisplay::getDisplayInfo(getDisplayInfo_cb _hidl_cb) { 83 ALOGD("getDisplayInfo"); 84 85 // Send back our self description 86 _hidl_cb(mInfo); 87 return Void(); 88} 89 90 91/** 92 * Clients may set the display state to express their desired state. 93 * The HAL implementation must gracefully accept a request for any state 94 * while in any other state, although the response may be to ignore the request. 95 * The display is defined to start in the NOT_VISIBLE state upon initialization. 96 * The client is then expected to request the VISIBLE_ON_NEXT_FRAME state, and 97 * then begin providing video. When the display is no longer required, the client 98 * is expected to request the NOT_VISIBLE state after passing the last video frame. 99 */ 100Return<EvsResult> EvsGlDisplay::setDisplayState(DisplayState state) { 101 ALOGD("setDisplayState"); 102 std::lock_guard<std::mutex> lock(mAccessLock); 103 104 if (mRequestedState == DisplayState::DEAD) { 105 // This object no longer owns the display -- it's been superceeded! 106 return EvsResult::OWNERSHIP_LOST; 107 } 108 109 // Ensure we recognize the requested state so we don't go off the rails 110 if (state >= DisplayState::NUM_STATES) { 111 return EvsResult::INVALID_ARG; 112 } 113 114 switch (state) { 115 case DisplayState::NOT_VISIBLE: 116 mGlWrapper.hideWindow(); 117 break; 118 case DisplayState::VISIBLE: 119 mGlWrapper.showWindow(); 120 break; 121 default: 122 break; 123 } 124 125 // Record the requested state 126 mRequestedState = state; 127 128 return EvsResult::OK; 129} 130 131 132/** 133 * The HAL implementation should report the actual current state, which might 134 * transiently differ from the most recently requested state. Note, however, that 135 * the logic responsible for changing display states should generally live above 136 * the device layer, making it undesirable for the HAL implementation to 137 * spontaneously change display states. 138 */ 139Return<DisplayState> EvsGlDisplay::getDisplayState() { 140 ALOGD("getDisplayState"); 141 std::lock_guard<std::mutex> lock(mAccessLock); 142 143 return mRequestedState; 144} 145 146 147/** 148 * This call returns a handle to a frame buffer associated with the display. 149 * This buffer may be locked and written to by software and/or GL. This buffer 150 * must be returned via a call to returnTargetBufferForDisplay() even if the 151 * display is no longer visible. 152 */ 153Return<void> EvsGlDisplay::getTargetBuffer(getTargetBuffer_cb _hidl_cb) { 154 ALOGV("getTargetBuffer"); 155 std::lock_guard<std::mutex> lock(mAccessLock); 156 157 if (mRequestedState == DisplayState::DEAD) { 158 ALOGE("Rejecting buffer request from object that lost ownership of the display."); 159 BufferDesc nullBuff = {}; 160 _hidl_cb(nullBuff); 161 return Void(); 162 } 163 164 // If we don't already have a buffer, allocate one now 165 if (!mBuffer.memHandle) { 166 // Initialize our display window 167 // NOTE: This will cause the display to become "VISIBLE" before a frame is actually 168 // returned, which is contrary to the spec and will likely result in a black frame being 169 // (briefly) shown. 170 if (!mGlWrapper.initialize()) { 171 // Report the failure 172 ALOGE("Failed to initialize GL display"); 173 BufferDesc nullBuff = {}; 174 _hidl_cb(nullBuff); 175 return Void(); 176 } 177 178 // Assemble the buffer description we'll use for our render target 179 mBuffer.width = mGlWrapper.getWidth(); 180 mBuffer.height = mGlWrapper.getHeight(); 181 mBuffer.format = HAL_PIXEL_FORMAT_RGBA_8888; 182 mBuffer.usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER; 183 mBuffer.bufferId = 0x3870; // Arbitrary magic number for self recognition 184 mBuffer.pixelSize = 4; 185 186 // Allocate the buffer that will hold our displayable image 187 buffer_handle_t handle = nullptr; 188 GraphicBufferAllocator& alloc(GraphicBufferAllocator::get()); 189 status_t result = alloc.allocate(mBuffer.width, mBuffer.height, 190 mBuffer.format, 1, 191 mBuffer.usage, &handle, 192 &mBuffer.stride, 193 0, "EvsGlDisplay"); 194 if (result != NO_ERROR) { 195 ALOGE("Error %d allocating %d x %d graphics buffer", 196 result, mBuffer.width, mBuffer.height); 197 BufferDesc nullBuff = {}; 198 _hidl_cb(nullBuff); 199 mGlWrapper.shutdown(); 200 return Void(); 201 } 202 if (!handle) { 203 ALOGE("We didn't get a buffer handle back from the allocator"); 204 BufferDesc nullBuff = {}; 205 _hidl_cb(nullBuff); 206 mGlWrapper.shutdown(); 207 return Void(); 208 } 209 210 mBuffer.memHandle = handle; 211 ALOGD("Allocated new buffer %p with stride %u", 212 mBuffer.memHandle.getNativeHandle(), mBuffer.stride); 213 mFrameBusy = false; 214 } 215 216 // Do we have a frame available? 217 if (mFrameBusy) { 218 // This means either we have a 2nd client trying to compete for buffers 219 // (an unsupported mode of operation) or else the client hasn't returned 220 // a previously issued buffer yet (they're behaving badly). 221 // NOTE: We have to make the callback even if we have nothing to provide 222 ALOGE("getTargetBuffer called while no buffers available."); 223 BufferDesc nullBuff = {}; 224 _hidl_cb(nullBuff); 225 return Void(); 226 } else { 227 // Mark our buffer as busy 228 mFrameBusy = true; 229 230 // Send the buffer to the client 231 ALOGV("Providing display buffer handle %p as id %d", 232 mBuffer.memHandle.getNativeHandle(), mBuffer.bufferId); 233 _hidl_cb(mBuffer); 234 return Void(); 235 } 236} 237 238 239/** 240 * This call tells the display that the buffer is ready for display. 241 * The buffer is no longer valid for use by the client after this call. 242 */ 243Return<EvsResult> EvsGlDisplay::returnTargetBufferForDisplay(const BufferDesc& buffer) { 244 ALOGV("returnTargetBufferForDisplay %p", buffer.memHandle.getNativeHandle()); 245 std::lock_guard<std::mutex> lock(mAccessLock); 246 247 // Nobody should call us with a null handle 248 if (!buffer.memHandle.getNativeHandle()) { 249 ALOGE ("returnTargetBufferForDisplay called without a valid buffer handle.\n"); 250 return EvsResult::INVALID_ARG; 251 } 252 if (buffer.bufferId != mBuffer.bufferId) { 253 ALOGE ("Got an unrecognized frame returned.\n"); 254 return EvsResult::INVALID_ARG; 255 } 256 if (!mFrameBusy) { 257 ALOGE ("A frame was returned with no outstanding frames.\n"); 258 return EvsResult::BUFFER_NOT_AVAILABLE; 259 } 260 261 mFrameBusy = false; 262 263 // If we've been displaced by another owner of the display, then we can't do anything else 264 if (mRequestedState == DisplayState::DEAD) { 265 return EvsResult::OWNERSHIP_LOST; 266 } 267 268 // If we were waiting for a new frame, this is it! 269 if (mRequestedState == DisplayState::VISIBLE_ON_NEXT_FRAME) { 270 mRequestedState = DisplayState::VISIBLE; 271 mGlWrapper.showWindow(); 272 } 273 274 // Validate we're in an expected state 275 if (mRequestedState != DisplayState::VISIBLE) { 276 // Not sure why a client would send frames back when we're not visible. 277 ALOGW ("Got a frame returned while not visible - ignoring.\n"); 278 } else { 279 // Update the texture contents with the provided data 280// TODO: Why doesn't it work to pass in the buffer handle we got from HIDL? 281// if (!mGlWrapper.updateImageTexture(buffer)) { 282 if (!mGlWrapper.updateImageTexture(mBuffer)) { 283 return EvsResult::UNDERLYING_SERVICE_ERROR; 284 } 285 286 // Put the image on the screen 287 mGlWrapper.renderImageToScreen(); 288 } 289 290 return EvsResult::OK; 291} 292 293} // namespace implementation 294} // namespace V1_0 295} // namespace evs 296} // namespace automotive 297} // namespace hardware 298} // namespace android 299