Index: content/common/gpu/media/gles2_external_texture_copier.cc |
diff --git a/content/common/gpu/media/gles2_external_texture_copier.cc b/content/common/gpu/media/gles2_external_texture_copier.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..7da6b6cf5438bf01d984d0a2c0d25a0edd63d64f |
--- /dev/null |
+++ b/content/common/gpu/media/gles2_external_texture_copier.cc |
@@ -0,0 +1,275 @@ |
+// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "content/common/gpu/media/gles2_external_texture_copier.h" |
+ |
+#include "base/logging.h" |
+ |
+namespace content { |
+ |
+static void checkGlError(const char* op) { |
+ for (GLint error = glGetError(); error; error = glGetError()) { |
+ LOG(ERROR) << "after " << op <<" glError (0x" << std::hex << error << ")"; |
+ NOTREACHED(); |
+ } |
+} |
+ |
+static const char g_vertex_shader[] = |
+ "uniform mat4 uMVPMatrix;\n" |
+ "uniform mat4 uSTMatrix;\n" |
+ "attribute vec4 aPosition;\n" |
+ "attribute vec4 aTextureCoord;\n" |
+ "varying vec2 vTextureCoord;\n" |
+ "void main() {\n" |
+ " gl_Position = uMVPMatrix * aPosition;\n" |
+ " vTextureCoord = (uSTMatrix * aTextureCoord).xy;\n" |
+ "}\n"; |
+ |
+static const char g_fragment_shader[] = |
+ "#extension GL_OES_EGL_image_external : require\n" |
+ "precision mediump float;\n" |
+ "varying vec2 vTextureCoord;\n" |
+ "uniform samplerExternalOES sTexture;\n" |
+ "void main() {\n" |
+ " gl_FragColor = texture2D(sTexture, vTextureCoord);\n" |
+ "}\n"; |
+ |
+enum { kVerticeStride = 5 * sizeof(float) }; |
+ |
+static const GLfloat g_vertices[] = { |
+ -1.0f, -1.0f, 0, 0.f, 0.f, |
+ 1.0f, -1.0f, 0, 1.f, 0.f, |
+ -1.0f, 1.0f, 0, 0.f, 1.f, |
+ 1.0f, 1.0f, 0, 1.f, 1.f, |
+}; |
+ |
+// Due to the absence of matrix functions in NDK, a pre-calculated matrix |
+// is used. g_mvp_matrix = P * L * I |
+// Matrix.setLookAtM(L, 0, 0, 0, 2, 0, 0, 0, 0, -1, 0); |
+// Matrix.orthoM(P, 0, -1, 1, -1, 1, 1, 3); |
+// Matrix.setIdentityM(I, 0); |
+// TODO(dwkang): currently, (0, -1, 0) is used for the up vector. |
+// figure out why up vector (0, 1, 0) generates flipped screen. |
+static const GLfloat g_mvp_matrix[] = { |
+ 1.f, 0.f, 0.f, 0.f, |
+ 0.f, -1.f, 0.f, 0.f, |
+ 0.f, 0.f, -1.f, 0.f, |
+ 0.f, 0.f, 0.f, 1.f, |
+}; |
+ |
+static GLuint 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); |
+ LOG(ERROR) << "Could not compile shader : " << buf; |
+ free(buf); |
+ } |
+ glDeleteShader(shader); |
+ shader = 0; |
+ } |
+ } |
+ } |
+ return shader; |
+} |
+ |
+static GLuint CreateProgram( |
+ const char* pVertexSource, const char* pFragmentSource) { |
+ GLuint vertexShader = LoadShader(GL_VERTEX_SHADER, pVertexSource); |
+ if (!vertexShader) { |
+ return 0; |
+ } |
+ |
+ GLuint pixelShader = LoadShader(GL_FRAGMENT_SHADER, pFragmentSource); |
+ if (!pixelShader) { |
+ return 0; |
+ } |
+ |
+ GLuint program = glCreateProgram(); |
+ if (program) { |
+ glAttachShader(program, vertexShader); |
+ checkGlError("glAttachShader"); |
+ glAttachShader(program, pixelShader); |
+ checkGlError("glAttachShader"); |
+ glLinkProgram(program); |
+ GLint linkStatus = GL_FALSE; |
+ glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); |
+ 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); |
+ LOG(ERROR) << "Could not link program: "<< buf; |
+ free(buf); |
+ } |
+ } |
+ glDeleteProgram(program); |
+ program = 0; |
+ } |
+ } |
+ return program; |
+} |
+ |
+Gles2ExternalTextureCopier::Gles2ExternalTextureCopier() |
+ : initialized_(false), |
+ width_(0), |
+ height_(0), |
+ framebuffer_id_(0), |
+ renderbuffer_id_(0), |
+ program_(0), |
+ position_handle_(0), |
+ st_matrix_handle_(0), |
+ mvp_matrix_handle_(0), |
+ texture_handle_(0) { |
+ memset(st_matrix_, 0, sizeof(st_matrix_)); |
+} |
+ |
+Gles2ExternalTextureCopier::~Gles2ExternalTextureCopier() { |
+ if (initialized_) { |
+ glDeleteFramebuffers(1, &framebuffer_id_); |
+ glDeleteRenderbuffers(1, &renderbuffer_id_); |
+ } |
+} |
+ |
+bool Gles2ExternalTextureCopier::SetupGraphics() { |
+ program_ = CreateProgram(g_vertex_shader, g_fragment_shader); |
+ if (!program_) { |
+ LOG(ERROR) << "Could not create program."; |
+ return false; |
+ } |
+ position_handle_ = glGetAttribLocation(program_, "aPosition"); |
+ checkGlError("glGetAttribLocation"); |
+ |
+ texture_handle_ = glGetAttribLocation(program_, "aTextureCoord"); |
+ checkGlError("glGetAttribLocation aTextureCoord"); |
+ |
+ mvp_matrix_handle_ = glGetUniformLocation(program_, "uMVPMatrix"); |
+ checkGlError("glGetUniformLocation uMVPMatrix"); |
+ |
+ st_matrix_handle_ = glGetUniformLocation(program_, "uSTMatrix"); |
+ checkGlError("glGetUniformLocation uSTMatrix"); |
+ |
+ return true; |
+} |
+ |
+void Gles2ExternalTextureCopier::RenderFrame(int w, int h, GLuint texture_id) { |
+ glViewport(0, 0, w, h); |
+ checkGlError("glViewport"); |
+ |
+ glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); |
ycheo (away)
2013/01/17 08:34:44
Remove a space after the opening parenthesis.
dwkang1
2013/01/18 07:14:08
Done.
|
+ checkGlError("glClear"); |
+ |
+ glUseProgram(program_); |
+ checkGlError("glUseProgram"); |
+ |
+ glActiveTexture(GL_TEXTURE0); |
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_id); |
+ checkGlError("glBindTexture"); |
+ |
+ glVertexAttribPointer( |
+ position_handle_, 3, GL_FLOAT, GL_FALSE, kVerticeStride, g_vertices); |
+ checkGlError("glVertexAttribPointer vPositionHandle"); |
+ glEnableVertexAttribArray(position_handle_); |
+ checkGlError("glEnableVertexAttribArray vPositionHandle"); |
+ |
+ glVertexAttribPointer( |
+ texture_handle_, 2, GL_FLOAT, GL_FALSE, kVerticeStride, g_vertices + 3); |
+ checkGlError("glVertexAttribPointer aTextureHandle"); |
+ glEnableVertexAttribArray(texture_handle_); |
+ checkGlError("glEnableVertexAttribArray aTextureHandle"); |
+ |
+ glUniformMatrix4fv(mvp_matrix_handle_, 1, GL_FALSE, g_mvp_matrix); |
+ checkGlError("glUniformMatrix4fv uMVPMatrixHandle"); |
+ |
+ glUniformMatrix4fv(st_matrix_handle_, 1, GL_FALSE, st_matrix_); |
+ checkGlError("glUniformMatrix4fv uSTMatrixHandle"); |
+ |
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
+ checkGlError("glDrawArrays"); |
+} |
+ |
+bool Gles2ExternalTextureCopier::Init(int32 width, int32 height) { |
+ if (initialized_) { |
+ LOG(ERROR) << "Init should not be called twice."; |
+ return false; |
+ } |
+ |
+ width_ = width; |
+ height_ = height; |
+ |
+ SetupGraphics(); |
+ if (!SetupFrameBuffer()) { |
+ LOG(ERROR) << "Failed to create a framebuffer."; |
+ return false; |
+ } |
+ |
+ initialized_ = true; |
+ return initialized_; |
+} |
+ |
+bool Gles2ExternalTextureCopier::Copy( |
+ GLuint source_texture_id, GLenum source_target, |
+ float transfrom_matrix[16], |
+ GLuint destination_texture_id, GLenum destination_target) { |
+ if (!initialized_) { |
+ return false; |
+ } |
+ if (source_target != GL_TEXTURE_EXTERNAL_OES |
+ || destination_target != GL_TEXTURE_2D) { |
+ LOG(ERROR) << "Unsupported texture targets: source(" |
+ << source_target << ") destination(" << destination_target << ")"; |
+ return false; |
+ } |
+ |
+ memcpy(st_matrix_, transfrom_matrix, sizeof(st_matrix_)); |
ycheo (away)
2013/01/17 08:34:44
What's the reason to copy transform_matrix to st_m
dwkang1
2013/01/18 07:14:08
Because I did this in a hurry? ;-) Fixed.
|
+ |
+ glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_id_); |
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
+ destination_texture_id, 0); |
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); |
+ if (status != GL_FRAMEBUFFER_COMPLETE) { |
+ LOG(ERROR) << "Framebuffer is not complete: " << status; |
+ return false; |
+ } |
+ glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_id_); |
+ checkGlError("glBindFramebuffer framebuffer_id_"); |
+ RenderFrame(width_, height_, source_texture_id); |
+ glBindFramebuffer(GL_FRAMEBUFFER, 0); |
+ checkGlError("glBindFramebuffer 0"); |
+ |
+ return true; |
+} |
+ |
+bool Gles2ExternalTextureCopier::SetupFrameBuffer() { |
+ GLuint framebuffer; |
+ glGenFramebuffers(1, &framebuffer); |
+ glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); |
+ |
+ GLuint depthbuffer; |
+ glGenRenderbuffers(1, &depthbuffer); |
+ |
+ glBindRenderbuffer(GL_RENDERBUFFER, depthbuffer); |
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width_, height_); |
+ glFramebufferRenderbuffer( |
+ GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthbuffer); |
+ checkGlError("glFramebufferRenderbuffer"); |
+ |
+ glBindFramebuffer(GL_FRAMEBUFFER, 0); |
+ framebuffer_id_ = framebuffer; |
+ renderbuffer_id_ = depthbuffer; |
+ return true; |
+} |
+ |
+} // namespace content |