From e50414db74681a92b533d7cb48a122fb7a9cb9f1 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sun, 2 Oct 2016 22:41:37 -0400 Subject: [PATCH] make screenshots into a real task --- tasks/task_screenshot.c | 216 +++++++++++++++++++++++++--------------- 1 file changed, 136 insertions(+), 80 deletions(-) diff --git a/tasks/task_screenshot.c b/tasks/task_screenshot.c index 92725a53bd..461546584b 100644 --- a/tasks/task_screenshot.c +++ b/tasks/task_screenshot.c @@ -14,8 +14,6 @@ * If not, see . */ -/* TODO/FIXME - turn this into actual task */ - #ifdef HAVE_CONFIG_H #include "../config.h" #endif @@ -57,9 +55,106 @@ #include "../gfx/video_driver.h" #include "../gfx/video_frame.h" - #include "tasks_internal.h" +typedef struct { +#ifdef _XBOX1 + D3DSurface *surf; +#endif + char filename[PATH_MAX_LENGTH]; + char shotname[256]; +#ifdef HAVE_RPNG + uint8_t *out_buffer; + struct scaler_ctx scaler; +#endif + const void *frame; + unsigned width; + unsigned height; + int pitch; + bool bgr24; + void *userbuf; +} screenshot_task_state_t; + +/** + * task_screenshot_handler: + * @task : the task being worked on + * + * Saves a screenshot to disk. + **/ +static void task_screenshot_handler(retro_task_t *task) +{ + screenshot_task_state_t *state = (screenshot_task_state_t*)task->state; + char *msg = NULL; + bool is_paused = runloop_ctl(RUNLOOP_CTL_IS_PAUSED, NULL); + bool ret = false; + + if (task->progress == 100) + { + task->finished = true; + + if (state->userbuf) + free(state->userbuf); + + free(state); + return; + } + +#if defined(_XBOX1) + if (XGWriteSurfaceToFile(state->surf, state->filename) == S_OK) + ret = true; + state->surf->Release(); +#elif defined(HAVE_RPNG) + video_frame_convert_to_bgr24( + &state->scaler, + state->out_buffer, + (const uint8_t*)state->frame + ((int)state->height - 1) * state->pitch, + state->width, state->height, + -state->pitch, + state->bgr24); + + scaler_ctx_gen_reset(&state->scaler); + + ret = rpng_save_image_bgr24( + state->filename, + state->out_buffer, + state->width, + state->height, + state->width * 3 + ); + + free(state->out_buffer); +#elif defined(HAVE_RBMP) + enum rbmp_source_type bmp_type = RBMP_SOURCE_TYPE_DONT_CARE; + + if (state->bgr24) + bmp_type = RBMP_SOURCE_TYPE_BGR24; + else if (video_driver_get_pixel_format() == RETRO_PIXEL_FORMAT_XRGB8888) + bmp_type = RBMP_SOURCE_TYPE_XRGB888; + + ret = rbmp_save_image(state->filename, + state->frame, + state->width, + state->height, + state->pitch, + bmp_type); +#endif + +#ifdef HAVE_IMAGEVIEWER + if (ret) + if (content_push_to_history_playlist(g_defaults.image_history, state->filename, + "imageviewer", "builtin")) + playlist_write_file(g_defaults.image_history); +#endif + + task->progress = 100; + + if (!ret) + { + msg = strdup(msg_hash_to_str(MSG_FAILED_TO_TAKE_SCREENSHOT)); + runloop_msg_queue_push(msg, 1, is_paused ? 1 : 180, true); + } +} + /* Take frame bottom-up. */ static bool screenshot_dump( const char *name_base, @@ -67,85 +162,46 @@ static bool screenshot_dump( const void *frame, unsigned width, unsigned height, - int pitch, bool bgr24) + int pitch, bool bgr24, void *userbuf) { - char filename[PATH_MAX_LENGTH] = {0}; - char shotname[256] = {0}; - bool ret = false; settings_t *settings = config_get_ptr(); -#if defined(HAVE_RPNG) - uint8_t *out_buffer = NULL; - struct scaler_ctx scaler = {0}; -#endif + retro_task_t *task = (retro_task_t*)calloc(1, sizeof(*task)); + screenshot_task_state_t *state = (screenshot_task_state_t*) + calloc(1, sizeof(*state)); + + state->bgr24 = bgr24; + state->height = height; + state->width = width; + state->pitch = pitch; + state->frame = frame; + state->userbuf = userbuf; if (settings->auto_screenshot_filename) - { - fill_str_dated_filename(shotname, path_basename(name_base), - IMG_EXT, sizeof(shotname)); - } + fill_str_dated_filename(state->shotname, path_basename(name_base), + IMG_EXT, sizeof(state->shotname)); else - { - snprintf(shotname, sizeof(shotname),"%s.png", path_basename(name_base)); - } - fill_pathname_join(filename, folder, shotname, sizeof(filename)); + snprintf(state->shotname, sizeof(state->shotname), "%s.png", path_basename(name_base)); + + fill_pathname_join(state->filename, folder, state->shotname, sizeof(state->filename)); #ifdef _XBOX1 d3d_video_t *d3d = (d3d_video_t*)video_driver_get_ptr(true); - D3DSurface *surf = NULL; - d3d->dev->GetBackBuffer(-1, D3DBACKBUFFER_TYPE_MONO, &surf); - if (XGWriteSurfaceToFile(surf, filename) == S_OK) - ret = true; - surf->Release(); + d3d->dev->GetBackBuffer(-1, D3DBACKBUFFER_TYPE_MONO, &state->surf); + #elif defined(HAVE_RPNG) - out_buffer = (uint8_t*)malloc(width * height * 3); - if (!out_buffer) + state->out_buffer = (uint8_t*)malloc(width * height * 3); + if (!state->out_buffer) return false; - - video_frame_convert_to_bgr24( - &scaler, - out_buffer, - (const uint8_t*)frame + ((int)height - 1) * pitch, - width, height, - -pitch, - bgr24); - - scaler_ctx_gen_reset(&scaler); - - ret = rpng_save_image_bgr24( - filename, - out_buffer, - width, - height, - width * 3 - ); - free(out_buffer); -#elif defined(HAVE_RBMP) - enum rbmp_source_type bmp_type = RBMP_SOURCE_TYPE_DONT_CARE; - - if (bgr24) - bmp_type = RBMP_SOURCE_TYPE_BGR24; - else if (video_driver_get_pixel_format() == RETRO_PIXEL_FORMAT_XRGB8888) - bmp_type = RBMP_SOURCE_TYPE_XRGB888; - - ret = rbmp_save_image(filename, - frame, - width, - height, - pitch, - bmp_type); #endif -#ifdef HAVE_IMAGEVIEWER - if (ret == true) - { - if (content_push_to_history_playlist(g_defaults.image_history, filename, - "imageviewer", "builtin")) - playlist_write_file(g_defaults.image_history); - } -#endif + task->type = TASK_TYPE_BLOCKING; + task->state = state; + task->handler = task_screenshot_handler; + task->title = strdup(msg_hash_to_str(MSG_TAKING_SCREENSHOT)); + task_queue_ctl(TASK_QUEUE_CTL_PUSH, task); - return ret; + return true; } #if !defined(VITA) @@ -164,11 +220,12 @@ static bool take_screenshot_viewport(const char *name_base) return false; buffer = (uint8_t*)malloc(vp.width * vp.height * 3); + if (!buffer) return false; if (!video_driver_read_viewport(buffer)) - goto done; + goto error; screenshot_dir = settings->directory.screenshot; @@ -181,19 +238,19 @@ static bool take_screenshot_viewport(const char *name_base) /* Data read from viewport is in bottom-up order, suitable for BMP. */ if (!screenshot_dump(name_base, screenshot_dir, buffer, vp.width, vp.height, - vp.width * 3, true)) - goto done; + vp.width * 3, true, buffer)) + goto error; - retval = true; + return true; -done: +error: if (buffer) free(buffer); return retval; } #endif -static bool take_screenshot_raw(const char *name_base) +static bool take_screenshot_raw(const char *name_base, void *userbuf) { unsigned width, height; size_t pitch; @@ -216,7 +273,7 @@ static bool take_screenshot_raw(const char *name_base) */ if (!screenshot_dump(name_base, screenshot_dir, (const uint8_t*)data + (height - 1) * pitch, - width, height, -pitch, false)) + width, height, -pitch, false, userbuf)) return false; return true; @@ -236,14 +293,14 @@ static bool take_screenshot_choice(const char *name_base) video_driver_set_texture_enable(false, false); video_driver_cached_frame_render(); #if defined(VITA) - return take_screenshot_raw(name_base); + return take_screenshot_raw(name_base, NULL); #else return take_screenshot_viewport(name_base); #endif } if (!video_driver_cached_frame_has_valid_framebuffer()) - return take_screenshot_raw(name_base); + return take_screenshot_raw(name_base, NULL); if (video_driver_supports_read_frame_raw()) { @@ -265,9 +322,8 @@ static bool take_screenshot_choice(const char *name_base) if (frame_data) { video_driver_set_cached_frame_ptr(frame_data); - if (take_screenshot_raw(name_base)) + if (take_screenshot_raw(name_base, frame_data)) ret = true; - free(frame_data); } return ret; @@ -286,7 +342,7 @@ bool take_screenshot(void) char *name_base = strdup(path_get(RARCH_PATH_BASENAME)); bool is_paused = runloop_ctl(RUNLOOP_CTL_IS_PAUSED, NULL); bool ret = take_screenshot_choice(name_base); - const char *msg_screenshot = ret + const char *msg_screenshot = ret ? msg_hash_to_str(MSG_TAKING_SCREENSHOT) : msg_hash_to_str(MSG_FAILED_TO_TAKE_SCREENSHOT); const char *msg = msg_screenshot;