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