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