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