all repos — mgba @ 206f38a47ce8ec0ec469dd8df3356c824e8b885f

mGBA Game Boy Advance Emulator

OpenGL: Attachable shaders for GL2
Jeffrey Pfau jeffrey@endrift.com
Thu, 29 Oct 2015 23:53:13 -0700
commit

206f38a47ce8ec0ec469dd8df3356c824e8b885f

parent

f689bfcb2b6831d65abc808d001b7e89370742ce

2 files changed, 113 insertions(+), 2 deletions(-)

jump to
M src/platform/opengl/gles2.csrc/platform/opengl/gles2.c

@@ -16,6 +16,15 @@ " gl_Position = position;\n"

" texCoord = (position.st + vec2(1.0, -1.0)) * vec2(0.46875, -0.3125);\n" "}"; +static const char* const _nullVertexShader = + "attribute vec4 position;\n" + "varying vec2 texCoord;\n" + + "void main() {\n" + " gl_Position = position * vec4(1.0, 1.0, 1.0, 1.0);\n" + " texCoord = (position.st + vec2(1.0, 1.0)) * vec2(0.5, 0.5);\n" + "}"; + static const char* const _fragmentShader = "varying vec2 texCoord;\n" "uniform sampler2D tex;\n"

@@ -56,16 +65,23 @@

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);

@@ -79,6 +95,7 @@ struct GBAGLES2Context* context = (struct GBAGLES2Context*) v;

glDeleteTextures(1, &context->tex); glDeleteShader(context->fragmentShader); glDeleteShader(context->vertexShader); + glDeleteShader(context->nullVertexShader); glDeleteProgram(context->program); }

@@ -106,10 +123,27 @@ }

void GBAGLES2ContextDrawFrame(struct VideoBackend* v) { struct GBAGLES2Context* context = (struct GBAGLES2Context*) v; - glUseProgram(context->program); - glUniform1i(context->texLocation, 0); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, context->tex); + 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); + + if (context->shader) { + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT, viewport); + glViewport(0, 0, context->shader->width, context->shader->height); + 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]); + } + glUseProgram(context->program); + glUniform1i(context->texLocation, 0); glVertexAttribPointer(context->positionLocation, 2, GL_FLOAT, GL_FALSE, 0, _vertices); glEnableVertexAttribArray(context->positionLocation); glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

@@ -140,4 +174,62 @@ context->d.postFrame = GBAGLES2ContextPostFrame;

context->d.drawFrame = GBAGLES2ContextDrawFrame; context->d.setMessage = 0; context->d.clearMessage = 0; + context->shader = 0; +} + +void GBAGLES2ShaderInit(struct GBAGLES2Shader* shader, const char* src, int width, int height, bool filter) { + shader->width = width > 0 ? width : 256; + shader->height = height > 0 ? height : 256; + glGenFramebuffers(1, &shader->fbo); + glBindFramebuffer(GL_FRAMEBUFFER, shader->fbo); + + glGenTextures(1, &shader->tex); + glBindTexture(GL_TEXTURE_2D, shader->tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter ? GL_LINEAR : GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter ? GL_LINEAR : 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); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, shader->tex, 0); + shader->program = glCreateProgram(); + shader->fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(shader->fragmentShader, 1, (const GLchar**) &src, 0); + glAttachShader(shader->program, shader->fragmentShader); + glCompileShader(shader->fragmentShader); + char log[1024]; + glGetShaderInfoLog(shader->fragmentShader, 1024, 0, log); + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + +void GBAGLES2ShaderDeinit(struct GBAGLES2Shader* shader) { + glDeleteTextures(1, &shader->tex); + glDeleteShader(shader->fragmentShader); + glDeleteProgram(shader->program); +} + +void GBAGLES2ShaderAttach(struct GBAGLES2Context* context, struct GBAGLES2Shader* shader) { + if (context->shader) { + if (context->shader == shader) { + 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"); +} + +void GBAGLES2ShaderDetach(struct GBAGLES2Context* context) { + if (!context->shader) { + return; + } + glDetachShader(context->shader->program, context->nullVertexShader); + context->shader = 0; }
M src/platform/opengl/gles2.hsrc/platform/opengl/gles2.h

@@ -18,18 +18,37 @@ #endif

#include "platform/video-backend.h" +struct GBAGLES2Shader { + unsigned width; + unsigned height; + GLuint tex; + GLuint fbo; + GLuint fragmentShader; + GLuint program; + GLuint texLocation; + GLuint positionLocation; +}; + struct GBAGLES2Context { struct VideoBackend d; GLuint tex; GLuint fragmentShader; GLuint vertexShader; + GLuint nullVertexShader; GLuint program; GLuint bufferObject; GLuint texLocation; GLuint positionLocation; + + struct GBAGLES2Shader* shader; }; void GBAGLES2ContextCreate(struct GBAGLES2Context*); + +void GBAGLES2ShaderInit(struct GBAGLES2Shader*, const char*, int width, int height, bool filter); +void GBAGLES2ShaderDeinit(struct GBAGLES2Shader*); +void GBAGLES2ShaderAttach(struct GBAGLES2Context*, struct GBAGLES2Shader*); +void GBAGLES2ShaderDetach(struct GBAGLES2Context*); #endif