From 1b93e8e98964f64df12009a9ce3d48feaa893536 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 22 Aug 2021 16:32:52 +0600 Subject: [PATCH] Initial Linux/Unix code --- .gitignore | 4 +- src/CMakeLists.txt | 7 +- src/include/86box/unix_sdl.h | 12 + src/network/slirp/CMakeLists.txt | 6 +- src/unix/CMakeLists.txt | 5 + src/unix/unix.c | 502 +++++++++++++++++++++++++++++++ src/unix/unix_cdrom.c | 264 ++++++++++++++++ src/unix/unix_midi.c | 57 ++++ src/unix/unix_sdl.c | 420 ++++++++++++++++++++++++++ src/unix/unix_thread.c | 158 ++++++++++ 10 files changed, 1432 insertions(+), 3 deletions(-) create mode 100644 src/include/86box/unix_sdl.h create mode 100644 src/unix/CMakeLists.txt create mode 100644 src/unix/unix.c create mode 100644 src/unix/unix_cdrom.c create mode 100644 src/unix/unix_midi.c create mode 100644 src/unix/unix_sdl.c create mode 100644 src/unix/unix_thread.c diff --git a/.gitignore b/.gitignore index 968c8d4bc..ac3c080a8 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,6 @@ src/NUL src/nvr/ src/roms/ /.vs -/CMakeUserPresets.json \ No newline at end of file +/CMakeUserPresets.json +/build +/.vscode diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cbe6f79f5..67cf3eca0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -123,4 +123,9 @@ add_subdirectory(sio) add_subdirectory(scsi) add_subdirectory(sound) add_subdirectory(video) -add_subdirectory(win) +if (${CMAKE_SYSTEM_NAME} MATCHES "Windows") + add_subdirectory(win) +else() + add_subdirectory(unix) + target_link_libraries(86Box glib-2.0) +endif() diff --git a/src/include/86box/unix_sdl.h b/src/include/86box/unix_sdl.h new file mode 100644 index 000000000..7019f0b85 --- /dev/null +++ b/src/include/86box/unix_sdl.h @@ -0,0 +1,12 @@ +#ifndef _UNIX_SDL_H +#define _UNIX_SDL_H +extern void sdl_close(void); +extern int sdl_inits(); +extern int sdl_inith(); +extern int sdl_initho(); +extern int sdl_pause(void); +extern void sdl_resize(int x, int y); +extern void sdl_enable(int enable); +extern void sdl_set_fs(int fs); +extern void sdl_reload(void); +#endif \ No newline at end of file diff --git a/src/network/slirp/CMakeLists.txt b/src/network/slirp/CMakeLists.txt index 4393d9d55..c04790265 100644 --- a/src/network/slirp/CMakeLists.txt +++ b/src/network/slirp/CMakeLists.txt @@ -17,4 +17,8 @@ add_library(slirp STATIC tinyglib.c arp_table.c bootp.c cksum.c dnssearch.c if.c ip_input.c ip_output.c mbuf.c misc.c sbuf.c slirp.c socket.c tcp_input.c tcp_output.c tcp_subr.c tcp_timer.c udp.c util.c version.c) -target_link_libraries(slirp wsock32 iphlpapi) \ No newline at end of file +#target_link_libraries(slirp wsock32 iphlpapi) +#target_link_libraries(slirp) +if (CMAKE_SYSTEM_NAME MATCHES "Windows") +target_link_libraries(wsock32 iphlpapi) +endif() diff --git a/src/unix/CMakeLists.txt b/src/unix/CMakeLists.txt new file mode 100644 index 000000000..e3f5b5780 --- /dev/null +++ b/src/unix/CMakeLists.txt @@ -0,0 +1,5 @@ +add_library(plat STATIC unix_thread.c unix_midi.c) +add_library(ui STATIC unix.c unix_sdl.c unix_cdrom.c) +target_compile_definitions(ui PUBLIC _FILE_OFFSET_BITS=64) +target_link_libraries(ui dl) +target_link_libraries(plat pthread) \ No newline at end of file diff --git a/src/unix/unix.c b/src/unix/unix.c new file mode 100644 index 000000000..99fffbc77 --- /dev/null +++ b/src/unix/unix.c @@ -0,0 +1,502 @@ +#ifdef __linux__ +#define _FILE_OFFSET_BITS 64 +#define _LARGEFILE64_SOURCE 1 +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/config.h> +#include <86box/plat.h> +#include <86box/plat_dynld.h> +#include <86box/device.h> +#include <86box/gameport.h> +#include <86box/unix_sdl.h> +#include <86box/timer.h> +#include <86box/nvr.h> +#include <86box/unix_sdl.h> +static int first_use = 1; +static uint64_t StartingTime; +static uint64_t Frequency; +int rctrl_is_lalt; +int update_icons; +int kbd_req_capture; +int hide_status_bar; +int fixed_size_x = 640; +int fixed_size_y = 480; +plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS]; +joystick_t joystick_state[MAX_JOYSTICKS]; +int joysticks_present; +SDL_mutex *blitmtx; + +typedef struct sdl_blit_params +{ + int x, y, y1, y2, w, h; +} sdl_blit_params; + +sdl_blit_params params = { 0, 0, 0, 0, 0, 0 }; +int blitreq = 0; + +void* dynld_module(const char *name, dllimp_t *table) +{ + dllimp_t* imp; + void* modhandle = dlopen(name, RTLD_LAZY | RTLD_GLOBAL); + if (modhandle) + { + for (imp = table; imp->name != NULL; imp++) + { + if ((imp->func = dlsym(modhandle, imp->name)) == NULL) + { + dlclose(modhandle); + return NULL; + } + } + } + return modhandle; +} + +void +plat_tempfile(char *bufp, char *prefix, char *suffix) +{ + struct tm* calendertime; + struct timeval t; + time_t curtime; + + if (prefix != NULL) + sprintf(bufp, "%s-", prefix); + else + strcpy(bufp, ""); + gettimeofday(&t, NULL); + curtime = time(NULL); + calendertime = localtime(&curtime); + sprintf(&bufp[strlen(bufp)], "%d%02d%02d-%02d%02d%02d-%03d%s", calendertime->tm_year, calendertime->tm_mon, calendertime->tm_mday, calendertime->tm_hour, calendertime->tm_min, calendertime->tm_sec, t.tv_usec / 1000, suffix); +} + +int +plat_getcwd(char *bufp, int max) +{ + return getcwd(bufp, max) != 0; +} + +int +plat_chdir(char* str) +{ + return chdir(str); +} + +void dynld_close(void *handle) +{ + dlclose(handle); +} + +wchar_t* plat_get_string(int i) +{ + return L""; +} + +FILE * +plat_fopen(const char *path, const char *mode) +{ + return fopen(path, mode); +} + +FILE * +plat_fopen64(const char *path, const char *mode) +{ + return fopen(path, mode); +} + +int +plat_path_abs(char *path) +{ + return path[0] == '/'; +} + +void +plat_path_slash(char *path) +{ + if ((path[strlen(path)-1] != '/')) { + strcat(path, "/"); + } +} + +void +plat_put_backslash(char *s) +{ + int c = strlen(s) - 1; + + if (s[c] != '/') + s[c] = '/'; +} + +/* Return the last element of a pathname. */ +char * +plat_get_basename(const char *path) +{ + int c = (int)strlen(path); + + while (c > 0) { + if (path[c] == '/') + return((char *)&path[c]); + c--; + } + + return((char *)path); +} +char * +plat_get_filename(char *s) +{ + int c = strlen(s) - 1; + + while (c > 0) { + if (s[c] == '/' || s[c] == '\\') + return(&s[c+1]); + c--; + } + + return(s); +} + + +char * +plat_get_extension(char *s) +{ + int c = strlen(s) - 1; + + if (c <= 0) + return(s); + + while (c && s[c] != '.') + c--; + + if (!c) + return(&s[strlen(s)]); + + return(&s[c+1]); +} + + +void +plat_append_filename(char *dest, const char *s1, const char *s2) +{ + strcpy(dest, s1); + plat_path_slash(dest); + strcat(dest, s2); +} + +int +plat_dir_check(char *path) +{ + struct stat dummy; + if (stat(path, &dummy) < 0) + { + return 0; + } + return S_ISDIR(dummy.st_mode); +} + +int +plat_dir_create(char *path) +{ + return mkdir(path, S_IRWXU); +} + +uint64_t +plat_timer_read(void) +{ + return SDL_GetPerformanceCounter(); +} + +static uint64_t +plat_get_ticks_common(void) +{ + uint64_t EndingTime, ElapsedMicroseconds; + if (first_use) { + Frequency = SDL_GetPerformanceFrequency(); + StartingTime = SDL_GetPerformanceCounter(); + first_use = 0; + } + EndingTime = SDL_GetPerformanceCounter(); + ElapsedMicroseconds = ((EndingTime - StartingTime) * 1000000) / Frequency; + return ElapsedMicroseconds; +} + +uint32_t +plat_get_ticks(void) +{ + return (uint32_t)(plat_get_ticks_common() / 1000); +} + +uint32_t +plat_get_micro_ticks(void) +{ + return (uint32_t)plat_get_ticks_common(); +} + +void plat_remove(char* path) +{ + remove(path); +} + +void +ui_sb_update_icon_state(int tag, int state) +{ + +} + +void +ui_sb_update_icon(int tag, int active) +{ + +} + +void +plat_delay_ms(uint32_t count) +{ + SDL_Delay(count); +} + +void +ui_sb_update_tip(int arg) +{ + +} + +void +ui_sb_update_panes() +{ + +} + +void +plat_get_dirname(char *dest, const char *path) +{ + int c = (int)strlen(path); + char *ptr; + + ptr = (char *)path; + + while (c > 0) { + if (path[c] == '/' || path[c] == '\\') { + ptr = (char *)&path[c]; + break; + } + c--; + } + + /* Copy to destination. */ + while (path < ptr) + *dest++ = *path++; + *dest = '\0'; +} +volatile int cpu_thread_run = 1; +void ui_sb_set_text_w(wchar_t *wstr) +{ + +} + +int stricmp(const char* s1, const char* s2) +{ + return strcasecmp(s1, s2); +} + +int strnicmp(const char *s1, const char *s2, size_t n) +{ + return strncasecmp(s1, s2, n); +} + +void +main_thread(void *param) +{ + uint32_t old_time, new_time; + int drawits, frames; + + framecountx = 0; + //title_update = 1; + old_time = SDL_GetTicks(); + drawits = frames = 0; + while (!is_quit && cpu_thread_run) { + /* See if it is time to run a frame of code. */ + new_time = SDL_GetTicks(); + drawits += (new_time - old_time); + old_time = new_time; + if (drawits > 0 && !dopause) { + /* Yes, so do one frame now. */ + drawits -= 10; + if (drawits > 50) + drawits = 0; + + /* Run a block of code. */ + pc_run(); + + /* Every 200 frames we save the machine status. */ + if (++frames >= 200 && nvr_dosave) { + nvr_save(); + nvr_dosave = 0; + frames = 0; + } + } else /* Just so we dont overload the host OS. */ + SDL_Delay(1); + + /* If needed, handle a screen resize. */ + if (doresize && !video_fullscreen && !is_quit) { + if (vid_resize & 2) + plat_resize(fixed_size_x, fixed_size_y); + else + plat_resize(scrnsz_x, scrnsz_y); + doresize = 0; + } + } + + is_quit = 1; +} + +thread_t* thMain = NULL; + +void mouse_poll() +{} + +void +do_start(void) +{ + /* We have not stopped yet. */ + is_quit = 0; + + /* Initialize the high-precision timer. */ + SDL_InitSubSystem(SDL_INIT_TIMER); + timer_freq = SDL_GetPerformanceFrequency(); + + /* Start the emulator, really. */ + thMain = thread_create(main_thread, NULL); +} + +void +do_stop(void) +{ + /* Claim the video blitter. */ + startblit(); + + sdl_close(); + + pc_close(thMain); + + thMain = NULL; +} + +int ui_msgbox(int flags, void *message) +{ + return 0; +} + +int ui_msgbox_header(int flags, void *message, void* header) +{ + // Parameters that are passed will crash the program so keep these off for the time being. + return 0; +} + +void plat_get_exe_name(char *s, int size) +{ + char* basepath = SDL_GetBasePath(); + snprintf(s, size, "%s/86box", basepath); +} + +void +plat_power_off(void) +{ + confirm_exit = 0; + nvr_save(); + config_save(); + + /* Deduct a sufficiently large number of cycles that no instructions will + run before the main thread is terminated */ + cycles -= 99999999; + + cpu_thread_run = 0; +} + +wchar_t* ui_sb_bugui(wchar_t *str) +{ + return str; +} +extern void sdl_blit(int x, int y, int y1, int y2, int w, int h); + +void ui_window_title(wchar_t* str) {} +void ui_sb_set_ready(int ready) {} +int main(int argc, char** argv) +{ + SDL_Event event; + + SDL_Init(0); + pc_init(argc, argv); + if (! pc_init_modules()) { + fprintf(stderr, "No ROMs found.\n"); + SDL_Quit(); + return 6; + } + blitmtx = SDL_CreateMutex(); + if (!blitmtx) + { + fprintf(stderr, "Failed to create blit mutex: %s", SDL_GetError()); + return -1; + } + sdl_initho(); + + if (start_in_fullscreen) + sdl_set_fs(1); + + /* Fire up the machine. */ + pc_reset_hard_init(); + + /* Set the PAUSE mode depending on the renderer. */ + //plat_pause(0); + + /* Initialize the rendering window, or fullscreen. */ + + + do_start(); + while (!is_quit) + { + if (SDL_PollEvent(&event)) + switch(event.type) + { + case SDL_QUIT: + do_stop(); + break; + + } + if (blitreq) + { + extern void sdl_blit(int x, int y, int y1, int y2, int w, int h); + sdl_blit(params.x, params.y, params.y1, params.y2, params.w, params.h); + } + } + + SDL_DestroyMutex(blitmtx); + SDL_Quit(); + return 0; +} +char* plat_vidapi_name(int i) +{ + return "default"; +} +void joystick_init(void) {} +void joystick_close(void) {} +void joystick_process(void) {} +void startblit() +{ + SDL_LockMutex(blitmtx); +} + +void endblit() +{ + SDL_UnlockMutex(blitmtx); +} \ No newline at end of file diff --git a/src/unix/unix_cdrom.c b/src/unix/unix_cdrom.c new file mode 100644 index 000000000..9eb3d962a --- /dev/null +++ b/src/unix/unix_cdrom.c @@ -0,0 +1,264 @@ +/* + * 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. + * + * Handle the platform-side of CDROM/ZIP/MO drives. + * + * + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ + +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/config.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/cassette.h> +#include <86box/cartridge.h> +#include <86box/fdd.h> +#include <86box/hdd.h> +#include <86box/scsi_device.h> +#include <86box/cdrom.h> +#include <86box/mo.h> +#include <86box/zip.h> +#include <86box/scsi_disk.h> +#include <86box/plat.h> +#include <86box/ui.h> + + + +void +cassette_mount(char *fn, uint8_t wp) +{ + pc_cas_set_fname(cassette, NULL); + memset(cassette_fname, 0, sizeof(cassette_fname)); + cassette_ui_writeprot = wp; + pc_cas_set_fname(cassette, fn); + if (fn != NULL) + memcpy(cassette_fname, fn, MIN(511, strlen(fn))); + ui_sb_update_icon_state(SB_CASSETTE, (fn == NULL) ? 1 : 0); + //media_menu_update_cassette(); + ui_sb_update_tip(SB_CASSETTE); + config_save(); +} + + +void +cassette_eject(void) +{ + pc_cas_set_fname(cassette, NULL); + memset(cassette_fname, 0x00, sizeof(cassette_fname)); + ui_sb_update_icon_state(SB_CASSETTE, 1); + //media_menu_update_cassette(); + ui_sb_update_tip(SB_CASSETTE); + config_save(); +} + + +void +cartridge_mount(uint8_t id, char *fn, uint8_t wp) +{ + cart_close(id); + cart_load(id, fn); + ui_sb_update_icon_state(SB_CARTRIDGE | id, strlen(cart_fns[id]) ? 0 : 1); + //media_menu_update_cartridge(id); + ui_sb_update_tip(SB_CARTRIDGE | id); + config_save(); +} + + +void +cartridge_eject(uint8_t id) +{ + cart_close(id); + ui_sb_update_icon_state(SB_CARTRIDGE | id, 1); + //media_menu_update_cartridge(id); + ui_sb_update_tip(SB_CARTRIDGE | id); + config_save(); +} + + +void +floppy_mount(uint8_t id, char *fn, uint8_t wp) +{ + fdd_close(id); + ui_writeprot[id] = wp; + fdd_load(id, fn); + ui_sb_update_icon_state(SB_FLOPPY | id, strlen(floppyfns[id]) ? 0 : 1); + //media_menu_update_floppy(id); + ui_sb_update_tip(SB_FLOPPY | id); + config_save(); +} + + +void +floppy_eject(uint8_t id) +{ + fdd_close(id); + ui_sb_update_icon_state(SB_FLOPPY | id, 1); + //media_menu_update_floppy(id); + ui_sb_update_tip(SB_FLOPPY | id); + config_save(); +} + + +void +plat_cdrom_ui_update(uint8_t id, uint8_t reload) +{ + cdrom_t *drv = &cdrom[id]; + + if (drv->host_drive == 0) { + ui_sb_update_icon_state(SB_CDROM|id, 1); + } else { + ui_sb_update_icon_state(SB_CDROM|id, 0); + } + + //media_menu_update_cdrom(id); + ui_sb_update_tip(SB_CDROM|id); +} + +void +cdrom_mount(uint8_t id, char *fn) +{ + cdrom[id].prev_host_drive = cdrom[id].host_drive; + strcpy(cdrom[id].prev_image_path, cdrom[id].image_path); + if (cdrom[id].ops && cdrom[id].ops->exit) + cdrom[id].ops->exit(&(cdrom[id])); + cdrom[id].ops = NULL; + memset(cdrom[id].image_path, 0, sizeof(cdrom[id].image_path)); + cdrom_image_open(&(cdrom[id]), fn); + /* Signal media change to the emulated machine. */ + if (cdrom[id].insert) + cdrom[id].insert(cdrom[id].priv); + cdrom[id].host_drive = (strlen(cdrom[id].image_path) == 0) ? 0 : 200; + if (cdrom[id].host_drive == 200) { + ui_sb_update_icon_state(SB_CDROM | id, 0); + } else { + ui_sb_update_icon_state(SB_CDROM | id, 1); + } + //media_menu_update_cdrom(id); + ui_sb_update_tip(SB_CDROM | id); + config_save(); +} + +void +mo_eject(uint8_t id) +{ + mo_t *dev = (mo_t *) mo_drives[id].priv; + + mo_disk_close(dev); + if (mo_drives[id].bus_type) { + /* Signal disk change to the emulated machine. */ + mo_insert(dev); + } + + ui_sb_update_icon_state(SB_MO | id, 1); + //media_menu_update_mo(id); + ui_sb_update_tip(SB_MO | id); + config_save(); +} + + +void +mo_mount(uint8_t id, char *fn, uint8_t wp) +{ + mo_t *dev = (mo_t *) mo_drives[id].priv; + + mo_disk_close(dev); + mo_drives[id].read_only = wp; + mo_load(dev, fn); + mo_insert(dev); + + ui_sb_update_icon_state(SB_MO | id, strlen(mo_drives[id].image_path) ? 0 : 1); + //media_menu_update_mo(id); + ui_sb_update_tip(SB_MO | id); + + config_save(); +} + + +void +mo_reload(uint8_t id) +{ + mo_t *dev = (mo_t *) mo_drives[id].priv; + + mo_disk_reload(dev); + if (strlen(mo_drives[id].image_path) == 0) { + ui_sb_update_icon_state(SB_MO|id, 1); + } else { + ui_sb_update_icon_state(SB_MO|id, 0); + } + + //media_menu_update_mo(id); + ui_sb_update_tip(SB_MO|id); + + config_save(); +} + +void +zip_eject(uint8_t id) +{ + zip_t *dev = (zip_t *) zip_drives[id].priv; + + zip_disk_close(dev); + if (zip_drives[id].bus_type) { + /* Signal disk change to the emulated machine. */ + zip_insert(dev); + } + + ui_sb_update_icon_state(SB_ZIP | id, 1); + //media_menu_update_zip(id); + ui_sb_update_tip(SB_ZIP | id); + config_save(); +} + + +void +zip_mount(uint8_t id, char *fn, uint8_t wp) +{ + zip_t *dev = (zip_t *) zip_drives[id].priv; + + zip_disk_close(dev); + zip_drives[id].read_only = wp; + zip_load(dev, fn); + zip_insert(dev); + + ui_sb_update_icon_state(SB_ZIP | id, strlen(zip_drives[id].image_path) ? 0 : 1); + //media_menu_update_zip(id); + ui_sb_update_tip(SB_ZIP | id); + + config_save(); +} + + +void +zip_reload(uint8_t id) +{ + zip_t *dev = (zip_t *) zip_drives[id].priv; + + zip_disk_reload(dev); + if (strlen(zip_drives[id].image_path) == 0) { + ui_sb_update_icon_state(SB_ZIP|id, 1); + } else { + ui_sb_update_icon_state(SB_ZIP|id, 0); + } + + //media_menu_update_zip(id); + ui_sb_update_tip(SB_ZIP|id); + + config_save(); +} diff --git a/src/unix/unix_midi.c b/src/unix/unix_midi.c new file mode 100644 index 000000000..c92820bef --- /dev/null +++ b/src/unix/unix_midi.c @@ -0,0 +1,57 @@ +#include +void plat_midi_init(void) +{ + +} + +void plat_midi_close(void) +{ + +} + +void plat_midi_play_msg(uint8_t *msg) +{ + +} + +void plat_midi_play_sysex(uint8_t *sysex, unsigned int len) +{ + +} + +int plat_midi_write(uint8_t val) +{ + return 0; +} + +int plat_midi_get_num_devs(void) +{ + return 0; +} + +void plat_midi_get_dev_name(int num, char *s) +{ + s[0] = ' '; + s[1] = 0; +} + +void plat_midi_input_init(void) +{ + +} + +void plat_midi_input_close(void) +{ + +} + +int plat_midi_in_get_num_devs(void) +{ + return 0; +} + +void plat_midi_in_get_dev_name(int num, char *s) +{ + s[0] = ' '; + s[1] = 0; +} \ No newline at end of file diff --git a/src/unix/unix_sdl.c b/src/unix/unix_sdl.c new file mode 100644 index 000000000..72b87776e --- /dev/null +++ b/src/unix/unix_sdl.c @@ -0,0 +1,420 @@ +#include +#include + +#include +#include +#include +#include +/* This #undef is needed because a SDL include header redefines HAVE_STDARG_H. */ +#undef HAVE_STDARG_H +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/plat.h> +#include <86box/plat_dynld.h> +#include <86box/video.h> +#include <86box/ui.h> +#include <86box/version.h> + +#define RENDERER_FULL_SCREEN 1 +#define RENDERER_HARDWARE 2 +#define RENDERER_OPENGL 4 + +typedef struct sdl_blit_params +{ + int x, y, y1, y2, w, h; +} sdl_blit_params; +extern sdl_blit_params params; +extern int blitreq; + +static SDL_Window *sdl_win = NULL; +static SDL_Renderer *sdl_render = NULL; +static SDL_Texture *sdl_tex = NULL; +static int sdl_w, sdl_h; +static int sdl_fs, sdl_flags = -1; +static int cur_w, cur_h; +static int cur_wx = 0, cur_wy = 0, cur_ww =0, cur_wh = 0; +static volatile int sdl_enabled = 1; +static SDL_mutex* sdl_mutex = NULL; +int mouse_capture; + +static void +sdl_integer_scale(double *d, double *g) +{ + double ratio; + + if (*d > *g) { + ratio = floor(*d / *g); + *d = *g * ratio; + } else { + ratio = ceil(*d / *g); + *d = *g / ratio; + } +} + +void sdl_reinit_texture(); + +static void +sdl_stretch(int *w, int *h, int *x, int *y) +{ + double hw, gw, hh, gh, dx, dy, dw, dh, gsr, hsr; + + hw = (double) sdl_w; + hh = (double) sdl_h; + gw = (double) *w; + gh = (double) *h; + hsr = hw / hh; + + switch (video_fullscreen_scale) { + case FULLSCR_SCALE_FULL: + default: + *w = sdl_w; + *h = sdl_h; + *x = 0; + *y = 0; + break; + case FULLSCR_SCALE_43: + case FULLSCR_SCALE_KEEPRATIO: + if (video_fullscreen_scale == FULLSCR_SCALE_43) + gsr = 4.0 / 3.0; + else + gsr = gw / gh; + if (gsr <= hsr) { + dw = hh * gsr; + dh = hh; + } else { + dw = hw; + dh = hw / gsr; + } + dx = (hw - dw) / 2.0; + dy = (hh - dh) / 2.0; + *w = (int) dw; + *h = (int) dh; + *x = (int) dx; + *y = (int) dy; + break; + case FULLSCR_SCALE_INT: + gsr = gw / gh; + if (gsr <= hsr) { + dw = hh * gsr; + dh = hh; + } else { + dw = hw; + dh = hw / gsr; + } + sdl_integer_scale(&dw, &gw); + sdl_integer_scale(&dh, &gh); + dx = (hw - dw) / 2.0; + dy = (hh - dh) / 2.0; + *w = (int) dw; + *h = (int) dh; + *x = (int) dx; + *y = (int) dy; + break; + } +} + + +void +sdl_blit_shim(int x, int y, int y1, int y2, int w, int h) +{ + params.x = x; + params.y = y; + params.w = w; + params.h = h; + params.y1 = y1; + params.y2 = y2; + blitreq = 1; +} + +void +sdl_blit(int x, int y, int y1, int y2, int w, int h) +{ + SDL_Rect r_src; + int ret; + + if (!sdl_enabled || (y1 == y2) || (h <= 0) || (render_buffer == NULL) || (sdl_render == NULL) || (sdl_tex == NULL)) { + video_blit_complete(); + return; + } + + SDL_LockMutex(sdl_mutex); + + r_src.x = 0; + r_src.y = y1; + r_src.w = w; + r_src.h = y2 - y1; + SDL_UpdateTexture(sdl_tex, &r_src, &(render_buffer->dat)[y1 * w], w * 4); + video_blit_complete(); + + SDL_RenderClear(sdl_render); + + r_src.x = 0; + r_src.y = 0; + r_src.w = w; + r_src.h = h; + + ret = SDL_RenderCopy(sdl_render, sdl_tex, &r_src, 0); + if (ret) + fprintf(stderr, "SDL: unable to copy texture to renderer (%s)\n", SDL_GetError()); + + SDL_RenderPresent(sdl_render); + SDL_UnlockMutex(sdl_mutex); +} + +static void +sdl_destroy_window(void) +{ + if (sdl_win != NULL) { + SDL_DestroyWindow(sdl_win); + sdl_win = NULL; + } +} + + +static void +sdl_destroy_texture(void) +{ + /* SDL_DestroyRenderer also automatically destroys all associated textures. */ + if (sdl_render != NULL) { + SDL_DestroyRenderer(sdl_render); + sdl_render = NULL; + } +} + +void +sdl_close(void) +{ + SDL_LockMutex(sdl_mutex); + + /* Unregister our renderer! */ + video_setblit(NULL); + + if (sdl_enabled) + sdl_enabled = 0; + + if (sdl_mutex != NULL) { + SDL_DestroyMutex(sdl_mutex); + sdl_mutex = NULL; + } + + sdl_destroy_texture(); + sdl_destroy_window(); + + /* Quit. */ + SDL_Quit(); + sdl_flags = -1; +} + +static int old_capture = 0; + +void +sdl_enable(int enable) +{ + if (sdl_flags == -1) + return; + + SDL_LockMutex(sdl_mutex); + sdl_enabled = !!enable; + + if (enable == 1) { + SDL_SetWindowSize(sdl_win, cur_ww, cur_wh); + sdl_reinit_texture(); + } + + SDL_UnlockMutex(sdl_mutex); +} + +static void +sdl_select_best_hw_driver(void) +{ + int i; + SDL_RendererInfo renderInfo; + + for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) + { + SDL_GetRenderDriverInfo(i, &renderInfo); + if (renderInfo.flags & SDL_RENDERER_ACCELERATED) { + SDL_SetHint(SDL_HINT_RENDER_DRIVER, renderInfo.name); + return; + } + } +} + + +void +sdl_reinit_texture() +{ + if (sdl_flags == -1) + return; + + sdl_destroy_texture(); + + SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1); + if (sdl_flags & RENDERER_HARDWARE) { + sdl_render = SDL_CreateRenderer(sdl_win, -1, SDL_RENDERER_ACCELERATED); + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, video_filter_method ? "1" : "0"); + } else + sdl_render = SDL_CreateRenderer(sdl_win, -1, SDL_RENDERER_SOFTWARE); + + sdl_tex = SDL_CreateTexture(sdl_render, SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STREAMING, 2048, 2048); +} + +void +sdl_set_fs(int fs) +{ + SDL_LockMutex(sdl_mutex); + sdl_enabled = 0; + sdl_destroy_texture(); + SDL_SetWindowFullscreen(sdl_win, fs ? SDL_WINDOW_FULLSCREEN : 0); + SDL_SetWindowMouseGrab(sdl_win, mouse_capture); + + sdl_fs = fs; + + if (fs) + sdl_flags |= RENDERER_FULL_SCREEN; + else + sdl_flags &= ~RENDERER_FULL_SCREEN; + + sdl_reinit_texture(); + sdl_enabled = 1; + SDL_UnlockMutex(sdl_mutex); +} + +void +sdl_resize(int x, int y) +{ + int ww = 0, wh = 0, wx = 0, wy = 0; + + if (video_fullscreen & 2) + return; + + if ((x == cur_w) && (y == cur_h)) + return; + + SDL_LockMutex(sdl_mutex); + + ww = x; + wh = y; + + cur_w = x; + cur_h = y; + + cur_wx = wx; + cur_wy = wy; + cur_ww = ww; + cur_wh = wh; + + SDL_SetWindowSize(sdl_win, cur_ww, cur_wh); + SDL_SetWindowPosition(sdl_win, cur_wx, cur_wy); + + sdl_reinit_texture(); + + SDL_UnlockMutex(sdl_mutex); +} +void +sdl_reload(void) +{ + if (sdl_flags & RENDERER_HARDWARE) + { + SDL_LockMutex(sdl_mutex); + + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, video_filter_method ? "1" : "0"); + sdl_reinit_texture(); + + SDL_UnlockMutex(sdl_mutex); + } +} + +int +plat_vidapi(char* api) +{ + return 0; +} + +static int +sdl_init_common(int flags) +{ + wchar_t temp[128]; + SDL_version ver; + + /* Get and log the version of the DLL we are using. */ + SDL_GetVersion(&ver); + fprintf(stderr, "SDL: version %d.%d.%d\n", ver.major, ver.minor, ver.patch); + + /* Initialize the SDL system. */ + if (SDL_Init(SDL_INIT_VIDEO) < 0) { + fprintf(stderr, "SDL: initialization failed (%s)\n", SDL_GetError()); + return(0); + } + + if (flags & RENDERER_HARDWARE) { + if (flags & RENDERER_OPENGL) { + SDL_SetHint(SDL_HINT_RENDER_DRIVER, "OpenGL"); + } + else + sdl_select_best_hw_driver(); + } + + sdl_mutex = SDL_CreateMutex(); + sdl_win = SDL_CreateWindow("86Box", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, scrnsz_x, scrnsz_y, SDL_WINDOW_OPENGL); + sdl_set_fs(video_fullscreen & 1); + if (!(video_fullscreen & 1)) + { + if (vid_resize & 2) + plat_resize(fixed_size_x, fixed_size_y); + else + plat_resize(scrnsz_x, scrnsz_y); + } + + /* Make sure we get a clean exit. */ + atexit(sdl_close); + + /* Register our renderer! */ + video_setblit(sdl_blit_shim); + + sdl_enabled = 1; + + return(1); +} + +int +sdl_inits() +{ + return sdl_init_common(0); +} + + +int +sdl_inith() +{ + return sdl_init_common(RENDERER_HARDWARE); +} + + +int +sdl_initho() +{ + return sdl_init_common(RENDERER_HARDWARE | RENDERER_OPENGL); +} + + +int +sdl_pause(void) +{ + return(0); +} + +void +plat_mouse_capture(int on) +{ + SDL_LockMutex(sdl_mutex); + SDL_SetWindowMouseGrab(sdl_win, (SDL_bool)on); + SDL_UnlockMutex(sdl_mutex); +} + +void plat_resize(int w, int h) +{ + SDL_SetWindowSize(sdl_win, w, h); +} diff --git a/src/unix/unix_thread.c b/src/unix/unix_thread.c new file mode 100644 index 000000000..2c1561597 --- /dev/null +++ b/src/unix/unix_thread.c @@ -0,0 +1,158 @@ +#include +#include +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/plat.h> + +typedef struct event_pthread_t +{ + pthread_cond_t cond; + pthread_mutex_t mutex; + int state; +} event_pthread_t; + +thread_t *thread_create(void (*thread_rout)(void *param), void *param) +{ + pthread_t *thread = malloc(sizeof(pthread_t)); + + pthread_create(thread, NULL, (void*)thread_rout, param); + + return thread; +} + +int +thread_wait(thread_t *arg, int timeout) +{ + return pthread_join(*(pthread_t*)(arg), NULL) != 0; +} + +event_t *thread_create_event() +{ + event_pthread_t *event = malloc(sizeof(event_pthread_t)); + + pthread_cond_init(&event->cond, NULL); + pthread_mutex_init(&event->mutex, NULL); + event->state = 0; + + return (event_t *)event; +} + +void thread_set_event(event_t *handle) +{ + event_pthread_t *event = (event_pthread_t *)handle; + + pthread_mutex_lock(&event->mutex); + event->state = 1; + pthread_cond_broadcast(&event->cond); + pthread_mutex_unlock(&event->mutex); +} + +void thread_reset_event(event_t *handle) +{ + event_pthread_t *event = (event_pthread_t *)handle; + + pthread_mutex_lock(&event->mutex); + event->state = 0; + pthread_mutex_unlock(&event->mutex); +} + +int thread_wait_event(event_t *handle, int timeout) +{ + event_pthread_t *event = (event_pthread_t *)handle; + struct timespec abstime; + +#if defined __linux__ || defined BSD + clock_gettime(CLOCK_REALTIME, &abstime); +#else + struct timeval now; + gettimeofday(&now, 0); + abstime.tv_sec = now.tv_sec; + abstime.tv_nsec = now.tv_usec*1000UL; +#endif + abstime.tv_nsec += (timeout % 1000) * 1000000; + abstime.tv_sec += (timeout / 1000); + if (abstime.tv_nsec > 1000000000) + { + abstime.tv_nsec -= 1000000000; + abstime.tv_sec++; + } + + pthread_mutex_lock(&event->mutex); + if (timeout == -1) + { + while (!event->state) + pthread_cond_wait(&event->cond, &event->mutex); + } + else if (!event->state) + pthread_cond_timedwait(&event->cond, &event->mutex, &abstime); + pthread_mutex_unlock(&event->mutex); + + return 0; +} + +void thread_destroy_event(event_t *handle) +{ + event_pthread_t *event = (event_pthread_t *)handle; + + pthread_cond_destroy(&event->cond); + pthread_mutex_destroy(&event->mutex); + + free(event); +} + +void thread_sleep(int t) +{ + usleep(t * 1000); +} + + +typedef struct pt_mutex_t +{ + pthread_mutex_t mutex; +} pt_mutex_t; + +mutex_t *thread_create_mutex(void) +{ + pt_mutex_t *mutex = malloc(sizeof(pt_mutex_t)); + + pthread_mutex_init(&mutex->mutex, NULL); + + return mutex; + +} + +mutex_t * +thread_create_mutex_with_spin_count(unsigned int spin_count) +{ + /* Setting spin count of a mutex is not possible with pthreads. */ + return thread_create_mutex(); +} + +int thread_wait_mutex(mutex_t *_mutex) +{ + if (_mutex == NULL) return(0); + pt_mutex_t *mutex = (pt_mutex_t *)_mutex; + + return pthread_mutex_lock(&mutex->mutex) != 0; +} + +int thread_release_mutex(mutex_t *_mutex) +{ + if (_mutex == NULL) return(0); + pt_mutex_t *mutex = (pt_mutex_t *)_mutex; + + return pthread_mutex_unlock(&mutex->mutex) != 0; +} + +void thread_close_mutex(mutex_t *_mutex) +{ + pt_mutex_t *mutex = (pt_mutex_t *)_mutex; + + pthread_mutex_destroy(&mutex->mutex); + + free(mutex); +} \ No newline at end of file