static bool take_screenshot_viewport(const char *global_name_base) { char screenshot_path[PATH_MAX_LENGTH] = {0}; const char *screenshot_dir = NULL; uint8_t *buffer = NULL; bool retval = false; struct video_viewport vp = {0}; settings_t *settings = config_get_ptr(); video_driver_get_viewport_info(&vp); if (!vp.width || !vp.height) return false; buffer = (uint8_t*)malloc(vp.width * vp.height * 3); if (!buffer) return false; if (!video_driver_read_viewport(buffer)) goto done; screenshot_dir = settings->directory.screenshot; if (string_is_empty(screenshot_dir)) { fill_pathname_basedir(screenshot_path, global_name_base, sizeof(screenshot_path)); screenshot_dir = screenshot_path; } /* Data read from viewport is in bottom-up order, suitable for BMP. */ if (!screenshot_dump(global_name_base, screenshot_dir, buffer, vp.width, vp.height, vp.width * 3, true)) goto done; retval = true; done: if (buffer) free(buffer); return retval; }
static bool take_screenshot_viewport(const char *name_base, bool savestate, bool is_idle, bool is_paused) { struct video_viewport vp; uint8_t *buffer = NULL; bool retval = false; vp.x = 0; vp.y = 0; vp.width = 0; vp.height = 0; vp.full_width = 0; vp.full_height = 0; video_driver_get_viewport_info(&vp); if (!vp.width || !vp.height) return false; buffer = (uint8_t*)malloc(vp.width * vp.height * 3); if (!buffer) return false; if (!video_driver_read_viewport(buffer, is_idle)) goto error; /* Data read from viewport is in bottom-up order, suitable for BMP. */ if (!screenshot_dump(name_base, buffer, vp.width, vp.height, vp.width * 3, true, buffer, savestate, is_idle, is_paused)) goto error; return true; error: if (buffer) free(buffer); return retval; }
void recording_dump_frame(const void *data, unsigned width, unsigned height, size_t pitch) { struct ffemu_video_data ffemu_data = {0}; driver_t *driver = driver_get_ptr(); global_t *global = global_get_ptr(); if (!driver->recording_data) return; ffemu_data.pitch = pitch; ffemu_data.width = width; ffemu_data.height = height; ffemu_data.data = data; if (global->record.gpu_buffer) { struct video_viewport vp = {0}; video_driver_viewport_info(&vp); if (!vp.width || !vp.height) { RARCH_WARN("Viewport size calculation failed! Will continue using raw data. This will probably not work right ...\n"); event_command(EVENT_CMD_GPU_RECORD_DEINIT); recording_dump_frame(data, width, height, pitch); return; } /* User has resized. We kinda have a problem now. */ if (vp.width != global->record.gpu_width || vp.height != global->record.gpu_height) { static const char msg[] = "Recording terminated due to resize."; RARCH_WARN("%s\n", msg); rarch_main_msg_queue_push(msg, 1, 180, true); event_command(EVENT_CMD_RECORD_DEINIT); return; } /* Big bottleneck. * Since we might need to do read-backs asynchronously, * it might take 3-4 times before this returns true. */ if (!video_driver_read_viewport(global->record.gpu_buffer)) return; ffemu_data.pitch = global->record.gpu_width * 3; ffemu_data.width = global->record.gpu_width; ffemu_data.height = global->record.gpu_height; ffemu_data.data = global->record.gpu_buffer + (ffemu_data.height - 1) * ffemu_data.pitch; ffemu_data.pitch = -ffemu_data.pitch; } if (!global->record.gpu_buffer) ffemu_data.is_dupe = !data; if (driver->recording && driver->recording->push_video) driver->recording->push_video(driver->recording_data, &ffemu_data); }
void recording_dump_frame(const void *data, unsigned width, unsigned height, size_t pitch) { struct ffemu_video_data ffemu_data = {0}; driver_t *driver = driver_get_ptr(); global_t *global = global_get_ptr(); if (!driver->recording_data) return; ffemu_data.pitch = pitch; ffemu_data.width = width; ffemu_data.height = height; ffemu_data.data = data; if (global->record.gpu_buffer) { struct video_viewport vp = {0}; video_driver_viewport_info(&vp); if (!vp.width || !vp.height) { RARCH_WARN("%s \n", msg_hash_to_str(MSG_VIEWPORT_SIZE_CALCULATION_FAILED)); event_command(EVENT_CMD_GPU_RECORD_DEINIT); recording_dump_frame(data, width, height, pitch); return; } /* User has resized. We kinda have a problem now. */ if (vp.width != global->record.gpu_width || vp.height != global->record.gpu_height) { RARCH_WARN("%s\n", msg_hash_to_str(MSG_RECORDING_TERMINATED_DUE_TO_RESIZE)); rarch_main_msg_queue_push_new(MSG_RECORDING_TERMINATED_DUE_TO_RESIZE, 1, 180, true); event_command(EVENT_CMD_RECORD_DEINIT); return; } /* Big bottleneck. * Since we might need to do read-backs asynchronously, * it might take 3-4 times before this returns true. */ if (!video_driver_read_viewport(global->record.gpu_buffer)) return; ffemu_data.pitch = global->record.gpu_width * 3; ffemu_data.width = global->record.gpu_width; ffemu_data.height = global->record.gpu_height; ffemu_data.data = global->record.gpu_buffer + (ffemu_data.height - 1) * ffemu_data.pitch; ffemu_data.pitch = -ffemu_data.pitch; } if (!global->record.gpu_buffer) ffemu_data.is_dupe = !data; if (driver->recording && driver->recording->push_video) driver->recording->push_video(driver->recording_data, &ffemu_data); }
void recording_dump_frame(const void *data, unsigned width, unsigned height, size_t pitch, bool is_idle) { bool has_gpu_record = false; uint8_t *gpu_buf = NULL; struct ffemu_video_data ffemu_data = {0}; video_driver_get_record_status(&has_gpu_record, &gpu_buf); ffemu_data.pitch = (int)pitch; ffemu_data.width = width; ffemu_data.height = height; ffemu_data.data = data; if (has_gpu_record) { struct video_viewport vp; vp.x = 0; vp.y = 0; vp.width = 0; vp.height = 0; vp.full_width = 0; vp.full_height = 0; video_driver_get_viewport_info(&vp); if (!vp.width || !vp.height) { RARCH_WARN("%s \n", msg_hash_to_str(MSG_VIEWPORT_SIZE_CALCULATION_FAILED)); command_event(CMD_EVENT_GPU_RECORD_DEINIT, NULL); recording_dump_frame(data, width, height, pitch, is_idle); return; } /* User has resized. We kinda have a problem now. */ if ( vp.width != recording_gpu_width || vp.height != recording_gpu_height) { RARCH_WARN("%s\n", msg_hash_to_str(MSG_RECORDING_TERMINATED_DUE_TO_RESIZE)); runloop_msg_queue_push( msg_hash_to_str(MSG_RECORDING_TERMINATED_DUE_TO_RESIZE), 1, 180, true); command_event(CMD_EVENT_RECORD_DEINIT, NULL); return; } if (!gpu_buf) return; /* Big bottleneck. * Since we might need to do read-backs asynchronously, * it might take 3-4 times before this returns true. */ if (!video_driver_read_viewport(gpu_buf, is_idle)) return; ffemu_data.pitch = (int)(recording_gpu_width * 3); ffemu_data.width = (unsigned)recording_gpu_width; ffemu_data.height = (unsigned)recording_gpu_height; ffemu_data.data = gpu_buf + (ffemu_data.height - 1) * ffemu_data.pitch; ffemu_data.pitch = -ffemu_data.pitch; } if (!has_gpu_record) ffemu_data.is_dupe = !data; if (recording_driver && recording_driver->push_video) recording_driver->push_video(recording_data, &ffemu_data); }