Compare commits

...

28 Commits

Author SHA1 Message Date
Rosalie Wanders 8ec4d7c0ab 3rdParty: experimental changes to mupen64plus-core 2025-05-29 00:55:26 +02:00
Rosalie Wanders 7014796e5f 3rdParty: experimental changes to mupen64plus-video-parallel 2025-05-29 00:55:26 +02:00
Rosalie Wanders 183fb2b626 3rdParty: backport some patches from simple64 to mupen64plus-video-parallel 2025-05-29 00:55:26 +02:00
Rosalie Wanders 188fa1b6f5 3rdParty: backport some patches from simple64 to mupen64plus-rsp-parallel 2025-05-29 00:55:26 +02:00
Rosalie Wanders 70cf93a0e9 3rdParty: backport some patches from simple64 to mupen64plus-core 2025-05-29 00:55:26 +02:00
Rosalie Wanders c8a26ea9d4 3rdParty: add small64 signature to open_rom() 2025-05-29 00:55:26 +02:00
Rosalie Wanders a74cff50f8 Package: add vulkan-headers to makedepends of PKGBUILD 2025-05-20 09:35:34 +02:00
Rosalie Wanders d4ac45a9c5 Package: v0.7.9 2025-05-19 23:59:01 +02:00
Rosalie Wanders 32aebfec1a RMG-Core: change default of RomBrowser_MaxItems to 2048 2025-05-19 23:51:06 +02:00
Rosalie Wanders aee7da8068 RMG: hide RomBrowserSearchWidget by default 2025-05-19 23:47:36 +02:00
Rosalie Wanders 078361e2e6 RMG: use const reference for slots 2025-05-19 23:41:28 +02:00
Rosalie Wanders e0cae9c1a9 RMG: disable action_View_Game{List,Grid} during emulation 2025-05-19 23:34:01 +02:00
Rosalie Wanders c8d46ee919 RMG: showSearchLineEdit -> showSearchWidget 2025-05-19 23:23:47 +02:00
Rosalie Wanders c5965b3940 RMG: introduce RomBrowserSearchWidget 2025-05-19 23:06:39 +02:00
Rosalie Wanders affb0ee0ee RMG: change placeholder text of searchLineEdit in RomBrowserWidget.cpp 2025-05-19 23:06:39 +02:00
Rosalie Wanders dd6ea4f22a RMG-Core: change casing of default KeyBinding_ViewSearch setting value 2025-05-19 23:06:39 +02:00
Rosalie Wanders 006a7c8eff RMG: re-add nullptr check in RomBrowserWidget::getCurrentData() 2025-05-18 19:32:59 +02:00
Rosalie Wanders 5f10f39ac0 3rdParty: update mupen64plus-rsp-hle 2025-05-18 19:19:12 +02:00
Rosalie Wanders 6e1df7fc79 3rdParty: update mupen64plus-video-GLideN64 2025-05-18 19:18:44 +02:00
Rosalie Wanders 5cab9282e7 3rdParty: allow cropping each side separately in mupen64plus-video-parallel 2025-05-18 19:17:12 +02:00
Rosalie Wanders 1c6d8a6f59 RMG: fix ROM browser index mapping 2025-05-18 19:02:29 +02:00
Rosalie Wanders c43f43e634 RMG-Core: Keybinding_ViewLog -> KeyBinding_ViewLog 2025-05-06 01:28:09 +02:00
Rosalie Wanders 409aac2caa RMG-Core: remove unrequired include 2025-05-06 01:28:09 +02:00
Rosalie Wanders 21b187dacc RMG: implement search for the ROM browser 2025-05-06 01:28:09 +02:00
Rosalie Wanders a110f48fad RMG-Core: add KeyBinding_ViewSearch setting 2025-05-06 00:48:47 +02:00
Rosalie Wanders 1f24d20054 RMG-Core: fix name having incorrect count in CoreGetCurrentRomHeader() 2025-05-03 16:38:56 +02:00
Rosalie Wanders 8e61b79ecf 3rdParty: update mupen64plus-core 2025-05-02 15:08:02 +02:00
Rosalie Wanders f459c456de RMG-Core: use const reference for local functions in Settings.cpp 2025-05-02 14:36:19 +02:00
73 changed files with 996 additions and 449 deletions
+3 -3
View File
@@ -1,14 +1,14 @@
# Maintainer: Rosalie Wanders <rosalie@mailbox.org>
pkgname=rmg
pkgver=0.7.8
pkgrel=1
pkgver=0.7.9
pkgrel=2
pkgdesc="Rosalie's Mupen GUI"
arch=('x86_64' 'aarch64')
url="https://github.com/Rosalie241/$pkgname"
license=('GPL3')
depends=("hidapi" "libsamplerate" "speexdsp" "minizip" "sdl2" "sdl2_net" "zlib" "freetype2" "qt6-base" "qt6-svg" "qt6-websockets")
makedepends=("git" "nasm" "cmake")
makedepends=("git" "nasm" "cmake" "vulkan-headers")
source=("git+https://github.com/Rosalie241/$pkgname.git#tag=v$pkgver")
sha256sums=('SKIP')
+1 -1
View File
@@ -1,5 +1,5 @@
Name: RMG
Version: 0.7.8
Version: 0.7.9
Release: %autorelease
Summary: Rosalie's Mupen GUI
@@ -29,6 +29,20 @@
</screenshot>
</screenshots>
<releases>
<release version="v0.7.9" date="2025-05-19" type="stable">
<description>
<p>Changes:</p>
<ul>
<li>Fix netplay allocating UDP packets during emulation</li>
<li>Fix 'Game List' and 'Game Grid' UI elements not being disabled during emulation</li>
<li>Fix compilation error with newer minizip-ng versions</li>
<li>Add search feature to the ROM browser</li>
<li>Add crop settings for each side in mupen64plus-video-parallel</li>
<li>Change default ROM search limit to 2048</li>
<li>Update mupen64plus-video-GLideN64 and mupen64plus-rsp-hle</li>
</ul>
</description>
</release>
<release version="v0.7.8" date="2025-03-23" type="stable">
<description>
<p>Changes:</p>
+25 -19
View File
@@ -26,26 +26,20 @@ jobs:
arch: x64
- cc: Clang
arch: x86
name: Linux / ${{ matrix.cc }} / ${{ matrix.arch }}
runs-on: ubuntu-22.04
name: Linux / ${{ matrix.cc }} ${{ matrix.arch }}
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Get build dependencies and arrange the environment
run: |
export C_CLANG_SUFFIX="-15" C_GCC_SUFFIX="-12"
export BUILD_DEPS="libfreetype6-dev libgl1-mesa-dev libglu1-mesa-dev libpng-dev libsdl1.2-dev libsdl2-dev libvulkan-dev zlib1g-dev"
export BUILD_DEPS="libfreetype6-dev libgl1-mesa-dev libglu1-mesa-dev libpng-dev libsdl2-dev libvulkan-dev zlib1g-dev"
./.github/workflows/scripts/ci_install_ubuntu_deps.sh ${{ matrix.arch }} ${{ matrix.cc }}
- name: Build and related stuff, backup binaries
run: |
export C_CLANG_SUFFIX="-15" C_GCC_SUFFIX="-12"
export PATH="$(pwd)/.github/workflows/scripts:${PATH}"
export CONFIG_OVERRIDE="ACCURATE_FPU=1 NEW_DYNAREC=1 SDL_CONFIG="sdl-config""
export CONFIG_OVERRIDE="ACCURATE_FPU=1 NEW_DYNAREC=1"
ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }}
export CONFIG_OVERRIDE="ACCURATE_FPU=1 NEW_DYNAREC=1 SDL_CONFIG="sdl2-config""
ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }}
export CONFIG_OVERRIDE="ACCURATE_FPU=0 NEW_DYNAREC=0 SDL_CONFIG="sdl-config" POSTFIX="-old""
ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }}
export CONFIG_OVERRIDE="ACCURATE_FPU=0 NEW_DYNAREC=0 SDL_CONFIG="sdl2-config" POSTFIX="-old""
export CONFIG_OVERRIDE="ACCURATE_FPU=0 NEW_DYNAREC=0 POSTFIX="-old""
ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }} makepkg
- name: Upload artifact
if: matrix.cc == 'GCC'
@@ -63,12 +57,24 @@ jobs:
arch: x64
cross: x86_64
env: MINGW64
gbc: 0
- cc: GCC
arch: x86
cross: i686
env: MINGW32
name: Windows / MSYS2 ${{ matrix.cc }} / ${{ matrix.arch }}
runs-on: windows-2022
gbc: 0
- cc: GCC
arch: x64
cross: ucrt-x86_64
env: UCRT64
gbc: 1
- cc: Clang
arch: x64
cross: clang-x86_64
env: CLANG64
gbc: 1
name: Windows ${{ matrix.arch }} / MSYS2 ${{ matrix.env }} ${{ matrix.cc }}
runs-on: windows-2025
defaults:
run:
shell: msys2 {0}
@@ -82,7 +88,6 @@ jobs:
git
libtool
make
mingw-w64-${{ matrix.cross }}-gcc
mingw-w64-${{ matrix.cross }}-toolchain
mingw-w64-${{ matrix.cross }}-freetype
mingw-w64-${{ matrix.cross }}-libpng
@@ -93,10 +98,11 @@ jobs:
mingw-w64-${{ matrix.cross }}-zlib
- name: Build and related stuff, backup binaries
run: |
if [[ ${{ matrix.gbc }} -eq 1 ]]; then pacman --noconfirm -S --needed mingw-w64-${{ matrix.cross }}-opencv; fi
export PATH="$(pwd)/.github/workflows/scripts:${PATH}"
export CONFIG_OVERRIDE="ACCURATE_FPU=1 NEW_DYNAREC=1"
export CONFIG_OVERRIDE="ACCURATE_FPU=1 NEW_DYNAREC=1 OPENCV=${{ matrix.gbc }}"
ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }}
export CONFIG_OVERRIDE="ACCURATE_FPU=0 NEW_DYNAREC=0 POSTFIX="-old""
export CONFIG_OVERRIDE="ACCURATE_FPU=0 NEW_DYNAREC=0 OPENCV=${{ matrix.gbc }} POSTFIX="-old""
ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }}
- name: Backup dependencies, etc...
run: |
@@ -114,11 +120,11 @@ jobs:
include:
- toolset: v143
arch: x64
vs: 2022
vs: 2025
- toolset: v141_xp
arch: x86
vs: 2019
name: Windows / MSVC with ${{ matrix.toolset }} / ${{ matrix.arch }}
name: Windows ${{ matrix.arch }} / MSVC with ${{ matrix.toolset }}
runs-on: windows-${{ matrix.vs }}
defaults:
run:
@@ -131,7 +137,7 @@ jobs:
set PATH=%CD%\.github\workflows\scripts;%PATH%
set TOOLSET=${{ matrix.toolset }}
call ci_msvc_build.cmd ${{ matrix.arch }}
ci_msvc_build.cmd ${{ matrix.arch }} newdyn
call ci_msvc_build.cmd ${{ matrix.arch }} newdyn
- name: Backup dependencies, etc...
run: |
.\.github\workflows\scripts\ci_backup_msvc_deps.cmd ${{ matrix.arch }} freetype.dll libpng16.dll SDL2.dll SDL2_net.dll zlib.dll
@@ -19,27 +19,21 @@ jobs:
arch: x64
- cc: Clang
arch: x86
name: Linux / ${{ matrix.cc }} / ${{ matrix.arch }}
runs-on: ubuntu-22.04
name: Linux / ${{ matrix.cc }} ${{ matrix.arch }}
runs-on: ubuntu-24.04
if: github.repository == 'mupen64plus/mupen64plus-core'
steps:
- uses: actions/checkout@v4
- name: Get build dependencies and arrange the environment
run: |
export C_CLANG_SUFFIX="-15" C_GCC_SUFFIX="-12"
export BUILD_DEPS="libfreetype6-dev libgl1-mesa-dev libglu1-mesa-dev libpng-dev libsdl1.2-dev libsdl2-dev libvulkan-dev zlib1g-dev"
export BUILD_DEPS="libfreetype6-dev libgl1-mesa-dev libglu1-mesa-dev libpng-dev libsdl2-dev libvulkan-dev zlib1g-dev"
./.github/workflows/scripts/ci_install_ubuntu_deps.sh ${{ matrix.arch }} ${{ matrix.cc }}
- name: Build and related stuff, backup binaries
run: |
export C_CLANG_SUFFIX="-15" C_GCC_SUFFIX="-12"
export PATH="$(pwd)/.github/workflows/scripts:${PATH}"
export CONFIG_OVERRIDE="ACCURATE_FPU=1 NEW_DYNAREC=1 SDL_CONFIG="sdl-config""
export CONFIG_OVERRIDE="ACCURATE_FPU=1 NEW_DYNAREC=1"
ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }}
export CONFIG_OVERRIDE="ACCURATE_FPU=1 NEW_DYNAREC=1 SDL_CONFIG="sdl2-config""
ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }}
export CONFIG_OVERRIDE="ACCURATE_FPU=0 NEW_DYNAREC=0 SDL_CONFIG="sdl-config" POSTFIX="-old""
ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }}
export CONFIG_OVERRIDE="ACCURATE_FPU=0 NEW_DYNAREC=0 SDL_CONFIG="sdl2-config" POSTFIX="-old""
export CONFIG_OVERRIDE="ACCURATE_FPU=0 NEW_DYNAREC=0 POSTFIX="-old""
ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }} makepkg
- name: Upload artifact
if: matrix.cc == 'GCC'
@@ -57,12 +51,24 @@ jobs:
arch: x64
cross: x86_64
env: MINGW64
gbc: 0
- cc: GCC
arch: x86
cross: i686
env: MINGW32
name: Windows / MSYS2 ${{ matrix.cc }} / ${{ matrix.arch }}
runs-on: windows-2022
gbc: 0
- cc: GCC
arch: x64
cross: ucrt-x86_64
env: UCRT64
gbc: 1
- cc: Clang
arch: x64
cross: clang-x86_64
env: CLANG64
gbc: 1
name: Windows ${{ matrix.arch }} / MSYS2 ${{ matrix.env }} ${{ matrix.cc }}
runs-on: windows-2025
if: github.repository == 'mupen64plus/mupen64plus-core'
defaults:
run:
@@ -77,7 +83,6 @@ jobs:
git
libtool
make
mingw-w64-${{ matrix.cross }}-gcc
mingw-w64-${{ matrix.cross }}-toolchain
mingw-w64-${{ matrix.cross }}-freetype
mingw-w64-${{ matrix.cross }}-libpng
@@ -88,10 +93,11 @@ jobs:
mingw-w64-${{ matrix.cross }}-zlib
- name: Build and related stuff, backup binaries
run: |
if [[ ${{ matrix.gbc }} -eq 1 ]]; then pacman --noconfirm -S --needed mingw-w64-${{ matrix.cross }}-opencv; fi
export PATH="$(pwd)/.github/workflows/scripts:${PATH}"
export CONFIG_OVERRIDE="ACCURATE_FPU=1 NEW_DYNAREC=1"
export CONFIG_OVERRIDE="ACCURATE_FPU=1 NEW_DYNAREC=1 OPENCV=${{ matrix.gbc }}"
ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }}
export CONFIG_OVERRIDE="ACCURATE_FPU=0 NEW_DYNAREC=0 POSTFIX="-old""
export CONFIG_OVERRIDE="ACCURATE_FPU=0 NEW_DYNAREC=0 OPENCV=${{ matrix.gbc }} POSTFIX="-old""
ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }}
- name: Backup dependencies, etc...
run: |
@@ -109,11 +115,11 @@ jobs:
include:
- toolset: v143
arch: x64
vs: 2022
vs: 2025
- toolset: v141_xp
arch: x86
vs: 2019
name: Windows / MSVC with ${{ matrix.toolset }} / ${{ matrix.arch }}
name: Windows ${{ matrix.arch }} / MSVC with ${{ matrix.toolset }}
runs-on: windows-${{ matrix.vs }}
if: github.repository == 'mupen64plus/mupen64plus-core'
defaults:
@@ -127,7 +133,7 @@ jobs:
set PATH=%CD%\.github\workflows\scripts;%PATH%
set TOOLSET=${{ matrix.toolset }}
call ci_msvc_build.cmd ${{ matrix.arch }}
ci_msvc_build.cmd ${{ matrix.arch }} newdyn
call ci_msvc_build.cmd ${{ matrix.arch }} newdyn
- name: Backup dependencies, etc...
run: |
.\.github\workflows\scripts\ci_backup_msvc_deps.cmd ${{ matrix.arch }} freetype.dll libpng16.dll SDL2.dll SDL2_net.dll zlib.dll
@@ -37,7 +37,7 @@ export REPO="${PWD##*/}"
if [[ "${REPO}" == "" ]]; then exit 6; fi
export BIN_OS="$(uname -s | tr [A-Z] [a-z])"
if [[ ! -z ${MSYSTEM} ]]; then export BIN_OS="msys2"; fi
if [[ ! -z ${MSYSTEM} ]]; then export BIN_OS="msys2-$(echo "${MSYSTEM}" | tr [A-Z] [a-z])"; fi
export ENV_NAME="$(uname -s)"
export LDD="ldd"
export PKG_PATH="usr/local/lib/mupen64plus/"
@@ -105,6 +105,7 @@ if [[ -z ${ARTIFACT} ]]; then
exit 5
else
cd pkg
if [[ -f "mupen64plus.desktop" ]]; then rm -f mupen64plus.desktop; fi
ls -gG "${PKG_PATH}${ARTIFACT}"
echo ""
${LDD} "${PKG_PATH}${ARTIFACT}" > ldd.log
@@ -1,12 +1,16 @@
#!/usr/bin/env bash
set -e +u
# NOTE: There is no native "libglew-dev:i386" in Ubuntu 22.04, we will use Debian ones...
# NOTE: There is no native "libglew-dev:i386" in Ubuntu 24.04, we will use Debian ones...
export GLEWVER="$(apt list libglew-dev | grep "amd64" | cut -d ' ' -f2)"
export PKGS="$(apt list libglew* | grep "${GLEWVER}" | cut -d '/' -f1)"
export DEBSOURCE="http://http.us.debian.org/debian/pool/main/g/glew/"
export PKGVER_LS="$(curl -sS ${DEBSOURCE} | grep "${GLEWVER}" | grep "amd64" | cut -d '_' -f2 | sort)"
export BUILDP1="$(echo "${GLEWVER}" | cut -d '-' -f1)"
export BUILDP2="$(echo "${GLEWVER}" | cut -d '-' -f2)"
export GLEWBUILD="${BUILDP1}"
if [[ "${GLEWBUILD}" != "${GLEWVER}" ]]; then export GLEWBUILD="${BUILDP1}-${BUILDP2:0:1}"; fi
export PKGVER_LS="$(curl -sS ${DEBSOURCE} | grep "${GLEWBUILD}" | grep "amd64" | cut -d '_' -f2 | sort)"
if [[ "${PKGVER_LS}" != "" ]]; then
for VER in ${PKGVER_LS}; do export PKGVER="${VER}"; done
cd /tmp
@@ -4,7 +4,7 @@ set -e +u
if [[ ${#} -lt 2 ]]; then exit 9; fi
unset ARCH_DEP CC_DEP
export BUILD_DEPS_I386="crossbuild-essential-i386 g++${C_GCC_SUFFIX}-i686-linux-gnu gcc${C_GCC_SUFFIX}-i686-linux-gnu libc6-i386"
export BUILD_DEPS_I386="crossbuild-essential-i386 g++${C_GCC_SUFFIX}-i686-linux-gnu gcc${C_GCC_SUFFIX}-i686-linux-gnu"
export HOTFIX_I386="libatomic1:i386 libgcc-s1:i386 libstdc++6:i386 ${HOTFIX_I386}"
export ENV_ARGS="$(echo "${*}" | tr [A-Z] [a-z])"
@@ -17,7 +17,7 @@ for ARG in ${ENV_ARGS}; do
export CC_DEP="g++${C_GCC_SUFFIX} gcc${C_GCC_SUFFIX}"
;;
multilib )
export BUILD_DEPS_I386="g++${C_GCC_SUFFIX}-multilib gcc${C_GCC_SUFFIX}-multilib libc6-dev-i386"
export BUILD_DEPS_I386="g++${C_GCC_SUFFIX}-multilib gcc${C_GCC_SUFFIX}-multilib"
;;
x64 )
export ARCH_DEP="x64"
@@ -31,9 +31,9 @@ done
if [[ -z ${ARCH_DEP} ]]; then exit 8; fi
if [[ -z ${CC_DEP} ]]; then exit 7; fi
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
if [[ "${ARCH_DEP}" == "x86" ]]; then sudo dpkg --add-architecture i386; fi
sudo apt-get update
sudo apt-mark hold grub-common grub-efi-amd64-bin python3 python3-apt shim-signed
sudo apt-get -y install build-essential git nasm pkg-config ${CC_DEP} ${BUILD_DEPS}
if [[ "${ARCH_DEP}" == "x86" ]]; then
if [[ "${BUILD_DEPS}" != "" ]]; then
+3 -3
View File
@@ -6,7 +6,7 @@
[subrepo]
remote = git@github.com:mupen64plus/mupen64plus-core.git
branch = master
commit = e170c409fb006aa38fd02031b5eefab6886ec125
parent = 37839b0178b42b57a38a040bbf4e1f410e6952a1
commit = c5b1e72be0d2b33c18be48c989e726ac176e7872
parent = c8048741165583eaced380e84945764e924df6bf
method = merge
cmdver = 0.4.6
cmdver = 0.4.9
+4 -4
View File
@@ -339,11 +339,11 @@ LDLIBS += $(LIBPNG_LDLIBS)
ifeq ($(OPENCV), 1)
# OpenCV lib
ifeq ($(origin OPENCV_CFLAGS) $(origin OPENCV_LDLIBS), undefined undefined)
ifeq ($(shell $(PKG_CONFIG) --modversion opencv 2>/dev/null),)
$(error No OpenCV development libraries found!)
ifeq ($(shell $(PKG_CONFIG) --modversion opencv4 2>/dev/null),)
$(error No OpenCV 4 development libraries found!)
endif
OPENCV_CFLAGS += $(shell $(PKG_CONFIG) --cflags opencv)
OPENCV_LDLIBS += $(shell $(PKG_CONFIG) --libs opencv)
OPENCV_CFLAGS += $(shell $(PKG_CONFIG) --cflags opencv4)
OPENCV_LDLIBS += $(shell $(PKG_CONFIG) --libs opencv4)
endif
CFLAGS += $(OPENCV_CFLAGS)
LDLIBS += $(OPENCV_LDLIBS)
@@ -281,7 +281,7 @@ static db_addr_t
db_disasm_insn ( struct r4k_dis_t * state,
int insn,
db_addr_t loc,
bool altfmt )
unsigned char altfmt)
{
char * rel;
InstFmt i;
@@ -24,11 +24,9 @@
#if defined(WIN32)
typedef unsigned int uint32_t;
typedef unsigned char bool;
#define false 0
#define true 1
#else
#include <stdbool.h>
#include <stdint.h>
#endif
+2 -1
View File
@@ -129,6 +129,7 @@ void init_device(struct device* dev,
{ &dev->dd, dd_mecha_int_handler }, /* DD MECHA */
{ &dev->dd, dd_bm_int_handler }, /* DD BM */
{ &dev->dd, dd_dv_int_handler }, /* DD DRIVE */
{ &dev->sp, rsp_task_event },
};
#define R(x) read_ ## x
@@ -141,7 +142,7 @@ void init_device(struct device* dev,
/* memory map */
{ A(MM_RDRAM_DRAM, 0x3efffff), M64P_MEM_RDRAM, { &dev->rdram, RW(rdram_dram) } },
{ A(MM_RDRAM_REGS, 0xfffff), M64P_MEM_RDRAMREG, { &dev->rdram, RW(rdram_regs) } },
{ A(MM_RSP_MEM, 0xffff), M64P_MEM_RSPMEM, { &dev->sp, RW(rsp_mem) } },
{ A(MM_RSP_MEM, 0x3ffff), M64P_MEM_RSPMEM, { &dev->sp, RW(rsp_mem) } },
{ A(MM_RSP_REGS, 0xffff), M64P_MEM_RSPREG, { &dev->sp, RW(rsp_regs) } },
{ A(MM_RSP_REGS2, 0xffff), M64P_MEM_RSP, { &dev->sp, RW(rsp_regs2) } },
{ A(MM_DPC_REGS, 0xffff), M64P_MEM_DP, { &dev->dp, RW(dpc_regs) } },
+3 -2
View File
@@ -173,11 +173,12 @@ struct interrupt_handler
void (*callback)(void*);
};
enum { CP0_INTERRUPT_HANDLERS_COUNT = 16 };
enum { CP0_INTERRUPT_HANDLERS_COUNT = 17 };
enum {
INTR_UNSAFE_R4300 = 0x01,
INTR_UNSAFE_RSP = 0x02,
INTR_UNSAFE_RSP = 0x02,
INTR_UNSAFE_RDP = 0x04,
};
struct cp0
@@ -656,6 +656,11 @@ void gen_interrupt(struct r4300_core* r4300)
call_interrupt_handler(&r4300->cp0, 15);
break;
case RSP_TSK_EVT:
remove_interrupt_event(&r4300->cp0);
call_interrupt_handler(&r4300->cp0, 16);
break;
default:
DebugMessage(M64MSG_ERROR, "Unknown interrupt queue event type %.8X.", r4300->cp0.q.first->data.type);
remove_interrupt_event(&r4300->cp0);
@@ -69,5 +69,6 @@ void nmi_int_handler(void* opaque);
#define DD_MC_INT 0x1000
#define DD_BM_INT 0x2000
#define DD_DV_INT 0x4000
#define RSP_TSK_EVT 0x8000
#endif /* M64P_DEVICE_R4300_INTERRUPT_H */
@@ -4274,7 +4274,7 @@ static void loop_preload(signed char pre[],signed char entry[])
// Generate address for load/store instruction
static void address_generation(int i,struct regstat *i_regs,signed char entry[])
{
if(i>=4069) return;
if(i>=MAXBLOCK) return;
if(itype[i]==LOAD||itype[i]==LOADLR||itype[i]==STORE||itype[i]==STORELR||itype[i]==C1LS) {
int ra=0;
int agr=AGEN1+(i&1);
@@ -4381,7 +4381,7 @@ static void address_generation(int i,struct regstat *i_regs,signed char entry[])
}
}
// Preload constants for next instruction
if(i+1>=4096) return;
if(i+1>=MAXBLOCK) return;
if(itype[i+1]==LOAD||itype[i+1]==LOADLR||itype[i+1]==STORE||itype[i+1]==STORELR||itype[i+1]==C1LS) {
int agr,ra;
#if (NEW_DYNAREC!=NEW_DYNAREC_X86) && (NEW_DYNAREC!=NEW_DYNAREC_X64)
@@ -153,7 +153,7 @@ void read_pi_regs(void* opaque, uint32_t address, uint32_t* value)
struct pi_controller* pi = (struct pi_controller*)opaque;
uint32_t reg = pi_reg(address);
if (reg < PI_REGS_COUNT)
if (reg < PI_REGS_COUNT)
*value = pi->regs[reg];
if (reg == PI_WR_LEN_REG || reg == PI_RD_LEN_REG)
@@ -26,6 +26,7 @@
#include "device/memory/memory.h"
#include "device/rcp/mi/mi_controller.h"
#include "device/rcp/rsp/rsp_core.h"
#include "device/r4300/r4300_core.h"
#include "plugin/plugin.h"
static void update_dpc_status(struct rdp_core* dp, uint32_t w)
@@ -40,7 +41,13 @@ static void update_dpc_status(struct rdp_core* dp, uint32_t w)
dp->dpc_regs[DPC_STATUS_REG] &= ~DPC_STATUS_FREEZE;
if (dp->do_on_unfreeze & DELAY_DP_INT)
{
dp->mi->r4300->cp0.interrupt_unsafe_state &= ~INTR_UNSAFE_RDP;
signal_rcp_interrupt(dp->mi, MI_INTR_DP);
clear_rsp_wait(dp->sp, WAIT_PENDING_DP_SYNC);
}
if (dp->do_on_unfreeze & DELAY_UPDATESCREEN)
gfx.updateScreen();
dp->do_on_unfreeze = 0;
@@ -51,6 +58,22 @@ static void update_dpc_status(struct rdp_core* dp, uint32_t w)
if (w & DPC_CLR_FLUSH) dp->dpc_regs[DPC_STATUS_REG] &= ~DPC_STATUS_FLUSH;
if (w & DPC_SET_FLUSH) dp->dpc_regs[DPC_STATUS_REG] |= DPC_STATUS_FLUSH;
if (w & DPC_CLR_TMEM_CTR)
{
dp->dpc_regs[DPC_STATUS_REG] &= ~DPC_STATUS_TMEM_BUSY;
dp->dpc_regs[DPC_TMEM_REG] = 0;
}
if (w & DPC_CLR_PIPE_CTR)
{
dp->dpc_regs[DPC_STATUS_REG] &= ~DPC_STATUS_PIPE_BUSY;
dp->dpc_regs[DPC_PIPEBUSY_REG] = 0;
}
if (w & DPC_CLR_CMD_CTR)
{
dp->dpc_regs[DPC_STATUS_REG] &= ~DPC_STATUS_CMD_BUSY;
dp->dpc_regs[DPC_BUFBUSY_REG] = 0;
}
/* clear clock counter */
if (w & DPC_CLR_CLOCK_CTR) dp->dpc_regs[DPC_CLOCK_REG] = 0;
}
@@ -73,11 +96,13 @@ void poweron_rdp(struct rdp_core* dp)
{
memset(dp->dpc_regs, 0, DPC_REGS_COUNT*sizeof(uint32_t));
memset(dp->dps_regs, 0, DPS_REGS_COUNT*sizeof(uint32_t));
dp->dpc_regs[DPC_STATUS_REG] |= DPC_STATUS_START_GCLK;
dp->dpc_regs[DPC_STATUS_REG] |= DPC_STATUS_START_GCLK | DPC_STATUS_PIPE_BUSY | DPC_STATUS_CBUF_READY;
dp->do_on_unfreeze = 0;
poweron_fb(&dp->fb);
dp->mi->r4300->cp0.interrupt_unsafe_state &= ~INTR_UNSAFE_RDP;
}
@@ -106,18 +131,35 @@ void write_dpc_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mas
return;
}
masked_write(&dp->dpc_regs[reg], value, mask);
switch(reg)
{
case DPC_START_REG:
dp->dpc_regs[DPC_CURRENT_REG] = dp->dpc_regs[DPC_START_REG];
if (!(dp->dpc_regs[DPC_STATUS_REG] & DPC_STATUS_START_VALID))
{
masked_write(&dp->dpc_regs[reg], value & UINT32_C(0xFFFFF8), mask);
}
dp->dpc_regs[DPC_STATUS_REG] |= DPC_STATUS_START_VALID;
break;
case DPC_END_REG:
masked_write(&dp->dpc_regs[reg], value & UINT32_C(0xFFFFF8), mask);
if (dp->dpc_regs[DPC_STATUS_REG] & DPC_STATUS_START_VALID)
{
dp->dpc_regs[DPC_CURRENT_REG] = dp->dpc_regs[DPC_START_REG];
dp->dpc_regs[DPC_STATUS_REG] &= ~DPC_STATUS_START_VALID;
}
unprotect_framebuffers(&dp->fb);
gfx.processRDPList();
protect_framebuffers(&dp->fb);
signal_rcp_interrupt(dp->mi, MI_INTR_DP);
if (dp->mi->regs[MI_INTR_REG] & MI_INTR_DP)
{
dp->mi->regs[MI_INTR_REG] &= ~MI_INTR_DP;
dp->mi->r4300->cp0.interrupt_unsafe_state |= INTR_UNSAFE_RDP;
if (dp->dpc_regs[DPC_STATUS_REG] & DPC_STATUS_FREEZE) {
dp->do_on_unfreeze |= DELAY_DP_INT;
} else {
add_interrupt_event(&dp->mi->r4300->cp0, DP_INT, dp->dpc_regs[DPC_CLOCK_REG]);
}
}
break;
}
}
@@ -149,6 +191,9 @@ void rdp_interrupt_event(void* opaque)
{
struct rdp_core* dp = (struct rdp_core*)opaque;
dp->mi->r4300->cp0.interrupt_unsafe_state &= ~INTR_UNSAFE_RDP;
raise_rcp_interrupt(dp->mi, MI_INTR_DP);
clear_rsp_wait(dp->sp, WAIT_PENDING_DP_SYNC);
}
@@ -37,7 +37,11 @@ enum
DPC_STATUS_FREEZE = 0x002,
DPC_STATUS_FLUSH = 0x004,
DPC_STATUS_START_GCLK = 0x008,
DPC_STATUS_TMEM_BUSY = 0x010,
DPC_STATUS_PIPE_BUSY = 0x020,
DPC_STATUS_CMD_BUSY = 0x040,
DPC_STATUS_CBUF_READY = 0x080,
DPC_STATUS_DMA_BUSY = 0x100,
DPC_STATUS_END_VALID = 0x200,
DPC_STATUS_START_VALID = 0x400,
/* DPC status - write */
+119 -104
View File
@@ -76,13 +76,16 @@ static void do_sp_dma(struct rsp_core* sp, const struct sp_dma* dma)
pre_framebuffer_read(&sp->dp->fb, dramaddr);
for(i=0; i<length; i++) {
spmem[(memaddr^S8) & 0xfff] = dram[(dramaddr^S8) & 0x7fffff];
spmem[(memaddr & 0xfff)^S8] = dram[(dramaddr^S8) & 0x7fffff];
memaddr++;
dramaddr++;
}
dramaddr+=skip;
}
sp->regs[SP_MEM_ADDR_REG] = (memaddr & 0xfff) + (dma->memaddr & 0x1000);
sp->regs[SP_DRAM_ADDR_REG] = dramaddr;
sp->regs[SP_MEM_ADDR_REG] = memaddr & 0xfff;
sp->regs[SP_DRAM_ADDR_REG] = dramaddr & 0xffffff;
sp->regs[SP_RD_LEN_REG] = 0xff8;
@@ -146,69 +149,87 @@ static void fifo_pop(struct rsp_core* sp)
static void update_sp_status(struct rsp_core* sp, uint32_t w)
{
/* clear / set halt */
if ((w & 0x3) == 0x1) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_HALT;
if ((w & 0x3) == 0x2) sp->regs[SP_STATUS_REG] |= SP_STATUS_HALT;
if ((w & SP_CLR_HALT) && !(w & SP_SET_HALT))
{
sp->rsp_wait &= ~WAIT_HALTED;
sp->regs[SP_STATUS_REG] &= ~SP_STATUS_HALT;
}
if ((w & SP_SET_HALT) && !(w & SP_CLR_HALT))
{
remove_event(&sp->mi->r4300->cp0.q, SP_INT);
sp->rsp_status = 0;
sp->first_run = 1;
sp->rsp_wait |= WAIT_HALTED;
sp->regs[SP_STATUS_REG] |= SP_STATUS_HALT;
}
/* clear broke */
if (w & 0x4) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_BROKE;
if (w & SP_CLR_BROKE) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_BROKE;
/* clear SP interrupt */
if ((w & 0x18) == 0x8)
if ((w & SP_CLR_INTR) && !(w & SP_SET_INTR))
{
clear_rcp_interrupt(sp->mi, MI_INTR_SP);
}
/* set SP interrupt */
if ((w & 0x18) == 0x10)
if ((w & SP_SET_INTR) && !(w & SP_CLR_INTR))
{
signal_rcp_interrupt(sp->mi, MI_INTR_SP);
}
/* clear / set single step */
if ((w & 0x60) == 0x20) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SSTEP;
if ((w & 0x60) == 0x40) sp->regs[SP_STATUS_REG] |= SP_STATUS_SSTEP;
if ((w & SP_CLR_SSTEP) && !(w & SP_SET_SSTEP)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SSTEP;
if ((w & SP_SET_SSTEP) && !(w & SP_CLR_SSTEP)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SSTEP;
/* clear / set interrupt on break */
if ((w & 0x180) == 0x80) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_INTR_BREAK;
if ((w & 0x180) == 0x100) sp->regs[SP_STATUS_REG] |= SP_STATUS_INTR_BREAK;
if ((w & SP_CLR_INTR_BREAK) && !(w & SP_SET_INTR_BREAK))
{
if (sp->rsp_wait & WAIT_PENDING_SP_INT_BROKE)
{
// If a game clears SP_SET_INTR_BREAK before the interrupt happens,
// that means it would have been cleared before the BREAK command
remove_event(&sp->mi->r4300->cp0.q, SP_INT);
sp->rsp_wait &= ~WAIT_PENDING_SP_INT_BROKE;
sp->regs[SP_STATUS_REG] = sp->rsp_status;
sp->rsp_status = 0;
}
sp->regs[SP_STATUS_REG] &= ~SP_STATUS_INTR_BREAK;
}
if ((w & SP_SET_INTR_BREAK) && !(w & SP_CLR_INTR_BREAK)) sp->regs[SP_STATUS_REG] |= SP_STATUS_INTR_BREAK;
/* clear / set signal 0 */
if ((w & 0x600) == 0x200) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG0;
if ((w & 0x600) == 0x400) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG0;
if ((w & SP_CLR_SIG0) && !(w & SP_SET_SIG0)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG0;
if ((w & SP_SET_SIG0) && !(w & SP_CLR_SIG0)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG0;
/* clear / set signal 1 */
if ((w & 0x1800) == 0x800) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG1;
if ((w & 0x1800) == 0x1000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG1;
if ((w & SP_CLR_SIG1) && !(w & SP_SET_SIG1)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG1;
if ((w & SP_SET_SIG1) && !(w & SP_CLR_SIG1)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG1;
/* clear / set signal 2 */
if ((w & 0x6000) == 0x2000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG2;
if ((w & 0x6000) == 0x4000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG2;
if ((w & SP_CLR_SIG2) && !(w & SP_SET_SIG2)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG2;
if ((w & SP_SET_SIG2) && !(w & SP_CLR_SIG2)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG2;
/* clear / set signal 3 */
if ((w & 0x18000) == 0x8000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG3;
if ((w & 0x18000) == 0x10000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG3;
if ((w & SP_CLR_SIG3) && !(w & SP_SET_SIG3)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG3;
if ((w & SP_SET_SIG3) && !(w & SP_CLR_SIG3)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG3;
/* clear / set signal 4 */
if ((w & 0x60000) == 0x20000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG4;
if ((w & 0x60000) == 0x40000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG4;
if ((w & SP_CLR_SIG4) && !(w & SP_SET_SIG4)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG4;
if ((w & SP_SET_SIG4) && !(w & SP_CLR_SIG4)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG4;
/* clear / set signal 5 */
if ((w & 0x180000) == 0x80000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG5;
if ((w & 0x180000) == 0x100000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG5;
if ((w & SP_CLR_SIG5) && !(w & SP_SET_SIG5)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG5;
if ((w & SP_SET_SIG5) && !(w & SP_CLR_SIG5)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG5;
/* clear / set signal 6 */
if ((w & 0x600000) == 0x200000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG6;
if ((w & 0x600000) == 0x400000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG6;
if ((w & SP_CLR_SIG6) && !(w & SP_SET_SIG6)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG6;
if ((w & SP_SET_SIG6) && !(w & SP_CLR_SIG6)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG6;
/* clear / set signal 7 */
if ((w & 0x1800000) == 0x800000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG7;
if ((w & 0x1800000) == 0x1000000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG7;
if ((w & SP_CLR_SIG7) && !(w & SP_SET_SIG7)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG7;
if ((w & SP_SET_SIG7) && !(w & SP_CLR_SIG7)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG7;
if (sp->rsp_task_locked && (get_event(&sp->mi->r4300->cp0.q, SP_INT))) return;
if (!((w & 0x3) == 1) && !(w & 0x4) && !sp->rsp_task_locked)
return;
if (!(sp->regs[SP_STATUS_REG] & SP_STATUS_HALT))
do_SP_Task(sp);
do_SP_Task(sp);
}
void init_rsp(struct rsp_core* sp,
@@ -230,7 +251,9 @@ void poweron_rsp(struct rsp_core* sp)
memset(sp->regs2, 0, SP_REGS2_COUNT*sizeof(uint32_t));
memset(sp->fifo, 0, SP_DMA_FIFO_SIZE*sizeof(struct sp_dma));
sp->rsp_task_locked = 0;
sp->rsp_status = 0;
sp->first_run = 1;
sp->rsp_wait = 0;
sp->mi->r4300->cp0.interrupt_unsafe_state &= ~INTR_UNSAFE_RSP;
sp->regs[SP_STATUS_REG] = 1;
sp->regs[SP_RD_LEN_REG] = 0xff8;
@@ -286,6 +309,12 @@ void write_rsp_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mas
switch(reg)
{
case SP_MEM_ADDR_REG:
sp->regs[SP_MEM_ADDR_REG] &= 0x1ff8;
break;
case SP_DRAM_ADDR_REG:
sp->regs[SP_DRAM_ADDR_REG] &= 0xfffff8;
break;
case SP_RD_LEN_REG:
fifo_push(sp, SP_DMA_WRITE);
break;
@@ -317,7 +346,10 @@ void write_rsp_regs2(void* opaque, uint32_t address, uint32_t value, uint32_t ma
uint32_t reg = rsp_reg2(address);
if (reg == SP_PC_REG)
mask &= 0xffc;
{
masked_write(&sp->regs2[SP_PC_REG], value & 0xffc, mask);
return;
}
if (reg < SP_REGS2_COUNT)
masked_write(&sp->regs2[reg], value, mask);
@@ -325,97 +357,66 @@ void write_rsp_regs2(void* opaque, uint32_t address, uint32_t value, uint32_t ma
void do_SP_Task(struct rsp_core* sp)
{
uint32_t save_pc = sp->regs2[SP_PC_REG] & ~0xfff;
if (sp->rsp_wait)
return;
if (get_event(&sp->mi->r4300->cp0.q, RSP_TSK_EVT))
return;
uint32_t sp_delay_time;
uint32_t saved_status = sp->regs[SP_STATUS_REG];
uint32_t sp_bit_set = sp->mi->regs[MI_INTR_REG] & MI_INTR_SP;
uint32_t dp_bit_set = sp->mi->regs[MI_INTR_REG] & MI_INTR_DP;
if (sp->mem[0xfc0/4] == 1)
uint32_t rsp_cycles = rsp.doRspCycles(sp->first_run) / 2;
if (sp->mi->regs[MI_INTR_REG] & MI_INTR_DP && !dp_bit_set)
{
unprotect_framebuffers(&sp->dp->fb);
//gfx.processDList();
sp->regs2[SP_PC_REG] &= 0xfff;
#if defined(PROFILE)
timed_section_start(TIMED_SECTION_GFX);
#endif
rsp.doRspCycles(0xffffffff);
#if defined(PROFILE)
timed_section_end(TIMED_SECTION_GFX);
#endif
sp->regs2[SP_PC_REG] |= save_pc;
new_frame();
if (sp->mi->regs[MI_INTR_REG] & MI_INTR_DP)
{
sp->mi->regs[MI_INTR_REG] &= ~MI_INTR_DP;
if (sp->dp->dpc_regs[DPC_STATUS_REG] & DPC_STATUS_FREEZE) {
sp->dp->do_on_unfreeze |= DELAY_DP_INT;
} else {
cp0_update_count(sp->mi->r4300);
add_interrupt_event(&sp->mi->r4300->cp0, DP_INT, 4000);
}
sp->mi->regs[MI_INTR_REG] &= ~MI_INTR_DP;
sp->mi->r4300->cp0.interrupt_unsafe_state |= INTR_UNSAFE_RDP;
sp->rsp_wait |= WAIT_PENDING_DP_SYNC;
if (sp->dp->dpc_regs[DPC_STATUS_REG] & DPC_STATUS_FREEZE) {
sp->dp->do_on_unfreeze |= DELAY_DP_INT;
} else {
add_interrupt_event(&sp->mi->r4300->cp0, DP_INT, rsp_cycles + sp->dp->dpc_regs[DPC_CLOCK_REG]);
}
sp_delay_time = 1000;
protect_framebuffers(&sp->dp->fb);
}
else if (sp->mem[0xfc0/4] == 2)
{
//audio.processAList();
sp->regs2[SP_PC_REG] &= 0xfff;
#if defined(PROFILE)
timed_section_start(TIMED_SECTION_AUDIO);
#endif
rsp.doRspCycles(0xffffffff);
#if defined(PROFILE)
timed_section_end(TIMED_SECTION_AUDIO);
#endif
sp->regs2[SP_PC_REG] |= save_pc;
sp_delay_time = 4000;
sp->rsp_status = sp->regs[SP_STATUS_REG];
if ((sp->regs[SP_STATUS_REG] & SP_STATUS_HALT) == 0)
{
add_interrupt_event(&sp->mi->r4300->cp0, RSP_TSK_EVT, rsp_cycles);
sp->first_run = 0;
}
else
{
sp->regs2[SP_PC_REG] &= 0xfff;
rsp.doRspCycles(0xffffffff);
sp->regs2[SP_PC_REG] |= save_pc;
sp_delay_time = 0;
sp->rsp_wait |= WAIT_HALTED;
sp->first_run = 1;
}
sp->rsp_task_locked = 0;
sp->mi->r4300->cp0.interrupt_unsafe_state &= ~INTR_UNSAFE_RSP;
if ((sp->regs[SP_STATUS_REG] & (SP_STATUS_HALT | SP_STATUS_BROKE)) == 0)
if ((sp->regs[SP_STATUS_REG] & SP_STATUS_BROKE) && (sp->regs[SP_STATUS_REG] & SP_STATUS_INTR_BREAK))
{
sp->rsp_task_locked = 1;
sp->mi->r4300->cp0.interrupt_unsafe_state |= INTR_UNSAFE_RSP;
sp->mi->regs[MI_INTR_REG] |= MI_INTR_SP;
sp->rsp_wait |= WAIT_PENDING_SP_INT_BROKE;
add_interrupt_event(&sp->mi->r4300->cp0, SP_INT, rsp_cycles);
sp->regs[SP_STATUS_REG] = saved_status;
}
if (sp->mi->regs[MI_INTR_REG] & MI_INTR_SP)
else if (sp->mi->regs[MI_INTR_REG] & MI_INTR_SP && !sp_bit_set)
{
cp0_update_count(sp->mi->r4300);
add_interrupt_event(&sp->mi->r4300->cp0, SP_INT, sp_delay_time);
sp->rsp_wait |= WAIT_PENDING_SP_INT;
add_interrupt_event(&sp->mi->r4300->cp0, SP_INT, rsp_cycles);
}
sp->mi->r4300->cp0.interrupt_unsafe_state |= INTR_UNSAFE_RSP;
if (!sp_bit_set)
sp->mi->regs[MI_INTR_REG] &= ~MI_INTR_SP;
}
sp->regs[SP_STATUS_REG] &=
~(SP_STATUS_TASKDONE | SP_STATUS_BROKE | SP_STATUS_HALT);
}
void rsp_interrupt_event(void* opaque)
{
struct rsp_core* sp = (struct rsp_core*)opaque;
if (!sp->rsp_task_locked)
{
sp->regs[SP_STATUS_REG] |=
SP_STATUS_TASKDONE | SP_STATUS_BROKE | SP_STATUS_HALT;
}
sp->regs[SP_STATUS_REG] = sp->rsp_status;
sp->rsp_status = 0;
sp->mi->r4300->cp0.interrupt_unsafe_state &= ~INTR_UNSAFE_RSP;
raise_rcp_interrupt(sp->mi, MI_INTR_SP);
if ((sp->regs[SP_STATUS_REG] & SP_STATUS_INTR_BREAK) != 0)
{
raise_rcp_interrupt(sp->mi, MI_INTR_SP);
}
clear_rsp_wait(sp, WAIT_PENDING_SP_INT | WAIT_PENDING_SP_INT_BROKE);
}
void rsp_end_of_dma_event(void* opaque)
@@ -423,3 +424,17 @@ void rsp_end_of_dma_event(void* opaque)
struct rsp_core* sp = (struct rsp_core*)opaque;
fifo_pop(sp);
}
void rsp_task_event(void* opaque)
{
struct rsp_core* sp = (struct rsp_core*)opaque;
do_SP_Task(sp);
}
void clear_rsp_wait(struct rsp_core* sp, uint32_t value)
{
sp->rsp_wait &= ~value;
do_SP_Task(sp);
}
@@ -55,6 +55,36 @@ enum
SP_STATUS_SIG7 = 0x4000,
};
enum
{
/* SP_STATUS - write */
SP_CLR_HALT = 0x0000001,
SP_SET_HALT = 0x0000002,
SP_CLR_BROKE = 0x0000004,
SP_CLR_INTR = 0x0000008,
SP_SET_INTR = 0x0000010,
SP_CLR_SSTEP = 0x0000020,
SP_SET_SSTEP = 0x0000040,
SP_CLR_INTR_BREAK = 0x0000080,
SP_SET_INTR_BREAK = 0x0000100,
SP_CLR_SIG0 = 0x0000200,
SP_SET_SIG0 = 0x0000400,
SP_CLR_SIG1 = 0x0000800,
SP_SET_SIG1 = 0x0001000,
SP_CLR_SIG2 = 0x0002000,
SP_SET_SIG2 = 0x0004000,
SP_CLR_SIG3 = 0x0008000,
SP_SET_SIG3 = 0x0010000,
SP_CLR_SIG4 = 0x0020000,
SP_SET_SIG4 = 0x0040000,
SP_CLR_SIG5 = 0x0080000,
SP_SET_SIG5 = 0x0100000,
SP_CLR_SIG6 = 0x0200000,
SP_SET_SIG6 = 0x0400000,
SP_CLR_SIG7 = 0x0800000,
SP_SET_SIG7 = 0x1000000,
};
enum sp_registers
{
SP_MEM_ADDR_REG,
@@ -81,6 +111,14 @@ enum sp_dma_dir
SP_DMA_WRITE
};
enum sp_rsp_wait
{
WAIT_PENDING_SP_INT_BROKE = 0x1,
WAIT_PENDING_SP_INT = 0x2,
WAIT_PENDING_DP_SYNC = 0x4,
WAIT_HALTED = 0x8
};
enum { SP_DMA_FIFO_SIZE = 2} ;
struct sp_dma
@@ -96,7 +134,9 @@ struct rsp_core
uint32_t* mem;
uint32_t regs[SP_REGS_COUNT];
uint32_t regs2[SP_REGS2_COUNT];
uint32_t rsp_task_locked;
uint32_t rsp_status;
uint32_t first_run;
uint32_t rsp_wait;
struct mi_controller* mi;
struct rdp_core* dp;
@@ -141,4 +181,7 @@ void do_SP_Task(struct rsp_core* sp);
void rsp_interrupt_event(void* opaque);
void rsp_end_of_dma_event(void* opaque);
void rsp_task_event(void* opaque);
void clear_rsp_wait(struct rsp_core* sp, uint32_t value);
#endif
@@ -104,7 +104,7 @@ void read_vi_regs(void* opaque, uint32_t address, uint32_t* value)
/* update current field */
vi->regs[VI_CURRENT_REG] = (vi->regs[VI_CURRENT_REG] & (~1)) | vi->field;
}
if (reg < VI_REGS_COUNT)
{
*value = vi->regs[reg];
-1
View File
@@ -21,7 +21,6 @@
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include <SDL.h>
#include <SDL_syswm.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+6 -1
View File
@@ -76,12 +76,16 @@ static const uint8_t Z64_SIGNATURE[4] = { 0x80, 0x37, 0x12, 0x40 };
static const uint8_t V64_SIGNATURE[4] = { 0x37, 0x80, 0x40, 0x12 };
static const uint8_t N64_SIGNATURE[4] = { 0x40, 0x12, 0x37, 0x80 };
static const uint8_t ALT_Z64_SIGNATURE[4] = { 0x31, 0x37, 0x12, 0x40 };
/* Tests if a file is a valid N64 rom by checking the first 4 bytes and size */
static int is_valid_rom(const unsigned char *buffer, unsigned int size)
{
printf("rom signature: 0x%02X, 0x%02X, 0x%02X, 0x%02X\n", buffer[0], buffer[1], buffer[2], buffer[3]);
if ((memcmp(buffer, Z64_SIGNATURE, sizeof(Z64_SIGNATURE)) == 0)
|| (memcmp(buffer, V64_SIGNATURE, sizeof(V64_SIGNATURE)) == 0 && size % 2 == 0)
|| (memcmp(buffer, N64_SIGNATURE, sizeof(N64_SIGNATURE)) == 0 && size % 4 == 0))
|| (memcmp(buffer, N64_SIGNATURE, sizeof(N64_SIGNATURE)) == 0 && size % 4 == 0)
|| (memcmp(buffer, ALT_Z64_SIGNATURE, sizeof(ALT_Z64_SIGNATURE)) == 0))
return 1;
else
return 0;
@@ -149,6 +153,7 @@ m64p_error open_rom(const unsigned char* romimage, unsigned int size)
if (romimage == NULL || !is_valid_rom(romimage, size))
{
DebugMessage(M64MSG_ERROR, "open_rom(): not a valid ROM image");
printf("fail\n");
return M64ERR_INPUT_INVALID;
}
+2 -2
View File
@@ -949,7 +949,7 @@ static int savestates_load_m64p(struct device* dev, char *filepath)
/* reset fb state */
poweron_fb(&dev->dp.fb);
dev->sp.rsp_task_locked = 0;
//dev->sp.rsp_task_locked = 0;
dev->r4300.cp0.interrupt_unsafe_state = 0;
*r4300_cp0_last_addr(&dev->r4300.cp0) = *r4300_pc(&dev->r4300);
@@ -1253,7 +1253,7 @@ static int savestates_load_pj64(struct device* dev,
// No flashram info in pj64 savestate.
poweron_flashram(&dev->cart.flashram);
dev->sp.rsp_task_locked = 0;
//dev->sp.rsp_task_locked = 0;
dev->r4300.cp0.interrupt_unsafe_state = 0;
/* extra fb state */
@@ -127,4 +127,3 @@ void dummyvideo_ResizeVideoOutput(int width, int height)
{
}
@@ -41,6 +41,7 @@ extern void dummyvideo_ViWidthChanged(void);
extern void dummyvideo_ReadScreen2(void *dest, int *width, int *height, int front);
extern void dummyvideo_SetRenderingCallback(void (*callback)(int));
extern void dummyvideo_ResizeVideoOutput(int width, int height);
extern void dummyvideo_FullSync(void);
extern void dummyvideo_FBRead(unsigned int addr);
extern void dummyvideo_FBWrite(unsigned int addr, unsigned int size);
@@ -26,18 +26,16 @@ jobs:
arch: x64
- cc: Clang
arch: x86
name: Linux / ${{ matrix.cc }} / ${{ matrix.arch }}
runs-on: ubuntu-22.04
name: Linux / ${{ matrix.cc }} ${{ matrix.arch }}
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Get build dependencies and arrange the environment
run: |
git clone --depth 1 https://github.com/mupen64plus/mupen64plus-core.git ../mupen64plus-core
export C_CLANG_SUFFIX="-15" C_GCC_SUFFIX="-12"
./../mupen64plus-core/.github/workflows/scripts/ci_install_ubuntu_deps.sh ${{ matrix.arch }} ${{ matrix.cc }}
- name: Build and related stuff, backup binaries
run: |
export C_CLANG_SUFFIX="-15" C_GCC_SUFFIX="-12"
./../mupen64plus-core/.github/workflows/scripts/ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }} makepkg
- name: Upload artifact
if: matrix.cc == 'GCC'
@@ -59,8 +57,16 @@ jobs:
arch: x86
cross: i686
env: MINGW32
name: Windows / MSYS2 ${{ matrix.cc }} / ${{ matrix.arch }}
runs-on: windows-2022
- cc: GCC
arch: x64
cross: ucrt-x86_64
env: UCRT64
- cc: Clang
arch: x64
cross: clang-x86_64
env: CLANG64
name: Windows ${{ matrix.arch }} / MSYS2 ${{ matrix.env }} ${{ matrix.cc }}
runs-on: windows-2025
defaults:
run:
shell: msys2 {0}
@@ -74,7 +80,6 @@ jobs:
git
libtool
make
mingw-w64-${{ matrix.cross }}-gcc
mingw-w64-${{ matrix.cross }}-toolchain
mingw-w64-${{ matrix.cross }}-ntldd
- name: Build and related stuff, backup binaries
@@ -97,11 +102,11 @@ jobs:
include:
- toolset: v143
arch: x64
vs: 2022
vs: 2025
- toolset: v141_xp
arch: x86
vs: 2019
name: Windows / MSVC with ${{ matrix.toolset }} / ${{ matrix.arch }}
name: Windows ${{ matrix.arch }} / MSVC with ${{ matrix.toolset }}
runs-on: windows-${{ matrix.vs }}
defaults:
run:
@@ -19,19 +19,17 @@ jobs:
arch: x64
- cc: Clang
arch: x86
name: Linux / ${{ matrix.cc }} / ${{ matrix.arch }}
runs-on: ubuntu-22.04
name: Linux / ${{ matrix.cc }} ${{ matrix.arch }}
runs-on: ubuntu-24.04
if: github.repository == 'mupen64plus/mupen64plus-rsp-hle'
steps:
- uses: actions/checkout@v4
- name: Get build dependencies and arrange the environment
run: |
git clone --depth 1 https://github.com/mupen64plus/mupen64plus-core.git ../mupen64plus-core
export C_CLANG_SUFFIX="-15" C_GCC_SUFFIX="-12"
./../mupen64plus-core/.github/workflows/scripts/ci_install_ubuntu_deps.sh ${{ matrix.arch }} ${{ matrix.cc }}
- name: Build and related stuff, backup binaries
run: |
export C_CLANG_SUFFIX="-15" C_GCC_SUFFIX="-12"
./../mupen64plus-core/.github/workflows/scripts/ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }} makepkg
- name: Upload artifact
if: matrix.cc == 'GCC'
@@ -53,8 +51,16 @@ jobs:
arch: x86
cross: i686
env: MINGW32
name: Windows / MSYS2 ${{ matrix.cc }} / ${{ matrix.arch }}
runs-on: windows-2022
- cc: GCC
arch: x64
cross: ucrt-x86_64
env: UCRT64
- cc: Clang
arch: x64
cross: clang-x86_64
env: CLANG64
name: Windows ${{ matrix.arch }} / MSYS2 ${{ matrix.env }} ${{ matrix.cc }}
runs-on: windows-2025
if: github.repository == 'mupen64plus/mupen64plus-rsp-hle'
defaults:
run:
@@ -69,7 +75,6 @@ jobs:
git
libtool
make
mingw-w64-${{ matrix.cross }}-gcc
mingw-w64-${{ matrix.cross }}-toolchain
mingw-w64-${{ matrix.cross }}-ntldd
- name: Build and related stuff, backup binaries
@@ -92,11 +97,11 @@ jobs:
include:
- toolset: v143
arch: x64
vs: 2022
vs: 2025
- toolset: v141_xp
arch: x86
vs: 2019
name: Windows / MSVC with ${{ matrix.toolset }} / ${{ matrix.arch }}
name: Windows ${{ matrix.arch }} / MSVC with ${{ matrix.toolset }}
runs-on: windows-${{ matrix.vs }}
if: github.repository == 'mupen64plus/mupen64plus-rsp-hle'
defaults:
@@ -1,2 +1,5 @@
/projects/unix/_obj*/
/projects/unix/mupen64plus-rsp-hle*.so
/projects/unix/mupen64plus-rsp-hle*.dll
/projects/msvc/Win32/
/projects/msvc/x64/
+2 -2
View File
@@ -6,7 +6,7 @@
[subrepo]
remote = git@github.com:/mupen64plus/mupen64plus-rsp-hle.git
branch = master
commit = 47f8e92e9a8bb9e49195ecfb03e9df0b63add242
parent = 23120150f9ddbef13a0690f004c364bb334addfc
commit = 80efbed3d737a32114956e149905c304944ebd61
parent = 6e1df7fc792cbdee30d31366af395e72a6cde813
method = merge
cmdver = 0.4.6
+1 -1
View File
@@ -475,7 +475,7 @@ static void ReorderSubBlock(int16_t *dst, const int16_t *src, const unsigned int
unsigned int i;
/* source and destination sublocks cannot overlap */
assert(labs(dst - src) > SUBBLOCK_SIZE);
assert(labs(dst - src) >= SUBBLOCK_SIZE);
for (i = 0; i < SUBBLOCK_SIZE; ++i)
dst[i] = src[table[i]];
+10 -29
View File
@@ -20,8 +20,6 @@ RSP::CPU cpu;
#else
RSP::JIT::CPU cpu;
#endif
short MFC0_count[32];
int SP_STATUS_TIMEOUT;
} // namespace RSP
extern "C"
@@ -53,47 +51,33 @@ extern "C"
EXPORT unsigned int CALL DoRspCycles(unsigned int cycles)
{
if (*RSP::rsp.SP_STATUS_REG & (SP_STATUS_HALT | SP_STATUS_BROKE))
return 0;
// We don't know if Mupen from the outside invalidated our IMEM.
RSP::cpu.invalidate_imem();
if (cycles)
{
RSP::cpu.get_state().last_instruction_type = RSP::VU_INSTRUCTION;
RSP::cpu.get_state().instruction_pipeline = 0;
RSP::cpu.invalidate_imem();
}
// Run CPU until we either break or we need to fire an IRQ.
RSP::cpu.get_state().pc = *RSP::rsp.SP_PC_REG & 0xfff;
RSP::cpu.get_state().instruction_count = 0;
#ifdef INTENSE_DEBUG
fprintf(stderr, "RUN TASK: %u\n", RSP::cpu.get_state().pc);
log_rsp_mem_parallel();
#endif
for (auto &count : RSP::MFC0_count)
count = 0;
while (!(*RSP::rsp.SP_STATUS_REG & SP_STATUS_HALT))
{
auto mode = RSP::cpu.run();
if (mode == RSP::MODE_CHECK_FLAGS && (*RSP::cpu.get_state().cp0.irq & 1))
break;
if (mode == RSP::MODE_EXIT)
break;
}
*RSP::rsp.SP_PC_REG = 0x04001000 | (RSP::cpu.get_state().pc & 0xffc);
// From CXD4.
if (*RSP::rsp.SP_STATUS_REG & SP_STATUS_BROKE)
return cycles;
else if (*RSP::cpu.get_state().cp0.irq & 1)
RSP::rsp.CheckInterrupts();
else if (*RSP::rsp.SP_STATUS_REG & SP_STATUS_HALT)
return cycles;
else if (*RSP::rsp.SP_SEMAPHORE_REG != 0) // Semaphore lock fixes.
{
}
else
RSP::SP_STATUS_TIMEOUT = 16; // From now on, wait 16 times, not 0x7fff
// CPU restarts with the correct SIGs.
*RSP::rsp.SP_STATUS_REG &= ~SP_STATUS_HALT;
*RSP::rsp.SP_PC_REG = (RSP::cpu.get_state().pc & 0xffc);
return cycles;
}
@@ -157,9 +141,6 @@ extern "C"
*cr[RSP::CP0_REGISTER_SP_STATUS] = SP_STATUS_HALT;
RSP::cpu.get_state().cp0.irq = RSP::rsp.MI_INTR_REG;
// From CXD4.
RSP::SP_STATUS_TIMEOUT = 0x7fff;
RSP::cpu.set_dmem(reinterpret_cast<uint32_t *>(Rsp_Info.DMEM));
RSP::cpu.set_imem(reinterpret_cast<uint32_t *>(Rsp_Info.IMEM));
RSP::cpu.set_rdram(reinterpret_cast<uint32_t *>(Rsp_Info.RDRAM));
+130 -87
View File
@@ -6,8 +6,6 @@
namespace RSP
{
extern RSP_INFO rsp;
extern short MFC0_count[32];
extern int SP_STATUS_TIMEOUT;
} // namespace RSP
#endif
@@ -28,34 +26,15 @@ extern "C"
rsp->sr[rt] = res;
#ifdef PARALLEL_INTEGRATION
if (rd == CP0_REGISTER_SP_STATUS)
{
// Might be waiting for the CPU to set a signal bit on the STATUS register. Increment timeout
RSP::MFC0_count[rt] += 1;
if (RSP::MFC0_count[rt] >= RSP::SP_STATUS_TIMEOUT)
{
*RSP::rsp.SP_STATUS_REG |= SP_STATUS_HALT;
return MODE_CHECK_FLAGS;
}
}
#endif
#if 0 // FIXME: this is broken with upstream mupen64plus-core
if (rd == CP0_REGISTER_SP_SEMAPHORE)
{
if (*rsp->cp0.cr[CP0_REGISTER_SP_SEMAPHORE])
{
#ifdef PARALLEL_INTEGRATION
RSP::MFC0_count[rt] += 8; // Almost certainly waiting on the CPU. Timeout faster.
if (RSP::MFC0_count[rt] >= RSP::SP_STATUS_TIMEOUT)
{
*RSP::rsp.SP_STATUS_REG |= SP_STATUS_HALT;
return MODE_CHECK_FLAGS;
}
#endif
}
else
*rsp->cp0.cr[CP0_REGISTER_SP_SEMAPHORE] = 1;
*rsp->cp0.cr[CP0_REGISTER_SP_SEMAPHORE] = 1;
return MODE_EXIT;
}
// We don't return control to the CPU if the RDP FREEZE bit is set, doing so seems to cause flickering
else if (rd == CP0_REGISTER_SP_STATUS && (*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] & DPC_STATUS_FREEZE) == 0)
{
return MODE_EXIT;
}
#endif
@@ -65,12 +44,44 @@ extern "C"
return MODE_CONTINUE;
}
#define RSP_HANDLE_STATUS_WRITE(flag) \
switch (rt & (SP_SET_##flag | SP_CLR_##flag)) \
{ \
case SP_SET_##flag: status |= SP_STATUS_##flag; break; \
case SP_CLR_##flag: status &= ~SP_STATUS_##flag; break; \
default: break; \
static inline void rdp_status_write(RSP::CPUState *rsp, uint32_t rt)
{
uint32_t status = *rsp->cp0.cr[CP0_REGISTER_CMD_STATUS];
if (rt & DPC_CLR_XBUS_DMEM_DMA)
status &= ~DPC_STATUS_XBUS_DMEM_DMA;
else if (rt & DPC_SET_XBUS_DMEM_DMA)
status |= DPC_STATUS_XBUS_DMEM_DMA;
if (rt & DPC_CLR_FREEZE)
status &= ~DPC_STATUS_FREEZE;
else if (rt & DPC_SET_FREEZE)
status |= DPC_STATUS_FREEZE;
if (rt & DPC_CLR_FLUSH)
status &= ~DPC_STATUS_FLUSH;
else if (rt & DPC_SET_FLUSH)
status |= DPC_STATUS_FLUSH;
if (rt & DPC_CLR_TMEM_CTR)
{
status &= ~DPC_STATUS_TMEM_BUSY;
*rsp->cp0.cr[CP0_REGISTER_CMD_TMEM_BUSY] = 0;
}
if (rt & DPC_CLR_PIPE_CTR)
{
status &= ~DPC_STATUS_PIPE_BUSY;
*rsp->cp0.cr[CP0_REGISTER_CMD_PIPE_BUSY] = 0;
}
if (rt & DPC_CLR_CMD_CTR)
{
status &= ~DPC_STATUS_CMD_BUSY;
*rsp->cp0.cr[CP0_REGISTER_CMD_BUSY] = 0;
}
if (rt & DPC_CLR_CLOCK_CTR)
*rsp->cp0.cr[CP0_REGISTER_CMD_CLOCK] = 0;
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] = status;
}
static inline int rsp_status_write(RSP::CPUState *rsp, uint32_t rt)
@@ -79,28 +90,69 @@ extern "C"
uint32_t status = *rsp->cp0.cr[CP0_REGISTER_SP_STATUS];
RSP_HANDLE_STATUS_WRITE(HALT)
RSP_HANDLE_STATUS_WRITE(SSTEP)
RSP_HANDLE_STATUS_WRITE(INTR_BREAK)
RSP_HANDLE_STATUS_WRITE(SIG0)
RSP_HANDLE_STATUS_WRITE(SIG1)
RSP_HANDLE_STATUS_WRITE(SIG2)
RSP_HANDLE_STATUS_WRITE(SIG3)
RSP_HANDLE_STATUS_WRITE(SIG4)
RSP_HANDLE_STATUS_WRITE(SIG5)
RSP_HANDLE_STATUS_WRITE(SIG6)
RSP_HANDLE_STATUS_WRITE(SIG7)
switch (rt & (SP_SET_INTR | SP_CLR_INTR))
{
case SP_SET_INTR: *rsp->cp0.irq |= 1; break;
case SP_CLR_INTR: *rsp->cp0.irq &= ~1; break;
default: break;
}
if ((rt & SP_CLR_HALT) && !(rt & SP_SET_HALT))
status &= ~SP_STATUS_HALT;
if ((rt & SP_SET_HALT) && !(rt & SP_CLR_HALT))
status |= SP_STATUS_HALT;
if (rt & SP_CLR_BROKE)
status &= ~SP_STATUS_BROKE;
if ((rt & SP_CLR_INTR) && !(rt & SP_SET_INTR))
*rsp->cp0.irq &= ~1;
if ((rt & SP_SET_INTR) && !(rt & SP_CLR_INTR))
*rsp->cp0.irq |= 1;
if ((rt & SP_CLR_SSTEP) && !(rt & SP_SET_SSTEP))
status &= ~SP_STATUS_SSTEP;
if ((rt & SP_SET_SSTEP) && !(rt & SP_CLR_SSTEP))
status |= SP_STATUS_SSTEP;
if ((rt & SP_CLR_INTR_BREAK) && !(rt & SP_SET_INTR_BREAK))
status &= ~SP_STATUS_INTR_BREAK;
if ((rt & SP_SET_INTR_BREAK) && !(rt & SP_CLR_INTR_BREAK))
status |= SP_STATUS_INTR_BREAK;
if ((rt & SP_CLR_SIG0) && !(rt & SP_SET_SIG0))
status &= ~SP_STATUS_SIG0;
if ((rt & SP_SET_SIG0) && !(rt & SP_CLR_SIG0))
status |= SP_STATUS_SIG0;
if ((rt & SP_CLR_SIG1) && !(rt & SP_SET_SIG1))
status &= ~SP_STATUS_SIG1;
if ((rt & SP_SET_SIG1) && !(rt & SP_CLR_SIG1))
status |= SP_STATUS_SIG1;
if ((rt & SP_CLR_SIG2) && !(rt & SP_SET_SIG2))
status &= ~SP_STATUS_SIG2;
if ((rt & SP_SET_SIG2) && !(rt & SP_CLR_SIG2))
status |= SP_STATUS_SIG2;
if ((rt & SP_CLR_SIG3) && !(rt & SP_SET_SIG3))
status &= ~SP_STATUS_SIG3;
if ((rt & SP_SET_SIG3) && !(rt & SP_CLR_SIG3))
status |= SP_STATUS_SIG3;
if ((rt & SP_CLR_SIG4) && !(rt & SP_SET_SIG4))
status &= ~SP_STATUS_SIG4;
if ((rt & SP_SET_SIG4) && !(rt & SP_CLR_SIG4))
status |= SP_STATUS_SIG4;
if ((rt & SP_CLR_SIG5) && !(rt & SP_SET_SIG5))
status &= ~SP_STATUS_SIG5;
if ((rt & SP_SET_SIG5) && !(rt & SP_CLR_SIG5))
status |= SP_STATUS_SIG5;
if ((rt & SP_CLR_SIG6) && !(rt & SP_SET_SIG6))
status &= ~SP_STATUS_SIG6;
if ((rt & SP_SET_SIG6) && !(rt & SP_CLR_SIG6))
status |= SP_STATUS_SIG6;
if ((rt & SP_CLR_SIG7) && !(rt & SP_SET_SIG7))
status &= ~SP_STATUS_SIG7;
if ((rt & SP_SET_SIG7) && !(rt & SP_CLR_SIG7))
status |= SP_STATUS_SIG7;
*rsp->cp0.cr[CP0_REGISTER_SP_STATUS] = status;
return ((*rsp->cp0.irq & 1) || (status & SP_STATUS_HALT)) ? MODE_CHECK_FLAGS : MODE_CONTINUE;
}
@@ -109,14 +161,9 @@ extern "C"
static int rsp_dma_read(RSP::CPUState *rsp)
{
uint32_t length_reg = *rsp->cp0.cr[CP0_REGISTER_DMA_READ_LENGTH];
uint32_t length = (length_reg & 0xFFF) + 1;
uint32_t skip = (length_reg >> 20) & 0xFFF;
unsigned count = (length_reg >> 12) & 0xFF;
// Force alignment.
length = (length + 0x7) & ~0x7;
*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] &= ~0x3;
*rsp->cp0.cr[CP0_REGISTER_DMA_DRAM] &= ~0x7;
uint32_t length = ((length_reg & 0xFFF) | 7) + 1;
uint32_t skip = (length_reg >> 20) & 0xFF8;
unsigned count = ((length_reg >> 12) & 0xFF) + 1;
// Check length.
if (((*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] & 0xFFF) + length) > 0x1000)
@@ -156,7 +203,7 @@ extern "C"
source += length + skip;
dest += length;
} while (++i <= count);
} while (++i < count);
*rsp->cp0.cr[CP0_REGISTER_DMA_DRAM] = source;
*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] = dest;
@@ -171,14 +218,9 @@ extern "C"
static void rsp_dma_write(RSP::CPUState *rsp)
{
uint32_t length_reg = *rsp->cp0.cr[CP0_REGISTER_DMA_WRITE_LENGTH];
uint32_t length = (length_reg & 0xFFF) + 1;
uint32_t skip = (length_reg >> 20) & 0xFFF;
unsigned count = (length_reg >> 12) & 0xFF;
// Force alignment.
length = (length + 0x7) & ~0x7;
*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] &= ~0x3;
*rsp->cp0.cr[CP0_REGISTER_DMA_DRAM] &= ~0x7;
uint32_t length = ((length_reg & 0xFFF) | 7) + 1;
uint32_t skip = (length_reg >> 20) & 0xFF8;
unsigned count = ((length_reg >> 12) & 0xFF) + 1;
// Check length.
if (((*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] & 0xFFF) + length) > 0x1000)
@@ -210,7 +252,7 @@ extern "C"
source += length;
dest += length + skip;
} while (++i <= count);
} while (++i < count);
*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] = source;
*rsp->cp0.cr[CP0_REGISTER_DMA_DRAM] = dest;
@@ -228,11 +270,11 @@ extern "C"
switch (static_cast<CP0Registers>(rd & 15))
{
case CP0_REGISTER_DMA_CACHE:
*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] = val & 0x1fff;
*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] = val & 0x1ff8;
break;
case CP0_REGISTER_DMA_DRAM:
*rsp->cp0.cr[CP0_REGISTER_DMA_DRAM] = val & 0xffffff;
*rsp->cp0.cr[CP0_REGISTER_DMA_DRAM] = val & 0xfffff8;
break;
case CP0_REGISTER_DMA_READ_LENGTH:
@@ -254,26 +296,34 @@ extern "C"
return rsp_status_write(rsp, val);
case CP0_REGISTER_SP_SEMAPHORE:
// Any write to the semaphore register, regardless of value, sets it to 0 for the next read
*rsp->cp0.cr[CP0_REGISTER_SP_SEMAPHORE] = 0;
break;
case CP0_REGISTER_CMD_START:
#ifdef INTENSE_DEBUG
fprintf(stderr, "CMD_START 0x%x\n", val & 0xfffffff8u);
fprintf(stderr, "CMD_START 0x%x\n", val & 0xfffff8u);
#endif
*rsp->cp0.cr[CP0_REGISTER_CMD_START] = *rsp->cp0.cr[CP0_REGISTER_CMD_CURRENT] =
*rsp->cp0.cr[CP0_REGISTER_CMD_END] = val & 0xfffffff8u;
if (!(*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] & DPC_STATUS_START_VALID))
{
*rsp->cp0.cr[CP0_REGISTER_CMD_START] = val & 0xfffff8u;
}
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] |= DPC_STATUS_START_VALID;
break;
case CP0_REGISTER_CMD_END:
#ifdef INTENSE_DEBUG
fprintf(stderr, "CMD_END 0x%x\n", val & 0xfffffff8u);
fprintf(stderr, "CMD_END 0x%x\n", val & 0xfffff8u);
#endif
*rsp->cp0.cr[CP0_REGISTER_CMD_END] = val & 0xfffffff8u;
*rsp->cp0.cr[CP0_REGISTER_CMD_END] = val & 0xfffff8u;
if (*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] & DPC_STATUS_START_VALID)
{
*rsp->cp0.cr[CP0_REGISTER_CMD_CURRENT] = *rsp->cp0.cr[CP0_REGISTER_CMD_START];
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] &= ~DPC_STATUS_START_VALID;
}
#ifdef PARALLEL_INTEGRATION
RSP::rsp.ProcessRdpList();
if (*rsp->cp0.irq & 0x20)
return MODE_EXIT;
#endif
break;
@@ -282,14 +332,7 @@ extern "C"
break;
case CP0_REGISTER_CMD_STATUS:
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] &= ~(!!(val & 0x1) << 0);
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] |= (!!(val & 0x2) << 0);
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] &= ~(!!(val & 0x4) << 1);
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] |= (!!(val & 0x8) << 1);
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] &= ~(!!(val & 0x10) << 2);
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] |= (!!(val & 0x20) << 2);
*rsp->cp0.cr[CP0_REGISTER_CMD_TMEM_BUSY] &= !(val & 0x40) * -1;
*rsp->cp0.cr[CP0_REGISTER_CMD_CLOCK] &= !(val & 0x200) * -1;
rdp_status_write(rsp, val);
break;
case CP0_REGISTER_CMD_CURRENT:
+1 -2
View File
@@ -1927,14 +1927,13 @@ ReturnMode CPU::run()
{
case MODE_BREAK:
*state.cp0.cr[CP0_REGISTER_SP_STATUS] |= SP_STATUS_BROKE | SP_STATUS_HALT;
if (*state.cp0.cr[CP0_REGISTER_SP_STATUS] & SP_STATUS_INTR_BREAK)
*state.cp0.irq |= 1;
#ifndef PARALLEL_INTEGRATION
print_registers();
#endif
return MODE_BREAK;
case MODE_CHECK_FLAGS:
case MODE_EXIT:
case MODE_DMA_READ:
return static_cast<ReturnMode>(ret);
+36 -1
View File
@@ -48,6 +48,31 @@ enum CP0Registers
CP0_REGISTER_CMD_TMEM_BUSY = 15,
};
// CMD_STATUS read bits.
#define DPC_STATUS_XBUS_DMEM_DMA 0x001
#define DPC_STATUS_FREEZE 0x002
#define DPC_STATUS_FLUSH 0x004
#define DPC_STATUS_START_GCLK 0x008
#define DPC_STATUS_TMEM_BUSY 0x010
#define DPC_STATUS_PIPE_BUSY 0x020
#define DPC_STATUS_CMD_BUSY 0x040
#define DPC_STATUS_CBUF_READY 0x080
#define DPC_STATUS_DMA_BUSY 0x100
#define DPC_STATUS_END_VALID 0x200
#define DPC_STATUS_START_VALID 0x400
// CMD_STATUS write bits.
#define DPC_CLR_XBUS_DMEM_DMA 0x001
#define DPC_SET_XBUS_DMEM_DMA 0x002
#define DPC_CLR_FREEZE 0x004
#define DPC_SET_FREEZE 0x008
#define DPC_CLR_FLUSH 0x010
#define DPC_SET_FLUSH 0x020
#define DPC_CLR_TMEM_CTR 0x040
#define DPC_CLR_PIPE_CTR 0x080
#define DPC_CLR_CMD_CTR 0x100
#define DPC_CLR_CLOCK_CTR 0x200
// SP_STATUS read bits.
#define SP_STATUS_HALT 0x0001
#define SP_STATUS_BROKE 0x0002
@@ -117,6 +142,9 @@ struct alignas(64) CP2
struct CPUState
{
uint32_t pc = 0;
uint32_t instruction_count = 0;
uint32_t last_instruction_type = 0;
uint32_t instruction_pipeline = 0;
uint32_t dirty_blocks = 0;
static_assert(CODE_BLOCKS <= 32, "Code blocks must fit in 32-bit register.");
@@ -138,7 +166,14 @@ enum ReturnMode
MODE_CONTINUE = 1,
MODE_BREAK = 2,
MODE_DMA_READ = 3,
MODE_CHECK_FLAGS = 4
MODE_CHECK_FLAGS = 4,
MODE_EXIT = 5
};
enum InstructionType
{
VU_INSTRUCTION = 0,
SU_INSTRUCTION = 1
};
} // namespace RSP
+2 -2
View File
@@ -6,7 +6,7 @@
[subrepo]
remote = git@github.com:/gonetz/GLideN64.git
branch = master
commit = 9f8fc1e4c59c4cdb37112ef0c100158b25c2c1cb
parent = 3c615c84599a0ea8624c2deea4c8ba438ce988d6
commit = 55c436c706224eae6cd1395b88e083105b7d7834
parent = 5cab9282e7a7f1407cde18b6e5d1630f3c156042
method = merge
cmdver = 0.4.6
+1 -1
View File
@@ -204,7 +204,7 @@ void GBIInfo::_makeCurrent(MicrocodeInfo * _pCurrent)
RDP_Init();
G_TRI1 = G_TRI2 = G_TRIX = G_QUAD = -1; // For correct work of gSPFlushTriangles()
G_TRI1 = G_TRI2 = G_TRIX = G_QUAD = G_TRISTRIP = G_TRIFAN = -1; // For correct work of gSPFlushTriangles()
gSP.clipRatio = 1U;
switch (m_pCurrent->type) {
@@ -53,6 +53,7 @@ void _loadSettings(GlSettings & settings)
config.generalEmulation.enableLegacyBlending = settings.value("enableLegacyBlending", config.generalEmulation.enableLegacyBlending).toInt(); //ini only
config.generalEmulation.enableHybridFilter = settings.value("enableHybridFilter", config.generalEmulation.enableHybridFilter).toInt(); //ini only
config.generalEmulation.enableFragmentDepthWrite = settings.value("enableFragmentDepthWrite", config.generalEmulation.enableFragmentDepthWrite).toInt(); //ini only
config.generalEmulation.hacks |= settings.value("hacks", config.generalEmulation.hacks).toInt(); //ini only
config.generalEmulation.enableCustomSettings = settings.value("enableCustomSettings", config.generalEmulation.enableCustomSettings).toInt();
settings.endGroup();
@@ -58,6 +58,7 @@ void _loadSettings(QSettings & settings)
config.generalEmulation.enableLegacyBlending = settings.value("enableLegacyBlending", config.generalEmulation.enableLegacyBlending).toInt(); //ini only
config.generalEmulation.enableHybridFilter = settings.value("enableHybridFilter", config.generalEmulation.enableHybridFilter).toInt(); //ini only
config.generalEmulation.enableFragmentDepthWrite = settings.value("enableFragmentDepthWrite", config.generalEmulation.enableFragmentDepthWrite).toInt(); //ini only
config.generalEmulation.hacks |= settings.value("hacks", config.generalEmulation.hacks).toInt(); //ini only
config.generalEmulation.enableCustomSettings = settings.value("enableCustomSettings", config.generalEmulation.enableCustomSettings).toInt();
settings.endGroup();
@@ -193,7 +193,7 @@ void GLInfo::init() {
eglImage = (Utils::isEGLExtensionSupported("EGL_KHR_image_base") || Utils::isEGLExtensionSupported("EGL_KHR_image"));
ext_fetch_arm = Utils::isExtensionSupported(*this, "GL_ARM_shader_framebuffer_fetch") && !ext_fetch;
dual_source_blending = !isGLESX || (Utils::isExtensionSupported(*this, "GL_EXT_blend_func_extended") && !isAnyAdreno);
dual_source_blending = !isGLESX || ((!isGLES2) && (Utils::isExtensionSupported(*this, "GL_EXT_blend_func_extended") && !isAnyAdreno));
anisotropic_filtering = Utils::isExtensionSupported(*this, "GL_EXT_texture_filter_anisotropic");
#ifdef OS_ANDROID
@@ -43,6 +43,8 @@ void gSPFlushTriangles()
(RSP.nextCmd != G_TRI1) &&
(RSP.nextCmd != G_TRI2) &&
(RSP.nextCmd != G_TRIX) &&
(RSP.nextCmd != G_TRISTRIP) &&
(RSP.nextCmd != G_TRIFAN) &&
(RSP.nextCmd != G_QUAD)
) {
dwnd().getDrawer().drawTriangles();
@@ -396,6 +396,8 @@ void Config_LoadCustomConfig()
if (result == M64ERR_SUCCESS) config.generalEmulation.enableLegacyBlending = atoi(value);
result = ConfigExternalGetParameter(fileHandle, sectionName, "generalEmulation\\enableFragmentDepthWrite", value, sizeof(value));
if (result == M64ERR_SUCCESS) config.generalEmulation.enableFragmentDepthWrite = atoi(value);
result = ConfigExternalGetParameter(fileHandle, sectionName, "generalEmulation\\hacks", value, sizeof(value));
if (result == M64ERR_SUCCESS) config.generalEmulation.hacks |= atoi(value);
result = ConfigExternalGetParameter(fileHandle, sectionName, "graphics2D\\correctTexrectCoords", value, sizeof(value));
if (result == M64ERR_SUCCESS) config.graphics2D.correctTexrectCoords = atoi(value);
@@ -170,7 +170,9 @@ struct Vertices7
u8 v[7];
inline bool valid(u8 i) const
{ return v[i] < 64; }
{
return v[i] < 64;
}
};
static inline Vertices7 unpackVertices7(u32 w0, u32 w1)
@@ -186,8 +188,15 @@ static inline Vertices7 unpackVertices7(u32 w0, u32 w1)
return v;
}
struct DeferFlush
{
~DeferFlush()
{ gSPFlushTriangles(); }
};
static void F3DEX3_TriStrip(u32 w0, u32 w1)
{
DeferFlush flush;
Vertices7 vertices = unpackVertices7(w0, w1);
// *v1 - v2 - v3, v3 - v2 - v4, v3 - v4 - v5, v5 - v4 - v6, v5 - v6 - v7
if (!vertices.valid(0) || !vertices.valid(1) || !vertices.valid(2)) return;
@@ -208,6 +217,7 @@ static void F3DEX3_TriStrip(u32 w0, u32 w1)
static void F3DEX3_TriFan(u32 w0, u32 w1)
{
DeferFlush flush;
Vertices7 vertices = unpackVertices7(w0, w1);
// *v1 - v2 - v3, v1 - v3 - v4, v1 - v4 - v5, v1 - v5 - v6, v1 - v6 - v7
if (!vertices.valid(0) || !vertices.valid(1) || !vertices.valid(2)) return;
@@ -220,7 +230,7 @@ static void F3DEX3_TriFan(u32 w0, u32 w1)
gSPTriangle(vertices.v[0], vertices.v[3], vertices.v[4]);
if (!vertices.valid(5)) return;
gSPTriangle(vertices.v[0], vertices.v[3], vertices.v[5]);
gSPTriangle(vertices.v[0], vertices.v[4], vertices.v[5]);
if (!vertices.valid(6)) return;
gSPTriangle(vertices.v[0], vertices.v[5], vertices.v[6]);
+2 -2
View File
@@ -6,7 +6,7 @@
[subrepo]
remote = git@github.com:/Rosalie241/parallel-rdp-standalone.git
branch = RMG
commit = 74a9badf728fcb6a01ceb2ca9668aae5d1f1157c
parent = cb2948ec7404a7ee91e08fd5c3acb65c41629856
commit = 7d1281997ff5a03378c9dd51fefb164cdb4e7877
parent = fddf5eb4a7e99767c4095b34f542098670cdc78b
method = merge
cmdver = 0.4.6
@@ -61,17 +61,15 @@ MainDialog::MainDialog(QWidget* parent) : QDialog(parent)
}
this->resolutionUpscaleComboBox->setCurrentIndex(comboBoxIndex);
// set deinterlacer combobox
this->deinterlacerComboBox->setCurrentIndex(ConfigGetParamBool(configVideoParallel, KEY_DEINTERLACE) ? 1 : 0);
// set downscaling combobox
this->downscalerComboBox->setCurrentIndex(ConfigGetParamInt(configVideoParallel, KEY_DOWNSCALE));
// set cropOverscan combobox
this->cropOverscanSpinBox->setValue(ConfigGetParamInt(configVideoParallel, KEY_OVERSCANCROP));
// set verticalStretch combobox
this->verticalStretchSpinBox->setValue(ConfigGetParamInt(configVideoParallel, KEY_VERTICAL_STRETCH));
this->overscanGroupBox->setChecked(ConfigGetParamBool(configVideoParallel, KEY_OVERSCANCROPENABLE));
this->overscanLeftSpinBox->setValue(ConfigGetParamInt(configVideoParallel, KEY_OVERSCANCROPLEFT));
this->overscanRightSpinBox->setValue(ConfigGetParamInt(configVideoParallel, KEY_OVERSCANCROPRIGHT));
this->overscanTopSpinBox->setValue(ConfigGetParamInt(configVideoParallel, KEY_OVERSCANCROPTOP));
this->overscanBottomSpinBox->setValue(ConfigGetParamInt(configVideoParallel, KEY_OVERSCANCROPBOTTOM));
this->superSampledDitherCheckBox->setChecked(ConfigGetParamBool(configVideoParallel, KEY_SSDITHER));
this->viAaCheckBox->setChecked(ConfigGetParamBool(configVideoParallel, KEY_AA));
@@ -127,8 +125,16 @@ void MainDialog::on_buttonBox_clicked(QAbstractButton* button)
ConfigSetParameter(configVideoParallel, KEY_DOWNSCALE, M64TYPE_INT, &downscalingValue);
// cropOverscan
int cropOverscanValue = this->cropOverscanSpinBox->value();
ConfigSetParameter(configVideoParallel, KEY_OVERSCANCROP, M64TYPE_INT, &cropOverscanValue);
int overscanEnabled = this->overscanGroupBox->isChecked();
int overscanLeft = this->overscanLeftSpinBox->value();
int overscanRight = this->overscanRightSpinBox->value();
int overscanTop = this->overscanTopSpinBox->value();
int overscanBottom = this->overscanBottomSpinBox->value();
ConfigSetParameter(configVideoParallel, KEY_OVERSCANCROPENABLE, M64TYPE_BOOL, &overscanEnabled);
ConfigSetParameter(configVideoParallel, KEY_OVERSCANCROPLEFT, M64TYPE_INT, &overscanLeft);
ConfigSetParameter(configVideoParallel, KEY_OVERSCANCROPRIGHT, M64TYPE_INT, &overscanRight);
ConfigSetParameter(configVideoParallel, KEY_OVERSCANCROPTOP, M64TYPE_INT, &overscanTop);
ConfigSetParameter(configVideoParallel, KEY_OVERSCANCROPBOTTOM, M64TYPE_INT, &overscanBottom);
// verticalStretch
int verticalStretchValue = this->verticalStretchSpinBox->value();
@@ -167,8 +173,12 @@ void MainDialog::on_buttonBox_clicked(QAbstractButton* button)
this->resolutionUpscaleComboBox->setCurrentText("None");
this->deinterlacerComboBox->setCurrentIndex(0);
this->downscalerComboBox->setCurrentIndex(0);
this->cropOverscanSpinBox->setValue(0);
this->verticalStretchSpinBox->setValue(0);
this->overscanGroupBox->setChecked(false);
this->overscanLeftSpinBox->setValue(0);
this->overscanRightSpinBox->setValue(0);
this->overscanTopSpinBox->setValue(0);
this->overscanBottomSpinBox->setValue(0);
this->superSampledDitherCheckBox->setChecked(true);
this->viAaCheckBox->setChecked(true);
@@ -201,27 +201,6 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_8">
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>Crop overscan</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="cropOverscanSpinBox">
<property name="suffix">
<string> px</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_9">
<property name="bottomMargin">
@@ -358,6 +337,53 @@
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="overscanGroupBox">
<property name="title">
<string>Overscan</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QSpinBox" name="overscanTopSpinBox">
<property name="minimum">
<number>-99</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QSpinBox" name="overscanLeftSpinBox">
<property name="minimum">
<number>-99</number>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QSpinBox" name="overscanRightSpinBox">
<property name="minimum">
<number>-99</number>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="overscanBottomSpinBox">
<property name="minimum">
<number>-99</number>
</property>
</widget>
</item>
</layout>
<zorder>overscanBottomSpinBox</zorder>
<zorder>overscanRightSpinBox</zorder>
<zorder>overscanLeftSpinBox</zorder>
<zorder>overscanTopSpinBox</zorder>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
+11 -2
View File
@@ -38,6 +38,7 @@
#include "m64p_types.h"
#include "m64p_config.h"
#include "m64p_plugin.h"
#include <string.h>
#include <stdint.h>
@@ -181,7 +182,11 @@ EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle _CoreLibHandle, void *Co
ConfigSetDefaultBool(configVideoParallel, KEY_DEINTERLACE, 0, "Deinterlacing method. False=Bob, True=Weave");
ConfigSetDefaultBool(configVideoParallel, KEY_SSREADBACKS, 0, "Enable superscaling of readbacks when upsampling");
ConfigSetDefaultBool(configVideoParallel, KEY_SSDITHER, 1, "Enable superscaling of dithering when upsampling");
ConfigSetDefaultInt(configVideoParallel, KEY_OVERSCANCROP, 0, "Amount of overscan pixels to crop on all sides");
ConfigSetDefaultInt(configVideoParallel, KEY_OVERSCANCROPLEFT, 0, "Amount of overscan pixels to crop on the left side");
ConfigSetDefaultInt(configVideoParallel, KEY_OVERSCANCROPRIGHT, 0, "Amount of overscan pixels to crop on the right side");
ConfigSetDefaultInt(configVideoParallel, KEY_OVERSCANCROPTOP, 0, "Amount of overscan pixels to crop on the top side");
ConfigSetDefaultInt(configVideoParallel, KEY_OVERSCANCROPBOTTOM, 0, "Amount of overscan pixels to crop on the bottom side");
ConfigSetDefaultBool(configVideoParallel, KEY_OVERSCANCROPENABLE, 0, "Whether to enable overscan");
ConfigSetDefaultInt(configVideoParallel, KEY_VERTICAL_STRETCH, 0, "Amount of pixels to stretch by vertically. Can fix PAL ports that didn't fill the PAL resolution of 288p (use value of 24 in that case).");
ConfigSetDefaultBool(configVideoParallel, KEY_AA, 1, "VI anti-aliasing, smooths polygon edges.");
ConfigSetDefaultBool(configVideoParallel, KEY_DIVOT, 1, "Allow VI divot filter, cleans up stray black pixels.");
@@ -307,7 +312,11 @@ EXPORT int CALL RomOpen(void)
vk_native_tex_rect = ConfigGetParamBool(configVideoParallel, KEY_NATIVETEXTRECT);
vk_interlacing = ConfigGetParamBool(configVideoParallel, KEY_DEINTERLACE);
vk_downscaling_steps = ConfigGetParamInt(configVideoParallel, KEY_DOWNSCALE);
vk_overscan = ConfigGetParamInt(configVideoParallel, KEY_OVERSCANCROP);
vk_overscan_left = ConfigGetParamInt(configVideoParallel, KEY_OVERSCANCROPLEFT);
vk_overscan_right = ConfigGetParamInt(configVideoParallel, KEY_OVERSCANCROPRIGHT);
vk_overscan_top = ConfigGetParamInt(configVideoParallel, KEY_OVERSCANCROPTOP);
vk_overscan_bottom = ConfigGetParamInt(configVideoParallel, KEY_OVERSCANCROPBOTTOM);
vk_overscan_enable = ConfigGetParamBool(configVideoParallel, KEY_OVERSCANCROPENABLE);
vk_vertical_stretch = ConfigGetParamInt(configVideoParallel, KEY_VERTICAL_STRETCH);
m64p_error netplay_init = ConfigReceiveNetplayConfig(NULL, 0);
+5 -1
View File
@@ -35,7 +35,11 @@ extern ptr_ConfigSetParameter ConfigSetParameter;
#define KEY_WIDESCREEN "WidescreenStretch"
#define KEY_SSDITHER "SuperscaledDither"
#define KEY_SSREADBACKS "SuperscaledReads"
#define KEY_OVERSCANCROP "CropOverscan"
#define KEY_OVERSCANCROPLEFT "CropOverscanLeft"
#define KEY_OVERSCANCROPRIGHT "CropOverscanRight"
#define KEY_OVERSCANCROPTOP "CropOverscanTop"
#define KEY_OVERSCANCROPBOTTOM "CropOverscanBottom"
#define KEY_OVERSCANCROPENABLE "CropOverscanEnable"
#define KEY_VERTICAL_STRETCH "VerticalStretch"
#define KEY_DIVOT "Divot"
#define KEY_GAMMADITHER "GammaDither"
+12 -4
View File
@@ -19,9 +19,13 @@ static std::unique_ptr<MupenWSIPlatform> wsi_platform;
int32_t vk_rescaling;
bool vk_ssreadbacks;
bool vk_ssdither;
unsigned vk_overscan;
unsigned vk_vertical_stretch;
unsigned vk_downscaling_steps;
uint32_t vk_overscan_left;
uint32_t vk_overscan_right;
uint32_t vk_overscan_top;
uint32_t vk_overscan_bottom;
bool vk_overscan_enable;
uint32_t vk_vertical_stretch;
uint32_t vk_downscaling_steps;
bool vk_native_texture_lod;
bool vk_native_tex_rect;
bool vk_divot_filter, vk_gamma_dither;
@@ -180,7 +184,11 @@ static void render_frame(Vulkan::Device &device)
opts.blend_previous_frame = vk_interlacing;
opts.upscale_deinterlacing = !vk_interlacing;
opts.downscale_steps = vk_downscaling_steps;
opts.crop_overscan_pixels = vk_overscan;
opts.crop_rect.left = vk_overscan_left;
opts.crop_rect.right = vk_overscan_right;
opts.crop_rect.top = vk_overscan_top;
opts.crop_rect.bottom = vk_overscan_bottom;
opts.crop_rect.enable = vk_overscan_enable;
if (vk_vertical_stretch) {
opts.crop_rect.top = vk_vertical_stretch;
opts.crop_rect.bottom = vk_vertical_stretch;
+7 -3
View File
@@ -13,9 +13,13 @@ extern "C"
extern bool vk_ssreadbacks;
extern bool vk_ssdither;
extern unsigned vk_overscan;
extern unsigned vk_vertical_stretch;
extern unsigned vk_downscaling_steps;
extern uint32_t vk_overscan_left;
extern uint32_t vk_overscan_right;
extern uint32_t vk_overscan_top;
extern uint32_t vk_overscan_bottom;
extern bool vk_overscan_enable;
extern uint32_t vk_vertical_stretch;
extern uint32_t vk_downscaling_steps;
extern bool vk_native_texture_lod;
extern bool vk_native_tex_rect;
extern bool vk_divot_filter, vk_gamma_dither;
+21 -1
View File
@@ -24,6 +24,26 @@
// Local Functions
//
static std::string get_name_from_headername(uint8_t name[20])
{
std::string safeName;
size_t count = 0;
// count characters from internal
// ROM name, the maximum is 20 so
// we can hardcode that safely
for (; count < 20; count++)
{
if (name[count] == '\0')
{
break;
}
}
safeName = std::string(reinterpret_cast<char*>(name), count);
return CoreConvertStringEncoding(safeName, CoreStringEncoding::Shift_JIS);
}
static std::string get_gameid_from_header(m64p_rom_header header)
{
std::string gameID;
@@ -171,7 +191,7 @@ CORE_EXPORT bool CoreGetCurrentRomHeader(CoreRomHeader& header)
header.CRC1 = ntohl(m64p_header.CRC1);
header.CRC2 = ntohl(m64p_header.CRC2);
header.CountryCode = m64p_header.Country_code;
header.Name = CoreConvertStringEncoding(std::string(reinterpret_cast<char*>(m64p_header.Name), 20), CoreStringEncoding::Shift_JIS);
header.Name = get_name_from_headername(m64p_header.Name);
header.GameID = get_gameid_from_header(m64p_header);
header.Region = get_region_from_countrycode(static_cast<char>(header.CountryCode));
header.SystemType = get_systemtype_from_countrycode(header.CountryCode);
+13 -10
View File
@@ -497,9 +497,12 @@ static l_Setting get_setting(SettingsID settingId)
case SettingsID::KeyBinding_Fullscreen:
setting = {SETTING_SECTION_KEYBIND, "Fullscreen", std::string("Alt+Return")};
break;
case SettingsID::Keybinding_ViewLog:
case SettingsID::KeyBinding_ViewLog:
setting = {SETTING_SECTION_KEYBIND, "ViewLog", std::string("Ctrl+Alt+L")};
break;
case SettingsID::KeyBinding_ViewSearch:
setting = {SETTING_SECTION_KEYBIND, "ViewSearch", std::string("Ctrl+F")};
break;
case SettingsID::KeyBinding_GraphicsSettings:
setting = {SETTING_SECTION_KEYBIND, "GraphicsSettings", std::string("Ctrl+G")};
break;
@@ -538,7 +541,7 @@ static l_Setting get_setting(SettingsID settingId)
setting = {SETTING_SECTION_ROMBROWSER, "Recursive", true};
break;
case SettingsID::RomBrowser_MaxItems:
setting = {SETTING_SECTION_ROMBROWSER, "MaxItems", 1024};
setting = {SETTING_SECTION_ROMBROWSER, "MaxItems", 2048};
break;
case SettingsID::RomBrowser_ColumnVisibility:
setting = {SETTING_SECTION_ROMBROWSER, "ColumnVisibility", std::string("1;1;1;0;0;0;0;0;0;")};
@@ -1360,7 +1363,7 @@ static void config_listsections_callback(void*, const char* section)
l_sectionList.emplace_back(std::string(section));
}
static bool config_section_exists(std::string section)
static bool config_section_exists(const std::string& section)
{
std::string error;
m64p_error ret;
@@ -1384,7 +1387,7 @@ static bool config_section_exists(std::string section)
return std::find(l_sectionList.begin(), l_sectionList.end(), section) != l_sectionList.end();
}
static bool config_section_open(std::string section)
static bool config_section_open(const std::string& section)
{
std::string error;
m64p_error ret;
@@ -1417,7 +1420,7 @@ static void config_listkeys_callback(void*, const char* key, m64p_type)
l_keyList.push_back(std::string(key));
}
static bool config_key_exists(std::string section, std::string key)
static bool config_key_exists(const std::string& section, const std::string& key)
{
std::string error;
m64p_error ret;
@@ -1446,7 +1449,7 @@ static bool config_key_exists(std::string section, std::string key)
return std::find(l_keyList.begin(), l_keyList.end(), key) != l_keyList.end();
}
static bool config_option_set(std::string section, std::string key, m64p_type type, void *value)
static bool config_option_set(const std::string& section, const std::string& key, m64p_type type, void *value)
{
std::string error;
m64p_error ret;
@@ -1472,7 +1475,7 @@ static bool config_option_set(std::string section, std::string key, m64p_type ty
return ret == M64ERR_SUCCESS;
}
static bool config_option_get(std::string section, std::string key, m64p_type type, void *value, int size)
static bool config_option_get(const std::string& section, const std::string& key, m64p_type type, void *value, int size)
{
std::string error;
m64p_error ret;
@@ -1505,7 +1508,7 @@ static bool config_option_get(std::string section, std::string key, m64p_type ty
return ret == M64ERR_SUCCESS;
}
static bool config_option_default_set(std::string section, std::string key, m64p_type type, void *value, const char* description)
static bool config_option_default_set(const std::string& section, const std::string& key, m64p_type type, void *value, const char* description)
{
std::string error;
m64p_error ret;
@@ -1573,7 +1576,7 @@ static bool int_list_to_string(const std::vector<int>& intList, std::string& str
return true;
}
static bool string_to_int_list(std::string string, std::vector<int>& intList)
static bool string_to_int_list(const std::string& string, std::vector<int>& intList)
{
std::string error;
@@ -1628,7 +1631,7 @@ static bool string_list_to_string(const std::vector<std::string>& stringList, st
return true;
}
static bool string_to_string_list(std::string string, std::vector<std::string>& stringList)
static bool string_to_string_list(const std::string& string, std::vector<std::string>& stringList)
{
std::string error;
+2 -1
View File
@@ -166,7 +166,8 @@ enum class SettingsID
KeyBinding_SaveStateSlot8,
KeyBinding_SaveStateSlot9,
KeyBinding_Fullscreen,
Keybinding_ViewLog,
KeyBinding_ViewLog,
KeyBinding_ViewSearch,
KeyBinding_GraphicsSettings,
KeyBinding_AudioSettings,
KeyBinding_RspSettings,
+1
View File
@@ -49,6 +49,7 @@ set(RMG_SOURCES
UserInterface/Widget/RomBrowser/RomBrowserLoadingWidget.cpp
UserInterface/Widget/RomBrowser/RomBrowserEmptyWidget.cpp
UserInterface/Widget/RomBrowser/RomBrowserEmptyWidget.ui
UserInterface/Widget/RomBrowser/RomBrowserSearchWidget.cpp
UserInterface/Widget/Render/DummyWidget.cpp
UserInterface/Widget/Render/OGLWidget.cpp
UserInterface/Widget/Render/VKWidget.cpp
@@ -338,7 +338,7 @@ void AddCheatDialog::accept(void)
QDialog::accept();
}
void AddCheatDialog::on_nameLineEdit_textChanged(QString text)
void AddCheatDialog::on_nameLineEdit_textChanged(void)
{
this->validateOkButton();
}
@@ -49,7 +49,7 @@ class AddCheatDialog : public QDialog, private Ui::AddCheatDialog
private slots:
void accept(void) Q_DECL_OVERRIDE;
void on_nameLineEdit_textChanged(QString text);
void on_nameLineEdit_textChanged(void);
void on_codeTextEdit_textChanged(void);
void on_optionsTextEdit_textChanged(void);
};
@@ -141,7 +141,7 @@ void NetplaySessionDialog::updateCheatsTreeWidget(void)
CheatsCommon::AddCheatsToTreeWidget(true, cheatsArray, this->sessionFile, cheats, this->cheatsTreeWidget, true);
}
void NetplaySessionDialog::on_webSocket_textMessageReceived(QString message)
void NetplaySessionDialog::on_webSocket_textMessageReceived(const QString& message)
{
QJsonDocument jsonDocument = QJsonDocument::fromJson(message.toUtf8());
QJsonObject json = jsonDocument.object();
@@ -225,7 +225,7 @@ void NetplaySessionDialog::on_webSocket_textMessageReceived(QString message)
}
}
void NetplaySessionDialog::on_chatLineEdit_textChanged(QString text)
void NetplaySessionDialog::on_chatLineEdit_textChanged(const QString& text)
{
this->sendPushButton->setEnabled(!text.startsWith(' ') && !text.trimmed().isEmpty() && text.size() <= 256);
this->sendPushButton->setDefault(this->sendPushButton->isEnabled());
@@ -47,9 +47,9 @@ class NetplaySessionDialog : public QDialog, private Ui::NetplaySessionDialog
void updateCheatsTreeWidget(void);
private slots:
void on_webSocket_textMessageReceived(QString message);
void on_webSocket_textMessageReceived(const QString& message);
void on_chatLineEdit_textChanged(QString text);
void on_chatLineEdit_textChanged(const QString& text);
void on_sendPushButton_clicked(void);
void on_buttonBox_clicked(QAbstractButton* button);
@@ -1057,8 +1057,9 @@ void SettingsDialog::commonHotkeySettings(SettingsDialogAction action)
std::vector<keybinding> keybindings_View =
{
{ this->fullscreenKeyButton, SettingsID::KeyBinding_Fullscreen },
{ this->logKeyButton, SettingsID::Keybinding_ViewLog },
{ this->refreshRomListKeyButton, SettingsID::KeyBinding_RefreshROMList }
{ this->logKeyButton, SettingsID::KeyBinding_ViewLog },
{ this->refreshRomListKeyButton, SettingsID::KeyBinding_RefreshROMList },
{ this->searchKeyButton, SettingsID::KeyBinding_ViewSearch }
};
@@ -1681,6 +1681,24 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_122">
<item>
<widget class="QLabel" name="label_119">
<property name="text">
<string>Search</string>
</property>
</widget>
</item>
<item>
<widget class="KeybindButton" name="searchKeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_16">
<property name="orientation">
+12 -1
View File
@@ -837,6 +837,8 @@ void MainWindow::updateActions(bool inEmulation, bool isPaused)
keyBinding = QString::fromStdString(CoreSettingsGetStringValue(SettingsID::KeyBinding_Settings));
this->action_Settings_Settings->setShortcut(QKeySequence(keyBinding));
this->action_View_GameList->setEnabled(!inEmulation);
this->action_View_GameGrid->setEnabled(!inEmulation);
this->action_View_UniformSize->setEnabled(!inEmulation);
keyBinding = QString::fromStdString(CoreSettingsGetStringValue(SettingsID::KeyBinding_Fullscreen));
this->action_View_Fullscreen->setEnabled(inEmulation);
@@ -844,9 +846,12 @@ void MainWindow::updateActions(bool inEmulation, bool isPaused)
keyBinding = QString::fromStdString(CoreSettingsGetStringValue(SettingsID::KeyBinding_RefreshROMList));
this->action_View_RefreshRoms->setEnabled(!inEmulation);
this->action_View_RefreshRoms->setShortcut(QKeySequence(keyBinding));
keyBinding = QString::fromStdString(CoreSettingsGetStringValue(SettingsID::Keybinding_ViewLog));
keyBinding = QString::fromStdString(CoreSettingsGetStringValue(SettingsID::KeyBinding_ViewLog));
this->action_View_Log->setShortcut(QKeySequence(keyBinding));
this->action_View_ClearRomCache->setEnabled(!inEmulation);
keyBinding = QString::fromStdString(CoreSettingsGetStringValue(SettingsID::KeyBinding_ViewSearch));
this->action_View_Search->setShortcut(QKeySequence(keyBinding));
this->action_View_Search->setEnabled(!inEmulation);
#ifdef NETPLAY
this->action_Netplay_CreateSession->setEnabled(!inEmulation && this->netplaySessionDialog == nullptr);
@@ -1180,6 +1185,7 @@ void MainWindow::connectActionSignals(void)
connect(this->action_View_RefreshRoms, &QAction::triggered, this, &MainWindow::on_Action_View_RefreshRoms);
connect(this->action_View_ClearRomCache, &QAction::triggered, this, &MainWindow::on_Action_View_ClearRomCache);
connect(this->action_View_Log, &QAction::triggered, this, &MainWindow::on_Action_View_Log);
connect(this->action_View_Search, &QAction::triggered, this, &MainWindow::on_Action_View_Search);
connect(this->action_Netplay_CreateSession, &QAction::triggered, this, &MainWindow::on_Action_Netplay_CreateSession);
connect(this->action_Netplay_BrowseSessions, &QAction::triggered, this, &MainWindow::on_Action_Netplay_BrowseSessions);
@@ -1952,6 +1958,11 @@ void MainWindow::on_Action_View_Log(void)
this->logDialog.show();
}
void MainWindow::on_Action_View_Search(void)
{
this->ui_Widget_RomBrowser->SetToggleSearch();
}
void MainWindow::on_Action_Netplay_CreateSession(void)
{
#ifdef NETPLAY
+1
View File
@@ -210,6 +210,7 @@ class MainWindow : public QMainWindow, private Ui::MainWindow
void on_Action_View_RefreshRoms(void);
void on_Action_View_ClearRomCache(void);
void on_Action_View_Log(void);
void on_Action_View_Search(void);
void on_Action_Netplay_CreateSession(void);
void on_Action_Netplay_BrowseSessions(void);
+10
View File
@@ -137,6 +137,8 @@
<addaction name="action_View_ClearRomCache"/>
<addaction name="separator"/>
<addaction name="action_View_Log"/>
<addaction name="separator"/>
<addaction name="action_View_Search"/>
</widget>
<widget class="QMenu" name="menuHelp">
<property name="title">
@@ -633,6 +635,14 @@
<string>View Session</string>
</property>
</action>
<action name="action_View_Search">
<property name="icon">
<iconset theme="search-line"/>
</property>
<property name="text">
<string>Search</string>
</property>
</action>
</widget>
<resources>
<include location="UIResources.qrc"/>
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M18.031 16.6168L22.3137 20.8995L20.8995 22.3137L16.6168 18.031C15.0769 19.263 13.124 20 11 20C6.032 20 2 15.968 2 11C2 6.032 6.032 2 11 2C15.968 2 20 6.032 20 11C20 13.124 19.263 15.0769 18.031 16.6168ZM16.0247 15.8748C17.2475 14.6146 18 12.8956 18 11C18 7.1325 14.8675 4 11 4C7.1325 4 4 7.1325 4 11C4 14.8675 7.1325 18 11 18C12.8956 18 14.6146 17.2475 15.8748 16.0247L16.0247 15.8748Z"></path></svg>

After

Width:  |  Height:  |  Size: 489 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M18.031 16.6168L22.3137 20.8995L20.8995 22.3137L16.6168 18.031C15.0769 19.263 13.124 20 11 20C6.032 20 2 15.968 2 11C2 6.032 6.032 2 11 2C15.968 2 20 6.032 20 11C20 13.124 19.263 15.0769 18.031 16.6168ZM16.0247 15.8748C17.2475 14.6146 18 12.8956 18 11C18 7.1325 14.8675 4 11 4C7.1325 4 4 7.1325 4 11C4 14.8675 7.1325 18 11 18C12.8956 18 14.6146 17.2475 15.8748 16.0247L16.0247 15.8748Z" fill="#ffffff"></path></svg>

After

Width:  |  Height:  |  Size: 504 B

+2
View File
@@ -31,6 +31,7 @@
<file alias="icons/black/svg/shut-down-line.svg">Resource/icons/black/svg/shut-down-line.svg</file>
<file alias="icons/black/svg/speed-line.svg">Resource/icons/black/svg/speed-line.svg</file>
<file alias="icons/black/svg/tools-line.svg">Resource/icons/black/svg/tools-line.svg</file>
<file alias="icons/black/svg/search-line.svg">Resource/icons/black/svg/search-line.svg</file>
<file alias="icons/black/svg/server-line.svg">Resource/icons/black/svg/server-line.svg</file>
<file alias="icons/black/svg/settings-3-line.svg">Resource/icons/black/svg/settings-3-line.svg</file>
<file alias="icons/black/svg/volume-up-line.svg">Resource/icons/black/svg/volume-up-line.svg</file>
@@ -63,6 +64,7 @@
<file alias="icons/white/svg/shut-down-line.svg">Resource/icons/white/svg/shut-down-line.svg</file>
<file alias="icons/white/svg/speed-line.svg">Resource/icons/white/svg/speed-line.svg</file>
<file alias="icons/white/svg/tools-line.svg">Resource/icons/white/svg/tools-line.svg</file>
<file alias="icons/white/svg/search-line.svg">Resource/icons/white/svg/search-line.svg</file>
<file alias="icons/white/svg/server-line.svg">Resource/icons/white/svg/server-line.svg</file>
<file alias="icons/white/svg/settings-3-line.svg">Resource/icons/white/svg/settings-3-line.svg</file>
<file alias="icons/white/svg/volume-up-line.svg">Resource/icons/white/svg/volume-up-line.svg</file>
@@ -0,0 +1,57 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020-2025 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "RomBrowserSearchWidget.hpp"
using namespace UserInterface::Widget;
RomBrowserSearchWidget::RomBrowserSearchWidget(QWidget* parent) : QWidget(parent)
{
// configure search line edit
this->lineEdit = new QLineEdit(this);
this->lineEdit->setPlaceholderText("Search games...");
connect(this->lineEdit, &QLineEdit::textChanged, this, &RomBrowserSearchWidget::on_lineEdit_textChanged);
// configure close button
this->closeButton = new QPushButton(this);
this->closeButton->setText("Close");
connect(this->closeButton, &QPushButton::clicked, this, &RomBrowserSearchWidget::on_closeButton_clicked);
// configure layout
this->widgetLayout = new QHBoxLayout(this);
this->widgetLayout->addWidget(this->lineEdit);
this->widgetLayout->addWidget(this->closeButton);
this->setLayout(this->widgetLayout);
}
RomBrowserSearchWidget::~RomBrowserSearchWidget(void)
{
}
void RomBrowserSearchWidget::FocusSearchText(void)
{
this->lineEdit->setFocus();
}
void RomBrowserSearchWidget::ClearSearchTerm(void)
{
this->lineEdit->setText("");
}
void RomBrowserSearchWidget::on_lineEdit_textChanged(const QString& text)
{
emit this->SearchTextChanged(text);
}
void RomBrowserSearchWidget::on_closeButton_clicked(void)
{
this->hide();
this->ClearSearchTerm();
}
@@ -0,0 +1,48 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020-2025 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef ROMBROWSERSEARCHWIDGET_HPP
#define ROMBROWSERSEARCHWIDGET_HPP
#include <QPushButton>
#include <QHBoxLayout>
#include <QLineEdit>
#include <QWidget>
namespace UserInterface
{
namespace Widget
{
class RomBrowserSearchWidget : public QWidget
{
Q_OBJECT
public:
RomBrowserSearchWidget(QWidget* parent);
~RomBrowserSearchWidget(void);
void FocusSearchText(void);
void ClearSearchTerm(void);
signals:
void SearchTextChanged(const QString& text);
private:
QHBoxLayout* widgetLayout = nullptr;
QLineEdit* lineEdit = nullptr;
QPushButton* closeButton = nullptr;
private slots:
void on_lineEdit_textChanged(const QString& text);
void on_closeButton_clicked(void);
};
}
}
#endif // ROMBROWSERSEARCHWIDGET_HPP
@@ -56,11 +56,26 @@ Q_DECLARE_METATYPE(RomBrowserModelData);
// Exported Functions
//
RomBrowserWidget::RomBrowserWidget(QWidget *parent) : QStackedWidget(parent)
RomBrowserWidget::RomBrowserWidget(QWidget *parent) : QWidget(parent)
{
// configure signal types
qRegisterMetaType<CoreRomType>("CoreRomType");
// configure stacked widget
this->stackedWidget = new QStackedWidget(this);
// configure search widget
this->searchWidget = new Widget::RomBrowserSearchWidget(this);
this->searchWidget->setVisible(false);
connect(this->searchWidget, &RomBrowserSearchWidget::SearchTextChanged, this, &RomBrowserWidget::on_searchWidget_SearchTextChanged);
// configure layout
QVBoxLayout* layout = new QVBoxLayout(this);
layout->addWidget(this->stackedWidget);
layout->addWidget(this->searchWidget);
layout->setContentsMargins(0, 0, 0, 0);
this->setLayout(layout);
// configure rom searcher thread
this->romSearcherThread = new Thread::RomSearcherThread(this);
connect(this->romSearcherThread, &Thread::RomSearcherThread::RomsFound, this, &RomBrowserWidget::on_RomBrowserThread_RomsFound);
@@ -68,21 +83,23 @@ RomBrowserWidget::RomBrowserWidget(QWidget *parent) : QStackedWidget(parent)
// configure empty widget
this->emptyWidget = new Widget::RomBrowserEmptyWidget(this);
this->addWidget(this->emptyWidget);
this->stackedWidget->addWidget(this->emptyWidget);
connect(this->emptyWidget, &RomBrowserEmptyWidget::SelectRomDirectory, this, &RomBrowserWidget::on_Action_ChangeRomDirectory);
connect(this->emptyWidget, &RomBrowserEmptyWidget::Refresh, this, &RomBrowserWidget::on_Action_RefreshRomList);
connect(this->emptyWidget, &RomBrowserEmptyWidget::FileDropped, this, &RomBrowserWidget::FileDropped);
// configure loading widget
this->loadingWidget = new Widget::RomBrowserLoadingWidget(this);
connect(this, &QStackedWidget::currentChanged, this->loadingWidget, &RomBrowserLoadingWidget::on_RomBrowserWidget_currentChanged);
connect(this->stackedWidget, &QStackedWidget::currentChanged, this->loadingWidget, &RomBrowserLoadingWidget::on_RomBrowserWidget_currentChanged);
connect(this->loadingWidget, &RomBrowserLoadingWidget::FileDropped, this, &RomBrowserWidget::FileDropped);
this->loadingWidget->SetWidgetIndex(this->addWidget(this->loadingWidget));
this->loadingWidget->SetWidgetIndex(this->stackedWidget->addWidget(this->loadingWidget));
// configure list view widget
this->listViewWidget = new Widget::RomBrowserListViewWidget(this);
this->listViewModel = new QStandardItemModel(this);
this->listViewWidget->setModel(this->listViewModel);
this->listViewProxyModel = new QSortFilterProxyModel(this);
this->listViewProxyModel->setSourceModel(this->listViewModel);
this->listViewWidget->setModel(this->listViewProxyModel);
this->listViewWidget->setFrameStyle(QFrame::NoFrame);
this->listViewWidget->setItemDelegate(new NoFocusDelegate(this));
this->listViewWidget->setWordWrap(false);
@@ -101,7 +118,7 @@ RomBrowserWidget::RomBrowserWidget(QWidget *parent) : QStackedWidget(parent)
this->listViewWidget->horizontalHeader()->setSortIndicatorShown(false);
this->listViewWidget->horizontalHeader()->setHighlightSections(false);
this->listViewWidget->horizontalHeader()->setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu);
this->addWidget(this->listViewWidget);
this->stackedWidget->addWidget(this->listViewWidget);
connect(this->listViewWidget, &QTableView::doubleClicked, this, &RomBrowserWidget::on_DoubleClicked);
connect(this->listViewWidget->horizontalHeader(), &QHeaderView::sortIndicatorChanged, this, &RomBrowserWidget::on_listViewWidget_sortIndicatorChanged);
connect(this->listViewWidget->horizontalHeader(), &QHeaderView::sectionResized, this, &RomBrowserWidget::on_listViewWidget_sectionResized);
@@ -139,7 +156,9 @@ RomBrowserWidget::RomBrowserWidget(QWidget *parent) : QStackedWidget(parent)
// configure grid view widget
this->gridViewWidget = new Widget::RomBrowserGridViewWidget(this);
this->gridViewModel = new QStandardItemModel(this);
this->gridViewWidget->setModel(this->gridViewModel);
this->gridViewProxyModel = new QSortFilterProxyModel(this);
this->gridViewProxyModel->setSourceModel(this->gridViewModel);
this->gridViewWidget->setModel(this->gridViewProxyModel);
this->gridViewWidget->setFlow(QListView::Flow::LeftToRight);
this->gridViewWidget->setResizeMode(QListView::Adjust);
#ifndef DRAG_DROP
@@ -157,7 +176,7 @@ RomBrowserWidget::RomBrowserWidget(QWidget *parent) : QStackedWidget(parent)
int iconWidth = CoreSettingsGetIntValue(SettingsID::RomBrowser_GridViewIconWidth);
int iconHeight = CoreSettingsGetIntValue(SettingsID::RomBrowser_GridViewIconHeight);
this->gridViewWidget->setIconSize(QSize(iconWidth, iconHeight));
this->addWidget(this->gridViewWidget);
this->stackedWidget->addWidget(this->gridViewWidget);
connect(this->gridViewWidget, &QListView::doubleClicked, this, &RomBrowserWidget::on_DoubleClicked);
connect(this->gridViewWidget, &QListView::iconSizeChanged, this, &RomBrowserWidget::on_gridViewWidget_iconSizeChanged);
connect(this->gridViewWidget, &Widget::RomBrowserGridViewWidget::ZoomIn, this, &RomBrowserWidget::on_ZoomIn);
@@ -279,11 +298,15 @@ void RomBrowserWidget::RefreshRomList(void)
QString directory = QString::fromStdString(CoreSettingsGetStringValue(SettingsID::RomBrowser_Directory));
if (directory.isEmpty())
{
this->setCurrentWidget(this->emptyWidget);
this->stackedWidget->setCurrentWidget(this->emptyWidget);
return;
}
this->setCurrentWidget(this->loadingWidget);
this->stackedWidget->setCurrentWidget(this->loadingWidget);
this->showSearchWidget = this->searchWidget->isVisible();
this->searchWidget->hide();
this->romSearcherTimer.start();
this->romSearcherThread->SetMaximumFiles(CoreSettingsGetIntValue(SettingsID::RomBrowser_MaxItems));
@@ -308,9 +331,9 @@ void RomBrowserWidget::ShowList(void)
// only change widget now when we're not refreshing
if (!this->IsRefreshingRomList() &&
this->currentWidget() != this->emptyWidget)
this->stackedWidget->currentWidget() != this->emptyWidget)
{
this->setCurrentWidget(this->listViewWidget);
this->stackedWidget->setCurrentWidget(this->listViewWidget);
}
}
@@ -320,9 +343,9 @@ void RomBrowserWidget::ShowGrid(void)
// only change widget now when we're not refreshing
if (!this->IsRefreshingRomList() &&
this->currentWidget() != this->emptyWidget)
this->stackedWidget->currentWidget() != this->emptyWidget)
{
this->setCurrentWidget(this->gridViewWidget);
this->stackedWidget->setCurrentWidget(this->gridViewWidget);
}
}
@@ -330,7 +353,7 @@ void RomBrowserWidget::SetGridViewUniformSizes(bool value)
{
// refresh ROM list when we're currently in the grid view
// and we're not refreshing already
if (this->currentWidget() == this->gridViewWidget &&
if (this->stackedWidget->currentWidget() == this->gridViewWidget &&
!this->IsRefreshingRomList())
{
if (this->gridViewWidget->uniformItemSizes() != value)
@@ -344,20 +367,46 @@ void RomBrowserWidget::SetGridViewUniformSizes(bool value)
this->gridViewWidget->setUniformItemSizes(value);
}
void RomBrowserWidget::SetToggleSearch(void)
{
const bool show = !this->searchWidget->isVisible();
// do nothing when not in a valid view
QWidget* currentWidget = this->stackedWidget->currentWidget();
if (currentWidget == this->loadingWidget ||
currentWidget == this->emptyWidget)
{
return;
}
this->searchWidget->setVisible(show);
if (show)
{
// set focus when it's being shown
this->searchWidget->FocusSearchText();
}
else
{
// reset search when hidden
this->searchWidget->ClearSearchTerm();
}
}
QMap<QString, CoreRomSettings> RomBrowserWidget::GetModelData(void)
{
QMap<QString, CoreRomSettings> data;
QStandardItemModel* model = this->getCurrentModel();
QPair<QStandardItemModel*, QSortFilterProxyModel*> model = this->getCurrentModel();
RomBrowserModelData modelData;
if (model == nullptr)
if (model.first == nullptr)
{
return data;
}
for (int i = 0; i < model->rowCount(); i++)
for (int i = 0; i < model.first->rowCount(); i++)
{
modelData = model->item(i)->data().value<RomBrowserModelData>();
modelData = model.first->item(i)->data().value<RomBrowserModelData>();
// only add cartridges, 64dd disks aren't supported
if (modelData.type == CoreRomType::Cartridge)
{
@@ -368,9 +417,9 @@ QMap<QString, CoreRomSettings> RomBrowserWidget::GetModelData(void)
return data;
}
QStandardItemModel* RomBrowserWidget::getCurrentModel(void)
QPair<QStandardItemModel*, QSortFilterProxyModel*> RomBrowserWidget::getCurrentModel(void)
{
QWidget* currentWidget = this->currentWidget();
QWidget* currentWidget = this->stackedWidget->currentWidget();
if (currentWidget == this->loadingWidget)
{
currentWidget = this->currentViewWidget;
@@ -378,19 +427,19 @@ QStandardItemModel* RomBrowserWidget::getCurrentModel(void)
if (currentWidget == this->listViewWidget)
{
return this->listViewModel;
return qMakePair(this->listViewModel, this->listViewProxyModel);
}
else if (currentWidget == this->gridViewWidget)
{
return this->gridViewModel;
return qMakePair(this->gridViewModel, this->gridViewProxyModel);
}
return nullptr;
return qMakePair(nullptr, nullptr);
}
QAbstractItemView* RomBrowserWidget::getCurrentModelView(void)
{
QWidget* currentWidget = this->currentWidget();
QWidget* currentWidget = this->stackedWidget->currentWidget();
if (currentWidget == this->loadingWidget)
{
currentWidget = this->currentViewWidget;
@@ -410,16 +459,16 @@ QAbstractItemView* RomBrowserWidget::getCurrentModelView(void)
bool RomBrowserWidget::getCurrentData(RomBrowserModelData& data)
{
QStandardItemModel* model = this->getCurrentModel();
QAbstractItemView* view = this->getCurrentModelView();
QPair<QStandardItemModel*, QSortFilterProxyModel*> model = this->getCurrentModel();
QAbstractItemView* view = this->getCurrentModelView();
if (model == nullptr || view == nullptr)
if (model.first == nullptr || model.second == nullptr || view == nullptr)
{
return false;
}
QModelIndex index = view->currentIndex();
QStandardItem* item = model->item(index.row(), 0);
QModelIndex index = model.second->mapToSource(view->currentIndex());
QStandardItem* item = model.first->item(index.row(), 0);
if (item == nullptr)
{
@@ -614,7 +663,8 @@ QIcon RomBrowserWidget::getCurrentCover(QString file, CoreRomHeader header, Core
void RomBrowserWidget::timerEvent(QTimerEvent* event)
{
this->killTimer(event->timerId());
this->setCurrentWidget(this->currentViewWidget);
this->stackedWidget->setCurrentWidget(this->currentViewWidget);
this->searchWidget->setVisible(this->showSearchWidget);
}
void RomBrowserWidget::on_DoubleClicked(const QModelIndex& index)
@@ -624,9 +674,8 @@ void RomBrowserWidget::on_DoubleClicked(const QModelIndex& index)
void RomBrowserWidget::customContextMenuRequested(QPoint position)
{
QStandardItemModel* model = this->getCurrentModel();
QAbstractItemView* view = this->getCurrentModelView();
if (view == nullptr || model == nullptr)
QAbstractItemView* view = this->getCurrentModelView();
if (view == nullptr)
{
return;
}
@@ -713,20 +762,20 @@ void RomBrowserWidget::generateColumnsMenu(void)
void RomBrowserWidget::generatePlayWithDiskMenu(void)
{
QAction* playGameWithAction;
QStandardItemModel* model = this->getCurrentModel();
QPair<QStandardItemModel*, QSortFilterProxyModel*> model = this->getCurrentModel();
RomBrowserModelData modelData;
int count = 0;
this->menu_PlayGameWithDisk->clear();
if (model == nullptr)
if (model.first == nullptr)
{
return;
}
for (int i = 0; i < model->rowCount(); i++)
for (int i = 0; i < model.first->rowCount(); i++)
{
modelData = model->item(i)->data().value<RomBrowserModelData>();
modelData = model.first->item(i)->data().value<RomBrowserModelData>();
if (modelData.type == CoreRomType::Disk)
{
if (count == 0)
@@ -736,8 +785,8 @@ void RomBrowserWidget::generatePlayWithDiskMenu(void)
}
playGameWithAction = new QAction(this);
playGameWithAction->setText(model->item(i)->text());
playGameWithAction->setData(model->item(i)->data());
playGameWithAction->setText(model.first->item(i)->text());
playGameWithAction->setData(model.first->item(i)->data());
this->menu_PlayGameWithDisk->addAction(playGameWithAction);
// only add 10 disks to menu,
@@ -794,6 +843,19 @@ void RomBrowserWidget::generateStateMenu(void)
this->menu_PlayGameWithSlot->setDisabled(this->menu_PlayGameWithSlot->isEmpty());
}
void RomBrowserWidget::on_searchWidget_SearchTextChanged(const QString& text)
{
// TODO: I should really make a custom data
// model at this point to save memory & CPU cycles...
this->listViewProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
this->listViewProxyModel->setFilterWildcard(text);
this->listViewProxyModel->setFilterKeyColumn(0);
this->gridViewProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
this->gridViewProxyModel->setFilterWildcard(text);
this->gridViewProxyModel->setFilterKeyColumn(0);
}
void RomBrowserWidget::on_listViewWidget_sortIndicatorChanged(int logicalIndex, Qt::SortOrder sortOrder)
{
CoreSettingsSetValue(SettingsID::RomBrowser_ListViewSortSection, logicalIndex);
@@ -910,8 +972,8 @@ void RomBrowserWidget::on_RomBrowserThread_RomsFound(QList<RomSearcherThreadData
void RomBrowserWidget::on_RomBrowserThread_Finished(bool canceled)
{
// sort data
this->listViewModel->sort(this->listViewSortSection, (Qt::SortOrder)this->listViewSortOrder);
this->gridViewModel->sort(0, Qt::SortOrder::AscendingOrder);
this->listViewProxyModel->sort(this->listViewSortSection, (Qt::SortOrder)this->listViewSortOrder);
this->gridViewProxyModel->sort(0, Qt::SortOrder::AscendingOrder);
// retrieve column settings
std::vector<int> columnSizes = CoreSettingsGetIntListValue(SettingsID::RomBrowser_ColumnSizes);
@@ -1007,7 +1069,7 @@ void RomBrowserWidget::on_RomBrowserThread_Finished(bool canceled)
if (this->listViewModel->rowCount() == 0)
{
this->setCurrentWidget(this->emptyWidget);
this->stackedWidget->setCurrentWidget(this->emptyWidget);
return;
}
@@ -1020,7 +1082,8 @@ void RomBrowserWidget::on_RomBrowserThread_Finished(bool canceled)
return;
}
this->setCurrentWidget(this->currentViewWidget);
this->stackedWidget->setCurrentWidget(this->currentViewWidget);
this->searchWidget->setVisible(this->showSearchWidget);
}
void RomBrowserWidget::on_Action_PlayGame(void)
@@ -1144,9 +1207,9 @@ void RomBrowserWidget::on_Action_SetCoverImage(void)
QFileInfo sourceFileInfo;
QString coverFile;
QStandardItemModel* model = this->getCurrentModel();
QAbstractItemView* view = this->getCurrentModelView();
if (model == nullptr || view == nullptr)
QPair<QStandardItemModel*, QSortFilterProxyModel*> model = this->getCurrentModel();
QAbstractItemView* view = this->getCurrentModelView();
if (model.first == nullptr || model.second == nullptr || view == nullptr)
{
return;
}
@@ -1165,9 +1228,9 @@ void RomBrowserWidget::on_Action_SetCoverImage(void)
// retrieve file info
sourceFileInfo = QFileInfo(sourceFile);
QModelIndex index = view->currentIndex();
QStandardItem* item = model->item(index.row(), index.column());
RomBrowserModelData data = model->itemData(index).last().value<RomBrowserModelData>();
QModelIndex index = model.second->mapToSource(view->currentIndex());
QStandardItem* item = model.first->item(index.row(), index.column());
RomBrowserModelData data = model.first->itemData(index).last().value<RomBrowserModelData>();
// construct new file name (for the cover)
QString newFileName = this->coversDirectory;
@@ -1203,16 +1266,16 @@ void RomBrowserWidget::on_Action_SetCoverImage(void)
void RomBrowserWidget::on_Action_RemoveCoverImage(void)
{
QStandardItemModel* model = this->getCurrentModel();
QPair<QStandardItemModel*, QSortFilterProxyModel*> model = this->getCurrentModel();
QAbstractItemView* view = this->getCurrentModelView();
if (model == nullptr || view == nullptr)
if (model.first == nullptr || model.second == nullptr || view == nullptr)
{
return;
}
QModelIndex index = view->currentIndex();
QStandardItem* item = model->item(index.row(), index.column());
RomBrowserModelData data = model->itemData(index).last().value<RomBrowserModelData>();
QModelIndex index = model.second->mapToSource(view->currentIndex());
QStandardItem* item = model.first->item(index.row(), index.column());
RomBrowserModelData data = model.first->itemData(index).last().value<RomBrowserModelData>();
QString coverFile;
if (!data.coverFile.isEmpty() && QFile::exists(data.coverFile))
@@ -16,18 +16,22 @@
#include "RomBrowserListViewWidget.hpp"
#include "RomBrowserGridViewWidget.hpp"
#include "RomBrowserLoadingWidget.hpp"
#include "RomBrowserSearchWidget.hpp"
#include "RomBrowserEmptyWidget.hpp"
#include <QSortFilterProxyModel>
#include <QStandardItemModel>
#include <QStackedWidget>
#include <QGridLayout>
#include <QListWidget>
#include <QHeaderView>
#include <QTableView>
#include <QLineEdit>
#include <QAction>
#include <QString>
#include <QList>
#include <QMenu>
#include <QPair>
#include <QMap>
// forward declaration of internal struct
@@ -37,7 +41,7 @@ namespace UserInterface
{
namespace Widget
{
class RomBrowserWidget : public QStackedWidget
class RomBrowserWidget : public QWidget
{
Q_OBJECT
@@ -53,17 +57,24 @@ class RomBrowserWidget : public QStackedWidget
void ShowGrid(void);
void SetGridViewUniformSizes(bool value);
void SetToggleSearch(void);
QMap<QString, CoreRomSettings> GetModelData(void);
private:
QStackedWidget* stackedWidget = nullptr;
Widget::RomBrowserEmptyWidget* emptyWidget = nullptr;
Widget::RomBrowserLoadingWidget* loadingWidget = nullptr;
Widget::RomBrowserListViewWidget* listViewWidget = nullptr;
QStandardItemModel* listViewModel = nullptr;
QSortFilterProxyModel* listViewProxyModel = nullptr;
Widget::RomBrowserGridViewWidget* gridViewWidget = nullptr;
QStandardItemModel* gridViewModel = nullptr;
QSortFilterProxyModel* gridViewProxyModel = nullptr;
Widget::RomBrowserSearchWidget* searchWidget = nullptr;
bool showSearchWidget = false;
QWidget* currentViewWidget = nullptr;
@@ -96,7 +107,7 @@ class RomBrowserWidget : public QStackedWidget
QString coversDirectory;
QStandardItemModel* getCurrentModel(void);
QPair<QStandardItemModel*, QSortFilterProxyModel*> getCurrentModel(void);
QAbstractItemView* getCurrentModelView(void);
bool getCurrentData(RomBrowserModelData& data);
@@ -116,6 +127,8 @@ class RomBrowserWidget : public QStackedWidget
void generatePlayWithDiskMenu(void);
void generateStateMenu(void);
void on_searchWidget_SearchTextChanged(const QString& text);
void on_listViewWidget_sortIndicatorChanged(int logicalIndex, Qt::SortOrder sortOrder);
void on_listViewWidget_sectionResized(int logicalIndex, int oldWidth, int newWidth);
void on_listViewWidget_sectionMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex);
+1 -1
View File
@@ -1 +1 @@
v0.7.8
v0.7.9