summaryrefslogtreecommitdiffstats
path: root/cmds/screenrecord/Program.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cmds/screenrecord/Program.cpp')
-rw-r--r--cmds/screenrecord/Program.cpp303
1 files changed, 303 insertions, 0 deletions
diff --git a/cmds/screenrecord/Program.cpp b/cmds/screenrecord/Program.cpp
new file mode 100644
index 0000000..a198204
--- /dev/null
+++ b/cmds/screenrecord/Program.cpp
@@ -0,0 +1,303 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ScreenRecord"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include "Program.h"
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <assert.h>
+
+using namespace android;
+
+// 4x4 identity matrix
+const float Program::kIdentity[] = {
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f
+};
+
+// Simple vertex shader. Texture coord calc includes matrix for GLConsumer
+// transform.
+static const char* kVertexShader =
+ "uniform mat4 uMVPMatrix;\n"
+ "uniform mat4 uGLCMatrix;\n"
+ "attribute vec4 aPosition;\n"
+ "attribute vec4 aTextureCoord;\n"
+ "varying vec2 vTextureCoord;\n"
+ "void main() {\n"
+ " gl_Position = uMVPMatrix * aPosition;\n"
+ " vTextureCoord = (uGLCMatrix * aTextureCoord).xy;\n"
+ "}\n";
+
+// Trivial fragment shader for external texture.
+static const char* kExtFragmentShader =
+ "#extension GL_OES_EGL_image_external : require\n"
+ "precision mediump float;\n"
+ "varying vec2 vTextureCoord;\n"
+ "uniform samplerExternalOES uTexture;\n"
+ "void main() {\n"
+ " gl_FragColor = texture2D(uTexture, vTextureCoord);\n"
+ "}\n";
+
+// Trivial fragment shader for mundane texture.
+static const char* kFragmentShader =
+ "precision mediump float;\n"
+ "varying vec2 vTextureCoord;\n"
+ "uniform sampler2D uTexture;\n"
+ "void main() {\n"
+ " gl_FragColor = texture2D(uTexture, vTextureCoord);\n"
+ //" gl_FragColor = vec4(0.2, 1.0, 0.2, 1.0);\n"
+ "}\n";
+
+status_t Program::setup(ProgramType type) {
+ ALOGV("Program::setup type=%d", type);
+ status_t err;
+
+ mProgramType = type;
+
+ GLuint program;
+ if (type == PROGRAM_TEXTURE_2D) {
+ err = createProgram(&program, kVertexShader, kFragmentShader);
+ } else {
+ err = createProgram(&program, kVertexShader, kExtFragmentShader);
+ }
+ if (err != NO_ERROR) {
+ return err;
+ }
+ assert(program != 0);
+
+ maPositionLoc = glGetAttribLocation(program, "aPosition");
+ maTextureCoordLoc = glGetAttribLocation(program, "aTextureCoord");
+ muMVPMatrixLoc = glGetUniformLocation(program, "uMVPMatrix");
+ muGLCMatrixLoc = glGetUniformLocation(program, "uGLCMatrix");
+ muTextureLoc = glGetUniformLocation(program, "uTexture");
+ if ((maPositionLoc | maTextureCoordLoc | muMVPMatrixLoc |
+ muGLCMatrixLoc | muTextureLoc) == -1) {
+ ALOGE("Attrib/uniform lookup failed: %#x", glGetError());
+ glDeleteProgram(program);
+ return UNKNOWN_ERROR;
+ }
+
+ mProgram = program;
+ return NO_ERROR;
+}
+
+void Program::release() {
+ ALOGV("Program::release");
+ if (mProgram != 0) {
+ glDeleteProgram(mProgram);
+ mProgram = 0;
+ }
+}
+
+status_t Program::createProgram(GLuint* outPgm, const char* vertexShader,
+ const char* fragmentShader) {
+ GLuint vs, fs;
+ status_t err;
+
+ err = compileShader(GL_VERTEX_SHADER, vertexShader, &vs);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ err = compileShader(GL_FRAGMENT_SHADER, fragmentShader, &fs);
+ if (err != NO_ERROR) {
+ glDeleteShader(vs);
+ return err;
+ }
+
+ GLuint program;
+ err = linkShaderProgram(vs, fs, &program);
+ glDeleteShader(vs);
+ glDeleteShader(fs);
+ if (err == NO_ERROR) {
+ *outPgm = program;
+ }
+ return err;
+}
+
+status_t Program::compileShader(GLenum shaderType, const char* src,
+ GLuint* outShader) {
+ GLuint shader = glCreateShader(shaderType);
+ if (shader == 0) {
+ ALOGE("glCreateShader error: %#x", glGetError());
+ return UNKNOWN_ERROR;
+ }
+
+ glShaderSource(shader, 1, &src, NULL);
+ glCompileShader(shader);
+
+ GLint compiled = 0;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+ if (!compiled) {
+ ALOGE("Compile of shader type %d failed", shaderType);
+ GLint infoLen = 0;
+ glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
+ if (infoLen) {
+ char* buf = new char[infoLen];
+ if (buf) {
+ glGetShaderInfoLog(shader, infoLen, NULL, buf);
+ ALOGE("Compile log: %s", buf);
+ delete[] buf;
+ }
+ }
+ glDeleteShader(shader);
+ return UNKNOWN_ERROR;
+ }
+ *outShader = shader;
+ return NO_ERROR;
+}
+
+status_t Program::linkShaderProgram(GLuint vs, GLuint fs, GLuint* outPgm) {
+ GLuint program = glCreateProgram();
+ if (program == 0) {
+ ALOGE("glCreateProgram error: %#x", glGetError());
+ return UNKNOWN_ERROR;
+ }
+
+ glAttachShader(program, vs);
+ glAttachShader(program, fs);
+ glLinkProgram(program);
+ GLint linkStatus = GL_FALSE;
+ glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
+ if (linkStatus != GL_TRUE) {
+ ALOGE("glLinkProgram failed");
+ GLint bufLength = 0;
+ glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
+ if (bufLength) {
+ char* buf = new char[bufLength];
+ if (buf) {
+ glGetProgramInfoLog(program, bufLength, NULL, buf);
+ ALOGE("Link log: %s", buf);
+ delete[] buf;
+ }
+ }
+ glDeleteProgram(program);
+ return UNKNOWN_ERROR;
+ }
+
+ *outPgm = program;
+ return NO_ERROR;
+}
+
+
+
+status_t Program::blit(GLuint texName, const float* texMatrix,
+ int32_t x, int32_t y, int32_t w, int32_t h) const {
+ ALOGV("Program::blit %d xy=%d,%d wh=%d,%d", texName, x, y, w, h);
+
+ const float pos[] = {
+ float(x), float(y+h),
+ float(x+w), float(y+h),
+ float(x), float(y),
+ float(x+w), float(y),
+ };
+ const float uv[] = {
+ 0.0f, 0.0f,
+ 1.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 1.0f,
+ };
+ status_t err;
+
+ err = beforeDraw(texName, texMatrix, pos, uv);
+ if (err == NO_ERROR) {
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ err = afterDraw();
+ }
+ return err;
+}
+
+status_t Program::drawTriangles(GLuint texName, const float* texMatrix,
+ const float* vertices, const float* texes, size_t count) const {
+ ALOGV("Program::drawTriangles texName=%d", texName);
+
+ status_t err;
+
+ err = beforeDraw(texName, texMatrix, vertices, texes);
+ if (err == NO_ERROR) {
+ glDrawArrays(GL_TRIANGLES, 0, count);
+ err = afterDraw();
+ }
+ return err;
+}
+
+status_t Program::beforeDraw(GLuint texName, const float* texMatrix,
+ const float* vertices, const float* texes) const {
+ // Create an orthographic projection matrix based on viewport size.
+ GLint vp[4];
+ glGetIntegerv(GL_VIEWPORT, vp);
+ float screenToNdc[16] = {
+ 2.0f/float(vp[2]), 0.0f, 0.0f, 0.0f,
+ 0.0f, -2.0f/float(vp[3]), 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ -1.0f, 1.0f, 0.0f, 1.0f,
+ };
+
+ glUseProgram(mProgram);
+
+ glVertexAttribPointer(maPositionLoc, 2, GL_FLOAT, GL_FALSE, 0, vertices);
+ glVertexAttribPointer(maTextureCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, texes);
+ glEnableVertexAttribArray(maPositionLoc);
+ glEnableVertexAttribArray(maTextureCoordLoc);
+
+ glUniformMatrix4fv(muMVPMatrixLoc, 1, GL_FALSE, screenToNdc);
+ glUniformMatrix4fv(muGLCMatrixLoc, 1, GL_FALSE, texMatrix);
+
+ glActiveTexture(GL_TEXTURE0);
+
+ switch (mProgramType) {
+ case PROGRAM_EXTERNAL_TEXTURE:
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, texName);
+ break;
+ case PROGRAM_TEXTURE_2D:
+ glBindTexture(GL_TEXTURE_2D, texName);
+ break;
+ default:
+ ALOGE("unexpected program type %d", mProgramType);
+ return UNKNOWN_ERROR;
+ }
+
+ glUniform1i(muTextureLoc, 0);
+
+ GLenum glErr;
+ if ((glErr = glGetError()) != GL_NO_ERROR) {
+ ALOGE("GL error before draw: %#x", glErr);
+ glDisableVertexAttribArray(maPositionLoc);
+ glDisableVertexAttribArray(maTextureCoordLoc);
+ return UNKNOWN_ERROR;
+ }
+
+ return NO_ERROR;
+}
+
+status_t Program::afterDraw() const {
+ glDisableVertexAttribArray(maPositionLoc);
+ glDisableVertexAttribArray(maTextureCoordLoc);
+
+ GLenum glErr;
+ if ((glErr = glGetError()) != GL_NO_ERROR) {
+ ALOGE("GL error after draw: %#x", glErr);
+ return UNKNOWN_ERROR;
+ }
+
+ return NO_ERROR;
+}