diff --git a/src/86box.c b/src/86box.c index aa3afb085..24f6f0deb 100644 --- a/src/86box.c +++ b/src/86box.c @@ -172,7 +172,6 @@ int force_43 = 0; /* (C) video * int video_filter_method = 1; /* (C) video */ int video_vsync = 0; /* (C) video */ int video_framerate = -1; /* (C) video */ -char video_shader[512] = { '\0' }; /* (C) video */ bool serial_passthrough_enabled[SERIAL_MAX] = { 0, 0, 0, 0, 0, 0, 0 }; /* (C) activation and kind of pass-through for serial ports */ int bugger_enabled = 0; /* (C) enable ISAbugger */ @@ -252,6 +251,8 @@ int unscaled_size_y = SCREEN_RES_Y; /* current unscaled size Y */ int efscrnsz_y = SCREEN_RES_Y; #endif +__thread int is_cpu_thread = 0; + static wchar_t mouse_msg[3][200]; static volatile atomic_int do_pause_ack = 0; diff --git a/src/acpi.c b/src/acpi.c index b33653663..ccd51ebca 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -211,7 +211,10 @@ acpi_update_irq(acpi_t *dev) if ((dev->regs.pmcntrl & 0x01) && sci_level) switch (dev->irq_mode) { default: - picintlevel(1 << dev->irq_line, &dev->irq_state); + if (dev->irq_line != 0) + picintlevel(1 << dev->irq_line, &dev->irq_state); + else + dev->irq_state = 1; break; case 1: pci_set_irq(dev->slot, dev->irq_pin, &dev->irq_state); @@ -223,7 +226,10 @@ acpi_update_irq(acpi_t *dev) break; } else switch (dev->irq_mode) { default: - picintclevel(1 << dev->irq_line, &dev->irq_state); + if (dev->irq_line != 0) + picintclevel(1 << dev->irq_line, &dev->irq_state); + else + dev->irq_state = 0; break; case 1: pci_clear_irq(dev->slot, dev->irq_pin, &dev->irq_state); diff --git a/src/chipset/via_pipc.c b/src/chipset/via_pipc.c index dcfe41811..11a192450 100644 --- a/src/chipset/via_pipc.c +++ b/src/chipset/via_pipc.c @@ -413,7 +413,9 @@ pipc_reset_hard(void *priv) dev->power_regs[0x34] = 0x68; dev->power_regs[0x40] = 0x20; - dev->power_regs[0x42] = 0x50; + dev->power_regs[0x42] = 0x00; + acpi_set_irq_line(dev->acpi, 0x00); + dev->power_regs[0x48] = 0x01; if (dev->local == VIA_PIPC_686B) { @@ -1593,6 +1595,9 @@ pipc_reset(void *priv) pipc_write(pm_func, 0x48, 0x01, priv); pipc_write(pm_func, 0x49, 0x00, priv); + dev->power_regs[0x42] = 0x00; + acpi_set_irq_line(dev->acpi, 0x00); + pipc_write(1, 0x04, 0x80, priv); pipc_write(1, 0x09, 0x85, priv); pipc_write(1, 0x10, 0xf1, priv); @@ -1694,6 +1699,8 @@ pipc_init(const device_t *info) acpi_set_nvr(dev->acpi, dev->nvr); acpi_init_gporeg(dev->acpi, 0xff, 0xbf, 0xff, 0x7f); + + acpi_set_irq_mode(dev->acpi, 0); } return dev; diff --git a/src/chipset/via_vt82c49x.c b/src/chipset/via_vt82c49x.c index 3aaef55a6..f8a5bb593 100644 --- a/src/chipset/via_vt82c49x.c +++ b/src/chipset/via_vt82c49x.c @@ -275,8 +275,8 @@ vt82c49x_write(uint16_t addr, uint8_t val, void *priv) case 0x71: if (dev->has_ide) { ide_pri_disable(); - ide_set_base(0, (val & 0x40) ? 0x170 : 0x1f0); - ide_set_side(0, (val & 0x40) ? 0x376 : 0x3f6); + ide_set_base(0, (val & 0x40) ? HDC_SECONDARY_BASE : HDC_PRIMARY_BASE); + ide_set_side(0, (val & 0x40) ? HDC_SECONDARY_SIDE : HDC_PRIMARY_SIDE); if (val & 0x01) ide_pri_enable(); vt82c49x_log("VT82C496 IDE now %sabled as %sary\n", (val & 0x01) ? "en" : "dis", diff --git a/src/config.c b/src/config.c index 07e770822..e5fbe59b4 100644 --- a/src/config.c +++ b/src/config.c @@ -77,6 +77,12 @@ #include <86box/snd_opl.h> #include <86box/version.h> +#ifndef USE_SDL_UI +/* Deliberate to not make the 86box.h header kitchen-sink. */ +#include <86box/qt-glsl.h> +extern char gl3_shader_file[MAX_USER_SHADERS][512]; +#endif + static int cx; static int cy; static int cw; @@ -196,7 +202,6 @@ load_general(void) video_framerate = ini_section_get_int(cat, "video_gl_framerate", -1); video_vsync = ini_section_get_int(cat, "video_gl_vsync", 0); - strncpy(video_shader, ini_section_get_string(cat, "video_gl_shader", ""), sizeof(video_shader) - 1); window_remember = ini_section_get_int(cat, "window_remember", 0); if (window_remember) { @@ -1714,6 +1719,48 @@ load_other_peripherals(void) ini_section_delete_var(cat, temp); } +#ifndef USE_SDL_UI +/* Load OpenGL 3.0 renderer options. */ +static void +load_gl3_shaders(void) +{ + ini_section_t cat = ini_find_section(config, "GL3 Shaders"); + char *p; + char temp[512]; + int i = 0, shaders = 0; + memset(temp, 0, sizeof(temp)); + memset(gl3_shader_file, 0, sizeof(gl3_shader_file)); + + shaders = ini_section_get_int(cat, "shaders", 0); + if (shaders > MAX_USER_SHADERS) + shaders = MAX_USER_SHADERS; + + if (shaders == 0) { + ini_section_t general = ini_find_section(config, "General"); + if (general) { + p = ini_section_get_string(general, "video_gl_shader", NULL); + if (p) { + strncpy(gl3_shader_file[0], p, 512); + ini_delete_var(config, general, "video_gl_shader"); + return; + } + } + } + + for (i = 0; i < shaders; i++) { + temp[0] = 0; + snprintf(temp, 512, "shader%d", i); + p = ini_section_get_string(cat, temp, ""); + if (p[0]) { + strncpy(gl3_shader_file[i], p, 512); + } else { + gl3_shader_file[i][0] = 0; + break; + } + } +} +#endif + /* Load the specified or a default configuration file. */ void config_load(void) @@ -1810,6 +1857,9 @@ config_load(void) load_floppy_and_cdrom_drives(); /* Floppy and CD-ROM drives */ load_other_removable_devices(); /* Other removable devices */ load_other_peripherals(); /* Other peripherals */ +#ifndef USE_SDL_UI + load_gl3_shaders(); /* GL3 Shaders */ +#endif /* Migrate renamed device configurations. */ c = ini_find_section(config, "MDA"); @@ -2002,10 +2052,6 @@ save_general(void) ini_section_set_int(cat, "video_gl_vsync", video_vsync); else ini_section_delete_var(cat, "video_gl_vsync"); - if (strlen(video_shader) > 0) - ini_section_set_string(cat, "video_gl_shader", video_shader); - else - ini_section_delete_var(cat, "video_gl_shader"); if (do_auto_pause) ini_section_set_int(cat, "do_auto_pause", do_auto_pause); @@ -2632,6 +2678,40 @@ save_other_peripherals(void) ini_delete_section_if_empty(config, cat); } +#ifndef USE_SDL_UI +/* Save "GL3 Shaders" section. */ +static void +save_gl3_shaders(void) +{ + ini_section_t cat = ini_find_or_create_section(config, "GL3 Shaders"); + char temp[512]; + int shaders = 0, i = 0; + + for (i = 0; i < MAX_USER_SHADERS; i++) { + if (gl3_shader_file[i][0] == 0) { + temp[0] = 0; + snprintf(temp, 512, "shader%d", i); + ini_section_delete_var(cat, temp); + break; + } + shaders++; + } + + ini_section_set_int(cat, "shaders", shaders); + if (shaders == 0) { + ini_section_delete_var(cat, "shaders"); + } else { + for (i = 0; i < shaders; i++) { + temp[0] = 0; + snprintf(temp, 512, "shader%d", i); + ini_section_set_string(cat, temp, gl3_shader_file[i]); + } + } + + ini_delete_section_if_empty(config, cat); +} +#endif + /* Save "Hard Disks" section. */ static void save_hard_disks(void) @@ -2987,6 +3067,9 @@ config_save(void) save_floppy_and_cdrom_drives(); /* Floppy and CD-ROM drives */ save_other_removable_devices(); /* Other removable devices */ save_other_peripherals(); /* Other peripherals */ +#ifndef USE_SDL_UI + save_gl3_shaders(); /* GL3 Shaders */ +#endif ini_write(config, cfg_path); } diff --git a/src/device.c b/src/device.c index 434bd3776..25f0b55de 100644 --- a/src/device.c +++ b/src/device.c @@ -390,22 +390,21 @@ device_get_priv(const device_t *dev) int device_available(const device_t *dev) { - const device_config_t *config = NULL; - const device_config_bios_t *bios = NULL; - if (dev != NULL) { - config = dev->config; + const device_config_t *config = dev->config; if (config != NULL) { while (config->type != CONFIG_END) { if (config->type == CONFIG_BIOS) { int roms_present = 0; - - bios = (const device_config_bios_t *) config->bios; + const device_config_bios_t *bios = (const device_config_bios_t *) config->bios; /* Go through the ROM's in the device configuration. */ - while (bios->files_no != 0) { + while ((bios != NULL) && + (bios->name != NULL) && + (bios->internal_name != NULL) && + (bios->files_no != 0)) { int i = 0; - for (int bf = 0; bf < bios->files_no; bf++) + for (uint8_t bf = 0; bf < bios->files_no; bf++) i += !!rom_present(bios->files[bf]); if (i == bios->files_no) roms_present++; @@ -429,21 +428,128 @@ device_available(const device_t *dev) return 0; } -const char * -device_get_bios_file(const device_t *dev, const char *internal_name, int file_no) +uint8_t +device_get_bios_type(const device_t *dev, const char *internal_name) { - const device_config_t *config = NULL; - const device_config_bios_t *bios = NULL; - if (dev != NULL) { - config = dev->config; + const device_config_t *config = dev->config; if (config != NULL) { while (config->type != CONFIG_END) { if (config->type == CONFIG_BIOS) { - bios = config->bios; + const device_config_bios_t *bios = (const device_config_bios_t *) config->bios; + while ((bios != NULL) && + (bios->name != NULL) && + (bios->internal_name != NULL) && + (bios->files_no != 0)) { + if (!strcmp(internal_name, bios->internal_name)) + return bios->bios_type; + bios++; + } + } + config++; + } + } + } + + return 0; +} + +uint8_t +device_get_bios_num_files(const device_t *dev, const char *internal_name) +{ + if (dev != NULL) { + const device_config_t *config = dev->config; + if (config != NULL) { + while (config->type != CONFIG_END) { + if (config->type == CONFIG_BIOS) { + const device_config_bios_t *bios = (const device_config_bios_t *) config->bios; + while ((bios != NULL) && + (bios->name != NULL) && + (bios->internal_name != NULL) && + (bios->files_no != 0)) { + if (!strcmp(internal_name, bios->internal_name)) + return bios->files_no; + bios++; + } + } + config++; + } + } + } + + return 0; +} + +uint32_t +device_get_bios_local(const device_t *dev, const char *internal_name) +{ + if (dev != NULL) { + const device_config_t *config = dev->config; + if (config != NULL) { + while (config->type != CONFIG_END) { + if (config->type == CONFIG_BIOS) { + const device_config_bios_t *bios = (const device_config_bios_t *) config->bios; + while ((bios != NULL) && + (bios->name != NULL) && + (bios->internal_name != NULL) && + (bios->files_no != 0)) { + printf("Internal name was: %s", internal_name); + if (!strcmp(internal_name, bios->internal_name)) + return bios->local; + bios++; + } + } + config++; + } + } + } + + return 0; +} + +uint32_t +device_get_bios_file_size(const device_t *dev, const char *internal_name) +{ + if (dev != NULL) { + const device_config_t *config = dev->config; + if (config != NULL) { + while (config->type != CONFIG_END) { + if (config->type == CONFIG_BIOS) { + const device_config_bios_t *bios = (const device_config_bios_t *) config->bios; /* Go through the ROM's in the device configuration. */ - while (bios->files_no != 0) { + while ((bios != NULL) && + (bios->name != NULL) && + (bios->internal_name != NULL) && + (bios->files_no != 0)) { + if (!strcmp(internal_name, bios->internal_name)) + return bios->size; + bios++; + } + } + config++; + } + } + } + + return 0; +} + +const char * +device_get_bios_file(const device_t *dev, const char *internal_name, int file_no) +{ + if (dev != NULL) { + const device_config_t *config = dev->config; + if (config != NULL) { + while (config->type != CONFIG_END) { + if (config->type == CONFIG_BIOS) { + const device_config_bios_t *bios = (const device_config_bios_t *) config->bios; + + /* Go through the ROM's in the device configuration. */ + while ((bios != NULL) && + (bios->name != NULL) && + (bios->internal_name != NULL) && + (bios->files_no != 0)) { if (!strcmp(internal_name, bios->internal_name)) { if (file_no < bios->files_no) return bios->files[file_no]; @@ -660,13 +766,15 @@ device_get_config_string(const char *str) int device_get_config_int(const char *str) { - const device_config_t *cfg = device_current.dev->config; + if (device_current.dev != NULL) { + const device_config_t *cfg = device_current.dev->config; - while (cfg && cfg->type != CONFIG_END) { - if (!strcmp(str, cfg->name)) - return (config_get_int((char *) device_current.name, (char *) str, cfg->default_int)); + while ((cfg != NULL) && (cfg->type != CONFIG_END)) { + if (!strcmp(str, cfg->name)) + return (config_get_int((char *) device_current.name, (char *) str, cfg->default_int)); - cfg++; + cfg++; + } } return 0; @@ -675,13 +783,15 @@ device_get_config_int(const char *str) int device_get_config_int_ex(const char *str, int def) { - const device_config_t *cfg = device_current.dev->config; + if (device_current.dev != NULL) { + const device_config_t *cfg = device_current.dev->config; - while (cfg && cfg->type != CONFIG_END) { - if (!strcmp(str, cfg->name)) - return (config_get_int((char *) device_current.name, (char *) str, def)); + while ((cfg != NULL) && (cfg->type != CONFIG_END)) { + if (!strcmp(str, cfg->name)) + return (config_get_int((char *) device_current.name, (char *) str, def)); - cfg++; + cfg++; + } } return def; @@ -690,13 +800,15 @@ device_get_config_int_ex(const char *str, int def) int device_get_config_hex16(const char *str) { - const device_config_t *cfg = device_current.dev->config; + if (device_current.dev != NULL) { + const device_config_t *cfg = device_current.dev->config; - while (cfg && cfg->type != CONFIG_END) { - if (!strcmp(str, cfg->name)) - return (config_get_hex16((char *) device_current.name, (char *) str, cfg->default_int)); + while ((cfg != NULL) && (cfg->type != CONFIG_END)) { + if (!strcmp(str, cfg->name)) + return (config_get_hex16((char *) device_current.name, (char *) str, cfg->default_int)); - cfg++; + cfg++; + } } return 0; @@ -705,13 +817,15 @@ device_get_config_hex16(const char *str) int device_get_config_hex20(const char *str) { - const device_config_t *cfg = device_current.dev->config; + if (device_current.dev != NULL) { + const device_config_t *cfg = device_current.dev->config; - while (cfg && cfg->type != CONFIG_END) { - if (!strcmp(str, cfg->name)) - return (config_get_hex20((char *) device_current.name, (char *) str, cfg->default_int)); + while ((cfg != NULL) && (cfg->type != CONFIG_END)) { + if (!strcmp(str, cfg->name)) + return (config_get_hex20((char *) device_current.name, (char *) str, cfg->default_int)); - cfg++; + cfg++; + } } return 0; @@ -720,13 +834,15 @@ device_get_config_hex20(const char *str) int device_get_config_mac(const char *str, int def) { - const device_config_t *cfg = device_current.dev->config; + if (device_current.dev != NULL) { + const device_config_t *cfg = device_current.dev->config; - while (cfg && cfg->type != CONFIG_END) { - if (!strcmp(str, cfg->name)) - return (config_get_mac((char *) device_current.name, (char *) str, def)); + while ((cfg != NULL) && (cfg->type != CONFIG_END)) { + if (!strcmp(str, cfg->name)) + return (config_get_mac((char *) device_current.name, (char *) str, def)); - cfg++; + cfg++; + } } return def; @@ -735,60 +851,68 @@ device_get_config_mac(const char *str, int def) void device_set_config_int(const char *str, int val) { - const device_config_t *cfg = device_current.dev->config; + if (device_current.dev != NULL) { + const device_config_t *cfg = device_current.dev->config; - while (cfg && cfg->type != CONFIG_END) { - if (!strcmp(str, cfg->name)) { - config_set_int((char *) device_current.name, (char *) str, val); - break; + while ((cfg != NULL) && (cfg->type != CONFIG_END)) { + if (!strcmp(str, cfg->name)) { + config_set_int((char *) device_current.name, (char *) str, val); + break; + } + + cfg++; } - - cfg++; } } void device_set_config_hex16(const char *str, int val) { - const device_config_t *cfg = device_current.dev->config; + if (device_current.dev != NULL) { + const device_config_t *cfg = device_current.dev->config; - while (cfg && cfg->type != CONFIG_END) { - if (!strcmp(str, cfg->name)) { - config_set_hex16((char *) device_current.name, (char *) str, val); - break; + while ((cfg != NULL) && (cfg->type != CONFIG_END)) { + if (!strcmp(str, cfg->name)) { + config_set_hex16((char *) device_current.name, (char *) str, val); + break; + } + + cfg++; } - - cfg++; } } void device_set_config_hex20(const char *str, int val) { - const device_config_t *cfg = device_current.dev->config; + if (device_current.dev != NULL) { + const device_config_t *cfg = device_current.dev->config; - while (cfg && cfg->type != CONFIG_END) { - if (!strcmp(str, cfg->name)) { - config_set_hex20((char *) device_current.name, (char *) str, val); - break; - } + while ((cfg != NULL) && (cfg->type != CONFIG_END)) { + if (!strcmp(str, cfg->name)) { + config_set_hex20((char *) device_current.name, (char *) str, val); + break; + } cfg++; + } } } void device_set_config_mac(const char *str, int val) { - const device_config_t *cfg = device_current.dev->config; + if (device_current.dev != NULL) { + const device_config_t *cfg = device_current.dev->config; - while (cfg && cfg->type != CONFIG_END) { - if (!strcmp(str, cfg->name)) { - config_set_mac((char *) device_current.name, (char *) str, val); - break; + while ((cfg != NULL) && (cfg->type != CONFIG_END)) { + if (!strcmp(str, cfg->name)) { + config_set_mac((char *) device_current.name, (char *) str, val); + break; + } + + cfg++; } - - cfg++; } } @@ -806,20 +930,18 @@ device_is_valid(const device_t *device, int mch) int machine_get_config_int(char *str) { - const device_t *dev = machine_get_device(machine); - const device_config_t *cfg; + const device_t *dev = machine_get_device(machine); - if (dev == NULL) - return 0; + if (dev != NULL) { + const device_config_t *cfg = dev->config; - cfg = dev->config; - while (cfg && cfg->type != CONFIG_END) { - if (!strcmp(str, cfg->name)) - return (config_get_int((char *) dev->name, str, cfg->default_int)); + while ((cfg != NULL) && (cfg->type != CONFIG_END)) { + if (!strcmp(str, cfg->name)) + return (config_get_int((char *) dev->name, str, cfg->default_int)); - cfg++; + cfg++; + } } - return 0; } @@ -830,9 +952,8 @@ machine_get_config_string(char *str) const char *ret = ""; if (dev != NULL) { - const device_config_t *cfg; + const device_config_t *cfg = dev->config; - cfg = dev->config; while ((cfg != NULL) && (cfg->type != CONFIG_END)) { if (!strcmp(str, cfg->name)) { const char *s = config_get_string((char *) dev->name, str, diff --git a/src/disk/hdc.c b/src/disk/hdc.c index f09a9a430..582c33428 100644 --- a/src/disk/hdc.c +++ b/src/disk/hdc.c @@ -72,7 +72,9 @@ static const struct { { &ide_isa_device }, { &ide_isa_2ch_device }, { &xtide_at_device }, + { &xtide_at_2ch_device }, { &xtide_at_ps2_device }, + { &xtide_at_ps2_2ch_device }, { &xta_wdxt150_device }, { &xtide_acculogic_device }, { &xtide_device }, diff --git a/src/disk/hdc_xtide.c b/src/disk/hdc_xtide.c index c18a24c4e..154a28cec 100644 --- a/src/disk/hdc_xtide.c +++ b/src/disk/hdc_xtide.c @@ -41,11 +41,13 @@ #include <86box/mem.h> #include <86box/rom.h> #include <86box/timer.h> +#include <86box/nvr.h> #include <86box/device.h> #include <86box/hdc.h> #include <86box/hdc_ide.h> #include <86box/plat_unused.h> +#define ROM_PATH_TINY "roms/hdd/xtide/ide_tiny.bin" #define ROM_PATH_XT "roms/hdd/xtide/ide_xt.bin" #define ROM_PATH_XTP "roms/hdd/xtide/ide_xtp.bin" #define ROM_PATH_AT "roms/hdd/xtide/ide_at.bin" @@ -57,6 +59,7 @@ typedef struct xtide_t { void *ide_board; uint8_t data_high; rom_t bios_rom; + char nvr_path[64]; } xtide_t; static void @@ -136,14 +139,26 @@ xtide_init(const device_t *info) rom_init(&xtide->bios_rom, device_get_bios_file(info, device_get_config_bios("bios"), 0), - 0xc8000, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); + device_get_config_hex20("bios_addr"), 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); xtide->ide_board = ide_xtide_init(); - io_sethandler(0x0300, 16, + io_sethandler(device_get_config_hex16("base"), 16, xtide_read, NULL, NULL, xtide_write, NULL, NULL, xtide); + uint8_t rom_writes_enabled = device_get_config_int("rom_writes_enabled"); + + if (rom_writes_enabled) { + mem_mapping_set_write_handler(&xtide->bios_rom.mapping, rom_write, rom_writew, rom_writel); + sprintf(xtide->nvr_path, "xtide_%i.nvr", device_get_instance()); + FILE *fp = nvr_fopen(xtide->nvr_path, "rb"); + if (fp != NULL) { + fread(xtide->bios_rom.rom, 1, 0x2000, fp); + fclose(fp); + } + } + return xtide; } @@ -156,7 +171,10 @@ xtide_at_init(const device_t *info) device_get_bios_file(info, device_get_config_bios("bios"), 0), 0xc8000, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); - device_add(&ide_isa_2ch_device); + if (info->local == 1) + device_add(&ide_isa_2ch_device); + else + device_add(&ide_isa_device); return xtide; } @@ -189,6 +207,14 @@ xtide_close(void *priv) { xtide_t *xtide = (xtide_t *) priv; + if (xtide->nvr_path[0] != 0x00) { + FILE *fp = nvr_fopen(xtide->nvr_path, "wb"); + if (fp != NULL) { + fwrite(xtide->bios_rom.rom, 1, 0x2000, fp); + fclose(fp); + } + } + free(xtide); ide_xtide_close(); @@ -202,7 +228,10 @@ xtide_at_ps2_init(UNUSED(const device_t *info)) rom_init(&xtide->bios_rom, ROM_PATH_PS2AT, 0xc8000, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); - device_add(&ide_isa_2ch_device); + if (info->local == 1) + device_add(&ide_isa_2ch_device); + else + device_add(&ide_isa_device); return xtide; } @@ -221,8 +250,104 @@ xtide_at_close(void *priv) free(xtide); } +// clang-format off static const device_config_t xtide_config[] = { - // clang-format off + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x300, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "200H", .value = 0x200 }, + { .description = "210H", .value = 0x210 }, + { .description = "220H", .value = 0x220 }, + { .description = "230H", .value = 0x230 }, + { .description = "240H", .value = 0x240 }, + { .description = "250H", .value = 0x250 }, + { .description = "260H", .value = 0x260 }, + { .description = "270H", .value = 0x270 }, + { .description = "280H", .value = 0x280 }, + { .description = "290H", .value = 0x290 }, + { .description = "2A0H", .value = 0x2a0 }, + { .description = "2B0H", .value = 0x2b0 }, + { .description = "2C0H", .value = 0x2c0 }, + { .description = "2D0H", .value = 0x2d0 }, + { .description = "2E0H", .value = 0x2e0 }, + { .description = "2F0H", .value = 0x2f0 }, + { .description = "300H", .value = 0x300 }, + { .description = "310H", .value = 0x310 }, + { .description = "320H", .value = 0x320 }, + { .description = "330H", .value = 0x330 }, + { .description = "340H", .value = 0x340 }, + { .description = "350H", .value = 0x350 }, + { .description = "360H", .value = 0x360 }, + { .description = "370H", .value = 0x370 }, + { .description = "380H", .value = 0x380 }, + { .description = "390H", .value = 0x390 }, + { .description = "3A0H", .value = 0x3a0 }, + { .description = "3B0H", .value = 0x3b0 }, + { .description = "3C0H", .value = 0x3c0 }, + { .description = "3D0H", .value = 0x3d0 }, + { .description = "3E0H", .value = 0x3e0 }, + { .description = "3F0H", .value = 0x3f0 }, + { NULL } + }, + .bios = { { 0 } } + }, + { + .name = "rom_writes_enabled", + .description = "Enable BIOS extension ROM Writes", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0xd0000, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "Disabled", .value = 0x00000 }, +#if 0 + // Supported on XT IDE Deluxe By Monotech + { .description = "C000H", .value = 0xc0000 }, + { .description = "C200H", .value = 0xc2000 }, + { .description = "C400H", .value = 0xc4000 }, + { .description = "C600H", .value = 0xc6000 }, +#endif + { .description = "C800H", .value = 0xc8000 }, + { .description = "CA00H", .value = 0xca000 }, + { .description = "CC00H", .value = 0xcc000 }, + { .description = "CE00H", .value = 0xce000 }, + { .description = "D000H", .value = 0xd0000 }, + { .description = "D200H", .value = 0xd2000 }, + { .description = "D400H", .value = 0xd4000 }, + { .description = "D600H", .value = 0xd6000 }, + { .description = "D800H", .value = 0xd8000 }, + { .description = "DA00H", .value = 0xda000 }, + { .description = "DC00H", .value = 0xdc000 }, + { .description = "DE00H", .value = 0xde000 }, +#if 0 + // Supported on VCFed rev 2 + { .description = "E000H", .value = 0xe0000 }, + { .description = "E400H", .value = 0xe4000 }, + { .description = "E800H", .value = 0xe8000 }, + { .description = "EC00H", .value = 0xec000 }, +#endif + { .description = "" } + }, + .bios = { { 0 } } + }, { .name = "bios", .description = "BIOS Revision", @@ -255,11 +380,9 @@ static const device_config_t xtide_config[] = { }, }, { .name = "", .description = "", .type = CONFIG_END } - // clang-format on }; static const device_config_t xtide_at_config[] = { - // clang-format off { .name = "bios", .description = "BIOS Revision", @@ -292,8 +415,8 @@ static const device_config_t xtide_at_config[] = { }, }, { .name = "", .description = "", .type = CONFIG_END } - // clang-format on }; +// clang-format on const device_t xtide_device = { .name = "PC/XT XTIDE", @@ -310,10 +433,24 @@ const device_t xtide_device = { }; const device_t xtide_at_device = { + .name = "PC/AT XTIDE (Primary Only)", + .internal_name = "xtide_at_1ch", + .flags = DEVICE_ISA16, + .local = 0, + .init = xtide_at_init, + .close = xtide_at_close, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = xtide_at_config +}; + +const device_t xtide_at_2ch_device = { .name = "PC/AT XTIDE", .internal_name = "xtide_at", .flags = DEVICE_ISA16, - .local = 0, + .local = 1, .init = xtide_at_init, .close = xtide_at_close, .reset = NULL, @@ -338,8 +475,8 @@ const device_t xtide_acculogic_device = { }; const device_t xtide_at_ps2_device = { - .name = "PS/2 AT XTIDE (1.1.5)", - .internal_name = "xtide_at_ps2", + .name = "PS/2 AT XTIDE (1.1.5) (Primary Only)", + .internal_name = "xtide_at_ps2_1ch", .flags = DEVICE_ISA16, .local = 0, .init = xtide_at_ps2_init, @@ -350,3 +487,17 @@ const device_t xtide_at_ps2_device = { .force_redraw = NULL, .config = NULL }; + +const device_t xtide_at_ps2_2ch_device = { + .name = "PS/2 AT XTIDE (1.1.5)", + .internal_name = "xtide_at_ps2", + .flags = DEVICE_ISA16, + .local = 1, + .init = xtide_at_ps2_init, + .close = xtide_at_close, + .reset = NULL, + .available = xtide_at_ps2_available, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/floppy/fdc_monster.c b/src/floppy/fdc_monster.c index 1b0e2fbac..b91d4db66 100644 --- a/src/floppy/fdc_monster.c +++ b/src/floppy/fdc_monster.c @@ -47,57 +47,6 @@ typedef struct monster_fdc_t { char nvr_path[64]; } monster_fdc_t; -static void -rom_write(uint32_t addr, uint8_t val, void *priv) -{ - const rom_t *rom = (rom_t *) priv; - -#ifdef ROM_TRACE - if (rom->mapping.base == ROM_TRACE) - rom_log("ROM: read byte from BIOS at %06lX\n", addr); -#endif - - if (addr < rom->mapping.base) - return; - if (addr >= (rom->mapping.base + rom->sz)) - return; - rom->rom[(addr - rom->mapping.base) & rom->mask] = val; -} - -static void -rom_writew(uint32_t addr, uint16_t val, void *priv) -{ - rom_t *rom = (rom_t *) priv; - -#ifdef ROM_TRACE - if (rom->mapping.base == ROM_TRACE) - rom_log("ROM: read word from BIOS at %06lX\n", addr); -#endif - - if (addr < (rom->mapping.base - 1)) - return; - if (addr >= (rom->mapping.base + rom->sz)) - return; - *(uint16_t *) &rom->rom[(addr - rom->mapping.base) & rom->mask] = val; -} - -static void -rom_writel(uint32_t addr, uint32_t val, void *priv) -{ - rom_t *rom = (rom_t *) priv; - -#ifdef ROM_TRACE - if (rom->mapping.base == ROM_TRACE) - rom_log("ROM: read long from BIOS at %06lX\n", addr); -#endif - - if (addr < (rom->mapping.base - 3)) - return; - if (addr >= (rom->mapping.base + rom->sz)) - return; - *(uint32_t *) &rom->rom[(addr - rom->mapping.base) & rom->mask] = val; -} - static void monster_fdc_close(void *priv) { diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index 79bb84009..768ca6267 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -126,7 +126,6 @@ extern int video_filter_method; /* (C) video */ extern int video_vsync; /* (C) video */ extern int video_framerate; /* (C) video */ extern int gfxcard[GFXCARD_MAX]; /* (C) graphics/video card */ -extern char video_shader[512]; /* (C) video */ extern int bugger_enabled; /* (C) enable ISAbugger */ extern int novell_keycard_enabled; /* (C) enable Novell NetWare 2.x key card emulation. */ extern int postcard_enabled; /* (C) enable POST card */ @@ -188,6 +187,8 @@ extern FILE *stdlog; /* file to log output to */ #endif extern int config_changed; /* config has changed */ +extern __thread int is_cpu_thread; /* Is this the CPU thread? */ + /* Function prototypes. */ #ifdef HAVE_STDARG_H extern void pclog_ex(const char *fmt, va_list ap); diff --git a/src/include/86box/device.h b/src/include/86box/device.h index 4cc283a25..fb86d2adc 100644 --- a/src/include/86box/device.h +++ b/src/include/86box/device.h @@ -137,12 +137,11 @@ typedef struct device_config_spinner_t { typedef struct device_config_bios_t { const char *name; const char *internal_name; - int bios_type; - int files_no; + uint8_t bios_type; + uint8_t files_no; uint32_t local; uint32_t size; - void *dev1; - void *dev2; + void *dev[2]; const char *files[9]; } device_config_bios_t; @@ -211,6 +210,11 @@ extern void device_speed_changed(void); extern void device_force_redraw(void); extern void device_get_name(const device_t *dev, int bus, char *name); extern int device_has_config(const device_t *dev); + +extern uint8_t device_get_bios_type(const device_t *dev, const char *internal_name); +extern uint8_t device_get_bios_num_files(const device_t *dev, const char *internal_name); +extern uint32_t device_get_bios_local(const device_t *dev, const char *internal_name); +extern uint32_t device_get_bios_file_size(const device_t *dev, const char *internal_name); extern const char *device_get_bios_file(const device_t *dev, const char *internal_name, int file_no); extern int device_is_valid(const device_t *, int mch); diff --git a/src/include/86box/hdc.h b/src/include/86box/hdc.h index 7f91fd61b..71f83e5e6 100644 --- a/src/include/86box/hdc.h +++ b/src/include/86box/hdc.h @@ -99,10 +99,12 @@ extern const device_t mcide_device; extern const device_t xta_wdxt150_device; /* xta_wdxt150 */ extern const device_t xta_hd20_device; /* EuroPC internal */ -extern const device_t xtide_device; /* xtide_xt */ -extern const device_t xtide_at_device; /* xtide_at */ -extern const device_t xtide_acculogic_device; /* xtide_ps2 */ -extern const device_t xtide_at_ps2_device; /* xtide_at_ps2 */ +extern const device_t xtide_device; /* xtide_xt */ +extern const device_t xtide_at_device; /* xtide_at */ +extern const device_t xtide_at_2ch_device; /* xtide_at_2ch */ +extern const device_t xtide_acculogic_device; /* xtide_ps2 */ +extern const device_t xtide_at_ps2_device; /* xtide_at_ps2 */ +extern const device_t xtide_at_ps2_2ch_device; /* xtide_at_ps2_2ch */ /* Miscellaneous */ extern const device_t lba_enhancer_device; diff --git a/src/include/86box/ini.h b/src/include/86box/ini.h index d52620f69..bb250e697 100644 --- a/src/include/86box/ini.h +++ b/src/include/86box/ini.h @@ -31,6 +31,7 @@ typedef void *ini_section_t; extern ini_t ini_new(void); extern ini_t ini_read(const char *fn); +extern void ini_strip_quotes(ini_t ini); extern void ini_write(ini_t ini, const char *fn); extern void ini_dump(ini_t ini); extern void ini_close(ini_t ini); @@ -58,6 +59,7 @@ extern void ini_section_set_hex20(ini_section_t section, const char *name, i extern void ini_section_set_mac(ini_section_t section, const char *name, int val); extern void ini_section_set_string(ini_section_t section, const char *name, const char *val); extern void ini_section_set_wstring(ini_section_t section, const char *name, wchar_t *val); +extern int ini_has_entry(ini_section_t self, const char *name); #define ini_delete_var(ini, head, name) ini_section_delete_var(ini_find_section(ini, head), name) diff --git a/src/include/86box/keyboard.h b/src/include/86box/keyboard.h index 110e4f760..3a7260c72 100644 --- a/src/include/86box/keyboard.h +++ b/src/include/86box/keyboard.h @@ -54,16 +54,16 @@ typedef struct kbc_at_port_t { typedef struct atkbc_dev_t { const char *name; /* name of this device */ - uint8_t type; - uint8_t command; - uint8_t last_scan_code; - uint8_t state; - uint8_t resolution; - uint8_t rate; - uint8_t cmd_queue_start; - uint8_t cmd_queue_end; - uint8_t queue_start; - uint8_t queue_end; + uint8_t type; + uint8_t command; + uint8_t last_scan_code; + uint8_t state; + uint8_t resolution; + uint8_t rate; + uint8_t cmd_queue_start; + uint8_t cmd_queue_end; + uint8_t queue_start; + uint8_t queue_end; uint16_t flags; diff --git a/src/include/86box/qt-glsl.h b/src/include/86box/qt-glsl.h new file mode 100644 index 000000000..0cd8e27cd --- /dev/null +++ b/src/include/86box/qt-glsl.h @@ -0,0 +1,158 @@ +#ifndef SRC_WX_GLSL_H_ +#define SRC_WX_GLSL_H_ + +#define MAX_PREV 7 + +#define MAX_SHADERS 20 +#define MAX_TEXTURES 20 +#define MAX_PARAMETERS 100 + +#define MAX_USER_SHADERS 20 +//#define SDL2_SHADER_DEBUG + +struct shader_scale { + int mode[2]; + float value[2]; +}; + +struct shader_state { + float input_size[2]; + float input_texture_size[2]; + float output_texture_size[2]; + float output_size[2]; + float tex_coords[8]; +}; + +struct shader_vbo { + int vertex_coord; + int tex_coord; + int color; +}; + +struct shader_texture { + int id; + int width; + int height; + int type; + int internal_format; + int format; + int min_filter; + int mag_filter; + int wrap_mode; + void *data; + int mipmap; +}; + +struct shader_lut_texture { + char name[50]; + struct shader_texture texture; +}; + +struct shader_fbo { + int id; + struct shader_texture texture; + int srgb; + int mipmap_input; +}; + +struct shader_prev { + struct shader_fbo fbo; + struct shader_vbo vbo; +}; + +struct shader_input { + int texture; + int input_size; + int texture_size; + int tex_coord; +}; + +struct shader_uniforms { + int mvp_matrix; + int vertex_coord; + int tex_coord; + int color; + + int texture; + int input_size; + int texture_size; + int output_size; + + int frame_count; + int frame_direction; + + struct shader_input orig; + struct shader_input pass[MAX_SHADERS]; + struct shader_input prev_pass[MAX_SHADERS]; + struct shader_input prev[MAX_PREV]; + + int parameters[MAX_PARAMETERS]; + int lut_textures[MAX_TEXTURES]; +}; + +struct shader_program { + int vertex_shader; + int fragment_shader; + int id; +}; + +struct shader_parameter { + char id[64]; + char description[64]; + float default_value; + float value; + float min; + float max; + float step; +}; + +struct shader_pass { + int active; + char alias[64]; + int vertex_array; + int frame_count_mod; + struct shader_program program; + struct shader_uniforms uniforms; + struct shader_fbo fbo; + struct shader_vbo vbo; + struct shader_state state; + struct shader_scale scale; +}; + +struct glsl_shader { + int active; + char name[64]; + + int num_passes; + struct shader_pass passes[MAX_SHADERS]; + + int num_lut_textures; + struct shader_lut_texture lut_textures[MAX_TEXTURES]; + + int num_parameters; + struct shader_parameter parameters[MAX_PARAMETERS]; + + struct shader_pass prev_scene; + struct shader_prev prev[MAX_PREV + 1]; + + int last_prev_update; + int has_prev; + + float shader_refresh_rate; + + int input_filter_linear; +}; + +typedef struct glsl_t { + int num_shaders; + struct glsl_shader shaders[MAX_USER_SHADERS]; + struct shader_pass scene; + struct shader_pass final_pass; + struct shader_pass fs_color; +#ifdef SDL2_SHADER_DEBUG + struct shader_pass debug; +#endif + int srgb; +} glsl_t; + +#endif \ No newline at end of file diff --git a/src/include/86box/qt-glslp-parser.h b/src/include/86box/qt-glslp-parser.h new file mode 100644 index 000000000..853e50e66 --- /dev/null +++ b/src/include/86box/qt-glslp-parser.h @@ -0,0 +1,59 @@ +#ifndef SRC_WX_GLSLP_PARSER_H_ +#define SRC_WX_GLSLP_PARSER_H_ + +#include "qt-glsl.h" + +struct parameter { + char id[64]; + char description[64]; + float default_value; + float value; + float min; + float max; + float step; +}; + +struct texture { + char path[256]; + char name[50]; + int linear; + int mipmap; + char wrap_mode[50]; +}; + +struct shader { + char shader_fn[1024]; + char *shader_program; + char alias[64]; + int filter_linear; + int float_framebuffer; + int srgb_framebuffer; + int mipmap_input; + int frame_count_mod; + char wrap_mode[50]; + char scale_type_x[9], scale_type_y[9]; + float scale_x, scale_y; +}; + +typedef struct glslp_t { + char name[64]; + int num_shaders; + struct shader shaders[MAX_SHADERS]; + + int num_textures; + struct texture textures[MAX_TEXTURES]; + + int num_parameters; + struct parameter parameters[MAX_PARAMETERS]; + + int input_filter_linear; +} glslp_t; + +void get_glslp_name(const char *f, char *s, int size); +glslp_t *glslp_parse(const char *f); +void glslp_free(glslp_t *p); + +void glslp_read_shader_config(glslp_t *shader); +void glslp_write_shader_config(glslp_t *shader); + +#endif /* SRC_WX_GLSLP_PARSER_H_ */ diff --git a/src/include/86box/rom.h b/src/include/86box/rom.h index 83fd7cf90..331d78526 100644 --- a/src/include/86box/rom.h +++ b/src/include/86box/rom.h @@ -52,7 +52,12 @@ extern uint8_t rom_read(uint32_t addr, void *priv); extern uint16_t rom_readw(uint32_t addr, void *priv); extern uint32_t rom_readl(uint32_t addr, void *priv); +extern void rom_write(uint32_t addr, uint8_t val, void *priv); +extern void rom_writew(uint32_t addr, uint16_t val, void *priv); +extern void rom_writel(uint32_t addr, uint32_t val, void *priv); + extern void rom_get_full_path(char *dest, const char *fn); + extern FILE *rom_fopen(const char *fn, char *mode); extern int rom_getfile(char *fn, char *s, int size); extern int rom_present(const char *fn); diff --git a/src/mem/rom.c b/src/mem/rom.c index 8b2308402..666652d53 100644 --- a/src/mem/rom.c +++ b/src/mem/rom.c @@ -244,6 +244,57 @@ rom_readl(uint32_t addr, void *priv) return (*(uint32_t *) &rom->rom[(addr - rom->mapping.base) & rom->mask]); } +void +rom_write(uint32_t addr, uint8_t val, void *priv) +{ + const rom_t *rom = (rom_t *) priv; + +#ifdef ROM_TRACE + if (rom->mapping.base == ROM_TRACE) + rom_log("ROM: write byte from BIOS at %06lX\n", addr); +#endif + + if (addr < rom->mapping.base) + return; + if (addr >= (rom->mapping.base + rom->sz)) + return; + rom->rom[(addr - rom->mapping.base) & rom->mask] = val; +} + +void +rom_writew(uint32_t addr, uint16_t val, void *priv) +{ + rom_t *rom = (rom_t *) priv; + +#ifdef ROM_TRACE + if (rom->mapping.base == ROM_TRACE) + rom_log("ROM: write word from BIOS at %06lX\n", addr); +#endif + + if (addr < (rom->mapping.base - 1)) + return; + if (addr >= (rom->mapping.base + rom->sz)) + return; + *(uint16_t *) &rom->rom[(addr - rom->mapping.base) & rom->mask] = val; +} + +void +rom_writel(uint32_t addr, uint32_t val, void *priv) +{ + rom_t *rom = (rom_t *) priv; + +#ifdef ROM_TRACE + if (rom->mapping.base == ROM_TRACE) + rom_log("ROM: write long from BIOS at %06lX\n", addr); +#endif + + if (addr < (rom->mapping.base - 3)) + return; + if (addr >= (rom->mapping.base + rom->sz)) + return; + *(uint32_t *) &rom->rom[(addr - rom->mapping.base) & rom->mask] = val; +} + int rom_load_linear_oddeven(const char *fn, uint32_t addr, int sz, int off, uint8_t *ptr) { diff --git a/src/network/net_slirp.c b/src/network/net_slirp.c index 203428b83..92c4c4ddf 100644 --- a/src/network/net_slirp.c +++ b/src/network/net_slirp.c @@ -155,14 +155,22 @@ net_slirp_timer_mod(void *timer, int64_t expire_timer, UNUSED(void *opaque)) } static void +#if SLIRP_CHECK_VERSION(4, 9, 0) +net_slirp_register_poll_socket(slirp_os_socket fd, void *opaque) +#else net_slirp_register_poll_fd(int fd, void *opaque) +#endif { (void) fd; (void) opaque; } static void +#if SLIRP_CHECK_VERSION(4, 9, 0) +net_slirp_unregister_poll_socket(slirp_os_socket fd, void *opaque) +#else net_slirp_unregister_poll_fd(int fd, void *opaque) +#endif { (void) fd; (void) opaque; @@ -198,7 +206,11 @@ net_slirp_send_packet(const void *qp, size_t pkt_len, void *opaque) #ifdef _WIN32 static int +# if SLIRP_CHECK_VERSION(4, 9, 0) +net_slirp_add_poll(slirp_os_socket fd, int events, void *opaque) +# else net_slirp_add_poll(int fd, int events, void *opaque) +# endif { net_slirp_t *slirp = (net_slirp_t *) opaque; long bitmask = 0; @@ -216,7 +228,11 @@ net_slirp_add_poll(int fd, int events, void *opaque) } #else static int +# if SLIRP_CHECK_VERSION(4, 9, 0) +net_slirp_add_poll(slirp_os_socket fd, int events, void *opaque) +# else net_slirp_add_poll(int fd, int events, void *opaque) +# endif { net_slirp_t *slirp = (net_slirp_t *) opaque; @@ -307,8 +323,13 @@ static const SlirpCb slirp_cb = { .timer_new = net_slirp_timer_new, .timer_free = net_slirp_timer_free, .timer_mod = net_slirp_timer_mod, +#if SLIRP_CHECK_VERSION(4, 9, 0) + .register_poll_socket = net_slirp_register_poll_socket, + .unregister_poll_socket = net_slirp_unregister_poll_socket, +#else .register_poll_fd = net_slirp_register_poll_fd, .unregister_poll_fd = net_slirp_unregister_poll_fd, +#endif .notify = net_slirp_notify }; @@ -362,7 +383,11 @@ net_slirp_thread(void *priv) bool run = true; while (run) { uint32_t timeout = -1; +# if SLIRP_CHECK_VERSION(4, 9, 0) + slirp_pollfds_fill_socket(slirp->slirp, &timeout, net_slirp_add_poll, slirp); +# else slirp_pollfds_fill(slirp->slirp, &timeout, net_slirp_add_poll, slirp); +# endif if (timeout < 0) timeout = INFINITE; @@ -409,7 +434,11 @@ net_slirp_thread(void *priv) net_slirp_add_poll(net_event_get_fd(&slirp->stop_event), SLIRP_POLL_IN, slirp); net_slirp_add_poll(net_event_get_fd(&slirp->tx_event), SLIRP_POLL_IN, slirp); +# if SLIRP_CHECK_VERSION(4, 9, 0) + slirp_pollfds_fill_socket(slirp->slirp, &timeout, net_slirp_add_poll, slirp); +# else slirp_pollfds_fill(slirp->slirp, &timeout, net_slirp_add_poll, slirp); +# endif int ret = poll(slirp->pfd, slirp->pfd_len, timeout); @@ -460,10 +489,47 @@ net_slirp_init(const netcard_t *card, const uint8_t *mac_addr, UNUSED(void *priv struct in_addr dhcp = { .s_addr = htonl(0x0a00000f | (slirp_card_num << 8)) }; /* 10.0.x.15 */ struct in_addr dns = { .s_addr = htonl(0x0a000003 | (slirp_card_num << 8)) }; /* 10.0.x.3 */ struct in_addr bind = { .s_addr = htonl(0x00000000) }; /* 0.0.0.0 */ - struct in6_addr ipv6_dummy = { 0 }; /* contents don't matter; we're not using IPv6 */ + + const SlirpConfig slirp_config = { +#if SLIRP_CHECK_VERSION(4, 9, 0) + .version = 6, +#else + .version = 1, +#endif + .restricted = 0, + .in_enabled = 1, + .vnetwork = net, + .vnetmask = mask, + .vhost = host, + .in6_enabled = 0, + .vprefix_addr6 = { .s6_addr = { 0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, /* fec0:: - unused */ + .vprefix_len = 64, + .vhost6 = { .s6_addr = { 0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x02 } }, /* fec0::2 - unused */ + .vhostname = "86Box", + .tftp_server_name = NULL, + .tftp_path = NULL, + .bootfile = NULL, + .vdhcp_start = dhcp, + .vnameserver = dns, + .vnameserver6 = { .s6_addr = { 0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x03 } }, /* fec0::3 - unused */ + .vdnssearch = NULL, + .vdomainname = NULL, + .if_mtu = 0, + .if_mru = 0, + .disable_host_loopback = 0, + .enable_emu = 0, +#if SLIRP_CHECK_VERSION(4, 9, 0) + .outbound_addr = NULL, + .outbound_addr6 = NULL, + .disable_dns = 0, + .disable_dhcp = 0, + .mfr_id = 0, + .oob_eth_addr = { 0, 0, 0, 0, 0, 0 } +#endif + }; /* Initialize SLiRP. */ - slirp->slirp = slirp_init(0, 1, net, mask, host, 0, ipv6_dummy, 0, ipv6_dummy, NULL, NULL, NULL, NULL, dhcp, dns, ipv6_dummy, NULL, NULL, &slirp_cb, slirp); + slirp->slirp = slirp_new(&slirp_config, &slirp_cb, slirp); if (!slirp->slirp) { slirp_log("SLiRP: initialization failed\n"); snprintf(netdrv_errbuf, NET_DRV_ERRBUF_SIZE, "SLiRP initialization failed"); diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index c08a03016..90ea218af 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -89,11 +89,7 @@ add_library(ui STATIC qt_hardwarerenderer.hpp qt_openglrenderer.cpp qt_openglrenderer.hpp - qt_opengloptions.cpp - qt_opengloptions.hpp - qt_opengloptionsdialog.cpp - qt_opengloptionsdialog.hpp - qt_opengloptionsdialog.ui + qt_glsl_parser.cpp qt_settings.cpp qt_settings.hpp @@ -190,6 +186,14 @@ add_library(ui STATIC ../qt_resources.qrc ./qdarkstyle/dark/darkstyle.qrc + + qt_openglshadermanagerdialog.hpp + qt_openglshadermanagerdialog.cpp + qt_openglshadermanagerdialog.ui + + qt_openglshaderconfig.hpp + qt_openglshaderconfig.cpp + qt_openglshaderconfig.ui ) if(RTMIDI) diff --git a/src/qt/languages/vi-VN.po b/src/qt/languages/vi-VN.po index fafbbc160..abf9a1dea 100644 --- a/src/qt/languages/vi-VN.po +++ b/src/qt/languages/vi-VN.po @@ -682,10 +682,10 @@ msgid "Surface images" msgstr "Ảnh bề mặt" msgid "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." -msgstr "Mẫu máy \"%hs\" không giả lập được do thiếu file ROM tương ứng trong mục roms/machines. Hãy chọn mẫu máy khác." +msgstr "Mẫu máy \"%hs\" không giả lập được do thiếu file ROM tương ứng trong thư mục roms/machines. Hãy chọn mẫu máy khác." msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." -msgstr "Card đồ họa \"%hs\" không giả lập được do thiếu file ROM tương ứng trong mục roms/video. Hãy chọn card đồ họa khác." +msgstr "Card đồ họa \"%hs\" không giả lập được do thiếu file ROM tương ứng trong thư mục roms/video. Hãy chọn card đồ họa khác." msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." msgstr "Card đồ họa 2 \"%hs\" không giả lập được do thiếu file ROM tương ứng trong mục roms/video. Vô hiệu hóa card đồ họa thứ hai." @@ -1219,7 +1219,7 @@ msgid "Development of the WinBox manager stopped in 2022 due to a lack of mainta msgstr "Trình quản lý phiên WinBox đã bị dừng phát triển năm 2022 do thiếu nhân sự duy trì. Vì những quyết định để cho 86Box trở nên tốt hơn, chúng tôi đã không còn hỗ trợ trình quản lý WinBox.\n\n Sẽ không có bản cập nhật mới cho WinBox nữa, và nếu bạn tiếp tục sử dụng với các bản 86Box mới hơn có thể gặp lỗi. Bất kì các bản bug report liên quan đến lỗi của WinBox sẽ bị coi là không hợp lệ và bị đóng.\n\nTruy cập 86Box.net để tìm qua các trình quản lý phiên/manager khác cho phù hợp." msgid "Generate" -msgstr "Phát ra" +msgstr "Tạo" msgid "Joystick configuration" msgstr "Cấu hình cần điều khiển" @@ -1240,7 +1240,7 @@ msgid "List of MCA devices:" msgstr "Danh sách các thiết bị MCA:" msgid "Tablet tool" -msgstr "Công cụ máy tính bảng" +msgstr "Công cụ bảng nhập liệu" msgid "Qt (OpenGL &ES)" msgstr "QT (OpenGL &ES)" @@ -1264,19 +1264,19 @@ msgid "Cursor/Puck" msgstr "Con trỏ/puck" msgid "Pen" -msgstr "Cái bút" +msgstr "Bút" msgid "Host CD/DVD Drive (%1:)" msgstr "Máy chủ CD/DVD ổ đĩa (%1 :)" msgid "&Connected" -msgstr "& Kết nối" +msgstr "&Đã kết nối" msgid "Clear image history" msgstr "Xóa lịch sử ảnh đĩa" msgid "Create..." -msgstr "Tạo nên..." +msgstr "Tạo..." msgid "previous image" msgstr "đĩa trước đó" @@ -1309,7 +1309,7 @@ msgid "OpenGL 3.0 renderer options" msgstr "Tùy chọn kết xuất OpenGL 3.0" msgid "Render behavior" -msgstr "Hiện ra hành vi" +msgstr "Hành vi kết xuất" msgid "Use target framerate:" msgstr "Dùng số khung hình mục tiêu:" @@ -1321,16 +1321,16 @@ msgid "VSync" msgstr "Vsync" msgid "<html><head/><body><p>Render each frame immediately, in sync with the emulated display.</p><p><span style=" font-style:italic;">This is the recommended option if the shaders in use don't utilize frametime for animated effects.</span></p></body></html>" -msgstr "<html><head/><body><p>Kết xuất mỗi khung ngay lập tức, đồng bộ với màn hình mô phỏng.</p><p><span style=" font-style:italic;">Đây là tùy chọn được đề xuất nếu các shader đang sử dụng không sử dụng hình chữ nhật cho các hiệu ứng hoạt hình.</span></p></body></html>" +msgstr "<html><head/><body><p>Kết xuất mỗi khung ngay lập tức, đồng bộ với màn hình mô phỏng.</p><p><span style=" font-style:italic;">Đây là tùy chọn được đề xuất nếu các shader đang sử dụng không tối ưu frametime cho các hiệu ứng động.</span></p></body></html>" msgid "Synchronize with video" -msgstr "Đồng bộ hóa với video" +msgstr "Đồng bộ với video" msgid "Shaders" msgstr "Shaders" msgid "Remove" -msgstr "Di dời" +msgstr "Loại bỏ" msgid "No shader selected" msgstr "Không có shader được chọn" @@ -1363,19 +1363,19 @@ msgid "Error initializing OpenGL" msgstr "Lỗi khởi tạo OpenGL" msgid "Falling back to software rendering.\n" -msgstr "Rơi trở lại kết xuất phần mềm.\n" +msgstr "Quay trở lại kết xuất phần mềm.\n" msgid "Allocating memory for unpack buffer failed.\n" msgstr "Phân bổ bộ nhớ cho bộ đệm giải nén không thành công.\n" msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" -msgstr "<html><head/><body><p>Khi chọn hình ảnh phương tiện (CD-ROM, FLOPPY, v.v.), hộp thoại mở sẽ bắt đầu trong cùng thư mục với tệp cấu hình 86box. Cài đặt này có thể sẽ chỉ tạo ra sự khác biệt trên macOS.</p></body></html>" +msgstr "<html><head/><body><p>Khi chọn hình ảnh phương tiện (CD-ROM, ổ mềm, v.v.), hộp thoại mở sẽ bắt đầu trong cùng thư mục với tệp cấu hình 86box. Cài đặt này có thể sẽ chỉ tạo ra sự khác biệt trên macOS.</p></body></html>" msgid "This machine might have been moved or copied." -msgstr "Máy này có thể đã được di chuyển hoặc sao chép." +msgstr "Cấu hình máy này có thể đã được di chuyển hoặc sao chép." msgid "In order to ensure proper networking functionality, 86Box needs to know if this machine was moved or copied.\n\nSelect \"I Copied It\" if you are not sure." -msgstr "Để đảm bảo chức năng kết nối mạng thích hợp, 86box cần biết liệu máy này có được di chuyển hay sao chép không.\n\nNếu bạn không chắc chắn, chọn \"Tôi đã sao chép nó\"." +msgstr "Để đảm bảo chức năng kết nối mạng thích hợp, 86Box cần biết liệu máy này có được di chuyển hay sao chép không.\n\nNếu bạn không chắc chắn, chọn \"Tôi đã sao chép nó\"." msgid "I Moved It" msgstr "Tôi đã di chuyển nó" @@ -1390,7 +1390,7 @@ msgid "No MCA devices." msgstr "Không có thiết bị MCA." msgid "MiB" -msgstr "Mib" +msgstr "MiB" msgid "Network Card #1" msgstr "Thẻ mạng 1" @@ -1405,7 +1405,7 @@ msgid "Network Card #4" msgstr "Thẻ mạng 4" msgid "Mode" -msgstr "Cách thức" +msgstr "Chế độ" msgid "Interface" msgstr "Giao diện" @@ -1417,7 +1417,7 @@ msgid "VDE Socket" msgstr "Ổ cắm VDE" msgid "86Box Unit Tester" -msgstr "Người kiểm tra đơn vị 86box" +msgstr "Trình kiểm tra đơn vị 86box" msgid "Novell NetWare 2.x Key Card" msgstr "Thẻ khóa Novell Netware 2.x" @@ -1435,7 +1435,7 @@ msgid "Serial port passthrough 4" msgstr "Thông qua cổng serial 4" msgid "Vision Systems LBA Enhancer" -msgstr "Hệ thống tầm nhìn LBA Enhancer" +msgstr "Vision Systems LBA Enhancer" msgid "Renderer options..." msgstr "Tùy chọn kết xuất ..." @@ -1477,7 +1477,7 @@ msgid "Roland CM-32LN Emulation" msgstr "Mô phỏng Roland CM-32LN" msgid "OPL4-ML Daughterboard" -msgstr "Con gái OPL4-ML" +msgstr "Bo mạch con OPL4-ML" msgid "System MIDI" msgstr "MIDI của hệ thống" @@ -1489,7 +1489,7 @@ msgid "BIOS Address" msgstr "Địa chỉ BIOS" msgid "Enable BIOS extension ROM Writes" -msgstr "Bật ROM mở rộng BIOS" +msgstr "Kích hoạt ghi ROM mở rộng BIOS" msgid "Address" msgstr "Địa chỉ" @@ -1516,22 +1516,22 @@ msgid "BIOS size" msgstr "Kích thước BIOS" msgid "Map C0000-C7FFF as UMB" -msgstr "Bản đồ C0000-C7FFF dưới dạng UMB" +msgstr "Map C0000-C7FFF dưới dạng UMB" msgid "Map C8000-CFFFF as UMB" -msgstr "Bản đồ C8000-CFFFF dưới dạng UMB" +msgstr "Map C8000-CFFFF dưới dạng UMB" msgid "Map D0000-D7FFF as UMB" -msgstr "Bản đồ D0000-D7FFF dưới dạng UMB" +msgstr "Map D0000-D7FFF dưới dạng UMB" msgid "Map D8000-DFFFF as UMB" -msgstr "Bản đồ D8000-Dffff dưới dạng UMB" +msgstr "Map D8000-Dffff dưới dạng UMB" msgid "Map E0000-E7FFF as UMB" -msgstr "Bản đồ E0000-E7FFF dưới dạng UMB" +msgstr "Map E0000-E7FFF dưới dạng UMB" msgid "Map E8000-EFFFF as UMB" -msgstr "Bản đồ e8000-effff dưới dạng umb" +msgstr "Map e8000-effff dưới dạng umb" msgid "JS9 Jumper (JIM)" msgstr "JS9 Jumper (Jim)" @@ -1546,13 +1546,13 @@ msgid "MIDI Thru" msgstr "Thông qua đầu vào MIDI" msgid "MIDI Clockout" -msgstr "MIDI đồng hồ" +msgstr "MIDI Clockout" msgid "SoundFont" -msgstr "Soundfont" +msgstr "Font âm thanh" msgid "Output Gain" -msgstr "Đầu ra tăng" +msgstr "Tăng đầu ra" msgid "Chorus" msgstr "Điệp khúc" @@ -1591,7 +1591,7 @@ msgid "Interpolation Method" msgstr "Phương pháp nội suy" msgid "Reverb Output Gain" -msgstr "Gợi ý đầu ra hồi âm" +msgstr "Tăng đầu ra hồi âm" msgid "Reversed stereo" msgstr "Đảo ngược âm thanh nổi" @@ -1612,10 +1612,10 @@ msgid "RTS toggle" msgstr "RT chuyển đổi" msgid "Revision" -msgstr "Ôn tập" +msgstr "Bản sửa đổi" msgid "Controller" -msgstr "Người điều khiển" +msgstr "Bộ điều khiển" msgid "Show Crosshair" msgstr "Hiển thị hình chữ thập" @@ -1627,7 +1627,7 @@ msgid "MAC Address" msgstr "Địa chỉ MAC" msgid "MAC Address OUI" -msgstr " OUI địa chỉ MAC" +msgstr "OUI địa chỉ MAC" msgid "Enable BIOS" msgstr "Bật BIOS" @@ -1699,7 +1699,7 @@ msgid "Enable OPL" msgstr "Bật OPL" msgid "Receive MIDI input (MPU-401)" -msgstr "Nhận nhập MIDI (MPU-401)" +msgstr "Nhận đầu vào MIDI (MPU-401)" msgid "SB low DMA" msgstr "SB DMA thấp" @@ -1711,7 +1711,7 @@ msgid "Enable CMS" msgstr "Bật CMS" msgid "Mixer" -msgstr "Máy trộn" +msgstr "Bộ trộn" msgid "High DMA" msgstr "DMA cao" @@ -1747,13 +1747,13 @@ msgid "RGB type" msgstr "Loại RGB" msgid "Line doubling type" -msgstr "Dòng nhân đôi" +msgstr "Loại dòng kép" msgid "Snow emulation" -msgstr "Đun tuyết" +msgstr "Giả lập hiệu ứng tuyết" msgid "Monitor type" -msgstr "Loại giám sát" +msgstr "Loại màn hình" msgid "Character set" msgstr "Bộ ký tự" @@ -1762,13 +1762,13 @@ msgid "XGA type" msgstr "Loại XGA" msgid "Instance" -msgstr "Ví dụ" +msgstr "Bản chạy" msgid "MMIO Address" msgstr "Địa chỉ MMIO" msgid "RAMDAC type" -msgstr "Loại Ramdac" +msgstr "Loại RAMDAC" msgid "Blend" msgstr "Trộn" @@ -1792,13 +1792,13 @@ msgid "Texture memory size" msgstr "Kích thước bộ nhớ kết cấu" msgid "Dither subtraction" -msgstr "Phân biệt trừ" +msgstr "Giảm ngân tán" msgid "Screen Filter" msgstr "Bộ lọc màn hình" msgid "Render threads" -msgstr "Kết xuất chủ đề" +msgstr "Luồng kết xuất" msgid "SLI" msgstr "SLI" @@ -1813,13 +1813,13 @@ msgid "I/O Width" msgstr "Chiều rộng I/O" msgid "Transfer Speed" -msgstr "Tốc độ chuyển" +msgstr "Tốc độ truyền tải" msgid "EMS mode" msgstr "Chế độ EMS" msgid "Address for > 2 MB" -msgstr "Địa chỉ cho> 2 MB" +msgstr "Địa chỉ cho > 2 MB" msgid "Frame Address" msgstr "Địa chỉ khung" @@ -1834,7 +1834,7 @@ msgid "Always at selected speed" msgstr "Luôn ở tốc độ đã chọn" msgid "BIOS setting + Hotkeys (off during POST)" -msgstr "Cài đặt BIOS + phím nóng (TẮT trong bài đăng)" +msgstr "Cài đặt BIOS + phím nóng (TẮT trong POST)" msgid "64 kB starting from F0000" msgstr "64 kb bắt đầu từ f0000" @@ -1861,7 +1861,7 @@ msgid "Non-timed (original)" msgstr "Không đúng lúc (bản gốc)" msgid "45 Hz (JMP2 not populated)" -msgstr "45 Hz (JMP2 không dân cư)" +msgstr "45 Hz (JMP2 không phổ cập)" msgid "Two" msgstr "Hai" @@ -1870,10 +1870,10 @@ msgid "Three" msgstr "Ba" msgid "Wheel" -msgstr "Bánh xe" +msgstr "Con lăn" msgid "Five + Wheel" -msgstr "Năm + bánh xe" +msgstr "Năm + con lăn" msgid "A3 - SMT2 Serial / SMT3(R)V" msgstr "A3 - SMT2 Serial / SMT3(R)V" @@ -2008,7 +2008,7 @@ msgid "Color" msgstr "Màu sắc" msgid "U.S. English" -msgstr "Tiếng Anh Hoa Kỳ" +msgstr "Tiếng Anh Mỹ" msgid "Scandinavian" msgstr "Scandinavia" @@ -2020,13 +2020,13 @@ msgid "Bochs latest" msgstr "Bochs mới nhất" msgid "Mono Non-Interlaced" -msgstr "Đơn sắc không được xen kẽ" +msgstr "Đơn sắc không xen kẽ" msgid "Color Interlaced" msgstr "Màu sắc xen kẽ" msgid "Color Non-Interlaced" -msgstr "Màu sắc không được xen kẽ" +msgstr "Màu sắc không xen kẽ" msgid "3Dfx Voodoo Graphics" msgstr "Đồ họa 3Dfx Voodoo" @@ -2074,7 +2074,7 @@ msgid "Parallel Line Internet Protocol" msgstr "Parallel Line Internet Protocol" msgid "Protection Dongle for Savage Quest" -msgstr "Bảo vệ dongle cho Savage Quest" +msgstr "Dongle bảo vệ cho Savage Quest" msgid "Serial Passthrough Device" msgstr "Thiết bị thông qua cổng serial" @@ -2086,7 +2086,7 @@ msgid "Host Serial Device" msgstr "Thiết bị serial máy chủ" msgid "Name of pipe" -msgstr "Tên của đường ống" +msgstr "Tên đường ống" msgid "Data bits" msgstr "Bit dữ liệu" @@ -2095,10 +2095,10 @@ msgid "Stop bits" msgstr "Dừng bit" msgid "Baud Rate of Passthrough" -msgstr "Tốc độ baud của qua đường" +msgstr "Tốc độ baud của đường thông" msgid "Named Pipe (Server)" -msgstr "Đường ống được đặt tên (máy chủ)" +msgstr "Đường ống có tên (máy chủ)" msgid "Host Serial Passthrough" msgstr "Thông qua cổng serial của máy chủ" @@ -2107,19 +2107,19 @@ msgid "Eject %s" msgstr "Đẩy đĩa ra %s" msgid "&Unmute" -msgstr "&Không quay được" +msgstr "&Mở tiếng" msgid "Softfloat FPU" msgstr "Softfloat FPU" msgid "High performance impact" -msgstr "Tác động cao đến hiệu suất" +msgstr "Ảnh hưởng lớn đến hiệu suất" msgid "RAM Disk (max. speed)" -msgstr "Đĩa RAM (Tối đa. Tốc độ)" +msgstr "Đĩa RAM (tốc độ tối đa)" msgid "IBM 8514/A clone (ISA)" -msgstr "IBM 8514/A dòng vô tính (ISA)" +msgstr "IBM 8514/A bản nhái (ISA)" msgid "Vendor" msgstr "Nhà sản xuất" diff --git a/src/qt/qt.c b/src/qt/qt.c index a9a6460eb..13ddbf498 100644 --- a/src/qt/qt.c +++ b/src/qt/qt.c @@ -54,6 +54,8 @@ plat_vidapi(const char *api) return 4; } else if (!strcasecmp(api, "vnc")) { return 5; + } else if (!strcasecmp(api, "qt_opengl3_pcem")) { + return 6; } return 0; @@ -83,6 +85,9 @@ plat_vidapi_name(int api) case 5: name = "vnc"; break; + case 6: + name = "qt_opengl3_pcem"; + break; default: fatal("Unknown renderer: %i\n", api); break; diff --git a/src/qt/qt_deviceconfig.cpp b/src/qt/qt_deviceconfig.cpp index e2d6759ad..cda52e722 100644 --- a/src/qt/qt_deviceconfig.cpp +++ b/src/qt/qt_deviceconfig.cpp @@ -123,7 +123,7 @@ DeviceConfig::ProcessConfig(void *dc, const void *c, const bool is_dep) if (config == NULL) return; - while (config->type != -1) { + while (config->type != CONFIG_END) { const int config_type = config->type & CONFIG_TYPE_MASK; /* Ignore options of the wrong class. */ @@ -242,8 +242,12 @@ DeviceConfig::ProcessConfig(void *dc, const void *c, const bool is_dep) int currentIndex = -1; q = 0; - for (auto *bios = config->bios; (bios != nullptr) && (bios->name != nullptr) && - (strlen(bios->name) > 0); ++bios) { + for (auto *bios = config->bios; (bios != nullptr) && + (bios->name != nullptr) && + (bios->internal_name != nullptr) && + (strlen(bios->name) > 0) && + (strlen(bios->internal_name) > 0) && + (bios->files_no > 0); ++bios) { p = 0; for (int d = 0; d < bios->files_no; d++) p += !!rom_present(const_cast(bios->files[d])); @@ -372,7 +376,7 @@ DeviceConfig::ConfigureDevice(const _device_ *device, int instance, Settings *se return; config = device->config; - while (config->type != -1) { + while (config->type != CONFIG_END) { switch (config->type) { default: break; diff --git a/src/qt/qt_glsl_parser.cpp b/src/qt/qt_glsl_parser.cpp new file mode 100644 index 000000000..bf02014db --- /dev/null +++ b/src/qt/qt_glsl_parser.cpp @@ -0,0 +1,384 @@ +#include "qt_mainwindow.hpp" +#include +#include +#include + +extern MainWindow* main_window; + +#include +#include +#include +#include +#include +extern "C" +{ +#include <86box/86box.h> +#include <86box/ini.h> +#include <86box/config.h> +#include <86box/qt-glslp-parser.h> +#include <86box/path.h> + +extern void startblit(); +extern void endblit(); +} + +#define safe_strncpy(a, b, n) \ + do { \ + strncpy((a), (b), (n)-1); \ + (a)[(n)-1] = 0; \ + } while (0) + + + +static inline void *wx_config_load(const char *path) { ini_t ini = ini_read(path); if (ini) ini_strip_quotes(ini); return (void*)ini; } + +static inline int wx_config_get_string(void *config, const char *name, char *dst, int size, const char *defVal) { + int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); + char* str = ini_get_string((ini_t)config, "", name, (char*)defVal); + if (size == 0) + return res; + if (str != NULL) + strncpy(dst, str, size - 1); + else + dst[0] = 0; + return res; +} + +static inline int wx_config_get_int(void *config, const char *name, int *dst, int defVal) { + int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); + *dst = ini_get_int((ini_t)config, "", name, defVal); + return res; +} + +static inline int wx_config_get_float(void *config, const char *name, float *dst, float defVal) { + int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); + *dst = (float)ini_get_double((ini_t)config, "", name, defVal); + return res; +} + +static inline int wx_config_get_bool(void *config, const char *name, int *dst, int defVal) { + int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); + *dst = !!ini_get_int((ini_t)config, "", name, defVal); + return res; +} + +static inline int wx_config_has_entry(void *config, const char *name) { return ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); } +static inline void wx_config_free(void *config) { ini_close(config); }; + +static int endswith(const char *str, const char *ext) { + int i; + const char *p; + int elen = strlen(ext); + int slen = strlen(str); + if (slen >= elen) { + p = &str[slen - elen]; + for (i = 0; i < elen; ++i) { + if (tolower(p[i]) != tolower(ext[i])) + return 0; + } + return 1; + } + return 0; +} + +static char *load_file(const char *fn) { + FILE *f = fopen(fn, "rb"); + if (!f) + return 0; + fseek(f, 0, SEEK_END); + long fsize = ftell(f); + fseek(f, 0, SEEK_SET); + + char *data = (char*)malloc(fsize + 1); + + fread(data, fsize, 1, f); + fclose(f); + + data[fsize] = 0; + + return data; +} + +static void strip_lines(const char *program, const char *starts_with) { + /* strip parameters */ + char *ptr = strstr(program, starts_with); + while (ptr) { + while (*ptr != '\n' && *ptr != '\0') + *ptr++ = ' '; + ptr = strstr(program, starts_with); + } +} + +static void strip_parameters(const char *program) { + /* strip parameters */ + strip_lines(program, "#pragma parameter"); +} + +static void strip_defines(const char *program) { + /* strip texture define */ + strip_lines(program, "#define texture"); +} + +static int has_parameter(glslp_t *glsl, char *id) { + int i; + for (i = 0; i < glsl->num_parameters; ++i) + if (!strcmp(glsl->parameters[i].id, id)) + return 1; + return 0; +} + +static int get_parameters(glslp_t *glsl) { + int i; + struct parameter p; + for (i = 0; i < glsl->num_shaders; ++i) { + struct shader *shader = &glsl->shaders[i]; + FILE *f = fopen(shader->shader_fn, "rb"); + if (!f) + return 0; + + char line[1024]; + while (fgets(line, sizeof(line) - 1, f) && glsl->num_parameters < MAX_PARAMETERS) { + int num = sscanf(line, "#pragma parameter %63s \"%63[^\"]\" %f %f %f %f", p.id, p.description, + &p.default_value, &p.min, &p.max, &p.step); + if (num < 5) + continue; + p.id[63] = 0; + p.description[63] = 0; + + if (num == 5) + p.step = 0.1f * (p.max - p.min); + + p.value = p.default_value; + + if (!has_parameter(glsl, p.id)) { + memcpy(&glsl->parameters[glsl->num_parameters++], &p, sizeof(struct parameter)); + pclog("Read parameter: %s (%s) %f, %f -> %f (%f)\n", p.id, p.description, p.default_value, p.min, + p.max, p.step); + } + } + + fclose(f); + } + + return 1; +} + +static struct parameter *get_parameter(glslp_t *glslp, const char *id) { + int i; + for (i = 0; i < glslp->num_parameters; ++i) { + if (!strcmp(glslp->parameters[i].id, id)) { + return &glslp->parameters[i]; + } + } + return 0; +} + +static glslp_t *glsl_parse(const char *f) { + glslp_t *glslp = (glslp_t*)malloc(sizeof(glslp_t)); + memset(glslp, 0, sizeof(glslp_t)); + glslp->num_shaders = 1; + struct shader *shader = &glslp->shaders[0]; + strcpy(shader->shader_fn, f); + shader->shader_program = load_file(f); + if (!shader->shader_program) { + QMessageBox::critical((QWidget *) qApp->findChild(), QObject::tr("GLSL error"), QObject::tr("Could not load shader %1").arg(shader->shader_fn)); + //wx_simple_messagebox("GLSL error", "Could not load shader %s\n", shader->shader_fn); + glslp_free(glslp); + return 0; + } + strip_parameters(shader->shader_program); + strip_defines(shader->shader_program); + shader->scale_x = shader->scale_y = 1.0f; + strcpy(shader->scale_type_x, "source"); + strcpy(shader->scale_type_y, "source"); + get_parameters(glslp); + return glslp; +} + +extern "C" { + +void get_glslp_name(const char *f, char *s, int size) { safe_strncpy(s, path_get_filename((char *)f), size); } + +glslp_t *glslp_parse(const char *f) { + int i, j, len, sublen; + char s[513], t[513], z[540]; + + memset(s, 0, sizeof(s)); + if (endswith(f, ".glsl")) + return glsl_parse(f); + + void *cfg = wx_config_load(f); + + if (!cfg) { + fprintf(stderr, "GLSLP Error: Could not load GLSLP-file %s\n", f); + return 0; + } + + glslp_t *glslp = (glslp_t*)malloc(sizeof(glslp_t)); + memset(glslp, 0, sizeof(glslp_t)); + + get_glslp_name(f, glslp->name, sizeof(glslp->name)); + + wx_config_get_int(cfg, "shaders", &glslp->num_shaders, 0); + + wx_config_get_bool(cfg, "filter_linear0", &glslp->input_filter_linear, -1); + + for (i = 0; i < glslp->num_shaders; ++i) { + struct shader *shader = &glslp->shaders[i]; + + snprintf(s, sizeof(s) - 1, "shader%d", i); + if (!wx_config_get_string(cfg, s, t, sizeof(t), 0)) { + /* shader doesn't exist, lets break here */ + glslp->num_shaders = i; + break; + } + strcpy(s, f); + *path_get_filename(s) = 0; + snprintf(shader->shader_fn, sizeof(shader->shader_fn) - 1, "%s%s", s, t); + shader->shader_program = load_file(shader->shader_fn); + if (!shader->shader_program) { + fprintf(stderr, "GLSLP Error: Could not load shader %s\n", shader->shader_fn); + glslp_free(glslp); + return 0; + } + strip_parameters(shader->shader_program); + strip_defines(shader->shader_program); + + snprintf(s, sizeof(s) - 1, "alias%d", i); + wx_config_get_string(cfg, s, shader->alias, sizeof(shader->alias), 0); + + snprintf(s, sizeof(s) - 1, "filter_linear%d", i + 1); + wx_config_get_bool(cfg, s, &shader->filter_linear, 0); + + snprintf(s, sizeof(s) - 1, "wrap_mode%d", i); + wx_config_get_string(cfg, s, shader->wrap_mode, sizeof(shader->wrap_mode), 0); + + snprintf(s, sizeof(s) - 1, "float_framebuffer%d", i); + wx_config_get_bool(cfg, s, &shader->float_framebuffer, 0); + snprintf(s, sizeof(s) - 1, "srgb_framebuffer%d", i); + wx_config_get_bool(cfg, s, &shader->srgb_framebuffer, 0); + + snprintf(s, sizeof(s) - 1, "mipmap_input%d", i); + wx_config_get_bool(cfg, s, &shader->mipmap_input, 0); + + strcpy(shader->scale_type_x, "source"); + snprintf(s, sizeof(s) - 1, "scale_type_x%d", i); + wx_config_get_string(cfg, s, shader->scale_type_x, sizeof(shader->scale_type_x), 0); + strcpy(shader->scale_type_y, "source"); + snprintf(s, sizeof(s) - 1, "scale_type_y%d", i); + wx_config_get_string(cfg, s, shader->scale_type_y, sizeof(shader->scale_type_y), 0); + snprintf(s, sizeof(s) - 1, "scale_type%d", i); + if (wx_config_has_entry(cfg, s)) { + wx_config_get_string(cfg, s, shader->scale_type_x, sizeof(shader->scale_type_x), 0); + wx_config_get_string(cfg, s, shader->scale_type_y, sizeof(shader->scale_type_y), 0); + } + + snprintf(s, sizeof(s) - 1, "scale_x%d", i); + wx_config_get_float(cfg, s, &shader->scale_x, 1.0f); + snprintf(s, sizeof(s) - 1, "scale_y%d", i); + wx_config_get_float(cfg, s, &shader->scale_y, 1.0f); + snprintf(s, sizeof(s) - 1, "scale%d", i); + if (wx_config_has_entry(cfg, s)) { + wx_config_get_float(cfg, s, &shader->scale_x, 1.0f); + wx_config_get_float(cfg, s, &shader->scale_y, 1.0f); + } + + snprintf(s, sizeof(s) - 1, "frame_count_mod%d", i); + wx_config_get_int(cfg, s, &shader->frame_count_mod, 0); + } + + /* textures */ + glslp->num_textures = 0; + wx_config_get_string(cfg, "textures", t, sizeof(t), 0); + + len = strlen(t); + j = 0; + sublen = 0; + for (i = 0; i < len; ++i) { + if (t[i] == ';' || i == len - 1) { + sublen = (i - j) + ((i == len - 1) ? 1 : 0) + 1; + safe_strncpy(s, t + j, sublen); + s[511 < sublen ? 511 : sublen] = 0; + + if (s[strlen(s) - 1] == ';') s[strlen(s) - 1] = 0; + + struct texture *tex = &glslp->textures[glslp->num_textures++]; + + strcpy(tex->name, s); + wx_config_get_string(cfg, s, tex->path, sizeof(tex->path), 0); + + snprintf(z, sizeof(z) - 1, "%s_linear", s); + wx_config_get_bool(cfg, z, &tex->linear, 0); + + snprintf(z, sizeof(z) - 1, "%s_mipmap", s); + wx_config_get_bool(cfg, z, &tex->mipmap, 0); + + snprintf(z, sizeof(z) - 1, "%s_wrap_mode", s); + wx_config_get_string(cfg, z, tex->wrap_mode, sizeof(tex->wrap_mode), 0); + + j = i + 1; + } + } + + /* parameters */ + get_parameters(glslp); + + wx_config_get_string(cfg, "parameters", t, sizeof(t), 0); + + len = strlen(t); + j = 0; + sublen = 0; + for (i = 0; i < len; ++i) { + if (t[i] == ';' || i == len - 1) { + sublen = (i - j) + ((i == len - 1) ? 1 : 0) + 1; + safe_strncpy(s, t + j, sublen); + s[511 < sublen ? 511 : sublen] = 0; + + struct parameter *p = get_parameter(glslp, s); + + if (p) + wx_config_get_float(cfg, s, &p->default_value, 0); + + j = i + 1; + } + } + + wx_config_free(cfg); + + return glslp; +} + +void glslp_free(glslp_t *p) { + int i; + for (i = 0; i < p->num_shaders; ++i) + if (p->shaders[i].shader_program) + free(p->shaders[i].shader_program); + free(p); +} + +void glslp_read_shader_config(glslp_t *shader) { + char s[512]; + int i; + char *name = shader->name; + sprintf(s, "GL3 Shaders - %s", name); + for (i = 0; i < shader->num_parameters; ++i) { + struct parameter *param = &shader->parameters[i]; + param->value = config_get_double(s, param->id, param->default_value); + } +} + +void glslp_write_shader_config(glslp_t *shader) { + char s[512]; + int i; + char *name = shader->name; + + startblit(); + sprintf(s, "GL3 Shaders - %s", name); + for (i = 0; i < shader->num_parameters; ++i) { + struct parameter *param = &shader->parameters[i]; + config_set_double(s, param->id, param->value); + } + endblit(); +} + +} diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 719208c18..b48d272c5 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -90,6 +90,8 @@ extern "C" { #include <86box/timer.h> #include <86box/nvr.h> extern int qt_nvr_save(void); + +bool cpu_thread_running = false; } void qt_set_sequence_auto_mnemonic(bool b); @@ -389,6 +391,7 @@ main_thread_fn() // title_update = 1; uint64_t old_time = elapsed_timer.elapsed(); int drawits = frames = 0; + is_cpu_thread = 1; while (!is_quit && cpu_thread_run) { /* See if it is time to run a frame of code. */ const uint64_t new_time = elapsed_timer.elapsed(); @@ -443,6 +446,7 @@ main_thread_fn() } } + cpu_thread_running = false; is_quit = 1; for (uint8_t i = 1; i < GFXCARD_MAX; i ++) { if (gfxcard[i]) { @@ -735,6 +739,7 @@ main(int argc, char *argv[]) #endif plat_pause(0); + cpu_thread_running = true; main_thread = new std::thread(main_thread_fn); }); diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 1cc6c33c9..cdb46cb29 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -62,6 +62,8 @@ extern int qt_nvr_save(void); #ifdef MTR_ENABLED # include #endif + +extern bool cpu_thread_running; }; #include @@ -452,6 +454,9 @@ MainWindow::MainWindow(QWidget *parent) endblit(); } #endif + case 6: + newVidApi = RendererStack::Renderer::OpenGL3PCem; + break; } ui->stackedWidget->switchRenderer(newVidApi); if (!show_second_monitors) @@ -779,6 +784,14 @@ MainWindow::closeEvent(QCloseEvent *event) ui->stackedWidget->mouse_exit_func(); ui->stackedWidget->switchRenderer(RendererStack::Renderer::Software); + for (int i = 1; i < MONITORS_NUM; i++) { + if (renderers[i] && renderers[i]->isHidden()) { + renderers[i]->show(); + QApplication::processEvents(); + renderers[i]->switchRenderer(RendererStack::Renderer::Software); + QApplication::processEvents(); + } + } qt_nvr_save(); config_save(); @@ -1253,7 +1266,7 @@ MainWindow::eventFilter(QObject *receiver, QEvent *event) static auto curdopause = dopause; if (event->type() == QEvent::WindowBlocked) { curdopause = dopause; - plat_pause(1); + plat_pause(isShowMessage ? 2 : 1); emit setMouseCapture(false); } else if (event->type() == QEvent::WindowUnblocked) { plat_pause(curdopause); @@ -1267,6 +1280,7 @@ void MainWindow::refreshMediaMenu() { mm->refresh(ui->menuMedia); + status->setSoundGainAction(ui->actionSound_gain); status->refresh(ui->statusbar); ui->actionMCA_devices->setVisible(machine_has_bus(machine, MACHINE_BUS_MCA)); ui->actionACPI_Shutdown->setEnabled(!!acpi_enabled); @@ -1276,7 +1290,11 @@ void MainWindow::showMessage(int flags, const QString &header, const QString &message) { if (QThread::currentThread() == this->thread()) { - showMessage_(flags, header, message); + if (!cpu_thread_running) { + showMessageForNonQtThread(flags, header, message, nullptr); + } + else + showMessage_(flags, header, message); } else { std::atomic_bool done = false; emit showMessageForNonQtThread(flags, header, message, &done); @@ -1292,6 +1310,7 @@ MainWindow::showMessage_(int flags, const QString &header, const QString &messag if (done) { *done = false; } + isShowMessage = true; QMessageBox box(QMessageBox::Warning, header, message, QMessageBox::NoButton, this); if (flags & (MBX_FATAL)) { box.setIcon(QMessageBox::Critical); @@ -1303,6 +1322,7 @@ MainWindow::showMessage_(int flags, const QString &header, const QString &messag if (done) { *done = true; } + isShowMessage = false; if (cpu_thread_run == 0) QApplication::exit(-1); } @@ -1979,15 +1999,40 @@ MainWindow::changeEvent(QEvent *event) } } +void +MainWindow::reloadAllRenderers() +{ + reload_renderers = true; +} + void MainWindow::on_actionRenderer_options_triggered() { if (const auto dlg = ui->stackedWidget->getOptions(this)) { if (dlg->exec() == QDialog::Accepted) { - for (int i = 1; i < MONITORS_NUM; i++) { + if (ui->stackedWidget->reloadRendererOption()) { + ui->stackedWidget->switchRenderer(static_cast(vid_api)); + if (show_second_monitors) { + for (int i = 1; i < MONITORS_NUM; i++) { + if (renderers[i] && renderers[i]->reloadRendererOption() && renderers[i]->hasOptions()) { + ui->stackedWidget->switchRenderer(static_cast(vid_api)); + } + } + } + } else for (int i = 1; i < MONITORS_NUM; i++) { if (renderers[i] && renderers[i]->hasOptions()) renderers[i]->reloadOptions(); } + } else if (reload_renderers && ui->stackedWidget->reloadRendererOption()) { + reload_renderers = false; + ui->stackedWidget->switchRenderer(static_cast(vid_api)); + if (show_second_monitors) { + for (int i = 1; i < MONITORS_NUM; i++) { + if (renderers[i] && renderers[i]->reloadRendererOption() && renderers[i]->hasOptions()) { + ui->stackedWidget->switchRenderer(static_cast(vid_api)); + } + } + } } } } diff --git a/src/qt/qt_mainwindow.hpp b/src/qt/qt_mainwindow.hpp index 25e33d77c..479ed38a4 100644 --- a/src/qt/qt_mainwindow.hpp +++ b/src/qt/qt_mainwindow.hpp @@ -32,6 +32,7 @@ public: QSize getRenderWidgetSize(); void setSendKeyboardInput(bool enabled); void checkFullscreenHotkey(); + void reloadAllRenderers(); std::array, 8> renderers; signals: @@ -173,11 +174,17 @@ private: bool fs_on_signal = false; bool fs_off_signal = false; + /* Reload the renderers after closing renderer options dialog. */ + bool reload_renderers = false; + friend class SpecifyDimensions; friend class ProgSettings; friend class RendererCommon; friend class RendererStack; // For UI variable access by non-primary renderer windows. friend class WindowsRawInputFilter; // Needed to reload renderers on style sheet changes. + + + bool isShowMessage = false; }; #endif // QT_MAINWINDOW_HPP diff --git a/src/qt/qt_opengloptions.cpp b/src/qt/qt_opengloptions.cpp deleted file mode 100644 index 58030b467..000000000 --- a/src/qt/qt_opengloptions.cpp +++ /dev/null @@ -1,196 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * OpenGL renderer options for Qt - * - * - * - * Authors: Teemu Korhonen - * - * Copyright 2022 Teemu Korhonen - */ - -#include -#include -#include -#include - -#include - -#include "qt_opengloptions.hpp" - -extern "C" { -#include <86box/86box.h> -} - -/* Default vertex shader. */ -static const GLchar *vertex_shader = "\ -in vec2 VertexCoord;\n\ -in vec2 TexCoord;\n\ -out vec2 tex;\n\ -void main(){\n\ - gl_Position = vec4(VertexCoord, 0.0, 1.0);\n\ - tex = TexCoord;\n\ -}\n"; - -/* Default fragment shader. */ -static const GLchar *fragment_shader = "\ -in vec2 tex;\n\ -uniform sampler2D texsampler;\n\ -out vec4 color;\n\ -void main() {\n\ - color = texture(texsampler, tex);\n\ -}\n"; - -OpenGLOptions::OpenGLOptions(QObject *parent, bool loadConfig, const QString &glslVersion) - : QObject(parent) - , m_glslVersion(glslVersion) -{ - m_filter = video_filter_method == 0 - ? FilterType::Nearest - : FilterType::Linear; - - if (!loadConfig) - return; - - /* Initialize with config. */ - m_vsync = video_vsync != 0; - m_framerate = video_framerate; - - m_renderBehavior = video_framerate == -1 - ? RenderBehaviorType::SyncWithVideo - : RenderBehaviorType::TargetFramerate; - - QString shaderPath(video_shader); - - if (shaderPath.isEmpty()) { - addDefaultShader(); - } else { - try { - addShader(shaderPath); - } catch (const std::runtime_error &) { - /* Fallback to default shader */ - addDefaultShader(); - } - } -} - -void -OpenGLOptions::save() const -{ - video_vsync = m_vsync ? 1 : 0; - video_framerate = m_renderBehavior == RenderBehaviorType::SyncWithVideo ? -1 : m_framerate; - video_filter_method = m_filter == FilterType::Nearest ? 0 : 1; - - /* TODO: multiple shaders */ - auto path = m_shaders.first().path().toLocal8Bit(); - - if (!path.isEmpty()) - qstrncpy(video_shader, path.constData(), sizeof(video_shader)); - else - video_shader[0] = '\0'; -} - -OpenGLOptions::FilterType -OpenGLOptions::filter() const -{ - /* Filter method is controlled externally */ - return video_filter_method == 0 - ? FilterType::Nearest - : FilterType::Linear; -} - -void -OpenGLOptions::setRenderBehavior(RenderBehaviorType value) -{ - m_renderBehavior = value; -} - -void -OpenGLOptions::setFrameRate(int value) -{ - m_framerate = value; -} - -void -OpenGLOptions::setVSync(bool value) -{ - m_vsync = value; -} - -void -OpenGLOptions::setFilter(FilterType value) -{ - m_filter = value; -} - -void -OpenGLOptions::addShader(const QString &path) -{ - QFile shader_file(path); - - if (!shader_file.open(QIODevice::ReadOnly | QIODevice::Text)) { - throw std::runtime_error( - QString(tr("Error opening \"%1\": %2")) - .arg(path) - .arg(shader_file.errorString()) - .toStdString()); - } - - auto shader_text = QString(shader_file.readAll()); - - shader_file.close(); - - /* Remove parameter lines */ - shader_text.remove(QRegularExpression("^\\s*#pragma parameter.*?\\n", QRegularExpression::MultilineOption)); - - QRegularExpression version("^\\s*(#version\\s+\\w+)", QRegularExpression::MultilineOption); - - auto match = version.match(shader_text); - - QString version_line(m_glslVersion); - - if (match.hasMatch()) { - /* Extract existing version and remove it. */ - version_line = match.captured(1); - shader_text.remove(version); - } - - auto shader = new QOpenGLShaderProgram(this); - - auto throw_shader_error = [path, shader](const QString &what) { - throw std::runtime_error( - QString(what % ":\n\n %2") - .arg(path) - .arg(shader->log()) - .toStdString()); - }; - - static const char *extension = "\n#extension GL_ARB_shading_language_420pack : enable\n"; - - if (!shader->addShaderFromSourceCode(QOpenGLShader::Vertex, version_line % extension % "\n#define VERTEX\n#line 1\n" % shader_text)) - throw_shader_error(tr("Error compiling vertex shader in file \"%1\"")); - - if (!shader->addShaderFromSourceCode(QOpenGLShader::Fragment, version_line % extension % "\n#define FRAGMENT\n#line 1\n" % shader_text)) - throw_shader_error(tr("Error compiling fragment shader in file \"%1\"")); - - if (!shader->link()) - throw_shader_error(tr("Error linking shader program in file \"%1\"")); - - m_shaders << OpenGLShaderPass(shader, path); -} - -void -OpenGLOptions::addDefaultShader() -{ - auto shader = new QOpenGLShaderProgram(this); - shader->addShaderFromSourceCode(QOpenGLShader::Vertex, m_glslVersion % "\n" % vertex_shader); - shader->addShaderFromSourceCode(QOpenGLShader::Fragment, m_glslVersion % "\n" % fragment_shader); - shader->link(); - m_shaders << OpenGLShaderPass(shader, QString()); -} diff --git a/src/qt/qt_opengloptions.hpp b/src/qt/qt_opengloptions.hpp deleted file mode 100644 index 64f761670..000000000 --- a/src/qt/qt_opengloptions.hpp +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Header for OpenGL renderer options - * - * - * - * Authors: Teemu Korhonen - * - * Copyright 2022 Teemu Korhonen - */ - -#ifndef QT_OPENGLOPTIONS_HPP -#define QT_OPENGLOPTIONS_HPP - -#include -#include -#include -#include - -class OpenGLShaderPass { -public: - OpenGLShaderPass(QOpenGLShaderProgram *shader, const QString &path) - : m_shader(shader) - , m_path(path) - , m_vertex_coord(shader->attributeLocation("VertexCoord")) - , m_tex_coord(shader->attributeLocation("TexCoord")) - , m_color(shader->attributeLocation("Color")) - , m_mvp_matrix(shader->uniformLocation("MVPMatrix")) - , m_input_size(shader->uniformLocation("InputSize")) - , m_output_size(shader->uniformLocation("OutputSize")) - , m_texture_size(shader->uniformLocation("TextureSize")) - , m_frame_count(shader->uniformLocation("FrameCount")) - { - } - - bool bind() const { return m_shader->bind(); } - const QString &path() const { return m_path; } - const GLint &vertex_coord() const { return m_vertex_coord; } - const GLint &tex_coord() const { return m_tex_coord; } - const GLint &color() const { return m_color; } - const GLint &mvp_matrix() const { return m_mvp_matrix; } - const GLint &input_size() const { return m_input_size; } - const GLint &output_size() const { return m_output_size; } - const GLint &texture_size() const { return m_texture_size; } - const GLint &frame_count() const { return m_frame_count; } - -private: - QOpenGLShaderProgram *m_shader; - QString m_path; - GLint m_vertex_coord; - GLint m_tex_coord; - GLint m_color; - GLint m_mvp_matrix; - GLint m_input_size; - GLint m_output_size; - GLint m_texture_size; - GLint m_frame_count; -}; - -class OpenGLOptions : public QObject { - Q_OBJECT - -public: - enum RenderBehaviorType { SyncWithVideo, - TargetFramerate }; - - enum FilterType { Nearest, - Linear }; - - OpenGLOptions(QObject *parent, bool loadConfig, const QString &glslVersion); - - RenderBehaviorType renderBehavior() const { return m_renderBehavior; } - int framerate() const { return m_framerate; } - bool vSync() const { return m_vsync; } - FilterType filter() const; - - const QList &shaders() const { return m_shaders; } - - void setRenderBehavior(RenderBehaviorType value); - void setFrameRate(int value); - void setVSync(bool value); - void setFilter(FilterType value); - void addShader(const QString &path); - void addDefaultShader(); - void save() const; - -private: - RenderBehaviorType m_renderBehavior = SyncWithVideo; - int m_framerate = -1; - bool m_vsync = false; - FilterType m_filter = Nearest; - QList m_shaders; - QString m_glslVersion; -}; - -#endif diff --git a/src/qt/qt_opengloptionsdialog.cpp b/src/qt/qt_opengloptionsdialog.cpp deleted file mode 100644 index acb2ce9f2..000000000 --- a/src/qt/qt_opengloptionsdialog.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * OpenGL renderer options dialog for Qt - * - * - * - * Authors: Teemu Korhonen - * - * Copyright 2022 Teemu Korhonen - */ - -#include -#include -#include - -#include - -#include "qt_opengloptionsdialog.hpp" -#include "qt_util.hpp" -#include "ui_qt_opengloptionsdialog.h" - -OpenGLOptionsDialog::OpenGLOptionsDialog(QWidget *parent, const OpenGLOptions &options, std::function optionsFactory) - : QDialog(parent) - , ui(new Ui::OpenGLOptionsDialog) - , createOptions(optionsFactory) -{ - ui->setupUi(this); - - if (options.renderBehavior() == OpenGLOptions::SyncWithVideo) - ui->syncWithVideo->setChecked(true); - else { - ui->syncToFramerate->setChecked(true); - ui->targetFps->setValue(options.framerate()); - } - - ui->vsync->setChecked(options.vSync()); - - if (!options.shaders().isEmpty()) { - auto path = options.shaders().first().path(); - if (!path.isEmpty()) - ui->shader->setPlainText(path); - } -} - -OpenGLOptionsDialog::~OpenGLOptionsDialog() -{ - delete ui; -} - -void -OpenGLOptionsDialog::accept() -{ - auto options = createOptions(); - - options->setRenderBehavior( - ui->syncWithVideo->isChecked() - ? OpenGLOptions::SyncWithVideo - : OpenGLOptions::TargetFramerate); - - options->setFrameRate(ui->targetFps->value()); - - options->setVSync(ui->vsync->isChecked()); - - auto shader = ui->shader->toPlainText(); - - try { - - if (!shader.isEmpty()) - options->addShader(shader); - else - options->addDefaultShader(); - - } catch (const std::runtime_error &e) { - delete options; - - QMessageBox msgBox(this); - msgBox.setWindowTitle(tr("Shader error")); - msgBox.setText(tr("Could not load shaders.")); - msgBox.setInformativeText(tr("More information in details.")); - msgBox.setDetailedText(e.what()); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Close); - msgBox.setDefaultButton(QMessageBox::Close); - msgBox.setStyleSheet("QTextEdit { min-width: 45em; }"); - msgBox.exec(); - - return; - } - - options->save(); - - emit optionsChanged(options); - - QDialog::accept(); -} - -void -OpenGLOptionsDialog::on_addShader_clicked() -{ - auto shader = QFileDialog::getOpenFileName( - this, - QString(), - QString(), - tr("OpenGL Shaders") % util::DlgFilter({ "glsl" }, true)); - - if (shader.isNull()) - return; - - ui->shader->setPlainText(shader); -} diff --git a/src/qt/qt_opengloptionsdialog.hpp b/src/qt/qt_opengloptionsdialog.hpp deleted file mode 100644 index f34d74d75..000000000 --- a/src/qt/qt_opengloptionsdialog.hpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Header for OpenGL renderer options dialog - * - * Authors: Teemu Korhonen - * - * Copyright 2022 Teemu Korhonen - */ - -#ifndef QT_OPENGLOPTIONSDIALOG_H -#define QT_OPENGLOPTIONSDIALOG_H - -#include - -#include - -#include "qt_opengloptions.hpp" - -namespace Ui { -class OpenGLOptionsDialog; -} - -class OpenGLOptionsDialog : public QDialog { - Q_OBJECT - -public: - explicit OpenGLOptionsDialog(QWidget *parent, const OpenGLOptions &options, std::function optionsFactory); - ~OpenGLOptionsDialog(); - -signals: - void optionsChanged(OpenGLOptions *options); - -public slots: - void accept() override; - -private: - Ui::OpenGLOptionsDialog *ui; - - std::function createOptions; - -private slots: - void on_addShader_clicked(); -}; - -#endif // QT_OPENGLOPTIONSDIALOG_H diff --git a/src/qt/qt_opengloptionsdialog.ui b/src/qt/qt_opengloptionsdialog.ui deleted file mode 100644 index a6f86b6c2..000000000 --- a/src/qt/qt_opengloptionsdialog.ui +++ /dev/null @@ -1,280 +0,0 @@ - - - OpenGLOptionsDialog - - - - 0 - 0 - 400 - 320 - - - - OpenGL 3.0 renderer options - - - - - - Render behavior - - - - - - Use target framerate: - - - - - - - false - - - fps - - - 15 - - - 240 - - - 60 - - - - - - - VSync - - - - - - - <html><head/><body><p>Render each frame immediately, in sync with the emulated display.</p><p><span style=" font-style:italic;">This is the recommended option if the shaders in use don't utilize frametime for animated effects.</span></p></body></html> - - - Synchronize with video - - - true - - - - - - - false - - - 15 - - - 240 - - - 60 - - - Qt::Horizontal - - - false - - - QSlider::NoTicks - - - - - - - - - - Shaders - - - - - - Remove - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - true - - - No shader selected - - - - - - - Browse... - - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - syncWithVideo - syncToFramerate - fpsSlider - targetFps - vsync - shader - addShader - removeShader - - - - - buttonBox - accepted() - OpenGLOptionsDialog - accept() - - - 257 - 310 - - - 157 - 274 - - - - - buttonBox - rejected() - OpenGLOptionsDialog - reject() - - - 325 - 310 - - - 286 - 274 - - - - - syncToFramerate - toggled(bool) - targetFps - setEnabled(bool) - - - 140 - 71 - - - 380 - 98 - - - - - syncToFramerate - toggled(bool) - fpsSlider - setEnabled(bool) - - - 158 - 66 - - - 168 - 87 - - - - - fpsSlider - valueChanged(int) - targetFps - setValue(int) - - - 252 - 90 - - - 308 - 89 - - - - - targetFps - valueChanged(int) - fpsSlider - setValue(int) - - - 364 - 93 - - - 134 - 93 - - - - - removeShader - clicked() - shader - clear() - - - 333 - 201 - - - 235 - 208 - - - - - diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp index 60aa998a9..97a782f57 100644 --- a/src/qt/qt_openglrenderer.cpp +++ b/src/qt/qt_openglrenderer.cpp @@ -6,52 +6,786 @@ * * This file is part of the 86Box distribution. * - * OpenGL renderer for Qt + * OpenGL renderer for Qt, mostly ported over from PCem. * * * * Authors: Teemu Korhonen + * Cacodemon345 + * bit + * Sarah Walker * * Copyright 2022 Teemu Korhonen + * Copyright 2025 Cacodemon345 + * Copyright 2017 Bit + * Copyright 2017-2020 Sarah Walker */ +#include "qt_renderercommon.hpp" +#include "qt_mainwindow.hpp" + +extern MainWindow* main_window; + #include #include -#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include #include -#include -#include +#include + +#include #include -#include "qt_opengloptionsdialog.hpp" #include "qt_openglrenderer.hpp" +#include "qt_openglshadermanagerdialog.hpp" -#ifndef GL_MAP_PERSISTENT_BIT -# define GL_MAP_PERSISTENT_BIT 0x0040 -#endif +extern "C" { +#include <86box/86box.h> +#include <86box/plat.h> +#include <86box/ui.h> +#include <86box/video.h> +#include <86box/path.h> +#include <86box/ini.h> +#include <86box/config.h> +#include <86box/qt-glslp-parser.h> -#ifndef GL_MAP_COHERENT_BIT -# define GL_MAP_COHERENT_BIT 0x0080 +char gl3_shader_file[MAX_USER_SHADERS][512]; +extern bool cpu_thread_running; +} + +#define SCALE_SOURCE 0 +#define SCALE_VIEWPORT 1 +#define SCALE_ABSOLUTE 2 + +static GLfloat matrix[] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; + +extern int video_filter_method; +extern int video_vsync; +extern int video_focus_dim; +extern int video_refresh_rate; + +const char *vertex_shader_default_tex_src = "#version 130\n" + "\n" + "in vec4 VertexCoord;\n" + "in vec2 TexCoord;\n" + "\n" + "out vec2 texCoord;\n" + "\n" + "void main()\n" + "{\n" + " gl_Position = VertexCoord;\n" + " texCoord = TexCoord;\n" + "}\n"; + +const char *fragment_shader_default_tex_src = "#version 130\n" + "\n" + "in vec2 texCoord;\n" + "uniform sampler2D Texture;\n" + "\n" + "out vec4 color;" + "\n" + "void main()\n" + "{\n" + " color = texture(Texture, texCoord);\n" + "}\n"; + +const char *vertex_shader_default_color_src = "#version 130\n" + "\n" + "in vec4 VertexCoord;\n" + "in vec4 Color;\n" + "\n" + "out vec4 color;\n" + "\n" + "void main()\n" + "{\n" + " gl_Position = VertexCoord;\n" + " color = Color;\n" + "}\n"; + +const char *fragment_shader_default_color_src = "#version 130\n" + "\n" + "in vec4 color;\n" + "\n" + "out vec4 outColor;" + "\n" + "void main()\n" + "{\n" + " outColor = color;\n" + "}\n"; + +static inline int +next_pow2(unsigned int n) +{ + n--; + n |= n >> 1; // Divide by 2^k for consecutive doublings of k up to 32, + n |= n >> 2; // and then or the results. + n |= n >> 4; + n |= n >> 8; + n |= n >> 16; + n++; + + return n; +} + +int +OpenGLRenderer::create_program(struct shader_program *program) +{ + GLint status; + program->id = glw.glCreateProgram(); + glw.glAttachShader(program->id, program->vertex_shader); + glw.glAttachShader(program->id, program->fragment_shader); + + glw.glLinkProgram(program->id); + + glw.glDeleteShader(program->vertex_shader); + glw.glDeleteShader(program->fragment_shader); + + program->vertex_shader = program->fragment_shader = 0; + + glw.glGetProgramiv(program->id, GL_LINK_STATUS, &status); + + if (!status) { + int maxLength; + int length; + glw.glGetProgramiv(program->id, GL_INFO_LOG_LENGTH, &maxLength); + char *log = (char *) malloc(maxLength); + glw.glGetProgramInfoLog(program->id, maxLength, &length, log); + main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("GLSL Error"), tr("Program not linked:\n\n%1").arg(log).replace("\n", "
")); + // wx_simple_messagebox("GLSL Error", "Program not linked:\n%s", log); + free(log); + return 0; + } + + return 1; +} + +int +OpenGLRenderer::compile_shader(GLenum shader_type, const char *prepend, const char *program, int *dst) +{ + const char *source[3]; + char version[50]; + int ver = 0; + char *version_loc = strstr(program, "#version"); + if (version_loc) + ver = (int) strtol(version_loc + 8, (char **) &program, 10); + else { + ver = glsl_version[0] * 100 + glsl_version[1] * 10; + if (ver == 300) + ver = 130; + else if (ver == 310) + ver = 140; + else if (ver == 320) + ver = 150; + } + sprintf(version, "#version %d\n", ver); + source[0] = version; + source[1] = prepend ? prepend : ""; + source[2] = program; + + pclog("GLSL version %d\n", ver); + + GLuint shader = glw.glCreateShader(shader_type); + glw.glShaderSource(shader, 3, source, NULL); + glw.glCompileShader(shader); + + GLint status = 0; + glw.glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + if (!status) { + GLint length; + glw.glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); + char *log = (char *) malloc(length); + glw.glGetShaderInfoLog(shader, length, &length, log); + main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("GLSL Error"), tr("Could not compile shader:\n\n%1").arg(log).replace("\n", "
")); + // wx_simple_messagebox("GLSL Error", "Could not compile shader:\n%s", log); + + pclog("Could not compile shader: %s\n", log); + // pclog("Shader: %s\n", program); + + free(log); + return 0; + } + + *dst = shader; + + return 1; +} + +GLuint +OpenGLRenderer::get_uniform(GLuint program, const char *name) +{ + return glw.glGetUniformLocation(program, name); +} + +GLuint +OpenGLRenderer::get_attrib(GLuint program, const char *name) +{ + return glw.glGetAttribLocation(program, name); +} + +void +OpenGLRenderer::find_uniforms(struct glsl_shader *glsl, int num_pass) +{ + int i; + char s[50]; + struct shader_pass *pass = &glsl->passes[num_pass]; + int p = pass->program.id; + glw.glUseProgram(p); + + struct shader_uniforms *u = &pass->uniforms; + + u->mvp_matrix = get_uniform(p, "MVPMatrix"); + u->vertex_coord = get_attrib(p, "VertexCoord"); + u->tex_coord = get_attrib(p, "TexCoord"); + u->color = get_attrib(p, "Color"); + + u->frame_count = get_uniform(p, "FrameCount"); + u->frame_direction = get_uniform(p, "FrameDirection"); + + u->texture = get_uniform(p, "Texture"); + u->input_size = get_uniform(p, "InputSize"); + u->texture_size = get_uniform(p, "TextureSize"); + u->output_size = get_uniform(p, "OutputSize"); + + u->orig.texture = get_uniform(p, "OrigTexture"); + u->orig.input_size = get_uniform(p, "OrigInputSize"); + u->orig.texture_size = get_uniform(p, "OrigTextureSize"); + + for (i = 0; i < glsl->num_passes; ++i) { + sprintf(s, "Pass%dTexture", (i + 1)); + u->pass[i].texture = get_uniform(p, s); + sprintf(s, "Pass%dInputSize", (i + 1)); + u->pass[i].input_size = get_uniform(p, s); + sprintf(s, "Pass%dTextureSize", (i + 1)); + u->pass[i].texture_size = get_uniform(p, s); + + sprintf(s, "PassPrev%dTexture", num_pass - i); + u->prev_pass[i].texture = get_uniform(p, s); + sprintf(s, "PassPrev%dInputSize", num_pass - i); + u->prev_pass[i].input_size = get_uniform(p, s); + sprintf(s, "PassPrev%dTextureSize", num_pass - i); + u->prev_pass[i].texture_size = get_uniform(p, s); + } + + u->prev[0].texture = get_uniform(p, "PrevTexture"); + u->prev[0].tex_coord = get_attrib(p, "PrevTexCoord"); + for (i = 1; i < MAX_PREV; ++i) { + sprintf(s, "Prev%dTexture", i); + u->prev[i].texture = get_uniform(p, s); + sprintf(s, "Prev%dTexCoord", i); + u->prev[i].tex_coord = get_attrib(p, s); + } + for (i = 0; i < MAX_PREV; ++i) + if (u->prev[i].texture >= 0) + glsl->has_prev = 1; + + for (i = 0; i < glsl->num_lut_textures; ++i) + u->lut_textures[i] = get_uniform(p, glsl->lut_textures[i].name); + + for (i = 0; i < glsl->num_parameters; ++i) + u->parameters[i] = get_uniform(p, glsl->parameters[i].id); + + glw.glUseProgram(0); +} + +static void +set_scale_mode(char *scale, int *dst) +{ + if (!strcmp(scale, "viewport")) + *dst = SCALE_VIEWPORT; + else if (!strcmp(scale, "absolute")) + *dst = SCALE_ABSOLUTE; + else + *dst = SCALE_SOURCE; +} + +static void +setup_scale(struct shader *shader, struct shader_pass *pass) +{ + set_scale_mode(shader->scale_type_x, &pass->scale.mode[0]); + set_scale_mode(shader->scale_type_y, &pass->scale.mode[1]); + pass->scale.value[0] = shader->scale_x; + pass->scale.value[1] = shader->scale_y; +} + +void +OpenGLRenderer::create_texture(struct shader_texture *tex) +{ + if (tex->width > max_texture_size) + tex->width = max_texture_size; + if (tex->height > max_texture_size) + tex->height = max_texture_size; + pclog("Create texture with size %dx%d\n", tex->width, tex->height); + glw.glGenTextures(1, (GLuint *) &tex->id); + glw.glBindTexture(GL_TEXTURE_2D, tex->id); + glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, tex->wrap_mode); + glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, tex->wrap_mode); + glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, tex->min_filter); + glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, tex->mag_filter); + glw.glTexImage2D(GL_TEXTURE_2D, 0, tex->internal_format, tex->width, tex->height, 0, tex->format, tex->type, tex->data); + if (tex->mipmap) + glw.glGenerateMipmap(GL_TEXTURE_2D); + glw.glBindTexture(GL_TEXTURE_2D, 0); +} + +void +OpenGLRenderer::delete_texture(struct shader_texture *tex) +{ + if (tex->id > 0) + glw.glDeleteTextures(1, (GLuint *) &tex->id); + tex->id = 0; +} + +void +OpenGLRenderer::delete_fbo(struct shader_fbo *fbo) +{ + if (fbo->id >= 0) { + glw.glDeleteFramebuffers(1, (GLuint *) &fbo->id); + delete_texture(&fbo->texture); + } +} + +void +OpenGLRenderer::delete_program(struct shader_program *program) +{ + if (program->vertex_shader) + glw.glDeleteShader(program->vertex_shader); + if (program->fragment_shader) + glw.glDeleteShader(program->fragment_shader); + glw.glDeleteProgram(program->id); +} + +void +OpenGLRenderer::delete_vbo(struct shader_vbo *vbo) +{ + if (vbo->color >= 0) + glw.glDeleteBuffers(1, (GLuint *) &vbo->color); + glw.glDeleteBuffers(1, (GLuint *) &vbo->vertex_coord); + glw.glDeleteBuffers(1, (GLuint *) &vbo->tex_coord); +} + +void +OpenGLRenderer::delete_pass(struct shader_pass *pass) +{ + delete_fbo(&pass->fbo); + delete_vbo(&pass->vbo); + delete_program(&pass->program); + glw.glDeleteVertexArrays(1, (GLuint *) &pass->vertex_array); +} + +void +OpenGLRenderer::delete_prev(struct shader_prev *prev) +{ + delete_fbo(&prev->fbo); + delete_vbo(&prev->vbo); +} + +void +OpenGLRenderer::delete_shader(struct glsl_shader *glsl) +{ + int i; + for (i = 0; i < glsl->num_passes; ++i) + delete_pass(&glsl->passes[i]); + if (glsl->has_prev) { + delete_pass(&glsl->prev_scene); + for (i = 0; i < MAX_PREV; ++i) + delete_prev(&glsl->prev[i]); + } + for (i = 0; i < glsl->num_lut_textures; ++i) + delete_texture(&glsl->lut_textures[i].texture); +} + +void +OpenGLRenderer::delete_glsl(glsl_t *glsl) +{ + int i; + for (i = 0; i < glsl->num_shaders; ++i) + delete_shader(&glsl->shaders[i]); + delete_pass(&glsl->scene); + delete_pass(&glsl->fs_color); + delete_pass(&glsl->final_pass); +#ifdef SDL2_SHADER_DEBUG + delete_pass(&glsl->debug); #endif +} + +void +OpenGLRenderer::create_fbo(struct shader_fbo *fbo) +{ + create_texture(&fbo->texture); + + glw.glGenFramebuffers(1, (GLuint *) &fbo->id); + glw.glBindFramebuffer(GL_FRAMEBUFFER, fbo->id); + glw.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo->texture.id, 0); + + if (glw.glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + pclog("Could not create framebuffer!\n"); + + glw.glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + +void +OpenGLRenderer::setup_fbo(struct shader *shader, struct shader_fbo *fbo) +{ + fbo->texture.internal_format = GL_RGBA8; + fbo->texture.format = GL_RGBA; + fbo->texture.min_filter = fbo->texture.mag_filter = shader->filter_linear ? GL_LINEAR : GL_NEAREST; + fbo->texture.width = 2048; + fbo->texture.height = 2048; + fbo->texture.type = GL_UNSIGNED_BYTE; + if (!strcmp(shader->wrap_mode, "repeat")) + fbo->texture.wrap_mode = GL_REPEAT; + else if (!strcmp(shader->wrap_mode, "mirrored_repeat")) + fbo->texture.wrap_mode = GL_MIRRORED_REPEAT; + else if (!strcmp(shader->wrap_mode, "clamp_to_edge")) + fbo->texture.wrap_mode = GL_CLAMP_TO_EDGE; + else + fbo->texture.wrap_mode = GL_CLAMP_TO_BORDER; + fbo->srgb = 0; + if (shader->srgb_framebuffer) { + fbo->texture.internal_format = GL_SRGB8_ALPHA8; + fbo->srgb = 1; + } else if (shader->float_framebuffer) { + fbo->texture.internal_format = GL_RGBA32F; + fbo->texture.type = GL_FLOAT; + } + + if (fbo->texture.mipmap) + fbo->texture.min_filter = shader->filter_linear ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST; + + create_fbo(fbo); +} + +void +OpenGLRenderer::recreate_fbo(struct shader_fbo *fbo, int width, int height) +{ + if (width != fbo->texture.width || height != fbo->texture.height) { + glw.glDeleteFramebuffers(1, (GLuint *) &fbo->id); + glw.glDeleteTextures(1, (GLuint *) &fbo->texture.id); + fbo->texture.width = width; + fbo->texture.height = height; + create_fbo(fbo); + } +} + +int +OpenGLRenderer::create_default_shader_tex(struct shader_pass *pass) +{ + if (!compile_shader(GL_VERTEX_SHADER, 0, vertex_shader_default_tex_src, &pass->program.vertex_shader) || !compile_shader(GL_FRAGMENT_SHADER, 0, fragment_shader_default_tex_src, &pass->program.fragment_shader) || !create_program(&pass->program)) + return 0; + glw.glGenVertexArrays(1, (GLuint *) &pass->vertex_array); + + struct shader_uniforms *u = &pass->uniforms; + int p = pass->program.id; + memset(u, -1, sizeof(struct shader_uniforms)); + u->vertex_coord = get_attrib(p, "VertexCoord"); + u->tex_coord = get_attrib(p, "TexCoord"); + u->texture = get_uniform(p, "Texture"); + pass->scale.mode[0] = pass->scale.mode[1] = SCALE_SOURCE; + pass->scale.value[0] = pass->scale.value[1] = 1.0f; + pass->fbo.id = -1; + pass->active = 1; + return 1; +} + +int +OpenGLRenderer::create_default_shader_color(struct shader_pass *pass) +{ + if (!compile_shader(GL_VERTEX_SHADER, 0, vertex_shader_default_color_src, &pass->program.vertex_shader) || !compile_shader(GL_FRAGMENT_SHADER, 0, fragment_shader_default_color_src, &pass->program.fragment_shader) || !create_program(&pass->program)) + return 0; + glw.glGenVertexArrays(1, (GLuint *) &pass->vertex_array); + + struct shader_uniforms *u = &pass->uniforms; + int p = pass->program.id; + memset(u, -1, sizeof(struct shader_uniforms)); + u->vertex_coord = get_attrib(p, "VertexCoord"); + u->color = get_attrib(p, "Color"); + pass->scale.mode[0] = pass->scale.mode[1] = SCALE_SOURCE; + pass->scale.value[0] = pass->scale.value[1] = 1.0f; + pass->fbo.id = -1; + pass->active = 1; + return 1; +} + +/* create the default scene shader */ +void +OpenGLRenderer::create_scene_shader() +{ + struct shader scene_shader_conf; + memset(&scene_shader_conf, 0, sizeof(struct shader)); + create_default_shader_tex(&active_shader->scene); + scene_shader_conf.filter_linear = video_filter_method; + if (active_shader->num_shaders > 0 && active_shader->shaders[0].input_filter_linear >= 0) + scene_shader_conf.filter_linear = active_shader->shaders[0].input_filter_linear; + setup_fbo(&scene_shader_conf, &active_shader->scene.fbo); + + memset(&scene_shader_conf, 0, sizeof(struct shader)); + create_default_shader_color(&active_shader->fs_color); + setup_fbo(&scene_shader_conf, &active_shader->fs_color.fbo); +} + +static int +load_texture(const char *f, struct shader_texture *tex) +{ + QImage img; + if (!img.load(f)) + return 0; + int width, height; + width = img.size().width(); + height = img.size().height(); + + if (width != next_pow2(width) || height != next_pow2(height)) + img = img.scaled(next_pow2(width), next_pow2(height)); + + width = img.size().width(); + height = img.size().height(); + + img.convertTo(QImage::Format_RGBA8888); + + const GLubyte *rgb = img.constBits(); + + int bpp = 4; + + GLubyte *data = (GLubyte *) malloc(width * height * bpp); + + int x, y, Y; + for (y = 0; y < height; ++y) { + Y = height - y - 1; + for (x = 0; x < width; x++) { + data[(y * width + x) * bpp + 0] = rgb[(Y * width + x) * 3 + 0]; + data[(y * width + x) * bpp + 1] = rgb[(Y * width + x) * 3 + 1]; + data[(y * width + x) * bpp + 2] = rgb[(Y * width + x) * 3 + 2]; + data[(y * width + x) * bpp + 3] = rgb[(Y * width + x) * 3 + 3]; + } + } + + tex->width = width; + tex->height = height; + tex->internal_format = GL_RGBA8; + tex->format = GL_RGBA; + tex->type = GL_UNSIGNED_BYTE; + tex->data = data; + return 1; +} + +glsl_t * +OpenGLRenderer::load_glslp(glsl_t *glsl, int num_shader, const char *f) +{ + int i, j; + glslp_t *p = glslp_parse(f); + + if (p) { + char path[512]; + char file[1024]; + int failed = 0; + strcpy(path, f); + char *filename = path_get_filename(path); + + struct glsl_shader *gshader = &glsl->shaders[num_shader]; + + strcpy(gshader->name, p->name); + *filename = 0; + + gshader->num_lut_textures = p->num_textures; + + for (i = 0; i < p->num_textures; ++i) { + struct texture *texture = &p->textures[i]; + + sprintf(file, "%s%s", path, texture->path); + + struct shader_lut_texture *tex = &gshader->lut_textures[i]; + strcpy(tex->name, texture->name); + + pclog("Load texture %s...\n", file); + + if (!load_texture(file, &tex->texture)) { + //QMessageBox::critical(main_window, tr("GLSL Error"), tr("Could not load texture: %s").arg(file)); + main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("GLSL Error"), tr("Could not load texture: %s").arg(file)); + pclog("Could not load texture %s!\n", file); + failed = 1; + break; + } + + if (!strcmp(texture->wrap_mode, "repeat")) + tex->texture.wrap_mode = GL_REPEAT; + else if (!strcmp(texture->wrap_mode, "mirrored_repeat")) + tex->texture.wrap_mode = GL_MIRRORED_REPEAT; + else if (!strcmp(texture->wrap_mode, "clamp_to_edge")) + tex->texture.wrap_mode = GL_CLAMP_TO_EDGE; + else + tex->texture.wrap_mode = GL_CLAMP_TO_BORDER; + + tex->texture.mipmap = texture->mipmap; + + tex->texture.min_filter = tex->texture.mag_filter = texture->linear ? GL_LINEAR : GL_NEAREST; + if (tex->texture.mipmap) + tex->texture.min_filter = texture->linear ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST; + + create_texture(&tex->texture); + free(tex->texture.data); + tex->texture.data = 0; + } + + if (!failed) { + gshader->input_filter_linear = p->input_filter_linear; + + gshader->num_parameters = p->num_parameters; + for (j = 0; j < gshader->num_parameters; ++j) + memcpy(&gshader->parameters[j], &p->parameters[j], sizeof(struct shader_parameter)); + + gshader->num_passes = p->num_shaders; + + for (i = 0; i < p->num_shaders; ++i) { + struct shader *shader = &p->shaders[i]; + struct shader_pass *pass = &gshader->passes[i]; + + strcpy(pass->alias, shader->alias); + if (!strlen(pass->alias)) + sprintf(pass->alias, "Pass %u", (i + 1)); + + pclog("Creating pass %u (%s)\n", (i + 1), pass->alias); + pclog("Loading shader %s...\n", shader->shader_fn); + if (!shader->shader_program) { + main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("GLSL Error"), tr("Could not load shader: %1").arg(shader->shader_fn)); + // wx_simple_messagebox("GLSL Error", "Could not load shader: %s", shader->shader_fn); + pclog("Could not load shader %s\n", shader->shader_fn); + failed = 1; + break; + } else + pclog("Shader %s loaded\n", shader->shader_fn); + failed = !compile_shader(GL_VERTEX_SHADER, "#define VERTEX\n#define PARAMETER_UNIFORM\n", + shader->shader_program, &pass->program.vertex_shader) + || !compile_shader(GL_FRAGMENT_SHADER, "#define FRAGMENT\n#define PARAMETER_UNIFORM\n", + shader->shader_program, &pass->program.fragment_shader); + if (failed) + break; + + if (!create_program(&pass->program)) { + failed = 1; + break; + } + pass->frame_count_mod = shader->frame_count_mod; + pass->fbo.mipmap_input = shader->mipmap_input; + + glw.glGenVertexArrays(1, (GLuint *) &pass->vertex_array); + find_uniforms(gshader, i); + setup_scale(shader, pass); + if (i == p->num_shaders - 1) /* last pass may or may not be an fbo depending on scale */ + { + if (num_shader == glsl->num_shaders - 1) { + pass->fbo.id = -1; + + for (j = 0; j < 2; ++j) { + if (pass->scale.mode[j] != SCALE_SOURCE || pass->scale.value[j] != 1) { + setup_fbo(shader, &pass->fbo); + break; + } + } + } else { + /* check if next shaders' first pass wants the input mipmapped (will this ever + * happen?) */ + pass->fbo.texture.mipmap = glsl->shaders[num_shader + 1].num_passes > 0 && glsl->shaders[num_shader + 1].passes[0].fbo.mipmap_input; + /* check if next shader wants the output of this pass to be filtered */ + if (glsl->shaders[num_shader + 1].num_passes > 0 && glsl->shaders[num_shader + 1].input_filter_linear >= 0) + shader->filter_linear = glsl->shaders[num_shader + 1].input_filter_linear; + setup_fbo(shader, &pass->fbo); + } + } else { + /* check if next pass wants the input mipmapped, if so we need to generate mipmaps of this + * pass */ + pass->fbo.texture.mipmap = (i + 1) < p->num_shaders && p->shaders[i + 1].mipmap_input; + setup_fbo(shader, &pass->fbo); + } + if (pass->fbo.srgb) + glsl->srgb = 1; + pass->active = 1; + } + if (!failed) { + if (gshader->has_prev) { + struct shader scene_shader_conf; + memset(&scene_shader_conf, 0, sizeof(struct shader)); + for (i = 0; i < MAX_PREV; ++i) { + setup_fbo(&scene_shader_conf, &gshader->prev[i].fbo); + } + } + } + } + + glslp_free(p); + + return glsl; + } + return 0; +} + +glsl_t * +OpenGLRenderer::load_shaders(int num, char shaders[MAX_USER_SHADERS][512]) +{ + int i; + glsl_t *glsl; + + glsl = (glsl_t *) malloc(sizeof(glsl_t)); + memset(glsl, 0, sizeof(glsl_t)); + + glsl->num_shaders = num; + int failed = 0; + for (i = num - 1; i >= 0; --i) { + const char *f = shaders[i]; + if (f && strlen(f)) { + if (!load_glslp(glsl, i, f)) { + failed = 1; + break; + } + } + } + if (failed) { + delete_glsl(glsl); + memset(glsl, 0, sizeof(glsl_t)); + } + return glsl; +} + +void +OpenGLRenderer::read_shader_config() +{ + char s[512]; + int i, j; + for (i = 0; i < active_shader->num_shaders; ++i) { + struct glsl_shader *shader = &active_shader->shaders[i]; + char *name = shader->name; + sprintf(s, "GL3 Shaders - %s", name); + // shader->shader_refresh_rate = config_get_float(CFG_MACHINE, s, "shader_refresh_rate", -1); + for (j = 0; j < shader->num_parameters; ++j) { + struct shader_parameter *param = &shader->parameters[j]; + param->value = config_get_double(s, param->id, param->default_value); + } + } +} OpenGLRenderer::OpenGLRenderer(QWidget *parent) : QWindow(parent->windowHandle()) , renderTimer(new QTimer(this)) - , options(nullptr) { - renderTimer->setTimerType(Qt::PreciseTimer); - /* TODO: need's more accuracy, maybe target 1ms earlier and spin yield */ - connect(renderTimer, &QTimer::timeout, this, &OpenGLRenderer::render); + connect(renderTimer, &QTimer::timeout, this, [this]() { this->render(); } ); + imagebufs[0] = std::unique_ptr(new uint8_t[2048 * 2048 * 4]); + imagebufs[1] = std::unique_ptr(new uint8_t[2048 * 2048 * 4]); - buf_usage = std::vector(BUFFERCOUNT); - for (auto &flag : buf_usage) - flag.clear(); - - setSurfaceType(QWindow::OpenGLSurface); + buf_usage = std::vector(2); + buf_usage[0].clear(); + buf_usage[1].clear(); QSurfaceFormat format; + setSurfaceType(QWindow::OpenGLSurface); + #ifdef Q_OS_MACOS format.setVersion(4, 1); #else @@ -62,16 +796,352 @@ OpenGLRenderer::OpenGLRenderer(QWidget *parent) if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) format.setRenderableType(QSurfaceFormat::OpenGLES); + format.setSwapInterval(video_vsync ? 1 : 0); + setFormat(format); parentWidget = parent; - source.setRect(0, 0, INIT_WIDTH, INIT_HEIGHT); + source.setRect(0, 0, 100, 100); + isInitialized = false; + isFinalized = false; } -OpenGLRenderer::~OpenGLRenderer() +OpenGLRenderer::~OpenGLRenderer() { finalize(); } + +void +OpenGLRenderer::initialize() { - finalize(); + try { + context = new QOpenGLContext(this); + + context->setFormat(format()); + + if (!context->create()) + throw opengl_init_error(tr("Couldn't create OpenGL context.")); + + if (!context->makeCurrent(this)) + throw opengl_init_error(tr("Couldn't switch to OpenGL context.")); + + auto version = context->format().version(); + + if (version.first < 3) + throw opengl_init_error(tr("OpenGL version 3.0 or greater is required. Current version is %1.%2").arg(version.first).arg(version.second)); + + glw.initializeOpenGLFunctions(); + + pclog("OpenGL information: [%s] %s (%s)\n", glw.glGetString(GL_VENDOR), glw.glGetString(GL_RENDERER), glw.glGetString(GL_VERSION)); + glsl_version[0] = glsl_version[1] = -1; + glw.glGetIntegerv(GL_MAJOR_VERSION, &glsl_version[0]); + glw.glGetIntegerv(GL_MINOR_VERSION, &glsl_version[1]); + if (glsl_version[0] < 3) { + throw opengl_init_error(tr("OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2").arg(glsl_version[0]).arg(glsl_version[1])); + } + pclog("Using OpenGL %s\n", glw.glGetString(GL_VERSION)); + pclog("Using Shading Language %s\n", glw.glGetString(GL_SHADING_LANGUAGE_VERSION)); + + glw.glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size); + pclog("Max texture size: %dx%d\n", max_texture_size, max_texture_size); + + glw.glEnable(GL_TEXTURE_2D); + + //renderTimer->start(75); + if (video_framerate != -1) { + renderTimer->start(ceilf(1000.f / (float)video_framerate)); + } + + scene_texture.data = NULL; + scene_texture.width = 2048; + scene_texture.height = 2048; + scene_texture.internal_format = GL_RGBA8; + scene_texture.format = GL_BGRA; + scene_texture.type = GL_UNSIGNED_INT_8_8_8_8_REV; + scene_texture.wrap_mode = GL_CLAMP_TO_BORDER; + scene_texture.min_filter = scene_texture.mag_filter = video_filter_method ? GL_LINEAR : GL_NEAREST; + scene_texture.mipmap = 0; + + create_texture(&scene_texture); + + /* load shader */ + // const char* shaders[1]; + // shaders[0] = gl3_shader_file; + // + // active_shader = load_shaders(1, shaders); + + // const char* shaders[3]; + // shaders[0] = "/home/phantasy/git/glsl-shaders/ntsc/ntsc-320px.glslp"; + // shaders[1] = "/home/phantasy/git/glsl-shaders/motionblur/motionblur-simple.glslp"; + // shaders[2] = "/home/phantasy/git/glsl-shaders/crt/crt-lottes-multipass.glslp"; + // + // active_shader = load_shaders(3, shaders); + int num_shaders = 0; + for (int i = 0; i < MAX_USER_SHADERS; ++i) { + if (strlen(gl3_shader_file[i])) + ++num_shaders; + else + break; + } + active_shader = load_shaders(num_shaders, gl3_shader_file); + + create_scene_shader(); + + /* read config */ + read_shader_config(); + + /* buffers */ + + GLfloat vertex[] = { -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f }; + + GLfloat inv_vertex[] = { -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f }; + + GLfloat tex_coords[] = { 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f }; + + GLfloat colors[] = { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; + + /* set the scene shader buffers */ + { + glw.glBindVertexArray(active_shader->scene.vertex_array); + + struct shader_vbo *vbo = &active_shader->scene.vbo; + + glw.glGenBuffers(1, (GLuint *) &vbo->vertex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->vertex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(inv_vertex), inv_vertex, GL_STATIC_DRAW); + glw.glVertexAttribPointer(active_shader->scene.uniforms.vertex_coord, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), + (GLvoid *) 0); + + glw.glGenBuffers(1, (GLuint *) &vbo->tex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->tex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(tex_coords), tex_coords, GL_DYNAMIC_DRAW); + glw.glVertexAttribPointer(active_shader->scene.uniforms.tex_coord, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(GLfloat), + (GLvoid *) 0); + } + + /* set buffers for all passes */ + for (int j = 0; j < active_shader->num_shaders; ++j) { + struct glsl_shader *shader = &active_shader->shaders[j]; + for (int i = 0; i < shader->num_passes; ++i) { + struct shader_uniforms *u = &shader->passes[i].uniforms; + + glw.glBindVertexArray(shader->passes[i].vertex_array); + + struct shader_vbo *vbo = &shader->passes[i].vbo; + + glw.glGenBuffers(1, (GLuint *) &vbo->vertex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->vertex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), vertex, GL_STATIC_DRAW); + + glw.glVertexAttribPointer(u->vertex_coord, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), (GLvoid *) 0); + + glw.glGenBuffers(1, (GLuint *) &vbo->tex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->tex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(tex_coords), tex_coords, GL_DYNAMIC_DRAW); + glw.glVertexAttribPointer(u->tex_coord, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(GLfloat), (GLvoid *) 0); + + if (u->color) { + glw.glGenBuffers(1, (GLuint *) &vbo->color); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->color); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW); + glw.glVertexAttribPointer(u->color, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (GLvoid *) 0); + } + } + } + + for (int i = 0; i < active_shader->num_shaders; ++i) { + struct glsl_shader *shader = &active_shader->shaders[i]; + if (shader->has_prev) { + struct shader_pass *prev_pass = &shader->prev_scene; + create_default_shader_tex(prev_pass); + + struct shader_vbo *vbo = &prev_pass->vbo; + + glw.glBindVertexArray(prev_pass->vertex_array); + + glw.glGenBuffers(1, (GLuint *) &vbo->vertex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->vertex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), vertex, GL_STATIC_DRAW); + glw.glVertexAttribPointer(prev_pass->uniforms.vertex_coord, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), + (GLvoid *) 0); + + glw.glGenBuffers(1, (GLuint *) &vbo->tex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->tex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(tex_coords), tex_coords, GL_DYNAMIC_DRAW); + glw.glVertexAttribPointer(prev_pass->uniforms.tex_coord, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(GLfloat), + (GLvoid *) 0); + + for (int j = 0; j < MAX_PREV; ++j) { + struct shader_prev *prev = &shader->prev[j]; + struct shader_vbo *prev_vbo = &prev->vbo; + + glw.glGenBuffers(1, (GLuint *) &prev_vbo->vertex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, prev_vbo->vertex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), vertex, GL_STATIC_DRAW); + + glw.glGenBuffers(1, (GLuint *) &prev_vbo->tex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, prev_vbo->tex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(tex_coords), tex_coords, GL_DYNAMIC_DRAW); + } + } + } + + /* create final pass */ + if (active_shader->num_shaders == 0 || active_shader->shaders[active_shader->num_shaders - 1].passes[active_shader->shaders[active_shader->num_shaders - 1].num_passes - 1].fbo.id >= 0) { + struct shader_pass *final_pass = &active_shader->final_pass; + create_default_shader_tex(final_pass); + + glw.glBindVertexArray(final_pass->vertex_array); + + struct shader_vbo *vbo = &final_pass->vbo; + + glw.glGenBuffers(1, (GLuint *) &vbo->vertex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->vertex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), vertex, GL_STATIC_DRAW); + glw.glVertexAttribPointer(final_pass->uniforms.vertex_coord, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), + (GLvoid *) 0); + + glw.glGenBuffers(1, (GLuint *) &vbo->tex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->tex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(tex_coords), tex_coords, GL_DYNAMIC_DRAW); + glw.glVertexAttribPointer(final_pass->uniforms.tex_coord, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(GLfloat), + (GLvoid *) 0); + } + + { + struct shader_pass *color_pass = &active_shader->fs_color; + create_default_shader_color(color_pass); + + glw.glBindVertexArray(color_pass->vertex_array); + + struct shader_vbo *vbo = &color_pass->vbo; + + glw.glGenBuffers(1, (GLuint *) &vbo->vertex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->vertex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), vertex, GL_STATIC_DRAW); + glw.glVertexAttribPointer(color_pass->uniforms.vertex_coord, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), + (GLvoid *) 0); + + glw.glGenBuffers(1, (GLuint *) &vbo->color); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->color); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_DYNAMIC_DRAW); + glw.glVertexAttribPointer(color_pass->uniforms.color, 4, GL_FLOAT, GL_TRUE, 4 * sizeof(GLfloat), (GLvoid *) 0); + } +#ifdef SDL2_SHADER_DEBUG + struct shader_pass *debug_pass = &active_shader->debug; + create_default_shader(debug_pass); + + glw.glBindVertexArray(debug_pass->vertex_array); + + struct shader_vbo *vbo = &debug_pass->vbo; + + glw.glGenBuffers(1, &vbo->vertex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->vertex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), vertex, GL_STATIC_DRAW); + glw.glVertexAttribPointer(debug_pass->uniforms.vertex_coord, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), (GLvoid *) 0); + + glw.glGenBuffers(1, &vbo->tex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->tex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(tex_coords), tex_coords, GL_DYNAMIC_DRAW); + glw.glVertexAttribPointer(debug_pass->uniforms.tex_coord, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(GLfloat), (GLvoid *) 0); +#endif + + glw.glBindBuffer(GL_ARRAY_BUFFER, 0); + glw.glBindVertexArray(0); + + isInitialized = true; + isFinalized = false; + + emit initialized(); + + glw.glClearColor(0, 0, 0, 1); + + glw.glClear(GL_COLOR_BUFFER_BIT); + + context->swapBuffers(this); + } catch (const opengl_init_error &e) { + /* Mark all buffers as in use */ + for (auto &flag : buf_usage) + flag.test_and_set(); + + main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("Error initializing OpenGL"), e.what() + tr("\nFalling back to software rendering.")); + + context->doneCurrent(); + isFinalized = true; + isInitialized = true; + + emit errorInitializing(); + } +} + +void +OpenGLRenderer::finalize() +{ + if (isFinalized) + return; + + context->makeCurrent(this); + + delete_texture(&scene_texture); + + if (active_shader) { + delete_glsl(active_shader); + free(active_shader); + } + active_shader = NULL; + + context->doneCurrent(); + + context = nullptr; + + isFinalized = true; +} + +void +OpenGLRenderer::onBlit(int buf_idx, int x, int y, int w, int h) +{ + if (notReady()) + return; + + context->makeCurrent(this); + +#ifdef Q_OS_MACOS + glViewport( + destination.x() * devicePixelRatio(), + destination.y() * devicePixelRatio(), + destination.width() * devicePixelRatio(), + destination.height() * devicePixelRatio()); +#endif + + if (source.width() != w || source.height() != h) { + glw.glBindTexture(GL_TEXTURE_2D, scene_texture.id); + glw.glTexImage2D(GL_TEXTURE_2D, 0, (GLenum) QOpenGLTexture::RGBA8_UNorm, w, h, 0, (GLenum) QOpenGLTexture::BGRA, (GLenum) QOpenGLTexture::UInt32_RGBA8_Rev, NULL); + glw.glBindTexture(GL_TEXTURE_2D, 0); + } + + source.setRect(x, y, w, h); + + glw.glBindTexture(GL_TEXTURE_2D, scene_texture.id); + glw.glPixelStorei(GL_UNPACK_ROW_LENGTH, 2048); + glw.glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, (GLenum) QOpenGLTexture::BGRA, (GLenum) QOpenGLTexture::UInt32_RGBA8_Rev, (const void *) ((uintptr_t) imagebufs[buf_idx].get() + (uintptr_t) (2048 * 4 * y + x * 4))); + glw.glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + glw.glBindTexture(GL_TEXTURE_2D, 0); + + buf_usage[buf_idx].clear(); + source.setRect(x, y, w, h); + onResize(this->width(), this->height()); + + if (video_framerate == -1) + render(); +} + +std::vector> +OpenGLRenderer::getBuffers() +{ + std::vector> buffers; + + buffers.push_back(std::make_tuple(imagebufs[0].get(), &buf_usage[0])); + buffers.push_back(std::make_tuple(imagebufs[1].get(), &buf_usage[1])); + + return buffers; } void @@ -97,13 +1167,158 @@ OpenGLRenderer::resizeEvent(QResizeEvent *event) context->makeCurrent(this); - glViewport( + glw.glViewport( destination.x() * devicePixelRatio(), destination.y() * devicePixelRatio(), destination.width() * devicePixelRatio(), destination.height() * devicePixelRatio()); } +void +OpenGLRenderer::render_pass(struct render_data *data) +{ + int i; + GLuint texture_unit = 0; + + // pclog("pass %d: %gx%g, %gx%g -> %gx%g, %gx%g, %gx%g\n", num_pass, pass->state.input_size[0], + // pass->state.input_size[1], pass->state.input_texture_size[0], pass->state.input_texture_size[1], + // pass->state.output_size[0], pass->state.output_size[1], pass->state.output_texture_size[0], + // pass->state.output_texture_size[1], output_size[0], output_size[1]); + + glw.glBindVertexArray(data->shader_pass->vertex_array); + + GLint p = data->shader_pass->program.id; + struct shader_uniforms *u = &data->shader_pass->uniforms; + + glw.glUseProgram(p); + + if (data->texture) { + glw.glActiveTexture(GL_TEXTURE0 + texture_unit); + glw.glBindTexture(GL_TEXTURE_2D, data->texture); + glw.glUniform1i(u->texture, texture_unit); + texture_unit++; + } + + if (u->color >= 0) + glw.glEnableVertexAttribArray(u->color); + + if (u->mvp_matrix >= 0) + glw.glUniformMatrix4fv(u->mvp_matrix, 1, 0, matrix); + if (u->frame_direction >= 0) + glw.glUniform1i(u->frame_direction, 1); + + int framecnt = data->frame_count; + if (data->shader_pass->frame_count_mod > 0) + framecnt = framecnt % data->shader_pass->frame_count_mod; + if (u->frame_count >= 0) + glw.glUniform1i(u->frame_count, framecnt); + + if (u->input_size >= 0) + glw.glUniform2fv(u->input_size, 1, data->shader_pass->state.input_size); + if (u->texture_size >= 0) + glw.glUniform2fv(u->texture_size, 1, data->shader_pass->state.input_texture_size); + if (u->output_size >= 0) + glw.glUniform2fv(u->output_size, 1, data->output_size); + + if (data->shader) { + /* parameters */ + for (i = 0; i < data->shader->num_parameters; ++i) + if (u->parameters[i] >= 0) + glw.glUniform1f(u->parameters[i], data->shader->parameters[i].value); + + if (data->pass > 0) { + struct shader_pass *passes = data->shader->passes; + struct shader_pass *orig = data->orig_pass; + if (u->orig.texture >= 0) { + glw.glActiveTexture(GL_TEXTURE0 + texture_unit); + glw.glBindTexture(GL_TEXTURE_2D, orig->fbo.texture.id); + glw.glUniform1i(u->orig.texture, texture_unit); + texture_unit++; + } + if (u->orig.input_size >= 0) + glw.glUniform2fv(u->orig.input_size, 1, orig->state.input_size); + if (u->orig.texture_size >= 0) + glw.glUniform2fv(u->orig.texture_size, 1, orig->state.input_texture_size); + + for (i = 0; i < data->pass; ++i) { + if (u->pass[i].texture >= 0) { + glw.glActiveTexture(GL_TEXTURE0 + texture_unit); + glw.glBindTexture(GL_TEXTURE_2D, passes[i].fbo.texture.id); + glw.glUniform1i(u->pass[i].texture, texture_unit); + texture_unit++; + } + if (u->pass[i].texture_size >= 0) + glw.glUniform2fv(u->pass[i].texture_size, 1, passes[i].state.input_texture_size); + if (u->pass[i].input_size >= 0) + glw.glUniform2fv(u->pass[i].input_size, 1, passes[i].state.input_size); + + if (u->prev_pass[i].texture >= 0) { + glw.glActiveTexture(GL_TEXTURE0 + texture_unit); + glw.glBindTexture(GL_TEXTURE_2D, passes[i].fbo.texture.id); + glw.glUniform1i(u->prev_pass[i].texture, texture_unit); + texture_unit++; + } + if (u->prev_pass[i].texture_size >= 0) + glw.glUniform2fv(u->prev_pass[i].texture_size, 1, passes[i].state.input_texture_size); + if (u->prev_pass[i].input_size >= 0) + glw.glUniform2fv(u->prev_pass[i].input_size, 1, passes[i].state.input_size); + } + } + + if (data->shader->has_prev) { + /* loop through each previous frame */ + for (i = 0; i < MAX_PREV; ++i) { + if (u->prev[i].texture >= 0) { + glw.glActiveTexture(GL_TEXTURE0 + texture_unit); + glw.glBindTexture(GL_TEXTURE_2D, data->shader->prev[i].fbo.texture.id); + glw.glUniform1i(u->prev[i].texture, texture_unit); + texture_unit++; + } + if (u->prev[i].tex_coord >= 0) { + glw.glBindBuffer(GL_ARRAY_BUFFER, data->shader->prev[i].vbo.tex_coord); + glw.glVertexAttribPointer(u->prev[i].tex_coord, 2, GL_FLOAT, GL_TRUE, + 2 * sizeof(GLfloat), (GLvoid *) 0); + glw.glEnableVertexAttribArray(u->prev[i].tex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, 0); + } + } + } + + for (i = 0; i < data->shader->num_lut_textures; ++i) { + if (u->lut_textures[i] >= 0) { + glw.glActiveTexture(GL_TEXTURE0 + texture_unit); + glw.glBindTexture(GL_TEXTURE_2D, data->shader->lut_textures[i].texture.id); + glw.glUniform1i(u->lut_textures[i], texture_unit); + texture_unit++; + } + } + } + + glw.glEnableVertexAttribArray(u->vertex_coord); + glw.glEnableVertexAttribArray(u->tex_coord); + + glw.glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + glw.glActiveTexture(GL_TEXTURE0); + glw.glBindTexture(GL_TEXTURE_2D, 0); + + glw.glDisableVertexAttribArray(data->shader_pass->uniforms.vertex_coord); + glw.glDisableVertexAttribArray(data->shader_pass->uniforms.tex_coord); + if (data->shader_pass->uniforms.color >= 0) + glw.glDisableVertexAttribArray(data->shader_pass->uniforms.color); + + if (data->shader && data->shader->has_prev) { + for (i = 0; i < MAX_PREV; ++i) { + if (u->prev[i].tex_coord >= 0) + glw.glDisableVertexAttribArray(u->prev[i].tex_coord); + } + } + + glw.glBindVertexArray(0); + + glw.glUseProgram(0); +} + bool OpenGLRenderer::event(QEvent *event) { @@ -115,354 +1330,381 @@ OpenGLRenderer::event(QEvent *event) return res; } -void -OpenGLRenderer::initialize() -{ - try { - context = new QOpenGLContext(this); - - context->setFormat(format()); - - if (!context->create()) - throw opengl_init_error(tr("Couldn't create OpenGL context.")); - - if (!context->makeCurrent(this)) - throw opengl_init_error(tr("Couldn't switch to OpenGL context.")); - - auto version = context->format().version(); - - if (version.first < 3) - throw opengl_init_error(tr("OpenGL version 3.0 or greater is required. Current version is %1.%2").arg(version.first).arg(version.second)); - - initializeOpenGLFunctions(); - - /* Prepare the shader version string */ - glslVersion = reinterpret_cast(glGetString(GL_SHADING_LANGUAGE_VERSION)); - glslVersion.truncate(4); - glslVersion.remove('.'); - glslVersion.prepend("#version "); - if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) - glslVersion.append(" es"); - else if (context->format().profile() == QSurfaceFormat::CoreProfile) - glslVersion.append(" core"); - - initializeExtensions(); - - initializeBuffers(); - - /* Vertex, texture 2d coordinates and color (white) making a quad as triangle strip */ - const GLfloat surface[] = { - -1.f, 1.f, 0.f, 0.f, 1.f, 1.f, 1.f, 1.f, - 1.f, 1.f, 1.f, 0.f, 1.f, 1.f, 1.f, 1.f, - -1.f, -1.f, 0.f, 1.f, 1.f, 1.f, 1.f, 1.f, - 1.f, -1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f - }; - - glGenVertexArrays(1, &vertexArrayID); - - glBindVertexArray(vertexArrayID); - - glGenBuffers(1, &vertexBufferID); - glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID); - glBufferData(GL_ARRAY_BUFFER, sizeof(surface), surface, GL_STATIC_DRAW); - - glGenTextures(1, &textureID); - glBindTexture(GL_TEXTURE_2D, textureID); - - const GLfloat border_color[] = { 0.f, 0.f, 0.f, 1.f }; - - glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - - glTexImage2D(GL_TEXTURE_2D, 0, QOpenGLTexture::RGBA8_UNorm, INIT_WIDTH, INIT_HEIGHT, 0, QOpenGLTexture::BGRA, QOpenGLTexture::UInt32_RGBA8_Rev, NULL); - - reloadOptions(); - - glClearColor(0.f, 0.f, 0.f, 1.f); - - glViewport( - destination.x() * devicePixelRatio(), - destination.y() * devicePixelRatio(), - destination.width() * devicePixelRatio(), - destination.height() * devicePixelRatio()); - - GLenum error = glGetError(); - if (error != GL_NO_ERROR) - throw opengl_init_error(tr("OpenGL initialization failed. Error %1.").arg(error)); - - isInitialized = true; - - emit initialized(); - - glClear(GL_COLOR_BUFFER_BIT); - - context->swapBuffers(this); - } catch (const opengl_init_error &e) { - /* Mark all buffers as in use */ - for (auto &flag : buf_usage) - flag.test_and_set(); - - QMessageBox::critical((QWidget *) qApp->findChild(), tr("Error initializing OpenGL"), e.what() % tr("\nFalling back to software rendering.")); - - context->doneCurrent(); - isFinalized = true; - isInitialized = true; - - emit errorInitializing(); - } -} - -void -OpenGLRenderer::finalize() -{ - if (isFinalized) - return; - - renderTimer->stop(); - - context->makeCurrent(this); - - if (hasBufferStorage) - glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); - - glDeleteBuffers(1, &unpackBufferID); - glDeleteTextures(1, &textureID); - glDeleteBuffers(1, &vertexBufferID); - glDeleteVertexArrays(1, &vertexArrayID); - - if (!hasBufferStorage && unpackBuffer) - free(unpackBuffer); - - context->doneCurrent(); - - isFinalized = true; -} - -QDialog * +QDialog* OpenGLRenderer::getOptions(QWidget *parent) { - auto dialog = new OpenGLOptionsDialog(parent, *options, [this]() { return new OpenGLOptions(this, false, glslVersion); }); - - connect(dialog, &OpenGLOptionsDialog::optionsChanged, this, &OpenGLRenderer::updateOptions); - - return dialog; -} - -void -OpenGLRenderer::initializeExtensions() -{ -#ifndef NO_BUFFER_STORAGE - if (context->hasExtension("GL_ARB_buffer_storage") || context->hasExtension("GL_EXT_buffer_storage")) { - hasBufferStorage = true; - - glBufferStorage = (PFNGLBUFFERSTORAGEEXTPROC_LOCAL) context->getProcAddress(context->hasExtension("GL_EXT_buffer_storage") ? "glBufferStorageEXT" : "glBufferStorage"); - if (!glBufferStorage) - glBufferStorage = (PFNGLBUFFERSTORAGEEXTPROC_LOCAL) context->getProcAddress("glBufferStorage"); - } -#endif -} - -void -OpenGLRenderer::initializeBuffers() -{ - glGenBuffers(1, &unpackBufferID); - - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, unpackBufferID); - - if (hasBufferStorage) { -#ifndef NO_BUFFER_STORAGE - /* Create persistent buffer for pixel transfer. */ - glBufferStorage(GL_PIXEL_UNPACK_BUFFER, BUFFERBYTES * BUFFERCOUNT, NULL, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); - - unpackBuffer = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, BUFFERBYTES * BUFFERCOUNT, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); -#endif - } else { - /* Fallback; create our own buffer. */ - unpackBuffer = malloc(BUFFERBYTES * BUFFERCOUNT); - - if (unpackBuffer == nullptr) - throw opengl_init_error(tr("Allocating memory for unpack buffer failed.")); - - glBufferData(GL_PIXEL_UNPACK_BUFFER, BUFFERBYTES * BUFFERCOUNT, NULL, GL_STREAM_DRAW); - } -} - -void -OpenGLRenderer::applyOptions() -{ - /* TODO: change detection in options */ - - if (options->framerate() > 0) { - int interval = (int) ceilf(1000.f / (float) options->framerate()); - renderTimer->setInterval(std::chrono::milliseconds(interval)); - } - - if (options->renderBehavior() == OpenGLOptions::TargetFramerate) - renderTimer->start(); - else - renderTimer->stop(); - - auto format = this->format(); - int interval = options->vSync() ? 1 : 0; - - if (format.swapInterval() != interval) { - format.setSwapInterval(interval); - setFormat(format); - context->setFormat(format); - } - - GLint filter = options->filter() == OpenGLOptions::Linear ? GL_LINEAR : GL_NEAREST; - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); - - currentFilter = options->filter(); -} - -void -OpenGLRenderer::reloadOptions() -{ - if (options) { - delete options; - options = nullptr; - } - options = new OpenGLOptions(this, true, glslVersion); - - applyOptions(); -} - -void -OpenGLRenderer::applyShader(const OpenGLShaderPass &shader) -{ - if (!shader.bind()) - return; - - if (shader.vertex_coord() != -1) { - glEnableVertexAttribArray(shader.vertex_coord()); - glVertexAttribPointer(shader.vertex_coord(), 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), 0); - } - - if (shader.tex_coord() != -1) { - glEnableVertexAttribArray(shader.tex_coord()); - glVertexAttribPointer(shader.tex_coord(), 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void *) (2 * sizeof(GLfloat))); - } - - if (shader.color() != -1) { - glEnableVertexAttribArray(shader.color()); - glVertexAttribPointer(shader.color(), 4, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void *) (4 * sizeof(GLfloat))); - } - - if (shader.mvp_matrix() != -1) { - static const GLfloat mvp[] = { - 1.f, 0.f, 0.f, 0.f, - 0.f, 1.f, 0.f, 0.f, - 0.f, 0.f, 1.f, 0.f, - 0.f, 0.f, 0.f, 1.f - }; - glUniformMatrix4fv(shader.mvp_matrix(), 1, GL_FALSE, mvp); - } - - if (shader.output_size() != -1) - glUniform2f(shader.output_size(), destination.width(), destination.height()); - - if (shader.input_size() != -1) - glUniform2f(shader.input_size(), source.width(), source.height()); - - if (shader.texture_size() != -1) - glUniform2f(shader.texture_size(), source.width(), source.height()); - - if (shader.frame_count() != -1) - glUniform1i(shader.frame_count(), frameCounter); + return new OpenGLShaderManagerDialog(parent); } void OpenGLRenderer::render() { - context->makeCurrent(this); + if (!context) + return; - if (options->filter() != currentFilter) - applyOptions(); - - /* TODO: multiple shader passes */ - applyShader(options->shaders().first()); - - glClear(GL_COLOR_BUFFER_BIT); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - context->swapBuffers(this); - - frameCounter = (frameCounter + 1) & 1023; -} - -void -OpenGLRenderer::updateOptions(OpenGLOptions *newOptions) -{ - context->makeCurrent(this); - - glUseProgram(0); - - delete options; - - options = newOptions; - - options->setParent(this); - - applyOptions(); -} - -std::vector> -OpenGLRenderer::getBuffers() -{ - std::vector> buffers; - - if (notReady() || !unpackBuffer) - return buffers; - - /* Split the buffer area */ - for (int i = 0; i < BUFFERCOUNT; i++) { - buffers.push_back(std::make_tuple((uint8_t *) unpackBuffer + BUFFERBYTES * i, &buf_usage[i])); - } - - return buffers; -} - -void -OpenGLRenderer::onBlit(int buf_idx, int x, int y, int w, int h) -{ if (notReady()) return; - context->makeCurrent(this); + int s, i, j; -#ifdef Q_OS_MACOS - glViewport( - destination.x() * devicePixelRatio(), - destination.y() * devicePixelRatio(), - destination.width() * devicePixelRatio(), - destination.height() * devicePixelRatio()); -#endif + struct { + uint32_t x, y, w, h; + } window_rect; - if (source.width() != w || source.height() != h) { - source.setRect(0, 0, w, h); + window_rect.x = destination.x() * devicePixelRatio(); + window_rect.y = destination.y() * devicePixelRatio(); + window_rect.w = destination.width() * devicePixelRatio(); + window_rect.h = destination.height() * devicePixelRatio(); - /* Resize the texture */ - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - glTexImage2D(GL_TEXTURE_2D, 0, (GLenum) QOpenGLTexture::RGBA8_UNorm, source.width(), source.height(), 0, (GLenum) QOpenGLTexture::BGRA, (GLenum) QOpenGLTexture::UInt32_RGBA8_Rev, NULL); - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, unpackBufferID); + glw.glBindTexture(GL_TEXTURE_2D, scene_texture.id); + scene_texture.min_filter = scene_texture.mag_filter = video_filter_method ? GL_LINEAR : GL_NEAREST; + glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, video_filter_method ? GL_LINEAR : GL_NEAREST); + glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, video_filter_method ? GL_LINEAR : GL_NEAREST); + glw.glBindTexture(GL_TEXTURE_2D, 0); + + GLfloat orig_output_size[] = { (GLfloat)window_rect.w, (GLfloat)window_rect.h }; + + if (active_shader->srgb) + glw.glEnable(GL_FRAMEBUFFER_SRGB); + + struct render_data data; + + /* render scene to texture */ + { + struct shader_pass *pass = &active_shader->scene; + + struct { + uint32_t x, y, w, h; + } rect; + rect.x = 0; + rect.y = 0; + rect.w = source.width(); + rect.h = source.height(); + + pass->state.input_size[0] = pass->state.output_size[0] = rect.w; + pass->state.input_size[1] = pass->state.output_size[1] = rect.h; + + pass->state.input_texture_size[0] = pass->state.output_texture_size[0] = next_pow2(pass->state.output_size[0]); + pass->state.input_texture_size[1] = pass->state.output_texture_size[1] = next_pow2(pass->state.output_size[1]); + + recreate_fbo(&active_shader->scene.fbo, pass->state.output_texture_size[0], pass->state.output_texture_size[1]); + + glw.glBindFramebuffer(GL_FRAMEBUFFER, active_shader->scene.fbo.id); + glw.glClearColor(0, 0, 0, 1); + glw.glClear(GL_COLOR_BUFFER_BIT); + + glw.glViewport(0, 0, pass->state.output_size[0], pass->state.output_size[1]); + + GLfloat minx = 0; + GLfloat miny = 0; + GLfloat maxx = pass->state.output_size[0] / (GLfloat) pass->state.output_texture_size[0]; + GLfloat maxy = pass->state.output_size[1] / (GLfloat) pass->state.output_texture_size[1]; + + pass->state.tex_coords[0] = minx; + pass->state.tex_coords[1] = miny; + pass->state.tex_coords[2] = minx; + pass->state.tex_coords[3] = maxy; + pass->state.tex_coords[4] = maxx; + pass->state.tex_coords[5] = miny; + pass->state.tex_coords[6] = maxx; + pass->state.tex_coords[7] = maxy; + + // create input tex coords + minx = 0; + miny = 0; + maxx = 1; + maxy = 1; + + GLfloat tex_coords[] = { minx, miny, minx, maxy, maxx, miny, maxx, maxy }; + + glw.glBindVertexArray(pass->vertex_array); + + glw.glBindBuffer(GL_ARRAY_BUFFER, pass->vbo.tex_coord); + glw.glBufferSubData(GL_ARRAY_BUFFER, 0, 8 * sizeof(GLfloat), tex_coords); + glw.glBindBuffer(GL_ARRAY_BUFFER, 0); + + memset(&data, 0, sizeof(struct render_data)); + data.pass = -1; + data.shader_pass = &active_shader->scene; + data.texture = scene_texture.id; + data.output_size = orig_output_size; + render_pass(&data); + + glw.glBindFramebuffer(GL_FRAMEBUFFER, 0); } - if (!hasBufferStorage) - glBufferSubData(GL_PIXEL_UNPACK_BUFFER, BUFFERBYTES * buf_idx, h * ROW_LENGTH * sizeof(uint32_t) + (y * ROW_LENGTH * sizeof(uint32_t)), (uint8_t *) unpackBuffer + BUFFERBYTES * buf_idx); + struct shader_pass *orig = &active_shader->scene; + struct shader_pass *input = &active_shader->scene; - glPixelStorei(GL_UNPACK_SKIP_PIXELS, BUFFERPIXELS * buf_idx + y * ROW_LENGTH + x); - glPixelStorei(GL_UNPACK_ROW_LENGTH, ROW_LENGTH); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, (GLenum) QOpenGLTexture::BGRA, (GLenum) QOpenGLTexture::UInt32_RGBA8_Rev, NULL); + for (s = 0; s < active_shader->num_shaders; ++s) { + struct glsl_shader *shader = &active_shader->shaders[s]; - /* TODO: check if fence sync is implementable here and still has any benefit. */ - glFinish(); + int frame_count = frameCounter; - buf_usage[buf_idx].clear(); + /* loop through each pass */ + for (i = 0; i < shader->num_passes; ++i) { + struct shader_pass *pass = &shader->passes[i]; - if (options->renderBehavior() == OpenGLOptions::SyncWithVideo) - render(); + memcpy(pass->state.input_size, input->state.output_size, 2 * sizeof(GLfloat)); + memcpy(pass->state.input_texture_size, input->state.output_texture_size, 2 * sizeof(GLfloat)); + + for (j = 0; j < 2; ++j) { + if (pass->scale.mode[j] == SCALE_VIEWPORT) + pass->state.output_size[j] = orig_output_size[j] * pass->scale.value[j]; + else if (pass->scale.mode[j] == SCALE_ABSOLUTE) + pass->state.output_size[j] = pass->scale.value[j]; + else + pass->state.output_size[j] = pass->state.input_size[j] * pass->scale.value[j]; + + pass->state.output_texture_size[j] = next_pow2(pass->state.output_size[j]); + } + + if (pass->fbo.id >= 0) { + recreate_fbo(&pass->fbo, pass->state.output_texture_size[0], pass->state.output_texture_size[1]); + + glw.glBindFramebuffer(GL_FRAMEBUFFER, pass->fbo.id); + glw.glViewport(0, 0, pass->state.output_size[0], pass->state.output_size[1]); + } else + glw.glViewport(window_rect.x, window_rect.y, window_rect.w, window_rect.h); + + glw.glClearColor(0, 0, 0, 1); + glw.glClear(GL_COLOR_BUFFER_BIT); + + GLfloat minx = 0; + GLfloat miny = 0; + GLfloat maxx = pass->state.output_size[0] / (GLfloat) pass->state.output_texture_size[0]; + GLfloat maxy = pass->state.output_size[1] / (GLfloat) pass->state.output_texture_size[1]; + + pass->state.tex_coords[0] = minx; + pass->state.tex_coords[1] = miny; + pass->state.tex_coords[2] = minx; + pass->state.tex_coords[3] = maxy; + pass->state.tex_coords[4] = maxx; + pass->state.tex_coords[5] = miny; + pass->state.tex_coords[6] = maxx; + pass->state.tex_coords[7] = maxy; + + glw.glBindVertexArray(pass->vertex_array); + + glw.glBindBuffer(GL_ARRAY_BUFFER, pass->vbo.tex_coord); + glw.glBufferSubData(GL_ARRAY_BUFFER, 0, 8 * sizeof(GLfloat), input->state.tex_coords); + glw.glBindBuffer(GL_ARRAY_BUFFER, 0); + + memset(&data, 0, sizeof(struct render_data)); + data.shader = shader; + data.pass = i; + data.shader_pass = pass; + data.texture = input->fbo.texture.id; + data.output_size = orig_output_size; + data.orig_pass = orig; + data.frame_count = frame_count; + + render_pass(&data); + + glw.glBindFramebuffer(GL_FRAMEBUFFER, 0); + + if (pass->fbo.texture.mipmap) { + glw.glActiveTexture(GL_TEXTURE0); + glw.glBindTexture(GL_TEXTURE_2D, pass->fbo.texture.id); + glw.glGenerateMipmap(GL_TEXTURE_2D); + glw.glBindTexture(GL_TEXTURE_2D, 0); + } + + input = pass; + } + + if (shader->has_prev) { + /* shift array */ + memmove(&shader->prev[1], &shader->prev[0], MAX_PREV * sizeof(struct shader_prev)); + memcpy(&shader->prev[0], &shader->prev[MAX_PREV], sizeof(struct shader_prev)); + + struct shader_pass *pass = orig; + struct shader_pass *prev_pass = &shader->prev_scene; + struct shader_prev *prev = &shader->prev[0]; + + memcpy(&prev_pass->state, &pass->state, sizeof(struct shader_state)); + + recreate_fbo(&prev->fbo, prev_pass->state.output_texture_size[0], + prev_pass->state.output_texture_size[1]); + + memcpy(&prev_pass->fbo, &prev->fbo, sizeof(struct shader_fbo)); + + glw.glBindFramebuffer(GL_FRAMEBUFFER, prev->fbo.id); + glw.glClearColor(0, 0, 0, 1); + glw.glClear(GL_COLOR_BUFFER_BIT); + + glw.glViewport(0, 0, pass->state.output_size[0], pass->state.output_size[1]); + + glw.glBindVertexArray(prev_pass->vertex_array); + + glw.glBindBuffer(GL_ARRAY_BUFFER, prev->vbo.tex_coord); + glw.glBufferSubData(GL_ARRAY_BUFFER, 0, 8 * sizeof(GLfloat), pass->state.tex_coords); + glw.glBindBuffer(GL_ARRAY_BUFFER, 0); + + glw.glBindBuffer(GL_ARRAY_BUFFER, prev_pass->vbo.tex_coord); + glw.glBufferSubData(GL_ARRAY_BUFFER, 0, 8 * sizeof(GLfloat), pass->state.tex_coords); + glw.glBindBuffer(GL_ARRAY_BUFFER, 0); + + memset(&data, 0, sizeof(struct render_data)); + data.shader = shader; + data.pass = -10; + data.shader_pass = prev_pass; + data.texture = pass->fbo.texture.id; + data.output_size = orig_output_size; + + render_pass(&data); + + glw.glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + + orig = input; + } + + if (active_shader->final_pass.active) { + struct shader_pass *pass = &active_shader->final_pass; + + memcpy(pass->state.input_size, input->state.output_size, 2 * sizeof(GLfloat)); + memcpy(pass->state.input_texture_size, input->state.output_texture_size, 2 * sizeof(GLfloat)); + + for (j = 0; j < 2; ++j) { + if (pass->scale.mode[j] == SCALE_VIEWPORT) + pass->state.output_size[j] = orig_output_size[j] * pass->scale.value[j]; + else if (pass->scale.mode[j] == SCALE_ABSOLUTE) + pass->state.output_size[j] = pass->scale.value[j]; + else + pass->state.output_size[j] = pass->state.input_size[j] * pass->scale.value[j]; + + pass->state.output_texture_size[j] = next_pow2(pass->state.output_size[j]); + } + + glw.glViewport(window_rect.x, window_rect.y, window_rect.w, window_rect.h); + + glw.glClearColor(0, 0, 0, 1); + glw.glClear(GL_COLOR_BUFFER_BIT); + + GLfloat minx = 0; + GLfloat miny = 0; + GLfloat maxx = pass->state.output_size[0] / (GLfloat) pass->state.output_texture_size[0]; + GLfloat maxy = pass->state.output_size[1] / (GLfloat) pass->state.output_texture_size[1]; + + pass->state.tex_coords[0] = minx; + pass->state.tex_coords[1] = miny; + pass->state.tex_coords[2] = minx; + pass->state.tex_coords[3] = maxy; + pass->state.tex_coords[4] = maxx; + pass->state.tex_coords[5] = miny; + pass->state.tex_coords[6] = maxx; + pass->state.tex_coords[7] = maxy; + + glw.glBindVertexArray(pass->vertex_array); + + glw.glBindBuffer(GL_ARRAY_BUFFER, pass->vbo.tex_coord); + glw.glBufferSubData(GL_ARRAY_BUFFER, 0, 8 * sizeof(GLfloat), input->state.tex_coords); + glw.glBindBuffer(GL_ARRAY_BUFFER, 0); + + memset(&data, 0, sizeof(struct render_data)); + data.pass = -2; + data.shader_pass = pass; + data.texture = input->fbo.texture.id; + data.output_size = orig_output_size; + data.orig_pass = orig; + + render_pass(&data); + } + + if (1) { + // if (video_focus_dim && !(SDL_GetWindowFlags(window) & SDL_WINDOW_INPUT_FOCUS)) { +#if 0 + if (0) { + struct shader_pass *pass = &active_shader->fs_color; + GLfloat r = 0; + GLfloat g = 0; + GLfloat b = 0; + GLfloat a = 0x80 / (float) 0xff; + + GLfloat colors[] = { r, g, b, a, r, g, b, a, r, g, b, a, r, g, b, a }; + + glw.glBindVertexArray(pass->vertex_array); + + glw.glBindBuffer(GL_ARRAY_BUFFER, pass->vbo.color); + glw.glBufferSubData(GL_ARRAY_BUFFER, 0, 16 * sizeof(GLfloat), colors); + glw.glBindBuffer(GL_ARRAY_BUFFER, 0); + + memset(&data, 0, sizeof(struct render_data)); + data.pass = -3; + data.shader_pass = pass; + data.texture = 0; + data.output_size = orig_output_size; + data.orig_pass = orig; + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + render_pass(&data); + glDisable(GL_BLEND); + } + + if (flash.enabled) { + struct shader_pass *pass = &active_shader->fs_color; + GLfloat r = (flash.color[0] & 0xff) / (float)0xff; + GLfloat g = (flash.color[1] & 0xff) / (float)0xff; + GLfloat b = (flash.color[2] & 0xff) / (float)0xff; + GLfloat a = (flash.color[3] & 0xff) / (float)0xff; + + GLfloat colors[] = {r, g, b, a, r, g, b, a, r, g, b, a, r, g, b, a}; + + glw.glBindVertexArray(pass->vertex_array); + + glw.glBindBuffer(GL_ARRAY_BUFFER, pass->vbo.color); + glw.glBufferSubData(GL_ARRAY_BUFFER, 0, 16 * sizeof(GLfloat), colors); + glw.glBindBuffer(GL_ARRAY_BUFFER, 0); + + memset(&data, 0, sizeof(struct render_data)); + data.pass = -3; + data.shader_pass = pass; + data.texture = 0; + data.output_size = orig_output_size; + data.orig_pass = orig; + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + render_pass(&data); + glDisable(GL_BLEND); + } +#endif + } else { +#if 0 + take_screenshot = 0; + + int width = window_rect.w; + int height = window_rect.h; + + SDL_GetWindowSize(window, &width, &height); + + unsigned char *rgba = (unsigned char *)malloc(width * height * 4); + + glFinish(); + glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, rgba); + + int x, y; + unsigned char *rgb = (unsigned char *)malloc(width * height * 3); + + for (x = 0; x < width; ++x) { + for (y = 0; y < height; ++y) { + rgb[(y * width + x) * 3 + 0] = rgba[((height - y - 1) * width + x) * 4 + 0]; + rgb[(y * width + x) * 3 + 1] = rgba[((height - y - 1) * width + x) * 4 + 1]; + rgb[(y * width + x) * 3 + 2] = rgba[((height - y - 1) * width + x) * 4 + 2]; + } + } + + screenshot_taken(rgb, width, height); + + free(rgb); + free(rgba); +#endif + } + + glw.glDisable(GL_FRAMEBUFFER_SRGB); + + frameCounter++; + context->swapBuffers(this); } diff --git a/src/qt/qt_openglrenderer.hpp b/src/qt/qt_openglrenderer.hpp index 27822600c..9db1e7307 100644 --- a/src/qt/qt_openglrenderer.hpp +++ b/src/qt/qt_openglrenderer.hpp @@ -11,12 +11,14 @@ * * * Authors: Teemu Korhonen + * Cacodemon345 * * Copyright 2022 Teemu Korhonen + * Copyright 2025 Cacodemon345 */ -#ifndef QT_OPENGLRENDERER_HPP -#define QT_OPENGLRENDERER_HPP +#ifndef QT_OpenGLRenderer_HPP +#define QT_OpenGLRenderer_HPP #if defined Q_OS_MACOS || __arm__ # define NO_BUFFER_STORAGE @@ -37,12 +39,24 @@ #include #include -#include "qt_opengloptions.hpp" #include "qt_renderercommon.hpp" -typedef void(QOPENGLF_APIENTRYP PFNGLBUFFERSTORAGEEXTPROC_LOCAL)(GLenum target, GLsizeiptr size, const void *data, GLbitfield flags); +extern "C" +{ +#include <86box/qt-glslp-parser.h> +} -class OpenGLRenderer : public QWindow, protected QOpenGLExtraFunctions, public RendererCommon { +struct render_data { + int pass; + struct glsl_shader *shader; + struct shader_pass *shader_pass; + GLfloat *output_size; + struct shader_pass *orig_pass; + GLint texture; + int frame_count; +}; + +class OpenGLRenderer : public QWindow, public RendererCommon { Q_OBJECT public: @@ -56,7 +70,7 @@ public: void finalize() override final; bool hasOptions() const override { return true; } QDialog *getOptions(QWidget *parent) override; - void reloadOptions() override; + bool reloadRendererOption() { return true; } signals: void initialized(); @@ -71,47 +85,64 @@ protected: bool event(QEvent *event) override; private: - static constexpr int INIT_WIDTH = 640; - static constexpr int INIT_HEIGHT = 400; - static constexpr int ROW_LENGTH = 2048; - static constexpr int BUFFERPIXELS = 4194304; - static constexpr int BUFFERBYTES = 16777216; /* Pixel is 4 bytes. */ - static constexpr int BUFFERCOUNT = 3; /* How many buffers to use for pixel transfer (2-3 is commonly recommended). */ + + std::array, 2> imagebufs; QTimer *renderTimer; - OpenGLOptions *options; - QString glslVersion; + QString glslVersion = ""; bool isInitialized = false; bool isFinalized = false; - GLuint unpackBufferID = 0; - GLuint vertexArrayID = 0; - GLuint vertexBufferID = 0; - GLuint textureID = 0; - int frameCounter = 0; + int max_texture_size = 65536; + int frameCounter = 0; - OpenGLOptions::FilterType currentFilter; + QOpenGLExtraFunctions glw; + struct shader_texture scene_texture; + glsl_t *active_shader; void *unpackBuffer = nullptr; + int glsl_version[2] = { 0, 0 }; + void initialize(); void initializeExtensions(); void initializeBuffers(); void applyOptions(); - void applyShader(const OpenGLShaderPass &shader); - bool notReady() const { return !isInitialized || isFinalized; } + + void create_scene_shader(); + void create_texture(struct shader_texture *tex); + void create_fbo(struct shader_fbo *fbo); + void recreate_fbo(struct shader_fbo *fbo, int width, int height); + void setup_fbo(struct shader *shader, struct shader_fbo *fbo); - /* GL_ARB_buffer_storage */ - bool hasBufferStorage = false; -#ifndef NO_BUFFER_STORAGE - PFNGLBUFFERSTORAGEEXTPROC_LOCAL glBufferStorage = nullptr; -#endif + bool notReady() const { return !isInitialized || isFinalized; } + glsl_t* load_glslp(glsl_t *glsl, int num_shader, const char *f); + glsl_t* load_shaders(int num, char shaders[MAX_USER_SHADERS][512]); + int compile_shader(GLenum shader_type, const char *prepend, const char *program, int *dst); + int create_default_shader_tex(struct shader_pass *pass); + int create_default_shader_color(struct shader_pass *pass); + int create_program(struct shader_program *program); + + GLuint get_uniform(GLuint program, const char *name); + GLuint get_attrib(GLuint program, const char *name); + + void find_uniforms(struct glsl_shader *glsl, int num_pass); + void delete_texture(struct shader_texture *tex); + void delete_fbo(struct shader_fbo *fbo); + void delete_program(struct shader_program *program); + void delete_vbo(struct shader_vbo *vbo); + void delete_pass(struct shader_pass *pass); + void delete_prev(struct shader_prev *prev); + void delete_shader(struct glsl_shader *glsl); + void delete_glsl(glsl_t *glsl); + void read_shader_config(); + + void render_pass(struct render_data *data); private slots: void render(); - void updateOptions(OpenGLOptions *newOptions); }; class opengl_init_error : public std::runtime_error { diff --git a/src/qt/qt_openglshaderconfig.cpp b/src/qt/qt_openglshaderconfig.cpp new file mode 100644 index 000000000..25f9d38a8 --- /dev/null +++ b/src/qt/qt_openglshaderconfig.cpp @@ -0,0 +1,85 @@ +#include "qt_openglshaderconfig.hpp" +#include "ui_qt_openglshaderconfig.h" + +#include "qt_mainwindow.hpp" + +extern MainWindow* main_window; + +extern "C" +{ +#include <86box/86box.h> +#include <86box/plat.h> +#include <86box/config.h> +} + +OpenGLShaderConfig::OpenGLShaderConfig(QWidget *parent, glslp_t* shader) + : QDialog(parent) + , ui(new Ui::OpenGLShaderConfig) +{ + ui->setupUi(this); + + currentShader = shader; + + connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + + glslp_read_shader_config(currentShader); + + for (int i = 0; i < currentShader->num_parameters; i++) { + auto spinBox = new QDoubleSpinBox; + spinBox->setObjectName(currentShader->parameters[i].id); + spinBox->setRange(currentShader->parameters[i].min, currentShader->parameters[i].max); + spinBox->setValue(currentShader->parameters[i].value); + spinBox->setSingleStep(currentShader->parameters[i].step); + QFormLayout* layout = (QFormLayout*)ui->scrollAreaWidgetContents->layout(); + layout->addRow(currentShader->parameters[i].description, spinBox); + } +} + +OpenGLShaderConfig::~OpenGLShaderConfig() +{ + delete ui; +} + +void OpenGLShaderConfig::on_buttonBox_clicked(QAbstractButton *button) +{ + if (ui->buttonBox->buttonRole(button) == QDialogButtonBox::ResetRole) { + for (int i = 0; i < currentShader->num_parameters; i++) { + QDoubleSpinBox* box = this->findChild(QString(currentShader->parameters[i].id)); + if (box) { + box->setValue(currentShader->parameters[i].default_value); + } + } + } else if (ui->buttonBox->buttonRole(button) == QDialogButtonBox::ApplyRole) { + startblit(); + for (int i = 0; i < currentShader->num_parameters; i++) { + QDoubleSpinBox* box = this->findChild(QString(currentShader->parameters[i].id)); + if (box) { + float val = (float)box->value(); + currentShader->parameters[i].value = val; + } + } + glslp_write_shader_config(currentShader); + config_save(); + endblit(); + main_window->reloadAllRenderers(); + } +} + + +void OpenGLShaderConfig::on_OpenGLShaderConfig_accepted() +{ + startblit(); + for (int i = 0; i < currentShader->num_parameters; i++) { + QDoubleSpinBox* box = (QDoubleSpinBox*)this->findChild(QString(currentShader->parameters[i].id)); + if (box) { + float val = (float)box->value(); + currentShader->parameters[i].value = val; + } + } + glslp_write_shader_config(currentShader); + config_save(); + endblit(); + main_window->reloadAllRenderers(); +} + diff --git a/src/qt/qt_openglshaderconfig.hpp b/src/qt/qt_openglshaderconfig.hpp new file mode 100644 index 000000000..f71299d38 --- /dev/null +++ b/src/qt/qt_openglshaderconfig.hpp @@ -0,0 +1,40 @@ +#ifndef QT_OPENGLSHADERCONFIG_HPP +#define QT_OPENGLSHADERCONFIG_HPP + +#include +#include +#include +#include + +#include +#include + +extern "C" +{ +#include <86box/qt-glslp-parser.h> +} + +namespace Ui { +class OpenGLShaderConfig; +} + +class OpenGLShaderConfig : public QDialog { + Q_OBJECT + +public: + explicit OpenGLShaderConfig(QWidget *parent = nullptr, glslp_t* shader = nullptr); + ~OpenGLShaderConfig(); + +private slots: + void on_buttonBox_clicked(QAbstractButton *button); + + void on_OpenGLShaderConfig_accepted(); + +private: + Ui::OpenGLShaderConfig *ui; + glslp_t* currentShader; + + std::map defaultValues; +}; + +#endif // QT_OPENGLSHADERCONFIG_HPP diff --git a/src/qt/qt_openglshaderconfig.ui b/src/qt/qt_openglshaderconfig.ui new file mode 100644 index 000000000..1aebdb6f6 --- /dev/null +++ b/src/qt/qt_openglshaderconfig.ui @@ -0,0 +1,92 @@ + + + OpenGLShaderConfig + + + + 0 + 0 + 400 + 300 + + + + Shader Configuration + + + + QLayout::SizeConstraint::SetMinAndMaxSize + + + + + true + + + + + 0 + 0 + 380 + 250 + + + + + QLayout::SizeConstraint::SetMaximumSize + + + QFormLayout::FieldGrowthPolicy::AllNonFixedFieldsGrow + + + + + + + + + Qt::Orientation::Horizontal + + + QDialogButtonBox::StandardButton::Apply|QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok|QDialogButtonBox::StandardButton::Reset + + + + + + + + + buttonBox + accepted() + OpenGLShaderConfig + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + OpenGLShaderConfig + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/qt/qt_openglshadermanagerdialog.cpp b/src/qt/qt_openglshadermanagerdialog.cpp new file mode 100644 index 000000000..0bf083252 --- /dev/null +++ b/src/qt/qt_openglshadermanagerdialog.cpp @@ -0,0 +1,260 @@ +#include "qt_openglshadermanagerdialog.hpp" +#include "ui_qt_openglshadermanagerdialog.h" + +#include "qt_mainwindow.hpp" +extern MainWindow* main_window; + +#include "qt_openglshaderconfig.hpp" + +#include +#include +#include + +extern "C" { +#include <86box/86box.h> +#include <86box/plat.h> +#include <86box/video.h> +#include <86box/path.h> +#include <86box/ini.h> +#include <86box/config.h> +#include <86box/qt-glslp-parser.h> + +extern char gl3_shader_file[MAX_USER_SHADERS][512]; +} + +OpenGLShaderManagerDialog::OpenGLShaderManagerDialog(QWidget *parent) + : QDialog(parent) + , ui(new Ui::OpenGLShaderManagerDialog) +{ + ui->setupUi(this); + + ui->checkBoxVSync->setChecked(!!video_vsync); + ui->radioButtonVideoSync->setChecked(video_framerate == -1); + ui->radioButtonTargetFramerate->setChecked(video_framerate != -1); + if (video_framerate != -1) { + ui->targetFrameRate->setValue(video_framerate); + } else { + ui->targetFrameRate->setDisabled(true); + } + + for (int i = 0; i < MAX_USER_SHADERS; i++) { + if (gl3_shader_file[i][0] != 0) { + char* filename = path_get_filename(gl3_shader_file[i]); + if (filename[0] != 0) { + glslp_t* shaderfile = glslp_parse(gl3_shader_file[i]); + if (shaderfile) { + QListWidgetItem* item = new QListWidgetItem(ui->shaderListWidget); + item->setText(filename); + item->setData(Qt::UserRole + 1, QString(gl3_shader_file[i])); + item->setData(Qt::UserRole + 2, (uintptr_t)shaderfile); + } + } + } + } + if (ui->shaderListWidget->count()) { + ui->shaderListWidget->setCurrentRow(ui->shaderListWidget->count() - 1); + auto current = ui->shaderListWidget->currentItem(); + if (current) { + glslp_t* shader = (glslp_t*)current->data(Qt::UserRole + 2).toULongLong(); + if (shader->num_parameters > 0) + ui->buttonConfigure->setEnabled(true); + else + ui->buttonConfigure->setEnabled(false); + } else { + ui->buttonConfigure->setEnabled(false); + } + } else { + ui->buttonRemove->setDisabled(true); + ui->buttonMoveUp->setDisabled(true); + ui->buttonMoveDown->setDisabled(true); + ui->buttonConfigure->setDisabled(true); + } +} + +OpenGLShaderManagerDialog::~OpenGLShaderManagerDialog() +{ + for (int i = 0; i < ui->shaderListWidget->count(); i++) { + if (ui->shaderListWidget->item(i) && ui->shaderListWidget->item(i)->data(Qt::UserRole + 2).toULongLong()) { + glslp_free((glslp_t*)ui->shaderListWidget->item(i)->data(Qt::UserRole + 2).toULongLong()); + } + } + delete ui; +} + +void OpenGLShaderManagerDialog::on_buttonBox_clicked(QAbstractButton *button) +{ + if (ui->buttonBox->buttonRole(button) == QDialogButtonBox::AcceptRole) { + accept(); + } else if (ui->buttonBox->buttonRole(button) == QDialogButtonBox::RejectRole) { + reject(); + } else if (ui->buttonBox->buttonRole(button) == QDialogButtonBox::ApplyRole) { + on_OpenGLShaderManagerDialog_accepted(); + main_window->reloadAllRenderers(); + } +} + + +void OpenGLShaderManagerDialog::on_buttonMoveUp_clicked() +{ + if (ui->shaderListWidget->currentRow() == 0) + return; + + int row = ui->shaderListWidget->currentRow(); + auto item = ui->shaderListWidget->takeItem(row); + ui->shaderListWidget->insertItem(row - 1, item); + ui->shaderListWidget->setCurrentItem(item); +} + + +void OpenGLShaderManagerDialog::on_shaderListWidget_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous) +{ + if (current == nullptr) { + ui->buttonRemove->setDisabled(true); + ui->buttonMoveUp->setDisabled(true); + ui->buttonMoveDown->setDisabled(true); + ui->buttonConfigure->setDisabled(true); + return; + } else { + ui->buttonRemove->setDisabled(false); + ui->buttonConfigure->setDisabled(true); + if (current) { + glslp_t* shader = (glslp_t*)current->data(Qt::UserRole + 2).toULongLong(); + if (shader->num_parameters > 0) + ui->buttonConfigure->setEnabled(true); + } + } + ui->buttonMoveUp->setDisabled(ui->shaderListWidget->currentRow() == 0); + ui->buttonMoveDown->setDisabled(ui->shaderListWidget->currentRow() == (ui->shaderListWidget->count() - 1)); +} + + +void OpenGLShaderManagerDialog::on_shaderListWidget_currentRowChanged(int currentRow) +{ + auto current = ui->shaderListWidget->currentItem(); + if (current == nullptr) { + ui->buttonRemove->setDisabled(true); + ui->buttonMoveUp->setDisabled(true); + ui->buttonMoveDown->setDisabled(true); + ui->buttonConfigure->setDisabled(true); + return; + } else { + ui->buttonRemove->setDisabled(false); + ui->buttonConfigure->setDisabled(true); + if (current) { + glslp_t* shader = (glslp_t*)current->data(Qt::UserRole + 2).toULongLong(); + if (shader->num_parameters > 0) + ui->buttonConfigure->setEnabled(true); + } + } + ui->buttonMoveUp->setDisabled(ui->shaderListWidget->currentRow() == 0); + ui->buttonMoveDown->setDisabled(ui->shaderListWidget->currentRow() == (ui->shaderListWidget->count() - 1)); +} + + +void OpenGLShaderManagerDialog::on_buttonMoveDown_clicked() +{ + if (ui->shaderListWidget->currentRow() == (ui->shaderListWidget->count() - 1)) + return; + + int row = ui->shaderListWidget->currentRow(); + auto item = ui->shaderListWidget->takeItem(row); + ui->shaderListWidget->insertItem(row + 1, item); + ui->shaderListWidget->setCurrentItem(item); +} + + +void OpenGLShaderManagerDialog::on_buttonAdd_clicked() +{ + auto res = QFileDialog::getOpenFileName(this, QString(), QString(), "GLSL Shaders (*.glslp *.glsl);;All files (*.*)"); + if (!res.isEmpty()) { + auto glslp_file = res.toUtf8(); + glslp_t* shaderfile = glslp_parse(glslp_file.data()); + if (shaderfile) { + auto filename = path_get_filename(glslp_file.data()); + QListWidgetItem* item = new QListWidgetItem(ui->shaderListWidget); + item->setText(filename); + item->setData(Qt::UserRole + 1, res); + item->setData(Qt::UserRole + 2, (uintptr_t)shaderfile); + if (ui->shaderListWidget->count()) { + ui->shaderListWidget->setCurrentRow(ui->shaderListWidget->count() - 1); + } + } else { + QMessageBox::critical(this, tr("GLSL error"), tr("Could not load filename %1").arg(res)); + } + } +} + + +void OpenGLShaderManagerDialog::on_buttonRemove_clicked() +{ + if (ui->shaderListWidget->currentItem()) { + auto item = ui->shaderListWidget->takeItem(ui->shaderListWidget->currentRow()); + + if (item->data(Qt::UserRole + 2).toULongLong()) { + glslp_free((glslp_t*)item->data(Qt::UserRole + 2).toULongLong()); + } + delete item; + + on_shaderListWidget_currentRowChanged(ui->shaderListWidget->currentRow()); + } +} + +void OpenGLShaderManagerDialog::on_OpenGLShaderManagerDialog_accepted() +{ + memset(gl3_shader_file, 0, sizeof(gl3_shader_file)); + for (int i = 0; i < ui->shaderListWidget->count(); i++) { + strncpy(gl3_shader_file[i], ui->shaderListWidget->item(i)->data(Qt::UserRole + 1).toString().toUtf8(), 512); + } + startblit(); + video_vsync = ui->checkBoxVSync->isChecked(); + if (ui->radioButtonTargetFramerate->isChecked()) { + video_framerate = ui->horizontalSliderFramerate->value(); + } else { + video_framerate = -1; + } + config_save(); + endblit(); +} + + +void OpenGLShaderManagerDialog::on_buttonConfigure_clicked() +{ + auto item = ui->shaderListWidget->currentItem(); + if (item) { + glslp_t* shader = (glslp_t*)item->data(Qt::UserRole + 2).toULongLong(); + + auto configDialog = new OpenGLShaderConfig(this, shader); + configDialog->exec(); + } +} + + +void OpenGLShaderManagerDialog::on_radioButtonVideoSync_clicked() +{ + ui->targetFrameRate->setDisabled(true); +} + + +void OpenGLShaderManagerDialog::on_radioButtonTargetFramerate_clicked() +{ + ui->targetFrameRate->setDisabled(false); +} + + +void OpenGLShaderManagerDialog::on_horizontalSliderFramerate_sliderMoved(int position) +{ + (void)position; + + if (ui->horizontalSliderFramerate->value() != ui->targetFrameRate->value()) + ui->targetFrameRate->setValue(ui->horizontalSliderFramerate->value()); +} + + +void OpenGLShaderManagerDialog::on_targetFrameRate_valueChanged(int arg1) +{ + (void)arg1; + + if (ui->horizontalSliderFramerate->value() != ui->targetFrameRate->value()) + ui->horizontalSliderFramerate->setValue(ui->targetFrameRate->value()); +} + diff --git a/src/qt/qt_openglshadermanagerdialog.hpp b/src/qt/qt_openglshadermanagerdialog.hpp new file mode 100644 index 000000000..a9f7ad3a9 --- /dev/null +++ b/src/qt/qt_openglshadermanagerdialog.hpp @@ -0,0 +1,50 @@ +#ifndef QT_OPENGLSHADERMANAGERDIALOG_H +#define QT_OPENGLSHADERMANAGERDIALOG_H + +#include +#include +#include + +namespace Ui { +class OpenGLShaderManagerDialog; +} + +class OpenGLShaderManagerDialog : public QDialog { + Q_OBJECT + +public: + explicit OpenGLShaderManagerDialog(QWidget *parent = nullptr); + ~OpenGLShaderManagerDialog(); + +private slots: + void on_buttonBox_clicked(QAbstractButton *button); + + void on_buttonMoveUp_clicked(); + + void on_shaderListWidget_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous); + + void on_shaderListWidget_currentRowChanged(int currentRow); + + void on_buttonMoveDown_clicked(); + + void on_buttonAdd_clicked(); + + void on_buttonRemove_clicked(); + + void on_OpenGLShaderManagerDialog_accepted(); + + void on_buttonConfigure_clicked(); + + void on_radioButtonVideoSync_clicked(); + + void on_radioButtonTargetFramerate_clicked(); + + void on_horizontalSliderFramerate_sliderMoved(int position); + + void on_targetFrameRate_valueChanged(int arg1); + +private: + Ui::OpenGLShaderManagerDialog *ui; +}; + +#endif // QT_OPENGLSHADERMANAGERDIALOG_H diff --git a/src/qt/qt_openglshadermanagerdialog.ui b/src/qt/qt_openglshadermanagerdialog.ui new file mode 100644 index 000000000..2a72c69ed --- /dev/null +++ b/src/qt/qt_openglshadermanagerdialog.ui @@ -0,0 +1,204 @@ + + + OpenGLShaderManagerDialog + + + + 0 + 0 + 400 + 465 + + + + Shader Manager + + + + QLayout::SizeConstraint::SetFixedSize + + + + + Shaders + + + + QLayout::SizeConstraint::SetFixedSize + + + + + QAbstractItemView::DragDropMode::InternalMove + + + QAbstractItemView::SelectionBehavior::SelectItems + + + + + + + QLayout::SizeConstraint::SetFixedSize + + + + + Add + + + + + + + Remove + + + + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + + + + + true + + + Configure + + + + + + + Move up + + + + + + + Move down + + + + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + + + + + Qt::Orientation::Vertical + + + QDialogButtonBox::StandardButton::Apply|QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok + + + false + + + + + + + + + + + + Render behavior + + + + QLayout::SizeConstraint::SetDefaultConstraint + + + + + Use target framerate: + + + + + + + 15 + + + 240 + + + 60 + + + Qt::Orientation::Horizontal + + + false + + + false + + + + + + + Synchronize with video + + + true + + + + + + + VSync + + + + + + + fps + + + 15 + + + 240 + + + 60 + + + + + + + + + + + diff --git a/src/qt/qt_platform.cpp b/src/qt/qt_platform.cpp index 561c94d8a..35dbc0081 100644 --- a/src/qt/qt_platform.cpp +++ b/src/qt/qt_platform.cpp @@ -385,6 +385,7 @@ plat_munmap(void *ptr, size_t size) #endif } +extern bool cpu_thread_running; void plat_pause(int p) { @@ -392,6 +393,10 @@ plat_pause(int p) wchar_t title[1024]; wchar_t paused_msg[512]; + if (!cpu_thread_running && p == 1) { + p = 2; + } + if ((!!p) == dopause) { #ifdef Q_OS_WINDOWS if (source_hwnd) diff --git a/src/qt/qt_renderercommon.hpp b/src/qt/qt_renderercommon.hpp index af72474c7..f3f5d2223 100644 --- a/src/qt/qt_renderercommon.hpp +++ b/src/qt/qt_renderercommon.hpp @@ -34,6 +34,8 @@ public: virtual QDialog *getOptions(QWidget *parent) { return nullptr; } /* Reloads options of renderer */ virtual void reloadOptions() { } + /* Make the renderer reload itself */ + virtual bool reloadRendererOption() { return false; } int r_monitor_index = 0; diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index 8c31da2b2..ca16b680e 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -337,6 +337,26 @@ RendererStack::createRenderer(Renderer renderer) current.reset(this->createWindowContainer(hw, this)); break; } + case Renderer::OpenGL3PCem: + { + this->createWinId(); + auto hw = new OpenGLRenderer(this); + rendererWindow = hw; + connect(this, &RendererStack::blitToRenderer, hw, &OpenGLRenderer::onBlit, Qt::QueuedConnection); + connect(hw, &OpenGLRenderer::initialized, [=]() { + /* Buffers are available only after initialization. */ + imagebufs = rendererWindow->getBuffers(); + endblit(); + emit rendererChanged(); + }); + connect(hw, &OpenGLRenderer::errorInitializing, [=]() { + /* Renderer not could initialize, fallback to software. */ + imagebufs = {}; + QTimer::singleShot(0, this, [this]() { switchRenderer(Renderer::Software); }); + }); + current.reset(this->createWindowContainer(hw, this)); + break; + } case Renderer::OpenGL3: { this->createWinId(); @@ -406,7 +426,7 @@ RendererStack::createRenderer(Renderer renderer) currentBuf = 0; - if (renderer != Renderer::OpenGL3 && renderer != Renderer::Vulkan) { + if (renderer != Renderer::OpenGL3 && renderer != Renderer::Vulkan && renderer != Renderer::OpenGL3PCem) { imagebufs = rendererWindow->getBuffers(); endblit(); emit rendererChanged(); diff --git a/src/qt/qt_rendererstack.hpp b/src/qt/qt_rendererstack.hpp index 5a08b351c..32ed5f7ca 100644 --- a/src/qt/qt_rendererstack.hpp +++ b/src/qt/qt_rendererstack.hpp @@ -59,6 +59,7 @@ public: OpenGLES, OpenGL3, Vulkan, + OpenGL3PCem = 6, None = -1 }; void switchRenderer(Renderer renderer); @@ -69,6 +70,8 @@ public: void reloadOptions() const { return rendererWindow->reloadOptions(); } /* Returns options dialog for current renderer */ QDialog *getOptions(QWidget *parent) { return rendererWindow ? rendererWindow->getOptions(parent) : nullptr; } + /* Reload the renderer itself */ + bool reloadRendererOption() { return rendererWindow ? rendererWindow->reloadRendererOption() : false; } void setFocusRenderer(); void onResize(int width, int height); diff --git a/src/qt/qt_settingssound.cpp b/src/qt/qt_settingssound.cpp index e0572c3d8..cca903076 100644 --- a/src/qt/qt_settingssound.cpp +++ b/src/qt/qt_settingssound.cpp @@ -50,13 +50,15 @@ void SettingsSound::save() { for (uint8_t i = 0; i < SOUND_CARD_MAX; ++i) { - auto *cbox = findChild(QString("comboBoxSoundCard%1").arg(i + 1)); - sound_card_current[i] = cbox->currentData().toInt(); + QComboBox *cbox = findChild(QString("comboBoxSoundCard%1").arg(i + 1)); + sound_card_current[i] = cbox->currentData().toInt(); } midi_output_device_current = ui->comboBoxMidiOut->currentData().toInt(); - midi_input_device_current = ui->comboBoxMidiIn->currentData().toInt(); - mpu401_standalone_enable = ui->checkBoxMPU401->isChecked() ? 1 : 0; + + midi_input_device_current = ui->comboBoxMidiIn->currentData().toInt(); + + mpu401_standalone_enable = ui->checkBoxMPU401->isChecked() ? 1 : 0; sound_is_float = ui->checkBoxFloat32->isChecked() ? 1 : 0; @@ -74,12 +76,13 @@ SettingsSound::onCurrentMachineChanged(const int machineId) int c; int selectedRow; + // Sound Card for (uint8_t i = 0; i < SOUND_CARD_MAX; ++i) { - auto * cbox = findChild(QString("comboBoxSoundCard%1").arg(i + 1)); - auto * model = cbox->model(); - const auto removeRows = model->rowCount(); - c = 0; - selectedRow = 0; + QComboBox *cbox = findChild(QString("comboBoxSoundCard%1").arg(i + 1)); + c = 0; + auto model = cbox->model(); + auto removeRows = model->rowCount(); + selectedRow = 0; while (true) { /* Skip "internal" if machine doesn't have it or this is not the primary card. */ @@ -88,17 +91,21 @@ SettingsSound::onCurrentMachineChanged(const int machineId) continue; } - auto name = DeviceConfig::DeviceName(sound_card_getdevice(c), sound_card_get_internal_name(c), 1); + const QString name = DeviceConfig::DeviceName(sound_card_getdevice(c), sound_card_get_internal_name(c), 1); if (name.isEmpty()) { break; } - if (sound_card_available(c) && device_is_valid(sound_card_getdevice(c), machineId)) { - int row = Models::AddEntry(model, name, c); - if (c == sound_card_current[i]) { - selectedRow = row - removeRows; + if (sound_card_available(c)) { + const device_t *sound_dev = sound_card_getdevice(c); + if (device_is_valid(sound_dev, machineId)) { + int row = Models::AddEntry(model, name, c); + if (c == sound_card_current[i]) { + selectedRow = row - removeRows; + } } } + c++; } @@ -108,12 +115,14 @@ SettingsSound::onCurrentMachineChanged(const int machineId) cbox->setCurrentIndex(selectedRow); } - auto model = ui->comboBoxMidiOut->model(); - auto removeRows = model->rowCount(); - c = 0; - selectedRow = 0; + // Midi Out + c = 0; + auto model = ui->comboBoxMidiOut->model(); + auto removeRows = model->rowCount(); + selectedRow = 0; + while (true) { - QString name = DeviceConfig::DeviceName(midi_out_device_getdevice(c), midi_out_device_get_internal_name(c), 0); + const QString name = DeviceConfig::DeviceName(midi_out_device_getdevice(c), midi_out_device_get_internal_name(c), 0); if (name.isEmpty()) { break; } @@ -124,19 +133,23 @@ SettingsSound::onCurrentMachineChanged(const int machineId) selectedRow = row - removeRows; } } + c++; } + model->removeRows(0, removeRows); ui->comboBoxMidiOut->setEnabled(model->rowCount() > 0); ui->comboBoxMidiOut->setCurrentIndex(-1); ui->comboBoxMidiOut->setCurrentIndex(selectedRow); + // Midi In + c = 0; model = ui->comboBoxMidiIn->model(); removeRows = model->rowCount(); - c = 0; selectedRow = 0; + while (true) { - QString name = DeviceConfig::DeviceName(midi_in_device_getdevice(c), midi_in_device_get_internal_name(c), 0); + const QString name = DeviceConfig::DeviceName(midi_in_device_getdevice(c), midi_in_device_get_internal_name(c), 0); if (name.isEmpty()) { break; } @@ -150,14 +163,19 @@ SettingsSound::onCurrentMachineChanged(const int machineId) c++; } + model->removeRows(0, removeRows); ui->comboBoxMidiIn->setEnabled(model->rowCount() > 0); ui->comboBoxMidiIn->setCurrentIndex(-1); ui->comboBoxMidiIn->setCurrentIndex(selectedRow); + // Standalone MPU401 ui->checkBoxMPU401->setChecked(mpu401_standalone_enable > 0); + + // Float32 Sound ui->checkBoxFloat32->setChecked(sound_is_float > 0); + // FM Driver switch (fm_driver) { case FM_DRV_YMFM: ui->radioButtonYMFM->setChecked(true); @@ -193,6 +211,7 @@ SettingsSound::on_comboBoxSoundCard1_currentIndexChanged(int index) return; } int sndCard = ui->comboBoxSoundCard1->currentData().toInt(); + if (sndCard == SOUND_INTERNAL) ui->pushButtonConfigureSoundCard1->setEnabled(machine_has_flags(machineId, MACHINE_SOUND) && device_has_config(machine_get_snd_device(machineId))); @@ -203,8 +222,9 @@ SettingsSound::on_comboBoxSoundCard1_currentIndexChanged(int index) void SettingsSound::on_pushButtonConfigureSoundCard1_clicked() { - int sndCard = ui->comboBoxSoundCard1->currentData().toInt(); - auto *device = sound_card_getdevice(sndCard); + int sndCard = ui->comboBoxSoundCard1->currentData().toInt(); + auto *device = sound_card_getdevice(sndCard); + if (sndCard == SOUND_INTERNAL) device = machine_get_snd_device(machineId); DeviceConfig::ConfigureDevice(device, 1, qobject_cast(Settings::settings)); @@ -216,15 +236,17 @@ SettingsSound::on_comboBoxSoundCard2_currentIndexChanged(int index) if (index < 0) { return; } + int sndCard = ui->comboBoxSoundCard2->currentData().toInt(); + ui->pushButtonConfigureSoundCard2->setEnabled(sound_card_has_config(sndCard)); } void SettingsSound::on_pushButtonConfigureSoundCard2_clicked() { - int sndCard = ui->comboBoxSoundCard2->currentData().toInt(); - auto *device = sound_card_getdevice(sndCard); + int sndCard = ui->comboBoxSoundCard2->currentData().toInt(); + const device_t *device = sound_card_getdevice(sndCard); DeviceConfig::ConfigureDevice(device, 2, qobject_cast(Settings::settings)); } @@ -234,15 +256,18 @@ SettingsSound::on_comboBoxSoundCard3_currentIndexChanged(int index) if (index < 0) { return; } + int sndCard = ui->comboBoxSoundCard3->currentData().toInt(); + ui->pushButtonConfigureSoundCard3->setEnabled(sound_card_has_config(sndCard)); } void SettingsSound::on_pushButtonConfigureSoundCard3_clicked() { - int sndCard = ui->comboBoxSoundCard3->currentData().toInt(); - auto *device = sound_card_getdevice(sndCard); + int sndCard = ui->comboBoxSoundCard3->currentData().toInt(); + const device_t *device = sound_card_getdevice(sndCard); + DeviceConfig::ConfigureDevice(device, 3, qobject_cast(Settings::settings)); } @@ -252,15 +277,18 @@ SettingsSound::on_comboBoxSoundCard4_currentIndexChanged(int index) if (index < 0) { return; } + int sndCard = ui->comboBoxSoundCard4->currentData().toInt(); + ui->pushButtonConfigureSoundCard4->setEnabled(sound_card_has_config(sndCard)); } void SettingsSound::on_pushButtonConfigureSoundCard4_clicked() { - int sndCard = ui->comboBoxSoundCard4->currentData().toInt(); - auto *device = sound_card_getdevice(sndCard); + int sndCard = ui->comboBoxSoundCard4->currentData().toInt(); + const device_t *device = sound_card_getdevice(sndCard); + DeviceConfig::ConfigureDevice(device, 4, qobject_cast(Settings::settings)); } @@ -270,6 +298,7 @@ SettingsSound::on_comboBoxMidiOut_currentIndexChanged(int index) if (index < 0) { return; } + ui->pushButtonConfigureMidiOut->setEnabled(midi_out_device_has_config(ui->comboBoxMidiOut->currentData().toInt())); ui->checkBoxMPU401->setEnabled(allowMpu401(ui) && (machine_has_bus(machineId, MACHINE_BUS_ISA) || machine_has_bus(machineId, MACHINE_BUS_MCA))); ui->pushButtonConfigureMPU401->setEnabled(allowMpu401(ui) && ui->checkBoxMPU401->isChecked()); @@ -288,6 +317,7 @@ SettingsSound::on_comboBoxMidiIn_currentIndexChanged(int index) if (index < 0) { return; } + ui->pushButtonConfigureMidiIn->setEnabled(midi_in_device_has_config(ui->comboBoxMidiIn->currentData().toInt())); ui->checkBoxMPU401->setEnabled(allowMpu401(ui) && (machine_has_bus(machineId, MACHINE_BUS_ISA) || machine_has_bus(machineId, MACHINE_BUS_MCA))); ui->pushButtonConfigureMPU401->setEnabled(allowMpu401(ui) && ui->checkBoxMPU401->isChecked()); diff --git a/src/qt/qt_settingsstoragecontrollers.cpp b/src/qt/qt_settingsstoragecontrollers.cpp index a86362909..4adfe1546 100644 --- a/src/qt/qt_settingsstoragecontrollers.cpp +++ b/src/qt/qt_settingsstoragecontrollers.cpp @@ -52,8 +52,8 @@ void SettingsStorageControllers::save() { /* Storage devices category */ - for (int i = 0; i < SCSI_CARD_MAX; ++i) { - auto *cbox = findChild(QString("comboBoxSCSI%1").arg(i + 1)); + for (uint8_t i = 0; i < SCSI_CARD_MAX; ++i) { + QComboBox *cbox = findChild(QString("comboBoxSCSI%1").arg(i + 1)); scsi_card_current[i] = cbox->currentData().toInt(); } hdc_current[0] = ui->comboBoxHD->currentData().toInt(); @@ -71,10 +71,11 @@ SettingsStorageControllers::onCurrentMachineChanged(int machineId) this->machineId = machineId; /*HD controller config*/ + int c = 0; auto *model = ui->comboBoxHD->model(); auto removeRows = model->rowCount(); - int c = 0; int selectedRow = 0; + while (true) { /* Skip "internal" if machine doesn't have it. */ if ((c == 1) && (machine_has_flags(machineId, MACHINE_HDC) == 0)) { @@ -88,7 +89,7 @@ SettingsStorageControllers::onCurrentMachineChanged(int machineId) } if (hdc_available(c)) { - auto *hdc_dev = hdc_get_device(c); + const device_t *hdc_dev = hdc_get_device(c); if (device_is_valid(hdc_dev, machineId)) { int row = Models::AddEntry(model, name, c); @@ -124,7 +125,7 @@ SettingsStorageControllers::onCurrentMachineChanged(int machineId) } if (fdc_card_available(c)) { - auto *fdc_dev = fdc_card_getdevice(c); + const device_t *fdc_dev = fdc_card_getdevice(c); if (device_is_valid(fdc_dev, machineId)) { int row = Models::AddEntry(model, name, c); @@ -141,10 +142,11 @@ SettingsStorageControllers::onCurrentMachineChanged(int machineId) ui->comboBoxFD->setCurrentIndex(selectedRow); /*CD interface controller config*/ - model = ui->comboBoxCDInterface->model(); - removeRows = model->rowCount(); - c = 0; + c = 0; + model = ui->comboBoxCDInterface->model(); + removeRows = model->rowCount(); selectedRow = 0; + while (true) { /* Skip "internal" if machine doesn't have it. */ QString name = DeviceConfig::DeviceName(cdrom_interface_get_device(c), cdrom_interface_get_internal_name(c), 1); @@ -153,7 +155,7 @@ SettingsStorageControllers::onCurrentMachineChanged(int machineId) } if (cdrom_interface_available(c)) { - auto *cdrom_interface_dev = cdrom_interface_get_device(c); + const device_t *cdrom_interface_dev = cdrom_interface_get_device(c); if (device_is_valid(cdrom_interface_dev, machineId)) { int row = Models::AddEntry(model, name, c); @@ -169,21 +171,21 @@ SettingsStorageControllers::onCurrentMachineChanged(int machineId) ui->comboBoxCDInterface->setCurrentIndex(-1); ui->comboBoxCDInterface->setCurrentIndex(selectedRow); - for (int i = 0; i < SCSI_CARD_MAX; ++i) { - auto *cbox = findChild(QString("comboBoxSCSI%1").arg(i + 1)); - model = cbox->model(); - removeRows = model->rowCount(); - c = 0; - selectedRow = 0; + for (uint8_t i = 0; i < SCSI_CARD_MAX; ++i) { + QComboBox *cbox = findChild(QString("comboBoxSCSI%1").arg(i + 1)); + c = 0; + model = cbox->model(); + removeRows = model->rowCount(); + selectedRow = 0; while (true) { - auto name = DeviceConfig::DeviceName(scsi_card_getdevice(c), scsi_card_get_internal_name(c), 1); + QString name = DeviceConfig::DeviceName(scsi_card_getdevice(c), scsi_card_get_internal_name(c), 1); if (name.isEmpty()) { break; } if (scsi_card_available(c)) { - auto *scsi_dev = scsi_card_getdevice(c); + const device_t *scsi_dev = scsi_card_getdevice(c); if (device_is_valid(scsi_dev, machineId)) { int row = Models::AddEntry(model, name, c); if (c == scsi_card_current[i]) { @@ -236,7 +238,8 @@ SettingsStorageControllers::on_comboBoxFD_currentIndexChanged(int index) ui->pushButtonFD->setEnabled(hdc_has_config(ui->comboBoxFD->currentData().toInt()) > 0); } -void SettingsStorageControllers::on_comboBoxCDInterface_currentIndexChanged(int index) +void +SettingsStorageControllers::on_comboBoxCDInterface_currentIndexChanged(int index) { if (index < 0) { return; @@ -346,14 +349,14 @@ SettingsStorageControllers::on_pushButtonSCSI4_clicked() DeviceConfig::ConfigureDevice(scsi_card_getdevice(ui->comboBoxSCSI4->currentData().toInt()), 4, qobject_cast(Settings::settings)); } -void SettingsStorageControllers::on_checkBoxLbaEnhancer_stateChanged(int arg1) +void +SettingsStorageControllers::on_checkBoxLbaEnhancer_stateChanged(int arg1) { ui->pushButtonConfigureLbaEnhancer->setEnabled(arg1 != 0); } - -void SettingsStorageControllers::on_pushButtonConfigureLbaEnhancer_clicked() +void +SettingsStorageControllers::on_pushButtonConfigureLbaEnhancer_clicked() { DeviceConfig::ConfigureDevice(&lba_enhancer_device); } - diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index c505d9f53..eed57c63b 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -373,7 +373,7 @@ scsi_cdrom_mode_sense_load(scsi_cdrom_t *dev) if (fp) { if (fread(dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE], 1, 0x10, fp) != 0x10) log_fatal(dev->log, "scsi_cdrom_mode_sense_load(): Error reading data\n"); - (void) fread(dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE_SONY], 1, + (void) !fread(dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE_SONY], 1, 0x10, fp); fclose(fp); } diff --git a/src/scsi/scsi_t128.c b/src/scsi/scsi_t128.c index 6b73ae131..eada27246 100644 --- a/src/scsi/scsi_t128.c +++ b/src/scsi/scsi_t128.c @@ -95,7 +95,7 @@ t128_write(uint32_t addr, uint8_t val, void *priv) t128->status, scsi_bus->period, timer_is_enabled(&t128->timer), t128->block_loaded); t128->status &= ~0x04; - timer_on_auto(&t128->timer, 1.0); + timer_on_auto(&t128->timer, 10.0); } } } @@ -147,7 +147,7 @@ t128_read(uint32_t addr, void *priv) scsi_bus->tx_mode = PIO_TX_BUS; timer_stop(&t128->timer); } else if (!timer_is_enabled(&t128->timer)) - timer_on_auto(&t128->timer, 1.0); + timer_on_auto(&t128->timer, 10.0); else t128->status &= ~0x04; } @@ -223,7 +223,7 @@ t128_dma_initiator_receive_ext(void *priv, void *ext_priv) t128->block_loaded = 1; t128->status &= ~0x04; - timer_on_auto(&t128->timer, 1.0); + timer_on_auto(&t128->timer, 10.0); } return 1; } @@ -252,7 +252,7 @@ t128_callback(void *priv) uint8_t status; if (scsi_bus->tx_mode != PIO_TX_BUS) - timer_on_auto(&t128->timer, scsi_bus->period / 65.0); + timer_on_auto(&t128->timer, scsi_bus->period / 60.0); if (scsi_bus->data_wait & 1) { scsi_bus->clear_req = 3; @@ -350,6 +350,7 @@ t128_callback(void *priv) if (!t128->block_count) { t128->block_loaded = 0; scsi_bus->bus_out |= BUS_REQ; + timer_on_auto(&t128->timer, 10.0); t128_log("IO End of read transfer\n"); } break; @@ -576,6 +577,10 @@ static const device_config_t t128_config[] = { { .description = "IRQ 3", .value = 3 }, { .description = "IRQ 5", .value = 5 }, { .description = "IRQ 7", .value = 7 }, + { .description = "IRQ 10", .value = 10 }, + { .description = "IRQ 12", .value = 12 }, + { .description = "IRQ 14", .value = 14 }, + { .description = "IRQ 15", .value = 15 }, { .description = "" } }, .bios = { { 0 } } diff --git a/src/sound/snd_pas16.c b/src/sound/snd_pas16.c index 353f9a3d5..675582367 100644 --- a/src/sound/snd_pas16.c +++ b/src/sound/snd_pas16.c @@ -789,6 +789,10 @@ pas16_in(uint16_t port, void *priv) scsi_bus = &pas16->scsi->ncr.scsibus; /* Bits 0-6 must absolutely be set for SCSI hard disk drivers to work. */ ret = (((scsi_bus->tx_mode != PIO_TX_BUS) && (pas16->scsi->status & 0x04)) << 7) | 0x7f; + if ((scsi_bus->tx_mode == PIO_TX_BUS) && !(ret & 0x80)) + ret |= 0x80; + + pas16_log("5C01 read ret=%02x, status=%02x, txmode=%x.\n", ret, pas16->scsi->status & 0x06, scsi_bus->tx_mode); } break; case 0x5c03: @@ -1190,6 +1194,7 @@ pas16_scsi_callback(void *priv) t128_callback(pas16->scsi); + pas16_log("TimeOutStatus=%02x, t128stat=%02x.\n", pas16->timeout_status, dev->status); if ((scsi_bus->tx_mode != PIO_TX_BUS) && (dev->status & 0x04)) { timer_stop(&pas16->scsi_timer); pas16->timeout_status &= 0x7f; diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index 689d0b91e..e89946486 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -1727,6 +1727,7 @@ ess_mixer_read(uint16_t addr, void *priv) case 0x32: case 0x36: case 0x38: + case 0x3a: case 0x3e: ret = mixer->regs[mixer->index]; break; @@ -2593,10 +2594,10 @@ ess_soundpiper_mca_write(const int port, const uint8_t val, void *priv) ess->dsp.sb_addr = 0x0000; break; case 0x08: - ess->dsp.sb_addr = 0x0240; + ess->dsp.sb_addr = 0x0220; break; case 0x0c: - ess->dsp.sb_addr = 0x0220; + ess->dsp.sb_addr = 0x0240; break; } @@ -2750,64 +2751,59 @@ ess_chipchat_mca_write(int port, uint8_t val, void *priv) ess->pos_regs[port & 7] = val; - if (ess->pos_regs[2] & 1) { - ess->dsp.sb_addr = (ess->pos_regs[2] == 0x51) ? 0x0220 : 0x0000; + if (ess->pos_regs[2] & 0x01) { + ess->dsp.sb_addr = 0x0220; - if (ess->dsp.sb_addr != 0x0000) { - io_sethandler(ess->dsp.sb_addr, 0x0004, - ess->opl.read, NULL, NULL, - ess->opl.write, NULL, NULL, - ess->opl.priv); - io_sethandler(ess->dsp.sb_addr + 8, 0x0002, - ess->opl.read, NULL, NULL, - ess->opl.write, NULL, NULL, - ess->opl.priv); - io_sethandler(ess->dsp.sb_addr + 8, 0x0002, + io_sethandler(ess->dsp.sb_addr, 0x0004, + ess->opl.read, NULL, NULL, + ess->opl.write, NULL, NULL, + ess->opl.priv); + io_sethandler(ess->dsp.sb_addr + 8, 0x0002, + ess->opl.read, NULL, NULL, + ess->opl.write, NULL, NULL, + ess->opl.priv); + io_sethandler(ess->dsp.sb_addr + 8, 0x0002, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); + io_sethandler(0x0388, 0x0004, + ess->opl.read, NULL, NULL, + ess->opl.write, NULL, NULL, ess->opl.priv); + io_sethandler(0x0388, 0x0004, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); + io_sethandler(ess->dsp.sb_addr + 4, 0x0002, + ess_mixer_read, NULL, NULL, + ess_mixer_write, NULL, NULL, + ess); + + io_sethandler(ess->dsp.sb_addr + 2, 0x0004, + ess_base_read, NULL, NULL, + ess_base_write, NULL, NULL, + ess); + io_sethandler(ess->dsp.sb_addr + 6, 0x0001, + ess_base_read, NULL, NULL, + ess_base_write, NULL, NULL, + ess); + io_sethandler(ess->dsp.sb_addr + 0x0a, 0x0006, + ess_base_read, NULL, NULL, + ess_base_write, NULL, NULL, + ess); + + if (ess->dsp.sb_subtype == SB_SUBTYPE_ESS_ES1688) { + mpu401_change_addr(ess->mpu, 0x0330); + + io_sethandler(0x0330, 0x0002, ess_fm_midi_read, NULL, NULL, ess_fm_midi_write, NULL, NULL, ess); - io_sethandler(0x0388, 0x0004, - ess->opl.read, NULL, NULL, - ess->opl.write, NULL, NULL, ess->opl.priv); - io_sethandler(0x0388, 0x0004, - ess_fm_midi_read, NULL, NULL, - ess_fm_midi_write, NULL, NULL, - ess); - io_sethandler(ess->dsp.sb_addr + 4, 0x0004, - ess_mixer_read, NULL, NULL, - ess_mixer_write, NULL, NULL, - ess); - - io_sethandler(ess->dsp.sb_addr + 2, 0x0004, - ess_base_read, NULL, NULL, - ess_base_write, NULL, NULL, - ess); - io_sethandler(ess->dsp.sb_addr + 6, 0x0001, - ess_base_read, NULL, NULL, - ess_base_write, NULL, NULL, - ess); - io_sethandler(ess->dsp.sb_addr + 0x0a, 0x0006, - ess_base_read, NULL, NULL, - ess_base_write, NULL, NULL, - ess); - - if (ess->dsp.sb_subtype == SB_SUBTYPE_ESS_ES1688) { - mpu401_change_addr(ess->mpu, (ess->pos_regs[2] == 0x51) ? 0x0330 : 0); - - if (ess->pos_regs[2] == 0x51) - io_sethandler(0x0330, 0x0002, - ess_fm_midi_read, NULL, NULL, - ess_fm_midi_write, NULL, NULL, - ess); - } } /* DSP I/O handler is activated in sb_dsp_setaddr */ sb_dsp_setaddr(&ess->dsp, ess->dsp.sb_addr); - gameport_remap(ess->gameport, (ess->pos_regs[2] == 0x51) ? 0x200 : 0); - } + gameport_remap(ess->gameport, 0x0200); - if (ess->pos_regs[2] == 0x51) { sb_dsp_setirq(&ess->dsp, 7); mpu401_setirq(ess->mpu, 7); diff --git a/src/sound/snd_sb_dsp.c b/src/sound/snd_sb_dsp.c index 9ce0b9fb7..10e5601f4 100644 --- a/src/sound/snd_sb_dsp.c +++ b/src/sound/snd_sb_dsp.c @@ -388,6 +388,7 @@ sb_update_status(sb_dsp_t *dsp, int bit, int set) { int masked = 0; + sb_dsp_log("SBIRQ8=%d, irqnum=%d, bit=%x, set=%x.\n", dsp->sb_irq8, dsp->sb_irqnum, bit, set); if (dsp->sb_irq8 || dsp->sb_irq16) return; @@ -423,6 +424,7 @@ sb_update_status(sb_dsp_t *dsp, int bit, int set) } } + sb_dsp_log("Masked=%02x.\n", masked); if (set && !masked) dsp->irq_update(dsp->irq_priv, 1); else if (!set) @@ -1039,6 +1041,8 @@ sb_ess_write_reg(sb_dsp_t *dsp, const uint8_t reg, uint8_t data) { uint8_t chg; + sb_dsp_log("ESS Write reg=%02x, val=%02x.\n", reg, data); + switch (reg) { case 0xA1: /* Extended Mode Sample Rate Generator */ { @@ -1110,6 +1114,7 @@ sb_ess_write_reg(sb_dsp_t *dsp, const uint8_t reg, uint8_t data) dsp->sb_irqnum = 10; break; } + sb_dsp_log("Legacy Audio IRQ control=%d.\n", dsp->sb_irqnum); sb_ess_update_irq_drq_readback_regs(dsp, false); break; case 0xB2: /* DRQ Control */ @@ -1131,6 +1136,7 @@ sb_ess_write_reg(sb_dsp_t *dsp, const uint8_t reg, uint8_t data) dsp->sb_8_dmanum = 3; break; } + sb_dsp_log("Legacy Audio DRQ control=%d, chg=%02x.\n", dsp->sb_8_dmanum, chg); sb_ess_update_irq_drq_readback_regs(dsp, false); if (chg & 0x40) sb_ess_update_dma_status(dsp); @@ -1876,12 +1882,12 @@ sb_write(uint16_t addr, uint8_t val, void *priv) { sb_dsp_t *dsp = (sb_dsp_t *) priv; - sb_dsp_log("[%04X:%08X] DSP: [W] %04X = %02X\n", CS, cpu_state.pc, addr, val); - /* Sound Blasters prior to Sound Blaster 16 alias the I/O ports. */ if ((dsp->sb_type < SB16_DSP_404) && (IS_NOT_ESS(dsp) || ((addr & 0xF) != 0xE))) addr &= 0xfffe; + sb_dsp_log("[%04X:%08X] DSP: [W] %04X = %02X\n", CS, cpu_state.pc, addr, val); + switch (addr & 0xF) { case 6: /* Reset */ sb_do_reset(dsp, val); @@ -1962,7 +1968,7 @@ sb_read(uint16_t addr, void *priv) uint8_t ret = 0x00; /* Sound Blasters prior to Sound Blaster 16 alias the I/O ports. */ - if ((dsp->sb_type < SB16_DSP_404) && (IS_NOT_ESS(dsp) || ((addr & 0xF) != 0xF))) + if ((dsp->sb_type < SB16_DSP_404) && (IS_NOT_ESS(dsp) || ((addr & 0xF) != 0xE))) /* Exception: ESS AudioDrive does not alias port base+0xf */ addr &= 0xfffe; @@ -2085,7 +2091,7 @@ sb_read(uint16_t addr, void *priv) break; } - sb_dsp_log("[%04X:%08X] DSP: [R] %04X = %02X\n", CS, cpu_state.pc, a, ret); + sb_dsp_log("[%04X:%08X] DSP: [R] %04X = %02X\n", CS, cpu_state.pc, addr, ret); return ret; } @@ -2319,6 +2325,7 @@ pollsb(void *priv) if (dsp->sb_8_enable && dsp->sb_pausetime < 0 && dsp->sb_8_output) { sb_dsp_update(dsp); + sb_dsp_log("8-bit format=%02x, pause=%x, length=%d.\n", dsp->sb_8_format, dsp->sb_8_pause, dsp->sb_8_length); switch (dsp->sb_8_format) { case 0x00: /* Mono unsigned */ if (!dsp->sb_8_pause) { diff --git a/src/utils/ini.c b/src/utils/ini.c index 78c873758..503b17ae3 100644 --- a/src/utils/ini.c +++ b/src/utils/ini.c @@ -157,6 +157,22 @@ find_entry(section_t *section, const char *name) return (NULL); } +int +ini_has_entry(ini_section_t self, const char *name) +{ + section_t *section = (section_t *) self; + const entry_t *entry; + + if (section == NULL) + return 0; + + entry = find_entry(section, name); + if (entry == NULL) + return 0; + + return 1; +} + static int entries_num(section_t *section) { @@ -237,9 +253,8 @@ ini_delete_section_if_empty(ini_t ini, ini_section_t section) static section_t * create_section(list_t *head, const char *name) { - section_t *ns = malloc(sizeof(section_t)); + section_t *ns = calloc(1, sizeof(section_t)); - memset(ns, 0x00, sizeof(section_t)); memcpy(ns->name, name, strlen(name) + 1); list_add(&ns->list, head); @@ -262,9 +277,8 @@ ini_find_or_create_section(ini_t ini, const char *name) static entry_t * create_entry(section_t *section, const char *name) { - entry_t *ne = malloc(sizeof(entry_t)); + entry_t *ne = calloc(1, sizeof(entry_t)); - memset(ne, 0x00, sizeof(entry_t)); memcpy(ne->name, name, strlen(name) + 1); list_add(&ne->list, §ion->entry_head); @@ -373,11 +387,8 @@ ini_read(const char *fn) if (fp == NULL) return NULL; - head = malloc(sizeof(list_t)); - memset(head, 0x00, sizeof(list_t)); - - sec = malloc(sizeof(section_t)); - memset(sec, 0x00, sizeof(section_t)); + head = calloc(1, sizeof(list_t)); + sec = calloc(1, sizeof(section_t)); list_add(&sec->list, head); if (bom) @@ -458,7 +469,7 @@ ini_read(const char *fn) d = c; /* Allocate a new variable entry.. */ - ne = malloc(sizeof(entry_t)); + ne = calloc(1, sizeof(entry_t)); memset(ne, 0x00, sizeof(entry_t)); memcpy(ne->name, ename, 128); wcsncpy(ne->wdata, &buff[d], sizeof_w(ne->wdata) - 1); @@ -534,6 +545,103 @@ ini_write(ini_t ini, const char *fn) (void) fclose(fp); } +/* Wide-character version of "trim" */ +wchar_t * +trim_w(wchar_t *str) +{ + size_t len = 0; + wchar_t *frontp = str; + wchar_t *endp = NULL; + + if (str == NULL) { + return NULL; + } + if (str[0] == L'\0') { + return str; + } + + len = wcslen(str); + endp = str + len; + + /* Move the front and back pointers to address the first non-whitespace + * characters from each end. + */ + while (iswspace((wint_t) *frontp)) { + ++frontp; + } + if (endp != frontp) { + while (iswspace((wint_t) *(--endp)) && endp != frontp) { } + } + + if (frontp != str && endp == frontp) + *str = L'\0'; + else if ((str + len - 1) != endp) + *(endp + 1) = L'\0'; + + /* Shift the string so that it starts at str so that if it's dynamically + * allocated, we can still free it on the returned pointer. Note the reuse + * of endp to mean the front of the string buffer now. + */ + endp = str; + if (frontp != str) { + while (*frontp) { + *endp++ = *frontp++; + } + *endp = L'\0'; + } + + return str; +} + +extern char* trim(char* str); + +void +ini_strip_quotes(ini_t ini) +{ + list_t *list = (list_t *) ini; + section_t *sec; + + sec = (section_t *) list->next; + + while (sec != NULL) { + entry_t *ent; + + ent = (entry_t *) sec->entry_head.next; + while (ent != NULL) { + if (ent->name[0] != '\0') { + int trailing_hash = strcspn(ent->data, "#"); + int trailing_quote; + ent->wdata[trailing_hash] = 0; + ent->data[trailing_hash] = 0; + if (ent->wdata[0] == L'\"') { + memmove(ent->wdata, &ent->wdata[1], sizeof(ent->wdata) - sizeof(wchar_t)); + } + if (ent->wdata[wcslen(ent->wdata) - 1] == L'\"') { + ent->wdata[wcslen(ent->wdata) - 1] = 0; + } + + if (ent->data[0] == '\"') { + memmove(ent->data, &ent->data[1], sizeof(ent->data) - sizeof(char)); + } + if (ent->data[strlen(ent->data) - 1] == '\"') { + ent->data[strlen(ent->data) - 1] = 0; + } + + trailing_quote = strcspn(ent->data, "\""); + ent->wdata[trailing_quote] = 0; + ent->data[trailing_quote] = 0; + + trim_w(ent->wdata); + trim(ent->data); + } + + ent = (entry_t *) ent->list.next; + } + + sec = (section_t *) sec->list.next; + } +} + ini_t ini_new(void) { @@ -593,6 +701,11 @@ ini_section_get_int(ini_section_t self, const char *name, int def) if (entry == NULL) return def; + if (stricmp(entry->data, "true") == 0) + return 1; + if (stricmp(entry->data, "false") == 0) + return 0; + sscanf(entry->data, "%i", &value); return value; diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index 0c8fb6691..d35257ea7 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -5226,7 +5226,7 @@ mach32_ap_writeb(uint32_t addr, uint8_t val, void *priv) uint8_t port_dword = addr & 0xfc; if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && - (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && (addr < (mach->ap_size << 20)))) { + (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20)))) { if (addr & 0x100) { mach_log("Port WORDB Write=%04x.\n", 0x02ee + (port_dword << 8)); mach_accel_outb(0x02ee + (addr & 1) + (port_dword << 8), val, mach); @@ -5279,6 +5279,9 @@ mach32_ap_writel(uint32_t addr, uint32_t val, void *priv) const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; uint8_t port_dword = addr & 0xfc; + mach_log("Linear WORDL Write=%08x, val=%08x, ON=%x, dpconfig=%04x, apsize=%08x.\n", + addr - mach->linear_base, val, dev->on, mach->accel.dp_config, mach->ap_size << 20); + if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20)))) { if (addr & 0x100) { @@ -5291,8 +5294,6 @@ mach32_ap_writel(uint32_t addr, uint32_t val, void *priv) mach_accel_outw(0x02e8 + (port_dword << 8) + 4, val >> 16, mach); } } else { - mach_log("Linear WORDL Write=%08x, val=%08x, ON=%x, dpconfig=%04x, apsize=%08x.\n", - addr - mach->linear_base, val, dev->on, mach->accel.dp_config, mach->ap_size << 20); if (dev->on) mach32_writel_linear(addr, val, mach); else diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 823ef4d2f..db2035717 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -3101,7 +3101,7 @@ da2_loadfont(char *fname, void *p) } uint32_t j = 0; while (ftell(mfile) < fsize) { - fread(&buf, sizeof(uint8_t), 1, mfile); + (void) !fread(&buf, sizeof(uint8_t), 1, mfile); da2->mmio.font[j] = buf; j++; } diff --git a/src/video/vid_s3_virge.c b/src/video/vid_s3_virge.c index 904d4a4cf..cc0985c02 100644 --- a/src/video/vid_s3_virge.c +++ b/src/video/vid_s3_virge.c @@ -53,10 +53,10 @@ static uint64_t virge_time = 0; static int dither[4][4] = { - {0, 4, 1, 5}, - {6, 2, 7, 3}, - {1, 5, 0, 4}, - {7, 3, 6, 2} + { 0, 4, 1, 5 }, + { 6, 2, 7, 3 }, + { 1, 5, 0, 4 }, + { 7, 3, 6, 2 } }; #define ROM_VIRGE_325 "roms/video/s3virge/86c325.bin" @@ -112,80 +112,80 @@ enum { }; enum { - FIFO_INVALID = (0x00 << 24), - FIFO_WRITE_BYTE = (0x01 << 24), - FIFO_WRITE_WORD = (0x02 << 24), + FIFO_INVALID = (0x00 << 24), + FIFO_WRITE_BYTE = (0x01 << 24), + FIFO_WRITE_WORD = (0x02 << 24), FIFO_WRITE_DWORD = (0x03 << 24) }; typedef struct { - uint32_t addr_type; - uint32_t val; + uint32_t addr_type; + uint32_t val; } fifo_entry_t; typedef struct s3d_t { - uint32_t cmd_set; - int clip_l; - int clip_r; - int clip_t; - int clip_b; + uint32_t cmd_set; + int clip_l; + int clip_r; + int clip_t; + int clip_b; - uint32_t dest_base; - uint32_t dest_str; + uint32_t dest_base; + uint32_t dest_str; - uint32_t z_base; - uint32_t z_str; + uint32_t z_base; + uint32_t z_str; - uint32_t tex_base; - uint32_t tex_bdr_clr; - uint32_t tbv; - uint32_t tbu; - int32_t TdVdX; - int32_t TdUdX; - int32_t TdVdY; - int32_t TdUdY; - uint32_t tus; - uint32_t tvs; + uint32_t tex_base; + uint32_t tex_bdr_clr; + uint32_t tbv; + uint32_t tbu; + int32_t TdVdX; + int32_t TdUdX; + int32_t TdVdY; + int32_t TdUdY; + uint32_t tus; + uint32_t tvs; - int32_t TdZdX; - int32_t TdZdY; - uint32_t tzs; + int32_t TdZdX; + int32_t TdZdY; + uint32_t tzs; - int32_t TdWdX; - int32_t TdWdY; - uint32_t tws; + int32_t TdWdX; + int32_t TdWdY; + uint32_t tws; - int32_t TdDdX; - int32_t TdDdY; - uint32_t tds; + int32_t TdDdX; + int32_t TdDdY; + uint32_t tds; - int16_t TdGdX; - int16_t TdBdX; - int16_t TdRdX; - int16_t TdAdX; - int16_t TdGdY; - int16_t TdBdY; - int16_t TdRdY; - int16_t TdAdY; - uint32_t tgs; - uint32_t tbs; - uint32_t trs; - uint32_t tas; + int16_t TdGdX; + int16_t TdBdX; + int16_t TdRdX; + int16_t TdAdX; + int16_t TdGdY; + int16_t TdBdY; + int16_t TdRdY; + int16_t TdAdY; + uint32_t tgs; + uint32_t tbs; + uint32_t trs; + uint32_t tas; - uint32_t TdXdY12; - uint32_t txend12; - uint32_t TdXdY01; - uint32_t txend01; - uint32_t TdXdY02; - uint32_t txs; - uint32_t tys; - int ty01; - int ty12; - int tlr; + uint32_t TdXdY12; + uint32_t txend12; + uint32_t TdXdY01; + uint32_t txend01; + uint32_t TdXdY02; + uint32_t txs; + uint32_t tys; + int ty01; + int ty12; + int tlr; - uint8_t fog_r; - uint8_t fog_g; - uint8_t fog_b; + uint8_t fog_r; + uint8_t fog_g; + uint8_t fog_b; } s3d_t; typedef struct virge_t { @@ -193,41 +193,41 @@ typedef struct virge_t { mem_mapping_t mmio_mapping; mem_mapping_t new_mmio_mapping; - rom_t bios_rom; + rom_t bios_rom; - svga_t svga; + svga_t svga; - uint8_t bank; - uint8_t ma_ext; + uint8_t bank; + uint8_t ma_ext; - uint8_t virge_id; - uint8_t virge_id_high; - uint8_t virge_id_low; - uint8_t virge_rev; + uint8_t virge_id; + uint8_t virge_id_high; + uint8_t virge_id_low; + uint8_t virge_rev; - uint32_t linear_base; - uint32_t linear_size; + uint32_t linear_base; + uint32_t linear_size; - uint8_t pci_regs[256]; - uint8_t pci_slot; + uint8_t pci_regs[256]; + uint8_t pci_slot; - int chip; + int chip; - int bilinear_enabled; - int dithering_enabled; - int memory_size; + int bilinear_enabled; + int dithering_enabled; + int memory_size; - int pixel_count; - int tri_count; + int pixel_count; + int tri_count; - thread_t * render_thread; - event_t * wake_render_thread; - event_t * wake_main_thread; - event_t * not_full_event; + thread_t *render_thread; + event_t *wake_render_thread; + event_t *wake_main_thread; + event_t *not_full_event; - uint32_t hwc_fg_col; - uint32_t hwc_bg_col; - int hwc_col_stack_pos; + uint32_t hwc_fg_col; + uint32_t hwc_bg_col; + int hwc_col_stack_pos; struct { uint32_t src_base; @@ -260,13 +260,13 @@ typedef struct virge_t { int lycnt; int line_dir; - int src_x; - int src_y; - int dest_x; - int dest_y; - int w; - int h; - uint8_t rop; + int src_x; + int src_y; + int dest_x; + int dest_y; + int w; + int h; + uint8_t rop; int data_left_count; uint32_t data_left; @@ -282,15 +282,16 @@ typedef struct virge_t { uint32_t plxstart; uint32_t pystart; uint32_t pycnt; - uint32_t dest_l, dest_r; + uint32_t dest_l; + uint32_t dest_r; } s3d; - s3d_t s3d_tri; + s3d_t s3d_tri; - s3d_t s3d_buffer[RB_SIZE]; - atomic_int s3d_read_idx; - atomic_int s3d_write_idx; - atomic_int s3d_busy; + s3d_t s3d_buffer[RB_SIZE]; + atomic_int s3d_read_idx; + atomic_int s3d_write_idx; + atomic_int s3d_busy; struct { uint32_t pri_ctrl; @@ -317,88 +318,89 @@ typedef struct virge_t { uint32_t sec_start; uint32_t sec_size; - int sdif; + int sdif; - int pri_x; - int pri_y; - int pri_w; - int pri_h; - int sec_x; - int sec_y; - int sec_w; - int sec_h; + int pri_x; + int pri_y; + int pri_w; + int pri_h; + int sec_x; + int sec_y; + int sec_w; + int sec_h; } streams; fifo_entry_t fifo[FIFO_SIZE]; atomic_int fifo_read_idx, fifo_write_idx; atomic_int fifo_thread_run, render_thread_run; - thread_t * fifo_thread; - event_t *wake_fifo_thread; - event_t * fifo_not_full_event; + thread_t *fifo_thread; + event_t *wake_fifo_thread; + event_t *fifo_not_full_event; - atomic_int virge_busy; - atomic_uint irq_pending; + atomic_int virge_busy; + atomic_uint irq_pending; - uint8_t subsys_stat; - uint8_t subsys_cntl; + uint8_t subsys_stat; + uint8_t subsys_cntl; - int local; + int local; - uint8_t serialport; + uint8_t serialport; - uint8_t irq_state; - uint8_t advfunc_cntl; + uint8_t irq_state; + uint8_t advfunc_cntl; - void *i2c, *ddc; + void *i2c, *ddc; - int onboard; - int fifo_slots_num; + int onboard; + int fifo_slots_num; - uint32_t vram_mask; + uint32_t vram_mask; - uint8_t reg6b; - uint8_t lfb_bios; - uint8_t int_line; - uint8_t cmd_dma; + uint8_t reg6b; + uint8_t lfb_bios; + uint8_t int_line; + uint8_t cmd_dma; - uint32_t cmd_dma_base; - uint32_t cmd_dma_buf_size; - uint32_t cmd_dma_buf_size_mask; - uint32_t cmd_base_addr; - uint32_t cmd_dma_write_ptr_reg; - uint32_t cmd_dma_write_ptr_update; - uint32_t cmd_dma_read_ptr_reg; - uint32_t dma_val; - uint32_t dma_dbl_words; - uint32_t dma_mmio_addr; - uint32_t dma_data_type; + uint32_t cmd_dma_base; + uint32_t cmd_dma_buf_size; + uint32_t cmd_dma_buf_size_mask; + uint32_t cmd_base_addr; + uint32_t cmd_dma_write_ptr_reg; + uint32_t cmd_dma_write_ptr_update; + uint32_t cmd_dma_read_ptr_reg; + uint32_t dma_val; + uint32_t dma_dbl_words; + uint32_t dma_mmio_addr; + uint32_t dma_data_type; - int pci; - int is_agp; + int pci; + int is_agp; - pc_timer_t irq_timer; + pc_timer_t irq_timer; } virge_t; static __inline void -wake_fifo_thread(virge_t *virge) { +wake_fifo_thread(virge_t *virge) +{ /* Wake up FIFO thread if moving from idle */ thread_set_event(virge->wake_fifo_thread); } -static virge_t *reset_state = NULL; +static virge_t *reset_state = NULL; static video_timings_t timing_diamond_stealth3d_2000_pci = { .type = VIDEO_PCI, .write_b = 2, .write_w = 2, .write_l = 3, .read_b = 28, .read_w = 28, .read_l = 45 }; static video_timings_t timing_diamond_stealth3d_3000_pci = { .type = VIDEO_PCI, .write_b = 2, .write_w = 2, .write_l = 4, .read_b = 26, .read_w = 26, .read_l = 42 }; static video_timings_t timing_virge_dx_pci = { .type = VIDEO_PCI, .write_b = 2, .write_w = 2, .write_l = 3, .read_b = 28, .read_w = 28, .read_l = 45 }; static video_timings_t timing_virge_agp = { .type = VIDEO_AGP, .write_b = 2, .write_w = 2, .write_l = 3, .read_b = 28, .read_w = 28, .read_l = 45 }; -static void queue_triangle(virge_t *virge); +static void queue_triangle(virge_t *virge); -static void s3_virge_recalctimings(svga_t *svga); -static void s3_virge_updatemapping(virge_t *virge); +static void s3_virge_recalctimings(svga_t *svga); +static void s3_virge_updatemapping(virge_t *virge); -static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat); +static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat); static uint8_t s3_virge_mmio_read(uint32_t addr, void *priv); static uint16_t s3_virge_mmio_read_w(uint32_t addr, void *priv); @@ -407,33 +409,33 @@ static void s3_virge_mmio_write(uint32_t addr, uint8_t val, void *priv); static void s3_virge_mmio_write_w(uint32_t addr, uint16_t val, void *priv); static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv); -static void s3_virge_queue(virge_t *virge, uint32_t addr, uint32_t val, uint32_t type); +static void s3_virge_queue(virge_t *virge, uint32_t addr, uint32_t val, uint32_t type); enum { - CMD_SET_AE = 1, - CMD_SET_HC = (1 << 1), + CMD_SET_AE = 1, + CMD_SET_HC = (1 << 1), - CMD_SET_FORMAT_MASK = (7 << 2), - CMD_SET_FORMAT_8 = (0 << 2), - CMD_SET_FORMAT_16 = (1 << 2), - CMD_SET_FORMAT_24 = (2 << 2), + CMD_SET_FORMAT_MASK = (7 << 2), + CMD_SET_FORMAT_8 = (0 << 2), + CMD_SET_FORMAT_16 = (1 << 2), + CMD_SET_FORMAT_24 = (2 << 2), - CMD_SET_MS = (1 << 6), - CMD_SET_IDS = (1 << 7), - CMD_SET_MP = (1 << 8), - CMD_SET_TP = (1 << 9), + CMD_SET_MS = (1 << 6), + CMD_SET_IDS = (1 << 7), + CMD_SET_MP = (1 << 8), + CMD_SET_TP = (1 << 9), - CMD_SET_ITA_MASK = (3 << 10), - CMD_SET_ITA_BYTE = (0 << 10), - CMD_SET_ITA_WORD = (1 << 10), - CMD_SET_ITA_DWORD = (2 << 10), + CMD_SET_ITA_MASK = (3 << 10), + CMD_SET_ITA_BYTE = (0 << 10), + CMD_SET_ITA_WORD = (1 << 10), + CMD_SET_ITA_DWORD = (2 << 10), - CMD_SET_ZUP = (1 << 23), + CMD_SET_ZUP = (1 << 23), - CMD_SET_ZB_MODE = (3 << 24), + CMD_SET_ZB_MODE = (3 << 24), - CMD_SET_XP = (1 << 25), - CMD_SET_YP = (1 << 26), + CMD_SET_XP = (1 << 25), + CMD_SET_YP = (1 << 26), CMD_SET_COMMAND_MASK = (15 << 27) }; @@ -444,11 +446,11 @@ enum { #define CMD_SET_TWE (1 << 26) enum { - CMD_SET_COMMAND_BITBLT = (0 << 27), - CMD_SET_COMMAND_RECTFILL = (2 << 27), - CMD_SET_COMMAND_LINE = (3 << 27), - CMD_SET_COMMAND_POLY = (5 << 27), - CMD_SET_COMMAND_NOP = (15 << 27) + CMD_SET_COMMAND_BITBLT = (0 << 27), + CMD_SET_COMMAND_RECTFILL = (2 << 27), + CMD_SET_COMMAND_LINE = (3 << 27), + CMD_SET_COMMAND_POLY = (5 << 27), + CMD_SET_COMMAND_NOP = (15 << 27) }; #define INT_VSY (1 << 0) @@ -475,7 +477,7 @@ s3_virge_update_irqs(virge_t *virge) } static void -s3_virge_update_irq_timer(void* priv) +s3_virge_update_irq_timer(void *priv) { virge_t *virge = (virge_t *) priv; @@ -491,7 +493,7 @@ static void s3_virge_out(uint16_t addr, uint8_t val, void *priv) { virge_t *virge = (virge_t *) priv; - svga_t * svga = &virge->svga; + svga_t *svga = &virge->svga; uint8_t old; uint32_t cursoraddr; @@ -538,7 +540,7 @@ s3_virge_out(uint16_t addr, uint8_t val, void *priv) if ((svga->crtcreg == 0x36) && (svga->crtc[0x39] != 0xa5)) return; - old = svga->crtc[svga->crtcreg]; + old = svga->crtc[svga->crtcreg]; svga->crtc[svga->crtcreg] = val; switch (svga->crtcreg) { @@ -622,7 +624,7 @@ s3_virge_out(uint16_t addr, uint8_t val, void *priv) switch (virge->hwc_col_stack_pos) { case 0: virge->hwc_bg_col = (virge->hwc_bg_col & 0xffff00) | val; - break; + break; case 1: virge->hwc_bg_col = (virge->hwc_bg_col & 0xff00ff) | (val << 8); break; @@ -705,9 +707,10 @@ s3_virge_out(uint16_t addr, uint8_t val, void *priv) } static uint8_t -s3_virge_in(uint16_t addr, void *priv) { +s3_virge_in(uint16_t addr, void *priv) +{ virge_t *virge = (virge_t *) priv; - svga_t * svga = &virge->svga; + svga_t *svga = &virge->svga; uint8_t ret; if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) @@ -758,7 +761,7 @@ s3_virge_in(uint16_t addr, void *priv) { break; case 0x45: virge->hwc_col_stack_pos = 0; - ret = svga->crtc[0x45]; + ret = svga->crtc[0x45]; break; case 0x51: ret = (svga->crtc[0x51] & 0xf0) | ((virge->bank >> 2) & 0xc) | ((virge->ma_ext >> 2) & 3); @@ -812,8 +815,10 @@ s3_virge_in(uint16_t addr, void *priv) { static void s3_virge_recalctimings(svga_t *svga) { - int n, r, m; - double freq; + int n; + int r; + int m; + double freq; virge_t *virge = (virge_t *) svga->priv; svga->hdisp = svga->hdisp_old; @@ -857,7 +862,7 @@ s3_virge_recalctimings(svga_t *svga) else r = (svga->seqregs[0x12] >> 5) & 0x03; - m = svga->seqregs[0x13] & 0x7f; + m = svga->seqregs[0x13] & 0x7f; freq = (((double) m + 2) / (((double) n + 2) * (double) (1 << r))) * 14318184.0; svga->clock = (cpuclock * (float) (1ULL << 32)) / freq; @@ -876,7 +881,7 @@ s3_virge_recalctimings(svga_t *svga) svga->vblankstart = svga->dispend; video_force_resize_set_monitor(1, svga->monitor_index); } else { - svga->hblankstart = (((svga->crtc[0x5d] & 0x04) >> 2) << 8) + svga->crtc[2]; + svga->hblankstart = (((svga->crtc[0x5d] & 0x04) >> 2) << 8) + svga->crtc[2]; svga->hblank_end_val = (svga->crtc[3] & 0x1f) | (((svga->crtc[5] & 0x80) >> 7) << 5) | (((svga->crtc[0x5d] & 0x08) >> 3) << 6); @@ -894,39 +899,39 @@ s3_virge_recalctimings(svga_t *svga) svga->rowoffset = 256; svga->lowres = !((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)); - if ((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)) switch (svga->bpp) { - case 8: - svga->render = svga_render_8bpp_highres; - break; - case 15: - svga->render = svga_render_15bpp_highres; - if ((virge->chip != S3_VIRGEVX) && (virge->chip < S3_VIRGEGX2)) { - svga->hdisp >>= 1; - svga->dots_per_clock >>= 1; - } - break; - case 16: - svga->render = svga_render_16bpp_highres; - if ((virge->chip != S3_VIRGEVX) && (virge->chip < S3_VIRGEGX2)) { - svga->hdisp >>= 1; - svga->dots_per_clock >>= 1; - } - break; - case 24: - svga->render = svga_render_24bpp_highres; - if ((virge->chip != S3_VIRGEVX) && (virge->chip < S3_VIRGEGX2)) - svga->rowoffset = (svga->rowoffset * 3) >> 2; /*Hack*/ - break; - case 32: - svga->render = svga_render_32bpp_highres; - break; + if ((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)) + switch (svga->bpp) { + case 8: + svga->render = svga_render_8bpp_highres; + break; + case 15: + svga->render = svga_render_15bpp_highres; + if ((virge->chip != S3_VIRGEVX) && (virge->chip < S3_VIRGEGX2)) { + svga->hdisp >>= 1; + svga->dots_per_clock >>= 1; + } + break; + case 16: + svga->render = svga_render_16bpp_highres; + if ((virge->chip != S3_VIRGEVX) && (virge->chip < S3_VIRGEGX2)) { + svga->hdisp >>= 1; + svga->dots_per_clock >>= 1; + } + break; + case 24: + svga->render = svga_render_24bpp_highres; + if ((virge->chip != S3_VIRGEVX) && (virge->chip < S3_VIRGEGX2)) + svga->rowoffset = (svga->rowoffset * 3) >> 2; /*Hack*/ + break; + case 32: + svga->render = svga_render_32bpp_highres; + break; - default: - break; - } + default: + break; + } - svga->vram_display_mask = (!(svga->crtc[0x31] & 0x08) && - (svga->crtc[0x32] & 0x40)) ? 0x3ffff : virge->vram_mask; + svga->vram_display_mask = (!(svga->crtc[0x31] & 0x08) && (svga->crtc[0x32] & 0x40)) ? 0x3ffff : virge->vram_mask; } else { /*Streams mode*/ if (virge->chip < S3_VIRGEGX2) { if (virge->streams.buffer_ctrl & 1) @@ -960,7 +965,7 @@ s3_virge_recalctimings(svga_t *svga) else svga->overlay.addr = virge->streams.sec_fb0; - svga->overlay.ena = (svga->overlay.x >= 0); + svga->overlay.ena = (svga->overlay.x >= 0); svga->overlay.h_acc = virge->streams.dda_horiz_accumulator; svga->overlay.v_acc = virge->streams.dda_vert_accumulator; @@ -968,8 +973,7 @@ s3_virge_recalctimings(svga_t *svga) svga->rowoffset = virge->streams.pri_stride >> 3; if (virge->chip <= S3_VIRGEDX && svga->overlay.ena) { - svga->overlay.ena = (((virge->streams.blend_ctrl >> 24) & 7) == 0b000) || - (((virge->streams.blend_ctrl >> 24) & 7) == 0b101); + svga->overlay.ena = (((virge->streams.blend_ctrl >> 24) & 7) == 0b000) || (((virge->streams.blend_ctrl >> 24) & 7) == 0b101); } else if (virge->chip >= S3_VIRGEGX2 && svga->overlay.ena) { /* 0x20 = Secondary Stream enabled */ /* 0x2000 = Primary Stream enabled */ @@ -1028,7 +1032,8 @@ s3_virge_recalctimings(svga_t *svga) } static void -s3_virge_updatemapping(virge_t *virge) { +s3_virge_updatemapping(virge_t *virge) +{ svga_t *svga = &virge->svga; if (!(virge->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) { @@ -1040,7 +1045,7 @@ s3_virge_updatemapping(virge_t *virge) { } switch (svga->gdcreg[6] & 0xc) { /*Banked framebuffer*/ - case 0x0: /*128k at A0000*/ + case 0x0: /*128k at A0000*/ mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); svga->banked_mask = 0xffff; break; @@ -1114,7 +1119,8 @@ s3_virge_updatemapping(virge_t *virge) { } static void -s3_virge_vblank_start(svga_t *svga) { +s3_virge_vblank_start(svga_t *svga) +{ virge_t *virge = (virge_t *) svga->priv; if (virge->irq_pending) @@ -1124,7 +1130,8 @@ s3_virge_vblank_start(svga_t *svga) { } static void -s3_virge_wait_fifo_idle(virge_t *virge) { +s3_virge_wait_fifo_idle(virge_t *virge) +{ while (!FIFO_EMPTY) { wake_fifo_thread(virge); thread_wait_event(virge->fifo_not_full_event, 1); @@ -1135,7 +1142,7 @@ static uint8_t s3_virge_mmio_read(uint32_t addr, void *priv) { virge_t *virge = (virge_t *) priv; - uint8_t ret; + uint8_t ret; switch (addr & 0xffff) { case 0x8504: @@ -1216,9 +1223,10 @@ s3_virge_mmio_read_w(uint32_t addr, void *priv) } static uint32_t -s3_virge_mmio_read_l(uint32_t addr, void *priv) { +s3_virge_mmio_read_l(uint32_t addr, void *priv) +{ virge_t *virge = (virge_t *) priv; - uint32_t ret = 0xffffffff; + uint32_t ret = 0xffffffff; switch (addr & 0xfffc) { case 0x8180: @@ -1447,7 +1455,7 @@ s3_virge_mmio_read_l(uint32_t addr, void *priv) { break; } - //pclog("MMIO ReadL=%04x, ret=%08x.\n", addr & 0xfffc, ret); + // pclog("MMIO ReadL=%04x, ret=%08x.\n", addr & 0xfffc, ret); return ret; } @@ -1461,15 +1469,15 @@ s3_virge_mmio_write_fifo_l(virge_t *virge, uint32_t addr, uint32_t val) int y = (addr >> 3) & 7; int color; int byte; - uint32_t newaddr = addr; - virge->s3d.pattern_8[y * 8 + x] = val & 0xff; + uint32_t newaddr = addr; + virge->s3d.pattern_8[y * 8 + x] = val & 0xff; virge->s3d.pattern_8[y * 8 + x + 1] = val >> 8; virge->s3d.pattern_8[y * 8 + x + 2] = val >> 16; virge->s3d.pattern_8[y * 8 + x + 3] = val >> 24; - x = (addr >> 1) & 6; - y = (addr >> 4) & 7; - virge->s3d.pattern_16[y * 8 + x] = val & 0xffff; + x = (addr >> 1) & 6; + y = (addr >> 4) & 7; + virge->s3d.pattern_16[y * 8 + x] = val & 0xffff; virge->s3d.pattern_16[y * 8 + x + 1] = val >> 16; newaddr &= 0x00ff; @@ -1482,22 +1490,21 @@ s3_virge_mmio_write_fifo_l(virge_t *virge, uint32_t addr, uint32_t val) virge->s3d.pattern_24[y * 8 + x] |= ((val >> byte) & 0xff) << color; } - x = (addr >> 2) & 7; - y = (addr >> 5) & 7; + x = (addr >> 2) & 7; + y = (addr >> 5) & 7; virge->s3d.pattern_32[y * 8 + x] = val & 0xffffff; - } break; + } + break; case 0xa4d4: case 0xa8d4: case 0xacd4: - virge->s3d.src_base = val & ((virge->memory_size == 8) ? - (val & 0x7ffff8) : (val & 0x3ffff8)); + virge->s3d.src_base = val & ((virge->memory_size == 8) ? (val & 0x7ffff8) : (val & 0x3ffff8)); break; case 0xa4d8: case 0xa8d8: case 0xacd8: - virge->s3d.dest_base = val & ((virge->memory_size == 8) ? - (val & 0x7ffff8) : (val & 0x3ffff8)); + virge->s3d.dest_base = val & ((virge->memory_size == 8) ? (val & 0x7ffff8) : (val & 0x3ffff8)); break; case 0xa4dc: case 0xa8dc: @@ -1515,7 +1522,7 @@ s3_virge_mmio_write_fifo_l(virge_t *virge, uint32_t addr, uint32_t val) case 0xa8e4: case 0xace4: virge->s3d.dest_str = (val >> 16) & 0xff8; - virge->s3d.src_str = val & 0xff8; + virge->s3d.src_str = val & 0xff8; break; case 0xa4e8: case 0xace8: @@ -1548,7 +1555,7 @@ s3_virge_mmio_write_fifo_l(virge_t *virge, uint32_t addr, uint32_t val) s3_virge_bitblt(virge, -1, 0); break; case 0xa504: - virge->s3d.r_width = (val >> 16) & 0x7ff; + virge->s3d.r_width = (val >> 16) & 0x7ff; virge->s3d.r_height = val & 0x7ff; break; case 0xa508: @@ -1566,7 +1573,7 @@ s3_virge_mmio_write_fifo_l(virge_t *virge, uint32_t addr, uint32_t val) virge->s3d.lxend1 = val & 0x7ff; break; case 0xa970: - virge->s3d.ldx = (int32_t)val; + virge->s3d.ldx = (int32_t) val; break; case 0xa974: virge->s3d.lxstart = val; @@ -1575,7 +1582,7 @@ s3_virge_mmio_write_fifo_l(virge_t *virge, uint32_t addr, uint32_t val) virge->s3d.lystart = val & 0x7ff; break; case 0xa97c: - virge->s3d.lycnt = val & 0x7ff; + virge->s3d.lycnt = val & 0x7ff; virge->s3d.line_dir = val >> 31; if (virge->s3d.cmd_set & CMD_SET_AE) s3_virge_bitblt(virge, -1, 0); @@ -1604,13 +1611,11 @@ s3_virge_mmio_write_fifo_l(virge_t *virge, uint32_t addr, uint32_t val) case 0xb0d4: case 0xb4d4: - virge->s3d_tri.z_base = val & ((virge->memory_size == 8) ? - (val & 0x7ffff8) : (val & 0x3ffff8)); + virge->s3d_tri.z_base = val & ((virge->memory_size == 8) ? (val & 0x7ffff8) : (val & 0x3ffff8)); break; case 0xb0d8: case 0xb4d8: - virge->s3d_tri.dest_base = val & ((virge->memory_size == 8) ? - (val & 0x7ffff8) : (val & 0x3ffff8)); + virge->s3d_tri.dest_base = val & ((virge->memory_size == 8) ? (val & 0x7ffff8) : (val & 0x3ffff8)); break; case 0xb0dc: case 0xb4dc: @@ -1625,15 +1630,14 @@ s3_virge_mmio_write_fifo_l(virge_t *virge, uint32_t addr, uint32_t val) case 0xb0e4: case 0xb4e4: virge->s3d_tri.dest_str = (val >> 16) & 0xff8; - virge->s3d.src_str = val & 0xff8; + virge->s3d.src_str = val & 0xff8; break; case 0xb0e8: case 0xb4e8: virge->s3d_tri.z_str = val & 0xff8; break; case 0xb4ec: - virge->s3d_tri.tex_base = val & ((virge->memory_size == 8) ? - (val & 0x7ffff8) : (val & 0x3ffff8)); + virge->s3d_tri.tex_base = val & ((virge->memory_size == 8) ? (val & 0x7ffff8) : (val & 0x3ffff8)); break; case 0xb4f0: virge->s3d_tri.tex_bdr_clr = val & 0xffffff; @@ -1750,17 +1754,17 @@ s3_virge_mmio_write_fifo_l(virge_t *virge, uint32_t addr, uint32_t val) case 0xb57c: virge->s3d_tri.ty01 = (val >> 16) & 0x7ff; virge->s3d_tri.ty12 = val & 0x7ff; - virge->s3d_tri.tlr = val >> 31; + virge->s3d_tri.tlr = val >> 31; if (virge->s3d_tri.cmd_set & CMD_SET_AE) queue_triangle(virge); - break; + break; } } static void fifo_thread(void *param) { - virge_t *virge = (virge_t *)param; + virge_t *virge = (virge_t *) param; while (virge->fifo_thread_run) { thread_set_event(virge->fifo_not_full_event); @@ -1768,10 +1772,10 @@ fifo_thread(void *param) thread_reset_event(virge->wake_fifo_thread); virge->virge_busy = 1; while (!FIFO_EMPTY) { - uint64_t start_time = plat_timer_read(); - uint64_t end_time; + uint64_t start_time = plat_timer_read(); + uint64_t end_time; fifo_entry_t *fifo = &virge->fifo[virge->fifo_read_idx & FIFO_MASK]; - uint32_t val = fifo->val; + uint32_t val = fifo->val; switch (fifo->addr_type & FIFO_TYPE) { case FIFO_WRITE_BYTE: @@ -1811,7 +1815,7 @@ fifo_thread(void *param) virge->virge_busy = 0; virge->subsys_stat |= (INT_FIFO_EMP | INT_3DF_EMP); if (virge->cmd_dma) - virge->subsys_stat |= (INT_HOST_DONE | INT_CMD_DONE); + virge->subsys_stat |= (INT_HOST_DONE | INT_CMD_DONE); virge->irq_pending++; } @@ -1820,8 +1824,8 @@ fifo_thread(void *param) static void s3_virge_queue(virge_t *virge, uint32_t addr, uint32_t val, uint32_t type) { - fifo_entry_t *fifo = &virge->fifo[virge->fifo_write_idx & FIFO_MASK]; - int limit = 0; + fifo_entry_t *fifo = &virge->fifo[virge->fifo_write_idx & FIFO_MASK]; + int limit = 0; if (type == FIFO_WRITE_DWORD) { switch (addr & 0xfffc) { @@ -1848,7 +1852,7 @@ s3_virge_queue(virge_t *virge, uint32_t addr, uint32_t val, uint32_t type) } } - fifo->val = val; + fifo->val = val; fifo->addr_type = (addr & FIFO_ADDR) | type; virge->fifo_write_idx++; @@ -1924,7 +1928,7 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) virge->streams.chroma_ctrl = val; break; case 0x8190: - virge->streams.sec_ctrl = val; + virge->streams.sec_ctrl = val; virge->streams.dda_horiz_accumulator = val & 0xfff; if (val & 0x1000) virge->streams.dda_horiz_accumulator |= ~0xfff; @@ -1935,7 +1939,7 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) virge->streams.chroma_upper_bound = val; break; case 0x8198: - virge->streams.sec_filter = val; + virge->streams.sec_filter = val; virge->streams.k1_horiz_scale = val & 0x7ff; if (val & 0x800) virge->streams.k1_horiz_scale |= ~0x7ff; @@ -2015,29 +2019,29 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) break; case 0x81f0: virge->streams.pri_start = val; - virge->streams.pri_x = (val >> 16) & 0x7ff; - virge->streams.pri_y = val & 0x7ff; + virge->streams.pri_x = (val >> 16) & 0x7ff; + virge->streams.pri_y = val & 0x7ff; svga_recalctimings(svga); svga->fullchange = changeframecount; break; case 0x81f4: virge->streams.pri_size = val; - virge->streams.pri_w = (val >> 16) & 0x7ff; - virge->streams.pri_h = val & 0x7ff; + virge->streams.pri_w = (val >> 16) & 0x7ff; + virge->streams.pri_h = val & 0x7ff; svga_recalctimings(svga); svga->fullchange = changeframecount; break; case 0x81f8: virge->streams.sec_start = val; - virge->streams.sec_x = (val >> 16) & 0x7ff; - virge->streams.sec_y = val & 0x7ff; + virge->streams.sec_x = (val >> 16) & 0x7ff; + virge->streams.sec_y = val & 0x7ff; svga_recalctimings(svga); svga->fullchange = changeframecount; break; case 0x81fc: virge->streams.sec_size = val; - virge->streams.sec_w = (val >> 16) & 0x7ff; - virge->streams.sec_h = val & 0x7ff; + virge->streams.sec_w = (val >> 16) & 0x7ff; + virge->streams.sec_h = val & 0x7ff; svga_recalctimings(svga); svga->fullchange = changeframecount; break; @@ -2054,23 +2058,23 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) break; case 0x8590: - virge->cmd_dma_base = val; - virge->cmd_dma_buf_size = (val & 2) ? 0x10000 : 0x1000; + virge->cmd_dma_base = val; + virge->cmd_dma_buf_size = (val & 2) ? 0x10000 : 0x1000; virge->cmd_dma_buf_size_mask = virge->cmd_dma_buf_size - 1; - virge->cmd_base_addr = (val & 2) ? (val & 0xffff0000) : (val & 0xfffff000); + virge->cmd_base_addr = (val & 2) ? (val & 0xffff0000) : (val & 0xfffff000); break; case 0x8594: virge->cmd_dma_write_ptr_update = val & (1 << 16); if (virge->cmd_dma_write_ptr_update) { virge->cmd_dma_write_ptr_reg = (virge->cmd_dma_buf_size == 0x10000) ? (val & 0xffff) : (val & 0xfff); - virge->dma_dbl_words = 0; - virge->dma_data_type = 0; - virge->dma_val = 0; + virge->dma_dbl_words = 0; + virge->dma_data_type = 0; + virge->dma_val = 0; if (virge->cmd_dma) { while (virge->cmd_dma_read_ptr_reg != virge->cmd_dma_write_ptr_reg) { virge->cmd_dma_write_ptr_update = 0; - dma_bm_read(virge->cmd_base_addr + virge->cmd_dma_read_ptr_reg, (uint8_t *)&virge->dma_val, 4, 4); + dma_bm_read(virge->cmd_base_addr + virge->cmd_dma_read_ptr_reg, (uint8_t *) &virge->dma_val, 4, 4); if (!virge->dma_dbl_words) { virge->dma_dbl_words = (virge->dma_val & 0xffff); virge->dma_data_type = !!(virge->dma_val & (1 << 31)); @@ -2094,9 +2098,9 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) break; case 0x859c: - virge->cmd_dma = val & 1; + virge->cmd_dma = val & 1; virge->cmd_dma_write_ptr_reg = 0; - virge->cmd_dma_read_ptr_reg = 0; + virge->cmd_dma_read_ptr_reg = 0; break; case 0xff20: @@ -2106,26 +2110,26 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) } } -#define READ(addr, val) \ - do { \ - switch (bpp) { \ - case 0: /*8 bpp*/ \ - val = vram[addr & virge->vram_mask]; \ - break; \ - case 1: /*16 bpp*/ \ - val = *(uint16_t *)&vram[addr & virge->vram_mask]; \ - break; \ - case 2: /*24 bpp*/ \ - val = (*(uint32_t *)&vram[addr & virge->vram_mask]) & 0xffffff; \ - break; \ - } \ +#define READ(addr, val) \ + do { \ + switch (bpp) { \ + case 0: /*8 bpp*/ \ + val = vram[addr & virge->vram_mask]; \ + break; \ + case 1: /*16 bpp*/ \ + val = *(uint16_t *) &vram[addr & virge->vram_mask]; \ + break; \ + case 2: /*24 bpp*/ \ + val = (*(uint32_t *) &vram[addr & virge->vram_mask]) & 0xffffff; \ + break; \ + } \ } while (0) -#define Z_READ(addr) *(uint16_t *)&vram[addr & virge->vram_mask] +#define Z_READ(addr) *(uint16_t *) &vram[addr & virge->vram_mask] -#define Z_WRITE(addr, val) \ - if (!(s3d_tri->cmd_set & CMD_SET_ZB_MODE)) \ - *(uint16_t *)&vram[addr & virge->vram_mask] = val +#define Z_WRITE(addr, val) \ + if (!(s3d_tri->cmd_set & CMD_SET_ZB_MODE)) \ + *(uint16_t *) &vram[addr & virge->vram_mask] = val #define CLIP(x, y) \ do { \ @@ -2174,12 +2178,12 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) else \ Zzb = Zs; \ break; \ - case 5: \ + case 5: \ if (Zs == Zzb) \ update = 0; \ else \ Zzb = Zs; \ - break; \ + break; \ case 6: \ if (Zs > Zzb) \ update = 0; \ @@ -2188,10 +2192,10 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) break; \ case 7: \ update = 1; \ - Zzb = Zs; \ + Zzb = Zs; \ break; \ } \ - } while (0) + } while (0) #define ROPMIX(R, D, P, S, out) \ { \ @@ -2967,7 +2971,11 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) } \ } -#define MIX() do { ROPMIX(virge->s3d.rop & 0xFF, dest, pattern, source, out); out &= 0xFFFFFF; } while (0) +#define MIX() \ + do { \ + ROPMIX(virge->s3d.rop & 0xFF, dest, pattern, source, out); \ + out &= 0xFFFFFF; \ + } while (0) #define WRITE(addr, val) \ do { \ @@ -2994,7 +3002,7 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) { - uint8_t *vram = virge->svga.vram; + uint8_t *vram = virge->svga.vram; uint32_t mono_pattern[64]; int count_mask; int x_inc = (virge->s3d.cmd_set & CMD_SET_XP) ? 1 : -1; @@ -3008,33 +3016,33 @@ s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) switch (virge->s3d.cmd_set & CMD_SET_FORMAT_MASK) { case CMD_SET_FORMAT_8: - bpp = 0; - x_mul = 1; + bpp = 0; + x_mul = 1; cpu_dat_shift = 8; - pattern_data = virge->s3d.pattern_8; - src_fg_clr = virge->s3d.src_fg_clr & 0xff; - src_bg_clr = virge->s3d.src_bg_clr & 0xff; + pattern_data = virge->s3d.pattern_8; + src_fg_clr = virge->s3d.src_fg_clr & 0xff; + src_bg_clr = virge->s3d.src_bg_clr & 0xff; break; case CMD_SET_FORMAT_16: - bpp = 1; - x_mul = 2; + bpp = 1; + x_mul = 2; cpu_dat_shift = 16; - pattern_data = virge->s3d.pattern_16; - src_fg_clr = virge->s3d.src_fg_clr & 0xffff; - src_bg_clr = virge->s3d.src_bg_clr & 0xffff; + pattern_data = virge->s3d.pattern_16; + src_fg_clr = virge->s3d.src_fg_clr & 0xffff; + src_bg_clr = virge->s3d.src_bg_clr & 0xffff; break; case CMD_SET_FORMAT_24: default: - bpp = 2; - x_mul = 3; + bpp = 2; + x_mul = 3; cpu_dat_shift = 24; - pattern_data = virge->s3d.pattern_24; - src_fg_clr = virge->s3d.src_fg_clr; - src_bg_clr = virge->s3d.src_bg_clr; + pattern_data = virge->s3d.pattern_24; + src_fg_clr = virge->s3d.src_fg_clr; + src_bg_clr = virge->s3d.src_bg_clr; break; - } - if (virge->s3d.cmd_set & CMD_SET_MP) - pattern_data = mono_pattern; + } + if (virge->s3d.cmd_set & CMD_SET_MP) + pattern_data = mono_pattern; switch (virge->s3d.cmd_set & CMD_SET_ITA_MASK) { case CMD_SET_ITA_BYTE: @@ -3052,16 +3060,16 @@ s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) int x; int y; for (y = 0; y < 4; y++) { - for (x = 0; x < 8; x++) { - if (virge->s3d.mono_pat_0 & (1 << (x + y * 8))) - mono_pattern[y * 8 + (7 - x)] = virge->s3d.pat_fg_clr; - else - mono_pattern[y * 8 + (7 - x)] = virge->s3d.pat_bg_clr; - if (virge->s3d.mono_pat_1 & (1 << (x + y * 8))) - mono_pattern[(y + 4) * 8 + (7 - x)] = virge->s3d.pat_fg_clr; - else - mono_pattern[(y + 4) * 8 + (7 - x)] = virge->s3d.pat_bg_clr; - } + for (x = 0; x < 8; x++) { + if (virge->s3d.mono_pat_0 & (1 << (x + y * 8))) + mono_pattern[y * 8 + (7 - x)] = virge->s3d.pat_fg_clr; + else + mono_pattern[y * 8 + (7 - x)] = virge->s3d.pat_bg_clr; + if (virge->s3d.mono_pat_1 & (1 << (x + y * 8))) + mono_pattern[(y + 4) * 8 + (7 - x)] = virge->s3d.pat_fg_clr; + else + mono_pattern[(y + 4) * 8 + (7 - x)] = virge->s3d.pat_bg_clr; + } } } switch (virge->s3d.cmd_set & CMD_SET_COMMAND_MASK) { @@ -3070,13 +3078,13 @@ s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) case CMD_SET_COMMAND_BITBLT: if (count == -1) { - virge->s3d.src_x = virge->s3d.rsrc_x; - virge->s3d.src_y = virge->s3d.rsrc_y; - virge->s3d.dest_x = virge->s3d.rdest_x; - virge->s3d.dest_y = virge->s3d.rdest_y; - virge->s3d.w = virge->s3d.r_width; - virge->s3d.h = virge->s3d.r_height; - virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; + virge->s3d.src_x = virge->s3d.rsrc_x; + virge->s3d.src_y = virge->s3d.rsrc_y; + virge->s3d.dest_x = virge->s3d.rdest_x; + virge->s3d.dest_y = virge->s3d.rdest_y; + virge->s3d.w = virge->s3d.r_width; + virge->s3d.h = virge->s3d.r_height; + virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; virge->s3d.data_left_count = 0; if (virge->s3d.cmd_set & CMD_SET_IDS) @@ -3092,8 +3100,8 @@ s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) uint32_t source = 0; uint32_t dest = 0; uint32_t pattern; - uint32_t out = 0; - int update = 1; + uint32_t out = 0; + int update = 1; switch (virge->s3d.cmd_set & (CMD_SET_MS | CMD_SET_IDS)) { case 0: @@ -3111,18 +3119,18 @@ s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) count -= (cpu_dat_shift - virge->s3d.data_left_count); virge->s3d.data_left_count = 0; if (count < cpu_dat_shift) { - virge->s3d.data_left = cpu_dat; + virge->s3d.data_left = cpu_dat; virge->s3d.data_left_count = count; - count = 0; + count = 0; } } else { source = cpu_dat; cpu_dat >>= cpu_dat_shift; count -= cpu_dat_shift; if (count < cpu_dat_shift) { - virge->s3d.data_left = cpu_dat; + virge->s3d.data_left = cpu_dat; virge->s3d.data_left_count = count; - count = 0; + count = 0; } } if ((virge->s3d.cmd_set & CMD_SET_TP) && source == src_fg_clr) @@ -3152,9 +3160,9 @@ s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) virge->s3d.dest_x += x_inc; virge->s3d.dest_x &= 0x7ff; if (!virge->s3d.w) { - virge->s3d.src_x = virge->s3d.rsrc_x; + virge->s3d.src_x = virge->s3d.rsrc_x; virge->s3d.dest_x = virge->s3d.rdest_x; - virge->s3d.w = virge->s3d.r_width; + virge->s3d.w = virge->s3d.r_width; virge->s3d.src_y += y_inc; virge->s3d.dest_y += y_inc; @@ -3182,23 +3190,22 @@ s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) case CMD_SET_COMMAND_RECTFILL: /*No source, pattern = pat_fg_clr*/ if (count == -1) { - virge->s3d.src_x = virge->s3d.rsrc_x; - virge->s3d.src_y = virge->s3d.rsrc_y; + virge->s3d.src_x = virge->s3d.rsrc_x; + virge->s3d.src_y = virge->s3d.rsrc_y; virge->s3d.dest_x = virge->s3d.rdest_x; virge->s3d.dest_y = virge->s3d.rdest_y; - virge->s3d.w = virge->s3d.r_width; - virge->s3d.h = virge->s3d.r_height; - virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; + virge->s3d.w = virge->s3d.r_width; + virge->s3d.h = virge->s3d.r_height; + virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; } while (count && virge->s3d.h) { - uint32_t dest_addr = virge->s3d.dest_base + (virge->s3d.dest_x * x_mul) + - (virge->s3d.dest_y * virge->s3d.dest_str); + uint32_t dest_addr = virge->s3d.dest_base + (virge->s3d.dest_x * x_mul) + (virge->s3d.dest_y * virge->s3d.dest_str); uint32_t source = 0; uint32_t dest = 0; uint32_t pattern = virge->s3d.pat_fg_clr; uint32_t out = 0; - int update = 1; + int update = 1; CLIP(virge->s3d.dest_x, virge->s3d.dest_y); @@ -3215,9 +3222,9 @@ s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) virge->s3d.dest_x += x_inc; virge->s3d.dest_x &= 0x7ff; if (!virge->s3d.w) { - virge->s3d.src_x = virge->s3d.rsrc_x; + virge->s3d.src_x = virge->s3d.rsrc_x; virge->s3d.dest_x = virge->s3d.rdest_x; - virge->s3d.w = virge->s3d.r_width; + virge->s3d.w = virge->s3d.r_width; virge->s3d.src_y += y_inc; virge->s3d.dest_y += y_inc; @@ -3225,7 +3232,7 @@ s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) if (!virge->s3d.h) return; } else - virge->s3d.w--; + virge->s3d.w--; count--; } break; @@ -3234,8 +3241,8 @@ s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) if (count == -1) { virge->s3d.dest_x = virge->s3d.lxstart; virge->s3d.dest_y = virge->s3d.lystart; - virge->s3d.h = virge->s3d.lycnt; - virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; + virge->s3d.h = virge->s3d.lycnt; + virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; } while (virge->s3d.h) { int x; @@ -3262,8 +3269,8 @@ s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) uint32_t source = 0; uint32_t dest = 0; uint32_t pattern; - uint32_t out = 0; - int update = 1; + uint32_t out = 0; + int update = 1; if ((virge->s3d.h == virge->s3d.lycnt || !first_pixel) && ((virge->s3d.line_dir && x < virge->s3d.lxend0) || @@ -3306,39 +3313,39 @@ skip_line: virge->s3d.dest_r = virge->s3d.prxstart; if (virge->s3d.pycnt & (1 << 29)) virge->s3d.dest_l = virge->s3d.plxstart; - virge->s3d.h = virge->s3d.pycnt & 0x7ff; + virge->s3d.h = virge->s3d.pycnt & 0x7ff; virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; while (virge->s3d.h) { - int x = virge->s3d.dest_l >> 20; - int xend = virge->s3d.dest_r >> 20; - int y = virge->s3d.pystart & 0x7ff; - int xdir = (x < xend) ? 1 : -1; - do { - uint32_t dest_addr = virge->s3d.dest_base + (x * x_mul) + (y * virge->s3d.dest_str); - uint32_t source = 0; - uint32_t dest = 0; - uint32_t pattern; - uint32_t out = 0; - int update = 1; + int x = virge->s3d.dest_l >> 20; + int xend = virge->s3d.dest_r >> 20; + int y = virge->s3d.pystart & 0x7ff; + int xdir = (x < xend) ? 1 : -1; + do { + uint32_t dest_addr = virge->s3d.dest_base + (x * x_mul) + (y * virge->s3d.dest_str); + uint32_t source = 0; + uint32_t dest = 0; + uint32_t pattern; + uint32_t out = 0; + int update = 1; - CLIP(x, y); + CLIP(x, y); - if (update) { - READ(dest_addr, dest); - pattern = pattern_data[(y & 7) * 8 + (x & 7)]; + if (update) { + READ(dest_addr, dest); + pattern = pattern_data[(y & 7) * 8 + (x & 7)]; - MIX(); + MIX(); - WRITE(dest_addr, out); - } + WRITE(dest_addr, out); + } - x = (x + xdir) & 0x7ff; - } while (x != (xend + xdir)); + x = (x + xdir) & 0x7ff; + } while (x != (xend + xdir)); - virge->s3d.dest_l += virge->s3d.pldx; - virge->s3d.dest_r += virge->s3d.prdx; - virge->s3d.h--; - virge->s3d.pystart = (virge->s3d.pystart - 1) & 0x7ff; + virge->s3d.dest_l += virge->s3d.pldx; + virge->s3d.dest_r += virge->s3d.prdx; + virge->s3d.h--; + virge->s3d.pystart = (virge->s3d.pystart - 1) & 0x7ff; } break; @@ -3375,54 +3382,57 @@ skip_line: #define RGB24(r, g, b) ((b) | ((g) << 8) | ((r) << 16)) typedef struct rgba_t { - int r, g, b, a; + int r; + int g; + int b; + int a; } rgba_t; typedef struct s3d_state_t { - int32_t r; - int32_t g; - int32_t b; - int32_t a; - int32_t u; - int32_t v; - int32_t d; - int32_t w; + int32_t r; + int32_t g; + int32_t b; + int32_t a; + int32_t u; + int32_t v; + int32_t d; + int32_t w; - int32_t base_r; - int32_t base_g; - int32_t base_b; - int32_t base_a; - int32_t base_u; - int32_t base_v; - int32_t base_d; - int32_t base_w; + int32_t base_r; + int32_t base_g; + int32_t base_b; + int32_t base_a; + int32_t base_u; + int32_t base_v; + int32_t base_d; + int32_t base_w; - uint32_t base_z; + uint32_t base_z; - uint32_t tbu; - uint32_t tbv; + uint32_t tbu; + uint32_t tbv; - uint32_t cmd_set; - int max_d; + uint32_t cmd_set; + int max_d; uint16_t *texture[10]; - uint32_t tex_bdr_clr; + uint32_t tex_bdr_clr; - int32_t x1; - int32_t x2; + int32_t x1; + int32_t x2; - int y; + int y; - rgba_t dest_rgba; + rgba_t dest_rgba; } s3d_state_t; typedef struct s3d_texture_state_t { - int level; - int texture_shift; + int level; + int texture_shift; - int32_t u; - int32_t v; + int32_t u; + int32_t v; } s3d_texture_state_t; static void (*tex_read)(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out); @@ -3436,7 +3446,8 @@ static int _x; static int _y; static void -tex_ARGB1555(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) { +tex_ARGB1555(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); uint16_t val = state->texture[texture_state->level][offset]; @@ -3448,7 +3459,8 @@ tex_ARGB1555(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out } static void -tex_ARGB1555_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) { +tex_ARGB1555_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); uint16_t val = state->texture[texture_state->level][offset]; @@ -3463,7 +3475,8 @@ tex_ARGB1555_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba } static void -tex_ARGB4444(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) { +tex_ARGB4444(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); uint16_t val = state->texture[texture_state->level][offset]; @@ -3475,7 +3488,8 @@ tex_ARGB4444(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out } static void -tex_ARGB4444_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) { +tex_ARGB4444_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); uint16_t val = state->texture[texture_state->level][offset]; @@ -3490,7 +3504,8 @@ tex_ARGB4444_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba } static void -tex_ARGB8888(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) { +tex_ARGB8888(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); uint32_t val = ((uint32_t *)state->texture[texture_state->level])[offset]; @@ -3502,7 +3517,8 @@ tex_ARGB8888(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out } static void -tex_ARGB8888_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) { +tex_ARGB8888_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); uint32_t val = ((uint32_t *)state->texture[texture_state->level])[offset]; @@ -3517,19 +3533,21 @@ tex_ARGB8888_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba } static void -tex_sample_normal(s3d_state_t *state) { +tex_sample_normal(s3d_state_t *state) +{ s3d_texture_state_t texture_state; - texture_state.level = state->max_d; + texture_state.level = state->max_d; texture_state.texture_shift = 18 + (9 - texture_state.level); - texture_state.u = state->u + state->tbu; - texture_state.v = state->v + state->tbv; + texture_state.u = state->u + state->tbu; + texture_state.v = state->v + state->tbv; tex_read(state, &texture_state, &state->dest_rgba); } static void -tex_sample_normal_filter(s3d_state_t *state) { +tex_sample_normal_filter(s3d_state_t *state) +{ s3d_texture_state_t texture_state; int tex_offset; rgba_t tex_samples[4]; @@ -3537,9 +3555,9 @@ tex_sample_normal_filter(s3d_state_t *state) { int dv; int d[4]; - texture_state.level = state->max_d; + texture_state.level = state->max_d; texture_state.texture_shift = 18 + (9 - texture_state.level); - tex_offset = 1 << texture_state.texture_shift; + tex_offset = 1 << texture_state.texture_shift; texture_state.u = state->u + state->tbu; texture_state.v = state->v + state->tbv; @@ -3575,21 +3593,23 @@ tex_sample_normal_filter(s3d_state_t *state) { } static void -tex_sample_mipmap(s3d_state_t *state) { +tex_sample_mipmap(s3d_state_t *state) +{ s3d_texture_state_t texture_state; texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); if (texture_state.level < 0) texture_state.level = 0; texture_state.texture_shift = 18 + (9 - texture_state.level); - texture_state.u = state->u + state->tbu; - texture_state.v = state->v + state->tbv; + texture_state.u = state->u + state->tbu; + texture_state.v = state->v + state->tbv; tex_read(state, &texture_state, &state->dest_rgba); } static void -tex_sample_mipmap_filter(s3d_state_t *state) { +tex_sample_mipmap_filter(s3d_state_t *state) +{ s3d_texture_state_t texture_state; int tex_offset; rgba_t tex_samples[4]; @@ -3601,7 +3621,7 @@ tex_sample_mipmap_filter(s3d_state_t *state) { if (texture_state.level < 0) texture_state.level = 0; texture_state.texture_shift = 18 + (9 - texture_state.level); - tex_offset = 1 << texture_state.texture_shift; + tex_offset = 1 << texture_state.texture_shift; texture_state.u = state->u + state->tbu; texture_state.v = state->v + state->tbv; @@ -3637,25 +3657,27 @@ tex_sample_mipmap_filter(s3d_state_t *state) { } static void -tex_sample_persp_normal(s3d_state_t *state) { +tex_sample_persp_normal(s3d_state_t *state) +{ s3d_texture_state_t texture_state; - int32_t w = 0; + int32_t w = 0; if (state->w) - w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + w = (int32_t) (((1ULL << 27) << 19) / (int64_t) state->w); - texture_state.level = state->max_d; + texture_state.level = state->max_d; texture_state.texture_shift = 18 + (9 - texture_state.level); - texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu; - texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv; + texture_state.u = (int32_t) (((int64_t) state->u * (int64_t) w) >> (12 + state->max_d)) + state->tbu; + texture_state.v = (int32_t) (((int64_t) state->v * (int64_t) w) >> (12 + state->max_d)) + state->tbv; tex_read(state, &texture_state, &state->dest_rgba); } static void -tex_sample_persp_normal_filter(s3d_state_t *state) { +tex_sample_persp_normal_filter(s3d_state_t *state) +{ s3d_texture_state_t texture_state; - int32_t w = 0; + int32_t w = 0; int32_t u; int32_t v; int tex_offset; @@ -3665,14 +3687,14 @@ tex_sample_persp_normal_filter(s3d_state_t *state) { int d[4]; if (state->w) - w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + w = (int32_t) (((1ULL << 27) << 19) / (int64_t) state->w); - u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu; - v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv; + u = (int32_t) (((int64_t) state->u * (int64_t) w) >> (12 + state->max_d)) + state->tbu; + v = (int32_t) (((int64_t) state->v * (int64_t) w) >> (12 + state->max_d)) + state->tbv; - texture_state.level = state->max_d; + texture_state.level = state->max_d; texture_state.texture_shift = 18 + (9 - texture_state.level); - tex_offset = 1 << texture_state.texture_shift; + tex_offset = 1 << texture_state.texture_shift; texture_state.u = u; texture_state.v = v; @@ -3708,25 +3730,27 @@ tex_sample_persp_normal_filter(s3d_state_t *state) { } static void -tex_sample_persp_normal_375(s3d_state_t *state) { +tex_sample_persp_normal_375(s3d_state_t *state) +{ s3d_texture_state_t texture_state; - int32_t w = 0; + int32_t w = 0; if (state->w) - w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + w = (int32_t) (((1ULL << 27) << 19) / (int64_t) state->w); - texture_state.level = state->max_d; + texture_state.level = state->max_d; texture_state.texture_shift = 18 + (9 - texture_state.level); - texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu; - texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv; + texture_state.u = (int32_t) (((int64_t) state->u * (int64_t) w) >> (8 + state->max_d)) + state->tbu; + texture_state.v = (int32_t) (((int64_t) state->v * (int64_t) w) >> (8 + state->max_d)) + state->tbv; tex_read(state, &texture_state, &state->dest_rgba); } static void -tex_sample_persp_normal_filter_375(s3d_state_t *state) { +tex_sample_persp_normal_filter_375(s3d_state_t *state) +{ s3d_texture_state_t texture_state; - int32_t w = 0; + int32_t w = 0; int32_t u; int32_t v; int tex_offset; @@ -3736,14 +3760,14 @@ tex_sample_persp_normal_filter_375(s3d_state_t *state) { int d[4]; if (state->w) - w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + w = (int32_t) (((1ULL << 27) << 19) / (int64_t) state->w); - u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu; - v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv; + u = (int32_t) (((int64_t) state->u * (int64_t) w) >> (8 + state->max_d)) + state->tbu; + v = (int32_t) (((int64_t) state->v * (int64_t) w) >> (8 + state->max_d)) + state->tbv; - texture_state.level = state->max_d; + texture_state.level = state->max_d; texture_state.texture_shift = 18 + (9 - texture_state.level); - tex_offset = 1 << texture_state.texture_shift; + tex_offset = 1 << texture_state.texture_shift; texture_state.u = u; texture_state.v = v; @@ -3779,27 +3803,29 @@ tex_sample_persp_normal_filter_375(s3d_state_t *state) { } static void -tex_sample_persp_mipmap(s3d_state_t *state) { +tex_sample_persp_mipmap(s3d_state_t *state) +{ s3d_texture_state_t texture_state; - int32_t w = 0; + int32_t w = 0; if (state->w) - w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + w = (int32_t) (((1ULL << 27) << 19) / (int64_t) state->w); texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); if (texture_state.level < 0) texture_state.level = 0; texture_state.texture_shift = 18 + (9 - texture_state.level); - texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu; - texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv; + texture_state.u = (int32_t) (((int64_t) state->u * (int64_t) w) >> (12 + state->max_d)) + state->tbu; + texture_state.v = (int32_t) (((int64_t) state->v * (int64_t) w) >> (12 + state->max_d)) + state->tbv; tex_read(state, &texture_state, &state->dest_rgba); } static void -tex_sample_persp_mipmap_filter(s3d_state_t *state) { +tex_sample_persp_mipmap_filter(s3d_state_t *state) +{ s3d_texture_state_t texture_state; - int32_t w = 0; + int32_t w = 0; int32_t u; int32_t v; int tex_offset; @@ -3809,16 +3835,16 @@ tex_sample_persp_mipmap_filter(s3d_state_t *state) { int d[4]; if (state->w) - w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + w = (int32_t) (((1ULL << 27) << 19) / (int64_t) state->w); - u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu; - v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv; + u = (int32_t) (((int64_t) state->u * (int64_t) w) >> (12 + state->max_d)) + state->tbu; + v = (int32_t) (((int64_t) state->v * (int64_t) w) >> (12 + state->max_d)) + state->tbv; texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); if (texture_state.level < 0) texture_state.level = 0; texture_state.texture_shift = 18 + (9 - texture_state.level); - tex_offset = 1 << texture_state.texture_shift; + tex_offset = 1 << texture_state.texture_shift; texture_state.u = u; texture_state.v = v; @@ -3854,27 +3880,29 @@ tex_sample_persp_mipmap_filter(s3d_state_t *state) { } static void -tex_sample_persp_mipmap_375(s3d_state_t *state) { +tex_sample_persp_mipmap_375(s3d_state_t *state) +{ s3d_texture_state_t texture_state; - int32_t w = 0; + int32_t w = 0; if (state->w) - w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + w = (int32_t) (((1ULL << 27) << 19) / (int64_t) state->w); texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); if (texture_state.level < 0) texture_state.level = 0; texture_state.texture_shift = 18 + (9 - texture_state.level); - texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu; - texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv; + texture_state.u = (int32_t) (((int64_t) state->u * (int64_t) w) >> (8 + state->max_d)) + state->tbu; + texture_state.v = (int32_t) (((int64_t) state->v * (int64_t) w) >> (8 + state->max_d)) + state->tbv; tex_read(state, &texture_state, &state->dest_rgba); } static void -tex_sample_persp_mipmap_filter_375(s3d_state_t *state) { +tex_sample_persp_mipmap_filter_375(s3d_state_t *state) +{ s3d_texture_state_t texture_state; - int32_t w = 0; + int32_t w = 0; int32_t u; int32_t v; int tex_offset; @@ -3884,16 +3912,16 @@ tex_sample_persp_mipmap_filter_375(s3d_state_t *state) { int d[4]; if (state->w) - w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + w = (int32_t) (((1ULL << 27) << 19) / (int64_t) state->w); - u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu; - v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv; + u = (int32_t) (((int64_t) state->u * (int64_t) w) >> (8 + state->max_d)) + state->tbu; + v = (int32_t) (((int64_t) state->v * (int64_t) w) >> (8 + state->max_d)) + state->tbv; texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); if (texture_state.level < 0) texture_state.level = 0; texture_state.texture_shift = 18 + (9 - texture_state.level); - tex_offset = 1 << texture_state.texture_shift; + tex_offset = 1 << texture_state.texture_shift; texture_state.u = u; texture_state.v = v; @@ -3928,40 +3956,41 @@ tex_sample_persp_mipmap_filter_375(s3d_state_t *state) { tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16; } -#define CLAMP(x) \ - do { \ - if ((x) & ~0xff) \ - x = ((x) < 0) ? 0 : 0xff; \ +#define CLAMP(x) \ + do { \ + if ((x) & ~0xff) \ + x = ((x) < 0) ? 0 : 0xff; \ } while (0) -#define CLAMP_RGBA(r, g, b, a) \ - if ((r) & ~0xff) \ - r = ((r) < 0) ? 0 : 0xff; \ - if ((g) & ~0xff) \ - g = ((g) < 0) ? 0 : 0xff; \ - if ((b) & ~0xff) \ - b = ((b) < 0) ? 0 : 0xff; \ - if ((a) & ~0xff) \ - a = ((a) < 0) ? 0 : 0xff; +#define CLAMP_RGBA(r, g, b, a) \ + if ((r) & ~0xff) \ + r = ((r) < 0) ? 0 : 0xff; \ + if ((g) & ~0xff) \ + g = ((g) < 0) ? 0 : 0xff; \ + if ((b) & ~0xff) \ + b = ((b) < 0) ? 0 : 0xff; \ + if ((a) & ~0xff) \ + a = ((a) < 0) ? 0 : 0xff; -#define CLAMP_RGB(r, g, b) \ - do { \ - if ((r) < 0) \ - r = 0; \ - if ((r) > 0xff) \ - r = 0xff; \ - if ((g) < 0) \ - g = 0; \ - if ((g) > 0xff) \ - g = 0xff; \ - if ((b) < 0) \ - b = 0; \ - if ((b) > 0xff) \ - b = 0xff; \ +#define CLAMP_RGB(r, g, b) \ + do { \ + if ((r) < 0) \ + r = 0; \ + if ((r) > 0xff) \ + r = 0xff; \ + if ((g) < 0) \ + g = 0; \ + if ((g) > 0xff) \ + g = 0xff; \ + if ((b) < 0) \ + b = 0; \ + if ((b) > 0xff) \ + b = 0xff; \ } while (0) static void -dest_pixel_gouraud_shaded_triangle(s3d_state_t *state) { +dest_pixel_gouraud_shaded_triangle(s3d_state_t *state) +{ state->dest_rgba.r = state->r >> 7; CLAMP(state->dest_rgba.r); @@ -3976,7 +4005,8 @@ dest_pixel_gouraud_shaded_triangle(s3d_state_t *state) { } static void -dest_pixel_unlit_texture_triangle(s3d_state_t *state) { +dest_pixel_unlit_texture_triangle(s3d_state_t *state) +{ tex_sample(state); if (state->cmd_set & CMD_SET_ABC_SRC) @@ -3984,7 +4014,8 @@ dest_pixel_unlit_texture_triangle(s3d_state_t *state) { } static void -dest_pixel_lit_texture_decal(s3d_state_t *state) { +dest_pixel_lit_texture_decal(s3d_state_t *state) +{ tex_sample(state); if (state->cmd_set & CMD_SET_ABC_SRC) @@ -3992,7 +4023,8 @@ dest_pixel_lit_texture_decal(s3d_state_t *state) { } static void -dest_pixel_lit_texture_reflection(s3d_state_t *state) { +dest_pixel_lit_texture_reflection(s3d_state_t *state) +{ tex_sample(state); state->dest_rgba.r += (state->r >> 7); @@ -4005,7 +4037,8 @@ dest_pixel_lit_texture_reflection(s3d_state_t *state) { } static void -dest_pixel_lit_texture_modulate(s3d_state_t *state) { +dest_pixel_lit_texture_modulate(s3d_state_t *state) +{ int r = state->r >> 7; int g = state->g >> 7; int b = state->b >> 7; @@ -4024,17 +4057,18 @@ dest_pixel_lit_texture_modulate(s3d_state_t *state) { } static void -tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int32_t dx1, int32_t dx2) { - uint8_t *vram = virge->svga.vram; - int x_dir = s3d_tri->tlr ? 1 : -1; - int use_z = !(s3d_tri->cmd_set & CMD_SET_ZB_MODE); - int y_count = yc; - int bpp = (s3d_tri->cmd_set >> 2) & 7; - uint32_t dest_offset; - uint32_t z_offset; +tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int32_t dx1, int32_t dx2) +{ + uint8_t *vram = virge->svga.vram; + int x_dir = s3d_tri->tlr ? 1 : -1; + int use_z = !(s3d_tri->cmd_set & CMD_SET_ZB_MODE); + int y_count = yc; + int bpp = (s3d_tri->cmd_set >> 2) & 7; + uint32_t dest_offset; + uint32_t z_offset; dest_offset = s3d_tri->dest_base + (state->y * s3d_tri->dest_str); - z_offset = s3d_tri->z_base + (state->y * s3d_tri->z_str); + z_offset = s3d_tri->z_base + (state->y * s3d_tri->z_str); if (s3d_tri->cmd_set & CMD_SET_HC) { if (state->y < s3d_tri->clip_t) @@ -4054,195 +4088,190 @@ tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int32_t dx1, int state->base_a += (s3d_tri->TdAdY * diff_y); state->base_d += (s3d_tri->TdDdY * diff_y); state->base_w += (s3d_tri->TdWdY * diff_y); - state->x1 += (dx1 * diff_y); - state->x2 += (dx2 * diff_y); - state->y -= diff_y; - dest_offset -= s3d_tri->dest_str; - z_offset -= s3d_tri->z_str; - y_count -= diff_y; + state->x1 += (dx1 * diff_y); + state->x2 += (dx2 * diff_y); + state->y -= diff_y; + dest_offset -= s3d_tri->dest_str; + z_offset -= s3d_tri->z_str; + y_count -= diff_y; } if ((state->y - y_count) < s3d_tri->clip_t) y_count = (state->y - s3d_tri->clip_t) + 1; } for (; y_count > 0; y_count--) { - int x = (state->x1 + ((1 << 20) - 1)) >> 20; - int xe = (state->x2 + ((1 << 20) - 1)) >> 20; - uint32_t z = (state->base_z > 0) ? (state->base_z << 1) : 0; + int x = (state->x1 + ((1 << 20) - 1)) >> 20; + int xe = (state->x2 + ((1 << 20) - 1)) >> 20; + uint32_t z = (state->base_z > 0) ? (state->base_z << 1) : 0; - if (x_dir < 0) { - x--; - xe--; - } + if (x_dir < 0) { + x--; + xe--; + } - if (x != xe && ((x_dir > 0 && x < xe) || (x_dir < 0 && x > xe))) { - uint32_t dest_addr; - uint32_t z_addr; - int dx = (x_dir > 0) ? ((31 - ((state->x1 - 1) >> 15)) & 0x1f) : - (((state->x1 - 1) >> 15) & 0x1f); - int x_offset = x_dir * (bpp + 1); - int xz_offset = x_dir << 1; + if (x != xe && ((x_dir > 0 && x < xe) || (x_dir < 0 && x > xe))) { + uint32_t dest_addr; + uint32_t z_addr; + int dx = (x_dir > 0) ? ((31 - ((state->x1 - 1) >> 15)) & 0x1f) : (((state->x1 - 1) >> 15) & 0x1f); + int x_offset = x_dir * (bpp + 1); + int xz_offset = x_dir << 1; - if (x_dir > 0) - dx += 1; + if (x_dir > 0) + dx += 1; - state->r = state->base_r + ((s3d_tri->TdRdX * dx) >> 5); - state->g = state->base_g + ((s3d_tri->TdGdX * dx) >> 5); - state->b = state->base_b + ((s3d_tri->TdBdX * dx) >> 5); - state->a = state->base_a + ((s3d_tri->TdAdX * dx) >> 5); - state->u = state->base_u + ((s3d_tri->TdUdX * dx) >> 5); - state->v = state->base_v + ((s3d_tri->TdVdX * dx) >> 5); - state->w = state->base_w + ((s3d_tri->TdWdX * dx) >> 5); - state->d = state->base_d + ((s3d_tri->TdDdX * dx) >> 5); - z += ((s3d_tri->TdZdX * dx) >> 5); + state->r = state->base_r + ((s3d_tri->TdRdX * dx) >> 5); + state->g = state->base_g + ((s3d_tri->TdGdX * dx) >> 5); + state->b = state->base_b + ((s3d_tri->TdBdX * dx) >> 5); + state->a = state->base_a + ((s3d_tri->TdAdX * dx) >> 5); + state->u = state->base_u + ((s3d_tri->TdUdX * dx) >> 5); + state->v = state->base_v + ((s3d_tri->TdVdX * dx) >> 5); + state->w = state->base_w + ((s3d_tri->TdWdX * dx) >> 5); + state->d = state->base_d + ((s3d_tri->TdDdX * dx) >> 5); + z += ((s3d_tri->TdZdX * dx) >> 5); - if (s3d_tri->cmd_set & CMD_SET_HC) { - if (x_dir > 0) { - if (x > s3d_tri->clip_r) - goto tri_skip_line; - if (xe < s3d_tri->clip_l) - goto tri_skip_line; - if (xe > s3d_tri->clip_r) - xe = s3d_tri->clip_r + 1; - if (x < s3d_tri->clip_l) { - int diff_x = s3d_tri->clip_l - x; + if (s3d_tri->cmd_set & CMD_SET_HC) { + if (x_dir > 0) { + if (x > s3d_tri->clip_r) + goto tri_skip_line; + if (xe < s3d_tri->clip_l) + goto tri_skip_line; + if (xe > s3d_tri->clip_r) + xe = s3d_tri->clip_r + 1; + if (x < s3d_tri->clip_l) { + int diff_x = s3d_tri->clip_l - x; - z += (s3d_tri->TdZdX * diff_x); - state->u += (s3d_tri->TdUdX * diff_x); - state->v += (s3d_tri->TdVdX * diff_x); - state->r += (s3d_tri->TdRdX * diff_x); - state->g += (s3d_tri->TdGdX * diff_x); - state->b += (s3d_tri->TdBdX * diff_x); - state->a += (s3d_tri->TdAdX * diff_x); - state->d += (s3d_tri->TdDdX * diff_x); - state->w += (s3d_tri->TdWdX * diff_x); + z += (s3d_tri->TdZdX * diff_x); + state->u += (s3d_tri->TdUdX * diff_x); + state->v += (s3d_tri->TdVdX * diff_x); + state->r += (s3d_tri->TdRdX * diff_x); + state->g += (s3d_tri->TdGdX * diff_x); + state->b += (s3d_tri->TdBdX * diff_x); + state->a += (s3d_tri->TdAdX * diff_x); + state->d += (s3d_tri->TdDdX * diff_x); + state->w += (s3d_tri->TdWdX * diff_x); - x = s3d_tri->clip_l; - } - } else { - if (x < s3d_tri->clip_l) - goto tri_skip_line; - if (xe > s3d_tri->clip_r) - goto tri_skip_line; - if (xe < s3d_tri->clip_l) - xe = s3d_tri->clip_l - 1; - if (x > s3d_tri->clip_r) { - int diff_x = x - s3d_tri->clip_r; + x = s3d_tri->clip_l; + } + } else { + if (x < s3d_tri->clip_l) + goto tri_skip_line; + if (xe > s3d_tri->clip_r) + goto tri_skip_line; + if (xe < s3d_tri->clip_l) + xe = s3d_tri->clip_l - 1; + if (x > s3d_tri->clip_r) { + int diff_x = x - s3d_tri->clip_r; - z += (s3d_tri->TdZdX * diff_x); - state->u += (s3d_tri->TdUdX * diff_x); - state->v += (s3d_tri->TdVdX * diff_x); - state->r += (s3d_tri->TdRdX * diff_x); - state->g += (s3d_tri->TdGdX * diff_x); - state->b += (s3d_tri->TdBdX * diff_x); - state->a += (s3d_tri->TdAdX * diff_x); - state->d += (s3d_tri->TdDdX * diff_x); - state->w += (s3d_tri->TdWdX * diff_x); + z += (s3d_tri->TdZdX * diff_x); + state->u += (s3d_tri->TdUdX * diff_x); + state->v += (s3d_tri->TdVdX * diff_x); + state->r += (s3d_tri->TdRdX * diff_x); + state->g += (s3d_tri->TdGdX * diff_x); + state->b += (s3d_tri->TdBdX * diff_x); + state->a += (s3d_tri->TdAdX * diff_x); + state->d += (s3d_tri->TdDdX * diff_x); + state->w += (s3d_tri->TdWdX * diff_x); - x = s3d_tri->clip_r; - } - } - } + x = s3d_tri->clip_r; + } + } + } - virge->svga.changedvram[(dest_offset & virge->vram_mask) >> 12] = changeframecount; + virge->svga.changedvram[(dest_offset & virge->vram_mask) >> 12] = changeframecount; - dest_addr = dest_offset + (x * (bpp + 1)); - z_addr = z_offset + (x << 1); + dest_addr = dest_offset + (x * (bpp + 1)); + z_addr = z_offset + (x << 1); - x &= 0xfff; - xe &= 0xfff; + x &= 0xfff; + xe &= 0xfff; - for (; x != xe; x = (x + x_dir) & 0xfff) { - int update = 1; - uint16_t src_z = 0; + for (; x != xe; x = (x + x_dir) & 0xfff) { + int update = 1; + uint16_t src_z = 0; - _x = x; - _y = state->y; + _x = x; + _y = state->y; - if (use_z) { - src_z = Z_READ(z_addr); - Z_CLIP(src_z, z >> 16); - } + if (use_z) { + src_z = Z_READ(z_addr); + Z_CLIP(src_z, z >> 16); + } - if (update) { - uint32_t dest_col; + if (update) { + uint32_t dest_col; - dest_pixel(state); + dest_pixel(state); - if (s3d_tri->cmd_set & CMD_SET_FE) { - int a = state->a >> 7; - state->dest_rgba.r = ((state->dest_rgba.r * a) + (s3d_tri->fog_r * (255 - a))) / 255; - state->dest_rgba.g = ((state->dest_rgba.g * a) + (s3d_tri->fog_g * (255 - a))) / 255; - state->dest_rgba.b = ((state->dest_rgba.b * a) + (s3d_tri->fog_b * (255 - a))) / 255; - } + if (s3d_tri->cmd_set & CMD_SET_FE) { + int a = state->a >> 7; + state->dest_rgba.r = ((state->dest_rgba.r * a) + (s3d_tri->fog_r * (255 - a))) / 255; + state->dest_rgba.g = ((state->dest_rgba.g * a) + (s3d_tri->fog_g * (255 - a))) / 255; + state->dest_rgba.b = ((state->dest_rgba.b * a) + (s3d_tri->fog_b * (255 - a))) / 255; + } - if (s3d_tri->cmd_set & CMD_SET_ABC_ENABLE) { - uint32_t src_col; - int src_r = 0; - uint32_t src_g = 0; - uint32_t src_b = 0; + if (s3d_tri->cmd_set & CMD_SET_ABC_ENABLE) { + uint32_t src_col; + int src_r = 0; + uint32_t src_g = 0; + uint32_t src_b = 0; + switch (bpp) { + case 0: /*8 bpp*/ + /*Not implemented yet*/ + break; + case 1: /*16 bpp*/ + src_col = *(uint16_t *) &vram[dest_addr & virge->vram_mask]; + RGB15_TO_24(src_col, src_r, src_g, src_b); + break; + case 2: /*24 bpp*/ + src_col = (*(uint32_t *) &vram[dest_addr & virge->vram_mask]) & 0xffffff; + RGB24_TO_24(src_col, src_r, src_g, src_b); + break; + } - switch (bpp) { - case 0: /*8 bpp*/ - /*Not implemented yet*/ - break; - case 1: /*16 bpp*/ - src_col = *(uint16_t *)&vram[dest_addr & virge->vram_mask]; - RGB15_TO_24(src_col, src_r, src_g, src_b); - break; - case 2: /*24 bpp*/ - src_col = (*(uint32_t *)&vram[dest_addr & virge->vram_mask]) & 0xffffff; - RGB24_TO_24(src_col, src_r, src_g, src_b); - break; - } + state->dest_rgba.r = ((state->dest_rgba.r * state->dest_rgba.a) + (src_r * (255 - state->dest_rgba.a))) / 255; + state->dest_rgba.g = ((state->dest_rgba.g * state->dest_rgba.a) + (src_g * (255 - state->dest_rgba.a))) / 255; + state->dest_rgba.b = ((state->dest_rgba.b * state->dest_rgba.a) + (src_b * (255 - state->dest_rgba.a))) / 255; + } - state->dest_rgba.r = ((state->dest_rgba.r * state->dest_rgba.a) + - (src_r * (255 - state->dest_rgba.a))) / 255; - state->dest_rgba.g = ((state->dest_rgba.g * state->dest_rgba.a) + - (src_g * (255 - state->dest_rgba.a))) / 255; - state->dest_rgba.b = ((state->dest_rgba.b * state->dest_rgba.a) + - (src_b * (255 - state->dest_rgba.a))) / 255; - } + switch (bpp) { + case 0: /*8 bpp*/ + /*Not implemented yet*/ + break; + case 1: /*16 bpp*/ + RGB15(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b, dest_col); + *(uint16_t *) &vram[dest_addr] = dest_col; + break; + case 2: /*24 bpp*/ + dest_col = RGB24(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b); + *(uint8_t *) &vram[dest_addr] = dest_col & 0xff; + *(uint8_t *) &vram[dest_addr + 1] = (dest_col >> 8) & 0xff; + *(uint8_t *) &vram[dest_addr + 2] = (dest_col >> 16) & 0xff; + break; + } - switch (bpp) { - case 0: /*8 bpp*/ - /*Not implemented yet*/ - break; - case 1: /*16 bpp*/ - RGB15(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b, dest_col); - *(uint16_t *)&vram[dest_addr] = dest_col; - break; - case 2: /*24 bpp*/ - dest_col = RGB24(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b); - *(uint8_t *)&vram[dest_addr] = dest_col & 0xff; - *(uint8_t *)&vram[dest_addr + 1] = (dest_col >> 8) & 0xff; - *(uint8_t *)&vram[dest_addr + 2] = (dest_col >> 16) & 0xff; - break; - } + if (use_z && (s3d_tri->cmd_set & CMD_SET_ZUP)) + Z_WRITE(z_addr, src_z); + } - if (use_z && (s3d_tri->cmd_set & CMD_SET_ZUP)) - Z_WRITE(z_addr, src_z); - } - - z += s3d_tri->TdZdX; - state->u += s3d_tri->TdUdX; - state->v += s3d_tri->TdVdX; - state->r += s3d_tri->TdRdX; - state->g += s3d_tri->TdGdX; - state->b += s3d_tri->TdBdX; - state->a += s3d_tri->TdAdX; - state->d += s3d_tri->TdDdX; - state->w += s3d_tri->TdWdX; - dest_addr += x_offset; - z_addr += xz_offset; - virge->pixel_count++; - } + z += s3d_tri->TdZdX; + state->u += s3d_tri->TdUdX; + state->v += s3d_tri->TdVdX; + state->r += s3d_tri->TdRdX; + state->g += s3d_tri->TdGdX; + state->b += s3d_tri->TdBdX; + state->a += s3d_tri->TdAdX; + state->d += s3d_tri->TdDdX; + state->w += s3d_tri->TdWdX; + dest_addr += x_offset; + z_addr += xz_offset; + virge->pixel_count++; + } } tri_skip_line: - state->x1 += dx1; - state->x2 += dx2; + state->x1 += dx1; + state->x2 += dx2; state->base_u += s3d_tri->TdUdY; state->base_v += s3d_tri->TdVdY; state->base_z += s3d_tri->TdZdY; @@ -4253,22 +4282,23 @@ tri_skip_line: state->base_d += s3d_tri->TdDdY; state->base_w += s3d_tri->TdWdY; state->y--; - dest_offset -= s3d_tri->dest_str; - z_offset -= s3d_tri->z_str; + dest_offset -= s3d_tri->dest_str; + z_offset -= s3d_tri->z_str; } } -static int tex_size[8] = {4 * 2, 2 * 2, 2 * 2, 1 * 2, 2 / 1, 2 / 1, 1 * 2, 1 * 2}; +static int tex_size[8] = { 4 * 2, 2 * 2, 2 * 2, 1 * 2, 2 / 1, 2 / 1, 1 * 2, 1 * 2 }; static void -s3_virge_triangle(virge_t *virge, s3d_t *s3d_tri) { +s3_virge_triangle(virge_t *virge, s3d_t *s3d_tri) +{ s3d_state_t state; - uint32_t tex_base; - int c; + uint32_t tex_base; + int c; - uint64_t start_time = plat_timer_read(); - uint64_t end_time; + uint64_t start_time = plat_timer_read(); + uint64_t end_time; state.tbu = s3d_tri->tbu << 11; state.tbv = s3d_tri->tbv << 11; @@ -4282,18 +4312,18 @@ s3_virge_triangle(virge_t *virge, s3d_t *s3d_tri) { state.base_u = s3d_tri->tus; state.base_v = s3d_tri->tvs; state.base_z = s3d_tri->tzs; - state.base_r = (int32_t)s3d_tri->trs; - state.base_g = (int32_t)s3d_tri->tgs; - state.base_b = (int32_t)s3d_tri->tbs; - state.base_a = (int32_t)s3d_tri->tas; + state.base_r = (int32_t) s3d_tri->trs; + state.base_g = (int32_t) s3d_tri->tgs; + state.base_b = (int32_t) s3d_tri->tbs; + state.base_a = (int32_t) s3d_tri->tas; state.base_d = s3d_tri->tds; state.base_w = s3d_tri->tws; tex_base = s3d_tri->tex_base; for (c = 9; c >= 0; c--) { - state.texture[c] = (uint16_t *)&virge->svga.vram[tex_base]; - if (c <= state.max_d) - tex_base += ((1 << (c * 2)) * tex_size[(s3d_tri->cmd_set >> 5) & 7]) / 2; + state.texture[c] = (uint16_t *) &virge->svga.vram[tex_base]; + if (c <= state.max_d) + tex_base += ((1 << (c * 2)) * tex_size[(s3d_tri->cmd_set >> 5) & 7]) / 2; } switch ((s3d_tri->cmd_set >> 27) & 0xf) { @@ -4407,7 +4437,7 @@ s3_virge_triangle(virge_t *virge, s3d_t *s3d_tri) { static void render_thread(void *param) { - virge_t *virge = (virge_t *)param; + virge_t *virge = (virge_t *) param; while (virge->render_thread_run) { thread_wait_event(virge->wake_render_thread, -1); @@ -4443,14 +4473,14 @@ queue_triangle(virge_t *virge) static void s3_virge_hwcursor_draw(svga_t *svga, int displine) { - virge_t *virge = (virge_t *) svga->priv; - int x; - uint16_t dat[2] = { 0, 0 }; - int xx; - int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; - uint32_t fg; - uint32_t bg; - uint32_t vram_mask = virge->vram_mask; + virge_t *virge = (virge_t *) svga->priv; + int x; + uint16_t dat[2] = { 0, 0 }; + int xx; + int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; + uint32_t fg; + uint32_t bg; + uint32_t vram_mask = virge->vram_mask; if (svga->interlace && svga->hwcursor_oddeven) svga->hwcursor_latch.addr += 16; @@ -4568,22 +4598,22 @@ s3_virge_hwcursor_draw(svga_t *svga, int displine) CLAMP(b[x_write + 1]); \ \ x_write = (x_write + 2) & 7; \ - } \ + } \ } while (0) /*Both YUV formats are untested*/ #define DECODE_YUV211() \ do { \ uint8_t y1, y2, y3, y4; \ - int8_t U, V; \ - int dR; \ - int dG; \ - int dB; \ + int8_t U, V; \ + int dR; \ + int dG; \ + int dB; \ \ - U = src[0] - 0x80; \ + U = src[0] - 0x80; \ y1 = (298 * (src[1] - 16)) >> 8; \ y2 = (298 * (src[2] - 16)) >> 8; \ - V = src[3] - 0x80; \ + V = src[3] - 0x80; \ y3 = (298 * (src[4] - 16)) >> 8; \ y4 = (298 * (src[5] - 16)) >> 8; \ src += 6; \ @@ -4634,9 +4664,9 @@ s3_virge_hwcursor_draw(svga_t *svga, int displine) int dG; \ int dB; \ \ - U = src[0] - 0x80; \ + U = src[0] - 0x80; \ y1 = (298 * (src[1] - 16)) >> 8; \ - V = src[2] - 0x80; \ + V = src[2] - 0x80; \ y2 = (298 * (src[3] - 16)) >> 8; \ src += 4; \ \ @@ -4757,13 +4787,13 @@ s3_virge_hwcursor_draw(svga_t *svga, int displine) static void s3_virge_overlay_draw(svga_t *svga, int displine) { - virge_t *virge = (virge_t *) svga->priv; + virge_t *virge = (virge_t *) svga->priv; int offset; int r[8]; int g[8]; int b[8]; int x_size; - int x_read = 4; + int x_read = 4; int x_write = 4; int x; uint32_t *p; @@ -4774,7 +4804,7 @@ s3_virge_overlay_draw(svga_t *svga, int displine) else offset = virge->streams.sec_x + 1; - p = &((uint32_t *)buffer32->line[displine])[offset + svga->x_add]; + p = &((uint32_t *) buffer32->line[displine])[offset + svga->x_add]; if (virge->chip < S3_VIRGEGX2) { if ((offset + virge->streams.sec_w) > virge->streams.pri_w) @@ -5078,9 +5108,9 @@ s3_virge_disable_handlers(virge_t *dev) reset_state->svga.mapping = dev->svga.mapping; reset_state->bios_rom.mapping = dev->bios_rom.mapping; - reset_state->svga.timer = dev->svga.timer; - reset_state->svga.timer8514 = dev->svga.timer8514; - reset_state->irq_timer = dev->irq_timer; + reset_state->svga.timer = dev->svga.timer; + reset_state->svga.timer8514 = dev->svga.timer8514; + reset_state->irq_timer = dev->irq_timer; } static void @@ -5090,12 +5120,12 @@ s3_virge_reset(void *priv) if (reset_state != NULL) { s3_virge_disable_handlers(dev); - dev->virge_busy = 0; - dev->fifo_write_idx = 0; - dev->fifo_read_idx = 0; - dev->s3d_busy = 0; - dev->s3d_write_idx = 0; - dev->s3d_read_idx = 0; + dev->virge_busy = 0; + dev->fifo_write_idx = 0; + dev->fifo_read_idx = 0; + dev->s3d_busy = 0; + dev->s3d_write_idx = 0; + dev->s3d_read_idx = 0; reset_state->pci_slot = dev->pci_slot; *dev = *reset_state; @@ -5106,8 +5136,8 @@ static void * s3_virge_init(const device_t *info) { const char *bios_fn = NULL; - virge_t *virge = (virge_t *) calloc(1, sizeof(virge_t)); - reset_state = calloc(1, sizeof(virge_t)); + virge_t *virge = (virge_t *) calloc(1, sizeof(virge_t)); + reset_state = calloc(1, sizeof(virge_t)); virge->bilinear_enabled = device_get_config_int("bilinear"); virge->dithering_enabled = device_get_config_int("dithering"); @@ -5118,44 +5148,45 @@ s3_virge_init(const device_t *info) virge->onboard = !!(info->local & 0x100); - if (!virge->onboard) switch (info->local) { - case S3_VIRGE_325: - bios_fn = ROM_VIRGE_325; - break; - case S3_DIAMOND_STEALTH3D_2000: - bios_fn = ROM_DIAMOND_STEALTH3D_2000; - break; - case S3_MIROCRYSTAL_3D: - bios_fn = ROM_MIROCRYSTAL_3D; - break; - case S3_DIAMOND_STEALTH3D_3000: - bios_fn = ROM_DIAMOND_STEALTH3D_3000; - break; - case S3_STB_VELOCITY_3D: - bios_fn = ROM_STB_VELOCITY_3D; - break; - case S3_VIRGE_DX: - bios_fn = ROM_VIRGE_DX; - break; - case S3_DIAMOND_STEALTH3D_2000PRO: - bios_fn = ROM_DIAMOND_STEALTH3D_2000PRO; - break; - case S3_VIRGE_GX: - bios_fn = ROM_VIRGE_GX; - break; - case S3_VIRGE_GX2: - bios_fn = ROM_VIRGE_GX2; - break; - case S3_DIAMOND_STEALTH3D_4000: - bios_fn = ROM_DIAMOND_STEALTH3D_4000; - break; - case S3_TRIO_3D2X: - bios_fn = ROM_TRIO3D2X; - break; - default: - free(virge); - return NULL; - } + if (!virge->onboard) + switch (info->local) { + case S3_VIRGE_325: + bios_fn = ROM_VIRGE_325; + break; + case S3_DIAMOND_STEALTH3D_2000: + bios_fn = ROM_DIAMOND_STEALTH3D_2000; + break; + case S3_MIROCRYSTAL_3D: + bios_fn = ROM_MIROCRYSTAL_3D; + break; + case S3_DIAMOND_STEALTH3D_3000: + bios_fn = ROM_DIAMOND_STEALTH3D_3000; + break; + case S3_STB_VELOCITY_3D: + bios_fn = ROM_STB_VELOCITY_3D; + break; + case S3_VIRGE_DX: + bios_fn = ROM_VIRGE_DX; + break; + case S3_DIAMOND_STEALTH3D_2000PRO: + bios_fn = ROM_DIAMOND_STEALTH3D_2000PRO; + break; + case S3_VIRGE_GX: + bios_fn = ROM_VIRGE_GX; + break; + case S3_VIRGE_GX2: + bios_fn = ROM_VIRGE_GX2; + break; + case S3_DIAMOND_STEALTH3D_4000: + bios_fn = ROM_DIAMOND_STEALTH3D_4000; + break; + case S3_TRIO_3D2X: + bios_fn = ROM_TRIO3D2X; + break; + default: + free(virge); + return NULL; + } svga_init(info, &virge->svga, virge, virge->memory_size << 20, s3_virge_recalctimings, @@ -5223,7 +5254,7 @@ s3_virge_init(const device_t *info) case S3_VIRGE_325: case S3_DIAMOND_STEALTH3D_2000: case S3_MIROCRYSTAL_3D: - virge->fifo_slots_num = 8; + virge->fifo_slots_num = 8; virge->svga.decode_mask = (4 << 20) - 1; virge->virge_id_high = 0x56; virge->virge_id_low = 0x31; @@ -5233,7 +5264,7 @@ s3_virge_init(const device_t *info) break; case S3_DIAMOND_STEALTH3D_3000: case S3_STB_VELOCITY_3D: - virge->fifo_slots_num = 8; + virge->fifo_slots_num = 8; virge->svga.decode_mask = (8 << 20) - 1; virge->virge_id_high = 0x88; virge->virge_id_low = 0x3d; @@ -5243,7 +5274,7 @@ s3_virge_init(const device_t *info) break; case S3_VIRGE_GX2: case S3_DIAMOND_STEALTH3D_4000: - virge->fifo_slots_num = 16; + virge->fifo_slots_num = 16; virge->svga.decode_mask = (4 << 20) - 1; virge->virge_id_high = 0x8a; virge->virge_id_low = 0x10; @@ -5255,7 +5286,7 @@ s3_virge_init(const device_t *info) break; case S3_TRIO_3D2X: - virge->fifo_slots_num = 16; + virge->fifo_slots_num = 16; virge->svga.decode_mask = (8 << 20) - 1; virge->virge_id_high = 0x8a; virge->virge_id_low = 0x13; @@ -5272,7 +5303,7 @@ s3_virge_init(const device_t *info) fallthrough; default: - virge->fifo_slots_num = 8; + virge->fifo_slots_num = 8; virge->svga.decode_mask = (4 << 20) - 1; virge->virge_id_high = 0x8a; virge->virge_id_low = 0x01; @@ -5341,16 +5372,16 @@ s3_virge_init(const device_t *info) virge->svga.force_old_addr = 1; - virge->render_thread_run = 1; + virge->render_thread_run = 1; virge->wake_render_thread = thread_create_event(); - virge->wake_main_thread = thread_create_event(); - virge->not_full_event = thread_create_event(); - virge->render_thread = thread_create(render_thread, virge); + virge->wake_main_thread = thread_create_event(); + virge->not_full_event = thread_create_event(); + virge->render_thread = thread_create(render_thread, virge); - virge->fifo_thread_run = 1; - virge->wake_fifo_thread = thread_create_event(); + virge->fifo_thread_run = 1; + virge->wake_fifo_thread = thread_create_event(); virge->fifo_not_full_event = thread_create_event(); - virge->fifo_thread = thread_create(fifo_thread, virge); + virge->fifo_thread = thread_create(fifo_thread, virge); timer_add(&virge->irq_timer, s3_virge_update_irq_timer, virge, 1); @@ -5473,7 +5504,7 @@ s3_virge_force_redraw(void *priv) } static const device_config_t s3_virge_config[] = { - // clang-format off + // clang-format off { .name = "memory", .description = "Memory size", @@ -5509,11 +5540,11 @@ static const device_config_t s3_virge_config[] = { .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } - // clang-format on + // clang-format on }; static const device_config_t s3_virge_stb_config[] = { - // clang-format off + // clang-format off { .name = "memory", .description = "Memory size", @@ -5550,11 +5581,11 @@ static const device_config_t s3_virge_stb_config[] = { .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } - // clang-format on + // clang-format on }; static const device_config_t s3_virge_357_config[] = { - // clang-format off + // clang-format off { .name = "bilinear", .description = "Bilinear filtering", @@ -5576,11 +5607,11 @@ static const device_config_t s3_virge_357_config[] = { .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } - // clang-format on + // clang-format on }; static const device_config_t s3_trio3d2x_config[] = { - // clang-format off + // clang-format off { .name = "memory", .description = "Memory size", @@ -5619,7 +5650,7 @@ static const device_config_t s3_trio3d2x_config[] = { .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } - // clang-format on + // clang-format on }; const device_t s3_virge_325_pci_device = { diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index caa20e196..1fd2460bd 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -782,7 +782,8 @@ svga_recalctimings(svga_t *svga) if (xga_active && (svga->xga != NULL)) { if (xga->on) { - if ((svga->mapping.base == 0xb8000) && (xga->aperture_cntl == 1)) /*Some operating systems reset themselves with ctrl-alt-del by going into text mode.*/ + svga_log("XGA on=%d, base=%05x, ap=%x.\n", xga->on, svga->mapping.base, xga->aperture_cntl); + if ((svga->mapping.base == 0xb8000) && (xga->aperture_cntl >= 1)) /*Some operating systems reset themselves with ctrl-alt-del by going into text mode.*/ xga->on = 0; } } @@ -1541,7 +1542,7 @@ svga_init(const device_t *info, svga_t *svga, void *priv, int memsize, svga->dac_hwcursor.cur_xsize = svga->dac_hwcursor.cur_ysize = 32; svga->translate_address = NULL; - + svga->cable_connected = 1; svga->ksc5601_english_font_type = 0; diff --git a/src/video/vid_xga.c b/src/video/vid_xga.c index 2cc20044a..4c08b7b71 100644 --- a/src/video/vid_xga.c +++ b/src/video/vid_xga.c @@ -2738,7 +2738,7 @@ xga_write_test(uint32_t addr, uint8_t val, void *priv) xga_t *xga = (xga_t *) svga->xga; if (xga_active && xga) { - if (((xga->op_mode & 7) >= 1) && xga->aperture_cntl) { + if (((xga->op_mode & 7) >= 1) && xga->aperture_cntl && (svga->mapping.base == 0xb8000)) { xga_log("WriteAddr=%05x.\n", addr); if (val == 0xa5) { /*Memory size test of XGA*/ xga->test = val; @@ -2843,7 +2843,7 @@ xga_read_test(uint32_t addr, void *priv) uint8_t ret = 0x00; if (xga_active && xga) { - if (((xga->op_mode & 7) >= 1) && xga->aperture_cntl) { + if (((xga->op_mode & 7) >= 1) && xga->aperture_cntl && (svga->mapping.base == 0xb8000)) { if (xga->test == 0xa5) { /*Memory size test of XGA*/ if (addr == 0xa0001) { ret = xga->test;