Merge pull request #649 from libretro/cpu-filter

Revamped soft-filter API
This commit is contained in:
Twinaphex 2014-04-15 04:30:56 +02:00
commit aefb91e2aa
9 changed files with 496 additions and 107 deletions

View File

@ -299,6 +299,7 @@ endif
ifeq ($(HAVE_DYLIB), 1)
LIBS += $(DYLIB_LIB)
OBJ += gfx/filter.o
endif
ifeq ($(HAVE_FREETYPE), 1)

View File

@ -194,6 +194,7 @@ endif
ifeq ($(HAVE_DYLIB), 1)
DEFINES += -DHAVE_DYLIB
OBJ += gfx/filter.o
endif
ifeq ($(HAVE_STDIN_CMD), 1)

View File

@ -1284,28 +1284,15 @@ void uninit_audio(void)
#ifdef HAVE_DYLIB
void rarch_deinit_filter(void)
{
g_extern.filter.active = false;
if (g_extern.filter.lib)
dylib_close(g_extern.filter.lib);
g_extern.filter.lib = NULL;
rarch_softfilter_free(g_extern.filter.filter);
free(g_extern.filter.buffer);
free(g_extern.filter.colormap);
free(g_extern.filter.scaler_out);
g_extern.filter.buffer = NULL;
g_extern.filter.colormap = NULL;
g_extern.filter.scaler_out = NULL;
scaler_ctx_gen_reset(&g_extern.filter.scaler);
memset(&g_extern.filter.scaler, 0, sizeof(g_extern.filter.scaler));
memset(&g_extern.filter, 0, sizeof(g_extern.filter));
}
void rarch_init_filter(bool rgb32)
{
unsigned i;
if (g_extern.filter.active)
return;
rarch_deinit_filter();
if (!*g_settings.video.filter_path)
return;
@ -1315,14 +1302,6 @@ void rarch_init_filter(bool rgb32)
return;
}
RARCH_LOG("Loading bSNES filter from \"%s\"\n", g_settings.video.filter_path);
g_extern.filter.lib = dylib_load(g_settings.video.filter_path);
if (!g_extern.filter.lib)
{
RARCH_ERR("Failed to load filter \"%s\"\n", g_settings.video.filter_path);
return;
}
struct retro_game_geometry *geom = &g_extern.system.av_info.geometry;
unsigned width = geom->max_width;
unsigned height = geom->max_height;
@ -1330,66 +1309,37 @@ void rarch_init_filter(bool rgb32)
unsigned pow2_y = 0;
unsigned maxsize = 0;
g_extern.filter.psize =
(void (*)(unsigned*, unsigned*))dylib_proc(g_extern.filter.lib, "filter_size");
g_extern.filter.prender =
(void (*)(uint32_t*, uint32_t*,
unsigned, const uint16_t*,
unsigned, unsigned, unsigned))dylib_proc(g_extern.filter.lib, "filter_render");
RARCH_LOG("Loading softfilter from \"%s\"\n", g_settings.video.filter_path);
g_extern.filter.filter = rarch_softfilter_new(g_settings.video.filter_path,
RARCH_SOFTFILTER_THREADS_AUTO,
rgb32 ? RETRO_PIXEL_FORMAT_XRGB8888 : RETRO_PIXEL_FORMAT_RGB565,
width, height);
if (!g_extern.filter.psize || !g_extern.filter.prender)
if (!g_extern.filter.filter)
{
RARCH_ERR("Failed to find functions in filter...\n");
goto error;
RARCH_ERR("Failed to load filter \"%s\"\n", g_settings.video.filter_path);
return;
}
g_extern.filter.active = true;
g_extern.filter.psize(&width, &height);
pow2_x = next_pow2(width);
pow2_y = next_pow2(height);
maxsize = pow2_x > pow2_y ? pow2_x : pow2_y;
rarch_softfilter_get_max_output_size(g_extern.filter.filter, &pow2_x, &pow2_y);
pow2_x = next_pow2(pow2_x);
pow2_y = next_pow2(pow2_y);
maxsize = max(pow2_x, pow2_y);
g_extern.filter.scale = maxsize / RARCH_SCALE_BASE;
g_extern.filter.buffer = (uint32_t*)malloc(RARCH_SCALE_BASE * RARCH_SCALE_BASE *
g_extern.filter.scale * g_extern.filter.scale * sizeof(uint32_t));
g_extern.filter.out_rgb32 = rarch_softfilter_get_output_format(g_extern.filter.filter) == RETRO_PIXEL_FORMAT_XRGB8888;
g_extern.filter.out_bpp = g_extern.filter.out_rgb32 ? sizeof(uint32_t) : sizeof(uint16_t);
// TODO: Aligned output.
g_extern.filter.buffer = malloc(width * height * g_extern.filter.out_bpp);
if (!g_extern.filter.buffer)
goto error;
g_extern.filter.pitch = RARCH_SCALE_BASE * g_extern.filter.scale * sizeof(uint32_t);
g_extern.filter.colormap = (uint32_t*)malloc(0x10000 * sizeof(uint32_t));
if (!g_extern.filter.colormap)
goto error;
// Set up conversion map from 16-bit XRGB1555 to 32-bit ARGB.
for (i = 0; i < 0x10000; i++)
{
unsigned r = (i >> 10) & 0x1f;
unsigned g = (i >> 5) & 0x1f;
unsigned b = (i >> 0) & 0x1f;
r = (r << 3) | (r >> 2);
g = (g << 3) | (g >> 2);
b = (b << 3) | (b >> 2);
g_extern.filter.colormap[i] = (r << 16) | (g << 8) | (b << 0);
}
g_extern.filter.scaler_out = (uint16_t*)malloc(sizeof(uint16_t) * geom->max_width * geom->max_height);
if (!g_extern.filter.scaler_out)
goto error;
g_extern.filter.scaler.scaler_type = SCALER_TYPE_POINT;
g_extern.filter.scaler.in_fmt = rgb32 ? SCALER_FMT_ARGB8888 : SCALER_FMT_RGB565;
g_extern.filter.scaler.out_fmt = SCALER_FMT_0RGB1555;
if (!scaler_ctx_gen_filter(&g_extern.filter.scaler))
goto error;
return;
error:
RARCH_ERR("CPU filter init failed.\n");
RARCH_ERR("Softfilter init failed.\n");
rarch_deinit_filter();
}
#endif
@ -1467,7 +1417,7 @@ void init_video_input(void)
unsigned scale = next_pow2(max_dim) / RARCH_SCALE_BASE;
scale = max(scale, 1);
if (g_extern.filter.active)
if (g_extern.filter.filter)
scale = g_extern.filter.scale;
// Update core-dependent aspect ratio values.
@ -1532,7 +1482,7 @@ void init_video_input(void)
video.force_aspect = g_settings.video.force_aspect;
video.smooth = g_settings.video.smooth;
video.input_scale = scale;
video.rgb32 = g_extern.filter.active || (g_extern.system.pix_fmt == RETRO_PIXEL_FORMAT_XRGB8888);
video.rgb32 = g_extern.filter.filter ? g_extern.filter.out_rgb32 : (g_extern.system.pix_fmt == RETRO_PIXEL_FORMAT_XRGB8888);
const input_driver_t *tmp = driver.input;
find_video_driver(); // Need to grab the "real" video driver interface on a reinit.

