• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 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 
18 #define LOG_TAG "CameraGpuCtsActivity"
19 
20 #include <jni.h>
21 #include <unistd.h>
22 
23 #include <memory>
24 #include <vector>
25 
26 #include <android/log.h>
27 #include <EGL/egl.h>
28 #include <EGL/eglext.h>
29 #include <GLES/gl.h>
30 #include <GLES/glext.h>
31 #include <GLES2/gl2.h>
32 
33 #include "CameraTestHelpers.h"
34 #include "ImageReaderTestHelpers.h"
35 
36 //#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
37 //#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
38 #define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
39 #define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
40 #define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
41 
42 namespace {
43 
44 static constexpr uint32_t kTestImageWidth = 640;
45 static constexpr uint32_t kTestImageHeight = 480;
46 static constexpr uint32_t kTestImageFormat = AIMAGE_FORMAT_PRIVATE;
47 static constexpr uint64_t kTestImageUsage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
48 static constexpr uint32_t kTestImageCount = 3;
49 
50 static const char kVertShader[] = R"(
51   attribute vec2 aPosition;
52   attribute vec2 aTextureCoords;
53   varying vec2 texCoords;
54 
55   void main() {
56     texCoords =  aTextureCoords;
57     gl_Position = vec4(aPosition, 0.0, 1.0);
58   }
59 )";
60 
61 static const char kFragShader[] = R"(
62   #extension GL_OES_EGL_image_external : require
63 
64   precision mediump float;
65   varying vec2 texCoords;
66   uniform samplerExternalOES sTexture;
67 
68   void main() {
69     gl_FragColor = texture2D(sTexture, texCoords);
70   }
71 )";
72 
73 // A 80%-full screen mesh.
74 GLfloat kScreenTriangleStrip[] = {
75     // 1st vertex
76     -0.8f, -0.8f, 0.0f, 1.0f,
77     // 2nd vertex
78     -0.8f, 0.8f, 0.0f, 0.0f,
79     // 3rd vertex
80     0.8f, -0.8f, 1.0f, 1.0f,
81     // 4th vertex
82     0.8f, 0.8f, 1.0f, 0.0f,
83 };
84 
checkGlError(const char * op)85 static void checkGlError(const char* op) {
86     for (GLint error = glGetError(); error; error
87             = glGetError()) {
88         ALOGW("after %s() glError (0x%x)\n", op, error);
89     }
90 }
91 
92 class CameraFrameRenderer {
93   public:
CameraFrameRenderer()94     CameraFrameRenderer()
95         : mImageReader(kTestImageWidth, kTestImageHeight, kTestImageFormat, kTestImageUsage,
96                        kTestImageCount) {}
97 
~CameraFrameRenderer()98     ~CameraFrameRenderer() {
99         if (mProgram) {
100             glDeleteProgram(mProgram);
101             mProgram = 0;
102         }
103 
104         if (mEglImage != EGL_NO_IMAGE_KHR) {
105             eglDestroyImageKHR(mEglDisplay, mEglImage);
106             mEglImage = EGL_NO_IMAGE_KHR;
107         }
108     }
109 
isCameraReady()110     bool isCameraReady() { return mCamera.isCameraReady(); }
111 
112     // Retrun Zero on success, or negative error code.
initRenderer()113     int initRenderer() {
114         int ret = mImageReader.initImageReader();
115         if (ret < 0) {
116             ALOGE("Failed to initialize image reader: %d", ret);
117             return ret;
118         }
119 
120         ret = mCamera.initCamera(mImageReader.getNativeWindow());
121         if (ret < 0) {
122             ALOGE("Failed to initialize camera: %d", ret);
123             return ret;
124         }
125 
126         // This test should only test devices with at least one camera.
127         if (!mCamera.isCameraReady()) {
128             ALOGW(
129                 "Camera is not ready after successful initialization. It's either due to camera on "
130                 "board lacks BACKWARDS_COMPATIBLE capability or the device does not have camera on "
131                 "board.");
132             return 0;
133         }
134 
135         // Load shader and program.
136         mProgram = glCreateProgram();
137         GLuint vertShader = loadShader(GL_VERTEX_SHADER, kVertShader);
138         GLuint fragShader = loadShader(GL_FRAGMENT_SHADER, kFragShader);
139 
140         if (vertShader == 0 || fragShader == 0) {
141             ALOGE("Failed to load shader");
142             return -EINVAL;
143         }
144 
145         mProgram = glCreateProgram();
146         glAttachShader(mProgram, vertShader);
147         checkGlError("glAttachShader");
148         glAttachShader(mProgram, fragShader);
149         checkGlError("glAttachShader");
150 
151         glLinkProgram(mProgram);
152         GLint success;
153         glGetProgramiv(mProgram, GL_LINK_STATUS, &success);
154         if (!success) {
155             GLchar infoLog[512];
156             glGetProgramInfoLog(mProgram, 512, nullptr, infoLog);
157             ALOGE("Shader failed to link: %s", infoLog);
158             return -EINVAL;
159         }
160 
161         // Get attributes.
162         mPositionHandle = glGetAttribLocation(mProgram, "aPosition");
163         mTextureCoordsHandle = glGetAttribLocation(mProgram, "aTextureCoords");
164 
165         // Get uniforms.
166         mTextureUniform = glGetUniformLocation(mProgram, "sTexture");
167         checkGlError("glGetUniformLocation");
168 
169         // Generate texture.
170         glGenTextures(1, &mTextureId);
171         checkGlError("glGenTextures");
172         glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureId);
173 
174         // Cache the display
175         mEglDisplay = eglGetCurrentDisplay();
176 
177         return 0;
178     }
179 
180     // Return Zero on success, or negative error code.
drawFrame()181     int drawFrame() {
182         if (!mCamera.isCameraReady()) {
183             // We should never reach here. This test should just report success and quit early if
184             // no camera can be found during initialization.
185             ALOGE("No camera is ready for frame capture.");
186             return -EINVAL;
187         }
188 
189         // Indicate the camera to take recording.
190         int ret = mCamera.takePicture();
191         if (ret < 0) {
192             ALOGE("Camera failed to take picture, error=%d", ret);
193         }
194 
195         // Render the current buffer and then release it.
196         AHardwareBuffer* buffer;
197         ret = mImageReader.getBufferFromCurrentImage(&buffer);
198         if (ret != 0) {
199           // There might be no buffer acquired yet.
200           return ret;
201         }
202 
203         AHardwareBuffer_Desc outDesc;
204         AHardwareBuffer_describe(buffer, &outDesc);
205 
206         // Render with EGLImage.
207         EGLClientBuffer eglBuffer = eglGetNativeClientBufferANDROID(buffer);
208         if (!eglBuffer) {
209           ALOGE("Failed to create EGLClientBuffer");
210           return -EINVAL;
211         }
212 
213         if (mEglImage != EGL_NO_IMAGE_KHR) {
214             eglDestroyImageKHR(mEglDisplay, mEglImage);
215             mEglImage = EGL_NO_IMAGE_KHR;
216         }
217 
218         EGLint attrs[] = {
219             EGL_IMAGE_PRESERVED_KHR,
220             EGL_TRUE,
221             EGL_NONE,
222         };
223 
224         mEglImage = eglCreateImageKHR(mEglDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
225                                       eglBuffer, attrs);
226 
227         if (mEglImage == EGL_NO_IMAGE_KHR) {
228             ALOGE("Failed to create EGLImage.");
229             return -EINVAL;
230         }
231 
232         glClearColor(0.4f, 0.6f, 1.0f, 0.2f);
233         glClear(GL_COLOR_BUFFER_BIT);
234         checkGlError("glClearColor");
235 
236         // Use shader
237         glUseProgram(mProgram);
238         checkGlError("glUseProgram");
239 
240         // Map texture
241         glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, mEglImage);
242 
243         glActiveTexture(GL_TEXTURE0);
244         glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureId);
245         glUniform1i(mTextureUniform, 0);
246         checkGlError("glUniform1i");
247 
248         // Draw mesh
249         glVertexAttribPointer(mPositionHandle, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat),
250                               kScreenTriangleStrip);
251         glEnableVertexAttribArray(mPositionHandle);
252         glVertexAttribPointer(mTextureCoordsHandle, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat),
253                               kScreenTriangleStrip + 2);
254         glEnableVertexAttribArray(mTextureCoordsHandle);
255 
256         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
257         checkGlError("glDrawArrays");
258 
259         return 0;
260     }
261 
262   private:
loadShader(GLenum shaderType,const char * source)263     static GLuint loadShader(GLenum shaderType, const char* source) {
264         GLuint shader = glCreateShader(shaderType);
265 
266         glShaderSource(shader, 1, &source, nullptr);
267         glCompileShader(shader);
268 
269         GLint success;
270         glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
271         if (!success) {
272             ALOGE("Shader Failed to compile: %s", source);
273             shader = 0;
274         }
275         return shader;
276     }
277 
278     ImageReaderHelper mImageReader;
279     CameraHelper mCamera;
280 
281     // Shader
282     GLuint mProgram{0};
283 
284     // Texture
285     EGLDisplay mEglDisplay{EGL_NO_DISPLAY};
286     EGLImageKHR mEglImage{EGL_NO_IMAGE_KHR};
287     GLuint mTextureId{0};
288     GLuint mTextureUniform{0};
289     GLuint mPositionHandle{0};
290     GLuint mTextureCoordsHandle{0};
291 };
292 
jptr(CameraFrameRenderer * native_video_player)293 inline jlong jptr(CameraFrameRenderer* native_video_player) {
294     return reinterpret_cast<intptr_t>(native_video_player);
295 }
296 
native(jlong ptr)297 inline CameraFrameRenderer* native(jlong ptr) {
298     return reinterpret_cast<CameraFrameRenderer*>(ptr);
299 }
300 
createRenderer(JNIEnv *,jclass)301 jlong createRenderer(JNIEnv*, jclass) {
302     auto renderer = std::unique_ptr<CameraFrameRenderer>(new CameraFrameRenderer);
303     int ret = renderer->initRenderer();
304     if (ret < 0) {
305         ALOGE("Failed to init renderer: %d", ret);
306         return jptr(nullptr);
307     }
308 
309     return jptr(renderer.release());
310 }
311 
isCameraReady(JNIEnv *,jclass,jlong renderer)312 bool isCameraReady(JNIEnv*, jclass, jlong renderer) {
313     if (renderer == 0) {
314         ALOGE("isCameraReady: Invalid renderer: nullptr.");
315         return false;
316     }
317 
318     return native(renderer)->isCameraReady();
319 }
320 
destroyRenderer(JNIEnv *,jclass,jlong renderer)321 void destroyRenderer(JNIEnv*, jclass, jlong renderer) { delete native(renderer); }
322 
drawFrame(JNIEnv *,jclass,jlong renderer)323 jint drawFrame(JNIEnv*, jclass, jlong renderer) {
324     if (renderer == 0) {
325         ALOGE("Invalid renderer.");
326         return -EINVAL;
327     }
328 
329     return native(renderer)->drawFrame();
330 }
331 
332 const std::vector<JNINativeMethod> gMethods = {{
333     {"nCreateRenderer", "()J", (void*)createRenderer},
334     {"nIsCameraReady", "(J)Z", (void*)isCameraReady},
335     {"nDestroyRenderer", "(J)V", (void*)destroyRenderer},
336     {"nDrawFrame", "(J)I", (void*)drawFrame},
337 }};
338 
339 }  // namespace
340 
register_android_graphics_cts_CameraGpuCtsActivity(JNIEnv * env)341 int register_android_graphics_cts_CameraGpuCtsActivity(JNIEnv* env) {
342     jclass clazz = env->FindClass("android/graphics/cts/CameraGpuCtsActivity");
343     return env->RegisterNatives(clazz, gMethods.data(), gMethods.size());
344 }
345