1 /*
2 * Copyright (C) 2023 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 <vector>
18 #include <math.h>
19
20 #define GL_GLEXT_PROTOTYPES
21 #define EGL_EGLEXT_PROTOTYPES
22 #include <EGL/egl.h>
23 #include <EGL/eglext.h>
24 #include <GLES2/gl2.h>
25 #include <GLES2/gl2ext.h>
26 #undef EGL_EGLEXT_PROTOTYPES
27 #undef GL_GLEXT_PROTOTYPES
28
29 #include "abc3d.h"
30 #include "debug.h"
31
32 namespace android {
33 namespace hardware {
34 namespace camera {
35 namespace provider {
36 namespace implementation {
37 namespace abc3d {
38 namespace {
39 constexpr char kTag[] = "abc3d";
40
dot3(const float a3[],const float b3[])41 float dot3(const float a3[], const float b3[]) {
42 return a3[0] * b3[0] + a3[1] * b3[1] + a3[2] * b3[2];
43 }
44
45 /*
46 * https://registry.khronos.org/OpenGL-Refpages/gl2.1/xhtml/gluLookAt.xml
47 * https://registry.khronos.org/OpenGL-Refpages/gl2.1/xhtml/glTranslate.xml
48 * This function takes `m44` (where zzz (assumed zero) and ooo (assumed one)
49 * are ignored) and multiplies it by a translation matrix.
50 *
51 * m44 translate
52 * [ s0 s1 s2 zzz ] [ 1 0 0 -eyeX ] [ s0 s1 s2 -dot3(m44[0:2], eye3) ]
53 * [ up0 up1 up2 zzz ] * [ 0 1 0 -eyeY ] = [ up0 up1 up2 -dot3(m44[4:6], eye3) ]
54 * [ b0 b1 b2 zzz ] [ 0 0 1 -eyeZ ] [ b0 b1 b2 -dot3(m44[8:10], eye3) ]
55 * [ zzz zzz zzz ooo ] [ 0 0 0 1 ] [ 0 0 0 1 ]
56 */
lookAtEyeCoordinates(float m44[],const float eye3[])57 void lookAtEyeCoordinates(float m44[], const float eye3[]) {
58 m44[3] = -dot3(&m44[0], eye3);
59 m44[7] = -dot3(&m44[4], eye3);
60 m44[11] = -dot3(&m44[8], eye3);
61 m44[12] = 0;
62 m44[13] = 0;
63 m44[14] = 0;
64 m44[15] = 1;
65 }
66 } // namespace
67
68 #define RETURN_CTOR_FAILED(S) \
69 ALOGE("%s:%s:%d %s failed", kTag, __func__, __LINE__, S); return;
70
AutoImageKHR(const EGLDisplay display,const EGLClientBuffer clientBuf)71 AutoImageKHR::AutoImageKHR(const EGLDisplay display, const EGLClientBuffer clientBuf)
72 : mEglDisplay(display) {
73 static const EGLint imageAttrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
74 mEglImage = eglCreateImageKHR(
75 display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuf, imageAttrs);
76 if (mEglImage == EGL_NO_IMAGE_KHR) {
77 RETURN_CTOR_FAILED("eglCreateImageKHR");
78 }
79 }
80
AutoImageKHR(AutoImageKHR && rhs)81 AutoImageKHR::AutoImageKHR(AutoImageKHR&& rhs) noexcept
82 : mEglDisplay(rhs.mEglDisplay)
83 , mEglImage(std::exchange(rhs.mEglImage, EGL_NO_IMAGE_KHR)) {}
84
operator =(AutoImageKHR && rhs)85 AutoImageKHR& AutoImageKHR::operator=(AutoImageKHR&& rhs) noexcept {
86 if (this != &rhs) {
87 mEglDisplay = rhs.mEglDisplay;
88 mEglImage = std::exchange(rhs.mEglImage, EGL_NO_IMAGE_KHR);
89 }
90 return *this;
91 }
92
~AutoImageKHR()93 AutoImageKHR::~AutoImageKHR() {
94 if (mEglImage != EGL_NO_IMAGE_KHR) {
95 eglDestroyImageKHR(mEglDisplay, mEglImage);
96 }
97 }
98
EglCurrentContext(const EGLDisplay display)99 EglCurrentContext::EglCurrentContext(const EGLDisplay display)
100 : mEglDisplay(display) {}
101
EglCurrentContext(EglCurrentContext && rhs)102 EglCurrentContext::EglCurrentContext(EglCurrentContext&& rhs) noexcept
103 : mEglDisplay(std::exchange(rhs.mEglDisplay, EGL_NO_DISPLAY)) {}
104
operator =(EglCurrentContext && rhs)105 EglCurrentContext& EglCurrentContext::operator=(EglCurrentContext&& rhs) noexcept {
106 if (this != &rhs) {
107 mEglDisplay = std::exchange(rhs.mEglDisplay, EGL_NO_DISPLAY);
108 }
109 return *this;
110 }
111
~EglCurrentContext()112 EglCurrentContext::~EglCurrentContext() {
113 if (mEglDisplay != EGL_NO_DISPLAY) {
114 LOG_ALWAYS_FATAL_IF(!eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE,
115 EGL_NO_SURFACE, EGL_NO_CONTEXT));
116 }
117 }
118
EglContext(EglContext && rhs)119 EglContext::EglContext(EglContext&& rhs) noexcept
120 : mEglDisplay(std::exchange(rhs.mEglDisplay, EGL_NO_DISPLAY))
121 , mEglContext(std::exchange(rhs.mEglContext, EGL_NO_CONTEXT))
122 , mEglSurface(std::exchange(rhs.mEglSurface, EGL_NO_SURFACE)) {}
123
operator =(EglContext && rhs)124 EglContext& EglContext::operator=(EglContext&& rhs) noexcept {
125 if (this != &rhs) {
126 mEglDisplay = std::exchange(rhs.mEglDisplay, EGL_NO_DISPLAY);
127 mEglContext = std::exchange(rhs.mEglContext, EGL_NO_CONTEXT);
128 mEglSurface = std::exchange(rhs.mEglSurface, EGL_NO_SURFACE);
129 }
130 return *this;
131 }
132
~EglContext()133 EglContext::~EglContext() {
134 clear();
135 }
136
clear()137 void EglContext::clear() {
138 if (mEglSurface != EGL_NO_SURFACE) {
139 eglDestroySurface(mEglDisplay, mEglSurface);
140 mEglSurface = EGL_NO_SURFACE;
141 }
142 if (mEglContext != EGL_NO_CONTEXT) {
143 eglDestroyContext(mEglDisplay, mEglContext);
144 mEglContext = EGL_NO_CONTEXT;
145 }
146 if (mEglDisplay != EGL_NO_DISPLAY) {
147 eglTerminate(mEglDisplay);
148 mEglDisplay = EGL_NO_DISPLAY;
149 }
150 }
151
init()152 EglCurrentContext EglContext::init() {
153 if (mEglContext != EGL_NO_CONTEXT) {
154 LOG_ALWAYS_FATAL_IF(!eglMakeCurrent(mEglDisplay, mEglSurface,
155 mEglSurface, mEglContext));
156 return EglCurrentContext(mEglDisplay);
157 }
158
159 const EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
160 if (display == EGL_NO_DISPLAY) {
161 return EglCurrentContext(FAILURE(EGL_NO_DISPLAY));
162 }
163
164 EGLint major, minor;
165 if (!eglInitialize(display, &major, &minor)) {
166 return EglCurrentContext(FAILURE(EGL_NO_DISPLAY));
167 }
168 ALOGD("%s:%d: Initialized EGL, version %d.%d", __func__, __LINE__,
169 static_cast<int>(major), static_cast<int>(minor));
170
171 static const EGLint configAttrs[] = {
172 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
173 EGL_CONFIG_CAVEAT, EGL_NONE,
174 EGL_RED_SIZE, 8,
175 EGL_GREEN_SIZE, 8,
176 EGL_BLUE_SIZE, 8,
177 EGL_ALPHA_SIZE, 8,
178 EGL_NONE
179 };
180
181 EGLint numConfigs = 1;
182 EGLConfig config = EGL_NO_CONFIG_KHR;
183 if (!eglChooseConfig(display, configAttrs, &config, 1, &numConfigs) ||
184 (config == EGL_NO_CONFIG_KHR) || (numConfigs != 1)) {
185 eglTerminate(display);
186 return EglCurrentContext(FAILURE(EGL_NO_DISPLAY));
187 }
188
189 static const EGLint contextAttrs[] = {
190 EGL_CONTEXT_CLIENT_VERSION, 2,
191 EGL_NONE
192 };
193 const EGLContext context = eglCreateContext(display, config,
194 EGL_NO_CONTEXT, contextAttrs);
195 if (context == EGL_NO_CONTEXT) {
196 eglTerminate(display);
197 return EglCurrentContext(FAILURE(EGL_NO_DISPLAY));
198 }
199
200 EGLSurface surface = EGL_NO_SURFACE;
201 if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, context)) {
202 // EGL_KHR_surfaceless_context is not supported
203 const EGLint surfaceAttrs[] = {
204 EGL_WIDTH, 1,
205 EGL_HEIGHT, 1,
206 EGL_NONE
207 };
208 surface = eglCreatePbufferSurface(display, config, surfaceAttrs);
209 if (surface == EGL_NO_SURFACE) {
210 eglDestroyContext(display, context);
211 eglTerminate(display);
212 return EglCurrentContext(FAILURE(EGL_NO_DISPLAY));
213 }
214
215 if (!eglMakeCurrent(display, surface, surface, context)) {
216 eglDestroySurface(display, surface);
217 eglDestroyContext(display, context);
218 eglTerminate(display);
219 return EglCurrentContext(FAILURE(EGL_NO_DISPLAY));
220 }
221 }
222
223 mEglDisplay = display;
224 mEglContext = context;
225 mEglSurface = surface;
226
227 return EglCurrentContext(display);
228 }
229
getCurrentContext()230 EglCurrentContext EglContext::getCurrentContext() {
231 if (mEglContext == EGL_NO_CONTEXT) {
232 return EglCurrentContext(EGL_NO_DISPLAY);
233 } else if (eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
234 return EglCurrentContext(mEglDisplay);
235 } else {
236 return EglCurrentContext(FAILURE(EGL_NO_DISPLAY));
237 }
238 }
239
AutoTexture(const GLenum target)240 AutoTexture::AutoTexture(const GLenum target) {
241 glGenTextures(1, &mTex);
242 if (mTex) {
243 glBindTexture(target, mTex);
244 } else {
245 RETURN_CTOR_FAILED("glGenTextures");
246 }
247 }
248
AutoTexture(const GLenum target,const GLint internalformat,const GLsizei width,const GLsizei height,const GLenum format,const GLenum type,const void * data)249 AutoTexture::AutoTexture(const GLenum target,
250 const GLint internalformat,
251 const GLsizei width,
252 const GLsizei height,
253 const GLenum format,
254 const GLenum type,
255 const void* data) {
256 glGenTextures(1, &mTex);
257 if (mTex) {
258 glBindTexture(target, mTex);
259 glTexImage2D(target, 0, internalformat, width, height, 0, format, type, data);
260 } else {
261 RETURN_CTOR_FAILED("glGenTextures");
262 }
263 }
264
AutoTexture(AutoTexture && rhs)265 AutoTexture::AutoTexture(AutoTexture&& rhs) noexcept
266 : mTex(std::exchange(rhs.mTex, 0)) {}
267
operator =(AutoTexture && rhs)268 AutoTexture& AutoTexture::operator=(AutoTexture&& rhs) noexcept {
269 if (this != &rhs) {
270 mTex = std::exchange(rhs.mTex, 0);
271 }
272 return *this;
273 }
274
~AutoTexture()275 AutoTexture::~AutoTexture() {
276 clear();
277 }
278
clear()279 void AutoTexture::clear() {
280 if (mTex) {
281 glDeleteTextures(1, &mTex);
282 mTex = 0;
283 }
284 }
285
AutoFrameBuffer()286 AutoFrameBuffer::AutoFrameBuffer() {
287 glGenFramebuffers(1, &mFBO);
288 if (mFBO) {
289 glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
290 } else {
291 RETURN_CTOR_FAILED("glGenFramebuffers");
292 }
293 }
294
~AutoFrameBuffer()295 AutoFrameBuffer::~AutoFrameBuffer() {
296 if (mFBO) {
297 glDeleteFramebuffers(1, &mFBO);
298 }
299 }
300
AutoShader(AutoShader && rhs)301 AutoShader::AutoShader(AutoShader&& rhs) noexcept
302 : mShader(std::exchange(rhs.mShader, 0)) {}
303
operator =(AutoShader && rhs)304 AutoShader& AutoShader::operator=(AutoShader&& rhs) noexcept {
305 if (this != &rhs) {
306 mShader = std::exchange(rhs.mShader, 0);
307 }
308 return *this;
309 }
310
~AutoShader()311 AutoShader::~AutoShader() {
312 if (mShader) {
313 glDeleteShader(mShader);
314 }
315 }
316
compile(const GLenum type,const char * text)317 GLuint AutoShader::compile(const GLenum type, const char* text) {
318 const GLuint shader = glCreateShader(type);
319 if (!shader) {
320 return FAILURE(0);
321 }
322
323 glShaderSource(shader, 1, &text, nullptr);
324 glCompileShader(shader);
325 GLint compiled = 0;
326 glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
327 if (!compiled) {
328 GLint infoLen = 0;
329 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
330 if(infoLen > 1) {
331 std::vector<char> msg(infoLen + 1);
332 glGetShaderInfoLog(shader, infoLen, nullptr, msg.data());
333 msg[infoLen] = 0;
334 ALOGE("%s:%d: error compiling shader '%s' (type=%d): '%s'",
335 __func__, __LINE__, text, type, msg.data());
336 }
337 glDeleteShader(shader);
338 return FAILURE(0);
339 }
340
341 if (mShader) {
342 glDeleteShader(mShader);
343 }
344
345 mShader = shader;
346 return shader;
347 }
348
AutoProgram(AutoProgram && rhs)349 AutoProgram::AutoProgram(AutoProgram&& rhs) noexcept
350 : mProgram(std::exchange(rhs.mProgram, 0)) {}
351
operator =(AutoProgram && rhs)352 AutoProgram& AutoProgram::operator=(AutoProgram&& rhs) noexcept {
353 if (this != &rhs) {
354 mProgram = std::exchange(rhs.mProgram, 0);
355 }
356 return *this;
357 }
358
~AutoProgram()359 AutoProgram::~AutoProgram() {
360 clear();
361 }
362
clear()363 void AutoProgram::clear() {
364 if (mProgram) {
365 glDeleteProgram(mProgram);
366 mProgram = 0;
367 }
368 }
369
link(const GLuint vertexShader,const GLuint fragmentShader)370 bool AutoProgram::link(const GLuint vertexShader,
371 const GLuint fragmentShader) {
372 const GLuint program = glCreateProgram();
373 if (!program) {
374 return FAILURE(false);
375 }
376
377 glAttachShader(program, vertexShader);
378 glAttachShader(program, fragmentShader);
379 glLinkProgram(program);
380
381 GLint linked = 0;
382 glGetProgramiv(program, GL_LINK_STATUS, &linked);
383 if (!linked) {
384 GLint infoLen = 0;
385 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen);
386 if(infoLen > 1) {
387 std::vector<char> msg(infoLen + 1);
388 glGetProgramInfoLog(program, infoLen, nullptr, msg.data());
389 msg[infoLen] = 0;
390 ALOGE("%s:%d: error linking shaders: '%s'",
391 __func__, __LINE__, msg.data());
392 }
393
394 glDeleteProgram(program);
395 return FAILURE(false);
396 }
397
398 if (mProgram) {
399 glDeleteProgram(mProgram);
400 }
401
402 mProgram = program;
403 return true;
404 }
405
getAttribLocation(const char * name) const406 GLint AutoProgram::getAttribLocation(const char* name) const {
407 if (mProgram > 0) {
408 const GLint result = glGetAttribLocation(mProgram, name);
409 return (result >= 0) ? result : FAILURE(-1);
410 } else {
411 return FAILURE(-1);
412 }
413 }
414
getUniformLocation(const char * name) const415 GLint AutoProgram::getUniformLocation(const char* name) const {
416 if (mProgram > 0) {
417 const GLint result = glGetUniformLocation(mProgram, name);
418 return (result >= 0) ? result : FAILURE(-1);
419 } else {
420 return FAILURE(-1);
421 }
422 }
423
424 // https://registry.khronos.org/OpenGL-Refpages/gl2.1/xhtml/glFrustum.xml
frustum(float m44[],const double left,const double right,const double bottom,const double top,const double near,const double far)425 void frustum(float m44[],
426 const double left, const double right,
427 const double bottom, const double top,
428 const double near, const double far) {
429 const double invWidth = 1.0 / (right - left);
430 const double invHeight = 1.0 / (top - bottom);
431 const double invDepth = 1.0 / (far - near);
432 const double near2 = 2 * near;
433
434 m44[0] = near2 * invWidth;
435 m44[1] = 0;
436 m44[2] = (right + left) * invWidth;
437 m44[3] = 0;
438
439 m44[4] = 0;
440 m44[5] = near2 * invHeight;
441 m44[6] = (top + bottom) * invHeight;
442 m44[7] = 0;
443
444 m44[8] = 0;
445 m44[9] = 0;
446 m44[10] = -(far + near) * invDepth;
447 m44[11] = -far * near2 * invDepth;
448
449 m44[12] = 0;
450 m44[13] = 0;
451 m44[14] = -1;
452 m44[15] = 0;
453 }
454
455 /*
456 * https://registry.khronos.org/OpenGL-Refpages/gl2.1/xhtml/gluLookAt.xml
457 * https://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
458 *
459 * Here we calculate {Side, Up, Backwards} from Euler angles in the XYZ order:
460 *
461 * [ 1, 0, 0 ] [ cosY, 0, sinY ] [ cosZ, -sinZ, 0 ] [ sx, ux, bx ]
462 * [ 0, cosX, -sinX ] * [ 0, 1, 0 ] * [ sinZ, cosZ, 0 ] = [ sy, uy, by ]
463 * [ 0, sinX, cosX ] [ -sinY, 0, cosY ] [ 0, 0, 1 ] [ sz, uz, bz ]
464 *
465 * We calculate `backwards` because the camera looks into the negative Z
466 * direction, so instead of calculating camera's forward and negating it twice,
467 * let's call it `backwards`.
468 *
469 * After multiplying the first two:
470 * [ cosY, 0, sinY ]
471 * [ sinX * sinY, cosX, -sinX * cosY ]
472 * [ -cosX * sinY, sinX, cosX * cosY ]
473 *
474 * The final result:
475 * [ cosY * cosZ, -cosY * sinZ, sinY ]
476 * [ sinX * sinY * cosZ + cosX * sinZ, -sinX * sinY * sinZ + cosX * cosZ, -sinX * cosY ]
477 * [ -cosX * sinY * cosZ + sinX * sinZ, cosX * sinY * sinZ + sinX * cosZ, cosX * cosY ]
478 *
479 * {Side, Up, Backwards} are the columns in the matrix above.
480 */
lookAtXyzRot(float m44[],const float eye3[],const float rot3[])481 void lookAtXyzRot(float m44[], const float eye3[], const float rot3[]) {
482 const double sinX = sin(rot3[0]);
483 const double cosX = cos(rot3[0]);
484 const double sinY = sin(rot3[1]);
485 const double cosY = cos(rot3[1]);
486 const double sinZ = sin(rot3[2]);
487 const double cosZ = cos(rot3[2]);
488
489 m44[0] = cosY * cosZ;
490 m44[1] = sinX * sinY * cosZ + cosX * sinZ;
491 m44[2] = -cosX * sinY * cosZ + sinX * sinZ;
492 m44[4] = -cosY * sinZ;
493 m44[5] = -sinX * sinY * sinZ + cosX * cosZ;
494 m44[6] = cosX * sinY * sinZ + sinX * cosZ;
495 m44[8] = sinY;
496 m44[9] = -sinX * cosY;
497 m44[10] = cosX * cosY;
498 lookAtEyeCoordinates(m44, eye3);
499 }
500
mulM44(float m44[],const float lhs44[],const float rhs44[])501 void mulM44(float m44[], const float lhs44[], const float rhs44[]) {
502 m44[0] = lhs44[0] * rhs44[0] + lhs44[1] * rhs44[4] + lhs44[2] * rhs44[8] + lhs44[3] * rhs44[12];
503 m44[1] = lhs44[0] * rhs44[1] + lhs44[1] * rhs44[5] + lhs44[2] * rhs44[9] + lhs44[3] * rhs44[13];
504 m44[2] = lhs44[0] * rhs44[2] + lhs44[1] * rhs44[6] + lhs44[2] * rhs44[10] + lhs44[3] * rhs44[14];
505 m44[3] = lhs44[0] * rhs44[3] + lhs44[1] * rhs44[7] + lhs44[2] * rhs44[11] + lhs44[3] * rhs44[15];
506
507 m44[4] = lhs44[4] * rhs44[0] + lhs44[5] * rhs44[4] + lhs44[6] * rhs44[8] + lhs44[7] * rhs44[12];
508 m44[5] = lhs44[4] * rhs44[1] + lhs44[5] * rhs44[5] + lhs44[6] * rhs44[9] + lhs44[7] * rhs44[13];
509 m44[6] = lhs44[4] * rhs44[2] + lhs44[5] * rhs44[6] + lhs44[6] * rhs44[10] + lhs44[7] * rhs44[14];
510 m44[7] = lhs44[4] * rhs44[3] + lhs44[5] * rhs44[7] + lhs44[6] * rhs44[11] + lhs44[7] * rhs44[15];
511
512 m44[8] = lhs44[8] * rhs44[0] + lhs44[9] * rhs44[4] + lhs44[10] * rhs44[8] + lhs44[11] * rhs44[12];
513 m44[9] = lhs44[8] * rhs44[1] + lhs44[9] * rhs44[5] + lhs44[10] * rhs44[9] + lhs44[11] * rhs44[13];
514 m44[10] = lhs44[8] * rhs44[2] + lhs44[9] * rhs44[6] + lhs44[10] * rhs44[10] + lhs44[11] * rhs44[14];
515 m44[11] = lhs44[8] * rhs44[3] + lhs44[9] * rhs44[7] + lhs44[10] * rhs44[11] + lhs44[11] * rhs44[15];
516
517 m44[12] = lhs44[12] * rhs44[0] + lhs44[13] * rhs44[4] + lhs44[14] * rhs44[8] + lhs44[15] * rhs44[12];
518 m44[13] = lhs44[12] * rhs44[1] + lhs44[13] * rhs44[5] + lhs44[14] * rhs44[9] + lhs44[15] * rhs44[13];
519 m44[14] = lhs44[12] * rhs44[2] + lhs44[13] * rhs44[6] + lhs44[14] * rhs44[10] + lhs44[15] * rhs44[14];
520 m44[15] = lhs44[12] * rhs44[3] + lhs44[13] * rhs44[7] + lhs44[14] * rhs44[11] + lhs44[15] * rhs44[15];
521 }
522
523 } // namespace abc3d
524 } // namespace implementation
525 } // namespace provider
526 } // namespace camera
527 } // namespace hardware
528 } // namespace android
529