blob: 9dba6fc4bb5a52c159e3fa36027c4117479e99fd [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
42 mInfo.displayId = "Mock Display";
43 mInfo.vendorFlags = 3870;
44 mInfo.defaultHorResolution = 320;
45 mInfo.defaultVerResolution = 240;
46}
47
48
49EvsDisplay::~EvsDisplay() {
50 ALOGD("EvsDisplay being destroyed");
51 std::lock_guard<std::mutex> lock(mAccessLock);
52
53 // Report if we're going away while a buffer is outstanding. This could be bad.
54 if (mFrameBusy) {
55 ALOGE("EvsDisplay going down while client is holding a buffer\n");
56 }
57
58 // Make sure we release our frame buffer
59 if (mBuffer) {
60 // Drop the graphics buffer we've been using
61 GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
62 alloc.free(mBuffer);
63 }
64 ALOGD("EvsDisplay destroyed");
65}
66
67
68/**
69 * Returns basic information about the EVS display provided by the system.
70 * See the description of the DisplayDesc structure below for details.
71 */
72Return<void> EvsDisplay::getDisplayInfo(getDisplayInfo_cb _hidl_cb) {
73 ALOGD("getDisplayInfo");
74
75 // Send back our self description
76 _hidl_cb(mInfo);
77 return Void();
78}
79
80
81/**
82 * Clients may set the display state to express their desired state.
83 * The HAL implementation must gracefully accept a request for any state
84 * while in any other state, although the response may be to ignore the request.
85 * The display is defined to start in the NOT_VISIBLE state upon initialization.
86 * The client is then expected to request the VISIBLE_ON_NEXT_FRAME state, and
87 * then begin providing video. When the display is no longer required, the client
88 * is expected to request the NOT_VISIBLE state after passing the last video frame.
89 */
90Return<EvsResult> EvsDisplay::setDisplayState(DisplayState state) {
91 ALOGD("setDisplayState");
92 std::lock_guard<std::mutex> lock(mAccessLock);
93
94 // Ensure we recognize the requested state so we don't go off the rails
95 if (state < DisplayState::NUM_STATES) {
96 // Record the requested state
97 mRequestedState = state;
98 return EvsResult::OK;
99 }
100 else {
101 // Turn off the display if asked for an unrecognized state
102 mRequestedState = DisplayState::NOT_VISIBLE;
103 return EvsResult::INVALID_ARG;
104 }
105}
106
107
108/**
109 * The HAL implementation should report the actual current state, which might
110 * transiently differ from the most recently requested state. Note, however, that
111 * the logic responsible for changing display states should generally live above
112 * the device layer, making it undesirable for the HAL implementation to
113 * spontaneously change display states.
114 */
115Return<DisplayState> EvsDisplay::getDisplayState() {
116 ALOGD("getDisplayState");
117 std::lock_guard<std::mutex> lock(mAccessLock);
118
119 // At the moment, we treat the requested state as immediately active
120 DisplayState currentState = mRequestedState;
121
122 return currentState;
123}
124
125
126/**
127 * This call returns a handle to a frame buffer associated with the display.
128 * This buffer may be locked and written to by software and/or GL. This buffer
129 * must be returned via a call to returnTargetBufferForDisplay() even if the
130 * display is no longer visible.
131 */
132// TODO: We need to know if/when our client dies so we can get the buffer back! (blocked b/31632518)
133Return<void> EvsDisplay::getTargetBuffer(getTargetBuffer_cb _hidl_cb) {
134 ALOGD("getTargetBuffer");
135 std::lock_guard<std::mutex> lock(mAccessLock);
136
137 // If we don't already have a buffer, allocate one now
138 if (!mBuffer) {
139 GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
140 status_t result = alloc.allocate(mInfo.defaultHorResolution, mInfo.defaultVerResolution,
141 HAL_PIXEL_FORMAT_RGBA_8888, 1,
142 GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_HW_COMPOSER,
143 &mBuffer, &mStride, 0, "EvsDisplay");
144 mFrameBusy = false;
145 ALOGD("Allocated new buffer %p with stride %u", mBuffer, mStride);
146 }
147
148 // Do we have a frame available?
149 if (mFrameBusy) {
150 // This means either we have a 2nd client trying to compete for buffers
151 // (an unsupported mode of operation) or else the client hasn't returned
152 // a previously issues buffer yet (they're behaving badly).
153 // NOTE: We have to make callback even if we have nothing to provide
154 ALOGE("getTargetBuffer called while no buffers available.");
155 _hidl_cb(nullptr);
156 }
157 else {
158 // Mark our buffer as busy
159 mFrameBusy = true;
160
161 // Send the buffer to the client
162 ALOGD("Providing display buffer %p", mBuffer);
163 _hidl_cb(mBuffer);
164 }
165
166 // All done
167 return Void();
168}
169
170
171/**
172 * This call tells the display that the buffer is ready for display.
173 * The buffer is no longer valid for use by the client after this call.
174 */
175Return<EvsResult> EvsDisplay::returnTargetBufferForDisplay(const hidl_handle& bufferHandle) {
176 ALOGD("returnTargetBufferForDisplay %p", bufferHandle.getNativeHandle());
177 std::lock_guard<std::mutex> lock(mAccessLock);
178
179 // This shouldn't happen if we haven't issued the buffer!
180 if (!bufferHandle) {
181 ALOGE ("returnTargetBufferForDisplay called without a valid buffer handle.\n");
182 return EvsResult::INVALID_ARG;
183 }
184 /* TODO(b/33492405): It would be nice to validate we got back the buffer we expect,
185 * but HIDL doesn't support that (yet?)
186 if (bufferHandle != mBuffer) {
187 ALOGE ("Got an unrecognized frame returned.\n");
188 return EvsResult::INVALID_ARG;
189 }
190 */
191 if (!mFrameBusy) {
192 ALOGE ("A frame was returned with no outstanding frames.\n");
193 return EvsResult::BUFFER_NOT_AVAILABLE;
194 }
195
196 mFrameBusy = false;
197
198 // If we were waiting for a new frame, this is it!
199 if (mRequestedState == DisplayState::VISIBLE_ON_NEXT_FRAME) {
200 mRequestedState = DisplayState::VISIBLE;
201 }
202
203 // Validate we're in an expected state
204 if (mRequestedState != DisplayState::VISIBLE) {
205 // We shouldn't get frames back when we're not visible.
206 ALOGE ("Got an unexpected frame returned while not visible - ignoring.\n");
207 }
208 else {
209 // Make this buffer visible
210 // TODO: Add code to put this image on the screen (or validate it somehow?)
211 }
212
213 return EvsResult::OK;
214}
215
216} // namespace implementation
217} // namespace V1_0
218} // namespace evs
219} // namespace hardware
220} // namespace android