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