Replace frame pacing with vblank timing and add VSync toggle

This commit is contained in:
moonpower
2026-04-05 19:47:08 +02:00
parent eb70fbc0fe
commit 476b46a873
43 changed files with 1689 additions and 336 deletions
+3 -1
View File
@@ -3,6 +3,8 @@
#include <stdint.h>
#include "frontend/diagnostics.h"
#include "queue.h"
#include "disc.h"
#include "../ic.h"
@@ -307,4 +309,4 @@ void psx_cdrom_update(psx_cdrom_t* cdrom, int cycles);
void psx_cdrom_get_audio_samples(psx_cdrom_t* cdrom, void* buf, size_t size);
void psx_cdrom_destroy(psx_cdrom_t* cdrom);
#endif
#endif
+3 -1
View File
@@ -1,6 +1,8 @@
#ifndef CUE_H
#define CUE_H
#include "frontend/diagnostics.h"
#include "list.h"
#include "disc.h"
@@ -97,4 +99,4 @@ int cue_get_track_lba(cue_t* cue, int track);
void cue_init_disc(cue_t* cue, psx_disc_t* disc);
void cue_destroy(cue_t* cue);
#endif
#endif
+62 -53
View File
@@ -1888,20 +1888,25 @@ void psx_gpu_set_udata(psx_gpu_t* gpu, int index, void* udata) {
gpu->udata[index] = udata;
}
#define GPU_CYCLES_PER_HDRAW_NTSC 2560.0f
#define GPU_CYCLES_PER_SCANL_NTSC 3413.0f
#define GPU_SCANS_PER_VDRAW_NTSC 240
#define GPU_SCANS_PER_FRAME_NTSC 263
#define GPU_CYCLES_PER_SCANL_PAL 3406.0f
#define GPU_SCANS_PER_FRAME_PAL 314
void gpu_hblank_event(psx_gpu_t* gpu) {
if (gpu->line < GPU_SCANS_PER_VDRAW_NTSC) {
if (gpu->line & 1) {
gpu->gpustat |= 1 << 31;
} else {
gpu->gpustat &= ~(1 << 31);
}
#define GPU_CYCLES_PER_HDRAW_NTSC 2560.0f
#define GPU_CYCLES_PER_SCANL_NTSC 3413.0f
#define GPU_SCANS_PER_VDRAW_NTSC 240
#define GPU_SCANS_PER_FRAME_NTSC 263
#define GPU_CYCLES_PER_HDRAW_PAL 2560.0f
#define GPU_CYCLES_PER_SCANL_PAL 3406.0f
#define GPU_SCANS_PER_VDRAW_PAL 288
#define GPU_SCANS_PER_FRAME_PAL 314
void gpu_hblank_event(psx_gpu_t* gpu) {
const int scans_per_vdraw = psx_gpu_is_pal_mode(gpu) ? GPU_SCANS_PER_VDRAW_PAL : GPU_SCANS_PER_VDRAW_NTSC;
const int scans_per_frame = psx_gpu_is_pal_mode(gpu) ? GPU_SCANS_PER_FRAME_PAL : GPU_SCANS_PER_FRAME_NTSC;
if (gpu->line < scans_per_vdraw) {
if (gpu->line & 1) {
gpu->gpustat |= 1 << 31;
} else {
gpu->gpustat &= ~(1 << 31);
}
// HACK!! More games are fine with this
// but others, like Dead or Alive, will refuse
@@ -1933,45 +1938,49 @@ void gpu_hblank_event(psx_gpu_t* gpu) {
// psx_ic_irq(gpu->ic, IC_SPU);
} else {
gpu->gpustat &= ~(1 << 31);
}
gpu->line++;
if (gpu->line == GPU_SCANS_PER_VDRAW_NTSC) {
if (gpu->event_cb_table[GPU_EVENT_VBLANK])
gpu->event_cb_table[GPU_EVENT_VBLANK](gpu);
psx_ic_irq(gpu->ic, IC_VBLANK);
} else if (gpu->line == GPU_SCANS_PER_FRAME_NTSC) {
if (gpu->event_cb_table[GPU_EVENT_VBLANK_END])
gpu->event_cb_table[GPU_EVENT_VBLANK_END](gpu);
gpu->line = 0;
}
}
void psx_gpu_update(psx_gpu_t* gpu, int cyc) {
int prev_hblank = (gpu->cycles >= GPU_CYCLES_PER_HDRAW_NTSC) &&
(gpu->cycles <= GPU_CYCLES_PER_SCANL_NTSC);
// Convert CPU (~33.8 MHz) cycles to GPU (~53.7 MHz) cycles
gpu->cycles += (float)cyc * (PSX_GPU_CLOCK_FREQ_NTSC / PSX_CPU_FREQ);
int curr_hblank = (gpu->cycles >= GPU_CYCLES_PER_HDRAW_NTSC) &&
(gpu->cycles <= GPU_CYCLES_PER_SCANL_NTSC);
if (curr_hblank && !prev_hblank) {
if (gpu->event_cb_table[GPU_EVENT_HBLANK])
gpu->event_cb_table[GPU_EVENT_HBLANK](gpu);
gpu_hblank_event(gpu);
} else if (prev_hblank && !curr_hblank) {
if (gpu->event_cb_table[GPU_EVENT_HBLANK_END])
gpu->event_cb_table[GPU_EVENT_HBLANK_END](gpu);
gpu->cycles -= (float)GPU_CYCLES_PER_SCANL_NTSC;
}
}
}
gpu->line++;
if (gpu->line == scans_per_vdraw) {
if (gpu->event_cb_table[GPU_EVENT_VBLANK])
gpu->event_cb_table[GPU_EVENT_VBLANK](gpu);
psx_ic_irq(gpu->ic, IC_VBLANK);
} else if (gpu->line == scans_per_frame) {
if (gpu->event_cb_table[GPU_EVENT_VBLANK_END])
gpu->event_cb_table[GPU_EVENT_VBLANK_END](gpu);
gpu->line = 0;
}
}
void psx_gpu_update(psx_gpu_t* gpu, int cyc) {
const float cycles_per_hdraw = psx_gpu_is_pal_mode(gpu) ? GPU_CYCLES_PER_HDRAW_PAL : GPU_CYCLES_PER_HDRAW_NTSC;
const float cycles_per_scanline = psx_gpu_is_pal_mode(gpu) ? GPU_CYCLES_PER_SCANL_PAL : GPU_CYCLES_PER_SCANL_NTSC;
const float gpu_clock = psx_gpu_clock_frequency(gpu);
int prev_hblank = (gpu->cycles >= cycles_per_hdraw) &&
(gpu->cycles <= cycles_per_scanline);
// Convert CPU (~33.8 MHz) cycles to GPU (~53.7 MHz) cycles
gpu->cycles += (float)cyc * (gpu_clock / PSX_CPU_FREQ);
int curr_hblank = (gpu->cycles >= cycles_per_hdraw) &&
(gpu->cycles <= cycles_per_scanline);
if (curr_hblank && !prev_hblank) {
if (gpu->event_cb_table[GPU_EVENT_HBLANK])
gpu->event_cb_table[GPU_EVENT_HBLANK](gpu);
gpu_hblank_event(gpu);
} else if (prev_hblank && !curr_hblank) {
if (gpu->event_cb_table[GPU_EVENT_HBLANK_END])
gpu->event_cb_table[GPU_EVENT_HBLANK_END](gpu);
gpu->cycles -= cycles_per_scanline;
}
}
void* psx_gpu_get_display_buffer(psx_gpu_t* gpu) {
if (gpu->gpustat & 0x800000)
+19 -7
View File
@@ -86,7 +86,7 @@ typedef struct {
uint16_t width, height;
} rect_data_t;
struct psx_gpu_t {
struct psx_gpu_t {
uint32_t bus_delay;
uint32_t io_base, io_size;
@@ -156,11 +156,23 @@ struct psx_gpu_t {
psx_ic_t* ic;
psx_gpu_event_callback_t event_cb_table[8];
};
psx_gpu_t* psx_gpu_create(void);
void psx_gpu_init(psx_gpu_t*, psx_ic_t*);
psx_gpu_event_callback_t event_cb_table[8];
};
static inline int psx_gpu_is_pal_mode(const psx_gpu_t* gpu) {
return gpu && ((gpu->display_mode & 0x8) != 0);
}
static inline float psx_gpu_clock_frequency(const psx_gpu_t* gpu) {
return psx_gpu_is_pal_mode(gpu) ? PSX_GPU_CLOCK_FREQ_PAL : PSX_GPU_CLOCK_FREQ_NTSC;
}
static inline float psx_gpu_frame_rate(const psx_gpu_t* gpu) {
return psx_gpu_is_pal_mode(gpu) ? 49.76f : 59.29f;
}
psx_gpu_t* psx_gpu_create(void);
void psx_gpu_init(psx_gpu_t*, psx_ic_t*);
uint32_t psx_gpu_read32(psx_gpu_t*, uint32_t);
uint16_t psx_gpu_read16(psx_gpu_t*, uint32_t);
uint8_t psx_gpu_read8(psx_gpu_t*, uint32_t);
@@ -173,4 +185,4 @@ void psx_gpu_set_event_callback(psx_gpu_t*, int, psx_gpu_event_callback_t);
void* psx_gpu_get_display_buffer(psx_gpu_t*);
void psx_gpu_update(psx_gpu_t*, int);
#endif
#endif
+1
View File
@@ -20,6 +20,7 @@
* IN THE SOFTWARE.
*/
#define PSXE_DIAG_STDIO_DISABLE
#include "log.h"
#define MAX_CALLBACKS 32
+2
View File
@@ -13,6 +13,8 @@
#include <stdbool.h>
#include <time.h>
#include "frontend/diagnostics.h"
#define LOG_VERSION "0.1.0"
typedef struct {
+5 -6
View File
@@ -34,11 +34,10 @@ void psx_update(psx_t* psx) {
psx_dma_update(psx->dma, psx->cpu->last_cycles);
}
void psx_run_frame(psx_t* psx) {
// NTSC: 59.29 Hz, PAL: 49.76 Hz
float framerate = (psx->gpu->display_mode & 0x8) ? 59.29 : 49.76;
unsigned int counter = (float)PSX_CPU_CPS / framerate;
void psx_run_frame(psx_t* psx) {
float framerate = psx_gpu_frame_rate(psx->gpu);
unsigned int counter = (float)PSX_CPU_CPS / framerate;
while (counter--) {
psx_update(psx);
@@ -306,4 +305,4 @@ psx_mdec_t* psx_get_mdec(psx_t* psx) {
psx_cpu_t* psx_get_cpu(psx_t* psx) {
return psx->cpu;
}
}