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