From 9bbdd2ba350aac319ca9b24eba042ce81070df9f Mon Sep 17 00:00:00 2001
From: Vicki Pfau <vi@endrift.com>
Date: Sun, 4 Oct 2020 18:10:47 -0700
Subject: [PATCH 01/10] Qt: Fix drawing on macOS break when using OpenGL (fixes
 #1899)

---
 CHANGES                       | 1 +
 src/platform/qt/DisplayGL.cpp | 4 ++++
 2 files changed, 5 insertions(+)

diff --git a/CHANGES b/CHANGES
index dabd10d1c..79fea85f4 100644
--- a/CHANGES
+++ b/CHANGES
@@ -69,6 +69,7 @@ Other fixes:
  - Qt: Add dummy English translation file (fixes mgba.io/i/1469)
  - Qt: Fix Battle Chip view not displaying chips on some DPI settings
  - Qt: Fix camera image being upside-down sometimes (fixes mgba.io/i/829 again)
+ - Qt: Fix drawing on macOS break when using OpenGL (fixes mgba.io/i/1899)
  - mGUI: Fix closing down a game if an exit is signalled
  - mVL: Fix injecting accidentally draining non-injection buffer
  - SM83: Simplify register pair access on big endian
diff --git a/src/platform/qt/DisplayGL.cpp b/src/platform/qt/DisplayGL.cpp
index d1e619c09..be545fe78 100644
--- a/src/platform/qt/DisplayGL.cpp
+++ b/src/platform/qt/DisplayGL.cpp
@@ -145,7 +145,9 @@ void DisplayGL::pauseDrawing() {
 		m_isDrawing = false;
 		CoreController::Interrupter interrupter(m_context);
 		QMetaObject::invokeMethod(m_painter, "pause", Qt::BlockingQueuedConnection);
+#ifndef Q_OS_MAC
 		setUpdatesEnabled(true);
+#endif
 	}
 }
 
@@ -154,7 +156,9 @@ void DisplayGL::unpauseDrawing() {
 		m_isDrawing = true;
 		CoreController::Interrupter interrupter(m_context);
 		QMetaObject::invokeMethod(m_painter, "unpause", Qt::BlockingQueuedConnection);
+#ifndef Q_OS_MAC
 		setUpdatesEnabled(false);
+#endif
 	}
 }
 

