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