Task* taskmgr_submit(TaskManager *mgr, TaskParams params) { assert(params.callback != NULL); Task *task = calloc(1, sizeof(Task)); task->callback = params.callback; task->userdata_free_callback = params.userdata_free_callback; task->userdata = params.userdata; task->prio = params.prio; task->status = TASK_PENDING; if(!(task->mutex = SDL_CreateMutex())) { log_sdl_error(LOG_WARN, "SDL_CreateMutex"); goto fail; } if(!(task->cond = SDL_CreateCond())) { log_sdl_error(LOG_WARN, "SDL_CreateCond"); goto fail; } SDL_LockMutex(mgr->mutex); if(params.topmost) { alist_insert_at_priority_head(&mgr->queue, task, task->prio, task_prio_func); } else { alist_insert_at_priority_tail(&mgr->queue, task, task->prio, task_prio_func); } task->in_queue = true; SDL_AtomicIncRef(&mgr->numtasks); SDL_CondSignal(mgr->cond); SDL_UnlockMutex(mgr->mutex); return task; fail: task_free(task); return NULL; }
void gamepad_init(void) { if(!config_get_int(CONFIG_GAMEPAD_ENABLED) || gamepad.initialized) { return; } if(SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) < 0) { log_sdl_error(LOG_ERROR, "SDL_InitSubSystem"); return; } gamepad.initialized = true; gamepad.axes = calloc(GAMEPAD_AXIS_MAX, sizeof(GamepadAxisState)); gamepad.buttons = calloc(GAMEPAD_BUTTON_MAX + GAMEPAD_EMULATED_BUTTON_MAX, sizeof(GamepadButtonState)); gamepad.active_dev_num = GAMEPAD_DEVNUM_INVALID; gamepad_load_all_mappings(); events_register_handler(&(EventHandler){ .proc = gamepad_event_handler, .priority = EPRIO_TRANSLATION, });
static bool gamepad_update_device_list(void) { int cnt = SDL_NumJoysticks(); log_info("Updating gamepad devices list"); if(gamepad.num_devices > 0) { assume(gamepad.devices != NULL); for(uint i = 0; i < gamepad.num_devices; ++i) { SDL_GameControllerClose(gamepad.devices[i].controller); } } gamepad.num_devices = 0; if(!cnt) { free(gamepad.devices); gamepad.devices = NULL; gamepad.num_devices_allocated = 0; log_info("No joysticks attached"); return false; } if(gamepad.num_devices_allocated != cnt) { free(gamepad.devices); gamepad.devices = calloc(cnt, sizeof(GamepadDevice)); gamepad.num_devices_allocated = cnt; } GamepadDevice *dev = gamepad.devices; for(int i = 0; i < cnt; ++i) { SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(i); char guid_str[33] = { 0 }; SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str)); if(!*guid_str) { log_warn("Failed to read GUID of joystick at index %i: %s", i, SDL_GetError()); continue; } if(!SDL_IsGameController(i)) { log_warn("Joystick at index %i (name: \"%s\"; guid: %s) is not recognized as a game controller by SDL. " "Most likely it just doesn't have a mapping. See https://git.io/vdvdV for solutions", i, SDL_JoystickNameForIndex(i), guid_str); continue; } dev->sdl_id = i; dev->controller = SDL_GameControllerOpen(i); if(dev->controller == NULL) { log_sdl_error(LOG_WARN, "SDL_GameControllerOpen"); continue; } dev->joy_instance = SDL_JoystickGetDeviceInstanceID(i); if(dev->joy_instance < 0) { log_sdl_error(LOG_WARN, "SDL_JoystickGetDeviceInstanceID"); continue; } log_info("Found device '%s' (#%i): %s", guid_str, DEVNUM(dev), gamepad_device_name_unmapped(i)); ++gamepad.num_devices; ++dev; } if(!gamepad.num_devices) { log_info("No usable devices"); return false; } return true; }
static int taskmgr_thread(void *arg) { TaskManager *mgr = arg; attr_unused SDL_threadID tid = SDL_ThreadID(); if(SDL_SetThreadPriority(mgr->thread_prio) < 0) { log_sdl_error(LOG_WARN, "SDL_SetThreadPriority"); } bool running; bool aborted; do { SDL_LockMutex(mgr->mutex); running = mgr->running; aborted = mgr->aborted; if(!running && !aborted) { SDL_CondWait(mgr->cond, mgr->mutex); } SDL_UnlockMutex(mgr->mutex); } while(!running && !aborted); while(running && !aborted) { SDL_LockMutex(mgr->mutex); Task *task = alist_pop(&mgr->queue); running = mgr->running; aborted = mgr->aborted; if(running && task == NULL && !aborted) { SDL_CondWait(mgr->cond, mgr->mutex); } SDL_UnlockMutex(mgr->mutex); if(task != NULL) { SDL_LockMutex(task->mutex); bool task_disowned = task->disowned; if(aborted && task->status == TASK_PENDING) { task->status = TASK_CANCELLED; } if(task->status == TASK_PENDING) { task->status = TASK_RUNNING; SDL_UnlockMutex(task->mutex); task->result = task->callback(task->userdata); SDL_LockMutex(task->mutex); assert(task->in_queue); task->in_queue = false; (void)SDL_AtomicDecRef(&mgr->numtasks); if((task_disowned = task->disowned)) { SDL_UnlockMutex(task->mutex); task_free(task); } else { task->status = TASK_FINISHED; SDL_CondBroadcast(task->cond); SDL_UnlockMutex(task->mutex); } } else if(task->status == TASK_CANCELLED) { assert(task->in_queue); task->in_queue = false; (void)SDL_AtomicDecRef(&mgr->numtasks); SDL_UnlockMutex(task->mutex); if(task_disowned) { task_free(task); } } else { UNREACHABLE; } } } return 0; }
TaskManager* taskmgr_create(uint numthreads, SDL_ThreadPriority prio, const char *name) { int numcores = SDL_GetCPUCount(); uint maxthreads = numcores * 8; if(numcores < 1) { log_warn("SDL_GetCPUCount() returned %i, assuming 1", numcores); numcores = 1; } if(numthreads == 0) { numthreads = numcores * 4; } else if(numthreads > maxthreads) { log_warn("Number of threads capped to %i (%i requested)", maxthreads, numthreads); numthreads = maxthreads; } TaskManager *mgr = calloc(1, sizeof(TaskManager) + numthreads * sizeof(SDL_Thread*)); if(!(mgr->mutex = SDL_CreateMutex())) { log_sdl_error(LOG_WARN, "SDL_CreateMutex"); goto fail; } if(!(mgr->cond = SDL_CreateCond())) { log_sdl_error(LOG_WARN, "SDL_CreateCond"); goto fail; } mgr->numthreads = numthreads; mgr->thread_prio = prio; for(uint i = 0; i < numthreads; ++i) { int digits = i ? log10(i) + 1 : 0; static const char *const prefix = "taskmgr"; char threadname[sizeof(prefix) + strlen(name) + digits + 2]; snprintf(threadname, sizeof(threadname), "%s:%s/%i", prefix, name, i); if(!(mgr->threads[i] = SDL_CreateThread(taskmgr_thread, threadname, mgr))) { log_sdl_error(LOG_WARN, "SDL_CreateThread"); for(uint j = 0; j < i; ++j) { SDL_DetachThread(mgr->threads[j]); mgr->threads[j] = NULL; } SDL_LockMutex(mgr->mutex); mgr->aborted = true; SDL_CondBroadcast(mgr->cond); SDL_UnlockMutex(mgr->mutex); goto fail; } } SDL_LockMutex(mgr->mutex); mgr->running = true; SDL_CondBroadcast(mgr->cond); SDL_UnlockMutex(mgr->mutex); log_debug( "Created task manager %s (%p) with %u threads at priority %i", name, (void*)mgr, mgr->numthreads, prio ); return mgr; fail: taskmgr_free(mgr); return NULL; }
void FPS::increment(SDL_Renderer * renderer) { unsigned int time_now = SDL_GetTicks(); unsigned int delta_time = time_now - fps_start_time; // increment the number of frames rendered current_frame_count += 1; // if it's time to update the fps count then if (delta_time > FRAME_RATE_PERIOD) { // change the current_fps current_fps = current_frame_count / FRAME_RATE_PERIOD; // FIXME: remove this! //std::cout << "fps: " << get_fps() << std::endl; // FIXME WE NEED // method to blat dynamic floats (digits to texture then render). // method to blat static strings (to texture then render) // // FIXME: this is slow.. // render on the GPU by making textures for each digit and displaying them fps_text_surface = TTF_RenderText_Solid( fps_font, // This doesn't work because of a bug in the current version of mingw/gcc!! // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52015 // std::to_string(current_frame_count).c_str(), "FIX THE FPS STUFF!!!", fps_font_color); if (!fps_text_surface) { // handle error here, perhaps print TTF_GetError at least log_ttf_error("Problem displaying fps text!"); } else { fps_text_texture = SDL_CreateTextureFromSurface(renderer, fps_text_surface); if (!fps_text_texture) { log_sdl_error("SDL_CreateTextureFromSurface: "); //return 4; } else { std::cout << "Draw FPS XXXX" << std::endl; } // draw the title SDL_Rect src = { 0, 0, fps_text_surface->w, fps_text_surface->h }; SDL_Rect dest = { 30, 30, fps_text_surface->w, fps_text_surface->h}; SDL_RenderCopy(renderer, fps_text_texture, &src, &dest); // perhaps we can reuse it, but I assume not for simplicity. SDL_FreeSurface(fps_text_surface); SDL_DestroyTexture(fps_text_texture); } // and reset the fps counters current_frame_count = 0; fps_start_time = time_now; } }