• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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 <GLES2/gl2.h>
18 #include <GLES2/gl2ext.h>
19 #include <jni.h>
20 #include <math.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include "db_utilities_camera.h"
24 #include "mosaic/ImageUtils.h"
25 #include "mosaic_renderer/FrameBuffer.h"
26 #include "mosaic_renderer/WarpRenderer.h"
27 #include "mosaic_renderer/SurfaceTextureRenderer.h"
28 #include "mosaic_renderer/YVURenderer.h"
29 
30 #include "mosaic/Log.h"
31 #define LOG_TAG "MosaicRenderer"
32 
33 #include "mosaic_renderer_jni.h"
34 
35 // Texture handle
36 GLuint gSurfaceTextureID[1];
37 
38 bool gWarpImage = true;
39 
40 // Low-Res input image frame in YUVA format for preview rendering and processing
41 // and high-res YUVA input image for processing.
42 unsigned char* gPreviewImage[NR];
43 // Low-Res & high-res preview image width
44 int gPreviewImageWidth[NR];
45 // Low-Res & high-res preview image height
46 int gPreviewImageHeight[NR];
47 
48 // Semaphore to protect simultaneous read/writes from gPreviewImage
49 sem_t gPreviewImage_semaphore;
50 
51 // Off-screen preview FBO width (large enough to store the entire
52 // preview mosaic).
53 int gPreviewFBOWidth;
54 // Off-screen preview FBO height (large enough to store the entire
55 // preview mosaic).
56 int gPreviewFBOHeight;
57 
58 // gK is the transformation to map the canonical {-1,1} vertex coordinate system
59 // to the {0,gPreviewImageWidth[LR]} input image frame coordinate system before
60 // applying the given affine transformation trs. gKm is the corresponding
61 // transformation for going to the {0,gPreviewFBOWidth}.
62 double gK[9];
63 double gKinv[9];
64 double gKm[9];
65 double gKminv[9];
66 
67 // Shader to copy input SurfaceTexture into and RGBA FBO. The two shaders
68 // render to the textures with dimensions corresponding to the low-res and
69 // high-res image frames.
70 SurfaceTextureRenderer gSurfTexRenderer[NR];
71 // Off-screen FBOs to store the low-res and high-res RGBA copied out from
72 // the SurfaceTexture by the gSurfTexRenderers.
73 FrameBuffer gBufferInput[NR];
74 
75 // Shader to convert RGBA textures into YVU textures for processing
76 YVURenderer gYVURenderer[NR];
77 // Off-screen FBOs to store the low-res and high-res YVU textures for processing
78 FrameBuffer gBufferInputYVU[NR];
79 
80 // Shader to translate the flip-flop FBO - gBuffer[1-current] -> gBuffer[current]
81 WarpRenderer gWarper1;
82 // Shader to add warped current frame to the flip-flop FBO - gBuffer[current]
83 WarpRenderer gWarper2;
84 // Off-screen FBOs (flip-flop) to store the result of gWarper1 & gWarper2
85 FrameBuffer gBuffer[2];
86 
87 // Shader to warp and render the preview FBO to the screen
88 WarpRenderer gPreview;
89 
90 // Index of the gBuffer FBO gWarper1 is going to write into
91 int gCurrentFBOIndex = 0;
92 
93 // 3x3 Matrices holding the transformation of this frame (gThisH1t) and of
94 // the last frame (gLastH1t) w.r.t the first frame.
95 double gThisH1t[9];
96 double gLastH1t[9];
97 
98 // Variables to represent the fixed position of the top-left corner of the
99 // current frame in the previewFBO
100 double gCenterOffsetX = 0.0f;
101 double gCenterOffsetY = 0.0f;
102 
103 // X-Offset of the viewfinder (current frame) w.r.t
104 // (gCenterOffsetX, gCenterOffsetY). This offset varies with time and is
105 // used to pan the viewfinder across the UI layout.
106 double gPanOffset = 0.0f;
107 
108 // Variables tracking the translation value for the current frame and the
109 // last frame (both w.r.t the first frame). The difference between these
110 // values is used to control the panning speed of the viewfinder display
111 // on the UI screen.
112 double gThisTx = 0.0f;
113 double gLastTx = 0.0f;
114 
115 // These are the scale factors used by the gPreview shader to ensure that
116 // the image frame is correctly scaled to the full UI layout height while
117 // maintaining its aspect ratio
118 double gUILayoutScalingX = 1.0f;
119 double gUILayoutScalingY = 1.0f;
120 
121 // Whether the view that we will render preview FBO onto is in landscape or portrait
122 // orientation.
123 bool gIsLandscapeOrientation = true;
124 
125 // State of the viewfinder. Set to false when the viewfinder hits the UI edge.
126 bool gPanViewfinder = true;
127 
128 // Affine transformation in GL 4x4 format (column-major) to warp the
129 // last frame mosaic into the current frame coordinate system.
130 GLfloat g_dAffinetransGL[16];
131 double g_dAffinetrans[16];
132 
133 // Affine transformation in GL 4x4 format (column-major) to translate the
134 // preview FBO across the screen (viewfinder panning).
135 GLfloat g_dAffinetransPanGL[16];
136 double g_dAffinetransPan[16];
137 
138 // XY translation in GL 4x4 format (column-major) to center the current
139 // preview mosaic in the preview FBO
140 GLfloat g_dTranslationToFBOCenterGL[16];
141 double g_dTranslationToFBOCenter[16];
142 
143 // GL 4x4 Identity transformation
144 GLfloat g_dAffinetransIdentGL[] = {
145     1., 0., 0., 0.,
146     0., 1., 0., 0.,
147     0., 0., 1., 0.,
148     0., 0., 0., 1.};
149 
150 // GL 4x4 Rotation transformation (column-majored): 90 degree
151 GLfloat g_dAffinetransRotation90GL[] = {
152     0., 1., 0., 0.,
153     -1., 0., 0., 0.,
154     0., 0., 1., 0.,
155     0., 0., 0., 1.};
156 
157 // 3x3 Rotation transformation (row-majored): 90 degree
158 double gRotation90[] = {
159     0., -1., 0.,
160     1., 0., 0.,
161     0., 0., 1.,};
162 
163 
164 float g_dIdent3x3[] = {
165     1.0, 0.0, 0.0,
166     0.0, 1.0, 0.0,
167     0.0, 0.0, 1.0};
168 
169 const int GL_TEXTURE_EXTERNAL_OES_ENUM = 0x8D65;
170 
printGLString(const char * name,GLenum s)171 static void printGLString(const char *name, GLenum s) {
172     const char *v = (const char *) glGetString(s);
173     LOGI("GL %s = %s", name, v);
174 }
175 
176 // @return false if there was an error
checkGlError(const char * op)177 bool checkGlError(const char* op) {
178     GLint error = glGetError();
179     if (error != 0) {
180         LOGE("after %s() glError (0x%x)", op, error);
181         return false;
182     }
183     return true;
184 }
185 
bindSurfaceTexture(GLuint texId)186 void bindSurfaceTexture(GLuint texId)
187 {
188     glBindTexture(GL_TEXTURE_EXTERNAL_OES_ENUM, texId);
189 
190     // Can't do mipmapping with camera source
191     glTexParameterf(GL_TEXTURE_EXTERNAL_OES_ENUM, GL_TEXTURE_MIN_FILTER,
192             GL_LINEAR);
193     glTexParameterf(GL_TEXTURE_EXTERNAL_OES_ENUM, GL_TEXTURE_MAG_FILTER,
194             GL_LINEAR);
195     // Clamp to edge is the only option
196     glTexParameteri(GL_TEXTURE_EXTERNAL_OES_ENUM, GL_TEXTURE_WRAP_S,
197             GL_CLAMP_TO_EDGE);
198     glTexParameteri(GL_TEXTURE_EXTERNAL_OES_ENUM, GL_TEXTURE_WRAP_T,
199             GL_CLAMP_TO_EDGE);
200 }
201 
ClearPreviewImage(int mID)202 void ClearPreviewImage(int mID)
203 {
204     unsigned char* ptr = gPreviewImage[mID];
205     for(int j = 0, i = 0;
206             j < gPreviewImageWidth[mID] * gPreviewImageHeight[mID] * 4;
207             j += 4)
208     {
209             ptr[i++] = 0;
210             ptr[i++] = 0;
211             ptr[i++] = 0;
212             ptr[i++] = 255;
213     }
214 
215 }
216 
ConvertAffine3x3toGL4x4(double * matGL44,double * mat33)217 void ConvertAffine3x3toGL4x4(double *matGL44, double *mat33)
218 {
219     matGL44[0] = mat33[0];
220     matGL44[1] = mat33[3];
221     matGL44[2] = 0.0;
222     matGL44[3] = mat33[6];
223 
224     matGL44[4] = mat33[1];
225     matGL44[5] = mat33[4];
226     matGL44[6] = 0.0;
227     matGL44[7] = mat33[7];
228 
229     matGL44[8] = 0;
230     matGL44[9] = 0;
231     matGL44[10] = 1.0;
232     matGL44[11] = 0.0;
233 
234     matGL44[12] = mat33[2];
235     matGL44[13] = mat33[5];
236     matGL44[14] = 0.0;
237     matGL44[15] = mat33[8];
238 }
239 
continuePanningFBO(double panOffset)240 bool continuePanningFBO(double panOffset) {
241     double normalizedScreenLimitLeft = -1.0 + VIEWPORT_BORDER_FACTOR_HORZ * 2.0;
242     double normalizedScreenLimitRight = 1.0 - VIEWPORT_BORDER_FACTOR_HORZ * 2.0;
243     double normalizedXPositionOnScreenLeft;
244     double normalizedXPositionOnScreenRight;
245 
246     // Compute the position of the current frame in the screen coordinate system
247     if (gIsLandscapeOrientation) {
248         normalizedXPositionOnScreenLeft = (2.0 *
249             (gCenterOffsetX + panOffset) / gPreviewFBOWidth - 1.0) *
250             gUILayoutScalingX;
251         normalizedXPositionOnScreenRight = (2.0 *
252             ((gCenterOffsetX + panOffset) + gPreviewImageWidth[HR]) /
253             gPreviewFBOWidth - 1.0) * gUILayoutScalingX;
254     } else {
255         normalizedXPositionOnScreenLeft = (2.0 *
256             (gCenterOffsetX + panOffset) / gPreviewFBOWidth - 1.0) *
257             gUILayoutScalingY;
258         normalizedXPositionOnScreenRight = (2.0 *
259             ((gCenterOffsetX + panOffset) + gPreviewImageWidth[HR]) /
260             gPreviewFBOWidth - 1.0) * gUILayoutScalingY;
261     }
262 
263     // Stop the viewfinder panning if we hit the maximum border allowed for
264     // this UI layout
265     if (normalizedXPositionOnScreenRight > normalizedScreenLimitRight ||
266             normalizedXPositionOnScreenLeft < normalizedScreenLimitLeft) {
267         return false;
268     } else {
269         return true;
270     }
271 }
272 
273 // This function computes fills the 4x4 matrices g_dAffinetrans,
274 // and g_dAffinetransPan using the specified 3x3 affine
275 // transformation between the first captured frame and the current frame.
276 // The computed g_dAffinetrans is such that it warps the preview mosaic in
277 // the last frame's coordinate system into the coordinate system of the
278 // current frame. Thus, applying this transformation will create the current
279 // frame mosaic but with the current frame missing. This frame will then be
280 // pasted in by gWarper2 after translating it by g_dTranslationToFBOCenter.
281 // The computed g_dAffinetransPan is such that it offsets the computed preview
282 // mosaic horizontally to make the viewfinder pan within the UI layout.
UpdateWarpTransformation(float * trs)283 void UpdateWarpTransformation(float *trs)
284 {
285     double H[9], Hp[9], Htemp1[9], Htemp2[9], T[9];
286 
287     for(int i = 0; i < 9; i++)
288     {
289         gThisH1t[i] = trs[i];
290     }
291 
292     // Alignment is done based on low-res data.
293     // To render the preview mosaic, the translation of the high-res mosaic is estimated to
294     // H2L_FACTOR x low-res-based tranlation.
295     gThisH1t[2] *= H2L_FACTOR;
296     gThisH1t[5] *= H2L_FACTOR;
297 
298     db_Identity3x3(T);
299     T[2] = -gCenterOffsetX;
300     T[5] = -gCenterOffsetY;
301 
302     // H = ( inv(gThisH1t) * gLastH1t ) * T
303     db_Identity3x3(Htemp1);
304     db_Identity3x3(Htemp2);
305     db_Identity3x3(H);
306     db_InvertAffineTransform(Htemp1, gThisH1t);
307     db_Multiply3x3_3x3(Htemp2, Htemp1, gLastH1t);
308     db_Multiply3x3_3x3(H, Htemp2, T);
309 
310     for(int i = 0; i < 9; i++)
311     {
312         gLastH1t[i] = gThisH1t[i];
313     }
314 
315     // Move the origin such that the frame is centered in the previewFBO
316     // i.e. H = inv(T) * H
317     H[2] += gCenterOffsetX;
318     H[5] += gCenterOffsetY;
319 
320     // Hp = inv(Km) * H * Km
321     // Km moves the coordinate system from openGL to image pixels so
322     // that the alignment transform H can be applied to them.
323     // inv(Km) moves the coordinate system back to openGL normalized
324     // coordinates so that the shader can correctly render it.
325     db_Identity3x3(Htemp1);
326     db_Multiply3x3_3x3(Htemp1, H, gKm);
327     db_Multiply3x3_3x3(Hp, gKminv, Htemp1);
328 
329     ConvertAffine3x3toGL4x4(g_dAffinetrans, Hp);
330 
331     ////////////////////////////////////////////////
332     ////// Compute g_dAffinetransPan now...   //////
333     ////////////////////////////////////////////////
334 
335     gThisTx = trs[2];
336 
337     if(gPanViewfinder)
338     {
339         gPanOffset += (gThisTx - gLastTx) * VIEWFINDER_PAN_FACTOR_HORZ;
340     }
341 
342     gLastTx = gThisTx;
343     gPanViewfinder = continuePanningFBO(gPanOffset);
344 
345     db_Identity3x3(H);
346     H[2] = gPanOffset;
347 
348     // Hp = inv(Km) * H * Km
349     db_Identity3x3(Htemp1);
350     db_Multiply3x3_3x3(Htemp1, H, gKm);
351     db_Multiply3x3_3x3(Hp, gKminv, Htemp1);
352 
353     if (gIsLandscapeOrientation) {
354         ConvertAffine3x3toGL4x4(g_dAffinetransPan, Hp);
355     } else {
356         // rotate Hp by 90 degress.
357         db_Multiply3x3_3x3(Htemp1, gRotation90, Hp);
358         ConvertAffine3x3toGL4x4(g_dAffinetransPan, Htemp1);
359     }
360 }
361 
AllocateTextureMemory(int widthHR,int heightHR,int widthLR,int heightLR)362 void AllocateTextureMemory(int widthHR, int heightHR, int widthLR, int heightLR)
363 {
364     gPreviewImageWidth[HR] = widthHR;
365     gPreviewImageHeight[HR] = heightHR;
366 
367     gPreviewImageWidth[LR] = widthLR;
368     gPreviewImageHeight[LR] = heightLR;
369 
370     sem_init(&gPreviewImage_semaphore, 0, 1);
371 
372     sem_wait(&gPreviewImage_semaphore);
373     gPreviewImage[LR] = ImageUtils::allocateImage(gPreviewImageWidth[LR],
374             gPreviewImageHeight[LR], 4);
375     ClearPreviewImage(LR);
376     gPreviewImage[HR] = ImageUtils::allocateImage(gPreviewImageWidth[HR],
377             gPreviewImageHeight[HR], 4);
378     ClearPreviewImage(HR);
379     sem_post(&gPreviewImage_semaphore);
380 
381     gPreviewFBOWidth = PREVIEW_FBO_WIDTH_SCALE * gPreviewImageWidth[HR];
382     gPreviewFBOHeight = PREVIEW_FBO_HEIGHT_SCALE * gPreviewImageHeight[HR];
383 
384     // The origin is such that the current frame will sit with its center
385     // at the center of the previewFBO
386     gCenterOffsetX = (gPreviewFBOWidth / 2 - gPreviewImageWidth[HR] / 2);
387     gCenterOffsetY = (gPreviewFBOHeight / 2 - gPreviewImageHeight[HR] / 2);
388 
389     gPanOffset = 0.0f;
390 
391     db_Identity3x3(gThisH1t);
392     db_Identity3x3(gLastH1t);
393 
394     gPanViewfinder = true;
395 
396     int w = gPreviewImageWidth[HR];
397     int h = gPreviewImageHeight[HR];
398 
399     int wm = gPreviewFBOWidth;
400     int hm = gPreviewFBOHeight;
401 
402     // K is the transformation to map the canonical [-1,1] vertex coordinate
403     // system to the [0,w] image coordinate system before applying the given
404     // affine transformation trs.
405     gKm[0] = wm / 2.0 - 0.5;
406     gKm[1] = 0.0;
407     gKm[2] = wm / 2.0 - 0.5;
408     gKm[3] = 0.0;
409     gKm[4] = hm / 2.0 - 0.5;
410     gKm[5] = hm / 2.0 - 0.5;
411     gKm[6] = 0.0;
412     gKm[7] = 0.0;
413     gKm[8] = 1.0;
414 
415     gK[0] = w / 2.0 - 0.5;
416     gK[1] = 0.0;
417     gK[2] = w / 2.0 - 0.5;
418     gK[3] = 0.0;
419     gK[4] = h / 2.0 - 0.5;
420     gK[5] = h / 2.0 - 0.5;
421     gK[6] = 0.0;
422     gK[7] = 0.0;
423     gK[8] = 1.0;
424 
425     db_Identity3x3(gKinv);
426     db_InvertCalibrationMatrix(gKinv, gK);
427 
428     db_Identity3x3(gKminv);
429     db_InvertCalibrationMatrix(gKminv, gKm);
430 
431     //////////////////////////////////////////
432     ////// Compute g_Translation now... //////
433     //////////////////////////////////////////
434     double T[9], Tp[9], Ttemp[9];
435 
436     db_Identity3x3(T);
437     T[2] = gCenterOffsetX;
438     T[5] = gCenterOffsetY;
439 
440     // Tp = inv(K) * T * K
441     db_Identity3x3(Ttemp);
442     db_Multiply3x3_3x3(Ttemp, T, gK);
443     db_Multiply3x3_3x3(Tp, gKinv, Ttemp);
444 
445     ConvertAffine3x3toGL4x4(g_dTranslationToFBOCenter, Tp);
446 
447     UpdateWarpTransformation(g_dIdent3x3);
448 }
449 
FreeTextureMemory()450 void FreeTextureMemory()
451 {
452     sem_wait(&gPreviewImage_semaphore);
453     ImageUtils::freeImage(gPreviewImage[LR]);
454     ImageUtils::freeImage(gPreviewImage[HR]);
455     sem_post(&gPreviewImage_semaphore);
456 
457     sem_destroy(&gPreviewImage_semaphore);
458 }
459 
460 extern "C"
461 {
462     JNIEXPORT jint JNICALL Java_com_android_camera_panorama_MosaicRenderer_init(
463             JNIEnv * env, jobject obj);
464     JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_reset(
465             JNIEnv * env, jobject obj,  jint width, jint height,
466             jboolean isLandscapeOrientation);
467     JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_preprocess(
468             JNIEnv * env, jobject obj, jfloatArray stMatrix);
469     JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_transferGPUtoCPU(
470             JNIEnv * env, jobject obj);
471     JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_step(
472             JNIEnv * env, jobject obj);
473     JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_ready(
474             JNIEnv * env, jobject obj);
475     JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_setWarping(
476             JNIEnv * env, jobject obj, jboolean flag);
477 };
478 
Java_com_android_camera_panorama_MosaicRenderer_init(JNIEnv * env,jobject obj)479 JNIEXPORT jint JNICALL Java_com_android_camera_panorama_MosaicRenderer_init(
480         JNIEnv * env, jobject obj)
481 {
482     gSurfTexRenderer[LR].InitializeGLProgram();
483     gSurfTexRenderer[HR].InitializeGLProgram();
484     gYVURenderer[LR].InitializeGLProgram();
485     gYVURenderer[HR].InitializeGLProgram();
486     gWarper1.InitializeGLProgram();
487     gWarper2.InitializeGLProgram();
488     gPreview.InitializeGLProgram();
489     gBuffer[0].InitializeGLContext();
490     gBuffer[1].InitializeGLContext();
491     gBufferInput[LR].InitializeGLContext();
492     gBufferInput[HR].InitializeGLContext();
493     gBufferInputYVU[LR].InitializeGLContext();
494     gBufferInputYVU[HR].InitializeGLContext();
495 
496     glBindFramebuffer(GL_FRAMEBUFFER, 0);
497 
498     glGenTextures(1, gSurfaceTextureID);
499     // bind the surface texture
500     bindSurfaceTexture(gSurfaceTextureID[0]);
501 
502     return (jint) gSurfaceTextureID[0];
503 }
504 
505 
calculateUILayoutScaling(int width,int height,bool isLandscape)506 void calculateUILayoutScaling(int width, int height, bool isLandscape) {
507     if (isLandscape) {
508         //  __________        ______
509         // |__________|  =>  |______|
510         // (Preview FBO)      (View)
511         //
512         // Scale the preview FBO's height to the height of view and
513         // maintain the aspect ratio of the current frame on the screen.
514         gUILayoutScalingY = PREVIEW_FBO_HEIGHT_SCALE;
515 
516         // Note that OpenGL scales a texture to view's width and height automatically.
517         // The "width / height" inverts the scaling, so as to maintain the aspect ratio
518         // of the current frame.
519         gUILayoutScalingX = ((float) (PREVIEW_FBO_WIDTH_SCALE * gPreviewImageWidth[LR])
520                 / (PREVIEW_FBO_HEIGHT_SCALE * gPreviewImageHeight[LR]) *  PREVIEW_FBO_HEIGHT_SCALE)
521                 / ((float) width / height);
522     } else {
523         //                     __
524         //  __________        |  |
525         // |__________|  =>   |  |
526         // (Preview FBO)      |  |
527         //                    |__|
528         //                   (View)
529         // Scale the preview FBO's height to the width of view and
530         // maintain the aspect ratio of the current frame on the screen.
531         gUILayoutScalingX = PREVIEW_FBO_HEIGHT_SCALE;
532 
533         // Note that OpenGL scales a texture to view's width and height automatically.
534         // The "height / width" inverts the scaling, so as to maintain the aspect ratio
535         // of the current frame.
536         gUILayoutScalingY = ((float) (PREVIEW_FBO_WIDTH_SCALE * gPreviewImageWidth[LR])
537                 / (PREVIEW_FBO_HEIGHT_SCALE * gPreviewImageHeight[LR]) *  PREVIEW_FBO_HEIGHT_SCALE)
538                 / ((float) height / width);
539 
540     }
541 }
542 
Java_com_android_camera_panorama_MosaicRenderer_reset(JNIEnv * env,jobject obj,jint width,jint height,jboolean isLandscapeOrientation)543 JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_reset(
544         JNIEnv * env, jobject obj,  jint width, jint height, jboolean isLandscapeOrientation)
545 {
546     gIsLandscapeOrientation = isLandscapeOrientation;
547     calculateUILayoutScaling(width, height, gIsLandscapeOrientation);
548 
549     gBuffer[0].Init(gPreviewFBOWidth, gPreviewFBOHeight, GL_RGBA);
550     gBuffer[1].Init(gPreviewFBOWidth, gPreviewFBOHeight, GL_RGBA);
551 
552     gBufferInput[LR].Init(gPreviewImageWidth[LR],
553             gPreviewImageHeight[LR], GL_RGBA);
554 
555     gBufferInput[HR].Init(gPreviewImageWidth[HR],
556             gPreviewImageHeight[HR], GL_RGBA);
557 
558     gBufferInputYVU[LR].Init(gPreviewImageWidth[LR],
559             gPreviewImageHeight[LR], GL_RGBA);
560 
561     gBufferInputYVU[HR].Init(gPreviewImageWidth[HR],
562             gPreviewImageHeight[HR], GL_RGBA);
563 
564     sem_wait(&gPreviewImage_semaphore);
565     ClearPreviewImage(LR);
566     ClearPreviewImage(HR);
567     sem_post(&gPreviewImage_semaphore);
568 
569     // bind the surface texture
570     bindSurfaceTexture(gSurfaceTextureID[0]);
571 
572     gSurfTexRenderer[LR].SetupGraphics(&gBufferInput[LR]);
573     gSurfTexRenderer[LR].Clear(0.0, 0.0, 0.0, 1.0);
574     gSurfTexRenderer[LR].SetViewportMatrix(1, 1, 1, 1);
575     gSurfTexRenderer[LR].SetScalingMatrix(1.0f, -1.0f);
576     gSurfTexRenderer[LR].SetInputTextureName(gSurfaceTextureID[0]);
577     gSurfTexRenderer[LR].SetInputTextureType(GL_TEXTURE_EXTERNAL_OES_ENUM);
578 
579     gSurfTexRenderer[HR].SetupGraphics(&gBufferInput[HR]);
580     gSurfTexRenderer[HR].Clear(0.0, 0.0, 0.0, 1.0);
581     gSurfTexRenderer[HR].SetViewportMatrix(1, 1, 1, 1);
582     gSurfTexRenderer[HR].SetScalingMatrix(1.0f, -1.0f);
583     gSurfTexRenderer[HR].SetInputTextureName(gSurfaceTextureID[0]);
584     gSurfTexRenderer[HR].SetInputTextureType(GL_TEXTURE_EXTERNAL_OES_ENUM);
585 
586     gYVURenderer[LR].SetupGraphics(&gBufferInputYVU[LR]);
587     gYVURenderer[LR].Clear(0.0, 0.0, 0.0, 1.0);
588     gYVURenderer[LR].SetInputTextureName(gBufferInput[LR].GetTextureName());
589     gYVURenderer[LR].SetInputTextureType(GL_TEXTURE_2D);
590 
591     gYVURenderer[HR].SetupGraphics(&gBufferInputYVU[HR]);
592     gYVURenderer[HR].Clear(0.0, 0.0, 0.0, 1.0);
593     gYVURenderer[HR].SetInputTextureName(gBufferInput[HR].GetTextureName());
594     gYVURenderer[HR].SetInputTextureType(GL_TEXTURE_2D);
595 
596     // gBuffer[1-gCurrentFBOIndex] --> gWarper1 --> gBuffer[gCurrentFBOIndex]
597     gWarper1.SetupGraphics(&gBuffer[gCurrentFBOIndex]);
598     gWarper1.Clear(0.0, 0.0, 0.0, 1.0);
599     gWarper1.SetViewportMatrix(1, 1, 1, 1);
600     gWarper1.SetScalingMatrix(1.0f, 1.0f);
601     gWarper1.SetInputTextureName(gBuffer[1 - gCurrentFBOIndex].GetTextureName());
602     gWarper1.SetInputTextureType(GL_TEXTURE_2D);
603 
604     // gBufferInput[HR] --> gWarper2 --> gBuffer[gCurrentFBOIndex]
605     gWarper2.SetupGraphics(&gBuffer[gCurrentFBOIndex]);
606     gWarper2.Clear(0.0, 0.0, 0.0, 1.0);
607     gWarper2.SetViewportMatrix(gPreviewImageWidth[HR],
608             gPreviewImageHeight[HR], gBuffer[gCurrentFBOIndex].GetWidth(),
609             gBuffer[gCurrentFBOIndex].GetHeight());
610     gWarper2.SetScalingMatrix(1.0f, 1.0f);
611     gWarper2.SetInputTextureName(gBufferInput[HR].GetTextureName());
612     gWarper2.SetInputTextureType(GL_TEXTURE_2D);
613 
614     gPreview.SetupGraphics(width, height);
615     gPreview.Clear(0.0, 0.0, 0.0, 1.0);
616     gPreview.SetViewportMatrix(1, 1, 1, 1);
617 
618     // Scale the previewFBO so that the viewfinder window fills the layout height
619     // while maintaining the image aspect ratio
620     gPreview.SetScalingMatrix(gUILayoutScalingX, -1.0f * gUILayoutScalingY);
621     gPreview.SetInputTextureName(gBuffer[gCurrentFBOIndex].GetTextureName());
622     gPreview.SetInputTextureType(GL_TEXTURE_2D);
623 }
624 
Java_com_android_camera_panorama_MosaicRenderer_preprocess(JNIEnv * env,jobject obj,jfloatArray stMatrix)625 JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_preprocess(
626         JNIEnv * env, jobject obj, jfloatArray stMatrix)
627 {
628     jfloat *stmat = env->GetFloatArrayElements(stMatrix, 0);
629 
630     gSurfTexRenderer[LR].SetSTMatrix((float*) stmat);
631     gSurfTexRenderer[HR].SetSTMatrix((float*) stmat);
632 
633     env->ReleaseFloatArrayElements(stMatrix, stmat, 0);
634 
635     gSurfTexRenderer[LR].DrawTexture(g_dAffinetransIdentGL);
636     gSurfTexRenderer[HR].DrawTexture(g_dAffinetransIdentGL);
637 }
638 
639 #ifndef now_ms
640 #include <time.h>
641 static double
now_ms(void)642 now_ms(void)
643 {
644     //struct timespec res;
645     struct timeval res;
646     //clock_gettime(CLOCK_REALTIME, &res);
647     gettimeofday(&res, NULL);
648     return 1000.0*res.tv_sec + (double)res.tv_usec/1e3;
649 }
650 #endif
651 
652 
653 
Java_com_android_camera_panorama_MosaicRenderer_transferGPUtoCPU(JNIEnv * env,jobject obj)654 JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_transferGPUtoCPU(
655         JNIEnv * env, jobject obj)
656 {
657     double t0, t1, time_c;
658 
659     gYVURenderer[LR].DrawTexture();
660     gYVURenderer[HR].DrawTexture();
661 
662     sem_wait(&gPreviewImage_semaphore);
663     // Bind to the input LR FBO and read the Low-Res data from there...
664     glBindFramebuffer(GL_FRAMEBUFFER, gBufferInputYVU[LR].GetFrameBufferName());
665     t0 = now_ms();
666     glReadPixels(0,
667                  0,
668                  gBufferInput[LR].GetWidth(),
669                  gBufferInput[LR].GetHeight(),
670                  GL_RGBA,
671                  GL_UNSIGNED_BYTE,
672                  gPreviewImage[LR]);
673 
674     checkGlError("glReadPixels LR");
675 
676     // Bind to the input HR FBO and read the high-res data from there...
677     glBindFramebuffer(GL_FRAMEBUFFER, gBufferInputYVU[HR].GetFrameBufferName());
678     t0 = now_ms();
679     glReadPixels(0,
680                  0,
681                  gBufferInput[HR].GetWidth(),
682                  gBufferInput[HR].GetHeight(),
683                  GL_RGBA,
684                  GL_UNSIGNED_BYTE,
685                  gPreviewImage[HR]);
686 
687     checkGlError("glReadPixels HR");
688 
689     sem_post(&gPreviewImage_semaphore);
690 }
691 
Java_com_android_camera_panorama_MosaicRenderer_step(JNIEnv * env,jobject obj)692 JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_step(
693         JNIEnv * env, jobject obj)
694 {
695     if(!gWarpImage) // ViewFinder
696     {
697         gWarper2.SetupGraphics(&gBuffer[gCurrentFBOIndex]);
698         gPreview.SetInputTextureName(gBuffer[gCurrentFBOIndex].GetTextureName());
699 
700         gWarper2.DrawTexture(g_dTranslationToFBOCenterGL);
701 
702         if (gIsLandscapeOrientation) {
703             gPreview.DrawTexture(g_dAffinetransIdentGL);
704         } else {
705             gPreview.DrawTexture(g_dAffinetransRotation90GL);
706         }
707     }
708     else
709     {
710         gWarper1.SetupGraphics(&gBuffer[gCurrentFBOIndex]);
711         // Clear the destination so that we can paint on it afresh
712         gWarper1.Clear(0.0, 0.0, 0.0, 1.0);
713         gWarper1.SetInputTextureName(
714                 gBuffer[1 - gCurrentFBOIndex].GetTextureName());
715         gWarper2.SetupGraphics(&gBuffer[gCurrentFBOIndex]);
716         gPreview.SetInputTextureName(gBuffer[gCurrentFBOIndex].GetTextureName());
717 
718         gWarper1.DrawTexture(g_dAffinetransGL);
719         gWarper2.DrawTexture(g_dTranslationToFBOCenterGL);
720         gPreview.DrawTexture(g_dAffinetransPanGL);
721 
722         gCurrentFBOIndex = 1 - gCurrentFBOIndex;
723     }
724 }
725 
Java_com_android_camera_panorama_MosaicRenderer_setWarping(JNIEnv * env,jobject obj,jboolean flag)726 JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_setWarping(
727         JNIEnv * env, jobject obj, jboolean flag)
728 {
729     // TODO: Review this logic
730     if(gWarpImage != (bool) flag) //switching from viewfinder to capture or vice-versa
731     {
732         // Clear gBuffer[0]
733         gWarper1.SetupGraphics(&gBuffer[0]);
734         gWarper1.Clear(0.0, 0.0, 0.0, 1.0);
735         // Clear gBuffer[1]
736         gWarper1.SetupGraphics(&gBuffer[1]);
737         gWarper1.Clear(0.0, 0.0, 0.0, 1.0);
738         // Clear the screen to black.
739         gPreview.Clear(0.0, 0.0, 0.0, 1.0);
740 
741         gLastTx = 0.0f;
742         gPanOffset = 0.0f;
743         gPanViewfinder = true;
744 
745         db_Identity3x3(gThisH1t);
746         db_Identity3x3(gLastH1t);
747     }
748 
749     gWarpImage = (bool)flag;
750 }
751 
752 
Java_com_android_camera_panorama_MosaicRenderer_ready(JNIEnv * env,jobject obj)753 JNIEXPORT void JNICALL Java_com_android_camera_panorama_MosaicRenderer_ready(
754         JNIEnv * env, jobject obj)
755 {
756     for(int i=0; i<16; i++)
757     {
758         g_dAffinetransGL[i] = g_dAffinetrans[i];
759         g_dAffinetransPanGL[i] = g_dAffinetransPan[i];
760         g_dTranslationToFBOCenterGL[i] = g_dTranslationToFBOCenter[i];
761     }
762 }
763