libobs: Cache effects to prevent shader duplicates

Switching between shaders often can cause a performance hit, so cache
effects so that they persist until the graphics subsystem is destroyed.
master
jp9000 2015-03-08 06:55:15 -07:00
parent 2abf7b057a
commit 699201a06e
4 changed files with 62 additions and 2 deletions

View File

@ -21,11 +21,17 @@
#include "vec3.h"
#include "vec4.h"
void gs_effect_actually_destroy(gs_effect_t *effect)
{
effect_free(effect);
bfree(effect);
}
void gs_effect_destroy(gs_effect_t *effect)
{
if (effect) {
effect_free(effect);
bfree(effect);
if (!effect->effect_path)
gs_effect_actually_destroy(effect);
}
}

View File

@ -148,6 +148,8 @@ struct gs_effect {
gs_eparam_t *view_proj, *world, *scale;
graphics_t *graphics;
struct gs_effect *next;
size_t loop_pass;
bool looping;
};

View File

@ -285,6 +285,9 @@ struct graphics_subsystem {
DARRAY(uint32_t) colors;
DARRAY(struct vec2) texverts[16];
pthread_mutex_t effect_mutex;
struct gs_effect *first_effect;
pthread_mutex_t mutex;
volatile long ref;

View File

@ -115,12 +115,17 @@ static bool graphics_init(struct graphics_subsystem *graphics)
graphics->exports.device_enter_context(graphics->device);
pthread_mutex_init_value(&graphics->mutex);
pthread_mutex_init_value(&graphics->effect_mutex);
if (!graphics_init_immediate_vb(graphics))
return false;
if (!graphics_init_sprite_vb(graphics))
return false;
if (pthread_mutex_init(&graphics->mutex, NULL) != 0)
return false;
if (pthread_mutex_init(&graphics->effect_mutex, NULL) != 0)
return false;
graphics->exports.device_blend_function(graphics->device,
GS_BLEND_SRCALPHA, GS_BLEND_INVSRCALPHA);
@ -173,6 +178,8 @@ error:
return errcode;
}
extern void gs_effect_actually_destroy(gs_effect_t *effect);
void gs_destroy(graphics_t *graphics)
{
if (!graphics)
@ -182,15 +189,28 @@ void gs_destroy(graphics_t *graphics)
gs_leave_context();
if (graphics->device) {
struct gs_effect *effect = graphics->first_effect;
thread_graphics = graphics;
graphics->exports.device_enter_context(graphics->device);
while (effect) {
struct gs_effect *next = effect->next;
gs_effect_actually_destroy(effect);
effect = next;
}
graphics->exports.gs_vertexbuffer_destroy(
graphics->sprite_buffer);
graphics->exports.gs_vertexbuffer_destroy(
graphics->immediate_vertbuffer);
graphics->exports.device_destroy(graphics->device);
thread_graphics = NULL;
}
pthread_mutex_destroy(&graphics->mutex);
pthread_mutex_destroy(&graphics->effect_mutex);
da_free(graphics->matrix_stack);
da_free(graphics->viewport_stack);
if (graphics->module)
@ -644,6 +664,19 @@ gs_effect_t *gs_get_effect(void)
return thread_graphics ? thread_graphics->cur_effect : NULL;
}
static inline struct gs_effect *find_cached_effect(const char *filename)
{
struct gs_effect *effect = thread_graphics->first_effect;
while (effect) {
if (strcmp(effect->effect_path, filename) == 0)
break;
effect = effect->next;
}
return effect;
}
gs_effect_t *gs_effect_create_from_file(const char *file, char **error_string)
{
char *file_string;
@ -652,6 +685,10 @@ gs_effect_t *gs_effect_create_from_file(const char *file, char **error_string)
if (!thread_graphics || !file)
return NULL;
effect = find_cached_effect(file);
if (effect)
return effect;
file_string = os_quick_read_utf8_file(file);
if (!file_string) {
blog(LOG_ERROR, "Could not load effect file '%s'", file);
@ -675,6 +712,7 @@ gs_effect_t *gs_effect_create(const char *effect_string, const char *filename,
bool success;
effect->graphics = thread_graphics;
effect->effect_path = bstrdup(filename);
ep_init(&parser);
success = ep_parse(&parser, effect, effect_string, filename);
@ -686,6 +724,17 @@ gs_effect_t *gs_effect_create(const char *effect_string, const char *filename,
effect = NULL;
}
if (effect) {
pthread_mutex_lock(&thread_graphics->effect_mutex);
if (effect->effect_path) {
effect->next = thread_graphics->first_effect;
thread_graphics->first_effect = effect;
}
pthread_mutex_unlock(&thread_graphics->effect_mutex);
}
ep_free(&parser);
return effect;
}