308 lines
8.9 KiB
C++
308 lines
8.9 KiB
C++
/*
|
|
* 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, bool invert) 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, invert);
|
|
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, false);
|
|
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, bool invert) 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,
|
|
};
|
|
if (invert) {
|
|
screenToNdc[5] = -screenToNdc[5];
|
|
screenToNdc[13] = -screenToNdc[13];
|
|
}
|
|
|
|
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;
|
|
}
|