View File

@ -34,6 +34,7 @@
#include "performance.h"
#include "core_options.h"
#include "miscellaneous.h"
#include "gfx/filter.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
@ -504,20 +505,12 @@ struct global
struct
{
bool active;
uint32_t *buffer;
uint32_t *colormap;
unsigned pitch;
dylib_t lib;
rarch_softfilter_t *filter;
void *buffer;
unsigned scale;
void (*psize)(unsigned *width, unsigned *height);
void (*prender)(uint32_t *colormap, uint32_t *output, unsigned outpitch,
const uint16_t *input, unsigned pitch, unsigned width, unsigned height);
// CPU filters only work on *XRGB1555*. We have to convert to XRGB1555 first.
struct scaler_ctx scaler;
uint16_t *scaler_out;
unsigned out_bpp;
bool out_rgb32;
} filter;
msg_queue_t *msg_queue;

277
gfx/filter.c Normal file
View File

@ -0,0 +1,277 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "filter.h"
#include "../dynamic.h"
#include "../general.h"
#include "../performance.h"
#include <stdlib.h>
#ifdef HAVE_CONFIG_H
#include "../config.h"
#endif
#ifdef HAVE_THREADS
#include "../thread.h"
struct filter_thread_data
{
sthread_t *thread;
const struct softfilter_work_packet *packet;
scond_t *cond;
slock_t *lock;
void *userdata;
bool die;
bool done;
};
static void filter_thread_loop(void *data)
{
struct filter_thread_data *thr = (struct filter_thread_data*)data;
for (;;)
{
slock_lock(thr->lock);
while (thr->done && !thr->die)
scond_wait(thr->cond, thr->lock);
bool die = thr->die;
slock_unlock(thr->lock);
if (die)
break;
thr->packet->work(thr->userdata, thr->packet->thread_data);
slock_lock(thr->lock);
thr->done = true;
scond_signal(thr->cond);
slock_unlock(thr->lock);
}
}
#endif
struct rarch_softfilter
{
dylib_t *lib;
const struct softfilter_implementation *impl;
void *impl_data;
unsigned max_width, max_height;
enum retro_pixel_format pix_fmt, out_pix_fmt;
struct softfilter_work_packet *packets;
unsigned threads;
#ifdef HAVE_THREADS
struct filter_thread_data *thread_data;
#endif
};
rarch_softfilter_t *rarch_softfilter_new(const char *filter_path,
unsigned threads,
enum retro_pixel_format in_pixel_format,
unsigned max_width, unsigned max_height)
{
unsigned i;
rarch_softfilter_t *filt = (rarch_softfilter_t*)calloc(1, sizeof(*filt));
if (!filt)
return NULL;
filt->lib = dylib_load(filter_path);
if (!filt->lib)
goto error;
softfilter_get_implementation_t cb = (softfilter_get_implementation_t)dylib_proc(filt->lib, "softfilter_get_implementation");
if (!cb)
{
RARCH_ERR("Couldn't find softfilter symbol.\n");
goto error;
}
unsigned cpu_features = rarch_get_cpu_features();
filt->impl = cb(cpu_features);
if (!filt->impl)
goto error;
RARCH_LOG("Loaded softfilter \"%s\".\n", filt->impl->ident);
if (filt->impl->api_version != SOFTFILTER_API_VERSION)
{
RARCH_ERR("Softfilter ABI mismatch.\n");
goto error;
}
// Simple assumptions.
filt->pix_fmt = in_pixel_format;
unsigned input_fmt = in_pixel_format == RETRO_PIXEL_FORMAT_XRGB8888 ?
SOFTFILTER_FMT_XRGB8888 : SOFTFILTER_FMT_RGB565;
unsigned input_fmts = filt->impl->query_input_formats();
if (!(input_fmt & input_fmts))
{
RARCH_ERR("Softfilter does not support input format.\n");
goto error;
}
unsigned output_fmts = filt->impl->query_output_formats(input_fmt);
if (output_fmts & input_fmt) // If we have a match of input/output formats, use that.
filt->out_pix_fmt = in_pixel_format;
else if (output_fmts & SOFTFILTER_FMT_XRGB8888)
filt->out_pix_fmt = RETRO_PIXEL_FORMAT_XRGB8888;
else if (output_fmts & SOFTFILTER_FMT_RGB565)
filt->out_pix_fmt = RETRO_PIXEL_FORMAT_RGB565;
else
{
RARCH_ERR("Did not find suitable output format for softfilter.\n");
goto error;
}
filt->max_width = max_width;
filt->max_height = max_height;
filt->impl_data = filt->impl->create(input_fmt, input_fmt, max_width, max_height,
threads != RARCH_SOFTFILTER_THREADS_AUTO ? threads : 1, cpu_features);
if (!filt->impl_data)
{
RARCH_ERR("Failed to create softfilter state.\n");
goto error;
}
threads = filt->impl->query_num_threads(filt->impl_data);
if (!threads)
{
RARCH_ERR("Invalid number of threads.\n");
goto error;
}
filt->packets = (struct softfilter_work_packet*)calloc(threads, sizeof(*filt->packets));
if (!filt->packets)
{
RARCH_ERR("Failed to allocate softfilter packets.\n");
goto error;
}
#ifdef HAVE_THREADS
filt->thread_data = (struct filter_thread_data*)calloc(threads, sizeof(*filt->thread_data));
if (!filt->thread_data)
goto error;
filt->threads = threads;
for (i = 0; i < threads; i++)
{
filt->thread_data[i].userdata = filt->impl_data;
filt->thread_data[i].done = true;
filt->thread_data[i].lock = slock_new();
if (!filt->thread_data[i].lock)
goto error;
filt->thread_data[i].cond = scond_new();
if (!filt->thread_data[i].cond)
goto error;
filt->thread_data[i].thread = sthread_create(filter_thread_loop, &filt->thread_data[i]);
if (!filt->thread_data[i].thread)
goto error;
}
#endif
return filt;
error:
rarch_softfilter_free(filt);
return NULL;
}
void rarch_softfilter_free(rarch_softfilter_t *filt)
{
unsigned i;
if (!filt)
return;
free(filt->packets);
if (filt->impl && filt->impl_data)
filt->impl->destroy(filt->impl_data);
if (filt->lib)
dylib_close(filt->lib);
#ifdef HAVE_THREADS
for (i = 0; i < filt->threads; i++)
{
if (!filt->thread_data[i].thread)
continue;
slock_lock(filt->thread_data[i].lock);
filt->thread_data[i].die = true;
scond_signal(filt->thread_data[i].cond);
slock_unlock(filt->thread_data[i].lock);
sthread_join(filt->thread_data[i].thread);
slock_free(filt->thread_data[i].lock);
scond_free(filt->thread_data[i].cond);
}
free(filt->thread_data);
#endif
free(filt);
}
void rarch_softfilter_get_max_output_size(rarch_softfilter_t *filt,
unsigned *width, unsigned *height)
{
rarch_softfilter_get_output_size(filt, width, height, filt->max_width, filt->max_height);
}
void rarch_softfilter_get_output_size(rarch_softfilter_t *filt,
unsigned *out_width, unsigned *out_height,
unsigned width, unsigned height)
{
filt->impl->query_output_size(filt->impl_data, out_width, out_height, width, height);
}
enum retro_pixel_format rarch_softfilter_get_output_format(rarch_softfilter_t *filt)
{
return filt->out_pix_fmt;
}
void rarch_softfilter_process(rarch_softfilter_t *filt,
void *output, size_t output_stride,
const void *input, unsigned width, unsigned height, size_t input_stride)
{
unsigned i;
filt->impl->get_work_packets(filt->impl_data, filt->packets,
output, output_stride, input, width, height, input_stride);
#ifdef HAVE_THREADS
// Fire off workers
for (i = 0; i < filt->threads; i++)
{
//RARCH_LOG("Firing off filter thread %u ...\n", i);
filt->thread_data[i].packet = &filt->packets[i];
slock_lock(filt->thread_data[i].lock);
filt->thread_data[i].done = false;
scond_signal(filt->thread_data[i].cond);
slock_unlock(filt->thread_data[i].lock);
}
// Wait for workers
for (i = 0; i < filt->threads; i++)
{
//RARCH_LOG("Waiting for filter thread %u ...\n", i);
slock_lock(filt->thread_data[i].lock);
while (!filt->thread_data[i].done)
scond_wait(filt->thread_data[i].cond, filt->thread_data[i].lock);
slock_unlock(filt->thread_data[i].lock);
}
#else
for (i = 0; i < filt->threads; i++)
filt->packets[i].work(filt->impl_data, filt->packets[i].thread_data);
#endif
}

