1 /*
2 * Copyright (C) 2017 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 "RenderDirectView.h"
18
19 #include "VideoTex.h"
20 #include "glError.h"
21 #include "shader.h"
22 #include "shader_simpleTex.h"
23
24 #include <android-base/logging.h>
25 #include <android/hardware/camera/device/3.2/ICameraDevice.h>
26 #include <math/mat4.h>
27 #include <system/camera_metadata.h>
28
29 using ::android::hardware::camera::device::V3_2::Stream;
30 using ::android::hardware::graphics::common::V1_0::PixelFormat;
31
32
33 typedef struct {
34 int32_t id;
35 int32_t width;
36 int32_t height;
37 int32_t format;
38 int32_t direction;
39 int32_t framerate;
40 } RawStreamConfig;
41
42 const size_t kStreamCfgSz = sizeof(RawStreamConfig) / sizeof(int32_t);
43
44
RenderDirectView(sp<IEvsEnumerator> enumerator,const CameraDesc & camDesc,const ConfigManager & config)45 RenderDirectView::RenderDirectView(sp<IEvsEnumerator> enumerator,
46 const CameraDesc& camDesc,
47 const ConfigManager& config) :
48 mEnumerator(enumerator),
49 mCameraDesc(camDesc),
50 mConfig(config) {
51 // Find and store the target camera configuration
52 const auto& camList = mConfig.getCameras();
53 const auto target = std::find_if(camList.begin(), camList.end(),
54 [this](const ConfigManager::CameraInfo& info) {
55 return info.cameraId == mCameraDesc.v1.cameraId;
56 });
57 if (target != camList.end()) {
58 // Store the info
59 mCameraInfo = *target;
60
61 // Calculate a rotation matrix
62 float sinRoll, cosRoll;
63 sincosf(mCameraInfo.roll, &sinRoll, &cosRoll);
64 mRotationMat = {cosRoll, -sinRoll, sinRoll, cosRoll};
65 }
66 }
67
68
activate()69 bool RenderDirectView::activate() {
70 // Ensure GL is ready to go...
71 if (!prepareGL()) {
72 LOG(ERROR) << "Error initializing GL";
73 return false;
74 }
75
76 // Load our shader program if we don't have it already
77 if (!mShaderProgram) {
78 mShaderProgram = buildShaderProgram(vtxShader_simpleTexture,
79 pixShader_simpleTexture,
80 "simpleTexture");
81 if (!mShaderProgram) {
82 LOG(ERROR) << "Error building shader program";
83 return false;
84 }
85 }
86
87 bool foundCfg = false;
88 std::unique_ptr<Stream> targetCfg(new Stream());
89
90 if (!foundCfg) {
91 // This logic picks the first configuration in the list among them that
92 // support RGBA8888 format and its frame rate is faster than minReqFps.
93 const int32_t minReqFps = 15;
94 int32_t maxArea = 0;
95 camera_metadata_entry_t streamCfgs;
96 if (!find_camera_metadata_entry(
97 reinterpret_cast<camera_metadata_t *>(mCameraDesc.metadata.data()),
98 ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
99 &streamCfgs)) {
100 // Stream configurations are found in metadata
101 RawStreamConfig *ptr = reinterpret_cast<RawStreamConfig *>(streamCfgs.data.i32);
102 for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) {
103 if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
104 ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
105
106 if (ptr->framerate >= minReqFps &&
107 ptr->width * ptr->height > maxArea) {
108 targetCfg->id = ptr->id;
109 targetCfg->width = ptr->width;
110 targetCfg->height = ptr->height;
111
112 maxArea = ptr->width * ptr->height;
113
114 foundCfg = true;
115 }
116 }
117 ++ptr;
118 }
119 } else {
120 LOG(WARNING) << "No stream configuration data is found; "
121 << "default parameters will be used.";
122 }
123 }
124
125 // This client always wants below input data format
126 targetCfg->format =
127 static_cast<PixelFormat>(HAL_PIXEL_FORMAT_RGBA_8888);
128
129 // Construct our video texture
130 mTexture.reset(createVideoTexture(mEnumerator,
131 mCameraDesc.v1.cameraId.c_str(),
132 foundCfg ? std::move(targetCfg) : nullptr,
133 sDisplay,
134 mConfig.getUseExternalMemory(),
135 mConfig.getExternalMemoryFormat()));
136 if (!mTexture) {
137 LOG(ERROR) << "Failed to set up video texture for " << mCameraDesc.v1.cameraId;
138 // TODO: For production use, we may actually want to fail in this case, but not yet...
139 // return false;
140 }
141
142 return true;
143 }
144
145
deactivate()146 void RenderDirectView::deactivate() {
147 // Release our video texture
148 // We can't hold onto it because some other Render object might need the same camera
149 // TODO(b/131492626): investigate whether sharing video textures can save
150 // the time.
151 mTexture = nullptr;
152 }
153
154
drawFrame(const BufferDesc & tgtBuffer)155 bool RenderDirectView::drawFrame(const BufferDesc& tgtBuffer) {
156 // Tell GL to render to the given buffer
157 if (!attachRenderTarget(tgtBuffer)) {
158 LOG(ERROR) << "Failed to attached render target";
159 return false;
160 }
161
162 // Select our screen space simple texture shader
163 glUseProgram(mShaderProgram);
164
165 // Set up the model to clip space transform (identity matrix if we're modeling in screen space)
166 android::vec2 leftTop = {-0.5f, 0.5f};
167 android::vec2 rightTop = {0.5f, 0.5f};
168 android::vec2 leftBottom = {-0.5f, -0.5f};
169 android::vec2 rightBottom = {0.5f, -0.5f};
170 GLint loc = glGetUniformLocation(mShaderProgram, "cameraMat");
171 if (loc < 0) {
172 LOG(ERROR) << "Couldn't set shader parameter 'cameraMat'";
173 return false;
174 } else {
175 const android::mat4 identityMatrix;
176 glUniformMatrix4fv(loc, 1, false, identityMatrix.asArray());
177
178 // Rotate the preview
179 leftTop = mRotationMat * leftTop;
180 leftBottom = mRotationMat * leftBottom;
181 rightTop = mRotationMat * rightTop;
182 rightBottom = mRotationMat * rightBottom;
183 }
184
185 // Bind the texture and assign it to the shader's sampler
186 mTexture->refresh();
187 glActiveTexture(GL_TEXTURE0);
188 glBindTexture(GL_TEXTURE_2D, mTexture->glId());
189
190
191 GLint sampler = glGetUniformLocation(mShaderProgram, "tex");
192 if (sampler < 0) {
193 LOG(ERROR) << "Couldn't set shader parameter 'tex'";
194 return false;
195 } else {
196 // Tell the sampler we looked up from the shader to use texture slot 0 as its source
197 glUniform1i(sampler, 0);
198 }
199
200 // We want our image to show up opaque regardless of alpha values
201 glDisable(GL_BLEND);
202
203
204 // Draw a rectangle on the screen
205 GLfloat vertsCarPos[] = { -1.0, 1.0, 0.0f, // left top in window space
206 1.0, 1.0, 0.0f, // right top
207 -1.0, -1.0, 0.0f, // left bottom
208 1.0, -1.0, 0.0f // right bottom
209 };
210
211 // Flip the preview if needed
212 if (mCameraInfo.hflip) {
213 std::swap(leftTop.x, rightTop.x);
214 std::swap(leftBottom.x, rightBottom.x);
215 }
216
217 if (mCameraInfo.vflip) {
218 std::swap(leftTop.y, leftBottom.y);
219 std::swap(rightTop.y, rightBottom.y);
220 }
221
222 GLfloat vertsCarTex[] = { leftTop.x + 0.5f, leftTop.y + 0.5f,
223 rightTop.x + 0.5f, rightTop.y + 0.5f,
224 leftBottom.x + 0.5f, leftBottom.y + 0.5f,
225 rightBottom.x + 0.5f, rightBottom.y + 0.5f
226 };
227 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vertsCarPos);
228 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, vertsCarTex);
229 glEnableVertexAttribArray(0);
230 glEnableVertexAttribArray(1);
231
232 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
233
234 glDisableVertexAttribArray(0);
235 glDisableVertexAttribArray(1);
236
237
238 // Now that everything is submitted, release our hold on the texture resource
239 detachRenderTarget();
240
241 // Wait for the rendering to finish
242 glFinish();
243 detachRenderTarget();
244 return true;
245 }
246