static void *emulation_thread_entry(void *data) { fs_emu_log("emulation thread started\n"); g_fs_emu_emulation_thread_running = 1; #ifdef WINDOWS if (SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL)) { fs_emu_log("thread priority set to THREAD_PRIORITY_ABOVE_NORMAL\n"); } else { int dwError = GetLastError(); fs_emu_log("Failed to set thread priority (%d)\n", dwError); } #endif #ifdef WITH_NETPLAY if (fs_emu_netplay_enabled()) { fs_emu_log("netplay is enabled - waiting for connection\n"); while (!fs_emu_netplay_connected()) { // waiting for connection fs_emu_msleep(10); if (!fs_emu_netplay_enabled()) { // net play mode was aborted fs_emu_log("netplay aborted\n"); break; } } } #endif void (*main_function)() = data; if (main_function) { fs_emu_log("main function at %p\n", data); main_function(); } else { fs_emu_fatal("main function is NULL pointer\n"); } // call fs_ml_quit in case the quit was not explicitly requested already fs_ml_quit(); g_fs_emu_emulation_thread_running = 0; // with this set, and fs_ml_quit being called, the frame render // function will call fs_ml_stop when the fadeout effect is done g_fs_emu_emulation_thread_stopped = 1; //fs_emu_log("calling fs_ml_stop because emulation thread has ended\n"); //fs_ml_stop(); return NULL; }
static void *emulation_thread(void *data) { fse_log("[FSE] Emulation thread started\n"); #ifdef WINDOWS set_windows_thread_priority(); #endif #ifdef WITH_NETPLAY if (fs_emu_netplay_enabled()) { fse_log("[NETPLAY] Enabled - waiting for connection...\n"); while (!fs_emu_netplay_connected()) { /* Waiting for connection... */ fs_emu_msleep(10); if (!fs_emu_netplay_enabled()) { /* Net play mode was aborted. */ fse_log("netplay aborted\n"); break; } } } #endif g_fs_emu_emulation_thread_running = 1; void (*main_function)() = data; if (main_function) { fse_log("[FSE] Run main function at %p\n", data); main_function(); } else { fs_emu_fatal("[FSE] NULL pointer main function\n"); } /* Call fs_ml_quit in case quit was not explicitly requested already. */ fs_ml_quit(); g_fs_emu_emulation_thread_running = 0; /* With this set, and fs_ml_quit being called, the frame render * function will call fs_ml_stop when the fadeout effect is done. */ g_fs_emu_emulation_thread_stopped = 1; return NULL; }
void fs_emu_initialize_textures() { if (g_fs_emu_theme.width == 0) { fs_emu_fatal("theme is not initialized yet"); } //g_atlas = fs_emu_texture_new_from_file("atlas"); fs_image *image = fs_image_new(); image->width = 1024; image->height = 1024; image->format = FS_IMAGE_FORMAT_RGBA; image->data = fs_malloc0(1024 * 1024 * 4); initialize_atlas(image); g_atlas = fs_new(fs_emu_texture, 1); g_atlas->width = image->width; g_atlas->height = image->height; g_atlas->image = image; load_texture(g_atlas); fs_emu_set_texture(g_atlas); fs_gl_add_context_notification(context_notification_handler, g_atlas); if (g_fs_emu_theme.overlay_image[0]) { char *path = fs_emu_theme_get_resource(g_fs_emu_theme.overlay_image); fs_log("g_fs_emu_theme.overlay_image %s => %s\n", g_fs_emu_theme.overlay_image, path); if (path) { g_fs_emu_overlay_texture = fs_emu_texture_new_from_file(path); } } for (int i = 0; i < FS_EMU_MAX_OVERLAYS; i++) { for (int j = 0; j < FS_EMU_MAX_OVERLAY_STATES; j++) { fs_emu_texture *tex = NULL; char *name = fs_strdup_printf("custom_%d_%d.png", i - FS_EMU_FIRST_CUSTOM_OVERLAY, j); char *path = fs_emu_theme_get_resource(name); if (!path && g_fs_emu_theme.overlays[i].name) { free(name); name = fs_strdup_printf("%s_%d.png", g_fs_emu_theme.overlays[i].name, j); path = fs_emu_theme_get_resource(name); } if (path) { tex = fs_emu_texture_new_from_file(path); g_fs_emu_theme.overlays[i].textures[j] = tex; free(path); } else if (j == 1) { char *base_name = fs_strdup_printf("custom_%d.png", i - FS_EMU_FIRST_CUSTOM_OVERLAY); path = fs_emu_theme_get_resource(base_name); if (!path && g_fs_emu_theme.overlays[i].name) { free(name); name = fs_strdup_printf("%s.png", g_fs_emu_theme.overlays[i].name); path = fs_emu_theme_get_resource(name); } if (path) { tex = fs_emu_texture_new_from_file(path); g_fs_emu_theme.overlays[i].textures[j] = tex; free(path); } free(base_name); } else if (j >= 2) { g_fs_emu_theme.overlays[i].textures[j] = \ g_fs_emu_theme.overlays[i].textures[j - 1]; } free(name); // size will be determined from the last loaded texture/state // for the overlay if (tex) { g_fs_emu_theme.overlays[i].w = (double) tex->width / g_fs_emu_theme.width; g_fs_emu_theme.overlays[i].h = (double) tex->height / g_fs_emu_theme.height; } } } }
static void set_video_mode() { int flags = SDL_WINDOW_OPENGL; if (g_fs_emu_video_fullscreen_mode != FULLSCREEN_WINDOW && g_window_resizable) { flags |= SDL_WINDOW_RESIZABLE; } int x = g_window_x, y = g_window_y; int w = -1, h = -1; // if (g_initial_input_grab) { // flags |= SDL_WINDOW_INPUT_GRABBED; // g_has_input_grab = 1; // } if (g_fs_emu_video_fullscreen == 1) { w = g_fullscreen_width; h = g_fullscreen_height; //w = g_window_width; //h = g_window_height; if (g_fs_emu_video_fullscreen_mode == FULLSCREEN_WINDOW) { fs_log("using fullscreen window mode\n"); //x = 0; //y = 0; //w = g_fullscreen_width; //h = g_fullscreen_height; flags |= SDL_WINDOW_BORDERLESS; FSEmuMonitor monitor; fs_emu_monitor_get_by_index(g_display, &monitor); x = monitor.rect.x; y = monitor.rect.y; w = monitor.rect.w; h = monitor.rect.h; } else if (g_fs_emu_video_fullscreen_mode == FULLSCREEN_DESKTOP) { fs_log("using fullscreen desktop mode\n"); // the width and height will not be used for the fullscreen // desktop mode, only for the window when toggling fullscreen // state #if 0 w = g_window_width; h = g_window_height; #else FSEmuMonitor monitor; fs_emu_monitor_get_by_index(g_display, &monitor); x = monitor.rect.x; y = monitor.rect.y; w = monitor.rect.w; h = monitor.rect.h; #endif flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; } else { fs_log("using SDL_FULLSCREEN mode\n"); flags |= SDL_WINDOW_FULLSCREEN; } fs_log("setting (fullscreen) video mode %d %d\n", w, h); } else { w = g_window_width; h = g_window_height; fs_log("using windowed mode\n"); //SDL_putenv("SDL_VIDEO_WINDOW_POS="); fs_log("setting (windowed) video mode %d %d\n", w, h); } if (fs_config_get_boolean("window_border") == 0) { fs_log("borderless window requested\n"); flags |= SDL_WINDOW_BORDERLESS; } #if 0 Uint8 data[] = "\0"; SDL_Cursor *cursor = SDL_CreateCursor(data, data, 8, 1, 0, 0); SDL_SetCursor(cursor); #endif g_fs_ml_video_width = w; g_fs_ml_video_height = h; fs_log("[SDL] CreateWindow(x=%d, y=%d, w=%d, h=%d, flags=%d)\n", x, y, w, h, flags); g_fs_ml_window = SDL_CreateWindow(g_window_title, x, y, w, h, flags); int assume_refresh_rate = fs_config_get_int("assume_refresh_rate"); if (assume_refresh_rate != FS_CONFIG_NONE) { fs_log("[DISPLAY] Assuming host refresh rate: %d Hz (from config)\n", assume_refresh_rate); g_fs_emu_video_frame_rate_host = assume_refresh_rate; } else { SDL_DisplayMode mode; if (SDL_GetWindowDisplayMode(g_fs_ml_window, &mode) == 0) { g_fs_emu_video_frame_rate_host = mode.refresh_rate; } else { g_fs_emu_video_frame_rate_host = 0; } fs_log("[DISPLAY] Host refresh rate: %d Hz\n", g_fs_emu_video_frame_rate_host); } if (g_fs_emu_video_frame_rate_host) { g_fs_ml_target_frame_time = 1000000 / g_fs_emu_video_frame_rate_host; } g_fs_ml_context = SDL_GL_CreateContext(g_fs_ml_window); #ifdef WITH_GLEW static int glew_initialized = 0; if (!glew_initialized) { GLenum err = glewInit(); if (GLEW_OK != err) { fprintf(stderr, "[GLEW] Error: %s\n", glewGetErrorString(err)); fs_emu_fatal("[GLEW] Error initializing glew"); } fs_log("[GLEW] Version %s\n", glewGetString(GLEW_VERSION)); glew_initialized = 1; } #elif defined(WITH_GLAD) static int glad_initialized = 0; if (!glad_initialized) { if (!gladLoadGLLoader((GLADloadproc) SDL_GL_GetProcAddress)) { fs_emu_fatal("[GLAD] Failed to initialize OpenGL context"); } glad_initialized = 1; } #endif fs_ml_configure_window(); // FIXME: this can be removed g_fs_ml_opengl_context_stamp++; log_opengl_information(); }