mirror of https://github.com/mgba-emu/mgba.git
OpenGL: Attachable shaders for GL2
This commit is contained in:
parent
f689bfcb2b
commit
206f38a47c
|
@ -16,6 +16,15 @@ static const char* const _vertexShader =
|
|||
" 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 @@ static void GBAGLES2ContextInit(struct VideoBackend* v, WHandle handle) {
|
|||
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 @@ static void GBAGLES2ContextDeinit(struct VideoBackend* v) {
|
|||
glDeleteTextures(1, &context->tex);
|
||||
glDeleteShader(context->fragmentShader);
|
||||
glDeleteShader(context->vertexShader);
|
||||
glDeleteShader(context->nullVertexShader);
|
||||
glDeleteProgram(context->program);
|
||||
}
|
||||
|
||||
|
@ -106,10 +123,27 @@ static void GBAGLES2ContextClear(struct VideoBackend* v) {
|
|||
|
||||
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 @@ void GBAGLES2ContextCreate(struct GBAGLES2Context* context) {
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -18,18 +18,37 @@
|
|||
|
||||
#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
|
||||
|
|
Loading…
Reference in New Issue