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