From 830aea2f57c37a69c23b7e3c2ece59c4a4c36567 Mon Sep 17 00:00:00 2001
From: Vicki Pfau <vi@endrift.com>
Date: Sun, 4 Oct 2020 22:06:14 -0700
Subject: [PATCH 02/10] Qt: Load/save bytes from memory viewer in the order
 visible (fixes #1900)

---
 CHANGES | 1 +
 1 file changed, 1 insertion(+)

diff --git a/CHANGES b/CHANGES
index 79fea85f4..08ad44c08 100644
--- a/CHANGES
+++ b/CHANGES
@@ -70,6 +70,7 @@ Other fixes:
  - Qt: Fix Battle Chip view not displaying chips on some DPI settings
  - Qt: Fix camera image being upside-down sometimes (fixes mgba.io/i/829 again)
  - Qt: Fix drawing on macOS break when using OpenGL (fixes mgba.io/i/1899)
+ - Qt: Load/save bytes from memory viewer in the order visible (fixes mgba.io/i/1900)
  - mGUI: Fix closing down a game if an exit is signalled
  - mVL: Fix injecting accidentally draining non-injection buffer
  - SM83: Simplify register pair access on big endian

From 3f10823ef560e2c492a6ae5aa885155e35b92d0c Mon Sep 17 00:00:00 2001
From: Vicki Pfau <vi@endrift.com>
Date: Mon, 5 Oct 2020 00:25:00 -0700
Subject: [PATCH 03/10] GBA Video: Fix deferred blending when OBJWIN matches
 window (fixes #1905)

---
 CHANGES                            |  1 +
 src/gba/renderers/video-software.c | 19 ++++++++++---------
 2 files changed, 11 insertions(+), 9 deletions(-)

diff --git a/CHANGES b/CHANGES
index 08ad44c08..8974a0317 100644
--- a/CHANGES
+++ b/CHANGES
@@ -48,6 +48,7 @@ Emulation fixes:
  - GBA Video: Fix rare regression blending semitransparent sprites (fixes mgba.io/i/1876)
  - GBA Video: Emulate sprite cycle limits in OpenGL renderer (fixes mgba.io/i/1635)
  - GBA Video: Do not affect OBJ pixel priority when writing OBJWIN (fixes mgba.io/i/1890)
+ - GBA Video: Fix deferred blending when OBJWIN matches window (fixes mgba.io/i/1905)
  - SM83: Emulate HALT bug
 Other fixes:
  - 3DS: Redo video sync to be more precise
diff --git a/src/gba/renderers/video-software.c b/src/gba/renderers/video-software.c
index 9df7983e7..1a746e2a5 100644
--- a/src/gba/renderers/video-software.c
+++ b/src/gba/renderers/video-software.c
@@ -644,17 +644,18 @@ static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* render
 	}
 	if (softwareRenderer->forceTarget1 && (softwareRenderer->blendEffect == BLEND_DARKEN || softwareRenderer->blendEffect == BLEND_BRIGHTEN)) {
 		x = 0;
-		uint32_t mask = FLAG_REBLEND | FLAG_IS_BACKGROUND;
-		uint32_t match = FLAG_REBLEND;
-		if (GBARegisterDISPCNTIsObjwinEnable(softwareRenderer->dispcnt)) {
-			mask |= FLAG_OBJWIN;
-			if (GBAWindowControlIsBlendEnable(softwareRenderer->objwin.packed)) {
-				match |= FLAG_OBJWIN;
-			}
-		}
 		for (w = 0; w < softwareRenderer->nWindows; ++w) {
 			int end = softwareRenderer->windows[w].endX;
-			if (!GBAWindowControlIsBlendEnable(softwareRenderer->windows[w].control.packed)) {
+			uint32_t mask = FLAG_REBLEND | FLAG_IS_BACKGROUND;
+			uint32_t match = FLAG_REBLEND;
+			bool objBlend = GBAWindowControlIsBlendEnable(softwareRenderer->objwin.packed);
+			bool winBlend = GBAWindowControlIsBlendEnable(softwareRenderer->windows[w].control.packed);
+			if (GBARegisterDISPCNTIsObjwinEnable(softwareRenderer->dispcnt) && objBlend != winBlend) {
+				mask |= FLAG_OBJWIN;
+				if (objBlend) {
+					match |= FLAG_OBJWIN;
+				}
+			} else if (!winBlend) {
 				x = end;
 				continue;
 			}

From 78343663c443cb936296e4b705832d46bc6d4387 Mon Sep 17 00:00:00 2001
From: Lothar Serra Mari <mail@serra.me>
Date: Mon, 5 Oct 2020 18:27:06 +0200
Subject: [PATCH 04/10] Win32: Fix supressing start menu item creation

---
 src/platform/windows/setup/setup.iss.in | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/platform/windows/setup/setup.iss.in b/src/platform/windows/setup/setup.iss.in
index fb164136a..1771aed4f 100644
--- a/src/platform/windows/setup/setup.iss.in
+++ b/src/platform/windows/setup/setup.iss.in
@@ -89,7 +89,7 @@ Source: "{#ResDir}\shaders\*"; DestDir: "{app}\shaders\"; Flags: ignoreversion r
 Source: "{#ResDir}\licenses\*"; DestDir: "{app}\licenses\"; Flags: ignoreversion recursesubdirs
 
 [Icons]
-Name: "{commonstartmenu}\{#AppName}"; Filename: "{app}\{#AppName}.exe"
+Name: "{commonstartmenu}\{#AppName}"; Filename: "{app}\{#AppName}.exe"; Check: not WizardNoIcons
 Name: "{commondesktop}\{#AppName}"; Filename: "{app}\{#AppName}.exe"; Tasks: desktopicon
 
 [Run]

From 22950a679673274f5b857d6c8570a7ac22c5120b Mon Sep 17 00:00:00 2001
From: Lothar Serra Mari <mail@serra.me>
Date: Mon, 5 Oct 2020 18:39:50 +0200
Subject: [PATCH 05/10] Win32: Add more language options to the installer

NOTE: Requires the content of the directory

	https://github.com/jrsoftware/issrc/tree/main/Files/Languages/Unofficial

to be present in the "Languages/" directory on the build host!
---
 src/platform/windows/setup/setup.iss.in | 24 ++++++++++++++++++------
 1 file changed, 18 insertions(+), 6 deletions(-)

diff --git a/src/platform/windows/setup/setup.iss.in b/src/platform/windows/setup/setup.iss.in
index 1771aed4f..9421d8fa9 100644
--- a/src/platform/windows/setup/setup.iss.in
+++ b/src/platform/windows/setup/setup.iss.in
@@ -64,11 +64,17 @@ ArchitecturesInstallIn64BitMode=x64
 ArchitecturesAllowed=x86 x64
 
 [Languages]
-Name: "english"; MessagesFile: "compiler:Default.isl"
-Name: "french"; MessagesFile: "compiler:Languages\French.isl"
 Name: "german"; MessagesFile: "compiler:Languages\German.isl"
-Name: "italian"; MessagesFile: "compiler:Languages\Italian.isl"
+Name: "english"; MessagesFile: "compiler:Default.isl"
 Name: "spanish"; MessagesFile: "compiler:Languages\Spanish.isl"
+Name: "french"; MessagesFile: "compiler:Languages\French.isl"
+Name: "italian"; MessagesFile: "compiler:Languages\Italian.isl"
+Name: "japanese"; MessagesFile: "compiler:Languages\Japanese.isl"
+Name: "korean"; MessagesFile: "compiler:Languages\Korean.isl"
+Name: "dutch"; MessagesFile: "compiler:Languages\Dutch.isl"
+Name: "russian"; MessagesFile: "compiler:Languages\Russian.isl"
+Name: "turkish"; MessagesFile: "compiler:Languages\Turkish.isl"
+Name: "chinesesimplified"; MessagesFile: "compiler:Languages\ChineseSimplified.isl"
 
 [Tasks]
 Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"
@@ -83,7 +89,7 @@ Source: "{#BinDir}\{#AppName2}-sdl.exe"; DestDir: "{app}"; Flags: ignoreversion
 Source: "{#BinDir}\CHANGES.txt"; DestDir: "{app}\"; Flags: ignoreversion isreadme
 Source: "{#BinDir}\LICENSE.txt"; DestDir: "{app}\"; Flags: ignoreversion
 Source: "{#ResDir}\nointro.dat"; DestDir: "{app}\"; Flags: ignoreversion
-Source: "{#BinDir}\README.html"; DestDir: "{app}\"; Flags: ignoreversion isreadme; Languages: english italian spanish
+Source: "{#BinDir}\README.html"; DestDir: "{app}\"; Flags: ignoreversion isreadme; Languages: not german
 Source: "{#BinDir}\README_DE.html"; DestDir: "{app}\"; DestName: "LIESMICH.html"; Flags: ignoreversion isreadme; Languages: german
 Source: "{#ResDir}\shaders\*"; DestDir: "{app}\shaders\"; Flags: ignoreversion recursesubdirs
 Source: "{#ResDir}\licenses\*"; DestDir: "{app}\licenses\"; Flags: ignoreversion recursesubdirs
@@ -129,9 +135,15 @@ procedure InitializeWizard();
         begin
         if ExpandConstant('{language}') = 'english' then noReleaseWarning := 'You are about to install a development build of {#AppName}.' + #13#10#13#10 + 'Development builds may contain bugs that are not yet discovered. Please report any issues you can find to the GitHub project page.';
         if ExpandConstant('{language}') = 'french' then noReleaseWarning := 'You are about to install a development build of {#AppName}.' + #13#10#13#10 + 'Development builds may contain bugs that are not yet discovered. Please report any issues you can find to the GitHub project page.';
-        if ExpandConstant('{language}') = 'italian' then noReleaseWarning := 'You are about to install a development build of {#AppName}.' + #13#10#13#10 + 'Development builds may contain bugs that are not yet discovered. Please report any issues you can find to the GitHub project page.';
+        if ExpandConstant('{language}') = 'german' then noReleaseWarning := 'Sie m�chten eine Entwicklerversion von {#AppName} installieren.' + #13#10#13#10 + 'Entwicklerversionen k�nnen bislang noch nicht endeckte Fehler beinhalten. Bitte melden Sie alle Fehler, die Sie finden k�nnen, auf der GitHub-Projektseite.';        if ExpandConstant('{language}') = 'spanish' then noReleaseWarning := 'You are about to install a development build of {#AppName}.' + #13#10#13#10 + 'Development builds may contain bugs that are not yet discovered. Please report any issues you can find to the GitHub project page.';
         if ExpandConstant('{language}') = 'spanish' then noReleaseWarning := 'You are about to install a development build of {#AppName}.' + #13#10#13#10 + 'Development builds may contain bugs that are not yet discovered. Please report any issues you can find to the GitHub project page.';
-        if ExpandConstant('{language}') = 'german' then noReleaseWarning := 'Sie m�chten eine Entwicklerversion von {#AppName} installieren.' + #13#10#13#10 + 'Entwicklerversionen k�nnen bislang noch nicht endeckte Fehler beinhalten. Bitte melden Sie alle Fehler, die Sie finden k�nnen, auf der GitHub-Projektseite.';
+        if ExpandConstant('{language}') = 'italian' then noReleaseWarning := 'You are about to install a development build of {#AppName}.' + #13#10#13#10 + 'Development builds may contain bugs that are not yet discovered. Please report any issues you can find to the GitHub project page.';
+        if ExpandConstant('{language}') = 'japanese' then noReleaseWarning := 'You are about to install a development build of {#AppName}.' + #13#10#13#10 + 'Development builds may contain bugs that are not yet discovered. Please report any issues you can find to the GitHub project page.';
+        if ExpandConstant('{language}') = 'korean' then noReleaseWarning := 'You are about to install a development build of {#AppName}.' + #13#10#13#10 + 'Development builds may contain bugs that are not yet discovered. Please report any issues you can find to the GitHub project page.';
+        if ExpandConstant('{language}') = 'dutch' then noReleaseWarning := 'You are about to install a development build of {#AppName}.' + #13#10#13#10 + 'Development builds may contain bugs that are not yet discovered. Please report any issues you can find to the GitHub project page.';
+        if ExpandConstant('{language}') = 'russian' then noReleaseWarning := 'You are about to install a development build of {#AppName}.' + #13#10#13#10 + 'Development builds may contain bugs that are not yet discovered. Please report any issues you can find to the GitHub project page.';
+        if ExpandConstant('{language}') = 'turkish' then noReleaseWarning := 'You are about to install a development build of {#AppName}.' + #13#10#13#10 + 'Development builds may contain bugs that are not yet discovered. Please report any issues you can find to the GitHub project page.';
+        if ExpandConstant('{language}') = 'chinesesimplified' then noReleaseWarning := 'You are about to install a development build of {#AppName}.' + #13#10#13#10 + 'Development builds may contain bugs that are not yet discovered. Please report any issues you can find to the GitHub project page.';
         MsgBox(noReleaseWarning, mbInformation, MB_OK);
       end;
   end;

From 7b3900ff937341eafac2e2ef3f05a0e17e2c4e94 Mon Sep 17 00:00:00 2001
From: Vicki Pfau <vi@endrift.com>
Date: Tue, 6 Oct 2020 01:11:34 -0700
Subject: [PATCH 06/10] Qt: Load/save bytes from memory viewer in the order
 visible (fixes #1900)

---
 src/platform/qt/MemoryModel.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/platform/qt/MemoryModel.cpp b/src/platform/qt/MemoryModel.cpp
index 856592a30..67b09e05e 100644
--- a/src/platform/qt/MemoryModel.cpp
+++ b/src/platform/qt/MemoryModel.cpp
@@ -246,7 +246,7 @@ QByteArray MemoryModel::serialize() {
 		for (uint32_t i = m_selection.first; i < m_selection.second; i += m_align) {
 			quint16 datum = m_core->rawRead16(m_core, i, m_currentBank);
 			char leDatum[2];
-			STORE_16LE(datum, 0, (uint16_t*) leDatum);
+			STORE_16BE(datum, 0, (uint16_t*) leDatum);
 			bytes.append(leDatum, 2);
 		}
 		break;
@@ -254,7 +254,7 @@ QByteArray MemoryModel::serialize() {
 		for (uint32_t i = m_selection.first; i < m_selection.second; i += m_align) {
 			quint32 datum = m_core->rawRead32(m_core, i, m_currentBank);
 			char leDatum[4];
-			STORE_32LE(datum, 0, (uint16_t*) leDatum);
+			STORE_32BE(datum, 0, (uint32_t*) leDatum);
 			bytes.append(leDatum, 4);
 		}
 		break;
@@ -275,7 +275,7 @@ void MemoryModel::deserialize(const QByteArray& bytes) {
 		for (int i = 0; i < bytes.size(); i += m_align, addr += m_align) {
 			char leDatum[2]{ bytes[i], bytes[i + 1] };
 			uint16_t datum;
-			LOAD_16LE(datum, 0, leDatum);
+			LOAD_16BE(datum, 0, leDatum);
 			m_core->rawWrite16(m_core, addr, m_currentBank, datum);
 		}
 		break;
@@ -283,7 +283,7 @@ void MemoryModel::deserialize(const QByteArray& bytes) {
 		for (int i = 0; i < bytes.size(); i += m_align, addr += m_align) {
 			char leDatum[4]{ bytes[i], bytes[i + 1], bytes[i + 2], bytes[i + 3] };
 			uint32_t datum;
-			LOAD_32LE(datum, 0, leDatum);
+			LOAD_32BE(datum, 0, leDatum);
 			m_core->rawWrite32(m_core, addr, m_currentBank, datum);
 		}
 		break;

From 8b8ff65821357ba2e436ce799b17c86be8d45730 Mon Sep 17 00:00:00 2001
From: Vicki Pfau <vi@endrift.com>
Date: Sun, 11 Oct 2020 16:37:49 -0700
Subject: [PATCH 07/10] GBA Video: Fix mode 4 transparency in OpenGL (fixes
 #1907)

---
 CHANGES                | 1 +
 src/gba/renderers/gl.c | 6 +++++-
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/CHANGES b/CHANGES
index 8974a0317..9cc50fabc 100644
--- a/CHANGES
+++ b/CHANGES
@@ -49,6 +49,7 @@ Emulation fixes:
  - GBA Video: Emulate sprite cycle limits in OpenGL renderer (fixes mgba.io/i/1635)
  - GBA Video: Do not affect OBJ pixel priority when writing OBJWIN (fixes mgba.io/i/1890)
  - GBA Video: Fix deferred blending when OBJWIN matches window (fixes mgba.io/i/1905)
+ - GBA Video: Fix mode 4 transparency in OpenGL (fixes mgba.io/i/1907)
  - SM83: Emulate HALT bug
 Other fixes:
  - 3DS: Redo video sync to be more precise
diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c
index 8856ec4ef..31c16f5cd 100644
--- a/src/gba/renderers/gl.c
+++ b/src/gba/renderers/gl.c
@@ -391,7 +391,11 @@ static const char* const _renderMode4 =
 	"	}\n"
 	"	int address = charBase + (coord.x >> 8) + (coord.y >> 8) * size.x;\n"
 	"	int twoEntries = texelFetch(vram, ivec2((address >> 1) & 255, address >> 9), 0).r;\n"
-	"	int paletteEntry = palette[(twoEntries >> (8 * (address & 1)) & 255)];\n"
+	"	int entry = (twoEntries >> (8 * (address & 1))) & 255;\n"
+	"	if (entry == 0) {\n"
+	"		discard;\n"
+	"	}\n"
+	"	int paletteEntry = palette[entry];\n"
 	"	color = vec4(PALETTE_ENTRY(paletteEntry), 1.);\n"
 	"}";
 

From ba566f334d4b7d34d7572a9fde8d7510d07ff162 Mon Sep 17 00:00:00 2001
From: Vicki Pfau <vi@endrift.com>
Date: Sun, 11 Oct 2020 22:42:23 -0700
Subject: [PATCH 08/10] GB Core: Add reload config option for SGB borders

---
 src/gb/core.c      | 6 ++++++
 src/gb/serialize.c | 1 -
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/src/gb/core.c b/src/gb/core.c
index 61cedc774..23ebb294d 100644
--- a/src/gb/core.c
+++ b/src/gb/core.c
@@ -292,6 +292,12 @@ static void _GBCoreReloadConfigOption(struct mCore* core, const char* option, co
 		}
 		return;
 	}
+	if (strcmp("sgb.borders", option) == 0) {
+		if (mCoreConfigGetIntValue(config, "sgb.borders", &fakeBool)) {
+			gb->video.sgbBorders = fakeBool;
+			gb->video.renderer->enableSGBBorder(gb->video.renderer, fakeBool);
+		}
+	}
 }
 
 static void _GBCoreDesiredVideoDimensions(const struct mCore* core, unsigned* width, unsigned* height) {
diff --git a/src/gb/serialize.c b/src/gb/serialize.c
index 002b5a650..35a54c752 100644
--- a/src/gb/serialize.c
+++ b/src/gb/serialize.c
@@ -256,7 +256,6 @@ void GBSGBSerialize(struct GB* gb, struct GBSerializedState* state) {
 	if (gb->video.renderer->sgbAttributes) {
 		memcpy(state->sgb.attributes, gb->video.renderer->sgbAttributes, sizeof(state->sgb.attributes));
 	}
-	gb->video.renderer->enableSGBBorder(gb->video.renderer, gb->video.sgbBorders);
 }
 
 void GBSGBDeserialize(struct GB* gb, const struct GBSerializedState* state) {

From 7a9e1e4600f0bba80a7734c6d0c3504b4495485d Mon Sep 17 00:00:00 2001
From: Vicki Pfau <vi@endrift.com>
Date: Sun, 11 Oct 2020 22:44:26 -0700
Subject: [PATCH 09/10] Qt: Fix stride changing when toggling SGB borders
 (fixes #1898)

---
 CHANGES                            |  1 +
 src/platform/qt/CoreController.cpp | 12 ++++++++++++
 2 files changed, 13 insertions(+)

diff --git a/CHANGES b/CHANGES
index 9cc50fabc..31599e7ce 100644
--- a/CHANGES
+++ b/CHANGES
@@ -73,6 +73,7 @@ Other fixes:
  - Qt: Fix camera image being upside-down sometimes (fixes mgba.io/i/829 again)
  - Qt: Fix drawing on macOS break when using OpenGL (fixes mgba.io/i/1899)
  - Qt: Load/save bytes from memory viewer in the order visible (fixes mgba.io/i/1900)
+ - Qt: Fix stride changing when toggling SGB borders (fixes mgba.io/i/1898)
  - mGUI: Fix closing down a game if an exit is signalled
  - mVL: Fix injecting accidentally draining non-injection buffer
  - SM83: Simplify register pair access on big endian
diff --git a/src/platform/qt/CoreController.cpp b/src/platform/qt/CoreController.cpp
index 99fc0299d..2f4edb6f5 100644
--- a/src/platform/qt/CoreController.cpp
+++ b/src/platform/qt/CoreController.cpp
@@ -263,11 +263,23 @@ void CoreController::loadConfig(ConfigController* config) {
 	m_fastForwardMute = config->getOption("fastForwardMute", -1).toInt();
 	mCoreConfigCopyValue(&m_threadContext.core->config, config->config(), "volume");
 	mCoreConfigCopyValue(&m_threadContext.core->config, config->config(), "mute");
+
+	QSize sizeBefore = screenDimensions();
 	mCoreLoadForeignConfig(m_threadContext.core, config->config());
+	QSize sizeAfter = screenDimensions();
 	if (hasStarted()) {
 		updateFastForward();
 		mCoreThreadRewindParamsChanged(&m_threadContext);
 	}
+	if (sizeBefore != sizeAfter) {
+		m_threadContext.core->setVideoBuffer(m_threadContext.core, reinterpret_cast<color_t*>(m_activeBuffer.data()), sizeAfter.width());
+#ifdef M_CORE_GB
+		mCoreConfigSetIntValue(&m_threadContext.core->config, "sgb.borders", 0);
+		m_threadContext.core->reloadConfigOption(m_threadContext.core, "sgb.borders", nullptr);
+		mCoreConfigCopyValue(&m_threadContext.core->config, config->config(), "sgb.borders");
+		m_threadContext.core->reloadConfigOption(m_threadContext.core, "sgb.borders", nullptr);
+#endif
+	}
 }
 
 #ifdef USE_DEBUGGERS

From 3b93e762ae248f80d2a19b7e3e39721304e7adad Mon Sep 17 00:00:00 2001
From: Vicki Pfau <vi@endrift.com>
Date: Sun, 11 Oct 2020 23:56:51 -0700
Subject: [PATCH 10/10] GB Video: Clean up OBJ parsing outside of renderer

---
 include/mgba/internal/gb/renderers/proxy.h    |  3 --
 include/mgba/internal/gb/renderers/software.h |  3 ++
 include/mgba/internal/gb/video.h              |  3 +-
 src/gb/extra/proxy.c                          | 18 ++++-----
 src/gb/renderers/software.c                   | 37 ++++++++++++++++---
 src/gb/video.c                                | 12 +-----
 6 files changed, 45 insertions(+), 31 deletions(-)

diff --git a/include/mgba/internal/gb/renderers/proxy.h b/include/mgba/internal/gb/renderers/proxy.h
index 244c5e39b..bde4e2ddb 100644
--- a/include/mgba/internal/gb/renderers/proxy.h
+++ b/include/mgba/internal/gb/renderers/proxy.h
@@ -17,9 +17,6 @@ struct GBVideoProxyRenderer {
 	struct GBVideoRenderer d;
 	struct GBVideoRenderer* backend;
 	struct mVideoLogger* logger;
-
-	struct GBObj objThisLine[40];
-	size_t oamMax;
 };
 
 void GBVideoProxyRendererCreate(struct GBVideoProxyRenderer* renderer, struct GBVideoRenderer* backend);
diff --git a/include/mgba/internal/gb/renderers/software.h b/include/mgba/internal/gb/renderers/software.h
index fe4b1ff98..11e107f6d 100644
--- a/include/mgba/internal/gb/renderers/software.h
+++ b/include/mgba/internal/gb/renderers/software.h
@@ -40,6 +40,9 @@ struct GBVideoSoftwareRenderer {
 	GBRegisterLCDC lcdc;
 	enum GBModel model;
 
+	struct GBObj obj[10];
+	int objMax;
+
 	int16_t objOffsetX;
 	int16_t objOffsetY;
 	int16_t offsetScx;
diff --git a/include/mgba/internal/gb/video.h b/include/mgba/internal/gb/video.h
index 13473776a..cd5a1e8d1 100644
--- a/include/mgba/internal/gb/video.h
+++ b/include/mgba/internal/gb/video.h
@@ -77,7 +77,7 @@ struct GBVideoRenderer {
 	void (*writeVRAM)(struct GBVideoRenderer* renderer, uint16_t address);
 	void (*writePalette)(struct GBVideoRenderer* renderer, int index, uint16_t value);
 	void (*writeOAM)(struct GBVideoRenderer* renderer, uint16_t oam);
-	void (*drawRange)(struct GBVideoRenderer* renderer, int startX, int endX, int y, struct GBObj* objOnLine, size_t nObj);
+	void (*drawRange)(struct GBVideoRenderer* renderer, int startX, int endX, int y);
 	void (*finishScanline)(struct GBVideoRenderer* renderer, int y);
 	void (*finishFrame)(struct GBVideoRenderer* renderer);
 	void (*enableSGBBorder)(struct GBVideoRenderer* renderer, bool enable);
@@ -139,7 +139,6 @@ struct GBVideo {
 	int vramCurrentBank;
 
 	union GBOAM oam;
-	struct GBObj objThisLine[10];
 	int objMax;
 
 	int bcpIndex;
diff --git a/src/gb/extra/proxy.c b/src/gb/extra/proxy.c
index f7b21cbda..24758cd2a 100644
--- a/src/gb/extra/proxy.c
+++ b/src/gb/extra/proxy.c
@@ -19,7 +19,7 @@ static void GBVideoProxyRendererWriteSGBPacket(struct GBVideoRenderer* renderer,
 static void GBVideoProxyRendererWriteVRAM(struct GBVideoRenderer* renderer, uint16_t address);
 static void GBVideoProxyRendererWriteOAM(struct GBVideoRenderer* renderer, uint16_t oam);
 static void GBVideoProxyRendererWritePalette(struct GBVideoRenderer* renderer, int address, uint16_t value);
-static void GBVideoProxyRendererDrawRange(struct GBVideoRenderer* renderer, int startX, int endX, int y, struct GBObj* obj, size_t oamMax);
+static void GBVideoProxyRendererDrawRange(struct GBVideoRenderer* renderer, int startX, int endX, int y);
 static void GBVideoProxyRendererFinishScanline(struct GBVideoRenderer* renderer, int y);
 static void GBVideoProxyRendererFinishFrame(struct GBVideoRenderer* renderer);
 static void GBVideoProxyRendererEnableSGBBorder(struct GBVideoRenderer* renderer, bool enable);
@@ -68,8 +68,6 @@ static void _reset(struct GBVideoProxyRenderer* proxyRenderer) {
 	memcpy(proxyRenderer->logger->oam, &proxyRenderer->d.oam->raw, GB_SIZE_OAM);
 	memcpy(proxyRenderer->logger->vram, proxyRenderer->d.vram, GB_SIZE_VRAM);
 
-	proxyRenderer->oamMax = 0;
-
 	mVideoLoggerRendererReset(proxyRenderer->logger);
 }
 
@@ -117,6 +115,7 @@ void GBVideoProxyRendererDeinit(struct GBVideoRenderer* renderer) {
 static bool _parsePacket(struct mVideoLogger* logger, const struct mVideoLoggerDirtyInfo* item) {
 	struct GBVideoProxyRenderer* proxyRenderer = logger->context;
 	uint8_t sgbPacket[16];
+	struct GBObj legacyBuffer[40];
 	switch (item->type) {
 	case DIRTY_REGISTER:
 		proxyRenderer->backend->writeVideoRegister(proxyRenderer->backend, item->address, item->value);
@@ -145,7 +144,7 @@ static bool _parsePacket(struct mVideoLogger* logger, const struct mVideoLoggerD
 		break;
 	case DIRTY_RANGE:
 		if (item->value < item->value2 && item->value2 <= GB_VIDEO_HORIZONTAL_PIXELS && item->address < GB_VIDEO_VERTICAL_PIXELS) {
-			proxyRenderer->backend->drawRange(proxyRenderer->backend, item->value, item->value2, item->address, proxyRenderer->objThisLine, proxyRenderer->oamMax);
+			proxyRenderer->backend->drawRange(proxyRenderer->backend, item->value, item->value2, item->address);
 		}
 		break;
 	case DIRTY_FRAME:
@@ -154,12 +153,10 @@ static bool _parsePacket(struct mVideoLogger* logger, const struct mVideoLoggerD
 	case DIRTY_BUFFER:
 		switch (item->address) {
 		case BUFFER_OAM:
-			proxyRenderer->oamMax = item->value2 / sizeof(struct GBObj);
-			if (proxyRenderer->oamMax > 40) {
-				proxyRenderer->oamMax = 0;
+			if (item->value2 / sizeof(struct GBObj) > 40) {
 				return false;
 			}
-			logger->readData(logger, &proxyRenderer->objThisLine, item->value2, true);
+			logger->readData(logger, legacyBuffer, item->value2, true);
 			break;
 		case BUFFER_SGB:
 			logger->readData(logger, sgbPacket, 16, true);
@@ -228,12 +225,11 @@ void GBVideoProxyRendererWriteOAM(struct GBVideoRenderer* renderer, uint16_t oam
 	mVideoLoggerRendererWriteOAM(proxyRenderer->logger, oam, ((uint8_t*) proxyRenderer->d.oam->raw)[oam]);
 }
 
-void GBVideoProxyRendererDrawRange(struct GBVideoRenderer* renderer, int startX, int endX, int y, struct GBObj* obj, size_t oamMax) {
+void GBVideoProxyRendererDrawRange(struct GBVideoRenderer* renderer, int startX, int endX, int y) {
 	struct GBVideoProxyRenderer* proxyRenderer = (struct GBVideoProxyRenderer*) renderer;
 	if (!proxyRenderer->logger->block) {
-		proxyRenderer->backend->drawRange(proxyRenderer->backend, startX, endX, y, obj, oamMax);
+		proxyRenderer->backend->drawRange(proxyRenderer->backend, startX, endX, y);
 	}
-	mVideoLoggerWriteBuffer(proxyRenderer->logger, BUFFER_OAM, 0, oamMax * sizeof(*obj), obj);	
 	mVideoLoggerRendererDrawRange(proxyRenderer->logger, startX, endX, y);	
 }
 
diff --git a/src/gb/renderers/software.c b/src/gb/renderers/software.c
index 637bae496..f6c4f9818 100644
--- a/src/gb/renderers/software.c
+++ b/src/gb/renderers/software.c
@@ -18,7 +18,7 @@ static void GBVideoSoftwareRendererWriteSGBPacket(struct GBVideoRenderer* render
 static void GBVideoSoftwareRendererWritePalette(struct GBVideoRenderer* renderer, int index, uint16_t value);
 static void GBVideoSoftwareRendererWriteVRAM(struct GBVideoRenderer* renderer, uint16_t address);
 static void GBVideoSoftwareRendererWriteOAM(struct GBVideoRenderer* renderer, uint16_t oam);
-static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, int startX, int endX, int y, struct GBObj* obj, size_t oamMax);
+static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, int startX, int endX, int y);
 static void GBVideoSoftwareRendererFinishScanline(struct GBVideoRenderer* renderer, int y);
 static void GBVideoSoftwareRendererFinishFrame(struct GBVideoRenderer* renderer);
 static void GBVideoSoftwareRendererEnableSGBBorder(struct GBVideoRenderer* renderer, bool enable);
@@ -499,7 +499,31 @@ static void GBVideoSoftwareRendererWriteOAM(struct GBVideoRenderer* renderer, ui
 	// Nothing to do
 }
 
-static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, int startX, int endX, int y, struct GBObj* obj, size_t oamMax) {
+static void _cleanOAM(struct GBVideoSoftwareRenderer* renderer, int y) {
+	// TODO: GBC differences
+	// TODO: Optimize
+	int spriteHeight = 8;
+	if (GBRegisterLCDCIsObjSize(renderer->lcdc)) {
+		spriteHeight = 16;
+	}
+	int o = 0;
+	int i;
+	for (i = 0; i < 40 && o < 10; ++i) {
+		uint8_t oy = renderer->d.oam->obj[i].y;
+		if (y < oy - 16 || y >= oy - 16 + spriteHeight) {
+			continue;
+		}
+		// TODO: Sort
+		renderer->obj[o] = renderer->d.oam->obj[i];
+		++o;
+		if (o == 10) {
+			break;
+		}
+	}
+	renderer->objMax = o;
+}
+
+static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, int startX, int endX, int y) {
 	struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
 	softwareRenderer->lastY = y;
 	softwareRenderer->lastX = endX;
@@ -536,9 +560,12 @@ static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, i
 	}
 
 	if (GBRegisterLCDCIsObjEnable(softwareRenderer->lcdc) && !softwareRenderer->d.disableOBJ) {
-		size_t i;
-		for (i = 0; i < oamMax; ++i) {
-			GBVideoSoftwareRendererDrawObj(softwareRenderer, &obj[i], startX, endX, y);
+		if (startX == 0) {
+			_cleanOAM(softwareRenderer, y);
+		}
+		int i;
+		for (i = 0; i < softwareRenderer->objMax; ++i) {
+			GBVideoSoftwareRendererDrawObj(softwareRenderer, &softwareRenderer->obj[i], startX, endX, y);
 		}
 	}
 
diff --git a/src/gb/video.c b/src/gb/video.c
index 6c207297d..8bf173797 100644
--- a/src/gb/video.c
+++ b/src/gb/video.c
@@ -403,26 +403,18 @@ void _updateFrameCount(struct mTiming* timing, void* context, uint32_t cyclesLat
 }
 
 static void _cleanOAM(struct GBVideo* video, int y) {
-	// TODO: GBC differences
-	// TODO: Optimize
-	video->objMax = 0;
 	int spriteHeight = 8;
 	if (GBRegisterLCDCIsObjSize(video->p->memory.io[REG_LCDC])) {
 		spriteHeight = 16;
 	}
 	int o = 0;
 	int i;
-	for (i = 0; i < 40; ++i) {
+	for (i = 0; i < 40 && o < 10; ++i) {
 		uint8_t oy = video->oam.obj[i].y;
 		if (y < oy - 16 || y >= oy - 16 + spriteHeight) {
 			continue;
 		}
-		// TODO: Sort
-		video->objThisLine[o] = video->oam.obj[i];
 		++o;
-		if (o == 10) {
-			break;
-		}
 	}
 	video->objMax = o;
 }
@@ -442,7 +434,7 @@ void GBVideoProcessDots(struct GBVideo* video, uint32_t cyclesLate) {
 		oldX = 0;
 	}
 	if (video->frameskipCounter <= 0) {
-		video->renderer->drawRange(video->renderer, oldX, video->x, video->ly, video->objThisLine, video->objMax);
+		video->renderer->drawRange(video->renderer, oldX, video->x, video->ly);
 	}
 }