Reimplement driver.*_data_own variables so that they actually

work for a usecase now -

on Xbox, full teardown/re-initing of D3D context seems to be
error-prone - so by flagging driver.video_data_own to true inside
of the video_init function, we signal later on to the uninit_drivers
function that we DO NOT want to call the free function of this driver
and clean up the handle.

Instead, this driver should properly retain the handle by returning
the pre-existing handle when (for example) driver.video_data is
not NULL. You can see an example of this in xdk/xdk_d3d.cpp.

Overall still a quite clean solution and we will only use this in
extraordinary conditions (like this Xbox one I suppose) - full
teardown/setup will be the goal for all other platforms where we
can be certain that the state can be brought down and up entirely
during runtime without any problems.
This commit is contained in:
twinaphex 2014-05-30 02:37:48 +02:00
parent 346701fce8
commit a97b53f9f1
3 changed files with 108 additions and 93 deletions

172
driver.c
View File

@ -503,17 +503,17 @@ bool driver_update_system_av_info(const struct retro_system_av_info *info)
void init_drivers(void)
{
driver.video_data_own = !driver.video_data;
driver.audio_data_own = !driver.audio_data;
driver.input_data_own = !driver.input_data;
driver.video_data_own = false;
driver.audio_data_own = false;
driver.input_data_own = false;
#ifdef HAVE_CAMERA
driver.camera_data_own = !driver.camera_data;
driver.camera_data_own = false;
#endif
#ifdef HAVE_LOCATION
driver.location_data_own = !driver.location_data;
driver.location_data_own = false;
#endif
#ifdef HAVE_OSK
driver.osk_data_own = !driver.osk_data;
driver.osk_data_own = false;
#endif
adjust_system_rates();
@ -550,6 +550,64 @@ void init_drivers(void)
g_extern.system.frame_time_last = 0;
}
void rarch_deinit_filter(void)
{
rarch_softfilter_free(g_extern.filter.filter);
free(g_extern.filter.buffer);
memset(&g_extern.filter, 0, sizeof(g_extern.filter));
}
static void deinit_pixel_converter(void)
{
scaler_ctx_gen_reset(&driver.scaler);
memset(&driver.scaler, 0, sizeof(driver.scaler));
free(driver.scaler_out);
driver.scaler_out = NULL;
}
static void deinit_shader_dir(void)
{
// It handles NULL, no worries :D
dir_list_free(g_extern.shader_dir.list);
g_extern.shader_dir.list = NULL;
g_extern.shader_dir.ptr = 0;
}
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",
2 * MEASURE_FRAME_TIME_SAMPLES_COUNT);
return;
}
double avg_fps = 0.0;
double stddev = 0.0;
unsigned samples = 0;
if (driver_monitor_fps_statistics(&avg_fps, &stddev, &samples))
{
RARCH_LOG("Average monitor Hz: %.6f Hz. (%.3f %% frame time deviation, based on %u last samples).\n",
avg_fps, 100.0 * stddev, samples);
}
}
static void uninit_video_misc(void)
{
deinit_pixel_converter();
rarch_deinit_filter();
deinit_shader_dir();
compute_monitor_fps_statistics();
}
void uninit_drivers(void)
{
uninit_audio();
@ -557,44 +615,41 @@ void uninit_drivers(void)
if (g_extern.system.hw_render_callback.context_destroy && !driver.video_cache_context)
g_extern.system.hw_render_callback.context_destroy();
#ifndef _XBOX
uninit_video_input();
#endif
uninit_video_misc();
if (!driver.video_data_own)
driver.video_data = NULL;
#ifdef HAVE_CAMERA
uninit_camera();
if (driver.camera_data_own)
if (!driver.camera_data_own)
{
uninit_camera();
driver.camera_data = NULL;
driver.camera_data_own = false;
}
#endif
#ifdef HAVE_LOCATION
uninit_location();
if (driver.location_data_own)
if (!driver.location_data_own)
{
uninit_location();
driver.location_data = NULL;
driver.location_data_own = false;
}
#endif
#ifdef HAVE_OSK
uninit_osk();
if (driver.osk_data_own)
if (!driver.osk_data_own)
{
uninit_osk();
driver.osk_data = NULL;
driver.osk_data_own = false;
}
#endif
#ifndef _XBOX
if (driver.video_data_own)
driver.video_data = NULL;
driver.video_data_own = false;
if (driver.input_data_own)
if (!driver.input_data_own)
driver.input_data = NULL;
driver.input_data_own = false;
#endif
if (driver.audio_data_own)
if (!driver.audio_data_own)
driver.audio_data = NULL;
driver.audio_data_own = false;
}
void rarch_init_dsp_filter(void)
@ -803,31 +858,6 @@ bool driver_monitor_fps_statistics(double *refresh_rate, double *deviation, unsi
return true;
}
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",
2 * MEASURE_FRAME_TIME_SAMPLES_COUNT);
return;
}
double avg_fps = 0.0;
double stddev = 0.0;
unsigned samples = 0;
if (driver_monitor_fps_statistics(&avg_fps, &stddev, &samples))
{
RARCH_LOG("Average monitor Hz: %.6f Hz. (%.3f %% frame time deviation, based on %u last samples).\n",
avg_fps, 100.0 * stddev, samples);
}
}
void uninit_audio(void)
{
if (driver.audio_data && driver.audio)
@ -859,13 +889,6 @@ void uninit_audio(void)
compute_audio_buffer_statistics();
}
void rarch_deinit_filter(void)
{
rarch_softfilter_free(g_extern.filter.filter);
free(g_extern.filter.buffer);
memset(&g_extern.filter, 0, sizeof(g_extern.filter));
}
void rarch_init_filter(enum retro_pixel_format colfmt)
{
rarch_deinit_filter();
@ -932,14 +955,6 @@ error:
rarch_deinit_filter();
}
static void deinit_shader_dir(void)
{
// It handles NULL, no worries :D
dir_list_free(g_extern.shader_dir.list);
g_extern.shader_dir.list = NULL;
g_extern.shader_dir.ptr = 0;
}
static void init_shader_dir(void)
{
unsigned i;
@ -960,14 +975,6 @@ static void init_shader_dir(void)
RARCH_LOG("Found shader \"%s\"\n", g_extern.shader_dir.list->elems[i].data);
}
static void deinit_pixel_converter(void)
{
scaler_ctx_gen_reset(&driver.scaler);
memset(&driver.scaler, 0, sizeof(driver.scaler));
free(driver.scaler_out);
driver.scaler_out = NULL;
}
static bool init_video_pixel_converter(unsigned size)
{
// This function can be called multiple times without deiniting first on consoles.
@ -1168,18 +1175,11 @@ void uninit_video_input(void)
}
#endif
if (driver.input_data != driver.video_data && driver.input && driver.input->free)
if (!driver.input_data_own && driver.input_data != driver.video_data && driver.input && driver.input->free)
input_free_func();
if (driver.video_data && driver.video && driver.video->free)
if (!driver.video_data_own && driver.video_data && driver.video && driver.video->free)
video_free_func();
deinit_pixel_converter();
rarch_deinit_filter();
deinit_shader_dir();
compute_monitor_fps_statistics();
}
driver_t driver;

