GBA Video: GL cleanup, initial work on blending

This commit is contained in:
Vicki Pfau 2019-05-10 23:44:04 -07:00
parent 18e6acaf72
commit 8a6ea929d2
2 changed files with 97 additions and 71 deletions

View File

@ -29,6 +29,15 @@ CXX_GUARD_START
#include <GLES2/gl2.h>
#endif
struct GBAVideoGLAffine {
int16_t dx;
int16_t dmx;
int16_t dy;
int16_t dmy;
int32_t sx;
int32_t sy;
};
struct GBAVideoGLBackground {
GLuint fbo;
GLuint tex;
@ -48,19 +57,8 @@ struct GBAVideoGLBackground {
uint16_t y;
int32_t refx;
int32_t refy;
int16_t dx;
int16_t dmx;
int16_t dy;
int16_t dmy;
int32_t sx;
int32_t sy;
int16_t lastDx;
int16_t lastDmx;
int16_t lastDy;
int16_t lastDmy;
int32_t lastSx;
int32_t lastSy;
struct GBAVideoGLAffine affine[2];
};
struct GBAVideoGLRenderer {

View File

@ -43,13 +43,13 @@ static const GLchar* const _gl3Header =
static const char* const _vertexShader =
"attribute vec2 position;\n"
"uniform ivec3 loc;\n"
"const ivec3 maxPos = ivec3(240, 160, 32);\n"
"uniform ivec2 loc;\n"
"const ivec2 maxPos = ivec2(240, 160);\n"
"varying vec2 texCoord;\n"
"void main() {\n"
" vec2 local = (position * loc.x + vec2(0, loc.y)) / vec2(1., maxPos.y);\n"
" gl_Position = vec4(local * 2. - 1., loc.z / float(maxPos.z), 1.);\n"
" gl_Position = vec4(local * 2. - 1., 0., 1.);\n"
" texCoord = local * maxPos.xy;\n"
"}";
@ -142,6 +142,7 @@ static const char* const _renderMode2 =
"uniform ivec2 oldOffset;\n"
"uniform mat2x2 transform;\n"
"uniform mat2x2 oldTransform;\n"
"uniform int firstD;\n"
"vec4 fetchTile(ivec2 coord);\n"
@ -164,22 +165,43 @@ static const char* const _renderMode2 =
"}"
"void main() {\n"
" vec2 newCoord = transform[0] * texCoord.x + offset;\n"
" vec2 oldCoord = oldTransform[0] * texCoord.x + oldOffset;\n"
" gl_FragColor = fetchTile(ivec2(newCoord * fract(texCoord.y) + oldCoord * (1. - fract(texCoord.y))));\n"
" float y = fract(texCoord.y);\n"
" float lin = y / ceil(y);\n"
" vec2 mixedTransform = mix(oldTransform[0], transform[0], lin);\n"
" vec2 mixedOffset = mix(oldOffset, offset, lin);\n"
" gl_FragColor = fetchTile(ivec2(mixedTransform * texCoord.x + mixedOffset));\n"
"}";
static const char* const _composite =
"varying vec2 texCoord;\n"
"uniform sampler2D layer;\n"
"uniform ivec3 inflags;\n"
"uniform int scale;\n"
"uniform vec3 blend;\n"
"uniform sampler2D layer;\n"
"uniform sampler2D oldLayer;\n"
"uniform sampler2D buffer;\n"
"out vec4 color;\n"
"out vec3 flags;\n"
"void main() {\n"
" vec4 color = texelFetch(layer, ivec2(texCoord * scale), 0);\n"
" if (color.a == 0) {\n"
" vec4 pix = texelFetch(layer, ivec2(texCoord * scale), 0);\n"
" if (pix.a == 0) {\n"
" discard;\n"
" }\n"
" gl_FragColor = color;\n"
" ivec3 oldFlags = ivec3(texelFetch(buffer, ivec2(texCoord * scale), 0).xyz * vec3(32., 4., 1.));\n"
" ivec3 outflags = ivec3(0, 0, 0);\n"
" if (inflags.x < oldFlags.x) {\n"
" outflags = inflags;\n"
" if ((inflags.y & 1) == 1 && (oldFlags.y & 2) == 2) {\n"
" vec4 oldpix = texelFetch(oldLayer, ivec2(texCoord * scale), 0);\n"
" pix *= blend.x;\n"
" pix += oldpix * blend.y;\n"
" }\n"
" } else {\n"
" pix = texelFetch(oldLayer, ivec2(texCoord * scale), 0);\n"
" }\n"
" color = pix;\n"
" flags = outflags / vec3(32., 4., 1.);\n"
"}";
static const GLint _vertices[] = {
@ -264,8 +286,8 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) {
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_DEPTH24_STENCIL8, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, glRenderer->layers[2], 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, glRenderer->layers[2], 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
@ -325,6 +347,8 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) {
shaderBuffer[1] = _composite;
_compileBackground(glRenderer, glRenderer->compositeProgram, shaderBuffer, 2, vs, log);
glBindFragDataLocation(glRenderer->compositeProgram, 0, "color");
glBindFragDataLocation(glRenderer->compositeProgram, 1, "flags");
glDeleteShader(vs);
@ -426,16 +450,16 @@ uint16_t GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer,
glRenderer->bg[3].y = value;
break;
case REG_BG2PA:
glRenderer->bg[2].dx = value;
glRenderer->bg[2].affine[0].dx = value;
break;
case REG_BG2PB:
glRenderer->bg[2].dmx = value;
glRenderer->bg[2].affine[0].dmx = value;
break;
case REG_BG2PC:
glRenderer->bg[2].dy = value;
glRenderer->bg[2].affine[0].dy = value;
break;
case REG_BG2PD:
glRenderer->bg[2].dmy = value;
glRenderer->bg[2].affine[0].dmy = value;
break;
case REG_BG2X_LO:
GBAVideoGLRendererWriteBGX_LO(&glRenderer->bg[2], value);
@ -450,16 +474,16 @@ uint16_t GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer,
GBAVideoGLRendererWriteBGY_HI(&glRenderer->bg[2], value);
break;
case REG_BG3PA:
glRenderer->bg[3].dx = value;
glRenderer->bg[3].affine[0].dx = value;
break;
case REG_BG3PB:
glRenderer->bg[3].dmx = value;
glRenderer->bg[3].affine[0].dmx = value;
break;
case REG_BG3PC:
glRenderer->bg[3].dy = value;
glRenderer->bg[3].affine[0].dy = value;
break;
case REG_BG3PD:
glRenderer->bg[3].dmy = value;
glRenderer->bg[3].affine[0].dmy = value;
break;
case REG_BG3X_LO:
GBAVideoGLRendererWriteBGX_LO(&glRenderer->bg[3], value);
@ -602,13 +626,15 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_SCISSOR_TEST);
if (y == 0) {
glClearDepthf(1);
glClear(GL_DEPTH_BUFFER_BIT);
glDrawBuffer(GL_COLOR_ATTACHMENT1);
glClearColor(1, (glRenderer->target1Bd | (glRenderer->target2Bd * 2)) / 4.f, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
unsigned priority;
for (priority = 0; priority < 4; ++priority) {
for (priority = 4; priority--;) {
if (TEST_LAYER_ENABLED(0) && GBARegisterDISPCNTGetMode(glRenderer->dispcnt) < 2) {
GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[0], y);
}
@ -646,25 +672,15 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
}
}
}
if (GBARegisterDISPCNTGetMode(glRenderer->dispcnt) != 0) {
glRenderer->bg[2].lastDx = glRenderer->bg[2].dx;
glRenderer->bg[2].lastDy = glRenderer->bg[2].dy;
glRenderer->bg[2].lastDmx = glRenderer->bg[2].dmx;
glRenderer->bg[2].lastDmy = glRenderer->bg[2].dmy;
glRenderer->bg[2].lastSx = glRenderer->bg[2].sx;
glRenderer->bg[2].lastSy = glRenderer->bg[2].sy;
glRenderer->bg[2].lastSx = glRenderer->bg[2].sx;
glRenderer->bg[2].lastSy = glRenderer->bg[2].sy;
glRenderer->bg[2].sx += glRenderer->bg[2].dmx;
glRenderer->bg[2].sy += glRenderer->bg[2].dmy;
glRenderer->bg[3].lastDx = glRenderer->bg[3].dx;
glRenderer->bg[3].lastDy = glRenderer->bg[3].dy;
glRenderer->bg[3].lastDmx = glRenderer->bg[3].dmx;
glRenderer->bg[3].lastDmy = glRenderer->bg[3].dmy;
glRenderer->bg[3].lastSx = glRenderer->bg[3].sx;
glRenderer->bg[3].lastSy = glRenderer->bg[3].sy;
glRenderer->bg[3].sx += glRenderer->bg[3].dmx;
glRenderer->bg[3].sy += glRenderer->bg[3].dmy;
memcpy(&glRenderer->bg[2].affine[1], &glRenderer->bg[2].affine[0], sizeof(struct GBAVideoGLAffine));
memcpy(&glRenderer->bg[3].affine[1], &glRenderer->bg[3].affine[0], sizeof(struct GBAVideoGLAffine));
glRenderer->bg[2].affine[0].sx += glRenderer->bg[2].affine[0].dmx;
glRenderer->bg[2].affine[0].sy += glRenderer->bg[2].affine[0].dmy;
glRenderer->bg[3].affine[0].sx += glRenderer->bg[3].affine[0].dmx;
glRenderer->bg[3].affine[0].sy += glRenderer->bg[3].affine[0].dmy;
}
}
@ -715,26 +731,26 @@ static void GBAVideoGLRendererWriteBGCNT(struct GBAVideoGLBackground* bg, uint16
static void GBAVideoGLRendererWriteBGX_LO(struct GBAVideoGLBackground* bg, uint16_t value) {
bg->refx = (bg->refx & 0xFFFF0000) | value;
bg->sx = bg->refx;
bg->affine[0].sx = bg->refx;
}
static void GBAVideoGLRendererWriteBGX_HI(struct GBAVideoGLBackground* bg, uint16_t value) {
bg->refx = (bg->refx & 0x0000FFFF) | (value << 16);
bg->refx <<= 4;
bg->refx >>= 4;
bg->sx = bg->refx;
bg->affine[0].sx = bg->refx;
}
static void GBAVideoGLRendererWriteBGY_LO(struct GBAVideoGLBackground* bg, uint16_t value) {
bg->refy = (bg->refy & 0xFFFF0000) | value;
bg->sy = bg->refy;
bg->affine[0].sy = bg->refy;
}
static void GBAVideoGLRendererWriteBGY_HI(struct GBAVideoGLBackground* bg, uint16_t value) {
bg->refy = (bg->refy & 0x0000FFFF) | (value << 16);
bg->refy <<= 4;
bg->refy >>= 4;
bg->sy = bg->refy;
bg->affine[0].sy = bg->refy;
}
static void GBAVideoGLRendererWriteBLDCNT(struct GBAVideoGLRenderer* renderer, uint16_t value) {
@ -754,25 +770,32 @@ static void GBAVideoGLRendererWriteBLDCNT(struct GBAVideoGLRenderer* renderer, u
renderer->target2Bd = GBARegisterBLDCNTGetTarget2Bd(value);
}
static void _compositeLayer(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {
static void _compositeLayer(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y, int flags) {
if ((y & 0x1F) != 0x1F) {
return;
}
glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[1]);
glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale);
glScissor(0, (y * renderer->scale) % (0x20 * renderer->scale), GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, 0x20 * renderer->scale);
glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
glUseProgram(renderer->compositeProgram);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, background->tex);
glUniform3i(0, 0x20, y & ~0x1F, (background->priority << 3) + (background->index << 1) + 1);
glUniform1i(1, 0);
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_2D, renderer->outputTex);
glActiveTexture(GL_TEXTURE0 + 2);
glBindTexture(GL_TEXTURE_2D, renderer->layers[2]);
glUniform2i(0, 0x20, y & ~0x1F);
glUniform3i(1, (background->priority << 3) + (background->index << 1) + 1, flags, renderer->blendEffect);
glUniform1i(2, renderer->scale);
glUniform3f(3, renderer->blda / 16.f, renderer->bldb / 16.f, renderer->bldy / 16.f);
glUniform1i(4, 0);
glUniform1i(5, 1);
glUniform1i(6, 2);
glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices);
glEnableVertexAttribArray(0);
glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 });
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisable(GL_DEPTH_TEST);
glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
}
void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {
@ -791,7 +814,7 @@ void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer,
glBindTexture(GL_TEXTURE_2D, renderer->vramTex);
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_2D, renderer->paletteTex);
glUniform3i(0, 1, y, 0);
glUniform2i(0, 1, y);
glUniform1i(1, 0);
glUniform1i(2, 1);
glUniform1i(3, background->screenBase);
@ -802,7 +825,7 @@ void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer,
glEnableVertexAttribArray(0);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
_compositeLayer(renderer, background, y);
_compositeLayer(renderer, background, y, background->target1 | (background->target2 * 2));
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
@ -816,21 +839,26 @@ void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer,
glBindTexture(GL_TEXTURE_2D, renderer->vramTex);
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_2D, renderer->paletteTex);
glUniform3i(0, 1, y, 0);
glUniform2i(0, 1, y);
glUniform1i(1, 0);
glUniform1i(2, 1);
glUniform1i(3, background->screenBase);
glUniform1i(4, background->charBase);
glUniform1i(5, background->size);
glUniform2i(6, background->sx, background->sy);
glUniform2i(7, background->lastSx, background->lastSy);
glUniformMatrix2fv(8, 1, GL_FALSE, (GLfloat[]) { background->dx, background->dy, background->dmx, background->dmy });
glUniformMatrix2fv(9, 1, GL_FALSE, (GLfloat[]) { background->lastDx, background->lastDy, background->lastDmx, background->lastDmy });
glUniform2i(6, background->affine[0].sx, background->affine[0].sy);
glUniformMatrix2fv(8, 1, GL_FALSE, (GLfloat[]) { background->affine[0].dx, background->affine[0].dy, background->affine[0].dmx, background->affine[0].dmy });
if (renderer->scale > 1) {
glUniform2i(7, background->affine[1].sx, background->affine[1].sy);
glUniformMatrix2fv(9, 1, GL_FALSE, (GLfloat[]) { background->affine[1].dx, background->affine[1].dy, background->affine[1].dmx, background->affine[1].dmy });
} else {
glUniform2i(7, background->affine[0].sx, background->affine[0].sy);
glUniformMatrix2fv(9, 1, GL_FALSE, (GLfloat[]) { background->affine[0].dx, background->affine[0].dy, background->affine[0].dmx, background->affine[0].dmy });
}
glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices);
glEnableVertexAttribArray(0);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
_compositeLayer(renderer, background, y);
_compositeLayer(renderer, background, y, background->target1 | (background->target2 * 2));
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}