From 751acd16371f670348b121bf5550deb7b810110f Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 18 Sep 2018 13:55:52 -0700 Subject: [PATCH 01/50] FFmpeg: Fix encoding audio/video queue issues --- CHANGES | 1 + src/feature/ffmpeg/ffmpeg-encoder.c | 10 ++++++---- src/feature/ffmpeg/ffmpeg-encoder.h | 1 - 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index 995724252..e0f784b9a 100644 --- a/CHANGES +++ b/CHANGES @@ -55,6 +55,7 @@ Bugfixes: - GBA Memory: Fix Vast Fame support (taizou) (fixes mgba.io/i/1170) - GB, GBA Savedata: Fix unmasking savedata crash - GBA DMA: Fix temporal sorting of DMAs of different priorities + - FFmpeg: Fix encoding audio/video queue issues Misc: - GBA Timer: Use global cycles for timers - GBA: Extend oddly-sized ROMs to full address space (fixes mgba.io/i/722) diff --git a/src/feature/ffmpeg/ffmpeg-encoder.c b/src/feature/ffmpeg/ffmpeg-encoder.c index 2e53479d6..acf21dd8c 100644 --- a/src/feature/ffmpeg/ffmpeg-encoder.c +++ b/src/feature/ffmpeg/ffmpeg-encoder.c @@ -205,7 +205,6 @@ bool FFmpegEncoderOpen(struct FFmpegEncoder* encoder, const char* outfile) { encoder->currentAudioSample = 0; encoder->currentAudioFrame = 0; encoder->currentVideoFrame = 0; - encoder->nextAudioPts = 0; AVOutputFormat* oformat = av_guess_format(encoder->containerFormat, 0, 0); #ifndef USE_LIBAV @@ -301,6 +300,7 @@ bool FFmpegEncoderOpen(struct FFmpegEncoder* encoder, const char* outfile) { encoder->video->width = encoder->width; encoder->video->height = encoder->height; encoder->video->time_base = (AVRational) { VIDEO_TOTAL_LENGTH, GBA_ARM7TDMI_FREQUENCY }; + encoder->video->framerate = (AVRational) { GBA_ARM7TDMI_FREQUENCY, VIDEO_TOTAL_LENGTH }; encoder->video->pix_fmt = encoder->pixFormat; encoder->video->gop_size = 60; encoder->video->max_b_frames = 3; @@ -457,14 +457,13 @@ void _ffmpegPostAudioFrame(struct mAVStream* stream, int16_t left, int16_t right (const uint8_t**) &encoder->audioBuffer, encoder->audioBufferSize / 4); #endif - encoder->audioFrame->pts = av_rescale_q(encoder->currentAudioFrame, encoder->audio->time_base, encoder->audioStream->time_base); + encoder->audioFrame->pts = encoder->currentAudioFrame; encoder->currentAudioFrame += samples; AVPacket packet; av_init_packet(&packet); packet.data = 0; packet.size = 0; - packet.pts = encoder->audioFrame->pts; int gotData; #ifdef FFMPEG_USE_PACKETS @@ -474,6 +473,9 @@ void _ffmpegPostAudioFrame(struct mAVStream* stream, int16_t left, int16_t right #else avcodec_encode_audio2(encoder->audio, &packet, encoder->audioFrame, &gotData); #endif + packet.pts = av_rescale_q(encoder->audioFrame->pts, encoder->audio->time_base, encoder->audioStream->time_base); + packet.dts = packet.pts; + if (gotData) { if (encoder->absf) { AVPacket tempPacket; @@ -532,7 +534,6 @@ void _ffmpegPostVideoFrame(struct mAVStream* stream, const color_t* pixels, size av_frame_make_writable(encoder->videoFrame); #endif encoder->videoFrame->pts = av_rescale_q(encoder->currentVideoFrame, encoder->video->time_base, encoder->videoStream->time_base); - packet.pts = encoder->videoFrame->pts; ++encoder->currentVideoFrame; sws_scale(encoder->scaleContext, (const uint8_t* const*) &pixels, (const int*) &stride, 0, encoder->iheight, encoder->videoFrame->data, encoder->videoFrame->linesize); @@ -544,6 +545,7 @@ void _ffmpegPostVideoFrame(struct mAVStream* stream, const color_t* pixels, size #else avcodec_encode_video2(encoder->video, &packet, encoder->videoFrame, &gotData); #endif + packet.pts = encoder->videoFrame->pts; if (gotData) { #ifndef FFMPEG_USE_PACKET_UNREF if (encoder->video->coded_frame->key_frame) { diff --git a/src/feature/ffmpeg/ffmpeg-encoder.h b/src/feature/ffmpeg/ffmpeg-encoder.h index f8c5add36..a5215b8a5 100644 --- a/src/feature/ffmpeg/ffmpeg-encoder.h +++ b/src/feature/ffmpeg/ffmpeg-encoder.h @@ -56,7 +56,6 @@ struct FFmpegEncoder { AVFrame* audioFrame; size_t currentAudioSample; int64_t currentAudioFrame; - int64_t nextAudioPts; // TODO (0.6): Remove #ifdef USE_LIBAVRESAMPLE struct AVAudioResampleContext* resampleContext; #else From 1aa256a7ee731a75e3f5e8d7c5d94b7dbe519063 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 18 Sep 2018 13:59:13 -0700 Subject: [PATCH 02/50] Qt: Fix lossless video encoding --- src/platform/qt/VideoView.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/platform/qt/VideoView.cpp b/src/platform/qt/VideoView.cpp index bc6563f01..b7fceae81 100644 --- a/src/platform/qt/VideoView.cpp +++ b/src/platform/qt/VideoView.cpp @@ -101,7 +101,7 @@ VideoView::VideoView(QWidget* parent) .container = "MKV", .vcodec = "h.264", .acodec = "FLAC", - .vbr = 0, + .vbr = -1, .abr = 0, .dims = QSize(), }); @@ -181,7 +181,7 @@ void VideoView::updatePresets() { .container = "MKV", .vcodec = "h.264", .acodec = "FLAC", - .vbr = 0, + .vbr = -1, .abr = 0, .dims = QSize(m_nativeWidth, m_nativeHeight) }); @@ -311,7 +311,7 @@ void VideoView::setAudioBitrate(int br, bool manual) { } void VideoView::setVideoBitrate(int br, bool manual) { - m_vbr = br * 1000; + m_vbr = br >= 0 ? br * 1000 : 0; FFmpegEncoderSetVideo(&m_encoder, m_videoCodecCstr, m_vbr); validateSettings(); if (manual) { From bf87a1db48ef4bef657708966370a62e4b96759e Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 18 Sep 2018 14:12:22 -0700 Subject: [PATCH 03/50] Qt: Upgrade WebM codecs --- src/platform/qt/VideoView.cpp | 4 ++-- src/platform/qt/VideoView.ui | 19 ++++++++++++------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/platform/qt/VideoView.cpp b/src/platform/qt/VideoView.cpp index b7fceae81..75ae3fb01 100644 --- a/src/platform/qt/VideoView.cpp +++ b/src/platform/qt/VideoView.cpp @@ -170,8 +170,8 @@ void VideoView::updatePresets() { addPreset(m_ui.presetWebM, { .container = "WebM", - .vcodec = "VP8", - .acodec = "Vorbis", + .vcodec = "VP9", + .acodec = "Opus", .vbr = 800, .abr = 128 }); diff --git a/src/platform/qt/VideoView.ui b/src/platform/qt/VideoView.ui index eb42fd4f5..1e9dfe367 100644 --- a/src/platform/qt/VideoView.ui +++ b/src/platform/qt/VideoView.ui @@ -106,7 +106,7 @@ - High Quality + High &Quality presets @@ -116,7 +116,7 @@ - YouTube + &YouTube presets @@ -136,7 +136,7 @@ - Lossless + &Lossless true @@ -153,7 +153,7 @@ - 1080p + &1080p resolutions @@ -163,7 +163,7 @@ - 720p + &720p resolutions @@ -173,7 +173,7 @@ - 480p + &480p resolutions @@ -186,7 +186,7 @@ false - Native + &Native true @@ -274,6 +274,11 @@ VP8 + + + VP9 + + FFV1 From 3e75dae3dce0fdae8e7ea0edc73ddd20a5e0e7d4 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 18 Sep 2018 14:24:22 -0700 Subject: [PATCH 04/50] FFmpeg: Support lossless VP9 encoding --- CHANGES | 1 + src/feature/ffmpeg/ffmpeg-encoder.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/CHANGES b/CHANGES index e0f784b9a..57090240b 100644 --- a/CHANGES +++ b/CHANGES @@ -89,6 +89,7 @@ Misc: - Wii: Move audio handling to callbacks (fixes mgba.io/i/803) - Qt: Clean up FPS target UI (fixes mgba.io/i/436) - Core: Remove broken option for whether rewinding restores save games + - FFmpeg: Support lossless VP9 encoding 0.6.3: (2017-04-14) Bugfixes: diff --git a/src/feature/ffmpeg/ffmpeg-encoder.c b/src/feature/ffmpeg/ffmpeg-encoder.c index acf21dd8c..c1c6439b4 100644 --- a/src/feature/ffmpeg/ffmpeg-encoder.c +++ b/src/feature/ffmpeg/ffmpeg-encoder.c @@ -334,6 +334,10 @@ bool FFmpegEncoderOpen(struct FFmpegEncoder* encoder, const char* outfile) { encoder->video->pix_fmt = AV_PIX_FMT_YUV444P; } } + if (strcmp(vcodec->name, "libvpx-vp9") == 0 && encoder->videoBitrate == 0) { + av_opt_set(encoder->video->priv_data, "lossless", "1", 0); + encoder->video->pix_fmt = AV_PIX_FMT_YUV444P; + } avcodec_open2(encoder->video, vcodec, 0); #if LIBAVCODEC_VERSION_MAJOR >= 55 From 65473a97f9606b51e7be0d81ef073d71235c0460 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 18 Sep 2018 18:51:37 -0700 Subject: [PATCH 05/50] GB Video: Frame event cleanup --- include/mgba/internal/gb/gb.h | 1 + src/gb/gb.c | 28 +++++++++++++++++++++++++++- src/gb/video.c | 24 +----------------------- 3 files changed, 29 insertions(+), 24 deletions(-) diff --git a/include/mgba/internal/gb/gb.h b/include/mgba/internal/gb/gb.h index d0e5df0d9..47c3a03df 100644 --- a/include/mgba/internal/gb/gb.h +++ b/include/mgba/internal/gb/gb.h @@ -177,6 +177,7 @@ void GBGetGameCode(const struct GB* gba, char* out); void GBTestKeypadIRQ(struct GB* gb); +void GBFrameStarted(struct GB* gb); void GBFrameEnded(struct GB* gb); CXX_GUARD_END diff --git a/src/gb/gb.c b/src/gb/gb.c index 4775f072c..29b12df2d 100644 --- a/src/gb/gb.c +++ b/src/gb/gb.c @@ -816,6 +816,18 @@ void GBGetGameCode(const struct GB* gb, char* out) { } } +void GBFrameStarted(struct GB* gb) { + GBTestKeypadIRQ(gb); + + size_t c; + for (c = 0; c < mCoreCallbacksListSize(&gb->coreCallbacks); ++c) { + struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&gb->coreCallbacks, c); + if (callbacks->videoFrameStarted) { + callbacks->videoFrameStarted(callbacks->context); + } + } +} + void GBFrameEnded(struct GB* gb) { GBSramClean(gb, gb->video.frameCounter); @@ -828,7 +840,21 @@ void GBFrameEnded(struct GB* gb) { } } - GBTestKeypadIRQ(gb); + // TODO: Move to common code + if (gb->stream && gb->stream->postVideoFrame) { + const color_t* pixels; + size_t stride; + gb->video.renderer->getPixels(gb->video.renderer, &stride, (const void**) &pixels); + gb->stream->postVideoFrame(gb->stream, pixels, stride); + } + + size_t c; + for (c = 0; c < mCoreCallbacksListSize(&gb->coreCallbacks); ++c) { + struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&gb->coreCallbacks, c); + if (callbacks->videoFrameEnded) { + callbacks->videoFrameEnded(callbacks->context); + } + } } enum GBModel GBNameToModel(const char* model) { diff --git a/src/gb/video.c b/src/gb/video.c index 5ab37d1af..f90536ae0 100644 --- a/src/gb/video.c +++ b/src/gb/video.c @@ -337,14 +337,6 @@ void _updateFrameCount(struct mTiming* timing, void* context, uint32_t cyclesLat return; } - size_t c; - for (c = 0; c < mCoreCallbacksListSize(&video->p->coreCallbacks); ++c) { - struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&video->p->coreCallbacks, c); - if (callbacks->videoFrameEnded) { - callbacks->videoFrameEnded(callbacks->context); - } - } - GBFrameEnded(video->p); mCoreSyncPostFrame(video->p->sync); --video->frameskipCounter; @@ -354,24 +346,10 @@ void _updateFrameCount(struct mTiming* timing, void* context, uint32_t cyclesLat } ++video->frameCounter; - // TODO: Move to common code - if (video->p->stream && video->p->stream->postVideoFrame) { - const color_t* pixels; - size_t stride; - video->renderer->getPixels(video->renderer, &stride, (const void**) &pixels); - video->p->stream->postVideoFrame(video->p->stream, pixels, stride); - } - if (!GBRegisterLCDCIsEnable(video->p->memory.io[REG_LCDC])) { mTimingSchedule(timing, &video->frameEvent, GB_VIDEO_TOTAL_LENGTH); } - - for (c = 0; c < mCoreCallbacksListSize(&video->p->coreCallbacks); ++c) { - struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&video->p->coreCallbacks, c); - if (callbacks->videoFrameStarted) { - callbacks->videoFrameStarted(callbacks->context); - } - } + GBFrameStarted(video->p); } static void _cleanOAM(struct GBVideo* video, int y) { From 76d64114794ed7370e843ba74ec069a1f28913d5 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 18 Sep 2018 20:12:42 -0700 Subject: [PATCH 06/50] GB Serialize: Fix IRQ pending/EI pending confusion --- CHANGES | 1 + include/mgba/internal/gb/serialize.h | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 57090240b..df61c3760 100644 --- a/CHANGES +++ b/CHANGES @@ -56,6 +56,7 @@ Bugfixes: - GB, GBA Savedata: Fix unmasking savedata crash - GBA DMA: Fix temporal sorting of DMAs of different priorities - FFmpeg: Fix encoding audio/video queue issues + - GB Serialize: Fix IRQ pending/EI pending confusion Misc: - GBA Timer: Use global cycles for timers - GBA: Extend oddly-sized ROMs to full address space (fixes mgba.io/i/722) diff --git a/include/mgba/internal/gb/serialize.h b/include/mgba/internal/gb/serialize.h index f4f36c640..14cfd12d4 100644 --- a/include/mgba/internal/gb/serialize.h +++ b/include/mgba/internal/gb/serialize.h @@ -47,7 +47,7 @@ mLOG_DECLARE_CATEGORY(GB_STATE); * | 0x00040 - 0x00043: Reserved (DI pending cycles) * | 0x00044 - 0x00047: Flags * | bit 0: Is condition met? - * | bit 1: Is condition IRQ pending? + * | bit 1: Is IRQ pending? * | bit 2: Double speed * | bit 3: Is EI pending? * | bits 4 - 31: Reserved @@ -232,7 +232,7 @@ DECL_BITFIELD(GBSerializedCpuFlags, uint32_t); DECL_BIT(GBSerializedCpuFlags, Condition, 0); DECL_BIT(GBSerializedCpuFlags, IrqPending, 1); DECL_BIT(GBSerializedCpuFlags, DoubleSpeed, 2); -DECL_BIT(GBSerializedCpuFlags, EiPending, 1); +DECL_BIT(GBSerializedCpuFlags, EiPending, 3); DECL_BITFIELD(GBSerializedTimerFlags, uint8_t); DECL_BIT(GBSerializedTimerFlags, IrqPending, 0); From cf61eb52a40f5258ae6afae6e4acb01650a9d5c9 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 18 Sep 2018 20:27:57 -0700 Subject: [PATCH 07/50] Switch: Fix texture colors --- src/platform/switch/gui-font.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/platform/switch/gui-font.c b/src/platform/switch/gui-font.c index 814c0c63a..42a1bfe76 100644 --- a/src/platform/switch/gui-font.c +++ b/src/platform/switch/gui-font.c @@ -243,7 +243,7 @@ void GUIFontDrawGlyph(const struct GUIFont* font, int x, int y, uint32_t color, glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glUniform1f(font->cutoffLocation, 0.7f); - glUniform4f(font->colorLocation, ((color >> 16) & 0xFF) / 255.0f, ((color >> 8) & 0xFF) / 255.0f, (color & 0xFF) / 255.0f, ((color >> 24) & 0xFF) / 255.0f); + glUniform4f(font->colorLocation, (color & 0xFF) / 255.0f, ((color >> 8) & 0xFF) / 255.0f, ((color >> 16) & 0xFF) / 255.0f, ((color >> 24) & 0xFF) / 255.0f); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDisableVertexAttribArray(font->offsetLocation); @@ -312,7 +312,7 @@ void GUIFontDrawIcon(const struct GUIFont* font, int x, int y, enum GUIAlignment glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glUniform1f(font->cutoffLocation, 0.7f); - glUniform4f(font->colorLocation, ((color >> 16) & 0xFF) / 255.0f, ((color >> 8) & 0xFF) / 255.0f, (color & 0xFF) / 255.0f, ((color >> 24) & 0xFF) / 255.0f); + glUniform4f(font->colorLocation, (color & 0xFF) / 255.0f, ((color >> 8) & 0xFF) / 255.0f, ((color >> 16) & 0xFF) / 255.0f, ((color >> 24) & 0xFF) / 255.0f); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDisableVertexAttribArray(font->offsetLocation); From 9564a1ab606ffcf28af258cafcb8f7ceff614720 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 18 Sep 2018 20:50:58 -0700 Subject: [PATCH 08/50] GB I/O: Fix PCM12/34 register numbers --- include/mgba/internal/gb/io.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/mgba/internal/gb/io.h b/include/mgba/internal/gb/io.h index 95afebe0f..15172ff0f 100644 --- a/include/mgba/internal/gb/io.h +++ b/include/mgba/internal/gb/io.h @@ -102,9 +102,9 @@ enum GBIORegisters { REG_UNK72 = 0x72, REG_UNK73 = 0x73, REG_UNK74 = 0x74, - REG_PCM12 = 0x75, - REG_PCM34 = 0x76, - REG_UNK77 = 0x77, + REG_UNK75 = 0x75, + REG_PCM12 = 0x76, + REG_PCM34 = 0x77, REG_MAX = 0x100 }; From 4b012035d83026cb86e9126dcafee9a02c9f2cd9 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 18 Sep 2018 20:51:35 -0700 Subject: [PATCH 09/50] Switch: Fixes for new mesa --- src/platform/switch/main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/platform/switch/main.c b/src/platform/switch/main.c index cc6b43111..3c8b1d999 100644 --- a/src/platform/switch/main.c +++ b/src/platform/switch/main.c @@ -105,11 +105,11 @@ static bool initEgl() { goto _fail1; } - //EGLint contextAttributeList[] = { - // EGL_CONTEXT_CLIENT_VERSION, 2, - // EGL_NONE - //}; - s_context = eglCreateContext(s_display, config, EGL_NO_CONTEXT, NULL); + EGLint contextAttributeList[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + s_context = eglCreateContext(s_display, config, EGL_NO_CONTEXT, contextAttributeList); if (!s_context) { goto _fail2; } From bb6ecd41cb8446d1df43b6d7a0cb4638091a5c7b Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 18 Sep 2018 20:51:52 -0700 Subject: [PATCH 10/50] Switch: Show charging info --- src/platform/switch/main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/platform/switch/main.c b/src/platform/switch/main.c index 3c8b1d999..0f3e2a891 100644 --- a/src/platform/switch/main.c +++ b/src/platform/switch/main.c @@ -312,6 +312,10 @@ static int _batteryState(void) { if (R_SUCCEEDED(psmGetBatteryChargePercentage(&charge))) { state = charge / 25; } + ChargerType type; + if (R_SUCCEEDED(psmGetChargerType(&type)) && type) { + state |= BATTERY_CHARGING; + } return state; } From 90c656961ebcdae682f52d916189b9672a4edbb8 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Wed, 19 Sep 2018 13:31:08 -0700 Subject: [PATCH 11/50] Switch: Update GL code to GLES 3, up frame limiter --- CMakeLists.txt | 17 +++++++++++- src/platform/switch/CMakeLists.txt | 4 +-- src/platform/switch/gui-font.c | 37 +++++++++++-------------- src/platform/switch/main.c | 43 ++++++++++++++++++------------ 4 files changed, 59 insertions(+), 42 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b6de581d..7f4d22a9d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,7 @@ set(BUILD_SHARED ON CACHE BOOL "Build a shared library") set(SKIP_LIBRARY OFF CACHE BOOL "Skip building the library (useful for only building libretro or OpenEmu cores)") set(BUILD_GL ON CACHE BOOL "Build with OpenGL") set(BUILD_GLES2 OFF CACHE BOOL "Build with OpenGL|ES 2") +set(BUILD_GLES3 OFF CACHE BOOL "Build with OpenGL|ES 3") set(USE_EPOXY ON CACHE STRING "Build with libepoxy") set(DISABLE_DEPS OFF CACHE BOOL "Build without dependencies") set(DISTBUILD OFF CACHE BOOL "Build distribution packages") @@ -296,7 +297,7 @@ if(DEFINED 3DS) endif() if(DEFINED SWITCH) - set(BUILD_GLES2 ON CACHE BOOL "Build with OpenGL|ES 2" FORCE) + set(BUILD_GLES3 ON CACHE BOOL "Build with OpenGL|ES 3" FORCE) endif() if(NOT M_CORE_GBA) @@ -438,6 +439,13 @@ endif() if(NOT BUILD_GLES2) set(OPENGLES2_LIBRARY "" CACHE PATH "" FORCE) endif() +if(BUILD_GLES3) + find_path(OPENGLES3_INCLUDE_DIR NAMES GLES3/gl3.h) + find_library(OPENGLES3_LIBRARY NAMES GLESv3 GLESv2) + if(NOT OPENGLES3_INCLUDE_DIR OR NOT OPENGLES3_LIBRARY) + set(BUILD_GLES3 OFF CACHE BOOL "OpenGL|ES 3 not found" FORCE) + endif() +endif() set(WANT_ZLIB ${USE_ZLIB}) set(WANT_PNG ${USE_PNG}) set(WANT_LIBZIP ${USE_LIBZIP}) @@ -878,6 +886,10 @@ if(BUILD_GLES2) add_definitions(-DBUILD_GLES2) endif() +if(BUILD_GLES3) + add_definitions(-DBUILD_GLES3) +endif() + if(DISABLE_FRONTENDS) set(BUILD_SDL OFF) set(BUILD_QT OFF) @@ -1096,6 +1108,9 @@ else() if(BUILD_GLES2) list(APPEND SUMMARY_GL_LIST "OpenGL|ES 2") endif() + if(BUILD_GLES3) + list(APPEND SUMMARY_GL_LIST "OpenGL|ES 3") + endif() endif() if(NOT SUMMARY_GL_LIST) set(SUMMARY_GL OFF) diff --git a/src/platform/switch/CMakeLists.txt b/src/platform/switch/CMakeLists.txt index 8b511705e..f33d6a937 100644 --- a/src/platform/switch/CMakeLists.txt +++ b/src/platform/switch/CMakeLists.txt @@ -8,7 +8,7 @@ set(OS_DEFINES USE_VFS_FILE IOAPI_NO_64) list(APPEND CORE_VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-file.c ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-dirent.c) list(APPEND GUI_SRC ${CMAKE_CURRENT_SOURCE_DIR}/gui-font.c) -include_directories(AFTER ${OPENGLES2_INCLUDE_DIR} ${OPENGL_EGL_INCLUDE_DIR}) +include_directories(AFTER ${OPENGLES3_INCLUDE_DIR} ${OPENGL_EGL_INCLUDE_DIR}) file(GLOB OS_SRC ${CMAKE_SOURCE_DIR}/src/platform/wii/wii-*.c) if(${CMAKE_BUILD_TYPE} STREQUAL Debug OR ${CMAKE_BUILD_TYPE} STREQUAL RelWithDebInfo) @@ -34,7 +34,7 @@ endif() add_executable(${BINARY_NAME}.elf ${GUI_SRC} ${PLATFORM_SRC} main.c) set_target_properties(${BINARY_NAME}.elf PROPERTIES COMPILE_DEFINITIONS "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES}") -target_link_libraries(${BINARY_NAME}.elf ${BINARY_NAME} ${M_LIBRARY} ${EGL_LIBRARY} ${OPENGLES2_LIBRARY} ${GLAPI_LIBRARY} ${NOUVEAU_LIBRARY} stdc++ ${OS_LIB}) +target_link_libraries(${BINARY_NAME}.elf ${BINARY_NAME} ${M_LIBRARY} ${EGL_LIBRARY} ${OPENGLES3_LIBRARY} ${GLAPI_LIBRARY} ${NOUVEAU_LIBRARY} stdc++ ${OS_LIB}) add_custom_command(OUTPUT control.nacp COMMAND ${NACPTOOL} --create "${PROJECT_NAME}" "endrift" "${VERSION_STRING}" control.nacp) diff --git a/src/platform/switch/gui-font.c b/src/platform/switch/gui-font.c index 42a1bfe76..af08ece63 100644 --- a/src/platform/switch/gui-font.c +++ b/src/platform/switch/gui-font.c @@ -9,7 +9,7 @@ #include #include -#include +#include #define GLYPH_HEIGHT 24 #define CELL_HEIGHT 32 @@ -58,7 +58,7 @@ struct GUIFont { GLuint font; GLuint program; GLuint vbo; - GLuint offsetLocation; + GLuint vao; GLuint texLocation; GLuint dimsLocation; GLuint transformLocation; @@ -166,12 +166,16 @@ struct GUIFont* GUIFontCreate(void) { font->originLocation = glGetUniformLocation(font->program, "origin"); font->glyphLocation = glGetUniformLocation(font->program, "glyph"); font->cutoffLocation = glGetUniformLocation(font->program, "cutoff"); - font->offsetLocation = glGetAttribLocation(font->program, "offset"); + GLuint offsetLocation = glGetAttribLocation(font->program, "offset"); glGenBuffers(1, &font->vbo); + glGenVertexArrays(1, &font->vao); + glBindVertexArray(font->vao); glBindBuffer(GL_ARRAY_BUFFER, font->vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(_offsets), _offsets, GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); + glVertexAttribPointer(offsetLocation, 2, GL_FLOAT, GL_FALSE, 0, NULL); + glEnableVertexAttribArray(offsetLocation); + glBindVertexArray(0); return font; } @@ -180,6 +184,7 @@ void GUIFontDestroy(struct GUIFont* font) { glDeleteBuffers(1, &font->vbo); glDeleteProgram(font->program); glDeleteTextures(1, &font->font); + glDeleteVertexArrays(1, &font->vao); free(font); } @@ -222,9 +227,9 @@ void GUIFontDrawGlyph(const struct GUIFont* font, int x, int y, uint32_t color, struct GUIFontGlyphMetric metric = defaultFontMetrics[glyph]; glUseProgram(font->program); + glBindVertexArray(font->vao); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, font->font); - glBindBuffer(GL_ARRAY_BUFFER, font->vbo); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -235,9 +240,6 @@ void GUIFontDrawGlyph(const struct GUIFont* font, int x, int y, uint32_t color, glUniform3f(font->originLocation, x, y - GLYPH_HEIGHT + metric.padding.top * 2, 0); glUniformMatrix2fv(font->transformLocation, 1, GL_FALSE, (float[4]) {1.0, 0.0, 0.0, 1.0}); - glVertexAttribPointer(font->offsetLocation, 2, GL_FLOAT, GL_FALSE, 0, NULL); - glEnableVertexAttribArray(font->offsetLocation); - glUniform1f(font->cutoffLocation, 0.1f); glUniform4f(font->colorLocation, 0.0, 0.0, 0.0, ((color >> 24) & 0xFF) / 128.0f); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); @@ -246,8 +248,7 @@ void GUIFontDrawGlyph(const struct GUIFont* font, int x, int y, uint32_t color, glUniform4f(font->colorLocation, (color & 0xFF) / 255.0f, ((color >> 8) & 0xFF) / 255.0f, ((color >> 16) & 0xFF) / 255.0f, ((color >> 24) & 0xFF) / 255.0f); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glDisableVertexAttribArray(font->offsetLocation); - glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); glUseProgram(0); } @@ -291,9 +292,9 @@ void GUIFontDrawIcon(const struct GUIFont* font, int x, int y, enum GUIAlignment } glUseProgram(font->program); + glBindVertexArray(font->vao); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, font->font); - glBindBuffer(GL_ARRAY_BUFFER, font->vbo); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -304,9 +305,6 @@ void GUIFontDrawIcon(const struct GUIFont* font, int x, int y, enum GUIAlignment glUniform3f(font->originLocation, x, y, 0); glUniformMatrix2fv(font->transformLocation, 1, GL_FALSE, (float[4]) {hFlip, 0.0, 0.0, vFlip}); - glVertexAttribPointer(font->offsetLocation, 2, GL_FLOAT, GL_FALSE, 0, NULL); - glEnableVertexAttribArray(font->offsetLocation); - glUniform1f(font->cutoffLocation, 0.1f); glUniform4f(font->colorLocation, 0.0, 0.0, 0.0, ((color >> 24) & 0xFF) / 128.0f); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); @@ -315,8 +313,7 @@ void GUIFontDrawIcon(const struct GUIFont* font, int x, int y, enum GUIAlignment glUniform4f(font->colorLocation, (color & 0xFF) / 255.0f, ((color >> 8) & 0xFF) / 255.0f, ((color >> 16) & 0xFF) / 255.0f, ((color >> 24) & 0xFF) / 255.0f); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glDisableVertexAttribArray(font->offsetLocation); - glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); glUseProgram(0); } @@ -334,9 +331,9 @@ void GUIFontDrawIconSize(const struct GUIFont* font, int x, int y, int w, int h, } glUseProgram(font->program); + glBindVertexArray(font->vao); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, font->font); - glBindBuffer(GL_ARRAY_BUFFER, font->vbo); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -347,9 +344,6 @@ void GUIFontDrawIconSize(const struct GUIFont* font, int x, int y, int w, int h, glUniform3f(font->originLocation, x + w / 2 - metric.width, y + h / 2 - metric.height, 0); glUniformMatrix2fv(font->transformLocation, 1, GL_FALSE, (float[4]) {w * 0.5f / metric.width, 0.0, 0.0, h * 0.5f / metric.height}); - glVertexAttribPointer(font->offsetLocation, 2, GL_FLOAT, GL_FALSE, 0, NULL); - glEnableVertexAttribArray(font->offsetLocation); - glUniform1f(font->cutoffLocation, 0.1f); glUniform4f(font->colorLocation, 0.0, 0.0, 0.0, ((color >> 24) & 0xFF) / 128.0f); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); @@ -358,7 +352,6 @@ void GUIFontDrawIconSize(const struct GUIFont* font, int x, int y, int w, int h, glUniform4f(font->colorLocation, ((color >> 16) & 0xFF) / 255.0f, ((color >> 8) & 0xFF) / 255.0f, (color & 0xFF) / 255.0f, ((color >> 24) & 0xFF) / 255.0f); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glDisableVertexAttribArray(font->offsetLocation); - glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); glUseProgram(0); } diff --git a/src/platform/switch/main.c b/src/platform/switch/main.c index 0f3e2a891..07bc4b909 100644 --- a/src/platform/switch/main.c +++ b/src/platform/switch/main.c @@ -13,12 +13,13 @@ #include #include -#include +#include #define AUTO_INPUT 0x4E585031 #define SAMPLES 0x400 #define BUFFER_SIZE 0x1000 #define N_BUFFERS 4 +#define FRAME_LIMIT 10 TimeType __nx_time_type = TimeType_UserSystemClock; @@ -63,7 +64,7 @@ static const char* const _fragmentShader = static GLuint program; static GLuint vbo; -static GLuint offsetLocation; +static GLuint vao; static GLuint texLocation; static GLuint dimsLocation; static GLuint insizeLocation; @@ -106,7 +107,7 @@ static bool initEgl() { } EGLint contextAttributeList[] = { - EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE }; s_context = eglCreateContext(s_display, config, EGL_NO_CONTEXT, contextAttributeList); @@ -144,11 +145,11 @@ static void _mapKey(struct mInputMap* map, uint32_t binding, int nativeKey, enum } static void _drawStart(void) { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glClear(GL_COLOR_BUFFER_BIT); } static void _drawEnd(void) { - if (frameLimiter || (framecount & 3) == 0) { + if (frameLimiter || (framecount % FRAME_LIMIT) == 0) { eglSwapBuffers(s_display, s_surface); } } @@ -199,12 +200,11 @@ static void _gameLoaded(struct mGUIRunner* runner) { } static void _drawTex(struct mGUIRunner* runner, unsigned width, unsigned height, bool faded) { - glBindBuffer(GL_ARRAY_BUFFER, vbo); - glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glUseProgram(program); + glBindVertexArray(vao); float aspectX = width / (float) runner->params.width; float aspectY = height / (float) runner->params.height; float max; @@ -226,26 +226,25 @@ static void _drawTex(struct mGUIRunner* runner, unsigned width, unsigned height, glUniform4f(colorLocation, 0.8f, 0.8f, 0.8f, 0.8f); } - glVertexAttribPointer(offsetLocation, 2, GL_FLOAT, GL_FALSE, 0, NULL); - glEnableVertexAttribArray(offsetLocation); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glDisableVertexAttribArray(offsetLocation); - glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); glUseProgram(0); } static void _drawFrame(struct mGUIRunner* runner, bool faded) { + ++framecount; + if (!frameLimiter && (framecount % FRAME_LIMIT) != 0) { + return; + } + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, tex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, frameBuffer); unsigned width, height; runner->core->desiredVideoDimensions(runner->core, &width, &height); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, height, GL_RGBA, GL_UNSIGNED_BYTE, frameBuffer); _drawTex(runner, width, height, faded); - - ++framecount; } static void _drawScreenshot(struct mGUIRunner* runner, const color_t* pixels, unsigned width, unsigned height, bool faded) { @@ -342,6 +341,7 @@ int main(int argc, char* argv[]) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); program = glCreateProgram(); GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); @@ -386,12 +386,16 @@ int main(int argc, char* argv[]) { colorLocation = glGetUniformLocation(program, "color"); dimsLocation = glGetUniformLocation(program, "dims"); insizeLocation = glGetUniformLocation(program, "insize"); - offsetLocation = glGetAttribLocation(program, "offset"); + GLuint offsetLocation = glGetAttribLocation(program, "offset"); glGenBuffers(1, &vbo); + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(_offsets), _offsets, GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); + glVertexAttribPointer(offsetLocation, 2, GL_FLOAT, GL_FALSE, 0, NULL); + glEnableVertexAttribArray(offsetLocation); + glBindVertexArray(0); stream.videoDimensionsChanged = NULL; stream.postVideoFrame = NULL; @@ -483,6 +487,11 @@ int main(int argc, char* argv[]) { audoutStartAudioOut(); mGUIRunloop(&runner); + glDeleteTextures(1, &tex); + glDeleteBuffers(1, &vbo); + glDeleteProgram(program); + glDeleteVertexArrays(1, &vao); + psmExit(); audoutExit(); deinitEgl(); From 35d2e0eee9a1f5be82b223b712f03a517b4ef6a4 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Wed, 19 Sep 2018 16:07:16 -0700 Subject: [PATCH 12/50] Switch: Use PBOs for texture streaming --- src/platform/switch/main.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/platform/switch/main.c b/src/platform/switch/main.c index 07bc4b909..c61707372 100644 --- a/src/platform/switch/main.c +++ b/src/platform/switch/main.c @@ -65,13 +65,14 @@ static const char* const _fragmentShader = static GLuint program; static GLuint vbo; static GLuint vao; +static GLuint pbo; static GLuint texLocation; static GLuint dimsLocation; static GLuint insizeLocation; static GLuint colorLocation; static GLuint tex; -static color_t frameBuffer[256 * 256]; +static color_t* frameBuffer; static struct mAVStream stream; static int audioBufferActive; static struct GBAStereoSample audioBuffer[N_BUFFERS][SAMPLES] __attribute__((__aligned__(0x1000))); @@ -237,14 +238,23 @@ static void _drawFrame(struct mGUIRunner* runner, bool faded) { if (!frameLimiter && (framecount % FRAME_LIMIT) != 0) { return; } + unsigned width, height; + runner->core->desiredVideoDimensions(runner->core, &width, &height); + + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo); + glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, tex); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, height, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - unsigned width, height; - runner->core->desiredVideoDimensions(runner->core, &width, &height); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, height, GL_RGBA, GL_UNSIGNED_BYTE, frameBuffer); _drawTex(runner, width, height, faded); + + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo); + frameBuffer = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, 256 * 256 * 4, GL_MAP_WRITE_BIT); + runner->core->setVideoBuffer(runner->core, frameBuffer, 256); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); } static void _drawScreenshot(struct mGUIRunner* runner, const color_t* pixels, unsigned width, unsigned height, bool faded) { @@ -343,6 +353,12 @@ int main(int argc, char* argv[]) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glGenBuffers(1, &pbo); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo); + glBufferData(GL_PIXEL_UNPACK_BUFFER, 256 * 256 * 4, NULL, GL_STREAM_DRAW); + frameBuffer = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, 256 * 256 * 4, GL_MAP_WRITE_BIT); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + program = glCreateProgram(); GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); @@ -487,6 +503,10 @@ int main(int argc, char* argv[]) { audoutStartAudioOut(); mGUIRunloop(&runner); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo); + glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); + glDeleteBuffers(1, &pbo); + glDeleteTextures(1, &tex); glDeleteBuffers(1, &vbo); glDeleteProgram(program); From d3a018c35b159d498a76df7f5dbfdc72ca811acc Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Wed, 19 Sep 2018 16:23:41 -0700 Subject: [PATCH 13/50] Switch: Configurable fast forward cap --- src/platform/switch/main.c | 45 ++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/src/platform/switch/main.c b/src/platform/switch/main.c index c61707372..da448193e 100644 --- a/src/platform/switch/main.c +++ b/src/platform/switch/main.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -19,7 +20,6 @@ #define SAMPLES 0x400 #define BUFFER_SIZE 0x1000 #define N_BUFFERS 4 -#define FRAME_LIMIT 10 TimeType __nx_time_type = TimeType_UserSystemClock; @@ -79,7 +79,8 @@ static struct GBAStereoSample audioBuffer[N_BUFFERS][SAMPLES] __attribute__((__a static AudioOutBuffer audoutBuffer[N_BUFFERS]; static int enqueuedBuffers; static bool frameLimiter = true; -static int framecount = 0; +static unsigned framecount = 0; +static unsigned framecap = 10; static bool initEgl() { s_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); @@ -150,8 +151,9 @@ static void _drawStart(void) { } static void _drawEnd(void) { - if (frameLimiter || (framecount % FRAME_LIMIT) == 0) { + if (frameLimiter || framecount >= framecap) { eglSwapBuffers(s_display, s_surface); + framecount = 0; } } @@ -198,6 +200,8 @@ static void _gameLoaded(struct mGUIRunner* runner) { double ratio = GBAAudioCalculateRatio(1, 60.0, 1); blip_set_rates(runner->core->getAudioChannel(runner->core, 0), runner->core->frequency(runner->core), samplerate * ratio); blip_set_rates(runner->core->getAudioChannel(runner->core, 1), runner->core->frequency(runner->core), samplerate * ratio); + + mCoreConfigGetUIntValue(&runner->config, "fastForwardCap", &framecap); } static void _drawTex(struct mGUIRunner* runner, unsigned width, unsigned height, bool faded) { @@ -233,11 +237,21 @@ static void _drawTex(struct mGUIRunner* runner, unsigned width, unsigned height, glUseProgram(0); } +static void _prepareForFrame(struct mGUIRunner* runner) { + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo); + frameBuffer = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, 256 * 256 * 4, GL_MAP_WRITE_BIT); + if (frameBuffer) { + runner->core->setVideoBuffer(runner->core, frameBuffer, 256); + } + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); +} + static void _drawFrame(struct mGUIRunner* runner, bool faded) { ++framecount; - if (!frameLimiter && (framecount % FRAME_LIMIT) != 0) { + if (!frameLimiter && framecount < framecap) { return; } + unsigned width, height; runner->core->desiredVideoDimensions(runner->core, &width, &height); @@ -250,11 +264,6 @@ static void _drawFrame(struct mGUIRunner* runner, bool faded) { glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); _drawTex(runner, width, height, faded); - - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo); - frameBuffer = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, 256 * 256 * 4, GL_MAP_WRITE_BIT); - runner->core->setVideoBuffer(runner->core, frameBuffer, 256); - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); } static void _drawScreenshot(struct mGUIRunner* runner, const color_t* pixels, unsigned width, unsigned height, bool faded) { @@ -475,12 +484,26 @@ int main(int argc, char* argv[]) { }, { .id = 0 } }, - .nConfigExtra = 0, + .configExtra = (struct GUIMenuItem[]) { + { + .title = "Fast forward cap", + .data = "fastForwardCap", + .submenu = 0, + .state = 7, + .validStates = (const char*[]) { + "3", "4", "5", "6", "7", "8", "9", + "10", "11", "12", "13", "14", "15", + "20", "30" + }, + .nStates = 15 + }, + }, + .nConfigExtra = 1, .setup = _setup, .teardown = NULL, .gameLoaded = _gameLoaded, .gameUnloaded = NULL, - .prepareForFrame = NULL, + .prepareForFrame = _prepareForFrame, .drawFrame = _drawFrame, .drawScreenshot = _drawScreenshot, .paused = NULL, From eb7f12b574e140f809dc9570f948f298fb5571bb Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Wed, 19 Sep 2018 19:20:15 -0700 Subject: [PATCH 14/50] mGUI: Add fast forward toggle --- CHANGES | 1 + src/feature/gui/gui-runner.c | 9 +++++++-- src/feature/gui/gui-runner.h | 3 ++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index df61c3760..08180740d 100644 --- a/CHANGES +++ b/CHANGES @@ -91,6 +91,7 @@ Misc: - Qt: Clean up FPS target UI (fixes mgba.io/i/436) - Core: Remove broken option for whether rewinding restores save games - FFmpeg: Support lossless VP9 encoding + - mGUI: Add fast forward toggle 0.6.3: (2017-04-14) Bugfixes: diff --git a/src/feature/gui/gui-runner.c b/src/feature/gui/gui-runner.c index 3877aef54..3dc0965a6 100644 --- a/src/feature/gui/gui-runner.c +++ b/src/feature/gui/gui-runner.c @@ -54,7 +54,8 @@ static const struct mInputPlatformInfo _mGUIKeyInfo = { [mGUI_INPUT_DECREASE_BRIGHTNESS] = "Decrease solar brightness", [mGUI_INPUT_SCREEN_MODE] = "Screen mode", [mGUI_INPUT_SCREENSHOT] = "Take screenshot", - [mGUI_INPUT_FAST_FORWARD] = "Fast forward", + [mGUI_INPUT_FAST_FORWARD_HELD] = "Fast forward (held)", + [mGUI_INPUT_FAST_FORWARD_TOGGLE] = "Fast forward (toggle)", }, .nKeys = GUI_INPUT_MAX }; @@ -412,6 +413,7 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) { runner->lastFpsCheck = 1000000LL * tv.tv_sec + tv.tv_usec; int frame = 0; + bool fastForward = false; while (running) { if (runner->running) { running = runner->running(runner); @@ -442,7 +444,10 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) { mCoreTakeScreenshot(runner->core); } if (runner->setFrameLimiter) { - if (heldKeys & (1 << mGUI_INPUT_FAST_FORWARD)) { + if (guiKeys & (1 << mGUI_INPUT_FAST_FORWARD_TOGGLE)) { + fastForward = !fastForward; + } + if (fastForward || (heldKeys & (1 << mGUI_INPUT_FAST_FORWARD_HELD))) { runner->setFrameLimiter(runner, false); } else { runner->setFrameLimiter(runner, true); diff --git a/src/feature/gui/gui-runner.h b/src/feature/gui/gui-runner.h index 6c91d1347..fda78f982 100644 --- a/src/feature/gui/gui-runner.h +++ b/src/feature/gui/gui-runner.h @@ -22,7 +22,8 @@ enum mGUIInput { mGUI_INPUT_DECREASE_BRIGHTNESS, mGUI_INPUT_SCREEN_MODE, mGUI_INPUT_SCREENSHOT, - mGUI_INPUT_FAST_FORWARD, + mGUI_INPUT_FAST_FORWARD_HELD, + mGUI_INPUT_FAST_FORWARD_TOGGLE }; struct mGUIBackground { From 5039d17a3048224b57fef74d468133a16c4bda04 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Wed, 19 Sep 2018 19:20:29 -0700 Subject: [PATCH 15/50] mGUI: Increase key delay --- src/util/gui.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/util/gui.c b/src/util/gui.c index ec37f99e5..8d5a1ec59 100644 --- a/src/util/gui.c +++ b/src/util/gui.c @@ -5,6 +5,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include +#define KEY_DELAY 45 +#define KEY_REPEAT 5 + void GUIInit(struct GUIParams* params) { memset(params->inputHistory, 0, sizeof(params->inputHistory)); strncpy(params->currentPath, params->basePath, PATH_MAX); @@ -19,7 +22,7 @@ void GUIPollInput(struct GUIParams* params, uint32_t* newInputOut, uint32_t* hel } else { params->inputHistory[i] = -1; } - if (!params->inputHistory[i] || (params->inputHistory[i] >= 30 && !(params->inputHistory[i] % 5))) { + if (!params->inputHistory[i] || (params->inputHistory[i] >= KEY_DELAY && !(params->inputHistory[i] % KEY_REPEAT))) { newInput |= (1 << i); } } From 1b9e1e8268fd292332a8ea132bb044e87d73e1e6 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Wed, 19 Sep 2018 19:21:49 -0700 Subject: [PATCH 16/50] Switch: Add argv loading --- src/platform/switch/main.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/platform/switch/main.c b/src/platform/switch/main.c index da448193e..63ade37c7 100644 --- a/src/platform/switch/main.c +++ b/src/platform/switch/main.c @@ -524,7 +524,16 @@ int main(int argc, char* argv[]) { _mapKey(&runner.params.keyMap, AUTO_INPUT, KEY_DRIGHT, GUI_INPUT_RIGHT); audoutStartAudioOut(); - mGUIRunloop(&runner); + + if (argc > 1) { + size_t i; + for (i = 0; runner.keySources[i].id; ++i) { + mInputMapLoad(&runner.params.keyMap, runner.keySources[i].id, mCoreConfigGetInput(&runner.config)); + } + mGUIRun(&runner, argv[1]); + } else { + mGUIRunloop(&runner); + } glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo); glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); From d7ec20900c0855b8e55bea1d80138b1ba2bb2d20 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Thu, 20 Sep 2018 11:19:54 -0700 Subject: [PATCH 17/50] Switch: Default map left stick to d-pad if no other bindings found --- src/platform/switch/main.c | 41 +++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/src/platform/switch/main.c b/src/platform/switch/main.c index 63ade37c7..cd6780deb 100644 --- a/src/platform/switch/main.c +++ b/src/platform/switch/main.c @@ -20,6 +20,7 @@ #define SAMPLES 0x400 #define BUFFER_SIZE 0x1000 #define N_BUFFERS 4 +#define ANALOG_DEADZONE 0x4000 TimeType __nx_time_type = TimeType_UserSystemClock; @@ -162,6 +163,40 @@ static uint32_t _pollInput(const struct mInputMap* map) { hidScanInput(); u32 padkeys = hidKeysHeld(CONTROLLER_P1_AUTO); keys |= mInputMapKeyBits(map, AUTO_INPUT, padkeys, 0); + + JoystickPosition jspos; + hidJoystickRead(&jspos, CONTROLLER_P1_AUTO, JOYSTICK_LEFT); + + int l = mInputMapKey(map, AUTO_INPUT, __builtin_ctz(KEY_LSTICK_LEFT)); + int r = mInputMapKey(map, AUTO_INPUT, __builtin_ctz(KEY_LSTICK_RIGHT)); + int u = mInputMapKey(map, AUTO_INPUT, __builtin_ctz(KEY_LSTICK_UP)); + int d = mInputMapKey(map, AUTO_INPUT, __builtin_ctz(KEY_LSTICK_DOWN)); + + if (l == -1) { + l = mInputMapKey(map, AUTO_INPUT, __builtin_ctz(KEY_DLEFT)); + } + if (r == -1) { + r = mInputMapKey(map, AUTO_INPUT, __builtin_ctz(KEY_DRIGHT)); + } + if (u == -1) { + u = mInputMapKey(map, AUTO_INPUT, __builtin_ctz(KEY_DUP)); + } + if (d == -1) { + d = mInputMapKey(map, AUTO_INPUT, __builtin_ctz(KEY_DDOWN)); + } + + if (jspos.dx < -ANALOG_DEADZONE && l != -1) { + keys |= 1 << l; + } + if (jspos.dx > ANALOG_DEADZONE && r != -1) { + keys |= 1 << r; + } + if (jspos.dy < -ANALOG_DEADZONE && d != -1) { + keys |= 1 << d; + } + if (jspos.dy > ANALOG_DEADZONE && u != -1) { + keys |= 1 << u; + } return keys; } @@ -275,11 +310,7 @@ static void _drawScreenshot(struct mGUIRunner* runner, const color_t* pixels, un } static uint16_t _pollGameInput(struct mGUIRunner* runner) { - int keys = 0; - hidScanInput(); - u32 padkeys = hidKeysHeld(CONTROLLER_P1_AUTO); - keys |= mInputMapKeyBits(&runner->core->inputMap, AUTO_INPUT, padkeys, 0); - return keys; + return _pollInput(&runner->core->inputMap); } static void _setFrameLimiter(struct mGUIRunner* runner, bool limit) { From b712a7208d0f9fc4ac2bd6648c4ee9b446f6c96b Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Thu, 20 Sep 2018 11:20:05 -0700 Subject: [PATCH 18/50] Switch: Round battery up --- src/platform/switch/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/switch/main.c b/src/platform/switch/main.c index cd6780deb..156a9ac44 100644 --- a/src/platform/switch/main.c +++ b/src/platform/switch/main.c @@ -359,7 +359,7 @@ static int _batteryState(void) { u32 charge; int state = 0; if (R_SUCCEEDED(psmGetBatteryChargePercentage(&charge))) { - state = charge / 25; + state = (charge + 12) / 25; } ChargerType type; if (R_SUCCEEDED(psmGetChargerType(&type)) && type) { From 9fb7485051241fa7939a6a88954dedbf69d7616a Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Thu, 20 Sep 2018 11:22:58 -0700 Subject: [PATCH 19/50] mGUI: Add BATTERY_NOT_PRESENT state --- include/mgba-util/gui.h | 3 ++- src/platform/switch/main.c | 2 ++ src/util/gui/menu.c | 3 +++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/include/mgba-util/gui.h b/include/mgba-util/gui.h index 183fcfa80..a13251bc6 100644 --- a/include/mgba-util/gui.h +++ b/include/mgba-util/gui.h @@ -47,7 +47,8 @@ enum { BATTERY_HIGH = 3, BATTERY_FULL = 4, - BATTERY_CHARGING = 8 + BATTERY_CHARGING = 8, + BATTERY_NOT_PRESENT = 16 }; struct GUIBackground { diff --git a/src/platform/switch/main.c b/src/platform/switch/main.c index 156a9ac44..55be2f910 100644 --- a/src/platform/switch/main.c +++ b/src/platform/switch/main.c @@ -360,6 +360,8 @@ static int _batteryState(void) { int state = 0; if (R_SUCCEEDED(psmGetBatteryChargePercentage(&charge))) { state = (charge + 12) / 25; + } else { + return BATTERY_NOT_PRESENT; } ChargerType type; if (R_SUCCEEDED(psmGetChargerType(&type)) && type) { diff --git a/src/util/gui/menu.c b/src/util/gui/menu.c index f9cba3d36..68ba7781f 100644 --- a/src/util/gui/menu.c +++ b/src/util/gui/menu.c @@ -260,6 +260,9 @@ void GUIDrawBattery(struct GUIParams* params) { return; } int state = params->batteryState(); + if (state == BATTERY_NOT_PRESENT) { + return; + } uint32_t color = 0xFF000000; if (state == (BATTERY_CHARGING | BATTERY_FULL)) { color |= 0xFFC060; From 51f9a76ab212514ba8035a85b60af4b963fabc11 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Thu, 20 Sep 2018 11:24:33 -0700 Subject: [PATCH 20/50] mGUI: Fix warnings on 64-bit --- src/feature/gui/remap.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/feature/gui/remap.c b/src/feature/gui/remap.c index b17560319..4238454b6 100644 --- a/src/feature/gui/remap.c +++ b/src/feature/gui/remap.c @@ -69,13 +69,13 @@ void mGUIRemapKeys(struct GUIParams* params, struct mInputMap* map, const struct if (item->data == (void*) (GUI_INPUT_MAX + map->info->nKeys + 2)) { for (i = 0; i < GUIMenuItemListSize(&menu.items); ++i) { item = GUIMenuItemListGetPointer(&menu.items, i); - if ((uint32_t) item->data < 1) { + if ((uintptr_t) item->data < 1) { continue; } - if ((uint32_t) item->data < GUI_INPUT_MAX + 1) { - mInputBindKey(¶ms->keyMap, keys->id, item->state - 1, (uint32_t) item->data - 1); - } else if ((uint32_t) item->data < GUI_INPUT_MAX + map->info->nKeys + 1) { - mInputBindKey(map, keys->id, item->state - 1, (uint32_t) item->data - GUI_INPUT_MAX - 1); + if ((uintptr_t) item->data < GUI_INPUT_MAX + 1) { + mInputBindKey(¶ms->keyMap, keys->id, item->state - 1, (uintptr_t) item->data - 1); + } else if ((uintptr_t) item->data < GUI_INPUT_MAX + map->info->nKeys + 1) { + mInputBindKey(map, keys->id, item->state - 1, (uintptr_t) item->data - GUI_INPUT_MAX - 1); } } break; From 9f1b2e9d1dd3387741a995de88056c8c1dfd969a Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Thu, 20 Sep 2018 11:27:57 -0700 Subject: [PATCH 21/50] Core: Finish removing rewindSave option --- include/mgba/core/config.h | 1 - src/core/config.c | 2 -- src/platform/sdl/main.c | 1 - 3 files changed, 4 deletions(-) diff --git a/include/mgba/core/config.h b/include/mgba/core/config.h index a55d19c0d..b2439c41e 100644 --- a/include/mgba/core/config.h +++ b/include/mgba/core/config.h @@ -33,7 +33,6 @@ struct mCoreOptions { int frameskip; bool rewindEnable; int rewindBufferCapacity; - bool rewindSave; float fpsTarget; size_t audioBuffers; unsigned sampleRate; diff --git a/src/core/config.c b/src/core/config.c index cb5c1a6dc..932c904c2 100644 --- a/src/core/config.c +++ b/src/core/config.c @@ -331,7 +331,6 @@ void mCoreConfigMap(const struct mCoreConfig* config, struct mCoreOptions* opts) _lookupIntValue(config, "frameskip", &opts->frameskip); _lookupIntValue(config, "volume", &opts->volume); _lookupIntValue(config, "rewindBufferCapacity", &opts->rewindBufferCapacity); - _lookupIntValue(config, "rewindSave", &opts->rewindSave); _lookupFloatValue(config, "fpsTarget", &opts->fpsTarget); unsigned audioBuffers; if (_lookupUIntValue(config, "audioBuffers", &audioBuffers)) { @@ -391,7 +390,6 @@ void mCoreConfigLoadDefaults(struct mCoreConfig* config, const struct mCoreOptio ConfigurationSetIntValue(&config->defaultsTable, 0, "frameskip", opts->frameskip); ConfigurationSetIntValue(&config->defaultsTable, 0, "rewindEnable", opts->rewindEnable); ConfigurationSetIntValue(&config->defaultsTable, 0, "rewindBufferCapacity", opts->rewindBufferCapacity); - ConfigurationSetIntValue(&config->defaultsTable, 0, "rewindSave", opts->rewindSave); ConfigurationSetFloatValue(&config->defaultsTable, 0, "fpsTarget", opts->fpsTarget); ConfigurationSetUIntValue(&config->defaultsTable, 0, "audioBuffers", opts->audioBuffers); ConfigurationSetUIntValue(&config->defaultsTable, 0, "sampleRate", opts->sampleRate); diff --git a/src/platform/sdl/main.c b/src/platform/sdl/main.c index 948c2bb04..dd20b0397 100644 --- a/src/platform/sdl/main.c +++ b/src/platform/sdl/main.c @@ -57,7 +57,6 @@ int main(int argc, char** argv) { .useBios = true, .rewindEnable = true, .rewindBufferCapacity = 600, - .rewindSave = true, .audioBuffers = 1024, .videoSync = false, .audioSync = true, From 5d8e77d96721aff70ae934d18865aba83abc7a2f Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Thu, 20 Sep 2018 11:56:52 -0700 Subject: [PATCH 22/50] GB MBC: Improve multicart detection heuristic (fixes #1177) --- CHANGES | 1 + src/gb/mbc.c | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index 08180740d..d6fb54028 100644 --- a/CHANGES +++ b/CHANGES @@ -57,6 +57,7 @@ Bugfixes: - GBA DMA: Fix temporal sorting of DMAs of different priorities - FFmpeg: Fix encoding audio/video queue issues - GB Serialize: Fix IRQ pending/EI pending confusion + - GB MBC: Improve multicart detection heuristic (fixes mgba.io/i/1177) Misc: - GBA Timer: Use global cycles for timers - GBA: Extend oddly-sized ROMs to full address space (fixes mgba.io/i/722) diff --git a/src/gb/mbc.c b/src/gb/mbc.c index 2da6a264e..817b3dc9d 100644 --- a/src/gb/mbc.c +++ b/src/gb/mbc.c @@ -95,17 +95,27 @@ void GBMBCSwitchHalfBank(struct GB* gb, int half, int bank) { } static bool _isMulticart(const uint8_t* mem) { - bool success = true; + bool success; struct VFile* vf; vf = VFileFromConstMemory(&mem[GB_SIZE_CART_BANK0 * 0x10], 1024); - success = success && GBIsROM(vf); + success = GBIsROM(vf); vf->close(vf); + if (!success) { + return false; + } + vf = VFileFromConstMemory(&mem[GB_SIZE_CART_BANK0 * 0x20], 1024); - success = success && GBIsROM(vf); + success = GBIsROM(vf); vf->close(vf); + if (!success) { + vf = VFileFromConstMemory(&mem[GB_SIZE_CART_BANK0 * 0x30], 1024); + success = GBIsROM(vf); + vf->close(vf); + } + return success; } From 909d1146a16b8fbd7986dd91c0d4db76b932ab57 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Thu, 20 Sep 2018 12:50:01 -0700 Subject: [PATCH 23/50] ImageMagick: Fix predefinitions issue --- src/feature/imagemagick/imagemagick-gif-encoder.h | 3 --- src/platform/qt/CMakeLists.txt | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/feature/imagemagick/imagemagick-gif-encoder.h b/src/feature/imagemagick/imagemagick-gif-encoder.h index 842cad942..67afdfe90 100644 --- a/src/feature/imagemagick/imagemagick-gif-encoder.h +++ b/src/feature/imagemagick/imagemagick-gif-encoder.h @@ -12,9 +12,6 @@ CXX_GUARD_START #include -#define MAGICKCORE_HDRI_ENABLE 0 -#define MAGICKCORE_QUANTUM_DEPTH 8 - #if MAGICKWAND_VERSION_MAJOR >= 7 #include #else diff --git a/src/platform/qt/CMakeLists.txt b/src/platform/qt/CMakeLists.txt index 42152b307..510b5baa6 100644 --- a/src/platform/qt/CMakeLists.txt +++ b/src/platform/qt/CMakeLists.txt @@ -269,7 +269,7 @@ endif() qt5_wrap_ui(UI_SRC ${UI_FILES}) add_executable(${BINARY_NAME}-qt WIN32 MACOSX_BUNDLE main.cpp ${CMAKE_SOURCE_DIR}/res/mgba.icns ${SOURCE_FILES} ${PLATFORM_SRC} ${UI_SRC} ${AUDIO_SRC} ${RESOURCES}) -set_target_properties(${BINARY_NAME}-qt PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/res/info.plist.in COMPILE_DEFINITIONS "${FEATURE_DEFINES};${FUNCTION_DEFINES};${OS_DEFINES};${QT_DEFINES}") +set_target_properties(${BINARY_NAME}-qt PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/res/info.plist.in COMPILE_DEFINITIONS "${FEATURE_DEFINES};${FUNCTION_DEFINES};${OS_DEFINES};${QT_DEFINES}" COMPILE_OPTIONS "${FEATURE_FLAGS}") list(APPEND QT_LIBRARIES Qt5::Widgets) if(BUILD_GL OR BUILD_GLES2) From 05bfcb4f098e00844c165b7c899e8ee3808a6b27 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Thu, 20 Sep 2018 13:17:05 -0700 Subject: [PATCH 24/50] Libretro: Properly center camera --- src/platform/libretro/libretro.c | 44 +++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/src/platform/libretro/libretro.c b/src/platform/libretro/libretro.c index 6e836a2c5..91155eadf 100644 --- a/src/platform/libretro/libretro.c +++ b/src/platform/libretro/libretro.c @@ -66,6 +66,8 @@ static struct mImageSource imageSource; static uint32_t* camData = NULL; static unsigned camWidth; static unsigned camHeight; +static unsigned imcapWidth; +static unsigned imcapHeight; static size_t camStride; static void _reloadSettings(void) { @@ -776,20 +778,40 @@ static uint8_t _readLux(struct GBALuminanceSource* lux) { } static void _updateCamera(const uint32_t* buffer, unsigned width, unsigned height, size_t pitch) { - if (!camData || width != camWidth || height != camHeight) { - camData = malloc(sizeof(*buffer) * height * pitch); + if (!camData || width > camWidth || height > camHeight) { + if (camData) { + free(camData); + } + unsigned bufPitch = pitch / sizeof(*buffer); + unsigned bufHeight = height; + if (imcapWidth > bufPitch) { + bufPitch = imcapWidth; + } + if (imcapHeight > bufHeight) { + bufHeight = imcapHeight; + } + camData = malloc(sizeof(*buffer) * bufHeight * bufPitch); + memset(camData, 0xFF, sizeof(*buffer) * bufHeight * bufPitch); camWidth = width; - camHeight = height; - camStride = pitch / sizeof(*buffer); + camHeight = bufHeight; + camStride = bufPitch; + } + size_t i; + for (i = 0; i < height; ++i) { + memcpy(&camData[camStride * i], &buffer[pitch * i / sizeof(*buffer)], pitch); } - memcpy(camData, buffer, sizeof(*buffer) * height * pitch); } static void _startImage(struct mImageSource* image, unsigned w, unsigned h, int colorFormats) { UNUSED(image); UNUSED(colorFormats); + if (camData) { + free(camData); + } camData = NULL; + imcapWidth = w; + imcapHeight = h; cam.start(); } @@ -802,8 +824,18 @@ static void _requestImage(struct mImageSource* image, const void** buffer, size_ UNUSED(image); if (!camData) { cam.start(); + *buffer = NULL; + return; } - *buffer = camData; + size_t offset = 0; + if (imcapWidth < camWidth) { + offset += (camWidth - imcapWidth) / 2; + } + if (imcapHeight < camHeight) { + offset += (camHeight - imcapHeight) / 2 * camStride; + } + + *buffer = &camData[offset]; *stride = camStride; *colorFormat = mCOLOR_XRGB8; } From 4ecc4b5a0d432abb37e598178f584ce51d3a03ae Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 21 Sep 2018 09:48:46 -0700 Subject: [PATCH 25/50] GBA Video: Fix not reseting proxy renderer on load --- src/gba/extra/proxy.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gba/extra/proxy.c b/src/gba/extra/proxy.c index 2cb003e25..9df8fe821 100644 --- a/src/gba/extra/proxy.c +++ b/src/gba/extra/proxy.c @@ -103,6 +103,7 @@ void GBAVideoProxyRendererInit(struct GBAVideoRenderer* renderer) { struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer; _init(proxyRenderer); + _reset(proxyRenderer); proxyRenderer->backend->init(proxyRenderer->backend); } From 97032109381c9029df57478fe2c3e4b8dcabe8cc Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 21 Sep 2018 14:13:54 -0700 Subject: [PATCH 26/50] GB Audio: Fix channel 3 reset value --- CHANGES | 1 + src/gb/audio.c | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index d6fb54028..7121c6bba 100644 --- a/CHANGES +++ b/CHANGES @@ -58,6 +58,7 @@ Bugfixes: - FFmpeg: Fix encoding audio/video queue issues - GB Serialize: Fix IRQ pending/EI pending confusion - GB MBC: Improve multicart detection heuristic (fixes mgba.io/i/1177) + - GB Audio: Fix channel 3 reset value Misc: - GBA Timer: Use global cycles for timers - GBA: Extend oddly-sized ROMs to full address space (fixes mgba.io/i/722) diff --git a/src/gb/audio.c b/src/gb/audio.c index daf479a26..ea0237da1 100644 --- a/src/gb/audio.c +++ b/src/gb/audio.c @@ -331,6 +331,7 @@ void GBAudioWriteNR34(struct GBAudio* audio, uint8_t value) { } } audio->ch3.window = 0; + audio->ch3.sample = 0; } mTimingDeschedule(audio->timing, &audio->ch3Fade); mTimingDeschedule(audio->timing, &audio->ch3Event); From f99bdc07de7ce72e823d6fd6a1863bbc1adb556d Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 21 Sep 2018 14:15:27 -0700 Subject: [PATCH 27/50] GB Audio: Fix channel 4 initial LFSR --- CHANGES | 1 + src/gb/audio.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 7121c6bba..c342c95da 100644 --- a/CHANGES +++ b/CHANGES @@ -59,6 +59,7 @@ Bugfixes: - GB Serialize: Fix IRQ pending/EI pending confusion - GB MBC: Improve multicart detection heuristic (fixes mgba.io/i/1177) - GB Audio: Fix channel 3 reset value + - GB Audio: Fix channel 4 initial LFSR Misc: - GBA Timer: Use global cycles for timers - GBA: Extend oddly-sized ROMs to full address space (fixes mgba.io/i/722) diff --git a/src/gb/audio.c b/src/gb/audio.c index ea0237da1..a0e5ef1b9 100644 --- a/src/gb/audio.c +++ b/src/gb/audio.c @@ -377,9 +377,9 @@ void GBAudioWriteNR44(struct GBAudio* audio, uint8_t value) { audio->playingCh4 = _resetEnvelope(&audio->ch4.envelope); if (audio->ch4.power) { - audio->ch4.lfsr = 0x40; + audio->ch4.lfsr = 0x7F; } else { - audio->ch4.lfsr = 0x4000; + audio->ch4.lfsr = 0x7FFF; } if (!audio->ch4.length) { audio->ch4.length = 64; From 6e7c250b19f63c4bdc02acd29170c0fb0d9013eb Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 21 Sep 2018 14:32:26 -0700 Subject: [PATCH 28/50] Core: Remove erroneous log message --- src/core/serialize.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/serialize.c b/src/core/serialize.c index 21cccc8b9..c6a29b242 100644 --- a/src/core/serialize.c +++ b/src/core/serialize.c @@ -360,7 +360,6 @@ bool mCoreSaveStateNamed(struct mCore* core, struct VFile* vf, int flags) { } } if (flags & SAVESTATE_RTC) { - mLOG(SAVESTATE, INFO, "Loading RTC"); struct mStateExtdataItem item; if (core->rtc.d.serialize) { core->rtc.d.serialize(&core->rtc.d, &item); From b6f3a2929d9fe2a7ca31a0f2d420031898196216 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 21 Sep 2018 17:59:37 -0700 Subject: [PATCH 29/50] GB, GBA Audio: Adjust mixdown --- src/gb/audio.c | 22 +++++++++++----------- src/gba/audio.c | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/gb/audio.c b/src/gb/audio.c index a0e5ef1b9..f356f45b8 100644 --- a/src/gb/audio.c +++ b/src/gb/audio.c @@ -576,47 +576,47 @@ void GBAudioUpdateFrame(struct GBAudio* audio, struct mTiming* timing) { } void GBAudioSamplePSG(struct GBAudio* audio, int16_t* left, int16_t* right) { - int dcOffset = audio->style == GB_AUDIO_GBA ? 0 : 0x8; + int dcOffset = audio->style == GB_AUDIO_GBA ? 0 : -0x8; int sampleLeft = dcOffset; int sampleRight = dcOffset; if (audio->playingCh1 && !audio->forceDisableCh[0]) { if (audio->ch1Left) { - sampleLeft -= audio->ch1.sample; + sampleLeft += audio->ch1.sample; } if (audio->ch1Right) { - sampleRight -= audio->ch1.sample; + sampleRight += audio->ch1.sample; } } if (audio->playingCh2 && !audio->forceDisableCh[1]) { if (audio->ch2Left) { - sampleLeft -= audio->ch2.sample; + sampleLeft += audio->ch2.sample; } if (audio->ch2Right) { - sampleRight -= audio->ch2.sample; + sampleRight += audio->ch2.sample; } } if (audio->playingCh3 && !audio->forceDisableCh[2]) { if (audio->ch3Left) { - sampleLeft -= audio->ch3.sample; + sampleLeft += audio->ch3.sample; } if (audio->ch3Right) { - sampleRight -= audio->ch3.sample; + sampleRight += audio->ch3.sample; } } if (audio->playingCh4 && !audio->forceDisableCh[3]) { if (audio->ch4Left) { - sampleLeft -= audio->ch4.sample; + sampleLeft += audio->ch4.sample; } if (audio->ch4Right) { - sampleRight -= audio->ch4.sample; + sampleRight += audio->ch4.sample; } } @@ -632,8 +632,8 @@ static void _sample(struct mTiming* timing, void* user, uint32_t cyclesLate) { int16_t sampleLeft = 0; int16_t sampleRight = 0; GBAudioSamplePSG(audio, &sampleLeft, &sampleRight); - sampleLeft = (sampleLeft * audio->masterVolume * 9) >> 7; - sampleRight = (sampleRight * audio->masterVolume * 9) >> 7; + sampleLeft = (sampleLeft * audio->masterVolume * 6) >> 7; + sampleRight = (sampleRight * audio->masterVolume * 6) >> 7; mCoreSyncLockAudio(audio->p->sync); unsigned produced; diff --git a/src/gba/audio.c b/src/gba/audio.c index 14f47ff56..c0ed7cf4c 100644 --- a/src/gba/audio.c +++ b/src/gba/audio.c @@ -253,7 +253,7 @@ static int _applyBias(struct GBAAudio* audio, int sample) { } else if (sample < 0) { sample = 0; } - return ((sample - GBARegisterSOUNDBIASGetBias(audio->soundbias)) * audio->masterVolume) >> 2; + return ((sample - GBARegisterSOUNDBIASGetBias(audio->soundbias)) * audio->masterVolume * 3) >> 4; } static void _sample(struct mTiming* timing, void* user, uint32_t cyclesLate) { From 555122e0a1bc1311040e6ff7a8b2d95090fa76ca Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 21 Sep 2018 21:41:57 -0700 Subject: [PATCH 30/50] GB Audio: Improve channel 4 accuracy --- include/mgba/internal/gb/audio.h | 3 +++ src/gb/audio.c | 42 ++++++++++++++++++++++---------- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/include/mgba/internal/gb/audio.h b/include/mgba/internal/gb/audio.h index ff7b3830a..837e0a1b3 100644 --- a/include/mgba/internal/gb/audio.h +++ b/include/mgba/internal/gb/audio.h @@ -137,6 +137,9 @@ struct GBAudioNoiseChannel { int length; uint32_t lfsr; + int nSamples; + int samples; + int8_t sample; }; diff --git a/src/gb/audio.c b/src/gb/audio.c index f356f45b8..f1489c9bb 100644 --- a/src/gb/audio.c +++ b/src/gb/audio.c @@ -37,6 +37,8 @@ static bool _updateSweep(struct GBAudioSquareChannel* sweep, bool initial); static void _updateSquareSample(struct GBAudioSquareChannel* ch); static int32_t _updateSquareChannel(struct GBAudioSquareChannel* ch); +static int8_t _coalesceNoiseChannel(struct GBAudioNoiseChannel* ch); + static void _updateFrame(struct mTiming* timing, void* user, uint32_t cyclesLate); static void _updateChannel1(struct mTiming* timing, void* user, uint32_t cyclesLate); static void _updateChannel2(struct mTiming* timing, void* user, uint32_t cyclesLate); @@ -118,6 +120,7 @@ void GBAudioReset(struct GBAudio* audio) { audio->ch1 = (struct GBAudioSquareChannel) { .envelope = { .dead = 2 } }; audio->ch2 = (struct GBAudioSquareChannel) { .envelope = { .dead = 2 } }; audio->ch3 = (struct GBAudioWaveChannel) { .bank = 0 }; + audio->ch4 = (struct GBAudioNoiseChannel) { .nSamples = 0 }; // TODO: DMG randomness audio->ch3.wavedata8[0] = 0x00; audio->ch3.wavedata8[1] = 0xFF; @@ -564,11 +567,13 @@ void GBAudioUpdateFrame(struct GBAudio* audio, struct mTiming* timing) { --audio->ch4.envelope.nextStep; if (audio->ch4.envelope.nextStep == 0) { int8_t sample = audio->ch4.sample > 0; + audio->ch4.samples -= audio->ch4.sample; _updateEnvelope(&audio->ch4.envelope); if (audio->ch4.envelope.dead == 2) { mTimingDeschedule(timing, &audio->ch4Event); } audio->ch4.sample = sample * audio->ch4.envelope.currentVolume; + audio->ch4.samples += audio->ch4.sample; } } break; @@ -611,12 +616,13 @@ void GBAudioSamplePSG(struct GBAudio* audio, int16_t* left, int16_t* right) { } if (audio->playingCh4 && !audio->forceDisableCh[3]) { + int8_t sample = _coalesceNoiseChannel(&audio->ch4); if (audio->ch4Left) { - sampleLeft += audio->ch4.sample; + sampleLeft += sample; } if (audio->ch4Right) { - sampleRight += audio->ch4.sample; + sampleRight += sample; } } @@ -745,6 +751,17 @@ static int32_t _updateSquareChannel(struct GBAudioSquareChannel* ch) { } } +static int8_t _coalesceNoiseChannel(struct GBAudioNoiseChannel* ch) { + if (!ch->nSamples) { + return ch->sample; + } + // TODO keep track of timing + int8_t sample = ch->samples / ch->nSamples; + ch->nSamples = 0; + ch->samples = 0; + return sample; +} + static void _updateEnvelope(struct GBAudioEnvelope* envelope) { if (envelope->direction) { ++envelope->currentVolume; @@ -895,18 +912,17 @@ static void _updateChannel4(struct mTiming* timing, void* user, uint32_t cyclesL struct GBAudio* audio = user; struct GBAudioNoiseChannel* ch = &audio->ch4; - int32_t baseCycles = ch->ratio ? 2 * ch->ratio : 1; - baseCycles <<= ch->frequency; - baseCycles *= 8 * audio->timingFactor; - int32_t cycles = 0; + int32_t cycles = ch->ratio ? 2 * ch->ratio : 1; + cycles <<= ch->frequency; + cycles *= 8 * audio->timingFactor; + + int lsb = ch->lfsr & 1; + ch->sample = lsb * ch->envelope.currentVolume; + ++ch->nSamples; + ch->samples += ch->sample; + ch->lfsr >>= 1; + ch->lfsr ^= (lsb * 0x60) << (ch->power ? 0 : 8); - do { - int lsb = ch->lfsr & 1; - ch->sample = lsb * ch->envelope.currentVolume; - ch->lfsr >>= 1; - ch->lfsr ^= (lsb * 0x60) << (ch->power ? 0 : 8); - cycles += baseCycles; - } while (cycles + baseCycles < audio->sampleInterval); mTimingSchedule(timing, &audio->ch4Event, cycles - cyclesLate); } From 6d5e53f2d8e21e5c120863ac55139a42d55a1f75 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sat, 22 Sep 2018 10:36:02 -0700 Subject: [PATCH 31/50] GB, GBA Video: Don't call finishFrame twice in thread proxy --- CHANGES | 1 + src/gb/extra/proxy.c | 4 +++- src/gba/extra/proxy.c | 6 ++++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index c342c95da..b521da8f0 100644 --- a/CHANGES +++ b/CHANGES @@ -60,6 +60,7 @@ Bugfixes: - GB MBC: Improve multicart detection heuristic (fixes mgba.io/i/1177) - GB Audio: Fix channel 3 reset value - GB Audio: Fix channel 4 initial LFSR + - GB, GBA Video: Don't call finishFrame twice in thread proxy Misc: - GBA Timer: Use global cycles for timers - GBA: Extend oddly-sized ROMs to full address space (fixes mgba.io/i/722) diff --git a/src/gb/extra/proxy.c b/src/gb/extra/proxy.c index 36411939b..5de65ae84 100644 --- a/src/gb/extra/proxy.c +++ b/src/gb/extra/proxy.c @@ -254,7 +254,9 @@ void GBVideoProxyRendererFinishFrame(struct GBVideoRenderer* renderer) { proxyRenderer->logger->lock(proxyRenderer->logger); proxyRenderer->logger->wait(proxyRenderer->logger); } - proxyRenderer->backend->finishFrame(proxyRenderer->backend); + if (!proxyRenderer->logger->block) { + proxyRenderer->backend->finishFrame(proxyRenderer->backend); + } mVideoLoggerRendererFinishFrame(proxyRenderer->logger); mVideoLoggerRendererFlush(proxyRenderer->logger); if (proxyRenderer->logger->block && proxyRenderer->logger->wait) { diff --git a/src/gba/extra/proxy.c b/src/gba/extra/proxy.c index 9df8fe821..8189c6f74 100644 --- a/src/gba/extra/proxy.c +++ b/src/gba/extra/proxy.c @@ -137,7 +137,7 @@ static bool _parsePacket(struct mVideoLogger* logger, const struct mVideoLoggerD } break; case DIRTY_OAM: - if (item->address < SIZE_PALETTE_RAM) { + if (item->address < SIZE_OAM) { logger->oam[item->address] = item->value; proxyRenderer->backend->writeOAM(proxyRenderer->backend, item->address); } @@ -252,7 +252,9 @@ void GBAVideoProxyRendererFinishFrame(struct GBAVideoRenderer* renderer) { proxyRenderer->logger->lock(proxyRenderer->logger); proxyRenderer->logger->wait(proxyRenderer->logger); } - proxyRenderer->backend->finishFrame(proxyRenderer->backend); + if (!proxyRenderer->logger->block) { + proxyRenderer->backend->finishFrame(proxyRenderer->backend); + } mVideoLoggerRendererFinishFrame(proxyRenderer->logger); mVideoLoggerRendererFlush(proxyRenderer->logger); if (proxyRenderer->logger->block && proxyRenderer->logger->wait) { From 56107e616ff54b5a83668ac268db6245b4620807 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sat, 22 Sep 2018 11:13:53 -0700 Subject: [PATCH 32/50] GB Video: Fix windows on reset --- src/gb/renderers/software.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gb/renderers/software.c b/src/gb/renderers/software.c index d339c9629..d2e000422 100644 --- a/src/gb/renderers/software.c +++ b/src/gb/renderers/software.c @@ -193,7 +193,7 @@ static void GBVideoSoftwareRendererInit(struct GBVideoRenderer* renderer, enum G softwareRenderer->scx = 0; softwareRenderer->wy = 0; softwareRenderer->currentWy = 0; - softwareRenderer->lastY = 0; + softwareRenderer->lastY = GB_VIDEO_VERTICAL_PIXELS; softwareRenderer->hasWindow = false; softwareRenderer->wx = 0; softwareRenderer->model = model; From ca9448cd353ca12264bfa1dcfddc6fe470f7d77a Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sat, 22 Sep 2018 15:34:18 -0700 Subject: [PATCH 33/50] GB Audio: Fix channel 1, 2 and 4 reset timing --- CHANGES | 1 + src/gb/audio.c | 18 ++++++------------ 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/CHANGES b/CHANGES index b521da8f0..032f4e537 100644 --- a/CHANGES +++ b/CHANGES @@ -61,6 +61,7 @@ Bugfixes: - GB Audio: Fix channel 3 reset value - GB Audio: Fix channel 4 initial LFSR - GB, GBA Video: Don't call finishFrame twice in thread proxy + - GB Audio: Fix channel 1, 2 and 4 reset timing Misc: - GBA Timer: Use global cycles for timers - GBA: Extend oddly-sized ROMs to full address space (fixes mgba.io/i/722) diff --git a/src/gb/audio.c b/src/gb/audio.c index f1489c9bb..6c8b7bfe1 100644 --- a/src/gb/audio.c +++ b/src/gb/audio.c @@ -206,11 +206,6 @@ void GBAudioWriteNR14(struct GBAudio* audio, uint8_t value) { } if (GBAudioRegisterControlIsRestart(value << 8)) { audio->playingCh1 = _resetEnvelope(&audio->ch1.envelope); - - if (audio->playingCh1) { - _updateSquareSample(&audio->ch1); - } - audio->ch1.sweep.realFrequency = audio->ch1.control.frequency; _resetSweep(&audio->ch1.sweep); if (audio->playingCh1 && audio->ch1.sweep.shift) { @@ -222,7 +217,8 @@ void GBAudioWriteNR14(struct GBAudio* audio, uint8_t value) { --audio->ch1.control.length; } } - if (audio->playingCh1 && audio->ch1.envelope.dead != 2 && !mTimingIsScheduled(audio->timing, &audio->ch1Event)) { + if (audio->playingCh1 && audio->ch1.envelope.dead != 2) { + mTimingDeschedule(audio->timing, &audio->ch1Event); mTimingSchedule(audio->timing, &audio->ch1Event, 0); } } @@ -263,17 +259,14 @@ void GBAudioWriteNR24(struct GBAudio* audio, uint8_t value) { if (GBAudioRegisterControlIsRestart(value << 8)) { audio->playingCh2 = _resetEnvelope(&audio->ch2.envelope); - if (audio->playingCh2) { - _updateSquareSample(&audio->ch2); - } - if (!audio->ch2.control.length) { audio->ch2.control.length = 64; if (audio->ch2.control.stop && !(audio->frame & 1)) { --audio->ch2.control.length; } } - if (audio->playingCh2 && audio->ch2.envelope.dead != 2 && !mTimingIsScheduled(audio->timing, &audio->ch2Event)) { + if (audio->playingCh2 && audio->ch2.envelope.dead != 2) { + mTimingDeschedule(audio->timing, &audio->ch2Event); mTimingSchedule(audio->timing, &audio->ch2Event, 0); } } @@ -390,7 +383,8 @@ void GBAudioWriteNR44(struct GBAudio* audio, uint8_t value) { --audio->ch4.length; } } - if (audio->playingCh4 && audio->ch4.envelope.dead != 2 && !mTimingIsScheduled(audio->timing, &audio->ch4Event)) { + if (audio->playingCh4 && audio->ch4.envelope.dead != 2) { + mTimingDeschedule(audio->timing, &audio->ch4Event); mTimingSchedule(audio->timing, &audio->ch4Event, 0); } } From de9bff4a29db25554e5234ff788617ed46a9436c Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 23 Sep 2018 13:26:32 -0700 Subject: [PATCH 34/50] Util: Fix wrapping edge cases in RingFIFO --- CHANGES | 1 + src/util/ring-fifo.c | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CHANGES b/CHANGES index 032f4e537..15bf4355a 100644 --- a/CHANGES +++ b/CHANGES @@ -62,6 +62,7 @@ Bugfixes: - GB Audio: Fix channel 4 initial LFSR - GB, GBA Video: Don't call finishFrame twice in thread proxy - GB Audio: Fix channel 1, 2 and 4 reset timing + - Util: Fix wrapping edge cases in RingFIFO Misc: - GBA Timer: Use global cycles for timers - GBA: Extend oddly-sized ROMs to full address space (fixes mgba.io/i/722) diff --git a/src/util/ring-fifo.c b/src/util/ring-fifo.c index 167690c61..39c10934a 100644 --- a/src/util/ring-fifo.c +++ b/src/util/ring-fifo.c @@ -33,8 +33,8 @@ size_t RingFIFOWrite(struct RingFIFO* buffer, const void* value, size_t length) ATOMIC_LOAD(end, buffer->readPtr); // Wrap around if we can't fit enough in here - if ((intptr_t) data - (intptr_t) buffer->data + length >= buffer->capacity) { - if (end == buffer->data) { + if ((uintptr_t) data - (uintptr_t) buffer->data + length >= buffer->capacity) { + if (end == buffer->data || end > data) { // Oops! If we wrap now, it'll appear empty return 0; } @@ -65,8 +65,8 @@ size_t RingFIFORead(struct RingFIFO* buffer, void* output, size_t length) { ATOMIC_LOAD(end, buffer->writePtr); // Wrap around if we can't fit enough in here - if ((intptr_t) data - (intptr_t) buffer->data + length >= buffer->capacity) { - if (end == data) { + if ((uintptr_t) data - (uintptr_t) buffer->data + length >= buffer->capacity) { + if (end >= data) { // Oops! If we wrap now, it'll appear full return 0; } @@ -78,7 +78,7 @@ size_t RingFIFORead(struct RingFIFO* buffer, void* output, size_t length) { uintptr_t bufferEnd = (uintptr_t) buffer->data + buffer->capacity; remaining = bufferEnd - (uintptr_t) data; } else { - remaining = (intptr_t) end - (intptr_t) data; + remaining = (uintptr_t) end - (uintptr_t) data; } // If the pointers touch, it's empty if (remaining < length) { @@ -87,6 +87,6 @@ size_t RingFIFORead(struct RingFIFO* buffer, void* output, size_t length) { if (output) { memcpy(output, data, length); } - ATOMIC_STORE(buffer->readPtr, (void*) ((intptr_t) data + length)); + ATOMIC_STORE(buffer->readPtr, (void*) ((uintptr_t) data + length)); return length; } From fdfab146a0deb24616034f6b9bb7d76a5f065e56 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 23 Sep 2018 13:26:52 -0700 Subject: [PATCH 35/50] Core: Fix up thread proxy waiting --- include/mgba-util/ring-fifo.h | 1 + src/feature/thread-proxy.c | 4 ++-- src/feature/video-logger.c | 3 +++ src/gb/extra/proxy.c | 1 - src/gba/extra/proxy.c | 5 ++--- src/util/ring-fifo.c | 12 ++++++++++++ 6 files changed, 20 insertions(+), 6 deletions(-) diff --git a/include/mgba-util/ring-fifo.h b/include/mgba-util/ring-fifo.h index c5b1fdcc5..1cfaa3d00 100644 --- a/include/mgba-util/ring-fifo.h +++ b/include/mgba-util/ring-fifo.h @@ -20,6 +20,7 @@ struct RingFIFO { void RingFIFOInit(struct RingFIFO* buffer, size_t capacity); void RingFIFODeinit(struct RingFIFO* buffer); size_t RingFIFOCapacity(const struct RingFIFO* buffer); +size_t RingFIFOSize(const struct RingFIFO* buffer); void RingFIFOClear(struct RingFIFO* buffer); size_t RingFIFOWrite(struct RingFIFO* buffer, const void* value, size_t length); size_t RingFIFORead(struct RingFIFO* buffer, void* output, size_t length); diff --git a/src/feature/thread-proxy.c b/src/feature/thread-proxy.c index 8fe944846..196877002 100644 --- a/src/feature/thread-proxy.c +++ b/src/feature/thread-proxy.c @@ -121,7 +121,7 @@ static bool _readData(struct mVideoLogger* logger, void* data, size_t length, bo if (!block || read) { break; } - mLOG(GBA_VIDEO, DEBUG, "Proxy thread can't read VRAM. CPU thread asleep?"); + mLOG(GBA_VIDEO, DEBUG, "Can't read %"PRIz"u bytes. CPU thread asleep?", length); MutexLock(&proxyRenderer->mutex); ConditionWake(&proxyRenderer->fromThreadCond); ConditionWait(&proxyRenderer->toThreadCond, &proxyRenderer->mutex); @@ -142,7 +142,7 @@ static void _wait(struct mVideoLogger* logger) { _proxyThreadRecover(proxyRenderer); return; } - while (proxyRenderer->threadState == PROXY_THREAD_BUSY) { + while (RingFIFOSize(&proxyRenderer->dirtyQueue)) { ConditionWake(&proxyRenderer->toThreadCond); ConditionWait(&proxyRenderer->fromThreadCond, &proxyRenderer->mutex); } diff --git a/src/feature/video-logger.c b/src/feature/video-logger.c index 6f49e482d..be1c7b3f7 100644 --- a/src/feature/video-logger.c +++ b/src/feature/video-logger.c @@ -258,6 +258,9 @@ void mVideoLoggerRendererFlush(struct mVideoLogger* logger) { 0xDEADBEEF, }; logger->writeData(logger, &dirty, sizeof(dirty)); + if (logger->wait) { + logger->wait(logger); + } } void mVideoLoggerRendererFinishFrame(struct mVideoLogger* logger) { diff --git a/src/gb/extra/proxy.c b/src/gb/extra/proxy.c index 5de65ae84..c5230c88c 100644 --- a/src/gb/extra/proxy.c +++ b/src/gb/extra/proxy.c @@ -252,7 +252,6 @@ void GBVideoProxyRendererFinishFrame(struct GBVideoRenderer* renderer) { struct GBVideoProxyRenderer* proxyRenderer = (struct GBVideoProxyRenderer*) renderer; if (proxyRenderer->logger->block && proxyRenderer->logger->wait) { proxyRenderer->logger->lock(proxyRenderer->logger); - proxyRenderer->logger->wait(proxyRenderer->logger); } if (!proxyRenderer->logger->block) { proxyRenderer->backend->finishFrame(proxyRenderer->backend); diff --git a/src/gba/extra/proxy.c b/src/gba/extra/proxy.c index 8189c6f74..d7092f30c 100644 --- a/src/gba/extra/proxy.c +++ b/src/gba/extra/proxy.c @@ -146,6 +146,8 @@ static bool _parsePacket(struct mVideoLogger* logger, const struct mVideoLoggerD if (item->address <= SIZE_VRAM - 0x1000) { logger->readData(logger, &logger->vram[item->address >> 1], 0x1000, true); proxyRenderer->backend->writeVRAM(proxyRenderer->backend, item->address); + } else { + logger->readData(logger, NULL, 0x1000, true); } break; case DIRTY_SCANLINE: @@ -250,7 +252,6 @@ void GBAVideoProxyRendererFinishFrame(struct GBAVideoRenderer* renderer) { struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer; if (proxyRenderer->logger->block && proxyRenderer->logger->wait) { proxyRenderer->logger->lock(proxyRenderer->logger); - proxyRenderer->logger->wait(proxyRenderer->logger); } if (!proxyRenderer->logger->block) { proxyRenderer->backend->finishFrame(proxyRenderer->backend); @@ -268,7 +269,6 @@ static void GBAVideoProxyRendererGetPixels(struct GBAVideoRenderer* renderer, si proxyRenderer->logger->lock(proxyRenderer->logger); // Insert an extra item into the queue to make sure it gets flushed mVideoLoggerRendererFlush(proxyRenderer->logger); - proxyRenderer->logger->wait(proxyRenderer->logger); } proxyRenderer->backend->getPixels(proxyRenderer->backend, stride, pixels); if (proxyRenderer->logger->block && proxyRenderer->logger->wait) { @@ -282,7 +282,6 @@ static void GBAVideoProxyRendererPutPixels(struct GBAVideoRenderer* renderer, si proxyRenderer->logger->lock(proxyRenderer->logger); // Insert an extra item into the queue to make sure it gets flushed mVideoLoggerRendererFlush(proxyRenderer->logger); - proxyRenderer->logger->wait(proxyRenderer->logger); } proxyRenderer->backend->putPixels(proxyRenderer->backend, stride, pixels); if (proxyRenderer->logger->block && proxyRenderer->logger->wait) { diff --git a/src/util/ring-fifo.c b/src/util/ring-fifo.c index 39c10934a..0d5b40266 100644 --- a/src/util/ring-fifo.c +++ b/src/util/ring-fifo.c @@ -22,6 +22,18 @@ size_t RingFIFOCapacity(const struct RingFIFO* buffer) { return buffer->capacity; } +size_t RingFIFOSize(const struct RingFIFO* buffer) { + const void* read; + const void* write; + ATOMIC_LOAD(read, buffer->readPtr); + ATOMIC_LOAD(write, buffer->readPtr); + if (read <= write) { + return (uintptr_t) write - (uintptr_t) read; + } else { + return buffer->capacity - (uintptr_t) read + (uintptr_t) write; + } +} + void RingFIFOClear(struct RingFIFO* buffer) { ATOMIC_STORE(buffer->readPtr, buffer->data); ATOMIC_STORE(buffer->writePtr, buffer->data); From 749038dd183b742e77dbaf270c387d457d6a437f Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 23 Sep 2018 13:55:14 -0700 Subject: [PATCH 36/50] Qt: Use libvorbis instead of vorbis --- src/platform/qt/VideoView.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/platform/qt/VideoView.cpp b/src/platform/qt/VideoView.cpp index 75ae3fb01..a1aeee61b 100644 --- a/src/platform/qt/VideoView.cpp +++ b/src/platform/qt/VideoView.cpp @@ -51,6 +51,7 @@ VideoView::VideoView(QWidget* parent) if (s_acodecMap.empty()) { s_acodecMap["mp3"] = "libmp3lame"; s_acodecMap["opus"] = "libopus"; + s_acodecMap["vorbis"] = "libvorbis"; s_acodecMap["uncompressed"] = "pcm_s16le"; } if (s_vcodecMap.empty()) { From 41c08151f3815af843491d1659f9770c4c115e6d Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 23 Sep 2018 19:41:36 -0700 Subject: [PATCH 37/50] Qt: Fix tearing issues --- src/platform/qt/CoreController.cpp | 12 +++++------- src/platform/qt/CoreController.h | 4 ++-- src/platform/qt/DisplayQt.cpp | 2 +- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/platform/qt/CoreController.cpp b/src/platform/qt/CoreController.cpp index f81eb6c9b..b8ac73de5 100644 --- a/src/platform/qt/CoreController.cpp +++ b/src/platform/qt/CoreController.cpp @@ -46,6 +46,7 @@ CoreController::CoreController(mCore* core, QObject* parent) m_buffers[0].fill(0xFF); m_buffers[1].fill(0xFF); m_activeBuffer = &m_buffers[0]; + m_completeBuffer = m_buffers[0]; m_threadContext.core->setVideoBuffer(m_threadContext.core, reinterpret_cast(m_activeBuffer->data()), size.width()); @@ -209,12 +210,9 @@ CoreController::~CoreController() { m_threadContext.core->deinit(m_threadContext.core); } -color_t* CoreController::drawContext() { +const color_t* CoreController::drawContext() { QMutexLocker locker(&m_mutex); - if (!m_completeBuffer) { - return nullptr; - } - return reinterpret_cast(m_completeBuffer->data()); + return reinterpret_cast(m_completeBuffer.constData()); } bool CoreController::isPaused() { @@ -790,7 +788,7 @@ int CoreController::updateAutofire() { void CoreController::finishFrame() { QMutexLocker locker(&m_mutex); - m_completeBuffer = m_activeBuffer; + memcpy(m_completeBuffer.data(), m_activeBuffer->constData(), m_activeBuffer->size()); // TODO: Generalize this to triple buffering? m_activeBuffer = &m_buffers[0]; @@ -798,7 +796,7 @@ void CoreController::finishFrame() { m_activeBuffer = &m_buffers[1]; } // Copy contents to avoid issues when doing frameskip - memcpy(m_activeBuffer->data(), m_completeBuffer->data(), m_activeBuffer->size()); + memcpy(m_activeBuffer->data(), m_completeBuffer.constData(), m_activeBuffer->size()); m_threadContext.core->setVideoBuffer(m_threadContext.core, reinterpret_cast(m_activeBuffer->data()), screenDimensions().width()); for (auto& action : m_frameActions) { diff --git a/src/platform/qt/CoreController.h b/src/platform/qt/CoreController.h index 4ea647402..ec6b7d998 100644 --- a/src/platform/qt/CoreController.h +++ b/src/platform/qt/CoreController.h @@ -58,7 +58,7 @@ public: mCoreThread* thread() { return &m_threadContext; } - color_t* drawContext(); + const color_t* drawContext(); bool isPaused(); bool hasStarted(); @@ -174,7 +174,7 @@ private: QByteArray m_buffers[2]; QByteArray* m_activeBuffer; - QByteArray* m_completeBuffer = nullptr; + QByteArray m_completeBuffer; std::unique_ptr m_cacheSet; std::unique_ptr m_override; diff --git a/src/platform/qt/DisplayQt.cpp b/src/platform/qt/DisplayQt.cpp index 846382f3a..6043a7399 100644 --- a/src/platform/qt/DisplayQt.cpp +++ b/src/platform/qt/DisplayQt.cpp @@ -51,7 +51,7 @@ void DisplayQt::filter(bool filter) { void DisplayQt::framePosted() { update(); - color_t* buffer = m_context->drawContext(); + const color_t* buffer = m_context->drawContext(); if (const_cast(m_backing).bits() == reinterpret_cast(buffer)) { return; } From 5d28145b525e81de9c531b1dbc531203d9827e03 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 23 Sep 2018 20:32:58 -0700 Subject: [PATCH 38/50] Util: Fix RingFIFOSize... --- src/util/ring-fifo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/ring-fifo.c b/src/util/ring-fifo.c index 0d5b40266..bdaac75aa 100644 --- a/src/util/ring-fifo.c +++ b/src/util/ring-fifo.c @@ -26,7 +26,7 @@ size_t RingFIFOSize(const struct RingFIFO* buffer) { const void* read; const void* write; ATOMIC_LOAD(read, buffer->readPtr); - ATOMIC_LOAD(write, buffer->readPtr); + ATOMIC_LOAD(write, buffer->writePtr); if (read <= write) { return (uintptr_t) write - (uintptr_t) read; } else { From 00f5e2ea2a585cf71a545a2150e382d9129ab4fb Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Mon, 24 Sep 2018 08:31:38 -0700 Subject: [PATCH 39/50] GB Audio: Fix channel 1, 2 reset --- src/gb/audio.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gb/audio.c b/src/gb/audio.c index 6c8b7bfe1..994eaeedb 100644 --- a/src/gb/audio.c +++ b/src/gb/audio.c @@ -95,7 +95,7 @@ void GBAudioInit(struct GBAudio* audio, size_t samples, uint8_t* nr52, enum GBAu audio->sampleEvent.context = audio; audio->sampleEvent.name = "GB Audio Sample"; audio->sampleEvent.callback = _sample; - audio->ch1Event.priority = 0x18; + audio->sampleEvent.priority = 0x18; } void GBAudioDeinit(struct GBAudio* audio) { @@ -218,6 +218,7 @@ void GBAudioWriteNR14(struct GBAudio* audio, uint8_t value) { } } if (audio->playingCh1 && audio->ch1.envelope.dead != 2) { + _updateSquareChannel(&audio->ch1); mTimingDeschedule(audio->timing, &audio->ch1Event); mTimingSchedule(audio->timing, &audio->ch1Event, 0); } @@ -266,6 +267,7 @@ void GBAudioWriteNR24(struct GBAudio* audio, uint8_t value) { } } if (audio->playingCh2 && audio->ch2.envelope.dead != 2) { + _updateSquareChannel(&audio->ch2); mTimingDeschedule(audio->timing, &audio->ch2Event); mTimingSchedule(audio->timing, &audio->ch2Event, 0); } From 4a72f5f56267bf331341d1470b684328827b6247 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Mon, 24 Sep 2018 09:49:25 -0700 Subject: [PATCH 40/50] Test: Add threaded video option to mgba-perf --- src/platform/test/perf-main.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/platform/test/perf-main.c b/src/platform/test/perf-main.c index 2f96057f2..8de4fb72e 100644 --- a/src/platform/test/perf-main.c +++ b/src/platform/test/perf-main.c @@ -29,11 +29,12 @@ #include #include -#define PERF_OPTIONS "DF:L:NPS:" +#define PERF_OPTIONS "DF:L:NPS:T" #define PERF_USAGE \ "\nBenchmark options:\n" \ " -F FRAMES Run for the specified number of FRAMES before exiting\n" \ " -N Disable video rendering entirely\n" \ + " -T Use threaded video rendering\n" \ " -P CSV output, useful for parsing\n" \ " -S SEC Run for SEC in-game seconds before exiting\n" \ " -L FILE Load a savestate when starting the test\n" \ @@ -41,6 +42,7 @@ struct PerfOpts { bool noVideo; + bool threadedVideo; bool csv; unsigned duration; unsigned frames; @@ -89,7 +91,7 @@ int main(int argc, char** argv) { struct mLogger logger = { .log = _log }; mLogSetDefaultLogger(&logger); - struct PerfOpts perfOpts = { false, false, 0, 0, 0, false }; + struct PerfOpts perfOpts = { false, false, false, 0, 0, 0, false }; struct mSubParser subparser = { .usage = PERF_USAGE, .parse = _parsePerfOpts, @@ -162,6 +164,12 @@ bool _mPerfRunCore(const char* fname, const struct mArguments* args, const struc mCoreConfigInit(&core->config, "perf"); mCoreConfigLoad(&core->config); + if (perfOpts->threadedVideo) { + mCoreConfigSetOverrideIntValue(&core->config, "threadedVideo", 1); + } else { + mCoreConfigSetOverrideIntValue(&core->config, "threadedVideo", 0); + } + struct mCoreOptions opts = {}; mCoreConfigMap(&core->config, &opts); opts.audioSync = false; @@ -200,6 +208,8 @@ bool _mPerfRunCore(const char* fname, const struct mArguments* args, const struc const char* rendererName; if (perfOpts->noVideo) { rendererName = "none"; + } else if (perfOpts->threadedVideo) { + rendererName = "threaded-software"; } else { rendererName = "software"; } @@ -313,6 +323,9 @@ static bool _parsePerfOpts(struct mSubParser* parser, int option, const char* ar case 'S': opts->duration = strtoul(arg, 0, 10); return !errno; + case 'T': + opts->threadedVideo = true; + return true; case 'L': opts->savestate = strdup(arg); return true; From 7198544873b8402285f36720902a99d6fac69aa1 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Mon, 24 Sep 2018 10:30:47 -0700 Subject: [PATCH 41/50] CMake: Add debug-separated packages --- CMakeLists.txt | 36 ++++++++++++++++++++++++++++++--- src/platform/qt/CMakeLists.txt | 8 ++++++++ src/platform/sdl/CMakeLists.txt | 8 ++++++++ 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7f4d22a9d..d8a402504 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -90,7 +90,7 @@ source_group("Utilities" FILES ${UTIL_SRC}) include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/src) if(NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type (e.g. Release or Debug)" FORCE) + set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type (e.g. Release, RelWithDebInfo, or Debug)" FORCE) endif() if(UNIX OR WIN32_UNIX_PATHS) @@ -264,6 +264,14 @@ if(APPLE OR CMAKE_C_COMPILER_ID STREQUAL "GNU" AND BUILD_LTO) set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -flto") endif() +if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang" OR CMAKE_C_COMPILER_ID STREQUAL "AppleClang") + find_program(OBJCOPY ${cross_prefix}objcopy) + find_program(STRIP ${cross_prefix}strip) + + set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELEASE} -gdwarf") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} -gdwarf") +endif() + if(BUILD_BBB OR BUILD_RASPI OR BUILD_PANDORA) if(NOT BUILD_EGL) add_definitions(-DCOLOR_16_BIT -DCOLOR_5_6_5) @@ -1043,9 +1051,18 @@ set(CPACK_STRIP_FILES ON) if(DISTBUILD) set(CPACK_ARCHIVE_COMPONENT_INSTALL ON) + if(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo" AND BUILD_SHARED) + if(NOT APPLE) + add_custom_command(TARGET ${BINARY_NAME} POST_BUILD COMMAND "${OBJCOPY}" --only-keep-debug "$" "$.dSYM") + add_custom_command(TARGET ${BINARY_NAME} POST_BUILD COMMAND "${STRIP}" -S "$") + install(FILES "$.dSYM" DESTINATION ${LIBDIR} COMPONENT lib${BINARY_NAME}-dbg) + endif() + endif() if(WIN32 OR APPLE) - set(CPACK_COMPONENTS_ALL ${BINARY_NAME} ${BINARY_NAME}-qt ${BINARY_NAME}-sdl ${BINARY_NAME}-perf) - set(CPACK_COMPONENTS_GROUPING ALL_COMPONENTS_IN_ONE) + set(CPACK_COMPONENTS_ALL ${BINARY_NAME} ${BINARY_NAME}-qt ${BINARY_NAME}-sdl ${BINARY_NAME}-qt-dbg ${BINARY_NAME}-sdl-dbg ${BINARY_NAME}-perf) + if(APPLE) + set(CPACK_COMPONENTS_GROUPING ALL_COMPONENTS_IN_ONE) + endif() elseif(3DS) set(CPACK_COMPONENTS_ALL ${BINARY_NAME} ${BINARY_NAME}-3ds ${BINARY_NAME}-perf) elseif(WII) @@ -1092,6 +1109,19 @@ if(SDL_FOUND) cpack_add_component(${BINARY_NAME}-sdl GROUP sdl) endif() +if(DISTBUILD AND CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") + cpack_add_component_group(debug PARENT_GROUP dev) + if(BUILD_SHARED AND NOT IS_EMBEDDED) + cpack_add_component(lib${BINARY_NAME}-dbg GROUP debug) + endif() + if(BUILD_QT) + cpack_add_component(${BINARY_NAME}-qt-dbg GROUP debug) + endif() + if(SDL_FOUND) + cpack_add_component(${BINARY_NAME}-sdl-dbg GROUP debug) + endif() +endif() + cpack_add_component_group(test PARENT_GROUP dev) cpack_add_component(${BINARY_NAME}-perf GROUP test) cpack_add_component(${BINARY_NAME}-fuzz GROUP test) diff --git a/src/platform/qt/CMakeLists.txt b/src/platform/qt/CMakeLists.txt index 510b5baa6..76e389c4b 100644 --- a/src/platform/qt/CMakeLists.txt +++ b/src/platform/qt/CMakeLists.txt @@ -348,3 +348,11 @@ elseif(WIN32) install(CODE "execute_process(COMMAND \"${BASH}\" \"${CMAKE_SOURCE_DIR}/tools/deploy-win.sh\" \"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.exe\" \"\${CMAKE_INSTALL_PREFIX}\" \"\$ENV{PWD}\" WORKING_DIRECTORY \"${CMAKE_BINARY_DIR}\")" COMPONENT ${BINARY_NAME}-qt) endif() endif() + +if(DISTBUILD AND CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") + if(NOT APPLE) + add_custom_command(TARGET ${BINARY_NAME}-qt POST_BUILD COMMAND "${OBJCOPY}" --only-keep-debug "$" "$.dSYM") + add_custom_command(TARGET ${BINARY_NAME}-qt POST_BUILD COMMAND "${STRIP}" -S "$") + install(FILES "$.dSYM" DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${BINARY_NAME}-qt-dbg) + endif() +endif() diff --git a/src/platform/sdl/CMakeLists.txt b/src/platform/sdl/CMakeLists.txt index f577c86ec..0c2fc771b 100644 --- a/src/platform/sdl/CMakeLists.txt +++ b/src/platform/sdl/CMakeLists.txt @@ -105,3 +105,11 @@ install(TARGETS ${BINARY_NAME}-sdl DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT if(UNIX) install(FILES ${CMAKE_SOURCE_DIR}/doc/mgba.6 DESTINATION ${MANDIR}/man6 COMPONENT ${BINARY_NAME}-sdl) endif() + +if(DISTBUILD AND CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") + if(NOT APPLE) + add_custom_command(TARGET ${BINARY_NAME}-sdl POST_BUILD COMMAND "${OBJCOPY}" --only-keep-debug "$" "$.dSYM") + add_custom_command(TARGET ${BINARY_NAME}-sdl POST_BUILD COMMAND "${STRIP}" -S "$") + install(FILES "$.dSYM" DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${BINARY_NAME}-sdl-dbg) + endif() +endif() From 909faa485ce4b19e9729d488fa70dfdd2f54c5c6 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Mon, 24 Sep 2018 16:52:06 -0700 Subject: [PATCH 42/50] Res: Update patrons --- res/patrons.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/res/patrons.txt b/res/patrons.txt index 4da58cb0e..deaca59b2 100644 --- a/res/patrons.txt +++ b/res/patrons.txt @@ -1,7 +1,8 @@ +Elijah Chondropoulos Jaime J. Denizard Fog Philip Horton +Oskenso Kashi Rohit Nirmal Rhys Powell -rootfather Yuri Kunde Schlesner From 776d8a7f7126aa6fe215a22c507a00e2aba9911a Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Mon, 24 Sep 2018 17:21:24 -0700 Subject: [PATCH 43/50] CHANGES: Update for 0.7 beta 1 --- CHANGES | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 15bf4355a..b3d69f100 100644 --- a/CHANGES +++ b/CHANGES @@ -99,13 +99,16 @@ Misc: - FFmpeg: Support lossless VP9 encoding - mGUI: Add fast forward toggle -0.6.3: (2017-04-14) +0.6 beta 1: (2018-09-24) +- Initial beta for 0.6 + +0.6.3: (2018-04-14) Bugfixes: - GB Audio: Revert unsigned audio changes - GB Video: Fix bad merge (fixes mgba.io/i/1040) - GBA Video: Fix OBJ blending regression (fixes mgba.io/i/1037) -0.6.2: (2017-04-03) +0.6.2: (2018-04-03) Bugfixes: - Core: Fix ROM patches not being unloaded when disabled (fixes mgba.io/i/962) - 3DS: Fix opening files in directory names with trailing slashes From 50622f9e557386192c7ff2d67921ad1c1ba04ec0 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 25 Sep 2018 11:16:30 -0700 Subject: [PATCH 44/50] PSP2: Fix audio crackling after fast forward --- CHANGES | 3 +++ src/platform/psp2/psp2-context.c | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/CHANGES b/CHANGES index b3d69f100..90e528c20 100644 --- a/CHANGES +++ b/CHANGES @@ -98,6 +98,9 @@ Misc: - Core: Remove broken option for whether rewinding restores save games - FFmpeg: Support lossless VP9 encoding - mGUI: Add fast forward toggle +Changes from beta 1: +Bugfixes: + - PSP2: Fix audio crackling after fast forward 0.6 beta 1: (2018-09-24) - Initial beta for 0.6 diff --git a/src/platform/psp2/psp2-context.c b/src/platform/psp2/psp2-context.c index 4ee45f59c..64f2e0798 100644 --- a/src/platform/psp2/psp2-context.c +++ b/src/platform/psp2/psp2-context.c @@ -280,6 +280,13 @@ uint16_t mPSP2PollInput(struct mGUIRunner* runner) { void mPSP2SetFrameLimiter(struct mGUIRunner* runner, bool limit) { UNUSED(runner); + if (!frameLimiter && limit) { + MutexLock(&audioContext.mutex); + while (audioContext.samples) { + ConditionWait(&audioContext.cond, &audioContext.mutex); + } + MutexUnlock(&audioContext.mutex); + } frameLimiter = limit; } From ec4e2e80d9b485fa98972f0e13affc986ec0f1de Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 25 Sep 2018 11:55:35 -0700 Subject: [PATCH 45/50] PSP2: Fix audio crackling when buffer is full --- CHANGES | 1 + src/platform/psp2/psp2-context.c | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index 90e528c20..0d9d77aec 100644 --- a/CHANGES +++ b/CHANGES @@ -101,6 +101,7 @@ Misc: Changes from beta 1: Bugfixes: - PSP2: Fix audio crackling after fast forward + - PSP2: Fix audio crackling when buffer is full 0.6 beta 1: (2018-09-24) - Initial beta for 0.6 diff --git a/src/platform/psp2/psp2-context.c b/src/platform/psp2/psp2-context.c index 64f2e0798..41e3a4a11 100644 --- a/src/platform/psp2/psp2-context.c +++ b/src/platform/psp2/psp2-context.c @@ -97,18 +97,23 @@ void mPSP2MapKey(struct mInputMap* map, int pspKey, int key) { static THREAD_ENTRY _audioThread(void* context) { struct mPSP2AudioContext* audio = (struct mPSP2AudioContext*) context; uint32_t zeroBuffer[PSP2_SAMPLES] = {0}; + void* buffer = zeroBuffer; int audioPort = sceAudioOutOpenPort(SCE_AUDIO_OUT_PORT_TYPE_MAIN, PSP2_SAMPLES, 48000, SCE_AUDIO_OUT_MODE_STEREO); while (audio->running) { MutexLock(&audio->mutex); - void* buffer; + if (buffer != zeroBuffer) { + // Can only happen in successive iterations + audio->samples -= PSP2_SAMPLES; + ConditionWake(&audio->cond); + } if (audio->samples >= PSP2_SAMPLES) { buffer = &audio->buffer[audio->readOffset]; - audio->samples -= PSP2_SAMPLES; audio->readOffset += PSP2_SAMPLES; if (audio->readOffset >= PSP2_AUDIO_BUFFER_SIZE) { audio->readOffset = 0; } - ConditionWake(&audio->cond); + // Don't mark samples as read until the next loop iteration to prevent + // writing to the buffer while being read (see above) } else { buffer = zeroBuffer; } From 76366ae70ac057d255a8470b46d436a421df3187 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 25 Sep 2018 15:15:22 -0700 Subject: [PATCH 46/50] Libretro: Add Game Boy cheat support --- CHANGES | 2 ++ src/platform/libretro/libretro.c | 57 +++++++++++++++++++++++--------- 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/CHANGES b/CHANGES index 0d9d77aec..ff5e64be4 100644 --- a/CHANGES +++ b/CHANGES @@ -99,6 +99,8 @@ Misc: - FFmpeg: Support lossless VP9 encoding - mGUI: Add fast forward toggle Changes from beta 1: +Features: + - Libretro: Add Game Boy cheat support Bugfixes: - PSP2: Fix audio crackling after fast forward - PSP2: Fix audio crackling when buffer is full diff --git a/src/platform/libretro/libretro.c b/src/platform/libretro/libretro.c index 91155eadf..eafc7fca1 100644 --- a/src/platform/libretro/libretro.c +++ b/src/platform/libretro/libretro.c @@ -605,24 +605,49 @@ void retro_cheat_set(unsigned index, bool enabled, const char* code) { cheatSet = device->createSet(device, NULL); mCheatAddSet(device, cheatSet); } - // Convert the super wonky unportable libretro format to something normal - char realCode[] = "XXXXXXXX XXXXXXXX"; - size_t len = strlen(code) + 1; // Include null terminator - size_t i, pos; - for (i = 0, pos = 0; i < len; ++i) { - if (isspace((int) code[i]) || code[i] == '+') { - realCode[pos] = ' '; - } else { - realCode[pos] = code[i]; +// Convert the super wonky unportable libretro format to something normal +#ifdef M_CORE_GBA + if (core->platform(core) == PLATFORM_GBA) { + char realCode[] = "XXXXXXXX XXXXXXXX"; + size_t len = strlen(code) + 1; // Include null terminator + size_t i, pos; + for (i = 0, pos = 0; i < len; ++i) { + if (isspace((int) code[i]) || code[i] == '+') { + realCode[pos] = ' '; + } else { + realCode[pos] = code[i]; + } + if ((pos == 13 && (realCode[pos] == ' ' || !realCode[pos])) || pos == 17) { + realCode[pos] = '\0'; + mCheatAddLine(cheatSet, realCode, 0); + pos = 0; + continue; + } + ++pos; } - if ((pos == 13 && (realCode[pos] == ' ' || !realCode[pos])) || pos == 17) { - realCode[pos] = '\0'; - mCheatAddLine(cheatSet, realCode, 0); - pos = 0; - continue; - } - ++pos; } +#endif +#ifdef M_CORE_GB + if (core->platform(core) == PLATFORM_GB) { + char realCode[] = "XXX-XXX-XXX"; + size_t len = strlen(code) + 1; // Include null terminator + size_t i, pos; + for (i = 0, pos = 0; i < len; ++i) { + if (isspace((int) code[i]) || code[i] == '+') { + realCode[pos] = '\0'; + } else { + realCode[pos] = code[i]; + } + if (pos == 11 || !realCode[pos]) { + realCode[pos] = '\0'; + mCheatAddLine(cheatSet, realCode, 0); + pos = 0; + continue; + } + ++pos; + } + } +#endif } unsigned retro_get_region(void) { From a6367030db01638c1106058ef4fe5cd53fdc1fb7 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 25 Sep 2018 23:33:34 -0700 Subject: [PATCH 47/50] Doc: Update man pages --- doc/mgba-qt.6 | 12 +++++------- doc/mgba.6 | 16 +++++----------- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/doc/mgba-qt.6 b/doc/mgba-qt.6 index 3cacd0ce0..ca4255f38 100644 --- a/doc/mgba-qt.6 +++ b/doc/mgba-qt.6 @@ -17,6 +17,7 @@ .Op Fl l Ar loglevel .Op Fl p Ar patchfile .Op Fl s Ar n +.Op Fl t Ar statefile .Ar file .Sh DESCRIPTION .Nm @@ -71,13 +72,7 @@ is a bitmask defining which types of messages to log: .It 32 \(en stub messages for unimplemented features .It -256 \(en in\(hygame errors -.It -512 \(en software interrupts -.It -1024 \(en emulator status messages -.It -2048 \(en serial I/O messages +64 \(en in\(hygame errors .El The default is to log warnings, errors, fatal errors, and status messages. .It Fl p Ar patchfile , Fl -patch Ar patchfile @@ -86,6 +81,9 @@ Specify a patch file in BPS, IPS, or UPS format. Skip every .Ar n frames. +.It Fl t Ar statefile , Fl -savestate Ar statefile +Load initial game state from +.Ar statefile . .El .Sh CONTROLS The default controls are as follows: diff --git a/doc/mgba.6 b/doc/mgba.6 index 4f8862e6d..640c878c6 100644 --- a/doc/mgba.6 +++ b/doc/mgba.6 @@ -18,7 +18,7 @@ .Op Fl l Ar loglevel .Op Fl p Ar patchfile .Op Fl s Ar n -.Op Fl v Ar moviefile +.Op Fl t Ar statefile .Ar file .Sh DESCRIPTION .Nm @@ -79,13 +79,7 @@ is a bitmask defining which types of messages to log: .It 32 \(en stub messages for unimplemented features .It -256 \(en in\(hygame errors -.It -512 \(en software interrupts -.It -1024 \(en emulator status messages -.It -2048 \(en serial I/O messages +64 \(en in\(hygame errors .El The default is to log warnings, errors, fatal errors, and status messages. .It Fl p Ar patchfile , Fl -patch Ar patchfile @@ -94,9 +88,9 @@ Specify a patch file in BPS, IPS, or UPS format. Skip every .Ar n frames. -.It Fl v Ar moviefile , Fl -movie Ar moviefile -Play back a movie of recording input from -.Ar moviefile . +.It Fl t Ar statefile , Fl -savestate Ar statefile +Load initial game state from +.Ar statefile . .El .Sh CONTROLS The default controls are as follows: From 20e0c8f303285bd3ce03f30cda62bda9996b6e9d Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Wed, 26 Sep 2018 09:17:06 -0700 Subject: [PATCH 48/50] 3DS: Fix unused screens not clearing (fixes #1184) --- CHANGES | 1 + src/platform/3ds/main.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/CHANGES b/CHANGES index ff5e64be4..522c5fdcb 100644 --- a/CHANGES +++ b/CHANGES @@ -104,6 +104,7 @@ Features: Bugfixes: - PSP2: Fix audio crackling after fast forward - PSP2: Fix audio crackling when buffer is full + - 3DS: Fix unused screens not clearing (fixes mgba.io/i/1184) 0.6 beta 1: (2018-09-24) - Initial beta for 0.6 diff --git a/src/platform/3ds/main.c b/src/platform/3ds/main.c index d9243e875..f08290edc 100644 --- a/src/platform/3ds/main.c +++ b/src/platform/3ds/main.c @@ -194,7 +194,9 @@ static void _drawStart(void) { C3D_FrameBegin(flags); ctrStartFrame(); + C3D_FrameDrawOn(bottomScreen[doubleBuffer]); C3D_RenderTargetClear(bottomScreen[doubleBuffer], C3D_CLEAR_COLOR, 0, 0); + C3D_FrameDrawOn(topScreen[doubleBuffer]); C3D_RenderTargetClear(topScreen[doubleBuffer], C3D_CLEAR_COLOR, 0, 0); } From 031081b0055f4266a4f90862e382360fe3a27c0c Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Wed, 26 Sep 2018 17:06:04 -0700 Subject: [PATCH 49/50] mGUI: Add SGB border configuration option --- CHANGES | 2 ++ src/feature/gui/gui-config.c | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/CHANGES b/CHANGES index 522c5fdcb..a7652188a 100644 --- a/CHANGES +++ b/CHANGES @@ -105,6 +105,8 @@ Bugfixes: - PSP2: Fix audio crackling after fast forward - PSP2: Fix audio crackling when buffer is full - 3DS: Fix unused screens not clearing (fixes mgba.io/i/1184) +Misc: + - mGUI: Add SGB border configuration option 0.6 beta 1: (2018-09-24) - Initial beta for 0.6 diff --git a/src/feature/gui/gui-config.c b/src/feature/gui/gui-config.c index 6d6aa75af..3a938fade 100644 --- a/src/feature/gui/gui-config.c +++ b/src/feature/gui/gui-config.c @@ -108,6 +108,16 @@ void mGUIShowConfig(struct mGUIRunner* runner, struct GUIMenuItem* extra, size_t .title = "Select SGB BIOS path", .data = "sgb.bios", }; + *GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) { + .title = "Enable SGB borders", + .data = "sgb.borders", + .submenu = 0, + .state = true, + .validStates = (const char*[]) { + "Off", "On" + }, + .nStates = 2 + }; #endif size_t i; const char* mapNames[GUI_MAX_INPUTS + 1]; From 40d2b0f77ad3503b99019589441b639748e38214 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Wed, 26 Sep 2018 17:06:53 -0700 Subject: [PATCH 50/50] Wii: Fix handling of core video dimensions changing --- src/platform/wii/main.c | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/src/platform/wii/main.c b/src/platform/wii/main.c index 185771dd6..1885f5c37 100644 --- a/src/platform/wii/main.c +++ b/src/platform/wii/main.c @@ -229,15 +229,6 @@ static void reconfigureScreen(struct mGUIRunner* runner) { double ratio = GBAAudioCalculateRatio(1, audioSampleRate, 1); blip_set_rates(runner->core->getAudioChannel(runner->core, 0), runner->core->frequency(runner->core), 48000 * ratio); blip_set_rates(runner->core->getAudioChannel(runner->core, 1), runner->core->frequency(runner->core), 48000 * ratio); - - runner->core->desiredVideoDimensions(runner->core, &corew, &coreh); - int hfactor = vmode->fbWidth / (corew * wAdjust); - int vfactor = vmode->efbHeight / (coreh * hAdjust); - if (hfactor > vfactor) { - scaleFactor = vfactor; - } else { - scaleFactor = hfactor; - } } } } @@ -812,7 +803,7 @@ void _unpaused(struct mGUIRunner* runner) { } void _drawFrame(struct mGUIRunner* runner, bool faded) { - UNUSED(runner); + runner->core->desiredVideoDimensions(runner->core, &corew, &coreh); uint32_t color = 0xFFFFFF3F; if (!faded) { color |= 0xC0; @@ -838,9 +829,9 @@ void _drawFrame(struct mGUIRunner* runner, bool faded) { GX_InvalidateTexAll(); GX_LoadTexObj(&tex, GX_TEXMAP0); - GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_S16, 0); - s16 vertWidth = TEX_W; - s16 vertHeight = TEX_H; + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0); + s16 vertWidth = corew; + s16 vertHeight = coreh; if (filterMode == FM_LINEAR_2x) { Mtx44 proj; @@ -850,19 +841,19 @@ void _drawFrame(struct mGUIRunner* runner, bool faded) { GX_Begin(GX_QUADS, GX_VTXFMT0, 4); GX_Position2s16(0, TEX_H * 2); GX_Color1u32(0xFFFFFFFF); - GX_TexCoord2s16(0, 1); + GX_TexCoord2f32(0, 1); GX_Position2s16(TEX_W * 2, TEX_H * 2); GX_Color1u32(0xFFFFFFFF); - GX_TexCoord2s16(1, 1); + GX_TexCoord2f32(1, 1); GX_Position2s16(TEX_W * 2, 0); GX_Color1u32(0xFFFFFFFF); - GX_TexCoord2s16(1, 0); + GX_TexCoord2f32(1, 0); GX_Position2s16(0, 0); GX_Color1u32(0xFFFFFFFF); - GX_TexCoord2s16(0, 0); + GX_TexCoord2f32(0, 0); GX_End(); GX_SetTexCopySrc(0, 0, TEX_W * 2, TEX_H * 2); @@ -871,6 +862,14 @@ void _drawFrame(struct mGUIRunner* runner, bool faded) { GX_LoadTexObj(&rescaleTex, GX_TEXMAP0); } + int hfactor = vmode->fbWidth / (corew * wAdjust); + int vfactor = vmode->efbHeight / (coreh * hAdjust); + if (hfactor > vfactor) { + scaleFactor = vfactor; + } else { + scaleFactor = hfactor; + } + if (screenMode == SM_PA) { vertWidth *= scaleFactor; vertHeight *= scaleFactor; @@ -885,19 +884,19 @@ void _drawFrame(struct mGUIRunner* runner, bool faded) { GX_Begin(GX_QUADS, GX_VTXFMT0, 4); GX_Position2s16(0, vertHeight); GX_Color1u32(color); - GX_TexCoord2s16(0, 1); + GX_TexCoord2f32(0, coreh / (float) TEX_H); GX_Position2s16(vertWidth, vertHeight); GX_Color1u32(color); - GX_TexCoord2s16(1, 1); + GX_TexCoord2f32(corew / (float) TEX_W, coreh / (float) TEX_H); GX_Position2s16(vertWidth, 0); GX_Color1u32(color); - GX_TexCoord2s16(1, 0); + GX_TexCoord2f32(corew / (float) TEX_W, 0); GX_Position2s16(0, 0); GX_Color1u32(color); - GX_TexCoord2s16(0, 0); + GX_TexCoord2f32(0, 0); GX_End(); }