mosaic_renderer_jni.cpp revision b96ce59e1d477622f9a3c235135d7040f642e262
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
36GLuint gSurfaceTextureID[1];
37
38bool 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.
42unsigned char* gPreviewImage[NR];
43// Low-Res & high-res preview image width
44int gPreviewImageWidth[NR];
45// Low-Res & high-res preview image height
46int gPreviewImageHeight[NR];
47
48// Semaphore to protect simultaneous read/writes from gPreviewImage
49sem_t gPreviewImage_semaphore;
50
51// Off-screen preview FBO width (large enough to store the entire
52// preview mosaic).
53int gPreviewFBOWidth;
54// Off-screen preview FBO height (large enough to store the entire
55// preview mosaic).
56int 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}.
62double gK[9];
63double gKinv[9];
64double gKm[9];
65double 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.
70SurfaceTextureRenderer gSurfTexRenderer[NR];
71// Off-screen FBOs to store the low-res and high-res RGBA copied out from
72// the SurfaceTexture by the gSurfTexRenderers.
73FrameBuffer gBufferInput[NR];
74
75// Shader to convert RGBA textures into YVU textures for processing
76YVURenderer gYVURenderer[NR];
77// Off-screen FBOs to store the low-res and high-res YVU textures for processing
78FrameBuffer gBufferInputYVU[NR];
79
80// Shader to translate the flip-flop FBO - gBuffer[1-current] -> gBuffer[current]
81WarpRenderer gWarper1;
82// Shader to add warped current frame to the flip-flop FBO - gBuffer[current]
83WarpRenderer gWarper2;
84// Off-screen FBOs (flip-flop) to store the result of gWarper1 & gWarper2
85FrameBuffer gBuffer[2];
86
87// Shader to warp and render the preview FBO to the screen
88WarpRenderer gPreview;
89
90// Index of the gBuffer FBO gWarper1 is going to write into
91int 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.
95double gThisH1t[9];
96double gLastH1t[9];
97
98// Variables to represent the fixed position of the top-left corner of the
99// current frame in the previewFBO
100double gCenterOffsetX = 0.0f;
101double 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.
106double 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.
112double gThisTx = 0.0f;
113double 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
118double gUILayoutScalingX = 1.0f;
119double gUILayoutScalingY = 1.0f;
120
121// Whether the view that we will render preview FBO onto is in landscape or portrait
122// orientation.
123bool gIsLandscapeOrientation = true;
124
125// State of the viewfinder. Set to false when the viewfinder hits the UI edge.
126bool 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.
130GLfloat g_dAffinetransGL[16];
131double g_dAffinetrans[16];
132
133// Affine transformation in GL 4x4 format (column-major) to translate the
134// preview FBO across the screen (viewfinder panning).
135GLfloat g_dAffinetransPanGL[16];
136double g_dAffinetransPan[16];
137
138// XY translation in GL 4x4 format (column-major) to center the current
139// preview mosaic in the preview FBO
140GLfloat g_dTranslationToFBOCenterGL[16];
141double g_dTranslationToFBOCenter[16];
142
143// GL 4x4 Identity transformation
144GLfloat 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
151GLfloat 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
158double gRotation90[] = {
159    0., -1., 0.,
160    1., 0., 0.,
161    0., 0., 1.,};
162
163
164float g_dIdent3x3[] = {
165    1.0, 0.0, 0.0,
166    0.0, 1.0, 0.0,
167    0.0, 0.0, 1.0};
168
169const int GL_TEXTURE_EXTERNAL_OES_ENUM = 0x8D65;
170
171static 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
177bool 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
186void 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
202void 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
217void 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
240bool 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.
283void 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
362void 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_wait(&gPreviewImage_semaphore);
371    gPreviewImage[LR] = ImageUtils::allocateImage(gPreviewImageWidth[LR],
372            gPreviewImageHeight[LR], 4);
373    gPreviewImage[HR] = ImageUtils::allocateImage(gPreviewImageWidth[HR],
374            gPreviewImageHeight[HR], 4);
375    sem_post(&gPreviewImage_semaphore);
376
377    gPreviewFBOWidth = PREVIEW_FBO_WIDTH_SCALE * gPreviewImageWidth[HR];
378    gPreviewFBOHeight = PREVIEW_FBO_HEIGHT_SCALE * gPreviewImageHeight[HR];
379
380    // The origin is such that the current frame will sit with its center
381    // at the center of the previewFBO
382    gCenterOffsetX = (gPreviewFBOWidth / 2 - gPreviewImageWidth[HR] / 2);
383    gCenterOffsetY = (gPreviewFBOHeight / 2 - gPreviewImageHeight[HR] / 2);
384
385    gPanOffset = 0.0f;
386
387    db_Identity3x3(gThisH1t);
388    db_Identity3x3(gLastH1t);
389
390    gPanViewfinder = true;
391
392    int w = gPreviewImageWidth[HR];
393    int h = gPreviewImageHeight[HR];
394
395    int wm = gPreviewFBOWidth;
396    int hm = gPreviewFBOHeight;
397
398    // K is the transformation to map the canonical [-1,1] vertex coordinate
399    // system to the [0,w] image coordinate system before applying the given
400    // affine transformation trs.
401    gKm[0] = wm / 2.0 - 0.5;
402    gKm[1] = 0.0;
403    gKm[2] = wm / 2.0 - 0.5;
404    gKm[3] = 0.0;
405    gKm[4] = hm / 2.0 - 0.5;
406    gKm[5] = hm / 2.0 - 0.5;
407    gKm[6] = 0.0;
408    gKm[7] = 0.0;
409    gKm[8] = 1.0;
410
411    gK[0] = w / 2.0 - 0.5;
412    gK[1] = 0.0;
413    gK[2] = w / 2.0 - 0.5;
414    gK[3] = 0.0;
415    gK[4] = h / 2.0 - 0.5;
416    gK[5] = h / 2.0 - 0.5;
417    gK[6] = 0.0;
418    gK[7] = 0.0;
419    gK[8] = 1.0;
420
421    db_Identity3x3(gKinv);
422    db_InvertCalibrationMatrix(gKinv, gK);
423
424    db_Identity3x3(gKminv);
425    db_InvertCalibrationMatrix(gKminv, gKm);
426
427    //////////////////////////////////////////
428    ////// Compute g_Translation now... //////
429    //////////////////////////////////////////
430    double T[9], Tp[9], Ttemp[9];
431
432    db_Identity3x3(T);
433    T[2] = gCenterOffsetX;
434    T[5] = gCenterOffsetY;
435
436    // Tp = inv(K) * T * K
437    db_Identity3x3(Ttemp);
438    db_Multiply3x3_3x3(Ttemp, T, gK);
439    db_Multiply3x3_3x3(Tp, gKinv, Ttemp);
440
441    ConvertAffine3x3toGL4x4(g_dTranslationToFBOCenter, Tp);
442
443    UpdateWarpTransformation(g_dIdent3x3);
444}
445
446void FreeTextureMemory()
447{
448    sem_wait(&gPreviewImage_semaphore);
449    ImageUtils::freeImage(gPreviewImage[LR]);
450    ImageUtils::freeImage(gPreviewImage[HR]);
451    sem_post(&gPreviewImage_semaphore);
452}
453
454extern "C"
455{
456    JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved);
457    JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved);
458    JNIEXPORT jint JNICALL Java_com_android_camera_MosaicRenderer_init(
459            JNIEnv * env, jobject obj);
460    JNIEXPORT void JNICALL Java_com_android_camera_MosaicRenderer_reset(
461            JNIEnv * env, jobject obj,  jint width, jint height,
462            jboolean isLandscapeOrientation);
463    JNIEXPORT void JNICALL Java_com_android_camera_MosaicRenderer_preprocess(
464            JNIEnv * env, jobject obj, jfloatArray stMatrix);
465    JNIEXPORT void JNICALL Java_com_android_camera_MosaicRenderer_transferGPUtoCPU(
466            JNIEnv * env, jobject obj);
467    JNIEXPORT void JNICALL Java_com_android_camera_MosaicRenderer_step(
468            JNIEnv * env, jobject obj);
469    JNIEXPORT void JNICALL Java_com_android_camera_MosaicRenderer_ready(
470            JNIEnv * env, jobject obj);
471    JNIEXPORT void JNICALL Java_com_android_camera_MosaicRenderer_setWarping(
472            JNIEnv * env, jobject obj, jboolean flag);
473};
474
475
476JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
477{
478    sem_init(&gPreviewImage_semaphore, 0, 1);
479
480    return JNI_VERSION_1_4;
481}
482
483
484JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved)
485{
486    sem_destroy(&gPreviewImage_semaphore);
487}
488JNIEXPORT jint JNICALL Java_com_android_camera_MosaicRenderer_init(
489        JNIEnv * env, jobject obj)
490{
491    gSurfTexRenderer[LR].InitializeGLProgram();
492    gSurfTexRenderer[HR].InitializeGLProgram();
493    gYVURenderer[LR].InitializeGLProgram();
494    gYVURenderer[HR].InitializeGLProgram();
495    gWarper1.InitializeGLProgram();
496    gWarper2.InitializeGLProgram();
497    gPreview.InitializeGLProgram();
498    gBuffer[0].InitializeGLContext();
499    gBuffer[1].InitializeGLContext();
500    gBufferInput[LR].InitializeGLContext();
501    gBufferInput[HR].InitializeGLContext();
502    gBufferInputYVU[LR].InitializeGLContext();
503    gBufferInputYVU[HR].InitializeGLContext();
504
505    glBindFramebuffer(GL_FRAMEBUFFER, 0);
506
507    glGenTextures(1, gSurfaceTextureID);
508    // bind the surface texture
509    bindSurfaceTexture(gSurfaceTextureID[0]);
510
511    return (jint) gSurfaceTextureID[0];
512}
513
514
515void calculateUILayoutScaling(int width, int height, bool isLandscape) {
516    if (isLandscape) {
517        //  __________        ______
518        // |__________|  =>  |______|
519        // (Preview FBO)      (View)
520        //
521        // Scale the preview FBO's height to the height of view and
522        // maintain the aspect ratio of the current frame on the screen.
523        gUILayoutScalingY = PREVIEW_FBO_HEIGHT_SCALE;
524
525        // Note that OpenGL scales a texture to view's width and height automatically.
526        // The "width / height" inverts the scaling, so as to maintain the aspect ratio
527        // of the current frame.
528        gUILayoutScalingX = ((float) (PREVIEW_FBO_WIDTH_SCALE * gPreviewImageWidth[LR])
529                / (PREVIEW_FBO_HEIGHT_SCALE * gPreviewImageHeight[LR]) *  PREVIEW_FBO_HEIGHT_SCALE)
530                / ((float) width / height);
531    } else {
532        //                     __
533        //  __________        |  |
534        // |__________|  =>   |  |
535        // (Preview FBO)      |  |
536        //                    |__|
537        //                   (View)
538        // Scale the preview FBO's height to the width of view and
539        // maintain the aspect ratio of the current frame on the screen.
540        gUILayoutScalingX = PREVIEW_FBO_HEIGHT_SCALE;
541
542        // Note that OpenGL scales a texture to view's width and height automatically.
543        // The "height / width" inverts the scaling, so as to maintain the aspect ratio
544        // of the current frame.
545        gUILayoutScalingY = ((float) (PREVIEW_FBO_WIDTH_SCALE * gPreviewImageWidth[LR])
546                / (PREVIEW_FBO_HEIGHT_SCALE * gPreviewImageHeight[LR]) *  PREVIEW_FBO_HEIGHT_SCALE)
547                / ((float) height / width);
548
549    }
550}
551
552JNIEXPORT void JNICALL Java_com_android_camera_MosaicRenderer_reset(
553        JNIEnv * env, jobject obj,  jint width, jint height, jboolean isLandscapeOrientation)
554{
555    gIsLandscapeOrientation = isLandscapeOrientation;
556    calculateUILayoutScaling(width, height, gIsLandscapeOrientation);
557
558    gBuffer[0].Init(gPreviewFBOWidth, gPreviewFBOHeight, GL_RGBA);
559    gBuffer[1].Init(gPreviewFBOWidth, gPreviewFBOHeight, GL_RGBA);
560
561    gBufferInput[LR].Init(gPreviewImageWidth[LR],
562            gPreviewImageHeight[LR], GL_RGBA);
563
564    gBufferInput[HR].Init(gPreviewImageWidth[HR],
565            gPreviewImageHeight[HR], GL_RGBA);
566
567    gBufferInputYVU[LR].Init(gPreviewImageWidth[LR],
568            gPreviewImageHeight[LR], GL_RGBA);
569
570    gBufferInputYVU[HR].Init(gPreviewImageWidth[HR],
571            gPreviewImageHeight[HR], GL_RGBA);
572
573    // bind the surface texture
574    bindSurfaceTexture(gSurfaceTextureID[0]);
575
576    // To speed up, there is no need to clear the destination buffers
577    // (offscreen/screen buffers) of gSurfTexRenderer, gYVURenderer
578    // and gPreview because we always fill the whole destination buffers
579    // when we draw something to those offscreen/screen buffers.
580    gSurfTexRenderer[LR].SetupGraphics(&gBufferInput[LR]);
581    gSurfTexRenderer[LR].SetViewportMatrix(1, 1, 1, 1);
582    gSurfTexRenderer[LR].SetScalingMatrix(1.0f, -1.0f);
583    gSurfTexRenderer[LR].SetInputTextureName(gSurfaceTextureID[0]);
584    gSurfTexRenderer[LR].SetInputTextureType(GL_TEXTURE_EXTERNAL_OES_ENUM);
585
586    gSurfTexRenderer[HR].SetupGraphics(&gBufferInput[HR]);
587    gSurfTexRenderer[HR].SetViewportMatrix(1, 1, 1, 1);
588    gSurfTexRenderer[HR].SetScalingMatrix(1.0f, -1.0f);
589    gSurfTexRenderer[HR].SetInputTextureName(gSurfaceTextureID[0]);
590    gSurfTexRenderer[HR].SetInputTextureType(GL_TEXTURE_EXTERNAL_OES_ENUM);
591
592    gYVURenderer[LR].SetupGraphics(&gBufferInputYVU[LR]);
593    gYVURenderer[LR].SetInputTextureName(gBufferInput[LR].GetTextureName());
594    gYVURenderer[LR].SetInputTextureType(GL_TEXTURE_2D);
595
596    gYVURenderer[HR].SetupGraphics(&gBufferInputYVU[HR]);
597    gYVURenderer[HR].SetInputTextureName(gBufferInput[HR].GetTextureName());
598    gYVURenderer[HR].SetInputTextureType(GL_TEXTURE_2D);
599
600    // gBuffer[1-gCurrentFBOIndex] --> gWarper1 --> gBuffer[gCurrentFBOIndex]
601    gWarper1.SetupGraphics(&gBuffer[gCurrentFBOIndex]);
602
603    // Clear the destination buffer of gWarper1.
604    gWarper1.Clear(0.0, 0.0, 0.0, 1.0);
605    gWarper1.SetViewportMatrix(1, 1, 1, 1);
606    gWarper1.SetScalingMatrix(1.0f, 1.0f);
607    gWarper1.SetInputTextureName(gBuffer[1 - gCurrentFBOIndex].GetTextureName());
608    gWarper1.SetInputTextureType(GL_TEXTURE_2D);
609
610    // gBufferInput[HR] --> gWarper2 --> gBuffer[gCurrentFBOIndex]
611    gWarper2.SetupGraphics(&gBuffer[gCurrentFBOIndex]);
612
613    // gWarp2's destination buffer is the same to gWarp1's. No need to clear it
614    // again.
615    gWarper2.SetViewportMatrix(gPreviewImageWidth[HR],
616            gPreviewImageHeight[HR], gBuffer[gCurrentFBOIndex].GetWidth(),
617            gBuffer[gCurrentFBOIndex].GetHeight());
618    gWarper2.SetScalingMatrix(1.0f, 1.0f);
619    gWarper2.SetInputTextureName(gBufferInput[HR].GetTextureName());
620    gWarper2.SetInputTextureType(GL_TEXTURE_2D);
621
622    // gBuffer[gCurrentFBOIndex] --> gPreview --> Screen
623    gPreview.SetupGraphics(width, height);
624    gPreview.SetViewportMatrix(1, 1, 1, 1);
625
626    // Scale the previewFBO so that the viewfinder window fills the layout height
627    // while maintaining the image aspect ratio
628    gPreview.SetScalingMatrix(gUILayoutScalingX, -1.0f * gUILayoutScalingY);
629    gPreview.SetInputTextureName(gBuffer[gCurrentFBOIndex].GetTextureName());
630    gPreview.SetInputTextureType(GL_TEXTURE_2D);
631}
632
633JNIEXPORT void JNICALL Java_com_android_camera_MosaicRenderer_preprocess(
634        JNIEnv * env, jobject obj, jfloatArray stMatrix)
635{
636    jfloat *stmat = env->GetFloatArrayElements(stMatrix, 0);
637
638    gSurfTexRenderer[LR].SetSTMatrix((float*) stmat);
639    gSurfTexRenderer[HR].SetSTMatrix((float*) stmat);
640
641    env->ReleaseFloatArrayElements(stMatrix, stmat, 0);
642
643    gSurfTexRenderer[LR].DrawTexture(g_dAffinetransIdentGL);
644    gSurfTexRenderer[HR].DrawTexture(g_dAffinetransIdentGL);
645}
646
647#ifndef now_ms
648#include <time.h>
649static double
650now_ms(void)
651{
652    //struct timespec res;
653    struct timeval res;
654    //clock_gettime(CLOCK_REALTIME, &res);
655    gettimeofday(&res, NULL);
656    return 1000.0*res.tv_sec + (double)res.tv_usec/1e3;
657}
658#endif
659
660
661
662JNIEXPORT void JNICALL Java_com_android_camera_MosaicRenderer_transferGPUtoCPU(
663        JNIEnv * env, jobject obj)
664{
665    double t0, t1, time_c;
666
667    gYVURenderer[LR].DrawTexture();
668    gYVURenderer[HR].DrawTexture();
669
670    sem_wait(&gPreviewImage_semaphore);
671    // Bind to the input LR FBO and read the Low-Res data from there...
672    glBindFramebuffer(GL_FRAMEBUFFER, gBufferInputYVU[LR].GetFrameBufferName());
673    t0 = now_ms();
674    glReadPixels(0,
675                 0,
676                 gBufferInput[LR].GetWidth(),
677                 gBufferInput[LR].GetHeight(),
678                 GL_RGBA,
679                 GL_UNSIGNED_BYTE,
680                 gPreviewImage[LR]);
681
682    checkGlError("glReadPixels LR");
683
684    // Bind to the input HR FBO and read the high-res data from there...
685    glBindFramebuffer(GL_FRAMEBUFFER, gBufferInputYVU[HR].GetFrameBufferName());
686    t0 = now_ms();
687    glReadPixels(0,
688                 0,
689                 gBufferInput[HR].GetWidth(),
690                 gBufferInput[HR].GetHeight(),
691                 GL_RGBA,
692                 GL_UNSIGNED_BYTE,
693                 gPreviewImage[HR]);
694
695    checkGlError("glReadPixels HR");
696
697    sem_post(&gPreviewImage_semaphore);
698}
699
700JNIEXPORT void JNICALL Java_com_android_camera_MosaicRenderer_step(
701        JNIEnv * env, jobject obj)
702{
703    if(!gWarpImage) // ViewFinder
704    {
705        gWarper2.SetupGraphics(&gBuffer[gCurrentFBOIndex]);
706        gPreview.SetInputTextureName(gBuffer[gCurrentFBOIndex].GetTextureName());
707
708        gWarper2.DrawTexture(g_dTranslationToFBOCenterGL);
709
710        if (gIsLandscapeOrientation) {
711            gPreview.DrawTexture(g_dAffinetransIdentGL);
712        } else {
713            gPreview.DrawTexture(g_dAffinetransRotation90GL);
714        }
715    }
716    else
717    {
718        gWarper1.SetupGraphics(&gBuffer[gCurrentFBOIndex]);
719        // Clear the destination so that we can paint on it afresh
720        gWarper1.Clear(0.0, 0.0, 0.0, 1.0);
721        gWarper1.SetInputTextureName(
722                gBuffer[1 - gCurrentFBOIndex].GetTextureName());
723        gWarper2.SetupGraphics(&gBuffer[gCurrentFBOIndex]);
724        gPreview.SetInputTextureName(gBuffer[gCurrentFBOIndex].GetTextureName());
725
726        gWarper1.DrawTexture(g_dAffinetransGL);
727        gWarper2.DrawTexture(g_dTranslationToFBOCenterGL);
728        gPreview.DrawTexture(g_dAffinetransPanGL);
729
730        gCurrentFBOIndex = 1 - gCurrentFBOIndex;
731    }
732}
733
734JNIEXPORT void JNICALL Java_com_android_camera_MosaicRenderer_setWarping(
735        JNIEnv * env, jobject obj, jboolean flag)
736{
737    // TODO: Review this logic
738    if(gWarpImage != (bool) flag) //switching from viewfinder to capture or vice-versa
739    {
740        // Clear gBuffer[0]
741        gWarper1.SetupGraphics(&gBuffer[0]);
742        gWarper1.Clear(0.0, 0.0, 0.0, 1.0);
743        // Clear gBuffer[1]
744        gWarper1.SetupGraphics(&gBuffer[1]);
745        gWarper1.Clear(0.0, 0.0, 0.0, 1.0);
746        // Clear the screen to black.
747        gPreview.Clear(0.0, 0.0, 0.0, 1.0);
748
749        gLastTx = 0.0f;
750        gPanOffset = 0.0f;
751        gPanViewfinder = true;
752
753        db_Identity3x3(gThisH1t);
754        db_Identity3x3(gLastH1t);
755    }
756
757    gWarpImage = (bool)flag;
758}
759
760
761JNIEXPORT void JNICALL Java_com_android_camera_MosaicRenderer_ready(
762        JNIEnv * env, jobject obj)
763{
764    for(int i=0; i<16; i++)
765    {
766        g_dAffinetransGL[i] = g_dAffinetrans[i];
767        g_dAffinetransPanGL[i] = g_dAffinetransPan[i];
768        g_dTranslationToFBOCenterGL[i] = g_dTranslationToFBOCenter[i];
769    }
770}
771