mirror of
https://github.com/libretro/RetroArch
synced 2025-03-30 16:20:27 +00:00
Merge pull request #139 from Themaister/thread_video
Threaded video driver
This commit is contained in:
commit
bd4d97337c
3
Makefile
3
Makefile
@ -77,9 +77,8 @@ ifneq ($(findstring Linux,$(OS)),)
|
||||
JOYCONFIG_OBJ += input/linuxraw_joypad.o
|
||||
endif
|
||||
|
||||
OBJ += autosave.o thread.o
|
||||
|
||||
ifeq ($(HAVE_THREADS), 1)
|
||||
OBJ += autosave.o thread.o gfx/thread_wrapper.o
|
||||
ifeq ($(findstring Haiku,$(OS)),)
|
||||
LIBS += -lpthread
|
||||
endif
|
||||
|
@ -99,7 +99,7 @@ ifeq ($(HAVE_SDL), 1)
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_THREADS), 1)
|
||||
OBJ += autosave.o thread.o
|
||||
OBJ += autosave.o thread.o gfx/thread_wrapper.o
|
||||
DEFINES += -DHAVE_THREADS
|
||||
endif
|
||||
|
||||
|
@ -6,7 +6,6 @@ HAVE_SINC := 1
|
||||
HAVE_LOGGER := 1
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
ifeq ($(TARGET_ARCH),arm)
|
||||
LOCAL_CFLAGS += -DANDROID_ARM -marm
|
||||
LOCAL_ARM_MODE := arm
|
||||
@ -52,7 +51,7 @@ ifeq ($(PERF_TEST), 1)
|
||||
LOCAL_CFLAGS += -DPERF_TEST
|
||||
endif
|
||||
|
||||
LOCAL_CFLAGS += -Wall -Wno-unused-function -O3 -fno-stack-protector -funroll-loops -DNDEBUG -DHAVE_GRIFFIN -DANDROID -DHAVE_DYNAMIC -DHAVE_OPENGL -DHAVE_FBO -DHAVE_OVERLAY -DHAVE_OPENGLES -DHAVE_VID_CONTEXT -DHAVE_OPENGLES2 -DGLSL_DEBUG -DHAVE_GLSL -DWANT_MINIZ -DHAVE_ZLIB -DINLINE=inline -DLSB_FIRST -DHAVE_THREADS -D__LIBRETRO__ -DRARCH_PERFORMANCE_MODE -DPACKAGE_VERSION=\"$(RARCH_VERSION)\" -std=gnu99 -I../../../deps/miniz
|
||||
LOCAL_CFLAGS += -Wall -pthread -Wno-unused-function -O3 -fno-stack-protector -funroll-loops -DNDEBUG -DHAVE_GRIFFIN -DANDROID -DHAVE_DYNAMIC -DHAVE_OPENGL -DHAVE_FBO -DHAVE_OVERLAY -DHAVE_OPENGLES -DHAVE_VID_CONTEXT -DHAVE_OPENGLES2 -DGLSL_DEBUG -DHAVE_GLSL -DWANT_MINIZ -DHAVE_ZLIB -DINLINE=inline -DLSB_FIRST -DHAVE_THREADS -D__LIBRETRO__ -DRARCH_PERFORMANCE_MODE -DPACKAGE_VERSION=\"$(RARCH_VERSION)\" -std=gnu99 -I../../../deps/miniz
|
||||
|
||||
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -landroid -lEGL -lGLESv2 $(LOGGER_LDLIBS) -ldl
|
||||
|
||||
|
@ -86,12 +86,16 @@
|
||||
android:title="Aspect ratio" />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="Synchronization" >
|
||||
<CheckBoxPreference
|
||||
android:defaultValue="false"
|
||||
android:key="video_threaded"
|
||||
android:summary="Uses a multi-threaded video driver. Is likely to improve performance at the expense of slightly more latency and jitter. Use this if you have troubles getting good video and audio."
|
||||
android:title="Threaded video driver" />
|
||||
<EditTextPreference
|
||||
android:key="video_refresh_rate"
|
||||
android:numeric="decimal"
|
||||
android:summary="Force a specific refresh rate to be detected. Only set manually if calibration reports wrong refresh rate."
|
||||
android:title="Forced refresh rate (Hz)" />
|
||||
|
||||
<Preference
|
||||
android:summary="Attempts to find the true refresh rate of monitor. Updates value in 'Force refresh rate (Hz)' option. To help ensure accuracy, make sure no intense background services are running, and avoid triggering screensaver."
|
||||
android:title="Calibrate refresh rate" >
|
||||
|
@ -299,7 +299,7 @@ public class RetroArch extends Activity implements
|
||||
prefs.edit().putBoolean("first_time_refreshrate_calculate", true).commit();
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(this)
|
||||
.setTitle("Calculate Refresh Rate")
|
||||
.setMessage("It is highly recommended you run the refresh rate calibration test before you use RetroArch. Do you want to run it now?\n\nIf you choose No, you can run it at any time in the video preferences.")
|
||||
.setMessage("It is highly recommended you run the refresh rate calibration test before you use RetroArch. Do you want to run it now?\n\nIf you choose No, you can run it at any time in the video preferences.\n\nIf you get performance problems even after calibration, please try threaded video driver in video preferences.")
|
||||
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
@ -371,6 +371,7 @@ public class RetroArch extends Activity implements
|
||||
config.setInt("input_autodetect_icade_profile_pad4", prefs.getInt("input_autodetect_icade_profile_pad4", 0));
|
||||
|
||||
config.setDouble("video_refresh_rate", getRefreshRate());
|
||||
config.setBoolean("video_threaded", prefs.getBoolean("video_threaded", false));
|
||||
|
||||
String aspect = prefs.getString("video_aspect_ratio", "auto");
|
||||
if (aspect.equals("full")) {
|
||||
|
@ -31,12 +31,10 @@
|
||||
#define M_PI 3.14159265358979323846264338327
|
||||
#endif
|
||||
|
||||
typedef float sample_t;
|
||||
|
||||
struct resampler_data
|
||||
{
|
||||
const sample_t *data_in;
|
||||
sample_t *data_out;
|
||||
const float *data_in;
|
||||
float *data_out;
|
||||
|
||||
size_t input_frames;
|
||||
size_t output_frames;
|
||||
|
14
audio/sinc.c
14
audio/sinc.c
@ -105,9 +105,9 @@
|
||||
|
||||
typedef struct rarch_sinc_resampler
|
||||
{
|
||||
sample_t *phase_table;
|
||||
sample_t *buffer_l;
|
||||
sample_t *buffer_r;
|
||||
float *phase_table;
|
||||
float *buffer_l;
|
||||
float *buffer_r;
|
||||
|
||||
unsigned taps;
|
||||
|
||||
@ -116,7 +116,7 @@ typedef struct rarch_sinc_resampler
|
||||
|
||||
// A buffer for phase_table, buffer_l and buffer_r are created in a single calloc().
|
||||
// Ensure that we get as good cache locality as we can hope for.
|
||||
sample_t *main_buffer;
|
||||
float *main_buffer;
|
||||
} rarch_sinc_resampler_t;
|
||||
|
||||
static inline double sinc(double val)
|
||||
@ -405,8 +405,8 @@ static void resampler_sinc_process(void *re_, struct resampler_data *data)
|
||||
|
||||
uint32_t ratio = PHASES / data->ratio;
|
||||
|
||||
const sample_t *input = data->data_in;
|
||||
sample_t *output = data->data_out;
|
||||
const float *input = data->data_in;
|
||||
float *output = data->data_out;
|
||||
size_t frames = data->input_frames;
|
||||
size_t out_frames = 0;
|
||||
|
||||
@ -477,7 +477,7 @@ static void *resampler_sinc_new(double bandwidth_mod)
|
||||
#endif
|
||||
size_t elems = phase_elems + 4 * re->taps;
|
||||
|
||||
re->main_buffer = (sample_t*)aligned_alloc__(128, sizeof(sample_t) * elems);
|
||||
re->main_buffer = (float*)aligned_alloc__(128, sizeof(float) * elems);
|
||||
if (!re->main_buffer)
|
||||
goto error;
|
||||
|
||||
|
@ -218,6 +218,9 @@ static const bool disable_composition = false;
|
||||
// Video VSYNC (recommended)
|
||||
static const bool vsync = true;
|
||||
|
||||
// Threaded video. Will possibly increase performance significantly at cost of worse synchronization and latency.
|
||||
static const bool video_threaded = false;
|
||||
|
||||
// Smooths picture
|
||||
static const bool video_smooth = true;
|
||||
|
||||
|
@ -393,11 +393,13 @@ THREAD
|
||||
#include "../../thread/xenon_sdl_threads.c"
|
||||
#elif defined(HAVE_THREADS)
|
||||
#include "../../thread.c"
|
||||
#include "../../gfx/thread_wrapper.c"
|
||||
#ifndef RARCH_CONSOLE
|
||||
#include "../../autosave.c"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/*============================================================
|
||||
NETPLAY
|
||||
============================================================ */
|
||||
|
26
driver.c
26
driver.c
@ -23,6 +23,7 @@
|
||||
#include "compat/posix_string.h"
|
||||
#include "audio/utils.h"
|
||||
#include "audio/resampler.h"
|
||||
#include "gfx/thread_wrapper.h"
|
||||
|
||||
#ifdef HAVE_X11
|
||||
#include "gfx/context/x11_common.h"
|
||||
@ -423,7 +424,7 @@ void init_audio(void)
|
||||
g_extern.audio_data.data_ptr = 0;
|
||||
|
||||
rarch_assert(g_settings.audio.out_rate < g_settings.audio.in_rate * AUDIO_MAX_RATIO);
|
||||
rarch_assert(g_extern.audio_data.outsamples = (sample_t*)malloc(outsamples_max * sizeof(sample_t)));
|
||||
rarch_assert(g_extern.audio_data.outsamples = (float*)malloc(outsamples_max * sizeof(float)));
|
||||
|
||||
if (g_extern.audio_active && g_settings.audio.rate_control)
|
||||
{
|
||||
@ -492,6 +493,12 @@ static void compute_audio_buffer_statistics(void)
|
||||
|
||||
static void compute_monitor_fps_statistics(void)
|
||||
{
|
||||
if (g_settings.video.threaded)
|
||||
{
|
||||
RARCH_LOG("Monitor FPS estimation is disabled for threaded video.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_extern.measure_data.frame_time_samples_count < 2 * MEASURE_FRAME_TIME_SAMPLES_COUNT)
|
||||
{
|
||||
RARCH_LOG("Does not have enough samples for monitor refresh rate estimation. Requires to run for at least %u frames.\n",
|
||||
@ -800,7 +807,22 @@ void init_video_input(void)
|
||||
video.rgb32 = g_extern.filter.active || (g_extern.system.pix_fmt == RETRO_PIXEL_FORMAT_XRGB8888);
|
||||
|
||||
const input_driver_t *tmp = driver.input;
|
||||
driver.video_data = video_init_func(&video, &driver.input, &driver.input_data);
|
||||
#ifdef HAVE_THREADS
|
||||
if (g_settings.video.threaded)
|
||||
{
|
||||
find_video_driver(); // Need to grab the "real" video driver interface on a reinit.
|
||||
RARCH_LOG("Starting threaded video driver ...\n");
|
||||
if (!rarch_threaded_video_init(&driver.video, &driver.video_data,
|
||||
&driver.input, &driver.input_data,
|
||||
driver.video, &video))
|
||||
{
|
||||
RARCH_ERR("Cannot open threaded video driver ... Exiting ...\n");
|
||||
rarch_fail(1, "init_video_input()");
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
driver.video_data = video_init_func(&video, &driver.input, &driver.input_data);
|
||||
|
||||
if (driver.video_data == NULL)
|
||||
{
|
||||
|
2
driver.h
2
driver.h
@ -280,6 +280,8 @@ typedef struct driver
|
||||
void *video_data;
|
||||
void *input_data;
|
||||
|
||||
bool threaded_video;
|
||||
|
||||
// Set if the respective handles are owned by RetroArch driver core.
|
||||
// Consoles upper logic will generally intialize the drivers before
|
||||
// the driver core initializes. It will then be up to upper logic
|
||||
|
@ -18,7 +18,7 @@
|
||||
#ifndef _RARCH_DRIVER_FUNCS_H
|
||||
#define _RARCH_DRIVER_FUNCS_H
|
||||
|
||||
#if !defined(HAVE_GRIFFIN) /* Normal */
|
||||
#if !defined(HAVE_GRIFFIN) || defined(ANDROID) /* Normal */
|
||||
|
||||
#define audio_init_func(device, rate, latency) driver.audio->init(device, rate, latency)
|
||||
#define audio_write_func(buf, size) driver.audio->write(driver.audio_data, buf, size)
|
||||
|
@ -175,6 +175,7 @@ struct settings
|
||||
char filter_path[PATH_MAX];
|
||||
enum rarch_shader_type shader_type;
|
||||
float refresh_rate;
|
||||
bool threaded;
|
||||
|
||||
bool render_to_texture;
|
||||
|
||||
@ -398,7 +399,7 @@ struct global
|
||||
bool use_float;
|
||||
bool mute;
|
||||
|
||||
sample_t *outsamples;
|
||||
float *outsamples;
|
||||
int16_t *conv_outsamples;
|
||||
|
||||
int16_t *rewind_buf;
|
||||
|
@ -15,10 +15,12 @@
|
||||
*/
|
||||
|
||||
#include "../../driver.h"
|
||||
#include "../../general.h"
|
||||
#include "../gfx_common.h"
|
||||
#include "../gl_common.h"
|
||||
|
||||
#include <EGL/egl.h> /* Requires NDK r5 or newer */
|
||||
#include <android/looper.h>
|
||||
|
||||
#include "../../frontend/frontend_android.h"
|
||||
#include "../image.h"
|
||||
@ -148,6 +150,10 @@ static bool gfx_ctx_init(void)
|
||||
goto error;
|
||||
}
|
||||
|
||||
ALooper *looper = ALooper_forThread();
|
||||
if (!looper)
|
||||
ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
|
||||
|
||||
return true;
|
||||
|
||||
error:
|
||||
|
@ -1166,9 +1166,12 @@ static void *d3d9_init(const video_info_t *info, const input_driver_t **input,
|
||||
if (!vid)
|
||||
return nullptr;
|
||||
|
||||
void *dinput = input_dinput.init();
|
||||
*input = dinput ? &input_dinput : nullptr;
|
||||
*input_data = dinput;
|
||||
if (input && input_data)
|
||||
{
|
||||
void *dinput = input_dinput.init();
|
||||
*input = dinput ? &input_dinput : nullptr;
|
||||
*input_data = dinput;
|
||||
}
|
||||
|
||||
return vid;
|
||||
}
|
||||
|
3
gfx/gl.c
3
gfx/gl.c
@ -1717,7 +1717,8 @@ static void *gl_init(const video_info_t *video, const input_driver_t **input, vo
|
||||
gl_init_textures(gl, video);
|
||||
gl_init_textures_data(gl);
|
||||
|
||||
context_input_driver_func(input, input_data);
|
||||
if (input && input_data)
|
||||
context_input_driver_func(input, input_data);
|
||||
|
||||
#ifndef HAVE_RMENU
|
||||
// Comes too early for console - moved to gl_start
|
||||
|
@ -231,16 +231,19 @@ static void *sdl_gfx_init(const video_info_t *video, const input_driver_t **inpu
|
||||
|
||||
sdl_gfx_set_handles();
|
||||
|
||||
sdl_input = input_sdl.init();
|
||||
if (sdl_input)
|
||||
if (input && input_data)
|
||||
{
|
||||
*input = &input_sdl;
|
||||
*input_data = sdl_input;
|
||||
}
|
||||
else
|
||||
{
|
||||
*input = NULL;
|
||||
*input_data = NULL;
|
||||
sdl_input = input_sdl.init();
|
||||
if (sdl_input)
|
||||
{
|
||||
*input = &input_sdl;
|
||||
*input_data = sdl_input;
|
||||
}
|
||||
else
|
||||
{
|
||||
*input = NULL;
|
||||
*input_data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
sdl_init_font(vid, g_settings.video.font_path, g_settings.video.font_size);
|
||||
|
587
gfx/thread_wrapper.c
Normal file
587
gfx/thread_wrapper.c
Normal file
@ -0,0 +1,587 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2010-2013 - 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 "thread_wrapper.h"
|
||||
#include "../thread.h"
|
||||
#include "../general.h"
|
||||
#include "../performance.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
enum thread_cmd
|
||||
{
|
||||
CMD_NONE = 0,
|
||||
CMD_INIT,
|
||||
CMD_SET_SHADER,
|
||||
CMD_FREE,
|
||||
CMD_ALIVE, // Blocking alive check. Used when paused.
|
||||
CMD_SET_ROTATION,
|
||||
CMD_READ_VIEWPORT,
|
||||
CMD_SET_NONBLOCK,
|
||||
|
||||
#ifdef HAVE_OVERLAY
|
||||
CMD_OVERLAY_ENABLE,
|
||||
CMD_OVERLAY_LOAD,
|
||||
CMD_OVERLAY_TEX_GEOM,
|
||||
CMD_OVERLAY_VERTEX_GEOM,
|
||||
CMD_OVERLAY_FULL_SCREEN,
|
||||
CMD_OVERLAY_SET_ALPHA,
|
||||
#endif
|
||||
|
||||
CMD_DUMMY = INT_MAX
|
||||
};
|
||||
|
||||
typedef struct thread_video
|
||||
{
|
||||
slock_t *lock;
|
||||
scond_t *cond_cmd;
|
||||
scond_t *cond_thread;
|
||||
sthread_t *thread;
|
||||
|
||||
video_info_t info;
|
||||
const video_driver_t *driver;
|
||||
#ifdef HAVE_OVERLAY
|
||||
const video_overlay_interface_t *overlay;
|
||||
#endif
|
||||
void *driver_data;
|
||||
const input_driver_t **input;
|
||||
void **input_data;
|
||||
|
||||
bool alive;
|
||||
bool focus;
|
||||
|
||||
enum thread_cmd send_cmd;
|
||||
enum thread_cmd reply_cmd;
|
||||
union
|
||||
{
|
||||
bool b;
|
||||
int i;
|
||||
float f;
|
||||
const char *str;
|
||||
void *v;
|
||||
|
||||
struct
|
||||
{
|
||||
enum rarch_shader_type type;
|
||||
const char *path;
|
||||
unsigned index;
|
||||
} set_shader;
|
||||
|
||||
struct
|
||||
{
|
||||
float x, y, w, h;
|
||||
} rect;
|
||||
|
||||
struct
|
||||
{
|
||||
const uint32_t *data;
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
} image;
|
||||
} cmd_data;
|
||||
|
||||
struct rarch_viewport vp;
|
||||
struct rarch_viewport read_vp; // Last viewport reported to caller.
|
||||
|
||||
struct
|
||||
{
|
||||
slock_t *lock;
|
||||
uint8_t *buffer;
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
unsigned pitch;
|
||||
bool updated;
|
||||
char msg[1024];
|
||||
} frame;
|
||||
|
||||
video_driver_t video_thread;
|
||||
|
||||
} thread_video_t;
|
||||
|
||||
static void *thread_init_never_call(const video_info_t *video, const input_driver_t **input, void **input_data)
|
||||
{
|
||||
(void)video;
|
||||
(void)input;
|
||||
(void)input_data;
|
||||
RARCH_ERR("Sanity check fail! Threaded mustn't be reinit.\n");
|
||||
abort();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void thread_reply(thread_video_t *thr, enum thread_cmd cmd)
|
||||
{
|
||||
slock_lock(thr->lock);
|
||||
thr->reply_cmd = cmd;
|
||||
thr->send_cmd = CMD_NONE;
|
||||
scond_signal(thr->cond_cmd);
|
||||
slock_unlock(thr->lock);
|
||||
}
|
||||
|
||||
static void thread_loop(void *data)
|
||||
{
|
||||
thread_video_t *thr = (thread_video_t*)data;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
bool updated = false;
|
||||
slock_lock(thr->lock);
|
||||
while (thr->send_cmd == CMD_NONE && !thr->frame.updated)
|
||||
scond_wait(thr->cond_thread, thr->lock);
|
||||
if (thr->frame.updated)
|
||||
updated = true;
|
||||
slock_unlock(thr->lock);
|
||||
|
||||
switch (thr->send_cmd)
|
||||
{
|
||||
case CMD_INIT:
|
||||
thr->driver_data = thr->driver->init(&thr->info, thr->input, thr->input_data);
|
||||
thr->cmd_data.b = thr->driver_data;
|
||||
thr->driver->viewport_info(thr->driver_data, &thr->vp);
|
||||
thread_reply(thr, CMD_INIT);
|
||||
break;
|
||||
|
||||
case CMD_FREE:
|
||||
if (thr->driver_data)
|
||||
thr->driver->free(thr->driver_data);
|
||||
thr->driver_data = NULL;
|
||||
thread_reply(thr, CMD_FREE);
|
||||
return;
|
||||
|
||||
case CMD_SET_NONBLOCK:
|
||||
thr->driver->set_nonblock_state(thr->driver_data, thr->cmd_data.b);
|
||||
thread_reply(thr, CMD_SET_NONBLOCK);
|
||||
break;
|
||||
|
||||
case CMD_SET_ROTATION:
|
||||
thr->driver->set_rotation(thr->driver_data, thr->cmd_data.i);
|
||||
thread_reply(thr, CMD_SET_ROTATION);
|
||||
break;
|
||||
|
||||
case CMD_READ_VIEWPORT:
|
||||
{
|
||||
struct rarch_viewport vp = {0};
|
||||
thr->driver->viewport_info(thr->driver_data, &vp);
|
||||
if (memcmp(&vp, &thr->read_vp, sizeof(vp)) == 0) // We can read safely
|
||||
{
|
||||
thr->cmd_data.b = thr->driver->read_viewport(thr->driver_data, (uint8_t*)thr->cmd_data.v);
|
||||
thread_reply(thr, CMD_READ_VIEWPORT);
|
||||
}
|
||||
else // Viewport dimensions changed right after main thread read the async value. Cannot read safely.
|
||||
{
|
||||
thr->cmd_data.b = false;
|
||||
thread_reply(thr, CMD_READ_VIEWPORT);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case CMD_SET_SHADER:
|
||||
{
|
||||
bool ret = thr->driver->set_shader(thr->driver_data,
|
||||
thr->cmd_data.set_shader.type,
|
||||
thr->cmd_data.set_shader.path,
|
||||
thr->cmd_data.set_shader.index);
|
||||
thr->cmd_data.b = ret;
|
||||
thread_reply(thr, CMD_SET_SHADER);
|
||||
break;
|
||||
}
|
||||
|
||||
case CMD_ALIVE:
|
||||
thr->cmd_data.b = thr->driver->alive(thr->driver_data);
|
||||
thread_reply(thr, CMD_ALIVE);
|
||||
break;
|
||||
|
||||
#ifdef HAVE_OVERLAY
|
||||
case CMD_OVERLAY_ENABLE:
|
||||
thr->overlay->enable(thr->driver_data, thr->cmd_data.b);
|
||||
thread_reply(thr, CMD_OVERLAY_ENABLE);
|
||||
break;
|
||||
|
||||
case CMD_OVERLAY_LOAD:
|
||||
thr->cmd_data.b = thr->overlay->load(thr->driver_data,
|
||||
thr->cmd_data.image.data,
|
||||
thr->cmd_data.image.width,
|
||||
thr->cmd_data.image.height);
|
||||
thread_reply(thr, CMD_OVERLAY_LOAD);
|
||||
break;
|
||||
|
||||
case CMD_OVERLAY_TEX_GEOM:
|
||||
thr->overlay->tex_geom(thr->driver_data,
|
||||
thr->cmd_data.rect.x,
|
||||
thr->cmd_data.rect.y,
|
||||
thr->cmd_data.rect.w,
|
||||
thr->cmd_data.rect.h);
|
||||
thread_reply(thr, CMD_OVERLAY_TEX_GEOM);
|
||||
break;
|
||||
|
||||
case CMD_OVERLAY_VERTEX_GEOM:
|
||||
thr->overlay->vertex_geom(thr->driver_data,
|
||||
thr->cmd_data.rect.x,
|
||||
thr->cmd_data.rect.y,
|
||||
thr->cmd_data.rect.w,
|
||||
thr->cmd_data.rect.h);
|
||||
thread_reply(thr, CMD_OVERLAY_VERTEX_GEOM);
|
||||
break;
|
||||
|
||||
case CMD_OVERLAY_FULL_SCREEN:
|
||||
thr->overlay->full_screen(thr->driver_data, thr->cmd_data.b);
|
||||
thread_reply(thr, CMD_OVERLAY_FULL_SCREEN);
|
||||
break;
|
||||
|
||||
case CMD_OVERLAY_SET_ALPHA:
|
||||
thr->overlay->set_alpha(thr->driver_data, thr->cmd_data.f);
|
||||
thread_reply(thr, CMD_OVERLAY_SET_ALPHA);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
thread_reply(thr, thr->send_cmd);
|
||||
break;
|
||||
}
|
||||
|
||||
if (updated)
|
||||
{
|
||||
slock_lock(thr->frame.lock);
|
||||
bool ret = thr->driver->frame(thr->driver_data,
|
||||
thr->frame.buffer, thr->frame.width, thr->frame.height,
|
||||
thr->frame.pitch, *thr->frame.msg ? thr->frame.msg : NULL);
|
||||
slock_unlock(thr->frame.lock);
|
||||
|
||||
bool alive = ret && thr->driver->alive(thr->driver_data);
|
||||
bool focus = ret && thr->driver->focus(thr->driver_data);
|
||||
|
||||
struct rarch_viewport vp = {0};
|
||||
thr->driver->viewport_info(thr->driver_data, &vp);
|
||||
|
||||
slock_lock(thr->lock);
|
||||
thr->alive = alive;
|
||||
thr->focus = focus;
|
||||
thr->frame.updated = false;
|
||||
thr->vp = vp;
|
||||
slock_unlock(thr->lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void thread_send_cmd(thread_video_t *thr, enum thread_cmd cmd)
|
||||
{
|
||||
slock_lock(thr->lock);
|
||||
thr->send_cmd = cmd;
|
||||
thr->reply_cmd = CMD_NONE;
|
||||
scond_signal(thr->cond_thread);
|
||||
slock_unlock(thr->lock);
|
||||
}
|
||||
|
||||
static void thread_wait_reply(thread_video_t *thr, enum thread_cmd cmd)
|
||||
{
|
||||
slock_lock(thr->lock);
|
||||
while (cmd != thr->reply_cmd)
|
||||
scond_wait(thr->cond_cmd, thr->lock);
|
||||
slock_unlock(thr->lock);
|
||||
}
|
||||
|
||||
static bool thread_alive(void *data)
|
||||
{
|
||||
thread_video_t *thr = (thread_video_t*)data;
|
||||
if (g_extern.is_paused)
|
||||
{
|
||||
thread_send_cmd(thr, CMD_ALIVE);
|
||||
thread_wait_reply(thr, CMD_ALIVE);
|
||||
return thr->cmd_data.b;
|
||||
}
|
||||
else
|
||||
{
|
||||
slock_lock(thr->lock);
|
||||
bool ret = thr->alive;
|
||||
slock_unlock(thr->lock);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
static bool thread_focus(void *data)
|
||||
{
|
||||
thread_video_t *thr = (thread_video_t*)data;
|
||||
slock_lock(thr->lock);
|
||||
bool ret = thr->focus;
|
||||
slock_unlock(thr->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool thread_frame(void *data, const void *frame_,
|
||||
unsigned width, unsigned height, unsigned pitch, const char *msg)
|
||||
{
|
||||
if (!frame_)
|
||||
return true;
|
||||
|
||||
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);
|
||||
// Drop frame if updated flag is still set, as thread is still working on last frame.
|
||||
if (!thr->frame.updated)
|
||||
{
|
||||
slock_lock(thr->frame.lock);
|
||||
for (unsigned 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);
|
||||
slock_unlock(thr->frame.lock);
|
||||
}
|
||||
slock_unlock(thr->lock);
|
||||
|
||||
RARCH_PERFORMANCE_STOP(thread_frame);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void thread_set_nonblock_state(void *data, bool state)
|
||||
{
|
||||
thread_video_t *thr = (thread_video_t*)data;
|
||||
thr->cmd_data.b = state;
|
||||
thread_send_cmd(thr, CMD_SET_NONBLOCK);
|
||||
thread_wait_reply(thr, CMD_SET_NONBLOCK);
|
||||
}
|
||||
|
||||
static bool thread_init(thread_video_t *thr, const video_info_t *info, const input_driver_t **input,
|
||||
void **input_data)
|
||||
{
|
||||
thr->lock = slock_new();
|
||||
thr->frame.lock = slock_new();
|
||||
thr->cond_cmd = scond_new();
|
||||
thr->cond_thread = scond_new();
|
||||
thr->input = input;
|
||||
thr->input_data = input_data;
|
||||
thr->info = *info;
|
||||
thr->alive = true;
|
||||
thr->focus = true;
|
||||
|
||||
size_t max_size = info->input_scale * RARCH_SCALE_BASE;
|
||||
max_size *= max_size;
|
||||
max_size *= info->rgb32 ? sizeof(uint32_t) : sizeof(uint16_t);
|
||||
thr->frame.buffer = (uint8_t*)malloc(max_size);
|
||||
if (!thr->frame.buffer)
|
||||
return false;
|
||||
|
||||
memset(thr->frame.buffer, 0x80, max_size);
|
||||
|
||||
thr->thread = sthread_create(thread_loop, thr);
|
||||
if (!thr->thread)
|
||||
return false;
|
||||
thread_send_cmd(thr, CMD_INIT);
|
||||
thread_wait_reply(thr, CMD_INIT);
|
||||
|
||||
return thr->cmd_data.b;
|
||||
}
|
||||
|
||||
static bool thread_set_shader(void *data, enum rarch_shader_type type, const char *path, unsigned index)
|
||||
{
|
||||
thread_video_t *thr = (thread_video_t*)data;
|
||||
thr->cmd_data.set_shader.type = type;
|
||||
thr->cmd_data.set_shader.path = path;
|
||||
thr->cmd_data.set_shader.index = index;
|
||||
thread_send_cmd(thr, CMD_SET_SHADER);
|
||||
thread_wait_reply(thr, CMD_SET_SHADER);
|
||||
return thr->cmd_data.b;
|
||||
}
|
||||
|
||||
static void thread_set_rotation(void *data, unsigned rotation)
|
||||
{
|
||||
thread_video_t *thr = (thread_video_t*)data;
|
||||
thr->cmd_data.i = rotation;
|
||||
thread_send_cmd(thr, CMD_SET_ROTATION);
|
||||
thread_wait_reply(thr, CMD_SET_ROTATION);
|
||||
}
|
||||
|
||||
// This value is set async as stalling on the video driver for every query is too slow.
|
||||
// This means this value might not be correct, so viewport reads are not supported for now.
|
||||
static void thread_viewport_info(void *data, struct rarch_viewport *vp)
|
||||
{
|
||||
thread_video_t *thr = (thread_video_t*)data;
|
||||
slock_lock(thr->lock);
|
||||
*vp = thr->vp;
|
||||
|
||||
// Explicitly mem-copied so we can use memcmp correctly later.
|
||||
memcpy(&thr->read_vp, &thr->vp, sizeof(thr->vp));
|
||||
slock_unlock(thr->lock);
|
||||
}
|
||||
|
||||
static bool thread_read_viewport(void *data, uint8_t *buffer)
|
||||
{
|
||||
thread_video_t *thr = (thread_video_t*)data;
|
||||
thr->cmd_data.v = buffer;
|
||||
thread_send_cmd(thr, CMD_READ_VIEWPORT);
|
||||
thread_wait_reply(thr, CMD_READ_VIEWPORT);
|
||||
return thr->cmd_data.b;
|
||||
}
|
||||
|
||||
static void thread_free(void *data)
|
||||
{
|
||||
thread_video_t *thr = (thread_video_t*)data;
|
||||
if (!thr)
|
||||
return;
|
||||
|
||||
thread_send_cmd(thr, CMD_FREE);
|
||||
thread_wait_reply(thr, CMD_FREE);
|
||||
sthread_join(thr->thread);
|
||||
|
||||
free(thr->frame.buffer);
|
||||
slock_free(thr->frame.lock);
|
||||
slock_free(thr->lock);
|
||||
scond_free(thr->cond_cmd);
|
||||
scond_free(thr->cond_thread);
|
||||
|
||||
free(thr);
|
||||
}
|
||||
|
||||
#ifdef HAVE_OVERLAY
|
||||
static void thread_overlay_enable(void *data, bool state)
|
||||
{
|
||||
thread_video_t *thr = (thread_video_t*)data;
|
||||
thr->cmd_data.b = state;
|
||||
thread_send_cmd(thr, CMD_OVERLAY_ENABLE);
|
||||
thread_wait_reply(thr, CMD_OVERLAY_ENABLE);
|
||||
}
|
||||
|
||||
static bool thread_overlay_load(void *data, const uint32_t *image, unsigned width, unsigned height)
|
||||
{
|
||||
thread_video_t *thr = (thread_video_t*)data;
|
||||
thr->cmd_data.image.data = image;
|
||||
thr->cmd_data.image.width = width;
|
||||
thr->cmd_data.image.height = height;
|
||||
thread_send_cmd(thr, CMD_OVERLAY_LOAD);
|
||||
thread_wait_reply(thr, CMD_OVERLAY_LOAD);
|
||||
return thr->cmd_data.b;
|
||||
}
|
||||
|
||||
static void thread_overlay_tex_geom(void *data, float x, float y, float w, float h)
|
||||
{
|
||||
thread_video_t *thr = (thread_video_t*)data;
|
||||
thr->cmd_data.rect.x = x;
|
||||
thr->cmd_data.rect.y = y;
|
||||
thr->cmd_data.rect.w = w;
|
||||
thr->cmd_data.rect.h = h;
|
||||
thread_send_cmd(thr, CMD_OVERLAY_TEX_GEOM);
|
||||
thread_wait_reply(thr, CMD_OVERLAY_TEX_GEOM);
|
||||
}
|
||||
|
||||
static void thread_overlay_vertex_geom(void *data, float x, float y, float w, float h)
|
||||
{
|
||||
thread_video_t *thr = (thread_video_t*)data;
|
||||
thr->cmd_data.rect.x = x;
|
||||
thr->cmd_data.rect.y = y;
|
||||
thr->cmd_data.rect.w = w;
|
||||
thr->cmd_data.rect.h = h;
|
||||
thread_send_cmd(thr, CMD_OVERLAY_VERTEX_GEOM);
|
||||
thread_wait_reply(thr, CMD_OVERLAY_VERTEX_GEOM);
|
||||
}
|
||||
|
||||
static void thread_overlay_full_screen(void *data, bool enable)
|
||||
{
|
||||
thread_video_t *thr = (thread_video_t*)data;
|
||||
thr->cmd_data.b = enable;
|
||||
thread_send_cmd(thr, CMD_OVERLAY_FULL_SCREEN);
|
||||
thread_wait_reply(thr, CMD_OVERLAY_FULL_SCREEN);
|
||||
}
|
||||
|
||||
static void thread_overlay_set_alpha(void *data, float mod)
|
||||
{
|
||||
thread_video_t *thr = (thread_video_t*)data;
|
||||
thr->cmd_data.f = mod;
|
||||
thread_send_cmd(thr, CMD_OVERLAY_SET_ALPHA);
|
||||
thread_wait_reply(thr, CMD_OVERLAY_SET_ALPHA);
|
||||
}
|
||||
|
||||
static const video_overlay_interface_t thread_overlay = {
|
||||
thread_overlay_enable,
|
||||
thread_overlay_load,
|
||||
thread_overlay_tex_geom,
|
||||
thread_overlay_vertex_geom,
|
||||
thread_overlay_full_screen,
|
||||
thread_overlay_set_alpha,
|
||||
};
|
||||
|
||||
static void thread_get_overlay_interface(void *data, const video_overlay_interface_t **iface)
|
||||
{
|
||||
thread_video_t *thr = (thread_video_t*)data;
|
||||
*iface = &thread_overlay;
|
||||
thr->driver->overlay_interface(thr->driver_data, &thr->overlay);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const video_driver_t video_thread = {
|
||||
thread_init_never_call, // Should never be called directly.
|
||||
thread_frame,
|
||||
thread_set_nonblock_state,
|
||||
thread_alive,
|
||||
thread_focus,
|
||||
thread_set_shader,
|
||||
thread_free,
|
||||
"Thread wrapper",
|
||||
thread_set_rotation,
|
||||
thread_viewport_info,
|
||||
thread_read_viewport,
|
||||
#ifdef HAVE_OVERLAY
|
||||
thread_get_overlay_interface, // get_overlay_interface
|
||||
#endif
|
||||
};
|
||||
|
||||
static void thread_set_callbacks(thread_video_t *thr, const video_driver_t *driver)
|
||||
{
|
||||
thr->video_thread = video_thread;
|
||||
// Disable optional features if not present.
|
||||
if (!driver->read_viewport)
|
||||
thr->video_thread.read_viewport = NULL;
|
||||
if (!driver->set_rotation)
|
||||
thr->video_thread.set_rotation = NULL;
|
||||
if (!driver->set_shader)
|
||||
thr->video_thread.set_shader = NULL;
|
||||
#ifdef HAVE_OVERLAY
|
||||
if (!driver->overlay_interface)
|
||||
thr->video_thread.overlay_interface = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool rarch_threaded_video_init(const video_driver_t **out_driver, void **out_data,
|
||||
const input_driver_t **input, void **input_data,
|
||||
const video_driver_t *driver, const video_info_t *info)
|
||||
{
|
||||
thread_video_t *thr = (thread_video_t*)calloc(1, sizeof(*thr));
|
||||
if (!thr)
|
||||
return false;
|
||||
|
||||
thread_set_callbacks(thr, driver);
|
||||
|
||||
thr->driver = driver;
|
||||
*out_driver = &thr->video_thread;
|
||||
*out_data = thr;
|
||||
return thread_init(thr, info, input, input_data);
|
||||
}
|
||||
|
||||
|
24
gfx/thread_wrapper.h
Normal file
24
gfx/thread_wrapper.h
Normal file
@ -0,0 +1,24 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2010-2013 - 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 "../driver.h"
|
||||
#include "../boolean.h"
|
||||
|
||||
// Starts a video driver in a new thread.
|
||||
// Access to video driver will be mediated through this driver.
|
||||
bool rarch_threaded_video_init(const video_driver_t **out_driver, void **out_data,
|
||||
const input_driver_t **input, void **input_data,
|
||||
const video_driver_t *driver, const video_info_t *info);
|
||||
|
15
gfx/xvideo.c
15
gfx/xvideo.c
@ -464,14 +464,17 @@ static void *xv_init(const video_info_t *video, const input_driver_t **input, vo
|
||||
driver.video_display = (uintptr_t)xv->display;
|
||||
driver.video_window = (Window)xv->window;
|
||||
|
||||
xinput = input_x.init();
|
||||
if (xinput)
|
||||
if (input && input_data)
|
||||
{
|
||||
*input = &input_x;
|
||||
*input_data = xinput;
|
||||
xinput = input_x.init();
|
||||
if (xinput)
|
||||
{
|
||||
*input = &input_x;
|
||||
*input_data = xinput;
|
||||
}
|
||||
else
|
||||
*input = NULL;
|
||||
}
|
||||
else
|
||||
*input = NULL;
|
||||
|
||||
init_yuv_tables(xv);
|
||||
xv_init_font(xv, g_settings.video.font_path, g_settings.video.font_size);
|
||||
|
@ -88,7 +88,7 @@
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;HAVE_WIN32_D3D9;HAVE_CG;HAVE_GLSL;HAVE_ZLIB;WANT_MINIZ;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_SCREENSHOTS;HAVE_BSV_MOVIE;HAVE_DINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETPLAY;HAVE_NETWORK_CMD;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;HAVE_SINC;PACKAGE_VERSION="0.9.8";_CRT_SECURE_NO_WARNINGS;__SSE__;__i686__</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;HAVE_WIN32_D3D9;HAVE_CG;HAVE_GLSL;HAVE_ZLIB;WANT_MINIZ;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_SCREENSHOTS;HAVE_BSV_MOVIE;HAVE_DINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETPLAY;HAVE_NETWORK_CMD;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;HAVE_SINC;PACKAGE_VERSION="0.9.8";_CRT_SECURE_NO_WARNINGS;__SSE__;__i686__;HAVE_OVERLAY</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(MSBuildProjectDirectory);$(MSBuildProjectDirectory)\..\..\;$(CG_INC_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<CompileAs>CompileAsCpp</CompileAs>
|
||||
@ -108,7 +108,7 @@
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;HAVE_WIN32_D3D9;HAVE_CG;HAVE_GLSL;HAVE_ZLIB;WANT_MINIZ;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_SCREENSHOTS;HAVE_BSV_MOVIE;HAVE_DINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETPLAY;HAVE_NETWORK_CMD;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;HAVE_SINC;PACKAGE_VERSION="0.9.8";_CRT_SECURE_NO_WARNINGS;__SSE__;__SSE2__;__x86_64__</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;HAVE_WIN32_D3D9;HAVE_CG;HAVE_GLSL;HAVE_ZLIB;WANT_MINIZ;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_SCREENSHOTS;HAVE_BSV_MOVIE;HAVE_DINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETPLAY;HAVE_NETWORK_CMD;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;HAVE_SINC;PACKAGE_VERSION="0.9.8";_CRT_SECURE_NO_WARNINGS;__SSE__;__SSE2__;__x86_64__;HAVE_OVERLAY</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(MSBuildProjectDirectory);$(MSBuildProjectDirectory)\..\..\;$(CG_INC_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<CompileAs>CompileAsCpp</CompileAs>
|
||||
@ -130,7 +130,7 @@
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;HAVE_WIN32_D3D9;HAVE_CG;HAVE_GLSL;HAVE_ZLIB;WANT_MINIZ;HAVE_SINC;NDEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_SCREENSHOTS;HAVE_BSV_MOVIE;HAVE_DINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETPLAY;HAVE_NETWORK_CMD;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;PACKAGE_VERSION="0.9.8";_CRT_SECURE_NO_WARNINGS;__SSE__;__i686__</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;HAVE_WIN32_D3D9;HAVE_CG;HAVE_GLSL;HAVE_ZLIB;WANT_MINIZ;HAVE_SINC;NDEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_SCREENSHOTS;HAVE_BSV_MOVIE;HAVE_DINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETPLAY;HAVE_NETWORK_CMD;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;PACKAGE_VERSION="0.9.8";_CRT_SECURE_NO_WARNINGS;__SSE__;__i686__;HAVE_OVERLAY</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(MSBuildProjectDirectory);$(MSBuildProjectDirectory)\..\..\;$(CG_INC_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<CompileAs>CompileAsCpp</CompileAs>
|
||||
@ -154,7 +154,7 @@
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;HAVE_WIN32_D3D9;HAVE_CG;HAVE_GLSL;NDEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_SCREENSHOTS;HAVE_BSV_MOVIE;HAVE_DINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETPLAY;HAVE_NETWORK_CMD;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;HAVE_SINC;HAVE_ZLIB;WANT_MINIZ;PACKAGE_VERSION="0.9.8";_CRT_SECURE_NO_WARNINGS;__SSE__;__SSE2__;__x86_64__</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;HAVE_WIN32_D3D9;HAVE_CG;HAVE_GLSL;NDEBUG;_WINDOWS;%(PreprocessorDefinitions);HAVE_SCREENSHOTS;HAVE_BSV_MOVIE;HAVE_DINPUT;HAVE_XAUDIO;HAVE_DSOUND;HAVE_OPENGL;HAVE_DYLIB;HAVE_NETPLAY;HAVE_NETWORK_CMD;HAVE_COMMAND;HAVE_STDIN_CMD;HAVE_THREADS;HAVE_DYNAMIC;HAVE_SINC;HAVE_ZLIB;WANT_MINIZ;PACKAGE_VERSION="0.9.8";_CRT_SECURE_NO_WARNINGS;__SSE__;__SSE2__;__x86_64__;HAVE_OVERLAY</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(MSBuildProjectDirectory);$(MSBuildProjectDirectory)\..\..\;$(CG_INC_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<CompileAs>CompileAsCpp</CompileAs>
|
||||
@ -196,6 +196,8 @@
|
||||
<ClCompile Include="..\..\gfx\rpng\rpng.c" />
|
||||
<ClCompile Include="..\..\gfx\shader_cg.c" />
|
||||
<ClCompile Include="..\..\gfx\shader_glsl.c" />
|
||||
<ClCompile Include="..\..\gfx\thread_wrapper.c" />
|
||||
<ClCompile Include="..\..\input\overlay.c" />
|
||||
<ClCompile Include="..\..\performance.c">
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\command.c">
|
||||
|
@ -213,6 +213,12 @@
|
||||
<ClCompile Include="..\..\deps\miniz\miniz.c">
|
||||
<Filter>Source Files\deps</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\gfx\thread_wrapper.c">
|
||||
<Filter>Source Files\gfx</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\input\overlay.c">
|
||||
<Filter>Source Files\input</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="resource.h">
|
||||
|
@ -38,6 +38,7 @@ typedef int ssize_t;
|
||||
|
||||
// Disable some of the annoying warnings.
|
||||
#pragma warning(disable : 4800)
|
||||
#pragma warning(disable : 4805)
|
||||
#pragma warning(disable : 4244)
|
||||
#pragma warning(disable : 4305)
|
||||
#pragma warning(disable : 4146)
|
||||
|
@ -1023,7 +1023,7 @@ static void ffemu_audio_resample(ffemu_t *handle, struct ffemu_audio_data *data)
|
||||
{
|
||||
// It's always two channels ...
|
||||
struct resampler_data info = {0};
|
||||
info.data_in = (const sample_t*)data->data;
|
||||
info.data_in = (const float*)data->data;
|
||||
info.data_out = handle->audio.resample_out;
|
||||
info.input_frames = data->frames;
|
||||
info.ratio = handle->audio.ratio;
|
||||
|
@ -366,7 +366,7 @@ static bool audio_flush(const int16_t *data, size_t samples)
|
||||
if (!g_extern.audio_active)
|
||||
return false;
|
||||
|
||||
const sample_t *output_data = NULL;
|
||||
const float *output_data = NULL;
|
||||
unsigned output_frames = 0;
|
||||
|
||||
struct resampler_data src_data = {0};
|
||||
|
@ -65,6 +65,9 @@
|
||||
# Video vsync.
|
||||
# video_vsync = true
|
||||
|
||||
# Use threaded video driver. Using this might improve performance at possible cost of latency and more video stuttering.
|
||||
# video_threaded = false
|
||||
|
||||
# Smoothens picture with bilinear filtering. Should be disabled if using pixel shaders.
|
||||
# video_smooth = true
|
||||
|
||||
|
@ -159,6 +159,7 @@ void config_set_defaults(void)
|
||||
g_settings.video.fullscreen_y = fullscreen_y;
|
||||
g_settings.video.disable_composition = disable_composition;
|
||||
g_settings.video.vsync = vsync;
|
||||
g_settings.video.threaded = video_threaded;
|
||||
g_settings.video.smooth = video_smooth;
|
||||
g_settings.video.force_aspect = force_aspect;
|
||||
g_settings.video.scale_integer = scale_integer;
|
||||
@ -438,6 +439,7 @@ bool config_load_file(const char *path)
|
||||
CONFIG_GET_INT(video.monitor_index, "video_monitor_index");
|
||||
CONFIG_GET_BOOL(video.disable_composition, "video_disable_composition");
|
||||
CONFIG_GET_BOOL(video.vsync, "video_vsync");
|
||||
CONFIG_GET_BOOL(video.threaded, "video_threaded");
|
||||
CONFIG_GET_BOOL(video.smooth, "video_smooth");
|
||||
CONFIG_GET_BOOL(video.force_aspect, "video_force_aspect");
|
||||
CONFIG_GET_BOOL(video.scale_integer, "video_scale_integer");
|
||||
|
Loading…
x
Reference in New Issue
Block a user