View File

@ -484,13 +484,15 @@ typedef struct driver
bool video_cache_context;
bool video_cache_context_ack; // Set to true by driver if context caching succeeded.
// 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
// to finally free() up the driver handles.
// Driver core will still call init() and free(), but in this case
// these calls should be seen as "reinit() + ref_count++" and "ref_count--"
// respectively.
// Set this to true if the platform in question needs to 'own' the respective
// handle and therefore skip regular RetroArch driver teardown/reiniting procedure.
// If set to true, the 'free' function will get skipped. It is then up to the
// driver implementation to properly handle 'reiniting' inside the 'init' function
// and make sure it returns the existing handle instead of allocating and returning
// a pointer to a new handle.
//
// Typically, if a driver intends to make use of this, it should set this to true
// at the end of its 'init' function.
bool video_data_own;
bool audio_data_own;
bool input_data_own;

View File

@ -461,6 +461,14 @@ static void *d3d_init(const video_info_t *vid, const input_driver_t **input, voi
d3d_video_t *d3d = (d3d_video_t*)driver.video_data;
// Reinitialize textures as we might have changed pixel formats.
d3d_reinit_textures(d3d, vid);
if (input && input_data)
{
*input = driver.input;
*input_data = driver.input_data;
}
driver.video_data_own = true;
driver.input_data_own = true;
return driver.video_data;
}
@ -491,6 +499,11 @@ static void *d3d_init(const video_info_t *vid, const input_driver_t **input, voi
return NULL;
}
#ifdef _XBOX
driver.video_data_own = true;
driver.input_data_own = true;
#endif
return d3d;
}