This commit is contained in:
twinaphex 2015-07-31 22:37:02 +02:00
commit 89aece49ce
35 changed files with 656 additions and 109 deletions

View File

@ -27,7 +27,7 @@ Features:
- Undo-able savestate loading and saving
- Controller profiles now store shortcut settings
- Default controller profiles for several common controllers
- Libretro now supports BIOS and rumble
- Libretro now supports BIOS, rumble and solar sensor
- Implement BIOS call Stop, for sleep mode
Bugfixes:
- ARM7: Fix SWI and IRQ timings
@ -64,6 +64,7 @@ Bugfixes:
- Qt: Fix a missing va_end call in the log handler lambda within the GameController constructor
- GBA Cheats: Fix Pro Action Replay and GameShark issues when used together
- Qt: Fix analog buttons not getting unmapped
- GBA Video: Prevent tiles < 512 from being used in modes 3 - 5
Misc:
- Qt: Handle saving input settings better
- Debugger: Free watchpoints in addition to breakpoints

View File

@ -21,6 +21,7 @@ set(BUILD_PERF OFF CACHE BOOL "Build performance profiling tool")
set(BUILD_STATIC OFF CACHE BOOL "Build a static library")
set(BUILD_SHARED ON CACHE BOOL "Build a shared library")
set(BUILD_GL ON CACHE STRING "Build with OpenGL")
set(BUILD_GLES2 OFF CACHE STRING "Build with OpenGL|ES 2")
file(GLOB ARM_SRC ${CMAKE_SOURCE_DIR}/src/arm/*.c)
file(GLOB GBA_SRC ${CMAKE_SOURCE_DIR}/src/gba/*.c)
file(GLOB GBA_CHEATS_SRC ${CMAKE_SOURCE_DIR}/src/gba/cheats/*.c)
@ -125,7 +126,14 @@ endif()
if(BUILD_GL)
find_package(OpenGL QUIET)
if(NOT OPENGL_FOUND)
set(BUILD_GL OFF)
set(BUILD_GL OFF CACHE BOOL "OpenGL not found" FORCE)
endif()
endif()
if(BUILD_GLES2 AND NOT BUILD_RASPI)
find_path(OPENGLES2_INCLUDE_DIR NAMES GLES2/gl2.h)
find_library(OPENGLES2_LIBRARY NAMES GLESv2 GLESv2_CM)
if(NOT OPENGLES2_INCLUDE_DIR OR NOT OPENGLES2_LIBRARY)
set(BUILD_GLES2 OFF CACHE BOOL "OpenGL|ES 2 not found" FORCE)
endif()
endif()
find_feature(USE_FFMPEG "libavcodec;libavformat;libavresample;libavutil;libswscale")
@ -176,6 +184,10 @@ if(BUILD_BBB OR BUILD_RASPI OR BUILD_PANDORA)
endif()
endif()
if(BUILD_RASPI)
set(BUILD_GL OFF CACHE BOOL "OpenGL not supported" FORCE)
endif()
if(BUILD_PANDORA)
add_definitions(-DBUILD_PANDORA)
endif()
@ -366,6 +378,7 @@ endif()
if(BUILD_SHARED)
add_library(${BINARY_NAME} SHARED ${SRC})
set_target_properties(${BINARY_NAME} PROPERTIES SOVERSION ${LIB_VERSION_ABI})
if(BUILD_STATIC)
add_library(${BINARY_NAME}-static STATIC ${SRC})
set_target_properties(${BINARY_NAME}-static PROPERTIES COMPILE_DEFINITIONS "${FEATURE_DEFINES}")
@ -379,7 +392,7 @@ endif()
add_dependencies(${BINARY_NAME} version-info)
target_link_libraries(${BINARY_NAME} ${DEBUGGER_LIB} ${DEPENDENCY_LIB} ${OS_LIB})
install(TARGETS ${BINARY_NAME} DESTINATION ${LIBDIR} COMPONENT lib${BINARY_NAME})
install(TARGETS ${BINARY_NAME} LIBRARY DESTINATION ${LIBDIR} COMPONENT lib${BINARY_NAME} NAMELINK_SKIP ARCHIVE DESTINATION ${LIBDIR} RUNTIME DESTINATION ${LIBDIR} COMPONENT lib${BINARY_NAME})
if(UNIX AND NOT APPLE)
install(FILES ${CMAKE_SOURCE_DIR}/res/mgba-16.png DESTINATION share/icons/hicolor/16x16/apps RENAME mgba.png COMPONENT lib${BINARY_NAME})
install(FILES ${CMAKE_SOURCE_DIR}/res/mgba-24.png DESTINATION share/icons/hicolor/24x24/apps RENAME mgba.png COMPONENT lib${BINARY_NAME})
@ -397,6 +410,10 @@ if(BUILD_GL)
add_definitions(-DBUILD_GL)
endif()
if(BUILD_GLES2)
add_definitions(-DBUILD_GLES2)
endif()
if(BUILD_LIBRETRO)
file(GLOB RETRO_SRC ${CMAKE_SOURCE_DIR}/src/platform/libretro/*.c)
add_library(${BINARY_NAME}_libretro SHARED ${CORE_SRC} ${RETRO_SRC})

View File

@ -126,8 +126,6 @@ Footnotes
- OBJ window for modes 3, 4 and 5 ([Bug #5](http://mgba.io/b/5))
- Mosaic for transformed OBJs ([Bug #9](http://mgba.io/b/9))
- BIOS call RegisterRamReset is partially stubbed out ([Bug #141](http://mgba.io/b/141))
- Game Pak prefetch ([Bug #195](http://mgba.io/b/195))
- BIOS call Stop, for entering sleep mode ([Bug #199](http://mgba.io/b/199))
<a name="flashdetect">[2]</a> Flash memory size detection does not work in some cases. These can be configured at runtime, but filing a bug is recommended if such a case is encountered.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 525 KiB

After

Width:  |  Height:  |  Size: 518 KiB

View File

@ -56,6 +56,8 @@ static struct CLIDebuggerCommandSummary _debuggerCommands[] = {
{ "b/a", _setBreakpointARM, CLIDVParse, "Set a software breakpoint as ARM" },
{ "b/t", _setBreakpointThumb, CLIDVParse, "Set a software breakpoint as Thumb" },
{ "break", _setBreakpoint, CLIDVParse, "Set a breakpoint" },
{ "break/a", _setBreakpointARM, CLIDVParse, "Set a software breakpoint as ARM" },
{ "break/t", _setBreakpointThumb, CLIDVParse, "Set a software breakpoint as Thumb" },
{ "c", _continue, 0, "Continue execution" },
{ "continue", _continue, 0, "Continue execution" },
{ "d", _clearBreakpoint, CLIDVParse, "Delete a breakpoint" },

View File

@ -9,6 +9,8 @@
#include "gba/serialize.h"
#include "util/hash.h"
const int GBA_LUX_LEVELS[10] = { 5, 11, 18, 27, 42, 62, 84, 109, 139, 183 };
static void _readPins(struct GBACartridgeHardware* hw);
static void _outputPins(struct GBACartridgeHardware* hw, unsigned pins);

View File

@ -79,6 +79,8 @@ struct GBARotationSource {
int32_t (*readGyroZ)(struct GBARotationSource*);
};
extern const int GBA_LUX_LEVELS[10];
struct GBALuminanceSource {
void (*sample)(struct GBALuminanceSource*);

View File

@ -634,8 +634,12 @@ uint32_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
#define STORE_VRAM \
if ((address & 0x0001FFFF) < SIZE_VRAM) { \
STORE_32(value, address & 0x0001FFFC, gba->video.renderer->vram); \
gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x0001FFFC) + 2); \
gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x0001FFFC)); \
} else { \
STORE_32(value, address & 0x00017FFC, gba->video.renderer->vram); \
gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x00017FFC) + 2); \
gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x00017FFC)); \
} \
wait += waitstatesRegion[REGION_VRAM];
@ -728,8 +732,10 @@ void GBAStore16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycle
case REGION_VRAM:
if ((address & 0x0001FFFF) < SIZE_VRAM) {
STORE_16(value, address & 0x0001FFFE, gba->video.renderer->vram);
gba->video.renderer->writeVRAM(gba->video.renderer, address & 0x0001FFFE);
} else {
STORE_16(value, address & 0x00017FFE, gba->video.renderer->vram);
gba->video.renderer->writeVRAM(gba->video.renderer, address & 0x00017FFE);
}
break;
case REGION_OAM:
@ -794,8 +800,8 @@ void GBAStore8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCo
GBALog(gba, GBA_LOG_GAME_ERROR, "Cannot Store8 to OBJ: 0x%08X", address);
break;
}
((int8_t*) gba->video.renderer->vram)[address & 0x1FFFE] = value;
((int8_t*) gba->video.renderer->vram)[(address & 0x1FFFE) | 1] = value;
gba->video.renderer->vram[(address & 0x1FFFE) >> 1] = ((uint8_t) value) | (value << 8);
gba->video.renderer->writeVRAM(gba->video.renderer, address & 0x0001FFFE);
break;
case REGION_OAM:
GBALog(gba, GBA_LOG_GAME_ERROR, "Cannot Store8 to OAM: 0x%08X", address);

View File

@ -116,6 +116,9 @@ int GBAVideoSoftwareRendererPreprocessSprite(struct GBAVideoSoftwareRenderer* re
x >>= 23;
uint16_t* vramBase = &renderer->d.vram[BASE_TILE >> 1];
unsigned charBase = GBAObjAttributesCGetTile(sprite->c) * 0x20;
if (GBARegisterDISPCNTGetMode(renderer->dispcnt) >= 3 && GBAObjAttributesCGetTile(sprite->c) < 512) {
return 0;
}
int variant = renderer->target1Obj && GBAWindowControlIsBlendEnable(renderer->currentWindow.packed) && (renderer->blendEffect == BLEND_BRIGHTEN || renderer->blendEffect == BLEND_DARKEN);
if (GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT) {
int target2 = renderer->target2Bd << 4;

View File

@ -13,6 +13,7 @@
static void GBAVideoSoftwareRendererInit(struct GBAVideoRenderer* renderer);
static void GBAVideoSoftwareRendererDeinit(struct GBAVideoRenderer* renderer);
static void GBAVideoSoftwareRendererReset(struct GBAVideoRenderer* renderer);
static void GBAVideoSoftwareRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address);
static void GBAVideoSoftwareRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam);
static void GBAVideoSoftwareRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
static uint16_t GBAVideoSoftwareRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
@ -46,6 +47,7 @@ void GBAVideoSoftwareRendererCreate(struct GBAVideoSoftwareRenderer* renderer) {
renderer->d.reset = GBAVideoSoftwareRendererReset;
renderer->d.deinit = GBAVideoSoftwareRendererDeinit;
renderer->d.writeVideoRegister = GBAVideoSoftwareRendererWriteVideoRegister;
renderer->d.writeVRAM = GBAVideoSoftwareRendererWriteVRAM;
renderer->d.writeOAM = GBAVideoSoftwareRendererWriteOAM;
renderer->d.writePalette = GBAVideoSoftwareRendererWritePalette;
renderer->d.drawScanline = GBAVideoSoftwareRendererDrawScanline;
@ -327,6 +329,11 @@ static uint16_t GBAVideoSoftwareRendererWriteVideoRegister(struct GBAVideoRender
return value;
}
static void GBAVideoSoftwareRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address) {
UNUSED(renderer);
UNUSED(address);
}
static void GBAVideoSoftwareRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam) {
struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer;
softwareRenderer->oamDirty = 1;

View File

@ -17,6 +17,7 @@ static void GBAVideoDummyRendererInit(struct GBAVideoRenderer* renderer);
static void GBAVideoDummyRendererReset(struct GBAVideoRenderer* renderer);
static void GBAVideoDummyRendererDeinit(struct GBAVideoRenderer* renderer);
static uint16_t GBAVideoDummyRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
static void GBAVideoDummyRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address);
static void GBAVideoDummyRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
static void GBAVideoDummyRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam);
static void GBAVideoDummyRendererDrawScanline(struct GBAVideoRenderer* renderer, int y);
@ -47,6 +48,7 @@ static struct GBAVideoRenderer dummyRenderer = {
.reset = GBAVideoDummyRendererReset,
.deinit = GBAVideoDummyRendererDeinit,
.writeVideoRegister = GBAVideoDummyRendererWriteVideoRegister,
.writeVRAM = GBAVideoDummyRendererWriteVRAM,
.writePalette = GBAVideoDummyRendererWritePalette,
.writeOAM = GBAVideoDummyRendererWriteOAM,
.drawScanline = GBAVideoDummyRendererDrawScanline,
@ -222,6 +224,12 @@ static uint16_t GBAVideoDummyRendererWriteVideoRegister(struct GBAVideoRenderer*
return value;
}
static void GBAVideoDummyRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address) {
UNUSED(renderer);
UNUSED(address);
// Nothing to do
}
static void GBAVideoDummyRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
UNUSED(renderer);
UNUSED(address);

View File

@ -161,6 +161,7 @@ struct GBAVideoRenderer {
void (*deinit)(struct GBAVideoRenderer* renderer);
uint16_t (*writeVideoRegister)(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
void (*writeVRAM)(struct GBAVideoRenderer* renderer, uint32_t address);
void (*writePalette)(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
void (*writeOAM)(struct GBAVideoRenderer* renderer, uint32_t oam);
void (*drawScanline)(struct GBAVideoRenderer* renderer, int y);

View File

@ -8,6 +8,7 @@
#include "util/common.h"
#include "gba/gba.h"
#include "gba/interface.h"
#include "gba/renderers/video-software.h"
#include "gba/serialize.h"
#include "gba/supervisor/overrides.h"
@ -18,6 +19,8 @@
#define SAMPLES 1024
#define RUMBLE_PWM 35
#define SOLAR_SENSOR_LEVEL "mgba_solar_sensor_level"
static retro_environment_t environCallback;
static retro_video_refresh_t videoCallback;
static retro_audio_sample_batch_t audioCallback;
@ -31,6 +34,8 @@ static void GBARetroLog(struct GBAThread* thread, enum GBALogLevel level, const
static void _postAudioBuffer(struct GBAAVStream*, struct GBAAudio* audio);
static void _postVideoFrame(struct GBAAVStream*, struct GBAVideoRenderer* renderer);
static void _setRumble(struct GBARumble* rumble, int enable);
static uint8_t _readLux(struct GBALuminanceSource* lux);
static void _updateLux(struct GBALuminanceSource* lux);
static struct GBA gba;
static struct ARMCore cpu;
@ -44,6 +49,8 @@ static struct GBAAVStream stream;
static int rumbleLevel;
static struct CircleBuffer rumbleHistory;
static struct GBARumble rumble;
static struct GBALuminanceSource lux;
static int luxLevel;
unsigned retro_api_version(void) {
return RETRO_API_VERSION;
@ -51,6 +58,13 @@ unsigned retro_api_version(void) {
void retro_set_environment(retro_environment_t env) {
environCallback = env;
struct retro_variable vars[] = {
{ SOLAR_SENSOR_LEVEL, "Solar sensor level; 0|1|2|3|4|5|6|7|8|9|10" },
{ 0, 0 }
};
environCallback(RETRO_ENVIRONMENT_SET_VARIABLES, vars);
}
void retro_set_video_refresh(retro_video_refresh_t video) {
@ -119,7 +133,9 @@ void retro_init(void) {
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "Up" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "Down" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L" }
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3, "Brighten Solar Sensor" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3, "Darken Solar Sensor" }
};
environCallback(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, &inputDescriptors);
@ -134,6 +150,11 @@ void retro_init(void) {
rumbleCallback = 0;
}
luxLevel = 0;
lux.readLuminance = _readLux;
lux.sample = _updateLux;
_updateLux(&lux);
struct retro_log_callback log;
if (environCallback(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log)) {
logCallback = log.log;
@ -155,6 +176,7 @@ void retro_init(void) {
if (rumbleCallback) {
gba.rumble = &rumble;
}
gba.luminanceSource = &lux;
rom = 0;
const char* sysDir = 0;
@ -205,6 +227,26 @@ void retro_run(void) {
keys |= (!!inputCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R)) << 8;
keys |= (!!inputCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L)) << 9;
static bool wasAdjustingLux = false;
if (wasAdjustingLux) {
wasAdjustingLux = inputCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3) ||
inputCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3);
} else {
if (inputCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3)) {
++luxLevel;
if (luxLevel > 10) {
luxLevel = 10;
}
wasAdjustingLux = true;
} else if (inputCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3)) {
--luxLevel;
if (luxLevel < 0) {
luxLevel = 0;
}
wasAdjustingLux = true;
}
}
int frameCount = gba.video.frameCounter;
while (gba.video.frameCounter == frameCount) {
ARMRunLoop(&cpu);
@ -405,3 +447,40 @@ static void _setRumble(struct GBARumble* rumble, int enable) {
CircleBufferWrite8(&rumbleHistory, enable);
rumbleCallback(0, RETRO_RUMBLE_STRONG, rumbleLevel * 0xFFFF / RUMBLE_PWM);
}
static void _updateLux(struct GBALuminanceSource* lux) {
UNUSED(lux);
struct retro_variable var = {
.key = SOLAR_SENSOR_LEVEL,
.value = 0
};
bool updated = false;
if (!environCallback(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) || !updated) {
return;
}
if (!environCallback(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || !var.value) {
return;
}
char* end;
int newLuxLevel = strtol(var.value, &end, 10);
if (!*end) {
if (newLuxLevel > 10) {
luxLevel = 10;
} else if (newLuxLevel < 0) {
luxLevel = 0;
} else {
luxLevel = newLuxLevel;
}
}
}
static uint8_t _readLux(struct GBALuminanceSource* lux) {
UNUSED(lux);
int value = 0x16;
if (luxLevel > 0) {
value += GBA_LUX_LEVELS[luxLevel - 1];
}
return 0xFF - value;
}

136
src/platform/opengl/gles2.c Normal file
View File

@ -0,0 +1,136 @@
/* Copyright (c) 2013-2015 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 "gles2.h"
#include "gba/video.h"
static const char* const _vertexShader =
"attribute vec4 position;\n"
"varying vec2 texCoord;\n"
"void main() {\n"
" gl_Position = position;\n"
" texCoord = (position.st + vec2(1.0, -1.0)) * vec2(0.46875, -0.3125);\n"
"}";
static const char* const _fragmentShader =
"varying vec2 texCoord;\n"
"uniform sampler2D tex;\n"
"void main() {\n"
" vec4 color = texture2D(tex, texCoord);\n"
" color.a = 1.;\n"
" gl_FragColor = color;"
"}";
static const GLfloat _vertices[] = {
-1.f, -1.f,
-1.f, 1.f,
1.f, 1.f,
1.f, -1.f,
};
static void GBAGLES2ContextInit(struct VideoBackend* v, WHandle handle) {
UNUSED(handle);
struct GBAGLES2Context* context = (struct GBAGLES2Context*) v;
glGenTextures(1, &context->tex);
glBindTexture(GL_TEXTURE_2D, context->tex);
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);
#ifdef COLOR_16_BIT
#ifdef COLOR_5_6_5
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0);
#else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 0);
#endif
#else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
#endif
glShaderSource(context->fragmentShader, 1, (const GLchar**) &_fragmentShader, 0);
glShaderSource(context->vertexShader, 1, (const GLchar**) &_vertexShader, 0);
glAttachShader(context->program, context->vertexShader);
glAttachShader(context->program, context->fragmentShader);
char log[1024];
glCompileShader(context->fragmentShader);
glCompileShader(context->vertexShader);
glGetShaderInfoLog(context->fragmentShader, 1024, 0, log);
glGetShaderInfoLog(context->vertexShader, 1024, 0, log);
glLinkProgram(context->program);
glGetProgramInfoLog(context->program, 1024, 0, log);
printf("%s\n", log);
context->texLocation = glGetUniformLocation(context->program, "tex");
context->positionLocation = glGetAttribLocation(context->program, "position");
glClearColor(0.f, 0.f, 0.f, 1.f);
}
static void GBAGLES2ContextDeinit(struct VideoBackend* v) {
struct GBAGLES2Context* context = (struct GBAGLES2Context*) v;
glDeleteTextures(1, &context->tex);
}
static void GBAGLES2ContextResized(struct VideoBackend* v, int w, int h) {
int drawW = w;
int drawH = h;
if (v->lockAspectRatio) {
if (w * 2 > h * 3) {
drawW = h * 3 / 2;
} else if (w * 2 < h * 3) {
drawH = w * 2 / 3;
}
}
glViewport(0, 0, 240, 160);
glClearColor(0.f, 0.f, 0.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT);
glViewport((w - drawW) / 2, (h - drawH) / 2, drawW, drawH);
}
static void GBAGLES2ContextClear(struct VideoBackend* v) {
UNUSED(v);
glClearColor(0.f, 0.f, 0.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT);
}
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);
glVertexAttribPointer(context->positionLocation, 2, GL_FLOAT, GL_FALSE, 0, _vertices);
glEnableVertexAttribArray(context->positionLocation);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glUseProgram(0);
}
void GBAGLES2ContextPostFrame(struct VideoBackend* v, const void* frame) {
struct GBAGLES2Context* context = (struct GBAGLES2Context*) v;
glBindTexture(GL_TEXTURE_2D, context->tex);
#ifdef COLOR_16_BIT
#ifdef COLOR_5_6_5
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, frame);
#else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, frame);
#endif
#else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, frame);
#endif
}
void GBAGLES2ContextCreate(struct GBAGLES2Context* context) {
context->d.init = GBAGLES2ContextInit;
context->d.deinit = GBAGLES2ContextDeinit;
context->d.resized = GBAGLES2ContextResized;
context->d.swap = 0;
context->d.clear = GBAGLES2ContextClear;
context->d.postFrame = GBAGLES2ContextPostFrame;
context->d.drawFrame = GBAGLES2ContextDrawFrame;
context->d.setMessage = 0;
context->d.clearMessage = 0;
}

View File

@ -0,0 +1,27 @@
/* Copyright (c) 2013-2015 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 GLES2_H
#define GLES2_H
#include <GLES2/gl2.h>
#include "platform/video-backend.h"
struct GBAGLES2Context {
struct VideoBackend d;
GLuint tex;
GLuint fragmentShader;
GLuint vertexShader;
GLuint program;
GLuint bufferObject;
GLuint texLocation;
GLuint positionLocation;
};
void GBAGLES2ContextCreate(struct GBAGLES2Context*);
#endif

View File

@ -186,7 +186,7 @@ static void _GBAPerfRunloop(struct GBAThread* context, int* frames, bool quiet)
}
}
GBASyncWaitFrameEnd(&context->sync);
if (*frames == duration) {
if (duration > 0 && *frames == duration) {
_GBAPerfShutdown(0);
}
if (_dispatchExiting) {

View File

@ -10,7 +10,7 @@
#include <pthread.h>
#include <sys/time.h>
#ifdef __FreeBSD__
#if defined(__FreeBSD__) || defined(__OpenBSD__)
#include <pthread_np.h>
#endif
@ -79,7 +79,7 @@ static inline int ThreadJoin(Thread thread) {
static inline int ThreadSetName(const char* name) {
#ifdef __APPLE__
return pthread_setname_np(name);
#elif defined(__FreeBSD__)
#elif defined(__FreeBSD__) || defined(__OpenBSD__)
pthread_set_name_np(pthread_self(), name);
return 0;
#else

View File

@ -0,0 +1,36 @@
/* Copyright (c) 2013-2015 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 "AboutScreen.h"
#include "util/version.h"
#include <QPixmap>
using namespace QGBA;
AboutScreen::AboutScreen(QWidget* parent)
: QDialog(parent)
{
m_ui.setupUi(this);
QPixmap logo(":/res/mgba-1024.png");
logo = logo.scaled(m_ui.logo->minimumSize() * devicePixelRatio(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
logo.setDevicePixelRatio(devicePixelRatio());
m_ui.logo->setPixmap(logo);
m_ui.projectName->setText(QLatin1String(projectName));
m_ui.projectVersion->setText(QLatin1String(projectVersion));
QString gitInfo = m_ui.gitInfo->text();
gitInfo.replace("{gitBranch}", QLatin1String(gitBranch));
gitInfo.replace("{gitCommit}", QLatin1String(gitCommit));
m_ui.gitInfo->setText(gitInfo);
QString description = m_ui.description->text();
description.replace("{projectName}", QLatin1String(projectName));
m_ui.description->setText(description);
QString extraLinks = m_ui.extraLinks->text();
extraLinks.replace("{gitBranch}", QLatin1String(gitBranch));
m_ui.extraLinks->setText(extraLinks);
}

View File

@ -0,0 +1,27 @@
/* Copyright (c) 2013-2014 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 QGBA_ABOUT_SCREEN
#define QGBA_ABOUT_SCREEN
#include <QDialog>
#include "ui_AboutScreen.h"
namespace QGBA {
class AboutScreen : public QDialog {
Q_OBJECT
public:
AboutScreen(QWidget* parent = nullptr);
private:
Ui::AboutScreen m_ui;
};
}
#endif

View File

@ -0,0 +1,177 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AboutScreen</class>
<widget class="QWidget" name="AboutScreen">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>565</width>
<height>268</height>
</rect>
</property>
<property name="windowTitle">
<string>About</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<property name="sizeConstraint">
<enum>QLayout::SetFixedSize</enum>
</property>
<item row="0" column="1">
<widget class="QLabel" name="projectName">
<property name="font">
<font>
<pointsize>36</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>{projectName}</string>
</property>
<property name="alignment">
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
</property>
</widget>
</item>
<item row="6" column="0" colspan="4">
<widget class="QLabel" name="copyright">
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>© 2013 2015 Jeffrey Pfau — Game Boy Advance is a registered trademark of Nintendo Co., Ltd.</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="projectVersion">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>{projectVersion}</string>
</property>
<property name="alignment">
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="0" column="0" rowspan="6">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>8</number>
</property>
<property name="rightMargin">
<number>16</number>
</property>
<property name="bottomMargin">
<number>12</number>
</property>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="logo">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>256</width>
<height>192</height>
</size>
</property>
<property name="text">
<string>{logo}</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="3" column="1">
<widget class="QLabel" name="description">
<property name="text">
<string>{projectName} is an open-source Game Boy Advance emulator</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="extraLinks">
<property name="text">
<string>&lt;a href=&quot;http://mgba.io/&quot;&gt;Website&lt;/a&gt; • &lt;a href=&quot;https://forumsmgba.io/&quot;&gt;Forums / Support&lt;/a&gt; • &lt;a href=&quot;https://github.com/mgba-emu/mgba/tree/{gitBranch}&quot;&gt;Source&lt;/a&gt; • &lt;a href=&quot;https://github.com/mgba-emu/mgba/blob/{gitBranch}/LICENSE&quot;&gt;License&lt;/a&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="gitInfo">
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>Branch: &lt;tt&gt;{gitBranch}&lt;/tt&gt;&lt;br/&gt;Revision: &lt;tt&gt;{gitCommit}&lt;/tt&gt;</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -28,7 +28,9 @@ endif()
set(CMAKE_AUTOMOC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
find_package(Qt5Multimedia)
if(NOT WIN32 OR NOT BUILD_SDL)
find_package(Qt5Multimedia)
endif()
find_package(Qt5OpenGL)
find_package(Qt5Widgets)
@ -38,7 +40,13 @@ if(NOT Qt5OpenGL_FOUND OR NOT Qt5Widgets_FOUND OR NOT OPENGL_FOUND)
return()
endif()
if(BUILD_GL)
list(APPEND PLATFORM_SRC ${PLATFORM_SRC} ${CMAKE_SOURCE_DIR}/src/platform/opengl/gl.c)
endif()
if(BUILD_GLES2)
list(APPEND PLATFORM_SRC ${PLATFORM_SRC} ${CMAKE_SOURCE_DIR}/src/platform/opengl/gles2.c)
endif()
get_target_property(QT_TYPE Qt5::Core TYPE)
if(QT_TYPE STREQUAL STATIC_LIBRARY)
@ -47,6 +55,7 @@ if(QT_TYPE STREQUAL STATIC_LIBRARY)
endif()
set(SOURCE_FILES
AboutScreen.cpp
AudioProcessor.cpp
CheatsModel.cpp
CheatsView.cpp
@ -83,6 +92,7 @@ set(SOURCE_FILES
VideoView.cpp)
qt5_wrap_ui(UI_FILES
AboutScreen.ui
CheatsView.ui
GIFView.ui
LoadSaveState.ui

View File

@ -135,7 +135,11 @@ PainterGL::PainterGL(QGLWidget* parent)
, m_context(nullptr)
, m_messagePainter(nullptr)
{
#ifdef BUILD_GL
GBAGLContextCreate(&m_backend);
#elif defined(BUILD_GLES2)
GBAGLES2ContextCreate(&m_backend);
#endif
m_backend.d.swap = [](VideoBackend* v) {
PainterGL* painter = static_cast<PainterGL*>(v->user);
painter->m_gl->swapBuffers();

View File

@ -14,7 +14,11 @@
#include <QTimer>
extern "C" {
#ifdef BUILD_GL
#include "platform/opengl/gl.h"
#elif defined(BUILD_GLES2)
#include "platform/opengl/gles2.h"
#endif
}
struct GBAThread;
@ -90,7 +94,11 @@ private:
QGLWidget* m_gl;
bool m_active;
GBAThread* m_context;
#ifdef BUILD_GL
GBAGLContext m_backend;
#elif defined(BUILD_GLES2)
GBAGLES2Context m_backend;
#endif
QSize m_size;
MessagePainter* m_messagePainter;
};

View File

@ -29,8 +29,6 @@ extern "C" {
using namespace QGBA;
using namespace std;
const int GameController::LUX_LEVELS[10] = { 5, 11, 18, 27, 42, 62, 84, 109, 139, 183 };
GameController::GameController(QObject* parent)
: QObject(parent)
, m_drawContext(new uint32_t[256 * 256])
@ -794,7 +792,7 @@ void GameController::setLuminanceValue(uint8_t value) {
value = std::max<int>(value - 0x16, 0);
m_luxLevel = 10;
for (int i = 0; i < 10; ++i) {
if (value < LUX_LEVELS[i]) {
if (value < GBA_LUX_LEVELS[i]) {
m_luxLevel = i;
break;
}
@ -806,7 +804,7 @@ void GameController::setLuminanceLevel(int level) {
int value = 0x16;
level = std::max(0, std::min(10, level));
if (level > 0) {
value += LUX_LEVELS[level - 1];
value += GBA_LUX_LEVELS[level - 1];
}
setLuminanceValue(value);
}

View File

@ -207,8 +207,6 @@ private:
uint8_t m_luxValue;
int m_luxLevel;
static const int LUX_LEVELS[10];
GBARTCGenericSource m_rtc;
};

View File

@ -208,9 +208,11 @@ void InputController::setPreferredGamepad(uint32_t type, const QString& device)
GBARumble* InputController::rumble() {
#ifdef BUILD_SDL
#if SDL_VERSION_ATLEAST(2, 0, 0)
if (m_playerAttached) {
return &m_sdlPlayer.rumble.d;
}
#endif
#endif
return nullptr;
}
@ -497,19 +499,29 @@ bool InputController::hasPendingEvent(GBAKey key) const {
return m_pendingEvents.contains(key);
}
#if defined(BUILD_SDL) && SDL_VERSION_ATLEAST(2, 0, 0)
void InputController::suspendScreensaver() {
#ifdef BUILD_SDL
#if SDL_VERSION_ATLEAST(2, 0, 0)
GBASDLSuspendScreensaver(&s_sdlEvents);
#endif
#endif
}
void InputController::resumeScreensaver() {
#ifdef BUILD_SDL
#if SDL_VERSION_ATLEAST(2, 0, 0)
GBASDLResumeScreensaver(&s_sdlEvents);
#endif
#endif
}
void InputController::setScreensaverSuspendable(bool suspendable) {
#ifdef BUILD_SDL
#if SDL_VERSION_ATLEAST(2, 0, 0)
GBASDLSetScreensaverSuspendable(&s_sdlEvents, suspendable);
}
#endif
#endif
}
void InputController::stealFocus(QWidget* focus) {
m_focusParent = focus;

View File

@ -87,12 +87,10 @@ signals:
public slots:
void testGamepad(int type);
#if defined(BUILD_SDL) && SDL_VERSION_ATLEAST(2, 0, 0)
// TODO: Move these to somewhere that makes sense
void suspendScreensaver();
void resumeScreensaver();
void setScreensaverSuspendable(bool);
#endif
private:
void postPendingEvent(GBAKey);

View File

@ -13,6 +13,7 @@
#include <QPainter>
#include <QStackedLayout>
#include "AboutScreen.h"
#include "CheatsView.h"
#include "ConfigController.h"
#include "Display.h"
@ -40,8 +41,8 @@ extern "C" {
using namespace QGBA;
#ifdef __WIN32
// This is a macro everywhere except MinGW, it seems
#if defined(__WIN32) || defined(__OpenBSD__)
// This is a macro everywhere except MinGW and OpenBSD, it seems
using std::isnan;
#endif
@ -344,6 +345,11 @@ void Window::openMemoryWindow() {
openView(memoryWindow);
}
void Window::openAboutScreen() {
AboutScreen* about = new AboutScreen();
openView(about);
}
#ifdef BUILD_SDL
void Window::openGamepadWindow() {
const char* profile = m_inputController.profileForType(SDL_BINDING_BUTTON);
@ -752,6 +758,14 @@ void Window::setupMenu(QMenuBar* menubar) {
});
addControlledAction(fileMenu, multiWindow, "multiWindow");
#ifndef Q_OS_MAC
fileMenu->addSeparator();
#endif
QAction* about = new QAction(tr("About"), fileMenu);
connect(about, SIGNAL(triggered()), this, SLOT(openAboutScreen()));
fileMenu->addAction(about);
#ifndef Q_OS_MAC
addControlledAction(fileMenu, fileMenu->addAction(tr("E&xit"), this, SLOT(close()), QKeySequence::Quit), "quit");
#endif
@ -1214,11 +1228,11 @@ void WindowBackground::paintEvent(QPaintEvent*) {
painter.setRenderHint(QPainter::SmoothPixmapTransform);
painter.fillRect(QRect(QPoint(), size()), Qt::black);
QSize s = size();
QSize ds = s;
if (s.width() * m_aspectHeight > s.height() * m_aspectWidth) {
ds.setWidth(s.height() * m_aspectWidth / m_aspectHeight);
} else if (s.width() * m_aspectHeight < s.height() * m_aspectWidth) {
ds.setHeight(s.width() * m_aspectHeight / m_aspectWidth);
QSize ds = s * 0.8;
if (ds.width() * m_aspectHeight > ds.height() * m_aspectWidth) {
ds.setWidth(ds.height() * m_aspectWidth / m_aspectHeight);
} else if (ds.width() * m_aspectHeight < ds.height() * m_aspectWidth) {
ds.setHeight(ds.width() * m_aspectHeight / m_aspectWidth);
}
QPoint origin = QPoint((s.width() - ds.width()) / 2, (s.height() - ds.height()) / 2);
QRect full(origin, ds);

View File

@ -82,6 +82,8 @@ public slots:
void openPaletteWindow();
void openMemoryWindow();
void openAboutScreen();
#ifdef BUILD_SDL
void openGamepadWindow();
#endif

View File

@ -10,9 +10,11 @@
#include <QtPlugin>
#ifdef _WIN32
Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
#ifdef BUILD_QT_MULTIMEDIA
Q_IMPORT_PLUGIN(QWindowsAudioPlugin);
#endif
#endif
#endif
int main(int argc, char* argv[]) {
QGBA::GBAApp application(argc, argv);

View File

@ -51,12 +51,14 @@ set(MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/main.c)
if(BUILD_RASPI)
add_definitions(-DBUILD_RASPI)
set(EGL_MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/egl-sdl.c)
set(EGL_LIBRARY "-lEGL -lGLESv2 -lbcm_host")
list(APPEND PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/opengl/gles2.c)
list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/egl-sdl.c)
set(OPENGLES2_LIBRARY "-lEGL -lGLESv2 -lbcm_host")
set(BUILD_GLES2 ON CACHE BOOL "Using OpenGL|ES 2" FORCE)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fgnu89-inline")
add_executable(${BINARY_NAME}-rpi ${PLATFORM_SRC} ${MAIN_SRC} ${EGL_MAIN_SRC})
add_executable(${BINARY_NAME}-rpi ${PLATFORM_SRC} ${MAIN_SRC})
set_target_properties(${BINARY_NAME}-rpi PROPERTIES COMPILE_DEFINITIONS "${FEATURE_DEFINES}")
target_link_libraries(${BINARY_NAME}-rpi ${BINARY_NAME} ${PLATFORM_LIBRARY} ${EGL_LIBRARY})
target_link_libraries(${BINARY_NAME}-rpi ${BINARY_NAME} ${PLATFORM_LIBRARY} ${OPENGLES2_LIBRARY})
install(TARGETS ${BINARY_NAME}-rpi DESTINATION bin COMPONENT ${BINARY_NAME}-rpi)
endif()
@ -67,12 +69,12 @@ else()
if(BUILD_GL)
list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/gl-sdl.c)
list(APPEND PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/opengl/gl.c)
include_directories(${OPENGL_INCLUDE_DIR})
include_directories(${OPENGL_INCLUDE_DIR} ${OPENGLES2_INCLUDE_DIR})
endif()
endif()
add_executable(${BINARY_NAME}-sdl WIN32 ${PLATFORM_SRC} ${MAIN_SRC})
set_target_properties(${BINARY_NAME}-sdl PROPERTIES COMPILE_DEFINITIONS "${FEATURE_DEFINES}")
target_link_libraries(${BINARY_NAME}-sdl ${BINARY_NAME} ${PLATFORM_LIBRARY} ${OPENGL_LIBRARY})
target_link_libraries(${BINARY_NAME}-sdl ${BINARY_NAME} ${PLATFORM_LIBRARY} ${OPENGL_LIBRARY} ${OPENGLES2_LIBRARY})
set_target_properties(${BINARY_NAME}-sdl PROPERTIES OUTPUT_NAME ${BINARY_NAME})
install(TARGETS ${BINARY_NAME}-sdl DESTINATION bin COMPONENT ${BINARY_NAME}-sdl)

View File

@ -1,37 +1,26 @@
/* Copyright (c) 2013-2014 Jeffrey Pfau
/* Copyright (c) 2013-2015 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 "main.h"
static const char* _vertexShader =
"attribute vec4 position;\n"
"varying vec2 texCoord;\n"
static void _sdlSwap(struct VideoBackend* context) {
UNUSED(context);
SDL_GL_SwapBuffers();
}
"void main() {\n"
" gl_Position = position;\n"
" texCoord = (position.st + vec2(1.0, -1.0)) * vec2(0.46875, -0.3125);\n"
"}";
static bool GBASDLGLES2Init(struct SDLSoftwareRenderer* renderer);
static void GBASDLGLES2Runloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer);
static void GBASDLGLES2Deinit(struct SDLSoftwareRenderer* renderer);
static const char* _fragmentShader =
"varying vec2 texCoord;\n"
"uniform sampler2D tex;\n"
void GBASDLGLES2Create(struct SDLSoftwareRenderer* renderer) {
renderer->init = GBASDLGLES2Init;
renderer->deinit = GBASDLGLES2Deinit;
renderer->runloop = GBASDLGLES2Runloop;
}
"void main() {\n"
" vec4 color = texture2D(tex, texCoord);\n"
" color.a = 1.;\n"
" gl_FragColor = color;"
"}";
static const GLfloat _vertices[] = {
-1.f, -1.f,
-1.f, 1.f,
1.f, 1.f,
1.f, -1.f,
};
bool GBASDLInit(struct SDLSoftwareRenderer* renderer) {
bool GBASDLGLES2Init(struct SDLSoftwareRenderer* renderer) {
bcm_host_init();
renderer->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
int major, minor;
@ -103,36 +92,19 @@ bool GBASDLInit(struct SDLSoftwareRenderer* renderer) {
renderer->d.outputBuffer = memalign(16, 256 * 256 * 4);
renderer->d.outputBufferStride = 256;
glGenTextures(1, &renderer->tex);
glBindTexture(GL_TEXTURE_2D, renderer->tex);
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, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
renderer->fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
renderer->vertexShader = glCreateShader(GL_VERTEX_SHADER);
renderer->program = glCreateProgram();
glShaderSource(renderer->fragmentShader, 1, (const GLchar**) &_fragmentShader, 0);
glShaderSource(renderer->vertexShader, 1, (const GLchar**) &_vertexShader, 0);
glAttachShader(renderer->program, renderer->vertexShader);
glAttachShader(renderer->program, renderer->fragmentShader);
char log[1024];
glCompileShader(renderer->fragmentShader);
glCompileShader(renderer->vertexShader);
glGetShaderInfoLog(renderer->fragmentShader, 1024, 0, log);
glGetShaderInfoLog(renderer->vertexShader, 1024, 0, log);
glLinkProgram(renderer->program);
glGetProgramInfoLog(renderer->program, 1024, 0, log);
printf("%s\n", log);
renderer->texLocation = glGetUniformLocation(renderer->program, "tex");
renderer->positionLocation = glGetAttribLocation(renderer->program, "position");
glClearColor(1.f, 0.f, 0.f, 1.f);
GBAGLES2ContextCreate(&renderer->gl);
renderer->gl.d.user = renderer;
renderer->gl.d.lockAspectRatio = renderer->lockAspectRatio;
renderer->gl.d.filter = renderer->filter;
renderer->gl.d.swap = _sdlSwap;
renderer->gl.d.init(&renderer->gl.d, 0);
return true;
}
void GBASDLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer) {
void GBASDLGLES2Runloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer) {
SDL_Event event;
struct VideoBackend* v = &renderer->gl.d;
while (context->state < THREAD_EXITING) {
while (SDL_PollEvent(&event)) {
@ -140,27 +112,22 @@ void GBASDLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* render
}
if (GBASyncWaitFrameStart(&context->sync, context->frameskip)) {
glViewport(0, 0, 240, 160);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(renderer->program);
glUniform1i(renderer->texLocation, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, renderer->tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, renderer->d.outputBuffer);
glVertexAttribPointer(renderer->positionLocation, 2, GL_FLOAT, GL_FALSE, 0, _vertices);
glEnableVertexAttribArray(renderer->positionLocation);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glUseProgram(0);
eglSwapBuffers(renderer->display, renderer->surface);
v->postFrame(v, renderer->d.outputBuffer);
}
v->drawFrame(v);
GBASyncWaitFrameEnd(&context->sync);
eglSwapBuffers(renderer->display, renderer->surface);
}
}
void GBASDLDeinit(struct SDLSoftwareRenderer* renderer) {
void GBASDLGLES2Deinit(struct SDLSoftwareRenderer* renderer) {
if (renderer->gl.d.deinit) {
renderer->gl.d.deinit(&renderer->gl.d);
}
eglMakeCurrent(renderer->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroySurface(renderer->display, renderer->surface);
eglDestroyContext(renderer->display, renderer->context);
eglTerminate(renderer->display);
free(renderer->d.outputBuffer);
bcm_host_deinit();
}

View File

@ -86,6 +86,8 @@ int main(int argc, char** argv) {
#ifdef BUILD_GL
GBASDLGLCreate(&renderer);
#elif defined(BUILD_GLES2)
GBASDLGLES2Create(&renderer);
#else
GBASDLSWCreate(&renderer);
#endif

View File

@ -20,13 +20,16 @@
#pragma GCC diagnostic ignored "-Wunused-function"
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#include <SDL/SDL.h>
#include <GLES2/gl2.h>
#include <EGL/egl.h>
#include <bcm_host.h>
#pragma GCC diagnostic pop
#endif
#ifdef BUILD_GLES2
#include "platform/opengl/gles2.h"
#endif
#ifdef USE_PIXMAN
#include <pixman.h>
#endif
@ -69,13 +72,7 @@ struct SDLSoftwareRenderer {
EGLSurface surface;
EGLContext context;
EGL_DISPMANX_WINDOW_T window;
GLuint tex;
GLuint fragmentShader;
GLuint vertexShader;
GLuint program;
GLuint bufferObject;
GLuint texLocation;
GLuint positionLocation;
struct GBAGLES2Context gl;
#endif
#ifdef BUILD_PANDORA
@ -90,4 +87,8 @@ void GBASDLSWCreate(struct SDLSoftwareRenderer* renderer);
#ifdef BUILD_GL
void GBASDLGLCreate(struct SDLSoftwareRenderer* renderer);
#endif
#ifdef BUILD_GLES2
void GBASDLGLES2Create(struct SDLSoftwareRenderer* renderer);
#endif
#endif

View File

@ -56,8 +56,8 @@ while [ $# -gt 0 ]; do
sed -i~ "s/,$//g" deb-temp/DEBIAN/control
sed -i~ "/^[^:]*: $/d" deb-temp/DEBIAN/control
rm deb-temp/DEBIAN/control~
chown -R 0:0 deb-temp
chmod 600 deb-temp/DEBIAN/md5sums
chmod 644 deb-temp/DEBIAN/md5sums
chown -R root:root deb-temp
dpkg-deb -b deb-temp $DEB
rm -rf deb-temp
shift