48
gfx/filter.h Normal file
View File

@ -0,0 +1,48 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef RARCH_FILTER_H__
#define RARCH_FILTER_H__
#include "../libretro.h"
#include <stddef.h>
#include "softfilter.h"
#define RARCH_SOFTFILTER_THREADS_AUTO 0
typedef struct rarch_softfilter rarch_softfilter_t;
rarch_softfilter_t *rarch_softfilter_new(const char *filter_path,
unsigned threads,
enum retro_pixel_format in_pixel_format,
unsigned max_width, unsigned max_height);
void rarch_softfilter_free(rarch_softfilter_t *filt);
void rarch_softfilter_get_max_output_size(rarch_softfilter_t *filt,
unsigned *width, unsigned *height);
void rarch_softfilter_get_output_size(rarch_softfilter_t *filt,
unsigned *out_width, unsigned *out_height,
unsigned width, unsigned height);
enum retro_pixel_format rarch_softfilter_get_output_format(rarch_softfilter_t *filt);
void rarch_softfilter_process(rarch_softfilter_t *filt,
void *output, size_t output_stride,
const void *input, unsigned width, unsigned height, size_t input_stride);
#endif

119
gfx/softfilter.h Normal file
View File

@ -0,0 +1,119 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SOFTFILTER_API_H__
#define SOFTFILTER_API_H__
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
#define SOFTFILTER_SIMD_SSE (1 << 0)
#define SOFTFILTER_SIMD_SSE2 (1 << 1)
#define SOFTFILTER_SIMD_VMX (1 << 2)
#define SOFTFILTER_SIMD_VMX128 (1 << 3)
#define SOFTFILTER_SIMD_AVX (1 << 4)
#define SOFTFILTER_SIMD_NEON (1 << 5)
#define SOFTFILTER_SIMD_SSE3 (1 << 6)
#define SOFTFILTER_SIMD_SSSE3 (1 << 7)
#define SOFTFILTER_SIMD_MMX (1 << 8)
#define SOFTFILTER_SIMD_MMXEXT (1 << 9)
#define SOFTFILTER_SIMD_SSE4 (1 << 10)
#define SOFTFILTER_SIMD_SSE42 (1 << 11)
#define SOFTFILTER_SIMD_AVX2 (1 << 12)
#define SOFTFILTER_SIMD_VFPU (1 << 13)
#define SOFTFILTER_SIMD_PS (1 << 14)
// A bit-mask of all supported SIMD instruction sets.
// Allows an implementation to pick different softfilter_implementation structs.
typedef unsigned softfilter_simd_mask_t;
// Dynamic library entrypoint.
typedef const struct softfilter_implementation *(*softfilter_get_implementation_t)(softfilter_simd_mask_t);
// The same SIMD mask argument is forwarded to create() callback as well to avoid having to keep lots of state around.
const struct softfilter_implementation *softfilter_get_implementation(softfilter_simd_mask_t simd);
#define SOFTFILTER_API_VERSION 1
#define SOFTFILTER_FMT_NONE 0
#define SOFTFILTER_FMT_RGB565 (1 << 0)
#define SOFTFILTER_FMT_XRGB8888 (1 << 1)
// Softfilter implementation.
// Returns a bitmask of supported input formats.
typedef unsigned (*softfilter_query_input_formats_t)(void);
// Returns a bitmask of supported output formats for a given input format.
typedef unsigned (*softfilter_query_output_formats_t)(unsigned input_format);
// In softfilter_process_t, the softfilter implementation submits work units to a worker thread pool.
typedef void (*softfilter_work_t)(void *data, void *thread_data);
struct softfilter_work_packet
{
softfilter_work_t work;
void *thread_data;
};
// Create a filter with given input and output formats as well as maximum possible input size.
// Input sizes can very per call to softfilter_process_t, but they will never be larger than the maximum.
typedef void *(*softfilter_create_t)(unsigned in_fmt, unsigned out_fmt,
unsigned max_width, unsigned max_height,
unsigned threads, softfilter_simd_mask_t simd);
typedef void (*softfilter_destroy_t)(void *data);
// Given an input size, query the output size of the filter.
// If width and height == max_width/max_height, no other combination of width/height must return a larger size in any dimension.
typedef void (*softfilter_query_output_size_t)(void *data,
unsigned *out_width, unsigned *out_height,
unsigned width, unsigned height);
// First step of processing a frame. The filter submits work by filling in the packets array.
// The number of elements in the array is as returned by query_num_threads.
// The processing itself happens in worker threads after this returns.
typedef void (*softfilter_get_work_packets_t)(void *data,
struct softfilter_work_packet *packets,
void *output, size_t output_stride,
const void *input, unsigned width, unsigned height, size_t input_stride);
// Returns the number of worker threads the filter will use.
// This can differ from the value passed to create() instead the filter cannot be parallelized, etc. The number of threads must be less-or-equal compared to the value passed to create().
typedef unsigned (*softfilter_query_num_threads_t)(void *data);
/////
struct softfilter_implementation
{
softfilter_query_input_formats_t query_input_formats;
softfilter_query_output_formats_t query_output_formats;
softfilter_create_t create;
softfilter_destroy_t destroy;
softfilter_query_num_threads_t query_num_threads;
softfilter_query_output_size_t query_output_size;
softfilter_get_work_packets_t get_work_packets;
const char *ident; // Human readable identifier of implementation.
unsigned api_version; // Must be SOFTFILTER_API_VERSION
};
#ifdef __cplusplus
}
#endif
#endif

