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