OpenGL: Revamp shader backend

This commit is contained in:
Jeffrey Pfau 2015-11-01 11:29:00 -08:00
parent 8c6a57f7d9
commit 4a502c2c03
2 changed files with 228 additions and 112 deletions

View File

@ -21,7 +21,7 @@ static const char* const _nullVertexShader =
"varying vec2 texCoord;\n"
"void main() {\n"
" gl_Position = position * vec4(1.0, 1.0, 1.0, 1.0);\n"
" gl_Position = position;\n"
" texCoord = (position.st + vec2(1.0, 1.0)) * vec2(0.5, 0.5);\n"
"}";
@ -36,7 +36,17 @@ static const char* const _fragmentShader =
" vec4 color = texture2D(tex, texCoord);\n"
" color.a = 1.;\n"
" color.rgb = scale * pow(color.rgb, vec3(gamma, gamma, gamma)) + bias;\n"
" gl_FragColor = color;"
" gl_FragColor = color;\n"
"}";
static const char* const _nullFragmentShader =
"varying vec2 texCoord;\n"
"uniform sampler2D tex;\n"
"void main() {\n"
" vec4 color = texture2D(tex, texCoord);\n"
" color.a = 1.;\n"
" gl_FragColor = color;\n"
"}";
static const GLfloat _vertices[] = {
@ -46,6 +56,7 @@ static const GLfloat _vertices[] = {
1.f, -1.f,
};
static void GBAGLES2ContextInit(struct VideoBackend* v, WHandle handle) {
UNUSED(handle);
struct GBAGLES2Context* context = (struct GBAGLES2Context*) v;
@ -64,44 +75,34 @@ static void GBAGLES2ContextInit(struct VideoBackend* v, WHandle handle) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
#endif
context->program = glCreateProgram();
context->fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
context->vertexShader = glCreateShader(GL_VERTEX_SHADER);
context->nullVertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(context->fragmentShader, 1, (const GLchar**) &_fragmentShader, 0);
glShaderSource(context->vertexShader, 1, (const GLchar**) &_vertexShader, 0);
glShaderSource(context->nullVertexShader, 1, (const GLchar**) &_nullVertexShader, 0);
glAttachShader(context->program, context->vertexShader);
glAttachShader(context->program, context->fragmentShader);
char log[1024];
glCompileShader(context->fragmentShader);
glCompileShader(context->vertexShader);
glCompileShader(context->nullVertexShader);
glGetShaderInfoLog(context->fragmentShader, 1024, 0, log);
printf("%s\n", log);
glGetShaderInfoLog(context->vertexShader, 1024, 0, log);
printf("%s\n", log);
glGetShaderInfoLog(context->nullVertexShader, 1024, 0, log);
printf("%s\n", log);
glLinkProgram(context->program);
glGetProgramInfoLog(context->program, 1024, 0, log);
printf("%s\n", log);
context->texLocation = glGetUniformLocation(context->program, "tex");
context->gammaLocation = glGetUniformLocation(context->program, "gamma");
context->biasLocation = glGetUniformLocation(context->program, "bias");
context->scaleLocation = glGetUniformLocation(context->program, "scale");
context->positionLocation = glGetAttribLocation(context->program, "position");
glClearColor(0.f, 0.f, 0.f, 1.f);
struct GBAGLES2Uniform* uniforms = malloc(sizeof(struct GBAGLES2Uniform) * 3);
uniforms[0].name = "gamma";
uniforms[0].type = GL_FLOAT;
uniforms[0].value.f = 1.0f;
uniforms[1].name = "scale";
uniforms[1].type = GL_FLOAT_VEC3;
uniforms[1].value.fvec3[0] = 1.0f;
uniforms[1].value.fvec3[1] = 1.0f;
uniforms[1].value.fvec3[2] = 1.0f;
uniforms[2].name = "bias";
uniforms[2].type = GL_FLOAT_VEC3;
uniforms[2].value.fvec3[0] = 0.0f;
uniforms[2].value.fvec3[1] = 0.0f;
uniforms[2].value.fvec3[2] = 0.0f;
GBAGLES2ShaderInit(&context->initialShader, _vertexShader, _fragmentShader, -1, -1, uniforms, 3);
GBAGLES2ShaderInit(&context->finalShader, 0, 0, 0, 0, 0, 0);
glDeleteFramebuffers(1, &context->finalShader.fbo);
context->finalShader.fbo = 0;
}
static void GBAGLES2ContextDeinit(struct VideoBackend* v) {
struct GBAGLES2Context* context = (struct GBAGLES2Context*) v;
glDeleteTextures(1, &context->tex);
glDeleteShader(context->fragmentShader);
glDeleteShader(context->vertexShader);
glDeleteShader(context->nullVertexShader);
glDeleteProgram(context->program);
GBAGLES2ShaderDeinit(&context->initialShader);
GBAGLES2ShaderDeinit(&context->finalShader);
free(context->initialShader.uniforms);
}
static void GBAGLES2ContextResized(struct VideoBackend* v, int w, int h) {
@ -126,46 +127,118 @@ static void GBAGLES2ContextClear(struct VideoBackend* v) {
glClear(GL_COLOR_BUFFER_BIT);
}
void _drawShader(struct GBAGLES2Shader* shader) {
GLint viewport[4];
glBindFramebuffer(GL_FRAMEBUFFER, shader->fbo);
if (shader->blend) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
} else {
glDisable(GL_BLEND);
}
glGetIntegerv(GL_VIEWPORT, viewport);
glViewport(0, 0, shader->width ? shader->width : viewport[2], shader->height ? shader->height : viewport[3]);
if (!shader->width || !shader->height) {
GLint oldTex;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTex);
glBindTexture(GL_TEXTURE_2D, shader->tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, shader->width ? shader->width : viewport[2], shader->height ? shader->height : viewport[3], 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, oldTex);
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, shader->filter ? GL_LINEAR : GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, shader->filter ? GL_LINEAR : GL_NEAREST);
glUseProgram(shader->program);
glUniform1i(shader->texLocation, 0);
glVertexAttribPointer(shader->positionLocation, 2, GL_FLOAT, GL_FALSE, 0, _vertices);
glEnableVertexAttribArray(shader->positionLocation);
size_t u;
for (u = 0; u < shader->nUniforms; ++u) {
struct GBAGLES2Uniform* uniform = &shader->uniforms[u];
switch (uniform->type) {
case GL_FLOAT:
glUniform1f(uniform->location, uniform->value.f);
break;
case GL_INT:
glUniform1f(uniform->location, uniform->value.i);
break;
case GL_UNSIGNED_INT:
glUniform1f(uniform->location, uniform->value.ui);
break;
case GL_FLOAT_VEC2:
glUniform2fv(uniform->location, 1, uniform->value.fvec2);
break;
case GL_FLOAT_VEC3:
glUniform3fv(uniform->location, 1, uniform->value.fvec3);
break;
case GL_FLOAT_VEC4:
glUniform4fv(uniform->location, 1, uniform->value.fvec4);
break;
case GL_INT_VEC2:
glUniform2iv(uniform->location, 1, uniform->value.ivec2);
break;
case GL_INT_VEC3:
glUniform3iv(uniform->location, 1, uniform->value.ivec3);
break;
case GL_INT_VEC4:
glUniform4iv(uniform->location, 1, uniform->value.ivec4);
break;
case GL_UNSIGNED_INT_VEC2:
glUniform2uiv(uniform->location, 1, uniform->value.uivec2);
break;
case GL_UNSIGNED_INT_VEC3:
glUniform3uiv(uniform->location, 1, uniform->value.uivec3);
break;
case GL_UNSIGNED_INT_VEC4:
glUniform4uiv(uniform->location, 1, uniform->value.uivec4);
break;
case GL_FLOAT_MAT2:
glUniformMatrix2fv(uniform->location, 1, GL_FALSE, uniform->value.fmat2x2);
break;
case GL_FLOAT_MAT2x3:
glUniformMatrix2x3fv(uniform->location, 1, GL_FALSE, uniform->value.fmat2x3);
break;
case GL_FLOAT_MAT2x4:
glUniformMatrix2x4fv(uniform->location, 1, GL_FALSE, uniform->value.fmat2x4);
break;
case GL_FLOAT_MAT3x2:
glUniformMatrix3x2fv(uniform->location, 1, GL_FALSE, uniform->value.fmat3x2);
break;
case GL_FLOAT_MAT3:
glUniformMatrix3fv(uniform->location, 1, GL_FALSE, uniform->value.fmat3x3);
break;
case GL_FLOAT_MAT3x4:
glUniformMatrix3x4fv(uniform->location, 1, GL_FALSE, uniform->value.fmat3x4);
break;
case GL_FLOAT_MAT4x2:
glUniformMatrix2fv(uniform->location, 1, GL_FALSE, uniform->value.fmat4x2);
break;
case GL_FLOAT_MAT4x3:
glUniformMatrix2x3fv(uniform->location, 1, GL_FALSE, uniform->value.fmat4x3);
break;
case GL_FLOAT_MAT4:
glUniformMatrix2x4fv(uniform->location, 1, GL_FALSE, uniform->value.fmat4x4);
break;
}
}
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, shader->tex);
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
}
void GBAGLES2ContextDrawFrame(struct VideoBackend* v) {
struct GBAGLES2Context* context = (struct GBAGLES2Context*) v;
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, context->tex);
if (context->shader) {
GLint viewport[4];
if (context->shader->blend) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
} else {
glDisable(GL_BLEND);
}
glGetIntegerv(GL_VIEWPORT, viewport);
glViewport(0, 0, context->shader->width, context->shader->height);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, context->shader->filter ? GL_LINEAR : GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, context->shader->filter ? GL_LINEAR : GL_NEAREST);
glBindFramebuffer(GL_FRAMEBUFFER, context->shader->fbo);
glUseProgram(context->shader->program);
glUniform1i(context->shader->texLocation, 0);
glVertexAttribPointer(context->shader->positionLocation, 2, GL_FLOAT, GL_FALSE, 0, _vertices);
glEnableVertexAttribArray(context->shader->positionLocation);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, context->shader->tex);
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
context->finalShader.filter = v->filter;
_drawShader(&context->initialShader);
size_t n;
for (n = 0; n < context->nShaders; ++n) {
_drawShader(&context->shaders[n]);
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, v->filter ? GL_LINEAR : GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, v->filter ? GL_LINEAR : GL_NEAREST);
glUseProgram(context->program);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glUniform1i(context->texLocation, 0);
glUniform1f(context->gammaLocation, context->gamma);
glUniform3f(context->biasLocation, context->bias[0], context->bias[1], context->bias[2]);
glUniform3f(context->scaleLocation, context->scale[0], context->scale[1], context->scale[2]);
glVertexAttribPointer(context->positionLocation, 2, GL_FLOAT, GL_FALSE, 0, _vertices);
glEnableVertexAttribArray(context->positionLocation);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisable(GL_BLEND);
_drawShader(&context->finalShader);
glUseProgram(0);
}
@ -195,21 +268,17 @@ void GBAGLES2ContextCreate(struct GBAGLES2Context* context) {
context->d.drawFrame = GBAGLES2ContextDrawFrame;
context->d.setMessage = 0;
context->d.clearMessage = 0;
context->shader = 0;
context->gamma = 1.0f;
context->bias[0] = 0.0f;
context->bias[1] = 0.0f;
context->bias[2] = 0.0f;
context->scale[0] = 1.0f;
context->scale[1] = 1.0f;
context->scale[2] = 1.0f;
context->shaders = 0;
context->nShaders = 0;
}
void GBAGLES2ShaderInit(struct GBAGLES2Shader* shader, const char* src, int width, int height) {
shader->width = width > 0 ? width : VIDEO_HORIZONTAL_PIXELS;
shader->height = height > 0 ? height : VIDEO_VERTICAL_PIXELS;
void GBAGLES2ShaderInit(struct GBAGLES2Shader* shader, const char* vs, const char* fs, int width, int height, struct GBAGLES2Uniform* uniforms, size_t nUniforms) {
shader->width = width >= 0 ? width : VIDEO_HORIZONTAL_PIXELS;
shader->height = height >= 0 ? height : VIDEO_VERTICAL_PIXELS;
shader->filter = false;
shader->blend = false;
shader->uniforms = uniforms;
shader->nUniforms = nUniforms;
glGenFramebuffers(1, &shader->fbo);
glBindFramebuffer(GL_FRAMEBUFFER, shader->fbo);
@ -219,16 +288,43 @@ void GBAGLES2ShaderInit(struct GBAGLES2Shader* shader, const char* src, int widt
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, shader->width, shader->height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
if (shader->width && shader->height) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, shader->width, shader->height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
}
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, shader->tex, 0);
shader->program = glCreateProgram();
shader->vertexShader = glCreateShader(GL_VERTEX_SHADER);
shader->fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(shader->fragmentShader, 1, (const GLchar**) &src, 0);
if (vs) {
glShaderSource(shader->vertexShader, 1, (const GLchar**) &vs, 0);
} else {
glShaderSource(shader->vertexShader, 1, (const GLchar**) &_nullVertexShader, 0);
}
if (fs) {
glShaderSource(shader->fragmentShader, 1, (const GLchar**) &fs, 0);
} else {
glShaderSource(shader->fragmentShader, 1, (const GLchar**) &_nullFragmentShader, 0);
}
glAttachShader(shader->program, shader->vertexShader);
glAttachShader(shader->program, shader->fragmentShader);
glCompileShader(shader->fragmentShader);
char log[1024];
glCompileShader(shader->fragmentShader);
glGetShaderInfoLog(shader->fragmentShader, 1024, 0, log);
printf("%s\n", log);
glCompileShader(shader->vertexShader);
glGetShaderInfoLog(shader->vertexShader, 1024, 0, log);
printf("%s\n", log);
glLinkProgram(shader->program);
glGetProgramInfoLog(shader->program, 1024, 0, log);
printf("%s\n", log);
shader->texLocation = glGetUniformLocation(shader->program, "tex");
shader->positionLocation = glGetAttribLocation(shader->program, "position");
size_t i;
for (i = 0; i < shader->nUniforms; ++i) {
shader->uniforms[i].location = glGetUniformLocation(shader->program, shader->uniforms[i].name);
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
@ -236,30 +332,23 @@ void GBAGLES2ShaderDeinit(struct GBAGLES2Shader* shader) {
glDeleteTextures(1, &shader->tex);
glDeleteShader(shader->fragmentShader);
glDeleteProgram(shader->program);
glDeleteFramebuffers(1, &shader->fbo);
}
void GBAGLES2ShaderAttach(struct GBAGLES2Context* context, struct GBAGLES2Shader* shader) {
if (context->shader) {
if (context->shader == shader) {
void GBAGLES2ShaderAttach(struct GBAGLES2Context* context, struct GBAGLES2Shader* shaders, size_t nShaders) {
if (context->shaders) {
if (context->shaders == shaders && context->nShaders == nShaders) {
return;
}
GBAGLES2ShaderDetach(context);
}
context->shader = shader;
glAttachShader(shader->program, context->nullVertexShader);
char log[1024];
glLinkProgram(shader->program);
glGetProgramInfoLog(shader->program, 1024, 0, log);
printf("%s\n", log);
shader->texLocation = glGetUniformLocation(shader->program, "tex");
shader->positionLocation = glGetAttribLocation(shader->program, "position");
context->shaders = shaders;
context->nShaders = nShaders;
}
void GBAGLES2ShaderDetach(struct GBAGLES2Context* context) {
if (!context->shader) {
if (!context->shaders) {
return;
}
glDetachShader(context->shader->program, context->nullVertexShader);
context->shader = 0;
context->shaders = 0;
}

View File

@ -8,7 +8,7 @@
#ifdef BUILD_GL
#ifdef __APPLE__
#include <OpenGL/gl.h>
#include <OpenGL/gl3.h>
#else
#include <GL/gl.h>
#endif
@ -18,6 +18,37 @@
#include "platform/video-backend.h"
union GBAGLES2UniformValue {
GLfloat f;
GLint i;
GLuint ui;
GLfloat fvec2[2];
GLfloat fvec3[3];
GLfloat fvec4[4];
GLint ivec2[2];
GLint ivec3[3];
GLint ivec4[4];
GLuint uivec2[2];
GLuint uivec3[3];
GLuint uivec4[4];
GLfloat fmat2x2[4];
GLfloat fmat2x3[6];
GLfloat fmat2x4[8];
GLfloat fmat3x2[6];
GLfloat fmat3x3[9];
GLfloat fmat3x4[12];
GLfloat fmat4x2[8];
GLfloat fmat4x3[12];
GLfloat fmat4x4[16];
};
struct GBAGLES2Uniform {
const char* name;
GLenum type;
union GBAGLES2UniformValue value;
GLuint location;
};
struct GBAGLES2Shader {
unsigned width;
unsigned height;
@ -26,38 +57,34 @@ struct GBAGLES2Shader {
GLuint tex;
GLuint fbo;
GLuint fragmentShader;
GLuint vertexShader;
GLuint program;
GLuint texLocation;
GLuint positionLocation;
struct GBAGLES2Uniform* uniforms;
size_t nUniforms;
};
struct GBAGLES2Context {
struct VideoBackend d;
GLuint tex;
GLuint fragmentShader;
GLuint vertexShader;
GLuint nullVertexShader;
GLuint program;
GLuint bufferObject;
GLuint texLocation;
GLuint positionLocation;
GLuint gammaLocation;
GLuint biasLocation;
GLuint scaleLocation;
GLfloat gamma;
GLfloat bias[3];
GLfloat scale[3];
struct GBAGLES2Shader initialShader;
struct GBAGLES2Shader finalShader;
struct GBAGLES2Shader* shader;
struct GBAGLES2Shader* shaders;
size_t nShaders;
};
void GBAGLES2ContextCreate(struct GBAGLES2Context*);
void GBAGLES2ShaderInit(struct GBAGLES2Shader*, const char*, int width, int height);
void GBAGLES2ShaderInit(struct GBAGLES2Shader*, const char* vs, const char* fs, int width, int height, struct GBAGLES2Uniform* uniforms, size_t nUniforms);
void GBAGLES2ShaderDeinit(struct GBAGLES2Shader*);
void GBAGLES2ShaderAttach(struct GBAGLES2Context*, struct GBAGLES2Shader*);
void GBAGLES2ShaderAttach(struct GBAGLES2Context*, struct GBAGLES2Shader*, size_t nShaders);
void GBAGLES2ShaderDetach(struct GBAGLES2Context*);
#endif