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