This commit is contained in:
moonpower
2025-11-18 03:59:11 +03:00
parent 32a93c23fd
commit db39d45da8
14 changed files with 530 additions and 260 deletions
Vendored
BIN
View File
Binary file not shown.
+2 -1
View File
@@ -24,4 +24,5 @@ snap/
*.iso
*.mcd
*.rom
*.o
*.o
psxe.app
+22 -28
View File
@@ -1,32 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>psxe</string>
<key>CFBundleIdentifier</key>
<string>psxe.app.0</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>psxe</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.1-alpha</string>
<key>CFBundleSignature</key>
<string>psxe</string>
<key>CFBundleVersion</key>
<string>0.1-alpha</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.games</string>
<key>LSMinimumSystemVersion</key>
<string>10.6</string>
<key>NSHighResolutionCapable</key>
<true/>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>psxe</string>
<key>CFBundleIdentifier</key>
<string>psxe.app.0</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>psxe</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.10.4-alpha</string>
<key>CFBundleVersion</key>
<string>0.10.4-alpha</string>
<key>LSMinimumSystemVersion</key>
<string>10.9</string>
<key>NSHighResolutionCapable</key>
<true/>
</dict>
</plist>
+62 -32
View File
@@ -1,35 +1,65 @@
.ONESHELL:
CFLAGS := -g -DLOG_USE_COLOR `sdl2-config --cflags --libs`
CFLAGS += -Ofast -Wno-overflow -Wall -pedantic -Wno-address-of-packed-member -flto
PLATFORM := $(shell uname -s)
ifeq ($(PLATFORM),Darwin)
CFLAGS += -mmacosx-version-min=10.9 -Wno-newline-eof
endif
VERSION_TAG := $(shell git describe --always --tags --abbrev=0)
COMMIT_HASH := $(shell git rev-parse --short HEAD)
OS_INFO := $(shell uname -rmo)
SOURCES := $(wildcard psx/*.c)
CFLAGS := -g -DLOG_USE_COLOR `sdl2-config --cflags --libs`
CFLAGS += -Ofast -Wno-overflow -Wall -pedantic -Wno-address-of-packed-member -flto
PLATFORM := $(shell uname -s)
ifeq ($(PLATFORM),Darwin)
CFLAGS += -mmacosx-version-min=10.9 -Wno-newline-eof
endif
SHARED_EXT := .so
SHARED_LDFLAGS := -shared
SHARED_CFLAGS := $(CFLAGS) -D__DLL_BUILD -fPIC
ifeq ($(PLATFORM),Darwin)
SHARED_EXT := .dylib
SHARED_LDFLAGS := -dynamiclib
endif
VERSION_TAG := $(shell git describe --always --tags --abbrev=0)
COMMIT_HASH := $(shell git rev-parse --short HEAD)
OS_INFO := $(shell uname -rmo)
SOURCES := $(wildcard psx/*.c)
SOURCES += $(wildcard psx/dev/*.c)
SOURCES += $(wildcard psx/dev/cdrom/*.c)
SOURCES += $(wildcard psx/input/*.c)
SOURCES += $(wildcard psx/disc/*.c)
SOURCES += $(wildcard frontend/*.c)
bin/psxe frontend/main.c:
mkdir -p bin
gcc $(SOURCES) -o bin/psxe \
-I"." \
-I"psx" \
-DOS_INFO="$(OS_INFO)" \
-DREP_VERSION="$(VERSION_TAG)" \
-DREP_COMMIT_HASH="$(COMMIT_HASH)" \
$(CFLAGS)
clean:
rm -rf "bin"
SOURCES += $(wildcard psx/dev/cdrom/*.c)
SOURCES += $(wildcard psx/input/*.c)
SOURCES += $(wildcard psx/disc/*.c)
SOURCES += $(wildcard frontend/*.c)
SHARED_SOURCES := $(filter-out frontend/main.c,$(SOURCES))
BIN_DIR := bin
BIN := $(BIN_DIR)/psxe
SHARED_BIN := $(BIN_DIR)/libpsxe$(SHARED_EXT)
.PHONY: all clean shared
all: $(BIN)
$(BIN_DIR):
mkdir -p $(BIN_DIR)
$(BIN): $(SOURCES) | $(BIN_DIR)
gcc $(SOURCES) -o $(BIN) \
-I"." \
-I"psx" \
-DOS_INFO="$(OS_INFO)" \
-DREP_VERSION="$(VERSION_TAG)" \
-DREP_COMMIT_HASH="$(COMMIT_HASH)" \
$(CFLAGS)
shared: $(SHARED_BIN)
$(SHARED_BIN): $(SHARED_SOURCES) | $(BIN_DIR)
gcc $(SHARED_LDFLAGS) $(SHARED_SOURCES) -o $(SHARED_BIN) \
-I"." \
-I"psx" \
-DOS_INFO="$(OS_INFO)" \
-DREP_VERSION="$(VERSION_TAG)" \
-DREP_COMMIT_HASH="$(COMMIT_HASH)" \
$(SHARED_CFLAGS)
clean:
rm -rf "$(BIN_DIR)"
+46 -11
View File
@@ -12,11 +12,11 @@ A simple and portable Sony PlayStation emulator and emulation library written in
![macOS](https://github.com/allkern/psx/actions/workflows/macos.yml/badge.svg)
![Ubuntu](https://github.com/allkern/psx/actions/workflows/ubuntu.yml/badge.svg)
## Running
You can download the latest automated build for your platform on Releases. If your system isn't supported, you can easily build the emulator from source, instructions on "Building" below.
In order to run the emulator, you will need a BIOS file. You can either get one from the internet or [dump it from your own console](https://www.youtube.com/watch?v=u8eHp0COcBo).
## Running
You can download the latest automated build for your platform on Releases. If your system isn't supported, you can easily build the emulator from source, instructions on "Building" below.
In order to run the emulator, you will need a BIOS file. You can either get one from the internet or [dump it from your own console](https://www.youtube.com/watch?v=u8eHp0COcBo).
Most BIOS versions are confirmed to work.
Use the `-b` or `--bios` setting to configure the BIOS file.
@@ -72,12 +72,47 @@ cd psxe
make clean && make
```
### macOS
```
git clone https://github.com/allkern/psxe
cd psxe
./build.sh
```
### macOS
```
git clone https://github.com/allkern/psxe
cd psxe
./build.sh
```
## Configuration
A `settings.toml` is generated on first run next to the executable. CLI flags always override file settings for a session.
### Settings file keys
- `psxe_version` (string, managed by PSXE)
`[bios]`
- `search_path` (string): directory to search for BIOS files
- `preferred_model` (string): default model (e.g. `SCPH-1001`)
- `override_file` (string): explicit BIOS path; leave empty to use search/model
`[console]`
- `region` (string): `ntsc`, `pal`, or `auto`
`[video]`
- `texture_scale_mode` (bool): enable SDL texture scale mode; toggle bilinear via F4 when supported
### CLI flags (override settings)
`psxe [options] path-to-cdrom`
- `-a, --use-args` : ignore settings file
- `-b, --bios=<str>` : BIOS file
- `-B, --bios-folder` : BIOS search folder
- `-c, --console-source=<str>` : auto | null | kernel | atcons
- `-e, --exp-rom=<str>` : expansion ROM file
- `-L, --log-level=<int>` : 0=trace .. 5=fatal
- `-M, --model=<str>` : console model (SCPH-XXXX)
- `-r, --region=<str>` : console region
- `-s, --scale=<int>` : display scaling factor
- `-S, --settings-file=<str>` : settings file path
- `-q, --quiet` : silence logs
- `-x, --exe=<str>` : PS-X EXE to boot
- `--cdrom=<str>` : CDROM image
- `-h/--help` | `--help-model` | `--help-region` | `-v/--version` : info helpers
## Acknowledgements
This project uses external open source code that can be found on the following GitHub repos:
+29 -12
View File
@@ -1,19 +1,36 @@
#!/bin/sh
# Build emulator
make clean && make
# Build options:
# BUILD_DLL=1 -> build shared library (libpsxe.* with __DLL_BUILD)
# BUILD_DLL_ONLY=1 -> build only the shared library
# BUNDLE_APP=1 -> bundle macOS .app (uses executable build)
# Create bundle filesystem
mkdir -p psxe.app/Contents/MacOS/Libraries
make clean
# Move executable to folder
mv bin/psxe psxe.app/Contents/MacOS
if [ "${BUILD_DLL_ONLY:-0}" != "0" ]; then
make shared
else
make
if [ "${BUILD_DLL:-0}" != "0" ]; then
make shared
fi
# Make executable
chmod 777 psxe.app/Contents/MacOS/psxe
if [ "${BUNDLE_APP:-0}" != "0" ]; then
# Create bundle filesystem
mkdir -p psxe.app/Contents/MacOS/Libraries
# Bundle required dylibs
dylibbundler -b -x ./psxe.app/Contents/MacOS/psxe -d ./psxe.app/Contents/Libraries/ -p @executable_path/../Libraries/ -cd
# Copy executable to bundle folder (keep bin/psxe intact)
cp bin/psxe psxe.app/Contents/MacOS
# Move plist to Contents folder
mv Info.plist psxe.app/Contents/Info.plist
# Make executable
chmod 777 psxe.app/Contents/MacOS/psxe
# Bundle required dylibs
dylibbundler -b -x ./psxe.app/Contents/MacOS/psxe -d ./psxe.app/Contents/Libraries/ -p @executable_path/../Libraries/ -cd
# Copy plist to Contents folder (keep a copy in repo for subsequent builds)
cp Info.plist psxe.app/Contents/Info.plist
else
echo "Skipping macOS .app bundle. Set BUNDLE_APP=1 to build the application bundle."
fi
fi
+90 -54
View File
@@ -19,11 +19,11 @@ static const char* g_version_text =
"This is free software; see the source for copying conditions. There is NO\n"
"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n";
static const char g_default_settings[] =
"# Settings file generated by PSXE\n"
"\n"
"# Don't change please, reserved for future use\n"
"psxe_version = \"" STR(REP_VERSION) "\"\n"
static const char g_default_settings[] =
"# Settings file generated by PSXE\n"
"\n"
"# Don't change please, reserved for future use\n"
"psxe_version = \"" STR(REP_VERSION) "\"\n"
"\n"
"# BIOS-related settings:\n"
"[bios]\n"
@@ -31,9 +31,13 @@ static const char g_default_settings[] =
" preferred_model = \"SCPH-1001\"\n"
" override_file = \"\"\n"
"\n"
"# Console settings\n"
"[console]\n"
" region = \"auto\"\n";
"# Console settings\n"
"[console]\n"
" region = \"auto\"\n"
"\n"
"# Video settings\n"
"[video]\n"
" texture_scale_mode = false\n";
static const char* g_models_text =
"Available console models:\n"
@@ -78,8 +82,8 @@ void psxe_cfg_destroy(psxe_config_t* cfg) {
free(cfg);
}
void psxe_cfg_load_defaults(psxe_config_t* cfg) {
cfg->bios = "bios.bin";
void psxe_cfg_load_defaults(psxe_config_t* cfg) {
cfg->bios = "bios.bin";
cfg->bios_search = "bios";
cfg->exe = NULL;
cfg->help_model = 0;
@@ -91,25 +95,39 @@ void psxe_cfg_load_defaults(psxe_config_t* cfg) {
cfg->settings_path = NULL;
cfg->use_args = 0;
cfg->version = 0;
cfg->log_level = LOG_FATAL;
cfg->quiet = 0;
cfg->cd_path = NULL;
cfg->exp_path = NULL;
}
cfg->log_level = LOG_FATAL;
cfg->quiet = 0;
cfg->cd_path = NULL;
cfg->exp_path = NULL;
cfg->texture_scale_mode = 0;
}
void psxe_cfg_load(psxe_config_t* cfg, int argc, const char* argv[]) {
log_set_level(LOG_INFO);
void psxe_cfg_load(psxe_config_t* cfg, int argc, const char* argv[]) {
log_set_level(LOG_INFO);
// macOS .app bundles can inject a "-psn_*" argument; drop it before parsing
const char** argv_filtered = (const char**)malloc(sizeof(char*) * argc);
int argc_filtered = 0;
for (int i = 0; i < argc; i++) {
if (strncmp(argv[i], "-psn_", 5) == 0)
continue;
argv_filtered[argc_filtered++] = argv[i];
}
int use_args = 0;
int version = 0;
int use_args = 0;
int version = 0;
int help_model = 0;
int help_region = 0;
int log_level = 0;
int quiet = 0;
int console_source = 0;
int scale = 0;
const char* settings_path = NULL;
const char* bios = NULL;
int quiet = 0;
int console_source = 0;
int scale = 0;
int texture_scale_mode = 0;
const char* settings_path = NULL;
const char* bios = NULL;
int bios_from_cli = 0;
const char* bios_search = NULL;
const char* model = NULL;
const char* exe = NULL;
@@ -130,7 +148,7 @@ void psxe_cfg_load(psxe_config_t* cfg, int argc, const char* argv[]) {
OPT_BOOLEAN ('v', "version" , &version , "Display version and build information", NULL, 0, 0),
OPT_GROUP("Basic options"),
OPT_BOOLEAN ('a', "use-args" , &use_args , "Ignore settings file, use CLI args instead", NULL, 0, 0),
OPT_STRING ('b', "bios" , &bios , "Specify a BIOS file (ignores -B, -M)", NULL, 0, 0),
OPT_STRING ('b', "bios" , &bios , "Specify a BIOS file (ignores -B, -M)", NULL, 0, 0),
OPT_BOOLEAN ('B', "bios-folder" , &bios_search , "Specify a BIOS search folder", NULL, 0, 0),
OPT_STRING ('c', "console-source", &console_source, "Select console source (auto, null, kernel, atcons)"),
OPT_STRING ('e', "exp-rom" , &exp_path , "Specify an expansion ROM file"),
@@ -147,10 +165,13 @@ void psxe_cfg_load(psxe_config_t* cfg, int argc, const char* argv[]) {
struct argparse argparse;
argparse_init(&argparse, options, usages, 0);
argparse_describe(&argparse, NULL, g_desc_text);
argc = argparse_parse(&argparse, argc, argv);
argparse_init(&argparse, options, usages, 0);
argparse_describe(&argparse, NULL, g_desc_text);
argc = argparse_parse(&argparse, argc_filtered, argv_filtered);
if (bios)
bios_from_cli = 1;
if (help_model) {
printf("%s\n", g_models_text);
@@ -201,10 +222,10 @@ void psxe_cfg_load(psxe_config_t* cfg, int argc, const char* argv[]) {
toml_table_t* conf = toml_parse_file(settings, error, sizeof(error));
if (!conf) {
log_error("Couldn't parse settings file");
exit(1);
}
log_error("Couldn't parse settings file");
exit(1);
}
toml_datum_t s_version = toml_string_in(conf, "psxe_version");
@@ -227,27 +248,36 @@ void psxe_cfg_load(psxe_config_t* cfg, int argc, const char* argv[]) {
if (s_bios_preferred_model.ok)
model = s_bios_preferred_model.u.s;
toml_datum_t s_bios_override_file = toml_string_in(s_bios_table, "override_file");
if (s_bios_override_file.ok)
bios = s_bios_override_file.u.s;
toml_datum_t s_bios_override_file = toml_string_in(s_bios_table, "override_file");
if (!bios_from_cli && s_bios_override_file.ok && s_bios_override_file.u.s[0])
bios = s_bios_override_file.u.s;
}
toml_table_t* s_console_table = toml_table_in(conf, "console");
if (s_console_table) {
toml_datum_t s_console_region = toml_string_in(s_console_table, "region");
if (s_console_region.ok)
region = s_console_region.u.s;
}
psxe_version = s_version.u.s;
if (s_console_table) {
toml_datum_t s_console_region = toml_string_in(s_console_table, "region");
if (s_console_region.ok)
region = s_console_region.u.s;
}
toml_table_t* s_video_table = toml_table_in(conf, "video");
if (s_video_table) {
toml_datum_t s_texture_scale_mode = toml_bool_in(s_video_table, "texture_scale_mode");
if (s_texture_scale_mode.ok)
texture_scale_mode = s_texture_scale_mode.u.b;
}
psxe_version = s_version.u.s;
log_info("Settings file parsed. PSXE version: %s", psxe_version);
fclose(settings);
}
fclose(settings);
}
if (argc) {
if (argc > 1) {
@@ -283,12 +313,18 @@ void psxe_cfg_load(psxe_config_t* cfg, int argc, const char* argv[]) {
if (psxe_version)
cfg->psxe_version = psxe_version;
if (exp_path)
cfg->exp_path = exp_path;
if (scale)
cfg->scale = scale;
}
if (exp_path)
cfg->exp_path = exp_path;
if (scale)
cfg->scale = scale;
cfg->texture_scale_mode = texture_scale_mode;
log_info("Using BIOS path: %s", cfg->bios ? cfg->bios : "(none)");
free(argv_filtered);
}
// To-do: Implement BIOS searching
char* psxe_cfg_get_bios_path(psxe_config_t* cfg) {
@@ -296,4 +332,4 @@ char* psxe_cfg_get_bios_path(psxe_config_t* cfg) {
}
#undef STR1
#undef STR
#undef STR
+12 -11
View File
@@ -10,16 +10,17 @@ typedef struct {
int use_args;
int version;
int help_model;
int help_region;
int log_level;
int quiet;
int console_source;
int scale;
const char* snap_path;
const char* settings_path;
const char* bios;
const char* bios_search;
const char* model;
int help_region;
int log_level;
int quiet;
int console_source;
int scale;
int texture_scale_mode;
const char* snap_path;
const char* settings_path;
const char* bios;
const char* bios_search;
const char* model;
const char* exe;
const char* region;
const char* psxe_version;
@@ -34,4 +35,4 @@ void psxe_cfg_load(psxe_config_t*, int, const char**);
char* psxe_cfg_get_bios_path(psxe_config_t*);
void psxe_cfg_destroy(psxe_config_t*);
#endif
#endif
+15 -10
View File
@@ -37,21 +37,26 @@ int main(int argc, const char* argv[]) {
log_set_level(cfg->log_level);
psx_t* psx = psx_create();
psx_init(psx, cfg->bios, cfg->exp_path);
psx_t* psx = psx_create();
int init_result = psx_init(psx, cfg->bios, cfg->exp_path);
if (init_result) {
log_fatal("Failed to initialize PSX (code %d). Check BIOS/expansion paths and settings.", init_result);
return 1;
}
psx_cdrom_t* cdrom = psx_get_cdrom(psx);
// To-do: Set CDROM firmware version and region based
// on CLI options
if (cfg->cd_path)
psx_cdrom_open(cdrom, cfg->cd_path);
psxe_screen_t* screen = psxe_screen_create();
psxe_screen_init(screen, psx);
psxe_screen_set_scale(screen, cfg->scale);
psxe_screen_reload(screen);
if (cfg->cd_path)
psx_cdrom_open(cdrom, cfg->cd_path);
psxe_screen_t* screen = psxe_screen_create();
psxe_screen_init(screen, psx, cfg);
psxe_screen_set_scale(screen, cfg->scale);
psxe_screen_reload(screen);
SDL_Init(SDL_INIT_AUDIO);
@@ -126,4 +131,4 @@ int main(int argc, const char* argv[]) {
psxe_screen_destroy(screen);
return 0;
}
}
+92 -59
View File
@@ -1,7 +1,8 @@
#include "screen.h"
#include "input/sda.h"
#include "input/guncon.h"
#include "screen.h"
#include "input/sda.h"
#include "input/guncon.h"
#include "../psx/log.h"
uint32_t screen_get_button(SDL_Keycode k) {
if (k == SDLK_x ) return PSXI_SW_SDA_CROSS;
@@ -66,16 +67,30 @@ int screen_get_base_width(psxe_screen_t* screen) {
return 320;
}
psxe_screen_t* psxe_screen_create(void) {
return (psxe_screen_t*)malloc(sizeof(psxe_screen_t));
}
void psxe_screen_init(psxe_screen_t* screen, psx_t* psx) {
memset(screen, 0, sizeof(psxe_screen_t));
if (screen->debug_mode) {
screen->width = PSX_GPU_FB_WIDTH;
screen->height = PSX_GPU_FB_HEIGHT;
psxe_screen_t* psxe_screen_create(void) {
return (psxe_screen_t*)malloc(sizeof(psxe_screen_t));
}
static void psxe_screen_apply_texture_scale_mode(psxe_screen_t* screen) {
#if SDL_VERSION_ATLEAST(2, 0, 12)
if (!screen->texture_scale_mode)
return;
SDL_ScaleMode scale_mode = screen->bilinear ? SDL_ScaleModeLinear : SDL_ScaleModeNearest;
if (SDL_SetTextureScaleMode(screen->texture, scale_mode) < 0) {
log_warn("SDL_SetTextureScaleMode failed, disabling texture_scale_mode: %s", SDL_GetError());
screen->texture_scale_mode = 0;
}
#endif
}
void psxe_screen_init(psxe_screen_t* screen, psx_t* psx, const psxe_config_t* cfg) {
memset(screen, 0, sizeof(psxe_screen_t));
if (screen->debug_mode) {
screen->width = PSX_GPU_FB_WIDTH;
screen->height = PSX_GPU_FB_HEIGHT;
} else {
screen->width = 320;
screen->height = 240;
@@ -83,23 +98,29 @@ void psxe_screen_init(psxe_screen_t* screen, psx_t* psx) {
screen->scale = 1;
screen->open = 1;
screen->format = SDL_PIXELFORMAT_BGR555;
screen->psx = psx;
screen->pad = psx_get_pad(psx);
screen->texture_width = PSX_GPU_FB_WIDTH;
screen->texture_height = PSX_GPU_FB_HEIGHT;
screen->format = SDL_PIXELFORMAT_BGR555;
screen->psx = psx;
screen->pad = psx_get_pad(psx);
screen->texture_scale_mode = cfg ? cfg->texture_scale_mode : 0;
screen->bilinear = screen->texture_scale_mode ? SDL_ScaleModeLinear : SDL_ScaleModeNearest;
screen->texture_width = PSX_GPU_FB_WIDTH;
screen->texture_height = PSX_GPU_FB_HEIGHT;
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_GAMECONTROLLER);
SDL_SetRenderDrawColor(screen->renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
screen->controller = screen_find_controller();
}
void psxe_screen_reload(psxe_screen_t* screen) {
if (screen->texture) SDL_DestroyTexture(screen->texture);
if (screen->renderer) SDL_DestroyRenderer(screen->renderer);
if (screen->window) SDL_DestroyWindow(screen->window);
screen->controller = screen_find_controller();
}
void psxe_screen_set_window_handle(psxe_screen_t* screen, void* native_handle) {
screen->external_window = native_handle;
}
void psxe_screen_reload(psxe_screen_t* screen) {
if (screen->texture) SDL_DestroyTexture(screen->texture);
if (screen->renderer) SDL_DestroyRenderer(screen->renderer);
if (screen->window) SDL_DestroyWindow(screen->window);
if (screen->debug_mode) {
screen->width = PSX_GPU_FB_WIDTH;
@@ -113,14 +134,30 @@ void psxe_screen_reload(psxe_screen_t* screen) {
screen->height = 240;
}
}
screen->window = SDL_CreateWindow(
"psxe " STR(REP_VERSION) "-" STR(REP_COMMIT_HASH),
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
screen->width * screen->scale,
screen->height * screen->scale,
0
);
#ifndef __DLL_BUILD
screen->window = SDL_CreateWindow(
"psxe " STR(REP_VERSION) "-" STR(REP_COMMIT_HASH),
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
screen->width * screen->scale,
screen->height * screen->scale,
0
);
#else
if (!screen->external_window) {
log_error("DLL build requires external window handle before reload");
screen->open = 0;
return;
}
screen->window = SDL_CreateWindowFrom(screen->external_window);
if (!screen->window) {
log_error("Failed to create SDL window from external handle: %s", SDL_GetError());
screen->open = 0;
return;
}
#endif
screen->renderer = SDL_CreateRenderer(
screen->window,
@@ -128,16 +165,14 @@ void psxe_screen_reload(psxe_screen_t* screen) {
SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC
);
screen->texture = SDL_CreateTexture(
screen->renderer,
screen->format,
SDL_TEXTUREACCESS_STREAMING,
screen->texture_width, screen->texture_height
);
#if SDL_VERSION_ATLEAST(2, 0, 12)
SDL_SetTextureScaleMode(screen->texture, screen->bilinear);
#endif
screen->texture = SDL_CreateTexture(
screen->renderer,
screen->format,
SDL_TEXTUREACCESS_STREAMING,
screen->texture_width, screen->texture_height
);
psxe_screen_apply_texture_scale_mode(screen);
// Check for retina displays
int width = 0, height = 0;
@@ -511,19 +546,17 @@ void psxe_gpu_dmode_event_cb(psx_gpu_t* gpu) {
SDL_DestroyTexture(screen->texture);
screen->texture = SDL_CreateTexture(
screen->renderer,
screen->format,
SDL_TEXTUREACCESS_STREAMING,
screen->texture_width, screen->texture_height
);
#if SDL_VERSION_ATLEAST(2, 0, 12)
SDL_SetTextureScaleMode(screen->texture, screen->bilinear);
#endif
SDL_SetWindowSize(screen->window, screen->width, screen->height);
}
screen->texture = SDL_CreateTexture(
screen->renderer,
screen->format,
SDL_TEXTUREACCESS_STREAMING,
screen->texture_width, screen->texture_height
);
psxe_screen_apply_texture_scale_mode(screen);
SDL_SetWindowSize(screen->window, screen->width, screen->height);
}
void psxe_gpu_vblank_event_cb(psx_gpu_t* gpu) {
psxe_screen_t* screen = gpu->udata[0];
@@ -531,4 +564,4 @@ void psxe_gpu_vblank_event_cb(psx_gpu_t* gpu) {
psxe_screen_update(screen);
psxe_gpu_vblank_timer_event_cb(gpu);
}
}
+23 -19
View File
@@ -1,8 +1,9 @@
#ifndef SCREEN_H
#define SCREEN_H
#include "../psx/psx.h"
#include "common.h"
#include "../psx/psx.h"
#include "common.h"
#include "config.h"
#include <string.h>
@@ -22,29 +23,32 @@ typedef struct {
unsigned int width, height, scale;
unsigned int image_width, image_height;
unsigned int image_xoff, image_yoff;
unsigned int format;
unsigned int texture_width, texture_height;
int bilinear;
int fullscreen;
int vertical_mode;
int debug_mode;
int open;
unsigned int format;
unsigned int texture_width, texture_height;
void* external_window;
int texture_scale_mode;
int bilinear;
int fullscreen;
int vertical_mode;
int debug_mode;
int open;
SDL_GameController* controller;
} psxe_screen_t;
psxe_screen_t* psxe_screen_create(void);
void psxe_screen_init(psxe_screen_t*, psx_t*);
void psxe_screen_reload(psxe_screen_t*);
int psxe_screen_is_open(psxe_screen_t*);
void psxe_screen_update(psxe_screen_t*);
void psxe_screen_destroy(psxe_screen_t*);
void psxe_screen_set_scale(psxe_screen_t*, unsigned int);
void psxe_screen_toggle_debug_mode(psxe_screen_t*);
psxe_screen_t* psxe_screen_create(void);
void psxe_screen_init(psxe_screen_t*, psx_t*, const psxe_config_t*);
void psxe_screen_reload(psxe_screen_t*);
int psxe_screen_is_open(psxe_screen_t*);
void psxe_screen_update(psxe_screen_t*);
void psxe_screen_destroy(psxe_screen_t*);
void psxe_screen_set_scale(psxe_screen_t*, unsigned int);
void psxe_screen_set_window_handle(psxe_screen_t*, void* native_handle);
void psxe_screen_toggle_debug_mode(psxe_screen_t*);
// GPU event handlers
void psxe_gpu_dmode_event_cb(psx_gpu_t*);
void psxe_gpu_vblank_event_cb(psx_gpu_t*);
#endif
#endif
+25 -20
View File
@@ -1,13 +1,14 @@
#include "bios.h"
#include "../log.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
psx_bios_t* psx_bios_create(void) {
return (psx_bios_t*)malloc(sizeof(psx_bios_t));
}
#include "../log.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
psx_bios_t* psx_bios_create(void) {
return (psx_bios_t*)malloc(sizeof(psx_bios_t));
}
void psx_bios_init(psx_bios_t* bios) {
memset(bios, 0, sizeof(psx_bios_t));
@@ -17,14 +18,16 @@ void psx_bios_init(psx_bios_t* bios) {
bios->bus_delay = 18;
}
int psx_bios_load(psx_bios_t* bios, const char* path) {
if (!path)
return 0;
FILE* file = fopen(path, "rb");
if (!file)
return 1;
int psx_bios_load(psx_bios_t* bios, const char* path) {
if (!path)
return 0;
FILE* file = fopen(path, "rb");
if (!file) {
log_error("Failed to open BIOS at '%s': %s", path, strerror(errno));
return 1;
}
// Almost all PS1 BIOS ROMs are 512 KiB in size.
// There's (at least) one exception, and that is SCPH-5903.
@@ -40,8 +43,10 @@ int psx_bios_load(psx_bios_t* bios, const char* path) {
bios->buf = malloc(size);
bios->io_size = size;
if (!fread(bios->buf, 1, size, file))
return 2;
if (!fread(bios->buf, 1, size, file)) {
log_error("Failed to read BIOS at '%s': %s", path, strerror(errno));
return 2;
}
fclose(file);
@@ -75,4 +80,4 @@ void psx_bios_write8(psx_bios_t* bios, uint32_t offset, uint8_t value) {
void psx_bios_destroy(psx_bios_t* bios) {
free(bios->buf);
free(bios);
}
}
+12 -1
View File
@@ -4,6 +4,7 @@
#include <stdio.h>
#include "cdrom.h"
#include "../../log.h"
typedef void (*cdrom_cmd_func)(psx_cdrom_t* cdrom);
@@ -194,11 +195,21 @@ int psx_cdrom_open(psx_cdrom_t* cdrom, const char* path) {
cdrom->disc_type = psx_disc_open(cdrom->disc, path);
if (cdrom->disc_type == CDT_ERROR) {
log_error("Failed to open CD image: %s", path);
psx_cdrom_close(cdrom);
return 0;
}
if (cdrom->disc_type != CDT_LICENSED) {
log_error("CD image not recognized as a licensed PSX disc (type=%d). Use a proper BIN/CUE rip.", cdrom->disc_type);
psx_cdrom_close(cdrom);
return 0;
}
log_info("CD image type: Licensed");
return 1;
}
@@ -759,4 +770,4 @@ void psx_cdrom_write32(psx_cdrom_t* cdrom, uint32_t addr, uint32_t value) {
void psx_cdrom_write16(psx_cdrom_t* cdrom, uint32_t addr, uint32_t value) {
assert("16-bit CDROM writes are not supported" && 0);
}
}
+100 -2
View File
@@ -1,8 +1,10 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "disc.h"
#include "cue.h"
#include "../../log.h"
#define MSF_TO_LBA(m, s, f) ((m * 4500) + (s * 75) + f)
@@ -13,8 +15,67 @@ const char* disc_cd_extensions[] = {
0
};
typedef struct {
FILE* file;
uint32_t sector_size;
uint32_t sector_count;
} raw_disc_t;
static int raw_read(void* udata, uint32_t lba, void* buf) {
raw_disc_t* raw = (raw_disc_t*)udata;
if (!raw || !raw->file)
return 0;
if (lba >= raw->sector_count)
return 0;
if (fseek(raw->file, (long long)lba * raw->sector_size, SEEK_SET))
return 0;
size_t to_read = raw->sector_size;
memset(buf, 0, CD_SECTOR_SIZE);
return fread(buf, 1, to_read, raw->file) == to_read ? TS_DATA : 0;
}
static int raw_query(void* udata, uint32_t lba) {
raw_disc_t* raw = (raw_disc_t*)udata;
return (raw && (lba < raw->sector_count)) ? TS_DATA : TS_FAR;
}
static int raw_get_track_number(void* udata, uint32_t lba) {
(void)udata; (void)lba;
return 1;
}
static int raw_get_track_count(void* udata) {
(void)udata;
return 1;
}
static uint32_t raw_get_track_lba(void* udata, int track) {
(void)udata; (void)track;
return 0;
}
static void raw_destroy(void* udata) {
raw_disc_t* raw = (raw_disc_t*)udata;
if (raw && raw->file)
fclose(raw->file);
free(raw);
}
psx_disc_t* psx_disc_create(void) {
return malloc(sizeof(psx_disc_t));
psx_disc_t* disc = malloc(sizeof(psx_disc_t));
if (disc)
memset(disc, 0, sizeof(psx_disc_t));
return disc;
}
int disc_get_extension(const char* path) {
@@ -81,12 +142,49 @@ int psx_disc_open_as(psx_disc_t* disc, const char* path, int type) {
if (cue_load(cue, LD_FILE))
return CDT_ERROR;
} break;
case CD_EXT_BIN:
case CD_EXT_ISO: {
FILE* f = fopen(path, "rb");
if (!f)
return CDT_ERROR;
fseek(f, 0, SEEK_END);
long long size = ftell(f);
fseek(f, 0, SEEK_SET);
raw_disc_t* raw = (raw_disc_t*)malloc(sizeof(raw_disc_t));
raw->file = f;
raw->sector_size = (type == CD_EXT_BIN) ? CD_SECTOR_SIZE : 2048;
raw->sector_count = (uint32_t)(size / raw->sector_size);
disc->udata = raw;
disc->read_sector = raw_read;
disc->query_sector = raw_query;
disc->get_track_number = raw_get_track_number;
disc->get_track_count = raw_get_track_count;
disc->get_track_lba = raw_get_track_lba;
disc->destroy = raw_destroy;
} break;
default:
return CDT_ERROR;
}
if (!disc->read_sector) {
log_error("Unsupported or failed to open disc image: %s", path);
return CDT_ERROR;
}
return disc_get_cd_type(disc);
}
int psx_disc_read(psx_disc_t* disc, uint32_t lba, void* buf) {
if (!disc->read_sector)
return 0;
return disc->read_sector(disc->udata, lba, buf);
}
@@ -110,4 +208,4 @@ void psx_disc_destroy(psx_disc_t* disc) {
disc->destroy(disc->udata);
free(disc);
}
}