static bool d3d_read_viewport(void *data, uint8_t *buffer) { d3d_video_t *d3d = (d3d_video_t*)data; LPDIRECT3DDEVICE d3dr = d3d->dev; RARCH_PERFORMANCE_INIT(d3d_read_viewport); RARCH_PERFORMANCE_START(d3d_read_viewport); bool ret = true; LPDIRECT3DSURFACE target = NULL; LPDIRECT3DSURFACE dest = NULL; if (FAILED(d3d->d3d_err = d3dr->GetRenderTarget(0, &target))) { ret = false; goto end; } if (FAILED(d3d->d3d_err = d3dr->CreateOffscreenPlainSurface(d3d->screen_width, d3d->screen_height, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &dest, NULL))) { ret = false; goto end; } if (FAILED(d3d->d3d_err = d3dr->GetRenderTargetData(target, dest))) { ret = false; goto end; } D3DLOCKED_RECT rect; if (SUCCEEDED(dest->LockRect(&rect, NULL, D3DLOCK_READONLY))) { unsigned pitchpix = rect.Pitch / 4; const uint32_t *pixels = (const uint32_t*)rect.pBits; pixels += d3d->final_viewport.X; pixels += (d3d->final_viewport.Height - 1) * pitchpix; pixels -= d3d->final_viewport.Y * pitchpix; for (unsigned y = 0; y < d3d->final_viewport.Height; y++, pixels -= pitchpix) { for (unsigned x = 0; x < d3d->final_viewport.Width; x++) { *buffer++ = (pixels[x] >> 0) & 0xff; *buffer++ = (pixels[x] >> 8) & 0xff; *buffer++ = (pixels[x] >> 16) & 0xff; } } dest->UnlockRect(); }
bool D3DVideo::read_viewport(uint8_t *buffer) { RARCH_PERFORMANCE_INIT(d3d_read_viewport); RARCH_PERFORMANCE_START(d3d_read_viewport); bool ret = true; IDirect3DSurface9 *target = nullptr; IDirect3DSurface9 *dest = nullptr; if (FAILED(Callback::d3d_err = dev->GetRenderTarget(0, &target))) { ret = false; goto end; } if (FAILED(Callback::d3d_err = dev->CreateOffscreenPlainSurface(screen_width, screen_height, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &dest, nullptr))) { ret = false; goto end; } if (FAILED(Callback::d3d_err = dev->GetRenderTargetData(target, dest))) { ret = false; goto end; } D3DLOCKED_RECT rect; if (SUCCEEDED(dest->LockRect(&rect, nullptr, D3DLOCK_READONLY))) { unsigned pitchpix = rect.Pitch / 4; const uint32_t *pixels = (const uint32_t*)rect.pBits; pixels += final_viewport.X; pixels += (final_viewport.Height - 1) * pitchpix; pixels -= final_viewport.Y * pitchpix; for (unsigned y = 0; y < final_viewport.Height; y++, pixels -= pitchpix) { for (unsigned x = 0; x < final_viewport.Width; x++) { *buffer++ = (pixels[x] >> 0) & 0xff; *buffer++ = (pixels[x] >> 8) & 0xff; *buffer++ = (pixels[x] >> 16) & 0xff; } } dest->UnlockRect(); }
static void sdl_refresh_input_size(sdl2_video_t *vid, bool menu, bool rgb32, unsigned width, unsigned height, unsigned pitch) { sdl2_tex_t *target = menu ? &vid->menu : &vid->frame; if (!target->tex || target->w != width || target->h != height || target->rgb32 != rgb32 || target->pitch != pitch) { unsigned format; sdl_tex_zero(target); RARCH_PERFORMANCE_INIT(sdl_create_texture); RARCH_PERFORMANCE_START(sdl_create_texture); if (menu) format = rgb32 ? SDL_PIXELFORMAT_ARGB8888 : SDL_PIXELFORMAT_RGBA4444; else /* this assumes the frontend will convert 0RGB1555 to RGB565 */ format = rgb32 ? SDL_PIXELFORMAT_ARGB8888 : SDL_PIXELFORMAT_RGB565; SDL_SetHintWithPriority(SDL_HINT_RENDER_SCALE_QUALITY, (vid->video.smooth || menu) ? "linear" : "nearest", SDL_HINT_OVERRIDE); target->tex = SDL_CreateTexture(vid->renderer, format, SDL_TEXTUREACCESS_STREAMING, width, height); RARCH_PERFORMANCE_STOP(sdl_create_texture); if (!target->tex) { RARCH_ERR("Failed to create %s texture: %s\n", menu ? "menu" : "main", SDL_GetError()); return; } if (menu) SDL_SetTextureBlendMode(target->tex, SDL_BLENDMODE_BLEND); target->w = width; target->h = height; target->pitch = pitch; target->rgb32 = rgb32; target->active = true; } }
static bool sdl2_gfx_frame(void *data, const void *frame, unsigned width, unsigned height, unsigned pitch, const char *msg) { char buf[128]; sdl2_video_t *vid = (sdl2_video_t*)data; runloop_t *runloop = rarch_main_get_ptr(); driver_t *driver = driver_get_ptr(); if (vid->should_resize) sdl_refresh_viewport(vid); if (frame) { sdl_refresh_input_size(vid, false, vid->video.rgb32, width, height, pitch); RARCH_PERFORMANCE_INIT(sdl_copy_frame); RARCH_PERFORMANCE_START(sdl_copy_frame); SDL_UpdateTexture(vid->frame.tex, NULL, frame, pitch); RARCH_PERFORMANCE_STOP(sdl_copy_frame); } SDL_RenderCopyEx(vid->renderer, vid->frame.tex, NULL, NULL, vid->rotation, NULL, SDL_FLIP_NONE); #ifdef HAVE_MENU if (runloop->is_menu) menu_driver_frame(); #endif if (vid->menu.active) SDL_RenderCopy(vid->renderer, vid->menu.tex, NULL, NULL); if (msg) sdl2_render_msg(vid, msg); SDL_RenderPresent(vid->renderer); if (video_monitor_get_fps(buf, sizeof(buf), NULL, 0)) SDL_SetWindowTitle(vid->window, buf); vid->frame_count++; return true; }
void sdl2_poke_set_texture_frame(void *data, const void *frame, bool rgb32, unsigned width, unsigned height, float alpha) { sdl2_video_t *vid = (sdl2_video_t*)data; if (frame) { sdl_refresh_input_size(vid, true, rgb32, width, height, width * (rgb32 ? 4 : 2)); RARCH_PERFORMANCE_INIT(copy_texture_frame); RARCH_PERFORMANCE_START(copy_texture_frame); SDL_UpdateTexture(vid->menu.tex, NULL, frame, vid->menu.pitch); RARCH_PERFORMANCE_STOP(copy_texture_frame); } }
static void gfx_ctx_check_window(bool *quit, bool *resize, unsigned *width, unsigned *height, unsigned frame_count) { (void)width; (void)height; (void)frame_count; int id; struct android_app* android_app = g_android.app; *quit = false; *resize = false; RARCH_PERFORMANCE_INIT(alooper_pollonce); RARCH_PERFORMANCE_START(alooper_pollonce); id = ALooper_pollOnce(0, NULL, 0, NULL); if(id == LOOPER_ID_MAIN) { int8_t cmd; if (read(android_app->msgread, &cmd, sizeof(cmd)) == sizeof(cmd)) { if(cmd == APP_CMD_SAVE_STATE) free_saved_state(android_app); } else cmd = -1; engine_handle_cmd(android_app, cmd); } RARCH_PERFORMANCE_STOP(alooper_pollonce); // Check if we are exiting. if (g_extern.lifecycle_state & (1ULL << RARCH_QUIT_KEY)) *quit = true; }
static void gfx_ctx_check_window(bool *quit, bool *resize, unsigned *width, unsigned *height, unsigned frame_count) { (void)frame_count; struct android_app *android_app = (struct android_app*)g_android; *quit = false; unsigned new_width, new_height; gfx_ctx_get_video_size(&new_width, &new_height); if (new_width != *width || new_height != *height) { *width = new_width; *height = new_height; *resize = true; } RARCH_PERFORMANCE_INIT(alooper_pollonce); RARCH_PERFORMANCE_START(alooper_pollonce); while (ALooper_pollOnce(0, NULL, NULL, NULL) == LOOPER_ID_MAIN) { int8_t cmd; if (read(android_app->msgread, &cmd, sizeof(cmd)) != sizeof(cmd)) cmd = -1; engine_handle_cmd(android_app, cmd); } RARCH_PERFORMANCE_STOP(alooper_pollonce); // Check if we are exiting. if (g_extern.lifecycle_state & (1ULL << RARCH_QUIT_KEY)) *quit = true; }
static bool sdl2_gfx_read_viewport(void *data, uint8_t *buffer) { sdl2_video_t *vid = (sdl2_video_t*)data; RARCH_PERFORMANCE_INIT(sdl2_gfx_read_viewport); RARCH_PERFORMANCE_START(sdl2_gfx_read_viewport); rarch_render_cached_frame(); SDL_Surface *surf = SDL_GetWindowSurface(vid->window); SDL_Surface *bgr24 = SDL_ConvertSurfaceFormat(surf, SDL_PIXELFORMAT_BGR24, 0); if (!bgr24) { RARCH_WARN("Failed to convert viewport data to BGR24: %s", SDL_GetError()); return false; } memcpy(buffer, bgr24->pixels, bgr24->h * bgr24->pitch); RARCH_PERFORMANCE_STOP(sdl2_gfx_read_viewport); return true; }
static bool psp_frame(void *data, const void *frame, unsigned width, unsigned height, unsigned pitch, const char *msg) { static char fps_txt[128], fps_text_buf[128]; psp1_video_t *psp = (psp1_video_t*)data; #ifdef DISPLAY_FPS static uint64_t currentTick,lastTick; static float fps=0.0; static int frames; #endif if (!width || !height) return false; if (((uint32_t)frame&0x04000000) || (frame == RETRO_HW_FRAME_BUFFER_VALID)) psp->hw_render = true; else if (frame) psp->hw_render = false; if (!psp->hw_render) sceGuSync(0, 0); /* let the core decide when to sync when HW_RENDER */ pspDebugScreenSetBase(psp->draw_buffer); pspDebugScreenSetXY(0,0); video_monitor_get_fps(fps_txt, sizeof(fps_txt), g_settings.fps_show ? fps_text_buf : NULL, g_settings.fps_show ? sizeof(fps_text_buf) : 0); if(g_settings.fps_show) { pspDebugScreenSetXY(68 - strlen(fps_text_buf) - 1,0); pspDebugScreenPuts(fps_text_buf); pspDebugScreenSetXY(0,1); } if (msg) pspDebugScreenPuts(msg); if ((psp->vsync)&&(psp->vblank_not_reached)) sceDisplayWaitVblankStart(); psp->vblank_not_reached = true; #ifdef DISPLAY_FPS frames++; sceRtcGetCurrentTick(¤tTick); uint32_t diff = currentTick - lastTick; if(diff > 1000000) { fps = (float)frames * 1000000.0 / diff; lastTick = currentTick; frames = 0; } pspDebugScreenSetXY(0,0); pspDebugScreenPrintf("%f", fps); #endif psp->draw_buffer = FROM_GU_POINTER(sceGuSwapBuffers()); g_extern.frame_count++; RARCH_PERFORMANCE_INIT(psp_frame_run); RARCH_PERFORMANCE_START(psp_frame_run); if (psp->should_resize) psp_update_viewport(psp); psp_set_tex_coords(psp->frame_coords, width, height); sceGuStart(GU_DIRECT, psp->main_dList); sceGuTexFilter(psp->tex_filter, psp->tex_filter); sceGuClear(GU_COLOR_BUFFER_BIT); /* frame in VRAM ? texture/palette was * set in core so draw directly */ if (psp->hw_render) sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF | GU_TRANSFORM_2D, PSP_FRAME_VERTEX_COUNT, NULL, (void*)(psp->frame_coords)); else { if (frame) { sceKernelDcacheWritebackRange(frame,pitch * height); sceGuCopyImage(GU_PSM_5650, ((u32)frame & 0xF) >> psp->bpp_log2, 0, width, height, pitch >> psp->bpp_log2, (void*)((u32)frame & ~0xF), 0, 0, width, psp->texture); } sceGuTexImage(0, next_pow2(width), next_pow2(height), width, psp->texture); sceGuCallList(psp->frame_dList); } sceGuFinish(); RARCH_PERFORMANCE_STOP(psp_frame_run); if(psp->menu.active) { sceGuSendList(GU_TAIL, psp->menu.dList, &(psp->menu.context_storage)); sceGuSync(0, 0); } return true; }
static void android_input_poll(void *data) { (void)data; RARCH_PERFORMANCE_INIT(input_poll); RARCH_PERFORMANCE_START(input_poll); struct android_app* android_app = g_android.app; g_extern.lifecycle_state &= ~((1ULL << RARCH_RESET) | (1ULL << RARCH_REWIND) | (1ULL << RARCH_FAST_FORWARD_KEY) | (1ULL << RARCH_FAST_FORWARD_HOLD_KEY) | (1ULL << RARCH_MUTE) | (1ULL << RARCH_SAVE_STATE_KEY) | (1ULL << RARCH_LOAD_STATE_KEY) | (1ULL << RARCH_STATE_SLOT_PLUS) | (1ULL << RARCH_STATE_SLOT_MINUS)); // Read all pending events. while(AInputQueue_hasEvents(android_app->inputQueue)) { AInputEvent* event = NULL; AInputQueue_getEvent(android_app->inputQueue, &event); if (AInputQueue_preDispatchEvent(android_app->inputQueue, event)) continue; int32_t handled = 1; int source = AInputEvent_getSource(event); int id = AInputEvent_getDeviceId(event); int type_event = AInputEvent_getType(event); int state_id = state_device_ids[id]; if(state_id == -1) state_id = state_device_ids[id] = pads_connected++; int action = 0; #ifdef RARCH_INPUT_DEBUG char msg[128]; #endif if(type_event == AINPUT_EVENT_TYPE_MOTION) { action = AMotionEvent_getAction(event); int8_t motion_action = action & AMOTION_EVENT_ACTION_MASK; size_t motion_pointer = action >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; float x = AMotionEvent_getX(event, motion_pointer); float y = AMotionEvent_getY(event, motion_pointer); if(source & ~(AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_MOUSE)) { state[state_id] &= ~((1ULL << RETRO_DEVICE_ID_JOYPAD_LEFT) | (1ULL << RETRO_DEVICE_ID_JOYPAD_RIGHT) | (1ULL << RETRO_DEVICE_ID_JOYPAD_UP) | (1ULL << RETRO_DEVICE_ID_JOYPAD_DOWN)); state[state_id] |= PRESSED_LEFT(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_LEFT) : 0; state[state_id] |= PRESSED_RIGHT(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_RIGHT) : 0; state[state_id] |= PRESSED_UP(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_UP) : 0; state[state_id] |= PRESSED_DOWN(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_DOWN) : 0; } else { bool mouse_is_not_dirty = (source == AINPUT_SOURCE_MOUSE && action != AMOTION_EVENT_ACTION_DOWN); bool pointer_is_not_dirty = (action == AMOTION_EVENT_ACTION_UP || action == AMOTION_EVENT_ACTION_CANCEL || action == AMOTION_EVENT_ACTION_POINTER_UP); pointer_dirty = !(mouse_is_not_dirty || pointer_is_not_dirty); if (pointer_dirty) input_translate_coord_viewport(x, y, &pointer_x, &pointer_y); } #ifdef RARCH_INPUT_DEBUG snprintf(msg, sizeof(msg), "Pad %d : x = %.2f, y = %.2f, src %d.\n", state_id, x, y, source); #endif } else {
/** * check_rewind: * @pressed : was rewind key pressed or held? * * Checks if rewind toggle/hold was being pressed and/or held. **/ static void check_rewind(settings_t *settings, global_t *global, runloop_t *runloop, bool pressed) { static bool first = true; if (global->rewind.frame_is_reverse) { audio_driver_frame_is_reverse(); global->rewind.frame_is_reverse = false; } if (first) { first = false; return; } if (!global->rewind.state) return; if (pressed) { const void *buf = NULL; if (state_manager_pop(global->rewind.state, &buf)) { global->rewind.frame_is_reverse = true; audio_driver_setup_rewind(); rarch_main_msg_queue_push_new(MSG_REWINDING, 0, runloop->is_paused ? 1 : 30, true); pretro_unserialize(buf, global->rewind.size); if (global->bsv.movie) bsv_movie_frame_rewind(global->bsv.movie); } else rarch_main_msg_queue_push_new(MSG_REWIND_REACHED_END, 0, 30, true); } else { static unsigned cnt = 0; cnt = (cnt + 1) % (settings->rewind_granularity ? settings->rewind_granularity : 1); /* Avoid possible SIGFPE. */ if ((cnt == 0) || global->bsv.movie) { void *state = NULL; state_manager_push_where(global->rewind.state, &state); RARCH_PERFORMANCE_INIT(rewind_serialize); RARCH_PERFORMANCE_START(rewind_serialize); pretro_serialize(state, global->rewind.size); RARCH_PERFORMANCE_STOP(rewind_serialize); state_manager_push_do(global->rewind.state); } } retro_set_rewind_callbacks(); }
static bool d3d_frame(void *data, const void *frame, unsigned width, unsigned height, unsigned pitch, const char *msg) { d3d_video_t *d3d = (d3d_video_t*)data; if (!frame) return true; RARCH_PERFORMANCE_INIT(d3d_frame); RARCH_PERFORMANCE_START(d3d_frame); // We cannot recover in fullscreen. if (d3d->needs_restore && IsIconic(d3d->hWnd)) return true; if (d3d->needs_restore && !d3d_restore(d3d)) { RARCH_ERR("[D3D]: Failed to restore.\n"); return false; } if (d3d->should_resize) { d3d_calculate_rect(d3d, d3d->screen_width, d3d->screen_height, d3d->video_info.force_aspect, g_extern.system.aspect_ratio); renderchain_set_final_viewport(d3d->chain, &d3d->final_viewport); d3d_recompute_pass_sizes(d3d); d3d->should_resize = false; } // render_chain() only clears out viewport, clear out everything. D3DVIEWPORT screen_vp; screen_vp.X = 0; screen_vp.Y = 0; screen_vp.MinZ = 0; screen_vp.MaxZ = 1; screen_vp.Width = d3d->screen_width; screen_vp.Height = d3d->screen_height; d3d->dev->SetViewport(&screen_vp); d3d->dev->Clear(0, 0, D3DCLEAR_TARGET, 0, 1, 0); // Insert black frame first, so we can screenshot, etc. if (g_settings.video.black_frame_insertion) { if (d3d->dev->Present(NULL, NULL, NULL, NULL) != D3D_OK) { RARCH_ERR("[D3D]: Present() failed.\n"); d3d->needs_restore = true; return true; } d3d->dev->Clear(0, 0, D3DCLEAR_TARGET, 0, 1, 0); } if (!renderchain_render(d3d->chain, frame, width, height, pitch, d3d->dev_rotation)) { RARCH_ERR("[D3D]: Failed to render scene.\n"); return false; } if (d3d->font_ctx && d3d->font_ctx->render_msg) { font_params_t font_parms = {0}; #ifdef _XBOX #if defined(_XBOX1) float msg_width = 60; float msg_height = 365; #elif defined(_XBOX360) float msg_width = (g_extern.lifecycle_state & (1ULL << MODE_MENU_HD)) ? 160 : 100; float msg_height = 120; #endif font_parms.x = msg_width; font_parms.y = msg_height; font_parms.scale = 21; #endif d3d->font_ctx->render_msg(d3d, msg, &font_parms); } #ifdef HAVE_MENU if (d3d->rgui && d3d->rgui->enabled) d3d_overlay_render(d3d, d3d->rgui); #endif #ifdef HAVE_OVERLAY if (d3d->overlays_enabled) { for (unsigned i = 0; i < d3d->overlays.size(); i++) d3d_overlay_render(d3d, &d3d->overlays[i]); } #endif RARCH_PERFORMANCE_STOP(d3d_frame); #ifdef HAVE_MENU if (g_extern.lifecycle_state & (1ULL << MODE_MENU) && driver.menu_ctx && driver.menu_ctx->frame) driver.menu_ctx->frame(d3d); #endif if (d3d && d3d->ctx_driver && d3d->ctx_driver->update_window_title) d3d->ctx_driver->update_window_title(d3d); if (d3d && d3d->ctx_driver && d3d->ctx_driver->swap_buffers) d3d->ctx_driver->swap_buffers(d3d); return true; }
static bool thread_frame(void *data, const void *frame_, unsigned width, unsigned height, unsigned pitch, const char *msg) { unsigned copy_stride; const uint8_t *src = NULL; uint8_t *dst = NULL; thread_video_t *thr = (thread_video_t*)data; /* If called from within read_viewport, we're actually in the * driver thread, so just render directly. */ if (thr->frame.within_thread) { thread_update_driver_state(thr); if (thr->driver && thr->driver->frame) return thr->driver->frame(thr->driver_data, frame_, width, height, pitch, msg); return false; } RARCH_PERFORMANCE_INIT(thr_frame); RARCH_PERFORMANCE_START(thr_frame); copy_stride = width * (thr->info.rgb32 ? sizeof(uint32_t) : sizeof(uint16_t)); src = (const uint8_t*)frame_; dst = thr->frame.buffer; slock_lock(thr->lock); if (!thr->nonblock) { settings_t *settings = config_get_ptr(); retro_time_t target_frame_time = (retro_time_t) roundf(1000000 / settings->video.refresh_rate); retro_time_t target = thr->last_time + target_frame_time; /* Ideally, use absolute time, but that is only a good idea on POSIX. */ while (thr->frame.updated) { retro_time_t current = rarch_get_time_usec(); retro_time_t delta = target - current; if (delta <= 0) break; if (!scond_wait_timeout(thr->cond_cmd, thr->lock, delta)) break; } } /* Drop frame if updated flag is still set, as thread is * still working on last frame. */ if (!thr->frame.updated) { if (src) { unsigned h; for (h = 0; h < height; h++, src += pitch, dst += copy_stride) memcpy(dst, src, copy_stride); } thr->frame.updated = true; thr->frame.width = width; thr->frame.height = height; thr->frame.pitch = copy_stride; if (msg) strlcpy(thr->frame.msg, msg, sizeof(thr->frame.msg)); else *thr->frame.msg = '\0'; scond_signal(thr->cond_thread); #if defined(HAVE_MENU) if (thr->texture.enable) { while (thr->frame.updated) scond_wait(thr->cond_cmd, thr->lock); } #endif thr->hit_count++; } else thr->miss_count++; slock_unlock(thr->lock); RARCH_PERFORMANCE_STOP(thr_frame); thr->last_time = rarch_get_time_usec(); return true; }
static bool thread_frame(void *data, const void *frame_, unsigned width, unsigned height, unsigned pitch, const char *msg) { RARCH_PERFORMANCE_INIT(thread_frame); RARCH_PERFORMANCE_START(thread_frame); thread_video_t *thr = (thread_video_t*)data; unsigned copy_stride = width * (thr->info.rgb32 ? sizeof(uint32_t) : sizeof(uint16_t)); const uint8_t *src = (const uint8_t*)frame_; uint8_t *dst = thr->frame.buffer; slock_lock(thr->lock); // scond_wait_timeout cannot be implemented on consoles. #ifndef RARCH_CONSOLE if (!thr->nonblock) { retro_time_t target = thr->last_time + thr->target_frame_time; // Ideally, use absolute time, but that is only a good idea on POSIX. while (thr->frame.updated) { retro_time_t current = rarch_get_time_usec(); retro_time_t delta = target - current; if (delta <= 0) break; if (!scond_wait_timeout(thr->cond_cmd, thr->lock, delta)) break; } } #endif // Drop frame if updated flag is still set, as thread is still working on last frame. if (!thr->frame.updated) { if (src) { unsigned h; for (h = 0; h < height; h++, src += pitch, dst += copy_stride) memcpy(dst, src, copy_stride); } thr->frame.updated = true; thr->frame.width = width; thr->frame.height = height; thr->frame.pitch = copy_stride; if (msg) strlcpy(thr->frame.msg, msg, sizeof(thr->frame.msg)); else *thr->frame.msg = '\0'; scond_signal(thr->cond_thread); #if defined(HAVE_MENU) if (thr->texture.enable) { while (thr->frame.updated) scond_wait(thr->cond_cmd, thr->lock); } #endif thr->hit_count++; } else thr->miss_count++; slock_unlock(thr->lock); RARCH_PERFORMANCE_STOP(thread_frame); thr->last_time = rarch_get_time_usec(); return true; }
static void check_rewind(bool pressed) { static bool first = true; if (g_extern.frame_is_reverse) { /* We just rewound. Flush rewind audio buffer. */ retro_flush_audio(g_extern.audio_data.rewind_buf + g_extern.audio_data.rewind_ptr, g_extern.audio_data.rewind_size - g_extern.audio_data.rewind_ptr); g_extern.frame_is_reverse = false; } if (first) { first = false; return; } if (!g_extern.state_manager) return; if (pressed) { const void *buf = NULL; msg_queue_clear(g_extern.msg_queue); if (state_manager_pop(g_extern.state_manager, &buf)) { g_extern.frame_is_reverse = true; setup_rewind_audio(); msg_queue_push(g_extern.msg_queue, RETRO_MSG_REWINDING, 0, g_extern.is_paused ? 1 : 30); pretro_unserialize(buf, g_extern.state_size); if (g_extern.bsv.movie) bsv_movie_frame_rewind(g_extern.bsv.movie); } else msg_queue_push(g_extern.msg_queue, RETRO_MSG_REWIND_REACHED_END, 0, 30); } else { static unsigned cnt = 0; cnt = (cnt + 1) % (g_settings.rewind_granularity ? g_settings.rewind_granularity : 1); /* Avoid possible SIGFPE. */ if ((cnt == 0) || g_extern.bsv.movie) { void *state = NULL; state_manager_push_where(g_extern.state_manager, &state); RARCH_PERFORMANCE_INIT(rewind_serialize); RARCH_PERFORMANCE_START(rewind_serialize); pretro_serialize(state, g_extern.state_size); RARCH_PERFORMANCE_STOP(rewind_serialize); state_manager_push_do(g_extern.state_manager); } } retro_set_rewind_callbacks(); }
static void android_input_poll(void *data) { (void)data; RARCH_PERFORMANCE_INIT(input_poll); RARCH_PERFORMANCE_START(input_poll); bool debug_enable = g_settings.input.debug_enable; struct android_app* android_app = (struct android_app*)g_android; uint64_t *lifecycle_state = &g_extern.lifecycle_state; *lifecycle_state &= ~((1ULL << RARCH_RESET) | (1ULL << RARCH_REWIND) | (1ULL << RARCH_FAST_FORWARD_KEY) | (1ULL << RARCH_FAST_FORWARD_HOLD_KEY) | (1ULL << RARCH_MUTE) | (1ULL << RARCH_SAVE_STATE_KEY) | (1ULL << RARCH_LOAD_STATE_KEY) | (1ULL << RARCH_STATE_SLOT_PLUS) | (1ULL << RARCH_STATE_SLOT_MINUS)); // Read all pending events. while (AInputQueue_hasEvents(android_app->inputQueue) > 0) { AInputEvent* event = NULL; if (AInputQueue_getEvent(android_app->inputQueue, &event) < 0) break; bool long_msg_enable = false; int32_t handled = 1; int action = 0; char msg[128]; msg[0] = 0; int source = AInputEvent_getSource(event); int id = AInputEvent_getDeviceId(event); if (id == zeus_second_id) id = zeus_id; int keycode = AKeyEvent_getKeyCode(event); int type_event = AInputEvent_getType(event); int state_id = -1; if (source & (AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD)) state_id = 0; // touch overlay is always player 1 else { for (unsigned i = 0; i < pads_connected; i++) if (state_device_ids[i] == id) state_id = i; } if (state_id < 0) { state_id = pads_connected; state_device_ids[pads_connected++] = id; input_autodetect_setup(android_app, msg, sizeof(msg), state_id, id, source); long_msg_enable = true; } if (keycode == AKEYCODE_BACK ) { int meta = AKeyEvent_getMetaState(event); if (!(meta & AMETA_ALT_ON)) { *lifecycle_state |= (1ULL << RARCH_QUIT_KEY); AInputQueue_finishEvent(android_app->inputQueue, event, handled); break; } } if (type_event == AINPUT_EVENT_TYPE_MOTION) { float x = 0.0f; float y = 0.0f; action = AMotionEvent_getAction(event); size_t motion_pointer = action >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; action &= AMOTION_EVENT_ACTION_MASK; if (source & ~(AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_MOUSE)) { if (g_settings.input.dpad_emulation[state_id] != DPAD_EMULATION_NONE) { uint64_t *state_cur = &state[state_id]; x = AMotionEvent_getX(event, motion_pointer); y = AMotionEvent_getY(event, motion_pointer); *state_cur &= ~((1ULL << RETRO_DEVICE_ID_JOYPAD_LEFT) | (1ULL << RETRO_DEVICE_ID_JOYPAD_RIGHT) | (1ULL << RETRO_DEVICE_ID_JOYPAD_UP) | (1ULL << RETRO_DEVICE_ID_JOYPAD_DOWN)); *state_cur |= PRESSED_LEFT(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_LEFT) : 0; *state_cur |= PRESSED_RIGHT(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_RIGHT) : 0; *state_cur |= PRESSED_UP(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_UP) : 0; *state_cur |= PRESSED_DOWN(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_DOWN) : 0; } } else { bool keyup = (action == AMOTION_EVENT_ACTION_UP || action == AMOTION_EVENT_ACTION_CANCEL || action == AMOTION_EVENT_ACTION_POINTER_UP) || (source == AINPUT_SOURCE_MOUSE && action != AMOTION_EVENT_ACTION_DOWN); if (keyup && motion_pointer < MAX_TOUCH) { memmove(pointer + motion_pointer, pointer + motion_pointer + 1, (MAX_TOUCH - motion_pointer - 1) * sizeof(struct input_pointer)); if (pointer_count > 0) pointer_count--; } else { int pointer_max = min(AMotionEvent_getPointerCount(event), MAX_TOUCH); for (motion_pointer = 0; motion_pointer < pointer_max; motion_pointer++) { x = AMotionEvent_getX(event, motion_pointer); y = AMotionEvent_getY(event, motion_pointer); input_translate_coord_viewport(x, y, &pointer[motion_pointer].x, &pointer[motion_pointer].y, &pointer[motion_pointer].full_x, &pointer[motion_pointer].full_y); pointer_count = max(pointer_count, motion_pointer + 1); } } } if (debug_enable) snprintf(msg, sizeof(msg), "Pad %d : x = %.2f, y = %.2f, src %d.\n", state_id, x, y, source); } else if (type_event == AINPUT_EVENT_TYPE_KEY)
static bool ctr_frame(void* data, const void* frame, unsigned width, unsigned height, unsigned pitch, const char* msg) { ctr_video_t* ctr = (ctr_video_t*)data; settings_t* settings = config_get_ptr(); static uint64_t currentTick,lastTick; static float fps = 0.0; static int total_frames = 0; static int frames = 0; extern bool select_pressed; if (!width || !height) { gspWaitForEvent(GSPEVENT_VBlank0, true); return true; } if(!aptMainLoop()) { event_command(EVENT_CMD_QUIT); return true; } if (select_pressed) { event_command(EVENT_CMD_QUIT); return true; } svcWaitSynchronization(gspEvents[GSPEVENT_P3D], 20000000); svcClearEvent(gspEvents[GSPEVENT_P3D]); svcWaitSynchronization(gspEvents[GSPEVENT_PPF], 20000000); svcClearEvent(gspEvents[GSPEVENT_PPF]); gfxSwapBuffersGpu(); frames++; if (ctr->vsync) svcWaitSynchronization(gspEvents[GSPEVENT_VBlank0], U64_MAX); svcClearEvent(gspEvents[GSPEVENT_VBlank0]); currentTick = svcGetSystemTick(); uint32_t diff = currentTick - lastTick; if(diff > CTR_CPU_TICKS_PER_SECOND) { fps = (float)frames * ((float) CTR_CPU_TICKS_PER_SECOND / (float) diff); lastTick = currentTick; frames = 0; } printf("fps: %8.4f frames: %i\r", fps, total_frames++); fflush(stdout); RARCH_PERFORMANCE_INIT(ctrframe_f); RARCH_PERFORMANCE_START(ctrframe_f); ctrGuSetMemoryFill(true, (u32*)CTR_GPU_FRAMEBUFFER, 0x00000000, (u32*)(CTR_GPU_FRAMEBUFFER + CTR_TOP_FRAMEBUFFER_WIDTH * CTR_TOP_FRAMEBUFFER_HEIGHT * sizeof(uint32_t)), 0x201, (u32*)CTR_GPU_DEPTHBUFFER, 0x00000000, (u32*)(CTR_GPU_DEPTHBUFFER + CTR_TOP_FRAMEBUFFER_WIDTH * CTR_TOP_FRAMEBUFFER_HEIGHT * sizeof(uint32_t)), 0x201); GPUCMD_SetBufferOffset(0); if (width > ctr->texture_width) width = ctr->texture_width; if (height > ctr->texture_height) height = ctr->texture_height; if(frame) { if(((((u32)(frame)) >= 0x14000000 && ((u32)(frame)) < 0x1c000000)) /* frame in linear memory */ && !((u32)frame & 0x7F) /* 128-byte aligned */ && !((pitch) & 0xF)) /* 16-byte aligned */ { /* can copy the buffer directly with the GPU */ ctrGuCopyImage(false, frame, pitch / 2, height, CTRGU_RGB565, false, ctr->texture_swizzled, ctr->texture_width, CTRGU_RGB565, true); } else { int i; uint16_t* dst = (uint16_t*)ctr->texture_linear; const uint8_t* src = frame; for (i = 0; i < height; i++) { memcpy(dst, src, width * sizeof(uint16_t)); dst += ctr->texture_width; src += pitch; } GSPGPU_FlushDataCache(NULL, ctr->texture_linear, ctr->texture_width * ctr->texture_height * sizeof(uint16_t)); ctrGuCopyImage(false, ctr->texture_linear, ctr->texture_width, ctr->menu.texture_height, CTRGU_RGB565, false, ctr->texture_swizzled, ctr->texture_width, CTRGU_RGB565, true); } } ctrGuSetTexture(GPU_TEXUNIT0, VIRT_TO_PHYS(ctr->texture_swizzled), ctr->texture_width, ctr->texture_height, GPU_TEXTURE_MAG_FILTER(GPU_LINEAR) | GPU_TEXTURE_MIN_FILTER(GPU_LINEAR) | GPU_TEXTURE_WRAP_S(GPU_CLAMP_TO_EDGE) | GPU_TEXTURE_WRAP_T(GPU_CLAMP_TO_EDGE), GPU_RGB565); ctr->frame_coords->u = width; ctr->frame_coords->v = height; GSPGPU_FlushDataCache(NULL, (u8*)ctr->frame_coords, sizeof(ctr_vertex_t)); ctrGuSetAttributeBuffersAddress(VIRT_TO_PHYS(ctr->frame_coords)); ctrGuSetVertexShaderFloatUniform(0, (float*)&ctr->scale_vector, 1); GPU_DrawArray(GPU_UNKPRIM, 1); if (ctr->menu_texture_enable) { GSPGPU_FlushDataCache(NULL, ctr->menu.texture_linear, ctr->menu.texture_width * ctr->menu.texture_height * sizeof(uint16_t)); ctrGuCopyImage(false, ctr->menu.texture_linear, ctr->menu.texture_width, ctr->menu.texture_height, CTRGU_RGBA4444,false, ctr->menu.texture_swizzled, ctr->menu.texture_width, CTRGU_RGBA4444, true); ctrGuSetTexture(GPU_TEXUNIT0, VIRT_TO_PHYS(ctr->menu.texture_swizzled), ctr->menu.texture_width, ctr->menu.texture_height, GPU_TEXTURE_MAG_FILTER(GPU_LINEAR) | GPU_TEXTURE_MIN_FILTER(GPU_LINEAR) | GPU_TEXTURE_WRAP_S(GPU_CLAMP_TO_EDGE) | GPU_TEXTURE_WRAP_T(GPU_CLAMP_TO_EDGE), GPU_RGBA4); ctrGuSetAttributeBuffersAddress(VIRT_TO_PHYS(ctr->menu.frame_coords)); ctrGuSetVertexShaderFloatUniform(1, (float*)&ctr->menu.scale_vector, 1); GPU_DrawArray(GPU_UNKPRIM, 1); } GPU_FinishDrawing(); GPUCMD_Finalize(); ctrGuFlushAndRun(true); ctrGuDisplayTransfer(true, CTR_GPU_FRAMEBUFFER, 240,400, CTRGU_RGBA8, gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL), 240,400,CTRGU_RGB8, CTRGU_MULTISAMPLE_NONE); RARCH_PERFORMANCE_STOP(ctrframe_f); ctr->frame_count++; return true; }