GBA Video: Move window drawing to a shader

This commit is contained in:
Vicki Pfau 2019-05-27 20:48:42 -07:00
parent ba2d702fb5
commit ef2a2e5002
2 changed files with 171 additions and 140 deletions

View File

@ -112,6 +112,12 @@ enum {
GBA_GL_OBJ_OBJWIN, GBA_GL_OBJ_OBJWIN,
GBA_GL_OBJ_MOSAIC, GBA_GL_OBJ_MOSAIC,
GBA_GL_WIN_DISPCNT = 2,
GBA_GL_WIN_BLEND,
GBA_GL_WIN_FLAGS,
GBA_GL_WIN_WIN0,
GBA_GL_WIN_WIN1,
GBA_GL_FINALIZE_SCALE = 2, GBA_GL_FINALIZE_SCALE = 2,
GBA_GL_FINALIZE_LAYERS, GBA_GL_FINALIZE_LAYERS,
GBA_GL_FINALIZE_FLAGS, GBA_GL_FINALIZE_FLAGS,
@ -157,6 +163,7 @@ struct GBAVideoGLRenderer {
struct GBAVideoGLShader bgShader[6]; struct GBAVideoGLShader bgShader[6];
struct GBAVideoGLShader objShader[2]; struct GBAVideoGLShader objShader[2];
struct GBAVideoGLShader windowShader;
struct GBAVideoGLShader finalizeShader; struct GBAVideoGLShader finalizeShader;
GBARegisterDISPCNT dispcnt; GBARegisterDISPCNT dispcnt;
@ -173,11 +180,13 @@ struct GBAVideoGLRenderer {
GBAMosaicControl mosaic; GBAMosaicControl mosaic;
struct GBAVideoGLWindowN { struct GBAVideoGLWindowN {
struct GBAVideoWindowRegion h[2]; struct GBAVideoWindowRegion h;
struct GBAVideoWindowRegion v; struct GBAVideoWindowRegion v;
GBAWindowControl control; GBAWindowControl control;
} winN[2]; } winN[2];
GLint winNHistory[2][GBA_VIDEO_VERTICAL_PIXELS * 4];
GBAWindowControl winout; GBAWindowControl winout;
GBAWindowControl objwin; GBAWindowControl objwin;

View File

@ -496,6 +496,75 @@ static const char* const _renderObj =
" window = objwin.yzw;\n" " window = objwin.yzw;\n"
"}"; "}";
static const struct GBAVideoGLUniform _uniformsWindow[] = {
{ "loc", GBA_GL_VS_LOC, },
{ "maxPos", GBA_GL_VS_MAXPOS, },
{ "dispcnt", GBA_GL_WIN_DISPCNT, },
{ "blend", GBA_GL_WIN_BLEND, },
{ "flags", GBA_GL_WIN_FLAGS, },
{ "win0", GBA_GL_WIN_WIN0, },
{ "win1", GBA_GL_WIN_WIN1, },
{ 0 }
};
static const char* const _renderWindow =
"in vec2 texCoord;\n"
"uniform int dispcnt;\n"
"uniform ivec2 blend;\n"
"uniform ivec3 flags;\n"
"uniform ivec4 win0[160];\n"
"uniform ivec4 win1[160];\n"
"OUT(0) out ivec3 window;\n"
"void crop(vec4 windowParams, int flags, inout ivec3 windowFlags) {\n"
" bvec4 compare = lessThan(texCoord.xxyy, windowParams);\n"
" compare = equal(compare, bvec4(true, false, true, false));\n"
" if (any(compare)) {\n"
" vec2 h = windowParams.xy;\n"
" vec2 v = windowParams.zw;\n"
" if (v.x > v.y) {\n"
" if (compare.z && compare.w) {\n"
" return;\n"
" }\n"
" } else if (compare.z || compare.w) {\n"
" return;\n"
" }\n"
" if (h.x > h.y) {\n"
" if (compare.x && compare.y) {\n"
" return;\n"
" }\n"
" } else if (compare.x || compare.y) {\n"
" return;\n"
" }\n"
" }\n"
" windowFlags.x = flags;\n"
"}\n"
"vec4 interpolate(ivec4 win[160]) {\n"
" vec4 bottom = vec4(win[int(texCoord.y) - 1]);\n"
" vec4 top = vec4(win[int(texCoord.y)]);\n"
" if (distance(top, bottom) > 40.) {\n"
" return top;\n"
" }\n"
" return vec4(mix(bottom.xy, top.xy, fract(texCoord.y)), top.zw);\n"
"}\n"
"void main() {\n"
" int dispflags = (dispcnt & 0x1F) | 0x20;\n"
" if ((dispcnt & 0xE0) == 0) {\n"
" window = ivec3(dispflags, blend);\n"
" } else {\n"
" ivec3 windowFlags = ivec3(flags.z, blend);\n"
" if ((dispcnt & 0x40) != 0) { \n"
" crop(interpolate(win1), flags.y, windowFlags);\n"
" }\n"
" if ((dispcnt & 0x20) != 0) { \n"
" crop(interpolate(win0), flags.x, windowFlags);\n"
" }\n"
" window = windowFlags;\n"
" }\n"
"}\n";
static const struct GBAVideoGLUniform _uniformsFinalize[] = { static const struct GBAVideoGLUniform _uniformsFinalize[] = {
{ "loc", GBA_GL_VS_LOC, }, { "loc", GBA_GL_VS_LOC, },
{ "maxPos", GBA_GL_VS_MAXPOS, }, { "maxPos", GBA_GL_VS_MAXPOS, },
@ -805,6 +874,12 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) {
glBindFragDataLocation(glRenderer->objShader[1].program, 2, "window"); glBindFragDataLocation(glRenderer->objShader[1].program, 2, "window");
#endif #endif
shaderBuffer[1] = _renderWindow;
_compileShader(glRenderer, &glRenderer->windowShader, shaderBuffer, 2, vs, _uniformsWindow, log);
#ifndef BUILD_GLES3
glBindFragDataLocation(glRenderer->windowShader.program, 0, "window");
#endif
shaderBuffer[1] = _finalize; shaderBuffer[1] = _finalize;
_compileShader(glRenderer, &glRenderer->finalizeShader, shaderBuffer, 2, vs, _uniformsFinalize, log); _compileShader(glRenderer, &glRenderer->finalizeShader, shaderBuffer, 2, vs, _uniformsFinalize, log);
@ -878,14 +953,16 @@ uint16_t GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer,
GBAVideoCacheWriteVideoRegister(renderer->cache, address, value); GBAVideoCacheWriteVideoRegister(renderer->cache, address, value);
} }
bool dirty = true; bool dirty = false;
switch (address) { switch (address) {
case REG_DISPCNT: case REG_DISPCNT:
value &= 0xFFF7; value &= 0xFFF7;
dirty = true;
break; break;
case REG_BG0CNT: case REG_BG0CNT:
case REG_BG1CNT: case REG_BG1CNT:
value &= 0xDFFF; value &= 0xDFFF;
dirty = true;
break; break;
case REG_BG0HOFS: case REG_BG0HOFS:
case REG_BG0VOFS: case REG_BG0VOFS:
@ -896,87 +973,126 @@ uint16_t GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer,
case REG_BG3HOFS: case REG_BG3HOFS:
case REG_BG3VOFS: case REG_BG3VOFS:
value &= 0x01FF; value &= 0x01FF;
dirty = true;
break; break;
case REG_BG2PA: case REG_BG2PA:
glRenderer->bg[2].affine.dx = value; glRenderer->bg[2].affine.dx = value;
dirty = false;
break; break;
case REG_BG2PB: case REG_BG2PB:
glRenderer->bg[2].affine.dmx = value; glRenderer->bg[2].affine.dmx = value;
dirty = false;
break; break;
case REG_BG2PC: case REG_BG2PC:
glRenderer->bg[2].affine.dy = value; glRenderer->bg[2].affine.dy = value;
dirty = false;
break; break;
case REG_BG2PD: case REG_BG2PD:
glRenderer->bg[2].affine.dmy = value; glRenderer->bg[2].affine.dmy = value;
dirty = false;
break; break;
case REG_BG2X_LO: case REG_BG2X_LO:
GBAVideoGLRendererWriteBGX_LO(&glRenderer->bg[2], value); GBAVideoGLRendererWriteBGX_LO(&glRenderer->bg[2], value);
dirty = false;
break; break;
case REG_BG2X_HI: case REG_BG2X_HI:
GBAVideoGLRendererWriteBGX_HI(&glRenderer->bg[2], value); GBAVideoGLRendererWriteBGX_HI(&glRenderer->bg[2], value);
dirty = false;
break; break;
case REG_BG2Y_LO: case REG_BG2Y_LO:
GBAVideoGLRendererWriteBGY_LO(&glRenderer->bg[2], value); GBAVideoGLRendererWriteBGY_LO(&glRenderer->bg[2], value);
dirty = false;
break; break;
case REG_BG2Y_HI: case REG_BG2Y_HI:
GBAVideoGLRendererWriteBGY_HI(&glRenderer->bg[2], value); GBAVideoGLRendererWriteBGY_HI(&glRenderer->bg[2], value);
dirty = false;
break; break;
case REG_BG3PA: case REG_BG3PA:
glRenderer->bg[3].affine.dx = value; glRenderer->bg[3].affine.dx = value;
dirty = false;
break; break;
case REG_BG3PB: case REG_BG3PB:
glRenderer->bg[3].affine.dmx = value; glRenderer->bg[3].affine.dmx = value;
dirty = false;
break; break;
case REG_BG3PC: case REG_BG3PC:
glRenderer->bg[3].affine.dy = value; glRenderer->bg[3].affine.dy = value;
dirty = false;
break; break;
case REG_BG3PD: case REG_BG3PD:
glRenderer->bg[3].affine.dmy = value; glRenderer->bg[3].affine.dmy = value;
dirty = false;
break; break;
case REG_BG3X_LO: case REG_BG3X_LO:
GBAVideoGLRendererWriteBGX_LO(&glRenderer->bg[3], value); GBAVideoGLRendererWriteBGX_LO(&glRenderer->bg[3], value);
dirty = false;
break; break;
case REG_BG3X_HI: case REG_BG3X_HI:
GBAVideoGLRendererWriteBGX_HI(&glRenderer->bg[3], value); GBAVideoGLRendererWriteBGX_HI(&glRenderer->bg[3], value);
dirty = false;
break; break;
case REG_BG3Y_LO: case REG_BG3Y_LO:
GBAVideoGLRendererWriteBGY_LO(&glRenderer->bg[3], value); GBAVideoGLRendererWriteBGY_LO(&glRenderer->bg[3], value);
dirty = false;
break; break;
case REG_BG3Y_HI: case REG_BG3Y_HI:
GBAVideoGLRendererWriteBGY_HI(&glRenderer->bg[3], value); GBAVideoGLRendererWriteBGY_HI(&glRenderer->bg[3], value);
dirty = false;
break; break;
case REG_BLDALPHA: case REG_BLDALPHA:
value &= 0x1F1F; value &= 0x1F1F;
dirty = true;
break; break;
case REG_BLDY: case REG_BLDY:
value &= 0x1F; value &= 0x1F;
if (value > 0x10) { if (value > 0x10) {
value = 0x10; value = 0x10;
} }
dirty = true;
break;
case REG_WIN0H:
glRenderer->winN[0].h.end = value;
glRenderer->winN[0].h.start = value >> 8;
if (glRenderer->winN[0].h.start > GBA_VIDEO_HORIZONTAL_PIXELS && glRenderer->winN[0].h.start > glRenderer->winN[0].h.end) {
glRenderer->winN[0].h.start = 0;
}
if (glRenderer->winN[0].h.end > GBA_VIDEO_HORIZONTAL_PIXELS) {
glRenderer->winN[0].h.end = GBA_VIDEO_HORIZONTAL_PIXELS;
if (glRenderer->winN[0].h.start > GBA_VIDEO_HORIZONTAL_PIXELS) {
glRenderer->winN[0].h.start = GBA_VIDEO_HORIZONTAL_PIXELS;
}
}
break;
case REG_WIN1H:
glRenderer->winN[1].h.end = value;
glRenderer->winN[1].h.start = value >> 8;
if (glRenderer->winN[1].h.start > GBA_VIDEO_HORIZONTAL_PIXELS && glRenderer->winN[1].h.start > glRenderer->winN[1].h.end) {
glRenderer->winN[1].h.start = 0;
}
if (glRenderer->winN[1].h.end > GBA_VIDEO_HORIZONTAL_PIXELS) {
glRenderer->winN[1].h.end = GBA_VIDEO_HORIZONTAL_PIXELS;
if (glRenderer->winN[1].h.start > GBA_VIDEO_HORIZONTAL_PIXELS) {
glRenderer->winN[1].h.start = GBA_VIDEO_HORIZONTAL_PIXELS;
}
}
break;
case REG_WIN0V:
glRenderer->winN[0].v.end = value;
glRenderer->winN[0].v.start = value >> 8;
if (glRenderer->winN[0].v.start > GBA_VIDEO_VERTICAL_PIXELS && glRenderer->winN[0].v.start > glRenderer->winN[0].v.end) {
glRenderer->winN[0].v.start = 0;
}
if (glRenderer->winN[0].v.end > GBA_VIDEO_VERTICAL_PIXELS) {
glRenderer->winN[0].v.end = GBA_VIDEO_VERTICAL_PIXELS;
if (glRenderer->winN[0].v.start > GBA_VIDEO_VERTICAL_PIXELS) {
glRenderer->winN[0].v.start = GBA_VIDEO_VERTICAL_PIXELS;
}
}
break;
case REG_WIN1V:
glRenderer->winN[1].v.end = value;
glRenderer->winN[1].v.start = value >> 8;
if (glRenderer->winN[1].v.start > GBA_VIDEO_VERTICAL_PIXELS && glRenderer->winN[1].v.start > glRenderer->winN[1].v.end) {
glRenderer->winN[1].v.start = 0;
}
if (glRenderer->winN[1].v.end > GBA_VIDEO_VERTICAL_PIXELS) {
glRenderer->winN[1].v.end = GBA_VIDEO_VERTICAL_PIXELS;
if (glRenderer->winN[1].v.start > GBA_VIDEO_VERTICAL_PIXELS) {
glRenderer->winN[1].v.start = GBA_VIDEO_VERTICAL_PIXELS;
}
}
break; break;
case REG_WININ: case REG_WININ:
value &= 0x3F3F;
break;
case REG_WINOUT: case REG_WINOUT:
value &= 0x3F3F; value &= 0x3F3F;
dirty = true;
break; break;
default: default:
dirty = true;
break; break;
} }
if (glRenderer->shadowRegs[address >> 1] == value) { if (glRenderer->shadowRegs[address >> 1] == value) {
@ -1050,58 +1166,6 @@ void _cleanRegister(struct GBAVideoGLRenderer* glRenderer, int address, uint16_t
case REG_BLDY: case REG_BLDY:
glRenderer->bldy = value; glRenderer->bldy = value;
break; break;
case REG_WIN0H:
glRenderer->winN[0].h[0].end = value;
glRenderer->winN[0].h[0].start = value >> 8;
if (glRenderer->winN[0].h[0].start > GBA_VIDEO_HORIZONTAL_PIXELS && glRenderer->winN[0].h[0].start > glRenderer->winN[0].h[0].end) {
glRenderer->winN[0].h[0].start = 0;
}
if (glRenderer->winN[0].h[0].end > GBA_VIDEO_HORIZONTAL_PIXELS) {
glRenderer->winN[0].h[0].end = GBA_VIDEO_HORIZONTAL_PIXELS;
if (glRenderer->winN[0].h[0].start > GBA_VIDEO_HORIZONTAL_PIXELS) {
glRenderer->winN[0].h[0].start = GBA_VIDEO_HORIZONTAL_PIXELS;
}
}
break;
case REG_WIN1H:
glRenderer->winN[1].h[0].end = value;
glRenderer->winN[1].h[0].start = value >> 8;
if (glRenderer->winN[1].h[0].start > GBA_VIDEO_HORIZONTAL_PIXELS && glRenderer->winN[1].h[0].start > glRenderer->winN[1].h[0].end) {
glRenderer->winN[1].h[0].start = 0;
}
if (glRenderer->winN[1].h[0].end > GBA_VIDEO_HORIZONTAL_PIXELS) {
glRenderer->winN[1].h[0].end = GBA_VIDEO_HORIZONTAL_PIXELS;
if (glRenderer->winN[1].h[0].start > GBA_VIDEO_HORIZONTAL_PIXELS) {
glRenderer->winN[1].h[0].start = GBA_VIDEO_HORIZONTAL_PIXELS;
}
}
break;
case REG_WIN0V:
glRenderer->winN[0].v.end = value;
glRenderer->winN[0].v.start = value >> 8;
if (glRenderer->winN[0].v.start > GBA_VIDEO_VERTICAL_PIXELS && glRenderer->winN[0].v.start > glRenderer->winN[0].v.end) {
glRenderer->winN[0].v.start = 0;
}
if (glRenderer->winN[0].v.end > GBA_VIDEO_VERTICAL_PIXELS) {
glRenderer->winN[0].v.end = GBA_VIDEO_VERTICAL_PIXELS;
if (glRenderer->winN[0].v.start > GBA_VIDEO_VERTICAL_PIXELS) {
glRenderer->winN[0].v.start = GBA_VIDEO_VERTICAL_PIXELS;
}
}
break;
case REG_WIN1V:
glRenderer->winN[1].v.end = value;
glRenderer->winN[1].v.start = value >> 8;
if (glRenderer->winN[1].v.start > GBA_VIDEO_VERTICAL_PIXELS && glRenderer->winN[1].v.start > glRenderer->winN[1].v.end) {
glRenderer->winN[1].v.start = 0;
}
if (glRenderer->winN[1].v.end > GBA_VIDEO_VERTICAL_PIXELS) {
glRenderer->winN[1].v.end = GBA_VIDEO_VERTICAL_PIXELS;
if (glRenderer->winN[1].v.start > GBA_VIDEO_VERTICAL_PIXELS) {
glRenderer->winN[1].v.start = GBA_VIDEO_VERTICAL_PIXELS;
}
}
break;
case REG_WININ: case REG_WININ:
glRenderer->winN[0].control = value; glRenderer->winN[0].control = value;
glRenderer->winN[1].control = value >> 8; glRenderer->winN[1].control = value >> 8;
@ -1223,8 +1287,6 @@ static bool _needsVramUpload(struct GBAVideoGLRenderer* renderer, int y) {
void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
memcpy(&glRenderer->affine[0][y], &glRenderer->bg[2].affine, sizeof(struct GBAVideoGLAffine));
memcpy(&glRenderer->affine[1][y], &glRenderer->bg[3].affine, sizeof(struct GBAVideoGLAffine));
if (GBARegisterDISPCNTGetMode(glRenderer->dispcnt) != 0) { if (GBARegisterDISPCNTGetMode(glRenderer->dispcnt) != 0) {
if (glRenderer->firstAffine < 0) { if (glRenderer->firstAffine < 0) {
glRenderer->firstAffine = y; glRenderer->firstAffine = y;
@ -1243,9 +1305,6 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
glRenderer->firstY = y; glRenderer->firstY = y;
} }
memcpy(&glRenderer->winN[0].h[1], &glRenderer->winN[0].h[0], sizeof(struct GBAVideoWindowRegion));
memcpy(&glRenderer->winN[1].h[1], &glRenderer->winN[1].h[0], sizeof(struct GBAVideoWindowRegion));
int i; int i;
for (i = 0; i < 0x30; ++i) { for (i = 0; i < 0x30; ++i) {
if (!(glRenderer->regsDirty & (1ULL << i))) { if (!(glRenderer->regsDirty & (1ULL << i))) {
@ -1255,6 +1314,17 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
} }
glRenderer->regsDirty = 0; glRenderer->regsDirty = 0;
memcpy(&glRenderer->affine[0][y], &glRenderer->bg[2].affine, sizeof(struct GBAVideoGLAffine));
memcpy(&glRenderer->affine[1][y], &glRenderer->bg[3].affine, sizeof(struct GBAVideoGLAffine));
glRenderer->winNHistory[0][y * 4 + 0] = glRenderer->winN[0].h.start;
glRenderer->winNHistory[0][y * 4 + 1] = glRenderer->winN[0].h.end;
glRenderer->winNHistory[0][y * 4 + 2] = glRenderer->winN[0].v.start;
glRenderer->winNHistory[0][y * 4 + 3] = glRenderer->winN[0].v.end;
glRenderer->winNHistory[1][y * 4 + 0] = glRenderer->winN[1].h.start;
glRenderer->winNHistory[1][y * 4 + 1] = glRenderer->winN[1].h.end;
glRenderer->winNHistory[1][y * 4 + 2] = glRenderer->winN[1].v.start;
glRenderer->winNHistory[1][y * 4 + 3] = glRenderer->winN[1].v.end;
if (glRenderer->paletteDirty) { if (glRenderer->paletteDirty) {
for (i = 0; i < 512; ++i) { for (i = 0; i < 512; ++i) {
glRenderer->shadowPalette[i] = glRenderer->d.palette[i]; glRenderer->shadowPalette[i] = glRenderer->d.palette[i];
@ -1284,9 +1354,6 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
} }
if (y == 0) { if (y == 0) {
memcpy(&glRenderer->winN[0].h[1], &glRenderer->winN[0].h[0], sizeof(struct GBAVideoWindowRegion));
memcpy(&glRenderer->winN[1].h[1], &glRenderer->winN[1].h[0], sizeof(struct GBAVideoWindowRegion));
glDisable(GL_SCISSOR_TEST); glDisable(GL_SCISSOR_TEST);
glClearColor(0, 0, 0, 0); glClearColor(0, 0, 0, 0);
#ifdef BUILD_GLES3 #ifdef BUILD_GLES3
@ -1758,68 +1825,23 @@ void GBAVideoGLRendererDrawBackgroundMode5(struct GBAVideoGLRenderer* renderer,
glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 }); glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
} }
static void _scissorWindow(struct GBAVideoGLRenderer* renderer, int window, int start, int end, int y, int lines) {
if (start > end) {
_scissorWindow(renderer, window, start, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, y, lines);
_scissorWindow(renderer, window, 0, end, y, lines);
return;
}
glScissor(start, y, end - start, lines);
glClearBufferiv(GL_COLOR, 0, (GLint[]) { window, renderer->bldb, renderer->bldy, 0 });
}
static void _scissorWindowN(struct GBAVideoGLRenderer* renderer, const struct GBAVideoGLWindowN* window, const struct GBAVideoWindowRegion* y, int dispcnt) {
int sdelta = window->h[0].start - window->h[1].start;
int edelta = window->h[0].end - window->h[1].end;
int maxDelta = 0;
if (sdelta > maxDelta) {
maxDelta = sdelta;
} else if (-sdelta > maxDelta) {
maxDelta = -sdelta;
}
if (edelta > maxDelta) {
maxDelta = edelta;
} else if (-edelta > maxDelta) {
maxDelta = -edelta;
}
int startY = y->start;
int endY = y->end;
if (startY < window->v.start) {
startY = window->v.start;
}
if (endY >= window->v.end) {
endY = window->v.end - 1;
}
if (!(sdelta | edelta) || maxDelta >= GBA_VIDEO_VERTICAL_PIXELS / 2) {
_scissorWindow(renderer, window->control & dispcnt, window->h[0].start * renderer->scale, window->h[0].end * renderer->scale, startY * renderer->scale, (endY - startY + 1) * renderer->scale);
} else {
int i;
for (i = 0; i < renderer->scale * (endY - startY + 1); ++i) {
int start = window->h[1].start * renderer->scale + sdelta * i;
int end = window->h[1].end * renderer->scale + edelta * i;
_scissorWindow(renderer, window->control & dispcnt, start, end, startY * renderer->scale + i, 1);
}
}
}
void GBAVideoGLRendererDrawWindow(struct GBAVideoGLRenderer* renderer, int y) { void GBAVideoGLRendererDrawWindow(struct GBAVideoGLRenderer* renderer, int y) {
const struct GBAVideoGLShader* shader = &renderer->windowShader;
const GLuint* uniforms = shader->uniforms;
glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_WINDOW]); glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_WINDOW]);
int dispcnt = ((renderer->dispcnt >> 8) & 0x1F) | 0x20; glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale);
if (!(renderer->dispcnt & 0xE000)) { glScissor(0, renderer->firstY * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, renderer->scale * (y - renderer->firstY + 1));
_scissorWindow(renderer, dispcnt, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, renderer->firstY * renderer->scale, (y - renderer->firstY + 1) * renderer->scale); glUseProgram(shader->program);
} else { glBindVertexArray(shader->vao);
_scissorWindow(renderer, renderer->winout & dispcnt, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, renderer->firstY * renderer->scale, (y - renderer->firstY + 1) * renderer->scale); glUniform2i(uniforms[GBA_GL_VS_LOC], y - renderer->firstY + 1, renderer->firstY);
struct GBAVideoWindowRegion yRegion = { glUniform2i(uniforms[GBA_GL_VS_MAXPOS], GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS);
y, glUniform1i(uniforms[GBA_GL_WIN_DISPCNT], renderer->dispcnt >> 8);
renderer->firstY glUniform2i(uniforms[GBA_GL_WIN_BLEND], renderer->bldb, renderer->bldy);
}; glUniform3i(uniforms[GBA_GL_WIN_FLAGS], renderer->winN[0].control, renderer->winN[1].control, renderer->winout);
if (GBARegisterDISPCNTIsWin1Enable(renderer->dispcnt) && y >= renderer->winN[1].v.start && renderer->firstY < renderer->winN[1].v.end) { glUniform4iv(uniforms[GBA_GL_WIN_WIN0], GBA_VIDEO_VERTICAL_PIXELS, renderer->winNHistory[0]);
_scissorWindowN(renderer, &renderer->winN[1], &yRegion, dispcnt); glUniform4iv(uniforms[GBA_GL_WIN_WIN1], GBA_VIDEO_VERTICAL_PIXELS, renderer->winNHistory[1]);
} glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
if (GBARegisterDISPCNTIsWin0Enable(renderer->dispcnt) && y >= renderer->winN[0].v.start && renderer->firstY < renderer->winN[0].v.end) { glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
_scissorWindowN(renderer, &renderer->winN[0], &yRegion, dispcnt);
}
}
} }
#endif #endif