diff options
author | mbansal <mayank.bansal@sri.com> | 2011-08-02 11:31:28 -0400 |
---|---|---|
committer | Wei-Ta Chen <weita@google.com> | 2011-08-05 17:20:40 -0700 |
commit | eeb94d4de94bfd4e01f3a716803f77a530f5b92c (patch) | |
tree | 4a458d58afaccb39aa26a23ae1cd4f403c5f0bc7 /jni/feature_mos | |
parent | 178f4d6d1f20bb5fe7f714448cac9910c2c18c1f (diff) | |
download | LegacyCamera-eeb94d4de94bfd4e01f3a716803f77a530f5b92c.zip LegacyCamera-eeb94d4de94bfd4e01f3a716803f77a530f5b92c.tar.gz LegacyCamera-eeb94d4de94bfd4e01f3a716803f77a530f5b92c.tar.bz2 |
Updates for mosaic preview rendering to happen using native GLES2.0 code.
1) Added new subfolder mosaic_renderer in feature_mos/src with FrameBuffer and WarpRenderer classes.
2) Added mosaic_renderer_jni.h|cpp files to the jni folder to perform GL calls for rendering on the GL thread.
3) Updated code in feature_mos_jni.cpp to connect with mosaic_renderer_jni.cpp.
4) Added new java files in com.android.camera.panorama to encapsulate the GL JNI interface, a GLSurfaceView for display and a GLSurfaceView.Renderer for rendering.
5) Modified APP code to enable the new GL-based rendering and made relevant changes to the UI (in pano_views.xml).
6) Fixed a GL bug which was preventing the rendering from working properly after hitting the back button once.
7) Preview rendering now displays in the current frame coordinate system.
8) Fixed the ghost preview rendering bug.
Change-Id: Ieb64ee3fd4a9a2c6563a311a4930ddc85ce2247c
Diffstat (limited to 'jni/feature_mos')
-rwxr-xr-x | jni/feature_mos/src/mosaic_renderer/FrameBuffer.cpp | 99 | ||||
-rwxr-xr-x | jni/feature_mos/src/mosaic_renderer/FrameBuffer.h | 31 | ||||
-rwxr-xr-x | jni/feature_mos/src/mosaic_renderer/WarpRenderer.cpp | 378 | ||||
-rwxr-xr-x | jni/feature_mos/src/mosaic_renderer/WarpRenderer.h | 80 |
4 files changed, 588 insertions, 0 deletions
diff --git a/jni/feature_mos/src/mosaic_renderer/FrameBuffer.cpp b/jni/feature_mos/src/mosaic_renderer/FrameBuffer.cpp new file mode 100755 index 0000000..9a07e49 --- /dev/null +++ b/jni/feature_mos/src/mosaic_renderer/FrameBuffer.cpp @@ -0,0 +1,99 @@ +#include "FrameBuffer.h" + +FrameBuffer::FrameBuffer() +{ + Reset(); +} + +FrameBuffer::~FrameBuffer() { +} + +void FrameBuffer::Reset() { + mFrameBufferName = -1; + mTextureName = -1; + mWidth = 0; + mHeight = 0; + mFormat = -1; +} + +bool FrameBuffer::InitializeGLContext() { + Reset(); + return CreateBuffers(); +} + +bool FrameBuffer::Init(int width, int height, GLenum format) { + if (mFrameBufferName == (GLuint)-1) { + if (!CreateBuffers()) { + return false; + } + } + glBindFramebuffer(GL_FRAMEBUFFER, mFrameBufferName); + glBindTexture(GL_TEXTURE_2D, mTextureName); + + glTexImage2D(GL_TEXTURE_2D, + 0, + format, + width, + height, + 0, + format, + GL_UNSIGNED_BYTE, + NULL); + if (!checkGlError("bind/teximage")) { + return false; + } + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + // This is necessary to work with user-generated frame buffers with + // dimensions that are NOT powers of 2. + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + // Attach texture to frame buffer. + glFramebufferTexture2D(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + mTextureName, + 0); + + if (!checkGlError("texture setup")) { + return false; + } + mWidth = width; + mHeight = height; + mFormat = format; + glBindFramebuffer(GL_FRAMEBUFFER, 0); + return true; +} + +bool FrameBuffer::CreateBuffers() { + glGenFramebuffers(1, &mFrameBufferName); + glGenTextures(1, &mTextureName); + if (!checkGlError("texture generation")) { + return false; + } + return true; +} + +GLuint FrameBuffer::GetTextureName() const { + return mTextureName; +} + +GLuint FrameBuffer::GetFrameBufferName() const { + return mFrameBufferName; +} + +GLenum FrameBuffer::GetFormat() const { + return mFormat; +} + +int FrameBuffer::GetWidth() const { + return mWidth; +} + +int FrameBuffer::GetHeight() const { + return mHeight; +} + + + diff --git a/jni/feature_mos/src/mosaic_renderer/FrameBuffer.h b/jni/feature_mos/src/mosaic_renderer/FrameBuffer.h new file mode 100755 index 0000000..b6a20ad --- /dev/null +++ b/jni/feature_mos/src/mosaic_renderer/FrameBuffer.h @@ -0,0 +1,31 @@ +#pragma once + +#include <EGL/egl.h> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +extern bool checkGlError(const char* op); + +class FrameBuffer { + public: + FrameBuffer(); + virtual ~FrameBuffer(); + + bool InitializeGLContext(); + bool Init(int width, int height, GLenum format); + GLuint GetTextureName() const; + GLuint GetFrameBufferName() const; + GLenum GetFormat() const; + + int GetWidth() const; + int GetHeight() const; + + private: + void Reset(); + bool CreateBuffers(); + GLuint mFrameBufferName; + GLuint mTextureName; + int mWidth; + int mHeight; + GLenum mFormat; +}; diff --git a/jni/feature_mos/src/mosaic_renderer/WarpRenderer.cpp b/jni/feature_mos/src/mosaic_renderer/WarpRenderer.cpp new file mode 100755 index 0000000..9274721 --- /dev/null +++ b/jni/feature_mos/src/mosaic_renderer/WarpRenderer.cpp @@ -0,0 +1,378 @@ +#include "WarpRenderer.h" + +#include <GLES2/gl2ext.h> + +#include <android/log.h> +#define LOG_TAG "WarpRenderer" +#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) +#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) + + +static const char gVertexShader[] = +"uniform mat4 u_affinetrans; \n" +"uniform mat4 u_viewporttrans; \n" +"uniform mat4 u_scalingtrans; \n" +"attribute vec4 a_position; \n" +"attribute vec2 a_texCoord; \n" +"varying vec2 v_texCoord; \n" +"void main() \n" +"{ \n" +" gl_Position = u_scalingtrans * u_viewporttrans * u_affinetrans * a_position; \n" +" v_texCoord = a_texCoord; \n" +"} \n"; + +static const char gFragmentShader[] = +"precision mediump float; \n" +"varying vec2 v_texCoord; \n" +"uniform sampler2D s_texture; \n" +"void main() \n" +"{ \n" +" vec4 color; \n" +" color = texture2D(s_texture, v_texCoord); \n" +" gl_FragColor = color; \n" +"} \n"; + + +const GLfloat g_vVertices[] = { + -1.f, -1.f, 0.0f, 1.0f, // Position 0 + 0.0f, 1.0f, // TexCoord 0 + 1.f, -1.f, 0.0f, 1.0f, // Position 1 + 1.0f, 1.0f, // TexCoord 1 + -1.f, 1.f, 0.0f, 1.0f, // Position 2 + 0.0f, 0.0f, // TexCoord 2 + 1.f, 1.f, 0.0f, 1.0f, // Position 3 + 1.0f, 0.0f // TexCoord 3 +}; + +const int VERTEX_STRIDE = 6 * sizeof(GLfloat); + +GLushort g_iIndices[] = { 0, 1, 2, 3 }; + +WarpRenderer::WarpRenderer() + : mGlProgram(0), + mInputTextureName(-1), + mInputTextureWidth(0), + mInputTextureHeight(0), + mSurfaceWidth(0), + mSurfaceHeight(0) + { + InitializeGLContext(); +} + +WarpRenderer::~WarpRenderer() { +} + +GLuint WarpRenderer::loadShader(GLenum shaderType, const char* pSource) { + GLuint shader = glCreateShader(shaderType); + if (shader) { + glShaderSource(shader, 1, &pSource, NULL); + glCompileShader(shader); + GLint compiled = 0; + glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); + if (!compiled) { + GLint infoLen = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); + if (infoLen) { + char* buf = (char*) malloc(infoLen); + if (buf) { + glGetShaderInfoLog(shader, infoLen, NULL, buf); + LOGE("Could not compile shader %d:\n%s\n", + shaderType, buf); + free(buf); + } + glDeleteShader(shader); + shader = 0; + } + } + } + return shader; +} + +GLuint WarpRenderer::createProgram(const char* pVertexSource, const char* pFragmentSource) +{ + GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource); + if (!vertexShader) + { + return 0; + } + LOGI("VertexShader Loaded!"); + + GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource); + if (!pixelShader) + { + return 0; + } + LOGI("FragmentShader Loaded!"); + + GLuint program = glCreateProgram(); + if (program) + { + glAttachShader(program, vertexShader); + checkGlError("glAttachShader"); + glAttachShader(program, pixelShader); + checkGlError("glAttachShader"); + + LOGI("Shaders Attached!"); + + glLinkProgram(program); + GLint linkStatus = GL_FALSE; + glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); + + LOGI("Program Linked!"); + + if (linkStatus != GL_TRUE) + { + GLint bufLength = 0; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength); + if (bufLength) + { + char* buf = (char*) malloc(bufLength); + if (buf) + { + glGetProgramInfoLog(program, bufLength, NULL, buf); + LOGE("Could not link program:\n%s\n", buf); + free(buf); + } + } + glDeleteProgram(program); + program = 0; + } + } + return program; +} + +bool WarpRenderer::InitializeGLProgram() +{ + bool succeeded = false; + do { + GLuint glProgram; + glProgram = createProgram(VertexShaderSource(), + FragmentShaderSource()); + if (!glProgram) { + break; + } + + glUseProgram(glProgram); + if (!checkGlError("glUseProgram")) break; + + // Get attribute locations + mPositionLoc = glGetAttribLocation(glProgram, "a_position"); + mAffinetransLoc = glGetUniformLocation(glProgram, "u_affinetrans"); + mViewporttransLoc = glGetUniformLocation(glProgram, "u_viewporttrans"); + mScalingtransLoc = glGetUniformLocation(glProgram, "u_scalingtrans"); + mTexCoordLoc = glGetAttribLocation(glProgram, "a_texCoord"); + + // Get sampler location + mSamplerLoc = glGetUniformLocation(glProgram, "s_texture"); + + mGlProgram = glProgram; + succeeded = true; + } while (false); + + if (!succeeded && (mGlProgram != 0)) + { + glDeleteProgram(mGlProgram); + checkGlError("glDeleteProgram"); + mGlProgram = 0; + } + return succeeded; +} + +void WarpRenderer::SetViewportMatrix(int w, int h, int W, int H) +{ + for(int i=0; i<16; i++) + { + mViewportMatrix[i] = 0.0f; + } + + mViewportMatrix[0] = float(w)/float(W); + mViewportMatrix[5] = float(h)/float(H); + mViewportMatrix[10] = 1.0f; + mViewportMatrix[12] = -1.0f + float(w)/float(W); + mViewportMatrix[13] = -1.0f + float(h)/float(H); + mViewportMatrix[15] = 1.0f; +} + +void WarpRenderer::SetScalingMatrix(float xscale, float yscale) +{ + for(int i=0; i<16; i++) + { + mScalingMatrix[i] = 0.0f; + } + + mScalingMatrix[0] = xscale; + mScalingMatrix[5] = yscale; + mScalingMatrix[10] = 1.0f; + mScalingMatrix[15] = 1.0f; +} + +// Set this renderer to use the default frame-buffer (screen) and +// set the viewport size to be the given width and height (pixels). +bool WarpRenderer::SetupGraphics(int width, int height) +{ + bool succeeded = false; + do { + if (mGlProgram == 0) + { + if (!InitializeGLProgram()) + { + break; + } + } + glUseProgram(mGlProgram); + if (!checkGlError("glUseProgram")) break; + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + mFrameBuffer = NULL; + mSurfaceWidth = width; + mSurfaceHeight = height; + + glViewport(0, 0, mSurfaceWidth, mSurfaceHeight); + if (!checkGlError("glViewport")) break; + succeeded = true; + } while (false); + + return succeeded; +} + + +// Set this renderer to use the specified FBO and +// set the viewport size to be the width and height of this FBO. +bool WarpRenderer::SetupGraphics(FrameBuffer* buffer) +{ + bool succeeded = false; + do { + if (mGlProgram == 0) + { + if (!InitializeGLProgram()) + { + break; + } + } + glUseProgram(mGlProgram); + if (!checkGlError("glUseProgram")) break; + + glBindFramebuffer(GL_FRAMEBUFFER, buffer->GetFrameBufferName()); + + mFrameBuffer = buffer; + mSurfaceWidth = mFrameBuffer->GetWidth(); + mSurfaceHeight = mFrameBuffer->GetHeight(); + + glViewport(0, 0, mSurfaceWidth, mSurfaceHeight); + if (!checkGlError("glViewport")) break; + succeeded = true; + } while (false); + + return succeeded; +} + +bool WarpRenderer::Clear(float r, float g, float b, float a) +{ + bool succeeded = false; + do { + bool rt = (mFrameBuffer == NULL)? + SetupGraphics(mSurfaceWidth, mSurfaceHeight) : + SetupGraphics(mFrameBuffer); + + if(!rt) + break; + + glClearColor(r, g, b, a); + glClear(GL_COLOR_BUFFER_BIT); + + succeeded = true; + } while (false); + return succeeded; + +} + +bool WarpRenderer::DrawTexture(GLfloat *affine) +{ + bool succeeded = false; + do { + bool rt = (mFrameBuffer == NULL)? + SetupGraphics(mSurfaceWidth, mSurfaceHeight) : + SetupGraphics(mFrameBuffer); + + if(!rt) + break; + + glDisable(GL_BLEND); + + glActiveTexture(GL_TEXTURE0); + if (!checkGlError("glActiveTexture")) break; + + const GLenum texture_type = InputTextureType(); + glBindTexture(texture_type, mInputTextureName); + if (!checkGlError("glBindTexture")) break; + + // Set the sampler texture unit to 0 + glUniform1i(mSamplerLoc, 0); + + // Load the vertex position + glVertexAttribPointer(mPositionLoc, 4, GL_FLOAT, + GL_FALSE, VERTEX_STRIDE, g_vVertices); + + // Load the texture coordinate + glVertexAttribPointer(mTexCoordLoc, 2, GL_FLOAT, + GL_FALSE, VERTEX_STRIDE, &g_vVertices[4]); + + glEnableVertexAttribArray(mPositionLoc); + glEnableVertexAttribArray(mTexCoordLoc); + + // pass matrix information to the vertex shader + glUniformMatrix4fv(mAffinetransLoc, 1, GL_FALSE, affine); + glUniformMatrix4fv(mViewporttransLoc, 1, GL_FALSE, mViewportMatrix); + glUniformMatrix4fv(mScalingtransLoc, 1, GL_FALSE, mScalingMatrix); + + // And, finally, execute the GL draw command. + glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, g_iIndices); + + checkGlError("glDrawElements"); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + succeeded = true; + } while (false); + return succeeded; +} + +void WarpRenderer::InitializeGLContext() +{ + if(mFrameBuffer != NULL) + { + delete mFrameBuffer; + mFrameBuffer = NULL; + } + + mInputTextureName = -1; + mGlProgram = 0; + mTexHandle = 0; +} + +int WarpRenderer::GetTextureName() +{ + return mInputTextureName; +} + +void WarpRenderer::SetInputTextureName(GLuint textureName) +{ + mInputTextureName = textureName; +} + +void WarpRenderer::SetInputTextureDimensions(int width, int height) +{ + mInputTextureWidth = width; + mInputTextureHeight = height; +} + + +const char* WarpRenderer::VertexShaderSource() const +{ + return gVertexShader; +} + +const char* WarpRenderer::FragmentShaderSource() const +{ + return gFragmentShader; +} diff --git a/jni/feature_mos/src/mosaic_renderer/WarpRenderer.h b/jni/feature_mos/src/mosaic_renderer/WarpRenderer.h new file mode 100755 index 0000000..7986215 --- /dev/null +++ b/jni/feature_mos/src/mosaic_renderer/WarpRenderer.h @@ -0,0 +1,80 @@ +#pragma once + +#include "FrameBuffer.h" + +#include <GLES2/gl2.h> + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +class WarpRenderer { + public: + WarpRenderer(); + virtual ~WarpRenderer(); + + // Initialize OpenGL resources + // @return true if successful + bool InitializeGLProgram(); + + bool SetupGraphics(FrameBuffer* buffer); + bool SetupGraphics(int width, int height); + + bool Clear(float r, float g, float b, float a); + + void SetViewportMatrix(int w, int h, int W, int H); + void SetScalingMatrix(float xscale, float yscale); + bool DrawTexture(GLfloat *affine); + + int GetTextureName(); + void SetInputTextureName(GLuint textureName); + void SetInputTextureDimensions(int width, int height); + + void InitializeGLContext(); + + protected: + + GLuint loadShader(GLenum shaderType, const char* pSource); + GLuint createProgram(const char*, const char* ); + + int SurfaceWidth() const { return mSurfaceWidth; } + int SurfaceHeight() const { return mSurfaceHeight; } + + private: + // Source code for shaders. + virtual const char* VertexShaderSource() const; + virtual const char* FragmentShaderSource() const; + + // Redefine this to use special texture types such as + // GL_TEXTURE_EXTERNAL_OES. + virtual GLenum InputTextureType() const { return GL_TEXTURE_2D; } + + + GLuint mGlProgram; + GLuint mInputTextureName; + int mInputTextureWidth; + int mInputTextureHeight; + + GLuint mTexHandle; // Handle to s_texture. + GLuint mTexCoordHandle; // Handle to a_texCoord. + GLuint mTriangleVerticesHandle; // Handle to vPosition. + + // Attribute locations + GLint mPositionLoc; + GLint mAffinetransLoc; + GLint mViewporttransLoc; + GLint mScalingtransLoc; + GLint mTexCoordLoc; + + GLfloat mViewportMatrix[16]; + GLfloat mScalingMatrix[16]; + + // Sampler location + GLint mSamplerLoc; + + int mSurfaceWidth; // Width of target surface. + int mSurfaceHeight; // Height of target surface. + + FrameBuffer *mFrameBuffer; +}; + |