View File

@ -473,6 +473,9 @@ DYNAMIC
============================================================ */
#include "../dynamic.c"
#include "../dynamic_dummy.c"
#ifdef HAVE_DYLIB
#include "../gfx/filter.c"
#endif
/*============================================================
FILE

View File

@ -297,7 +297,7 @@ static void video_frame(const void *data, unsigned width, unsigned height, size_
// Slightly messy code,
// but we really need to do processing before blocking on VSync for best possible scheduling.
#ifdef HAVE_FFMPEG
if (g_extern.recording && (!g_extern.filter.active || !g_settings.video.post_filter_record || !data || g_extern.record_gpu_buffer))
if (g_extern.recording && (!g_extern.filter.filter || !g_settings.video.post_filter_record || !data || g_extern.record_gpu_buffer))
recording_dump_frame(data, width, height, pitch);
#endif
@ -305,28 +305,26 @@ static void video_frame(const void *data, unsigned width, unsigned height, size_
driver.current_msg = msg;
#ifdef HAVE_DYLIB
if (g_extern.filter.active && data)
if (g_extern.filter.filter && data)
{
struct scaler_ctx *scaler = &g_extern.filter.scaler;
scaler->in_width = scaler->out_width = width;
scaler->in_height = scaler->out_height = height;
scaler->in_stride = pitch;
scaler->out_stride = width * sizeof(uint16_t);
unsigned owidth = 0;
unsigned oheight = 0;
unsigned opitch = 0;
rarch_softfilter_get_output_size(g_extern.filter.filter,
&owidth, &oheight, width, height);
scaler_ctx_scale(scaler, g_extern.filter.scaler_out, data);
opitch = owidth * g_extern.filter.out_bpp;
unsigned owidth = width;
unsigned oheight = height;
g_extern.filter.psize(&owidth, &oheight);
g_extern.filter.prender(g_extern.filter.colormap, g_extern.filter.buffer,
g_extern.filter.pitch, g_extern.filter.scaler_out, scaler->out_stride, width, height);
rarch_softfilter_process(g_extern.filter.filter,
g_extern.filter.buffer, opitch,
data, width, height, pitch);
#ifdef HAVE_FFMPEG
if (g_extern.recording && g_settings.video.post_filter_record)
recording_dump_frame(g_extern.filter.buffer, owidth, oheight, g_extern.filter.pitch);
recording_dump_frame(g_extern.filter.buffer, owidth, oheight, opitch);
#endif
if (!video_frame_func(g_extern.filter.buffer, owidth, oheight, g_extern.filter.pitch, msg))
if (!video_frame_func(g_extern.filter.buffer, owidth, oheight, opitch, msg))
g_extern.video_active = false;
}
else if (!video_frame_func(data, width, height, pitch, msg))
@ -1381,14 +1379,13 @@ void rarch_init_recording(void)
else
params.aspect_ratio = (float)params.out_width / params.out_height;
if (g_settings.video.post_filter_record && g_extern.filter.active)
if (g_settings.video.post_filter_record && g_extern.filter.filter)
{
g_extern.filter.psize(&params.out_width, &params.out_height);
params.pix_fmt = FFEMU_PIX_ARGB8888;
params.pix_fmt = g_extern.filter.out_rgb32 ? FFEMU_PIX_ARGB8888 : FFEMU_PIX_RGB565;
unsigned max_width = params.fb_width;
unsigned max_height = params.fb_height;
g_extern.filter.psize(&max_width, &max_height);
unsigned max_width = 0;
unsigned max_height = 0;
rarch_softfilter_get_max_output_size(g_extern.filter.filter, &max_width, &max_height);
params.fb_width = next_pow2(max_width);
params.fb_height = next_pow2(max_height);
}