bool video_driver_frame_filter(const void *data, unsigned width, unsigned height, size_t pitch, unsigned *output_width, unsigned *output_height, unsigned *output_pitch) { settings_t *settings = config_get_ptr(); RARCH_PERFORMANCE_INIT(softfilter_process); if (!video_state.filter.filter) return false; if (!data) return false; rarch_softfilter_get_output_size(video_state.filter.filter, output_width, output_height, width, height); *output_pitch = (*output_width) * video_state.filter.out_bpp; RARCH_PERFORMANCE_START(softfilter_process); rarch_softfilter_process(video_state.filter.filter, video_state.filter.buffer, *output_pitch, data, width, height, pitch); RARCH_PERFORMANCE_STOP(softfilter_process); if (settings->video.post_filter_record) recording_dump_frame(video_state.filter.buffer, *output_width, *output_height, *output_pitch); return true; }
bool video_driver_frame_filter(const void *data, unsigned width, unsigned height, size_t pitch, unsigned *output_width, unsigned *output_height, unsigned *output_pitch) { static struct retro_perf_counter softfilter_process = {0}; settings_t *settings = config_get_ptr(); rarch_perf_init(&softfilter_process, "softfilter_process"); if (!video_state.filter.filter) return false; if (!data) return false; rarch_softfilter_get_output_size(video_state.filter.filter, output_width, output_height, width, height); *output_pitch = (*output_width) * video_state.filter.out_bpp; retro_perf_start(&softfilter_process); rarch_softfilter_process(video_state.filter.filter, video_state.filter.buffer, *output_pitch, data, width, height, pitch); retro_perf_stop(&softfilter_process); if (settings->video.post_filter_record) recording_dump_frame(video_state.filter.buffer, *output_width, *output_height, *output_pitch); return true; }
/** * video_frame: * @data : pointer to data of the video frame. * @width : width of the video frame. * @height : height of the video frame. * @pitch : pitch of the video frame. * * Video frame render callback function. **/ static void video_frame(const void *data, unsigned width, unsigned height, size_t pitch) { unsigned output_width = 0; unsigned output_height = 0; unsigned output_pitch = 0; const char *msg = NULL; driver_t *driver = driver_get_ptr(); global_t *global = global_get_ptr(); settings_t *settings = config_get_ptr(); const video_driver_t *video = driver ? (const video_driver_t*)driver->video : NULL; if (!driver->video_active) return; if (video_pixel_frame_scale(data, width, height, pitch)) { video_pixel_scaler_t *scaler = scaler_get_ptr(); data = scaler->scaler_out; pitch = scaler->scaler->out_stride; } video_driver_cached_frame_set(data, width, height, pitch); /* Slightly messy code, * but we really need to do processing before blocking on VSync * for best possible scheduling. */ if ((!video_driver_frame_filter_alive() || !settings->video.post_filter_record || !data || global->record.gpu_buffer) ) recording_dump_frame(data, width, height, pitch); msg = rarch_main_msg_queue_pull(); *driver->current_msg = 0; if (msg) strlcpy(driver->current_msg, msg, sizeof(driver->current_msg)); if (video_driver_frame_filter(data, width, height, pitch, &output_width, &output_height, &output_pitch)) { data = video_driver_frame_filter_get_buf_ptr(); width = output_width; height = output_height; pitch = output_pitch; } if (!video->frame(driver->video_data, data, width, height, pitch, driver->current_msg)) driver->video_active = false; }
void recording_dump_frame(const void *data, unsigned width, unsigned height, size_t pitch) { struct ffemu_video_data ffemu_data = {0}; global_t *global = global_get_ptr(); if (!recording_data) return; ffemu_data.pitch = pitch; ffemu_data.width = width; ffemu_data.height = height; ffemu_data.data = data; if (video_driver_ctl(RARCH_DISPLAY_CTL_HAS_GPU_RECORD, NULL)) { uint8_t *gpu_buf = NULL; 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)); runloop_msg_queue_push_new(MSG_RECORDING_TERMINATED_DUE_TO_RESIZE, 1, 180, true); event_command(EVENT_CMD_RECORD_DEINIT); return; } if (!video_driver_ctl(RARCH_DISPLAY_CTL_GPU_RECORD_GET, &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_ctl(RARCH_DISPLAY_CTL_READ_VIEWPORT, gpu_buf)) 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 = gpu_buf + (ffemu_data.height - 1) * ffemu_data.pitch; ffemu_data.pitch = -ffemu_data.pitch; } if (!video_driver_ctl(RARCH_DISPLAY_CTL_HAS_GPU_RECORD, NULL)) ffemu_data.is_dupe = !data; if (recording_driver && recording_driver->push_video) recording_driver->push_video(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("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, 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); }