blob: 720839535d9f6820e7926d7bfb227f3ed0444a80 [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,
Craig Donner7babeec2017-02-06 10:00:22 -0800152 mBuffer.usage, &handle,
153 &mBuffer.stride,
Scott Randolphdb5a5982017-01-23 12:35:05 -0800154 0, "EvsDisplay");
155 if (result != NO_ERROR) {
156 ALOGE("Error %d allocating %d x %d graphics buffer",
157 result, mBuffer.width, mBuffer.height);
158 BufferDesc nullBuff = {};
159 _hidl_cb(nullBuff);
160 return Void();
161 }
162 if (!handle) {
163 ALOGE("We didn't get a buffer handle back from the allocator");
164 BufferDesc nullBuff = {};
165 _hidl_cb(nullBuff);
166 return Void();
167 }
168
169 mBuffer.memHandle = handle;
Scott Randolph5c99d852016-11-15 17:01:23 -0800170 mFrameBusy = false;
Scott Randolphdb5a5982017-01-23 12:35:05 -0800171 ALOGD("Allocated new buffer %p with stride %u",
172 mBuffer.memHandle.getNativeHandle(), mStride);
Scott Randolph5c99d852016-11-15 17:01:23 -0800173 }
174
175 // Do we have a frame available?
176 if (mFrameBusy) {
177 // This means either we have a 2nd client trying to compete for buffers
178 // (an unsupported mode of operation) or else the client hasn't returned
Scott Randolphdb5a5982017-01-23 12:35:05 -0800179 // a previously issued buffer yet (they're behaving badly).
180 // NOTE: We have to make the callback even if we have nothing to provide
Scott Randolph5c99d852016-11-15 17:01:23 -0800181 ALOGE("getTargetBuffer called while no buffers available.");
Scott Randolphdb5a5982017-01-23 12:35:05 -0800182 BufferDesc nullBuff = {};
183 _hidl_cb(nullBuff);
184 return Void();
185 } else {
Scott Randolph5c99d852016-11-15 17:01:23 -0800186 // Mark our buffer as busy
187 mFrameBusy = true;
188
189 // Send the buffer to the client
Scott Randolphdb5a5982017-01-23 12:35:05 -0800190 ALOGD("Providing display buffer handle %p as id %d",
191 mBuffer.memHandle.getNativeHandle(), mBuffer.bufferId);
Scott Randolph5c99d852016-11-15 17:01:23 -0800192 _hidl_cb(mBuffer);
Scott Randolphdb5a5982017-01-23 12:35:05 -0800193 return Void();
Scott Randolph5c99d852016-11-15 17:01:23 -0800194 }
Scott Randolph5c99d852016-11-15 17:01:23 -0800195}
196
197
198/**
199 * This call tells the display that the buffer is ready for display.
200 * The buffer is no longer valid for use by the client after this call.
201 */
Scott Randolphdb5a5982017-01-23 12:35:05 -0800202Return<EvsResult> EvsDisplay::returnTargetBufferForDisplay(const BufferDesc& buffer) {
203 ALOGD("returnTargetBufferForDisplay %p", buffer.memHandle.getNativeHandle());
Scott Randolph5c99d852016-11-15 17:01:23 -0800204 std::lock_guard<std::mutex> lock(mAccessLock);
205
Scott Randolphdb5a5982017-01-23 12:35:05 -0800206 // Nobody should call us with a null handle
207 if (!buffer.memHandle.getNativeHandle()) {
Scott Randolph5c99d852016-11-15 17:01:23 -0800208 ALOGE ("returnTargetBufferForDisplay called without a valid buffer handle.\n");
209 return EvsResult::INVALID_ARG;
210 }
Scott Randolphdb5a5982017-01-23 12:35:05 -0800211 if (buffer.bufferId != mBuffer.bufferId) {
Scott Randolph5c99d852016-11-15 17:01:23 -0800212 ALOGE ("Got an unrecognized frame returned.\n");
213 return EvsResult::INVALID_ARG;
214 }
Scott Randolph5c99d852016-11-15 17:01:23 -0800215 if (!mFrameBusy) {
216 ALOGE ("A frame was returned with no outstanding frames.\n");
217 return EvsResult::BUFFER_NOT_AVAILABLE;
218 }
219
220 mFrameBusy = false;
221
222 // If we were waiting for a new frame, this is it!
223 if (mRequestedState == DisplayState::VISIBLE_ON_NEXT_FRAME) {
224 mRequestedState = DisplayState::VISIBLE;
225 }
226
227 // Validate we're in an expected state
228 if (mRequestedState != DisplayState::VISIBLE) {
229 // We shouldn't get frames back when we're not visible.
230 ALOGE ("Got an unexpected frame returned while not visible - ignoring.\n");
Scott Randolphdb5a5982017-01-23 12:35:05 -0800231 } else {
232 // This is where the buffer would be made visible.
233 // For now we simply validate it has the data we expect in it by reading it back
234
235 // Lock our display buffer for reading
236 uint32_t* pixels = nullptr;
237 GraphicBufferMapper &mapper = GraphicBufferMapper::get();
238 mapper.lock(mBuffer.memHandle,
239 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
240 android::Rect(mBuffer.width, mBuffer.height),
241 (void **)&pixels);
242
243 // If we failed to lock the pixel buffer, we're about to crash, but log it first
244 if (!pixels) {
245 ALOGE("Camera failed to gain access to image buffer for reading");
246 }
247
248 // Check the test pixels
249 bool frameLooksGood = true;
250 for (unsigned row = 0; row < mInfo.defaultVerResolution; row++) {
251 for (unsigned col = 0; col < mInfo.defaultHorResolution; col++) {
252 // Index into the row to check the pixel at this column.
253 // We expect 0xFF in the LSB channel, a vertical gradient in the
254 // second channel, a horitzontal gradient in the third channel, and
255 // 0xFF in the MSB.
256 // The exception is the very first 32 bits which is used for the
257 // time varying frame signature to avoid getting fooled by a static image.
258 uint32_t expectedPixel = 0xFF0000FF | // MSB and LSB
259 ((row & 0xFF) << 8) | // vertical gradient
260 ((col & 0xFF) << 16); // horizontal gradient
261 if ((row | col) == 0) {
262 // we'll check the "uniqueness" of the frame signature below
263 continue;
264 }
265 // Walk across this row (we'll step rows below)
266 if (pixels[col] != expectedPixel) {
267 ALOGE("Pixel check mismatch in frame buffer");
268 frameLooksGood = false;
269 break;
270 }
271 }
272
273 if (!frameLooksGood) {
274 break;
275 }
276
277 // Point to the next row
278 pixels = pixels + (mStride / sizeof(*pixels));
279 }
280
281 // Ensure we don't see the same buffer twice without it being rewritten
282 static uint32_t prevSignature = ~0;
283 uint32_t signature = pixels[0] & 0xFF;
284 if (prevSignature == signature) {
285 frameLooksGood = false;
286 ALOGE("Duplicate, likely stale frame buffer detected");
287 }
288
289
290 // Release our output buffer
291 mapper.unlock(mBuffer.memHandle);
292
293 if (!frameLooksGood) {
294 return EvsResult::UNDERLYING_SERVICE_ERROR;
295 }
Scott Randolph5c99d852016-11-15 17:01:23 -0800296 }
297
298 return EvsResult::OK;
299}
300
301} // namespace implementation
302} // namespace V1_0
303} // namespace evs
304} // namespace hardware
305} // namespace android