GBA Video: GL sprite initial work

This commit is contained in:
Vicki Pfau 2019-05-12 20:21:02 -07:00
parent 68f0176ee4
commit 62f70379f6
7 changed files with 265 additions and 106 deletions

View File

@ -0,0 +1,25 @@
/* Copyright (c) 2013-2019 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GBA_RENDERER_COMMON_H
#define GBA_RENDERER_COMMON_H
#include <mgba-util/common.h>
CXX_GUARD_START
#include <mgba/internal/gba/video.h>
struct GBAVideoRendererSprite {
struct GBAObj obj;
int16_t y;
int16_t endY;
};
int GBAVideoRendererCleanOAM(struct GBAObj* oam, struct GBAVideoRendererSprite* sprites, int offsetY);
CXX_GUARD_END
#endif

View File

@ -13,6 +13,7 @@ CXX_GUARD_START
#include <mgba/core/core.h>
#include <mgba/gba/interface.h>
#include <mgba/internal/gba/io.h>
#include <mgba/internal/gba/renderers/common.h>
#include <mgba/internal/gba/video.h>
#ifdef USE_EPOXY
@ -61,11 +62,23 @@ struct GBAVideoGLBackground {
struct GBAVideoGLAffine affine[4];
};
enum {
GBA_GL_FBO_OBJ = 0,
GBA_GL_FBO_COMPOSITE = 1,
GBA_GL_TEX_OBJ_COLOR = 0,
GBA_GL_TEX_OBJ_FLAGS = 1,
GBA_GL_TEX_COMPOSITE_FLAGS = 2,
};
struct GBAVideoGLRenderer {
struct GBAVideoRenderer d;
struct GBAVideoGLBackground bg[4];
int oamMax;
struct GBAVideoRendererSprite sprites[128];
GLuint fbo[2];
GLuint layers[3];
@ -81,7 +94,7 @@ struct GBAVideoGLRenderer {
unsigned vramDirty;
GLuint bgProgram[6];
GLuint objProgram;
GLuint objProgram[4];
GLuint compositeProgram;

View File

@ -13,14 +13,9 @@ CXX_GUARD_START
#include <mgba/core/core.h>
#include <mgba/gba/interface.h>
#include <mgba/internal/gba/io.h>
#include <mgba/internal/gba/renderers/common.h>
#include <mgba/internal/gba/video.h>
struct GBAVideoSoftwareSprite {
struct GBAObj obj;
int y;
int endY;
};
struct GBAVideoSoftwareBackground {
unsigned index;
int enabled;
@ -140,7 +135,7 @@ struct GBAVideoSoftwareRenderer {
int oamDirty;
int oamMax;
struct GBAVideoSoftwareSprite sprites[128];
struct GBAVideoRendererSprite sprites[128];
int16_t objOffsetX;
int16_t objOffsetY;

View File

@ -263,10 +263,7 @@ static void _GBACoreLoadConfig(struct mCore* core, const struct mCoreConfig* con
static void _GBACoreDesiredVideoDimensions(struct mCore* core, unsigned* width, unsigned* height) {
struct GBACore* gbacore = (struct GBACore*) core;
int fakeBool;
int scale = 1;
if (mCoreConfigGetIntValue(&core->config, "hwaccelVideo", &fakeBool) && fakeBool) {
scale = gbacore->glRenderer.scale;
}
int scale = gbacore->glRenderer.scale;
*width = GBA_VIDEO_HORIZONTAL_PIXELS * scale;
*height = GBA_VIDEO_VERTICAL_PIXELS * scale;

View File

@ -0,0 +1,33 @@
/* Copyright (c) 2013-2019 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <mgba/internal/gba/renderers/common.h>
#include <mgba/gba/interface.h>
int GBAVideoRendererCleanOAM(struct GBAObj* oam, struct GBAVideoRendererSprite* sprites, int offsetY) {
int i;
int oamMax = 0;
for (i = 0; i < 128; ++i) {
struct GBAObj obj;
LOAD_16LE(obj.a, 0, &oam[i].a);
LOAD_16LE(obj.b, 0, &oam[i].b);
LOAD_16LE(obj.c, 0, &oam[i].c);
if (GBAObjAttributesAIsTransformed(obj.a) || !GBAObjAttributesAIsDisable(obj.a)) {
int height = GBAVideoObjSizes[GBAObjAttributesAGetShape(obj.a) * 4 + GBAObjAttributesBGetSize(obj.b)][1];
if (GBAObjAttributesAIsTransformed(obj.a)) {
height <<= GBAObjAttributesAGetDoubleSize(obj.a);
}
if (GBAObjAttributesAGetY(obj.a) < GBA_VIDEO_VERTICAL_PIXELS || GBAObjAttributesAGetY(obj.a) + height >= VIDEO_VERTICAL_TOTAL_PIXELS) {
int y = GBAObjAttributesAGetY(obj.a) + offsetY;
sprites[oamMax].y = y;
sprites[oamMax].endY = y + height;
sprites[oamMax].obj = obj;
++oamMax;
}
}
}
return oamMax;
}

View File

@ -30,12 +30,15 @@ static void GBAVideoGLRendererWriteBGY_LO(struct GBAVideoGLBackground* bg, uint1
static void GBAVideoGLRendererWriteBGY_HI(struct GBAVideoGLBackground* bg, uint16_t value);
static void GBAVideoGLRendererWriteBLDCNT(struct GBAVideoGLRenderer* renderer, uint16_t value);
static void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GBAObj* sprite, int y, int spriteY);
static void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y);
static void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y);
static void GBAVideoGLRendererDrawBackgroundMode3(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y);
static void GBAVideoGLRendererDrawBackgroundMode4(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y);
static void GBAVideoGLRendererDrawBackgroundMode5(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y);
static void _compositeLayer(struct GBAVideoGLRenderer* renderer, GLuint tex, int y, int priority, int flags);
#define TEST_LAYER_ENABLED(X) !renderer->disableBG[X] && glRenderer->bg[X].enabled == 4 && glRenderer->bg[X].priority == priority
static const GLchar* const _gl3Header =
@ -44,13 +47,13 @@ static const GLchar* const _gl3Header =
static const char* const _vertexShader =
"attribute vec2 position;\n"
"uniform ivec2 loc;\n"
"const ivec2 maxPos = ivec2(240, 160);\n"
"uniform ivec2 maxPos;\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., 0., 1.);\n"
" texCoord = local * maxPos.xy;\n"
" vec2 local = vec2(position.x, float(position.y * loc.x + loc.y) / abs(maxPos.y));\n"
" gl_Position = vec4((local * 2. - 1.) * sign(maxPos), 0., 1.);\n"
" texCoord = local * abs(maxPos);\n"
"}";
static const char* const _renderTile16 =
@ -60,10 +63,9 @@ static const char* const _renderTile16 =
" int entry = int(halfrow[3 - (localCoord.x & 3)] * 15.9);\n"
" vec4 color = texelFetch(palette, ivec2(entry, paletteId), 0);\n"
" if (entry == 0) {\n"
" color.a = 0;\n"
" } else {\n"
" color.a = 1;\n"
" discard;\n"
" }\n"
" color.a = 1;\n"
" return color;\n"
"}";
@ -74,11 +76,10 @@ static const char* const _renderTile256 =
" int entry = int(halfrow[3 - 2 * (localCoord.x & 1)] * 15.9);\n"
" int pal2 = int(halfrow[2 - 2 * (localCoord.x & 1)] * 15.9);\n"
" vec4 color = texelFetch(palette, ivec2(entry, pal2 + (paletteId & 16)), 0);\n"
" if (pal2 > 0 || entry > 0) {\n"
" color.a = 1.;\n"
" } else {\n"
" color.a = 0.;\n"
" if (pal2 + entry == 0) {\n"
" discard;\n"
" }\n"
" color.a = 1.;\n"
" return color;\n"
"}";
@ -179,6 +180,26 @@ static const char* const _renderMode2 =
" gl_FragColor = fetchTile(ivec2(mixedTransform * texCoord.x + mixedOffset));\n"
"}";
static const char* const _renderObjNoTransform =
"varying vec2 texCoord;\n"
"uniform sampler2D vram;\n"
"uniform sampler2D palette;\n"
"uniform int charBase;\n"
"uniform int stride;\n"
"uniform int localPalette;\n"
"uniform ivec3 inflags;\n"
"out vec4 color;\n"
"out vec3 flags;\n"
"const vec3 flagCoeff = vec3(32., 8., 4.);\n"
"vec4 renderTile(int tile, int paletteId, ivec2 localCoord);\n"
"void main() {\n"
" ivec2 coord = ivec2(texCoord);\n"
" color = renderTile((coord.x >> 3) + (coord.y >> 3) * stride, 16 + localPalette, coord & 7);\n"
" flags = inflags / flagCoeff;\n"
"}";
static const char* const _composite =
"varying vec2 texCoord;\n"
"uniform ivec3 inflags;\n"
@ -186,20 +207,21 @@ static const char* const _composite =
"uniform vec3 blend;\n"
"uniform sampler2D layer;\n"
"uniform sampler2D oldLayer;\n"
"uniform sampler2D buffer;\n"
"uniform sampler2D oldFlags;\n"
"out vec4 color;\n"
"out vec3 flags;\n"
"const vec3 flagCoeff = vec3(32., 8., 4.);\n"
"void main() {\n"
" vec4 pix = texelFetch(layer, ivec2(texCoord * scale), 0);\n"
" if (pix.a == 0) {\n"
" discard;\n"
" }\n"
" ivec3 oldFlags = ivec3(texelFetch(buffer, ivec2(texCoord * scale), 0).xyz * vec3(32., 4., 1.));\n"
" ivec3 oflags = ivec3(texelFetch(oldFlags, ivec2(texCoord * scale), 0).xyz * flagCoeff);\n"
" ivec3 outflags = ivec3(0, 0, 0);\n"
" if (inflags.x < oldFlags.x) {\n"
" if (inflags.x < oflags.x) {\n"
" outflags = inflags;\n"
" if (inflags.z == 1 && (inflags.y & 1) == 1 && (oldFlags.y & 2) == 2) {\n"
" if (inflags.z == 1 && (inflags.y & 1) == 1 && (oflags.y & 2) == 2) {\n"
" vec4 oldpix = texelFetch(oldLayer, ivec2(texCoord * scale), 0);\n"
" pix *= blend.x;\n"
" pix += oldpix * blend.y;\n"
@ -208,7 +230,7 @@ static const char* const _composite =
" pix = texelFetch(oldLayer, ivec2(texCoord * scale), 0);\n"
" }\n"
" color = pix;\n"
" flags = outflags / vec3(32., 4., 1.);\n"
" flags = outflags / flagCoeff;\n"
"}";
static const GLint _vertices[] = {
@ -240,7 +262,7 @@ void GBAVideoGLRendererCreate(struct GBAVideoGLRenderer* renderer) {
renderer->scale = 1;
}
void _compileBackground(struct GBAVideoGLRenderer* glRenderer, GLuint program, const char** shaderBuffer, int shaderBufferLines, GLuint vs, char* log) {
void _compileShader(struct GBAVideoGLRenderer* glRenderer, GLuint program, const char** shaderBuffer, int shaderBufferLines, GLuint vs, char* log) {
GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
glAttachShader(program, vs);
glAttachShader(program, fs);
@ -279,7 +301,24 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[1]);
glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_OBJ]);
glBindTexture(GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_OBJ_COLOR]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
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_RGBA, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_OBJ_COLOR], 0);
glBindTexture(GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_OBJ_FLAGS]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
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, 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[GBA_GL_TEX_OBJ_FLAGS], 0);
glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_COMPOSITE]);
glBindTexture(GL_TEXTURE_2D, glRenderer->outputTex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@ -288,13 +327,13 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) {
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_ATTACHMENT0, GL_TEXTURE_2D, glRenderer->outputTex, 0);
glBindTexture(GL_TEXTURE_2D, glRenderer->layers[2]);
glBindTexture(GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_COMPOSITE_FLAGS]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
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, 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);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_COMPOSITE_FLAGS], 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
@ -315,7 +354,10 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) {
}
glRenderer->compositeProgram = glCreateProgram();
glRenderer->objProgram = glCreateProgram();
glRenderer->objProgram[0] = glCreateProgram();
glRenderer->objProgram[1] = glCreateProgram();
glRenderer->objProgram[2] = glCreateProgram();
glRenderer->objProgram[3] = glCreateProgram();
glRenderer->bgProgram[0] = glCreateProgram();
glRenderer->bgProgram[1] = glCreateProgram();
glRenderer->bgProgram[2] = glCreateProgram();
@ -339,21 +381,26 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) {
shaderBuffer[1] = _renderMode0;
shaderBuffer[2] = _renderTile16;
_compileBackground(glRenderer, glRenderer->bgProgram[0], shaderBuffer, 3, vs, log);
_compileShader(glRenderer, glRenderer->bgProgram[0], shaderBuffer, 3, vs, log);
shaderBuffer[2] = _renderTile256;
_compileBackground(glRenderer, glRenderer->bgProgram[1], shaderBuffer, 3, vs, log);
_compileShader(glRenderer, glRenderer->bgProgram[1], shaderBuffer, 3, vs, log);
shaderBuffer[1] = _renderMode2;
shaderBuffer[2] = _fetchTileOverflow;
_compileBackground(glRenderer, glRenderer->bgProgram[2], shaderBuffer, 3, vs, log);
_compileShader(glRenderer, glRenderer->bgProgram[2], shaderBuffer, 3, vs, log);
shaderBuffer[2] = _fetchTileNoOverflow;
_compileBackground(glRenderer, glRenderer->bgProgram[3], shaderBuffer, 3, vs, log);
_compileShader(glRenderer, glRenderer->bgProgram[3], shaderBuffer, 3, vs, log);
shaderBuffer[1] = _renderObjNoTransform;
shaderBuffer[2] = _renderTile16;
_compileShader(glRenderer, glRenderer->objProgram[0], shaderBuffer, 3, vs, log);
shaderBuffer[1] = _composite;
_compileBackground(glRenderer, glRenderer->compositeProgram, shaderBuffer, 2, vs, log);
_compileShader(glRenderer, glRenderer->compositeProgram, shaderBuffer, 2, vs, log);
glBindFragDataLocation(glRenderer->compositeProgram, 0, "color");
glBindFragDataLocation(glRenderer->compositeProgram, 1, "flags");
@ -369,6 +416,19 @@ void GBAVideoGLRendererDeinit(struct GBAVideoRenderer* renderer) {
glDeleteTextures(1, &glRenderer->paletteTex);
glDeleteTextures(1, &glRenderer->vramTex);
glDeleteTextures(1, &glRenderer->oamTex);
glDeleteProgram(glRenderer->bgProgram[0]);
glDeleteProgram(glRenderer->bgProgram[1]);
glDeleteProgram(glRenderer->bgProgram[2]);
glDeleteProgram(glRenderer->bgProgram[3]);
glDeleteProgram(glRenderer->bgProgram[4]);
glDeleteProgram(glRenderer->bgProgram[5]);
glDeleteProgram(glRenderer->bgProgram[6]);
glDeleteProgram(glRenderer->objProgram[0]);
glDeleteProgram(glRenderer->objProgram[1]);
glDeleteProgram(glRenderer->objProgram[2]);
glDeleteProgram(glRenderer->objProgram[3]);
glDeleteProgram(glRenderer->compositeProgram);
}
void GBAVideoGLRendererReset(struct GBAVideoRenderer* renderer) {
@ -610,11 +670,6 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1, 16, 32, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, glRenderer->d.palette);
glRenderer->paletteDirty = false;
}
if (glRenderer->oamDirty) {
glBindTexture(GL_TEXTURE_2D, glRenderer->oamTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R16UI, 4, 128, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, glRenderer->d.oam);
glRenderer->oamDirty = false;
}
int i;
for (i = 0; i < 24; ++i) {
if (!(glRenderer->vramDirty & (1 << i))) {
@ -628,16 +683,25 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
uint32_t backdrop = M_RGB5_TO_RGB8(renderer->palette[0]);
glClearColor(((backdrop >> 16) & 0xFF) / 256., ((backdrop >> 8) & 0xFF) / 256., (backdrop & 0xFF) / 256., 0.f);
glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[1]);
glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_COMPOSITE]);
glEnable(GL_SCISSOR_TEST);
glScissor(0, y * glRenderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, glRenderer->scale);
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_SCISSOR_TEST);
if (y == 0) {
glDrawBuffer(GL_COLOR_ATTACHMENT1);
glClearColor(1, (glRenderer->target1Bd | (glRenderer->target2Bd * 2)) / 4.f, 0, 1);
glClearColor(1, (glRenderer->target1Bd | (glRenderer->target2Bd * 2)) / 8.f, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glClearColor(0, 0, 0, 0);
glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_OBJ]);
glClear(GL_COLOR_BUFFER_BIT);
for (i = 0; i < 4; ++i) {
glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->bg[i].fbo);
glClear(GL_COLOR_BUFFER_BIT);
}
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
@ -658,6 +722,27 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
glRenderer->firstAffine = -1;
}
glEnable(GL_SCISSOR_TEST);
int spriteLayers = 0;
if (GBARegisterDISPCNTIsObjEnable(glRenderer->dispcnt) && !glRenderer->d.disableOBJ) {
if (glRenderer->oamDirty) {
glBindTexture(GL_TEXTURE_2D, glRenderer->oamTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R16UI, 4, 128, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, glRenderer->d.oam);
glRenderer->oamMax = GBAVideoRendererCleanOAM(glRenderer->d.oam->obj, glRenderer->sprites, 0);
glRenderer->oamDirty = false;
}
int i;
for (i = glRenderer->oamMax; i--;) {
struct GBAVideoRendererSprite* sprite = &glRenderer->sprites[i];
if ((y < sprite->y && (sprite->endY - 256 < 0 || y >= sprite->endY - 256)) || y >= sprite->endY) {
continue;
}
GBAVideoGLRendererDrawSprite(glRenderer, &sprite->obj, y, sprite->y);
spriteLayers |= 1 << GBAObjAttributesCGetPriority(sprite->obj.c);
}
}
unsigned priority;
for (priority = 4; priority--;) {
if (TEST_LAYER_ENABLED(0) && GBARegisterDISPCNTGetMode(glRenderer->dispcnt) < 2) {
@ -697,6 +782,7 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
}
}
}
_compositeLayer(glRenderer, glRenderer->layers[GBA_GL_TEX_OBJ_COLOR], y, 0, 0);
if (GBARegisterDISPCNTGetMode(glRenderer->dispcnt) != 0) {
memcpy(&glRenderer->bg[2].affine[3], &glRenderer->bg[2].affine[2], sizeof(struct GBAVideoGLAffine));
@ -804,34 +890,72 @@ static void GBAVideoGLRendererWriteBLDCNT(struct GBAVideoGLRenderer* renderer, u
renderer->target2Bd = GBARegisterBLDCNTGetTarget2Bd(value);
}
static void _compositeLayer(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y, int flags) {
static void _compositeLayer(struct GBAVideoGLRenderer* renderer, GLuint tex, int y, int priority, int flags) {
if ((y & 0x1F) != 0x1F) {
return;
}
glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[1]);
glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_COMPOSITE]);
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);
glScissor(0, (y & ~0x1F) * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, 0x20 * renderer->scale);
glUseProgram(renderer->compositeProgram);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, background->tex);
glBindTexture(GL_TEXTURE_2D, tex);
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_2D, renderer->outputTex);
glActiveTexture(GL_TEXTURE0 + 2);
glBindTexture(GL_TEXTURE_2D, renderer->layers[2]);
glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_COMPOSITE_FLAGS]);
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);
glUniform2i(1, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS);
glUniform3i(2, priority, flags, renderer->blendEffect);
glUniform1i(3, renderer->scale);
glUniform3f(4, renderer->blda / 16.f, renderer->bldb / 16.f, renderer->bldy / 16.f);
glUniform1i(5, 0);
glUniform1i(6, 1);
glUniform1i(7, 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);
glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GBAObj* sprite, int y, int spriteY) {
int width = GBAVideoObjSizes[GBAObjAttributesAGetShape(sprite->a) * 4 + GBAObjAttributesBGetSize(sprite->b)][0];
int height = GBAVideoObjSizes[GBAObjAttributesAGetShape(sprite->a) * 4 + GBAObjAttributesBGetSize(sprite->b)][1];
int32_t x = (uint32_t) GBAObjAttributesBGetX(sprite->b) << 23;
x >>= 23;
int align = GBAObjAttributesAIs256Color(sprite->a) && !GBARegisterDISPCNTIsObjCharacterMapping(renderer->dispcnt);
unsigned charBase = (BASE_TILE >> 1) + (GBAObjAttributesCGetTile(sprite->c) & ~align) * 0x10;
int stride = GBARegisterDISPCNTIsObjCharacterMapping(renderer->dispcnt) ? (width >> 3) : (0x10 >> !GBAObjAttributesAIs256Color(sprite->a));
if (spriteY + height >= 256) {
spriteY -= 256;
}
glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_OBJ]);
glViewport(x * renderer->scale, spriteY * renderer->scale, width * renderer->scale, height * renderer->scale);
glScissor(x * renderer->scale, y * renderer->scale, width * renderer->scale, renderer->scale);
glUseProgram(renderer->objProgram[0]);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, renderer->vramTex);
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_2D, renderer->paletteTex);
glUniform2i(0, 1, y - spriteY);
glUniform2i(1, GBAObjAttributesBIsHFlip(sprite->b) ? -width : width, height);
glUniform1i(2, 0);
glUniform1i(3, 1);
glUniform1i(4, charBase);
glUniform1i(5, stride);
glUniform1i(6, GBAObjAttributesCGetPalette(sprite->c));
glUniform3i(7, GBAObjAttributesCGetPriority(sprite->c) << 3, 0, 0);
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);
glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });}
void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {
int inY = y + background->y;
int yBase = inY & 0xFF;
@ -849,19 +973,18 @@ void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer,
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_2D, renderer->paletteTex);
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->x, yBase - y);
glUniform2i(1, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS);
glUniform1i(2, 0);
glUniform1i(3, 1);
glUniform1i(4, background->screenBase);
glUniform1i(5, background->charBase);
glUniform1i(6, background->size);
glUniform2i(7, background->x, yBase - y);
glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices);
glEnableVertexAttribArray(0);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
_compositeLayer(renderer, background, y, background->target1 | (background->target2 * 2));
glBindFramebuffer(GL_FRAMEBUFFER, 0);
_compositeLayer(renderer, background->tex, y, (background->priority << 3) + (background->index << 1) + 1, background->target1 | (background->target2 * 2));
}
void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {
@ -874,32 +997,33 @@ void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer,
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_2D, renderer->paletteTex);
glUniform2i(0, 1, y);
glUniform1i(1, 0);
glUniform1i(2, 1);
glUniform1i(3, background->screenBase);
glUniform1i(4, background->charBase);
glUniform1i(5, background->size);
glUniform2i(1, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS);
glUniform1i(2, 0);
glUniform1i(3, 1);
glUniform1i(4, background->screenBase);
glUniform1i(5, background->charBase);
glUniform1i(6, background->size);
if (renderer->scale > 1) {
glUniform2iv(6, 4, (GLint[]) {
glUniform2iv(7, 4, (GLint[]) {
background->affine[0].sx, background->affine[0].sy,
background->affine[1].sx, background->affine[1].sy,
background->affine[2].sx, background->affine[2].sy,
background->affine[3].sx, background->affine[3].sy,
});
glUniform2iv(10, 4, (GLint[]) {
glUniform2iv(11, 4, (GLint[]) {
background->affine[0].dx, background->affine[0].dy,
background->affine[1].dx, background->affine[1].dy,
background->affine[2].dx, background->affine[2].dy,
background->affine[3].dx, background->affine[3].dy,
});
} else {
glUniform2iv(6, 4, (GLint[]) {
glUniform2iv(7, 4, (GLint[]) {
background->affine[0].sx, background->affine[0].sy,
background->affine[0].sx, background->affine[0].sy,
background->affine[0].sx, background->affine[0].sy,
background->affine[0].sx, background->affine[0].sy,
});
glUniform2iv(10, 4, (GLint[]) {
glUniform2iv(11, 4, (GLint[]) {
background->affine[0].dx, background->affine[0].dy,
background->affine[0].dx, background->affine[0].dy,
background->affine[0].dx, background->affine[0].dy,
@ -910,7 +1034,5 @@ void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer,
glEnableVertexAttribArray(0);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
_compositeLayer(renderer, background, y, background->target1 | (background->target2 * 2));
glBindFramebuffer(GL_FRAMEBUFFER, 0);
_compositeLayer(renderer, background->tex, y, (background->priority << 3) + (background->index << 1) + 1, background->target1 | (background->target2 * 2));
}

View File

@ -36,7 +36,6 @@ static void GBAVideoSoftwareRendererWriteBGY_LO(struct GBAVideoSoftwareBackgroun
static void GBAVideoSoftwareRendererWriteBGY_HI(struct GBAVideoSoftwareBackground* bg, uint16_t value);
static void GBAVideoSoftwareRendererWriteBLDCNT(struct GBAVideoSoftwareRenderer* renderer, uint16_t value);
static void _cleanOAM(struct GBAVideoSoftwareRenderer* renderer);
static void _drawScanline(struct GBAVideoSoftwareRenderer* renderer, int y);
static void _updatePalettes(struct GBAVideoSoftwareRenderer* renderer);
@ -498,32 +497,6 @@ static void _breakWindowInner(struct GBAVideoSoftwareRenderer* softwareRenderer,
#endif
}
static void _cleanOAM(struct GBAVideoSoftwareRenderer* renderer) {
int i;
int oamMax = 0;
for (i = 0; i < 128; ++i) {
struct GBAObj obj;
LOAD_16(obj.a, 0, &renderer->d.oam->obj[i].a);
LOAD_16(obj.b, 0, &renderer->d.oam->obj[i].b);
LOAD_16(obj.c, 0, &renderer->d.oam->obj[i].c);
if (GBAObjAttributesAIsTransformed(obj.a) || !GBAObjAttributesAIsDisable(obj.a)) {
int height = GBAVideoObjSizes[GBAObjAttributesAGetShape(obj.a) * 4 + GBAObjAttributesBGetSize(obj.b)][1];
if (GBAObjAttributesAIsTransformed(obj.a)) {
height <<= GBAObjAttributesAGetDoubleSize(obj.a);
}
if (GBAObjAttributesAGetY(obj.a) < GBA_VIDEO_VERTICAL_PIXELS || GBAObjAttributesAGetY(obj.a) + height >= VIDEO_VERTICAL_TOTAL_PIXELS) {
int y = GBAObjAttributesAGetY(obj.a) + renderer->objOffsetY;
renderer->sprites[oamMax].y = y;
renderer->sprites[oamMax].endY = y + height;
renderer->sprites[oamMax].obj = obj;
++oamMax;
}
}
}
renderer->oamMax = oamMax;
renderer->oamDirty = 0;
}
static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer;
@ -821,14 +794,15 @@ static void _drawScanline(struct GBAVideoSoftwareRenderer* renderer, int y) {
int spriteLayers = 0;
if (GBARegisterDISPCNTIsObjEnable(renderer->dispcnt) && !renderer->d.disableOBJ) {
if (renderer->oamDirty) {
_cleanOAM(renderer);
renderer->oamMax = GBAVideoRendererCleanOAM(renderer->d.oam->obj, renderer->sprites, renderer->objOffsetY);
renderer->oamDirty = false;
}
renderer->spriteCyclesRemaining = GBARegisterDISPCNTIsHblankIntervalFree(renderer->dispcnt) ? OBJ_HBLANK_FREE_LENGTH : OBJ_LENGTH;
int mosaicV = GBAMosaicControlGetObjV(renderer->mosaic) + 1;
int mosaicY = y - (y % mosaicV);
int i;
for (i = 0; i < renderer->oamMax; ++i) {
struct GBAVideoSoftwareSprite* sprite = &renderer->sprites[i];
struct GBAVideoRendererSprite* sprite = &renderer->sprites[i];
int localY = y;
renderer->end = 0;
if (GBAObjAttributesAIsMosaic(sprite->obj.a)) {