blob: a1a76d04d1c3a76ad989438b14c971a10c38ea6a [file] [log] [blame]
Scott Randolph5c99d852016-11-15 17:01:23 -08001/*
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
Scott Randolph83422792017-03-01 20:32:59 -080017#define LOG_TAG "android.hardware.automotive.evs@1.0-service"
Scott Randolph5c99d852016-11-15 17:01:23 -080018
19#include "EvsDisplay.h"
20
21#include <ui/GraphicBufferAllocator.h>
22#include <ui/GraphicBufferMapper.h>
23
24
25namespace android {
26namespace hardware {
Scott Randolph83422792017-03-01 20:32:59 -080027namespace automotive {
Scott Randolph5c99d852016-11-15 17:01:23 -080028namespace evs {
29namespace V1_0 {
30namespace implementation {
31
32
33// TODO(b/31632518): Need to get notification when our client dies so we can close the camera.
34// As it stands, if the client dies suddently, the buffer may be stranded.
35// As possible work around would be to give the client a HIDL object to exclusively hold
36// and use it's destructor to perform some work in the server side.
37
38
39EvsDisplay::EvsDisplay() {
40 ALOGD("EvsDisplay instantiated");
41
42 // Set up our self description
Scott Randolphdb5a5982017-01-23 12:35:05 -080043 // NOTE: These are arbitrary values chosen for testing
Scott Randolph5c99d852016-11-15 17:01:23 -080044 mInfo.displayId = "Mock Display";
45 mInfo.vendorFlags = 3870;
46 mInfo.defaultHorResolution = 320;
47 mInfo.defaultVerResolution = 240;
48}
49
50
51EvsDisplay::~EvsDisplay() {
52 ALOGD("EvsDisplay being destroyed");
53 std::lock_guard<std::mutex> lock(mAccessLock);
54
Scott Randolphdb5a5982017-01-23 12:35:05 -080055 // Report if we're going away while a buffer is outstanding
Scott Randolph5c99d852016-11-15 17:01:23 -080056 if (mFrameBusy) {
Scott Randolphdb5a5982017-01-23 12:35:05 -080057 ALOGE("EvsDisplay going down while client is holding a buffer");
Scott Randolph5c99d852016-11-15 17:01:23 -080058 }
59
60 // Make sure we release our frame buffer
Scott Randolphdb5a5982017-01-23 12:35:05 -080061 if (mBuffer.memHandle) {
Scott Randolph5c99d852016-11-15 17:01:23 -080062 // Drop the graphics buffer we've been using
63 GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
Scott Randolphdb5a5982017-01-23 12:35:05 -080064 alloc.free(mBuffer.memHandle);
65 mBuffer.memHandle = nullptr;
Scott Randolph5c99d852016-11-15 17:01:23 -080066 }
67 ALOGD("EvsDisplay destroyed");
68}
69
70
71/**
72 * Returns basic information about the EVS display provided by the system.
73 * See the description of the DisplayDesc structure below for details.
74 */
75Return<void> EvsDisplay::getDisplayInfo(getDisplayInfo_cb _hidl_cb) {
76 ALOGD("getDisplayInfo");
77
78 // Send back our self description
79 _hidl_cb(mInfo);
80 return Void();
81}
82
83
84/**
85 * Clients may set the display state to express their desired state.
86 * The HAL implementation must gracefully accept a request for any state
87 * while in any other state, although the response may be to ignore the request.
88 * The display is defined to start in the NOT_VISIBLE state upon initialization.
89 * The client is then expected to request the VISIBLE_ON_NEXT_FRAME state, and
90 * then begin providing video. When the display is no longer required, the client
91 * is expected to request the NOT_VISIBLE state after passing the last video frame.
92 */
93Return<EvsResult> EvsDisplay::setDisplayState(DisplayState state) {
94 ALOGD("setDisplayState");
95 std::lock_guard<std::mutex> lock(mAccessLock);
96
97 // Ensure we recognize the requested state so we don't go off the rails
98 if (state < DisplayState::NUM_STATES) {
99 // Record the requested state
100 mRequestedState = state;
101 return EvsResult::OK;
102 }
103 else {
104 // Turn off the display if asked for an unrecognized state
105 mRequestedState = DisplayState::NOT_VISIBLE;
106 return EvsResult::INVALID_ARG;
107 }
108}
109
110
111/**
112 * The HAL implementation should report the actual current state, which might
113 * transiently differ from the most recently requested state. Note, however, that
114 * the logic responsible for changing display states should generally live above
115 * the device layer, making it undesirable for the HAL implementation to
116 * spontaneously change display states.
117 */
118Return<DisplayState> EvsDisplay::getDisplayState() {
119 ALOGD("getDisplayState");
120 std::lock_guard<std::mutex> lock(mAccessLock);
121
122 // At the moment, we treat the requested state as immediately active
123 DisplayState currentState = mRequestedState;
124
125 return currentState;
126}
127
128
129/**
130 * This call returns a handle to a frame buffer associated with the display.
131 * This buffer may be locked and written to by software and/or GL. This buffer
132 * must be returned via a call to returnTargetBufferForDisplay() even if the
133 * display is no longer visible.
134 */
135// TODO: We need to know if/when our client dies so we can get the buffer back! (blocked b/31632518)
136Return<void> EvsDisplay::getTargetBuffer(getTargetBuffer_cb _hidl_cb) {
137 ALOGD("getTargetBuffer");
138 std::lock_guard<std::mutex> lock(mAccessLock);
139
140 // If we don't already have a buffer, allocate one now
Scott Randolphdb5a5982017-01-23 12:35:05 -0800141 if (!mBuffer.memHandle) {
142 // Assemble the buffer description we'll use for our render target
143 mBuffer.width = mInfo.defaultHorResolution;
144 mBuffer.height = mInfo.defaultVerResolution;
145 mBuffer.format = HAL_PIXEL_FORMAT_RGBA_8888;
146 mBuffer.usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER;
147 mBuffer.bufferId = 0x3870; // Arbitrary magic number for self recognition
148
149 buffer_handle_t handle = nullptr;
Scott Randolph5c99d852016-11-15 17:01:23 -0800150 GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
Scott Randolphdb5a5982017-01-23 12:35:05 -0800151 status_t result = alloc.allocate(mBuffer.width, mBuffer.height,
152 mBuffer.format, 1, mBuffer.usage,
Craig Donner7babeec2017-02-06 10:00:22 -0800153 mBuffer.usage, &handle,
154 &mBuffer.stride,
Scott Randolphdb5a5982017-01-23 12:35:05 -0800155 0, "EvsDisplay");
156 if (result != NO_ERROR) {
157 ALOGE("Error %d allocating %d x %d graphics buffer",
158 result, mBuffer.width, mBuffer.height);
159 BufferDesc nullBuff = {};
160 _hidl_cb(nullBuff);
161 return Void();
162 }
163 if (!handle) {
164 ALOGE("We didn't get a buffer handle back from the allocator");
165 BufferDesc nullBuff = {};
166 _hidl_cb(nullBuff);
167 return Void();
168 }
169
170 mBuffer.memHandle = handle;
Scott Randolph5c99d852016-11-15 17:01:23 -0800171 mFrameBusy = false;
Scott Randolphdb5a5982017-01-23 12:35:05 -0800172 ALOGD("Allocated new buffer %p with stride %u",
Scott Randolph9a773c72017-02-15 16:25:48 -0800173 mBuffer.memHandle.getNativeHandle(), mBuffer.stride);
Scott Randolph5c99d852016-11-15 17:01:23 -0800174 }
175
176 // Do we have a frame available?
177 if (mFrameBusy) {
178 // This means either we have a 2nd client trying to compete for buffers
179 // (an unsupported mode of operation) or else the client hasn't returned
Scott Randolphdb5a5982017-01-23 12:35:05 -0800180 // a previously issued buffer yet (they're behaving badly).
181 // NOTE: We have to make the callback even if we have nothing to provide
Scott Randolph5c99d852016-11-15 17:01:23 -0800182 ALOGE("getTargetBuffer called while no buffers available.");
Scott Randolphdb5a5982017-01-23 12:35:05 -0800183 BufferDesc nullBuff = {};
184 _hidl_cb(nullBuff);
185 return Void();
186 } else {
Scott Randolph5c99d852016-11-15 17:01:23 -0800187 // Mark our buffer as busy
188 mFrameBusy = true;
189
190 // Send the buffer to the client
Scott Randolphdb5a5982017-01-23 12:35:05 -0800191 ALOGD("Providing display buffer handle %p as id %d",
192 mBuffer.memHandle.getNativeHandle(), mBuffer.bufferId);
Scott Randolph5c99d852016-11-15 17:01:23 -0800193 _hidl_cb(mBuffer);
Scott Randolphdb5a5982017-01-23 12:35:05 -0800194 return Void();
Scott Randolph5c99d852016-11-15 17:01:23 -0800195 }
Scott Randolph5c99d852016-11-15 17:01:23 -0800196}
197
198
199/**
200 * This call tells the display that the buffer is ready for display.
201 * The buffer is no longer valid for use by the client after this call.
202 */
Scott Randolphdb5a5982017-01-23 12:35:05 -0800203Return<EvsResult> EvsDisplay::returnTargetBufferForDisplay(const BufferDesc& buffer) {
204 ALOGD("returnTargetBufferForDisplay %p", buffer.memHandle.getNativeHandle());
Scott Randolph5c99d852016-11-15 17:01:23 -0800205 std::lock_guard<std::mutex> lock(mAccessLock);
206
Scott Randolphdb5a5982017-01-23 12:35:05 -0800207 // Nobody should call us with a null handle
208 if (!buffer.memHandle.getNativeHandle()) {
Scott Randolph5c99d852016-11-15 17:01:23 -0800209 ALOGE ("returnTargetBufferForDisplay called without a valid buffer handle.\n");
210 return EvsResult::INVALID_ARG;
211 }
Scott Randolphdb5a5982017-01-23 12:35:05 -0800212 if (buffer.bufferId != mBuffer.bufferId) {
Scott Randolph5c99d852016-11-15 17:01:23 -0800213 ALOGE ("Got an unrecognized frame returned.\n");
214 return EvsResult::INVALID_ARG;
215 }
Scott Randolph5c99d852016-11-15 17:01:23 -0800216 if (!mFrameBusy) {
217 ALOGE ("A frame was returned with no outstanding frames.\n");
218 return EvsResult::BUFFER_NOT_AVAILABLE;
219 }
220
221 mFrameBusy = false;
222
223 // If we were waiting for a new frame, this is it!
224 if (mRequestedState == DisplayState::VISIBLE_ON_NEXT_FRAME) {
225 mRequestedState = DisplayState::VISIBLE;
226 }
227
228 // Validate we're in an expected state
229 if (mRequestedState != DisplayState::VISIBLE) {
230 // We shouldn't get frames back when we're not visible.
231 ALOGE ("Got an unexpected frame returned while not visible - ignoring.\n");
Scott Randolphdb5a5982017-01-23 12:35:05 -0800232 } else {
233 // This is where the buffer would be made visible.
234 // For now we simply validate it has the data we expect in it by reading it back
235
236 // Lock our display buffer for reading
237 uint32_t* pixels = nullptr;
238 GraphicBufferMapper &mapper = GraphicBufferMapper::get();
239 mapper.lock(mBuffer.memHandle,
240 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
241 android::Rect(mBuffer.width, mBuffer.height),
242 (void **)&pixels);
243
244 // If we failed to lock the pixel buffer, we're about to crash, but log it first
245 if (!pixels) {
Scott Randolph83422792017-03-01 20:32:59 -0800246 ALOGE("Display failed to gain access to image buffer for reading");
Scott Randolphdb5a5982017-01-23 12:35:05 -0800247 }
248
249 // Check the test pixels
250 bool frameLooksGood = true;
251 for (unsigned row = 0; row < mInfo.defaultVerResolution; row++) {
252 for (unsigned col = 0; col < mInfo.defaultHorResolution; col++) {
253 // Index into the row to check the pixel at this column.
254 // We expect 0xFF in the LSB channel, a vertical gradient in the
255 // second channel, a horitzontal gradient in the third channel, and
256 // 0xFF in the MSB.
257 // The exception is the very first 32 bits which is used for the
258 // time varying frame signature to avoid getting fooled by a static image.
259 uint32_t expectedPixel = 0xFF0000FF | // MSB and LSB
260 ((row & 0xFF) << 8) | // vertical gradient
261 ((col & 0xFF) << 16); // horizontal gradient
262 if ((row | col) == 0) {
263 // we'll check the "uniqueness" of the frame signature below
264 continue;
265 }
266 // Walk across this row (we'll step rows below)
Scott Randolph9a773c72017-02-15 16:25:48 -0800267 uint32_t receivedPixel = pixels[col];
268 if (receivedPixel != expectedPixel) {
Scott Randolphdb5a5982017-01-23 12:35:05 -0800269 ALOGE("Pixel check mismatch in frame buffer");
270 frameLooksGood = false;
271 break;
272 }
273 }
274
275 if (!frameLooksGood) {
276 break;
277 }
278
Scott Randolph9a773c72017-02-15 16:25:48 -0800279 // Point to the next row (NOTE: gralloc reports stride in units of pixels)
280 pixels = pixels + mBuffer.stride;
Scott Randolphdb5a5982017-01-23 12:35:05 -0800281 }
282
283 // Ensure we don't see the same buffer twice without it being rewritten
284 static uint32_t prevSignature = ~0;
285 uint32_t signature = pixels[0] & 0xFF;
286 if (prevSignature == signature) {
287 frameLooksGood = false;
288 ALOGE("Duplicate, likely stale frame buffer detected");
289 }
290
291
292 // Release our output buffer
293 mapper.unlock(mBuffer.memHandle);
294
295 if (!frameLooksGood) {
296 return EvsResult::UNDERLYING_SERVICE_ERROR;
297 }
Scott Randolph5c99d852016-11-15 17:01:23 -0800298 }
299
300 return EvsResult::OK;
301}
302
303} // namespace implementation
304} // namespace V1_0
305} // namespace evs
Scott Randolph83422792017-03-01 20:32:59 -0800306} // namespace automotive
Scott Randolph5c99d852016-11-15 17:01:23 -0800307} // namespace hardware
308} // namespace android