mirror of
https://github.com/obsproject/obs-studio.git
synced 2024-07-14 23:34:08 +00:00
add major optimization to filter processing, and as a nice side effect, make it easier to create new filters and sources
This commit is contained in:
parent
5471625dd7
commit
19c4ee995e
|
@ -1,6 +1,6 @@
|
|||
uniform float4x4 ViewProj;
|
||||
uniform float4x4 yuv_matrix;
|
||||
uniform texture2d tex;
|
||||
uniform texture2d diffuse;
|
||||
|
||||
sampler_state def_sampler {
|
||||
Filter = Linear;
|
||||
|
@ -16,19 +16,19 @@ struct VertInOut {
|
|||
VertInOut VSDefault(VertInOut vert_in)
|
||||
{
|
||||
VertInOut vert_out;
|
||||
vert_out.pos = mul(vert_in.pos, ViewProj);
|
||||
vert_out.pos = mul(float4(vert_in.pos.xyz, 1.0), ViewProj);
|
||||
vert_out.uv = vert_in.uv;
|
||||
return vert_out;
|
||||
}
|
||||
|
||||
float4 PSDrawRGB(VertInOut vert_in) : TARGET
|
||||
{
|
||||
return tex.Sample(def_sampler, vert_in.uv);
|
||||
return diffuse.Sample(def_sampler, vert_in.uv);
|
||||
}
|
||||
|
||||
float4 PSDrawYUVToRGB(VertInOut vert_in) : TARGET
|
||||
{
|
||||
float4 yuv = tex.Sample(def_sampler, vert_in.uv);
|
||||
float4 yuv = diffuse.Sample(def_sampler, vert_in.uv);
|
||||
return saturate(mul(float4(yuv.xyz, 1.0), yuv_matrix));
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ float4 PShader(VertexInOut fragment_in) : TARGET
|
|||
return diffuse.Sample(texSampler, fragment_in.uv) * color;
|
||||
}
|
||||
|
||||
technique Default
|
||||
technique DrawRGB
|
||||
{
|
||||
pass
|
||||
{
|
||||
|
|
|
@ -29,3 +29,5 @@
|
|||
#define SOURCE_VIDEO (1<<0) /* Source has video */
|
||||
#define SOURCE_AUDIO (1<<1) /* Source has audio */
|
||||
#define SOURCE_ASYNC_VIDEO (1<<2) /* Async video (use with SOURCE_VIDEO) */
|
||||
#define SOURCE_DEFAULT_EFFECT (1<<3) /* Source uses default/filter effect */
|
||||
#define SOURCE_YUV (1<<4) /* Source is in YUV color space */
|
||||
|
|
|
@ -439,8 +439,8 @@ static bool upload_frame(texture_t tex, const struct source_frame *frame)
|
|||
static void obs_source_draw_texture(texture_t tex, struct source_frame *frame)
|
||||
{
|
||||
effect_t effect = obs->video.default_effect;
|
||||
bool yuv = is_yuv(frame->format);
|
||||
const char *type = yuv ? "DrawYUVToRGB" : "DrawRGB";
|
||||
bool yuv = is_yuv(frame->format);
|
||||
const char *type = yuv ? "DrawYUVToRGB" : "DrawRGB";
|
||||
technique_t tech;
|
||||
eparam_t param;
|
||||
|
||||
|
@ -482,16 +482,49 @@ static void obs_source_render_async_video(obs_source_t source)
|
|||
obs_source_releaseframe(source, frame);
|
||||
}
|
||||
|
||||
static inline void obs_source_render_filters(obs_source_t source)
|
||||
{
|
||||
source->rendering_filter = true;
|
||||
obs_source_video_render(source->filters.array[0]);
|
||||
source->rendering_filter = false;
|
||||
}
|
||||
|
||||
static inline void obs_source_default_render(obs_source_t source, bool yuv)
|
||||
{
|
||||
effect_t effect = obs->video.default_effect;
|
||||
const char *tech_name = yuv ? "DrawYUV" : "DrawRGB";
|
||||
technique_t tech = effect_gettechnique(effect, tech_name);
|
||||
size_t passes, i;
|
||||
|
||||
passes = technique_begin(tech);
|
||||
for (i = 0; i < passes; i++) {
|
||||
technique_beginpass(tech, i);
|
||||
source->callbacks.video_render(source->data);
|
||||
technique_endpass(tech);
|
||||
}
|
||||
technique_end(tech);
|
||||
}
|
||||
|
||||
static inline void obs_source_main_render(obs_source_t source)
|
||||
{
|
||||
uint32_t flags = source->callbacks.get_output_flags(source->data);
|
||||
bool default_effect = !source->filter_parent &&
|
||||
source->filters.num == 0 &&
|
||||
(flags & SOURCE_DEFAULT_EFFECT) != 0;
|
||||
|
||||
if (default_effect)
|
||||
obs_source_default_render(source, (flags & SOURCE_YUV) != 0);
|
||||
else
|
||||
source->callbacks.video_render(source->data);
|
||||
}
|
||||
|
||||
void obs_source_video_render(obs_source_t source)
|
||||
{
|
||||
if (source->callbacks.video_render) {
|
||||
if (source->filters.num && !source->rendering_filter) {
|
||||
source->rendering_filter = true;
|
||||
obs_source_video_render(source->filters.array[0]);
|
||||
source->rendering_filter = false;
|
||||
} else {
|
||||
source->callbacks.video_render(source->data);
|
||||
}
|
||||
if (source->filters.num && !source->rendering_filter)
|
||||
obs_source_render_filters(source);
|
||||
else
|
||||
obs_source_main_render(source);
|
||||
|
||||
} else if (source->filter_target) {
|
||||
obs_source_video_render(source->filter_target);
|
||||
|
@ -531,6 +564,11 @@ void obs_source_setparam(obs_source_t source, const char *param,
|
|||
source->callbacks.setparam(source->data, param, data, size);
|
||||
}
|
||||
|
||||
obs_source_t obs_filter_getparent(obs_source_t filter)
|
||||
{
|
||||
return filter->filter_parent;
|
||||
}
|
||||
|
||||
obs_source_t obs_filter_gettarget(obs_source_t filter)
|
||||
{
|
||||
return filter->filter_target;
|
||||
|
@ -892,3 +930,71 @@ void obs_source_getid(obs_source_t source, enum obs_source_type *type,
|
|||
*type = source->type;
|
||||
*id = source->callbacks.id;
|
||||
}
|
||||
|
||||
static inline void render_filter_bypass(obs_source_t target, effect_t effect,
|
||||
uint32_t width, uint32_t height, bool yuv)
|
||||
{
|
||||
const char *tech_name = yuv ? "DrawYUV" : "DrawRGB";
|
||||
technique_t tech = effect_gettechnique(effect, tech_name);
|
||||
eparam_t diffuse = effect_getparambyname(effect, "diffuse");
|
||||
size_t passes, i;
|
||||
|
||||
passes = technique_begin(tech);
|
||||
for (i = 0; i < passes; i++) {
|
||||
technique_beginpass(tech, i);
|
||||
obs_source_video_render(target);
|
||||
technique_endpass(tech);
|
||||
}
|
||||
technique_end(tech);
|
||||
}
|
||||
|
||||
static inline void render_filter_tex(texture_t tex, effect_t effect,
|
||||
uint32_t width, uint32_t height, bool yuv)
|
||||
{
|
||||
const char *tech_name = yuv ? "DrawYUV" : "DrawRGB";
|
||||
technique_t tech = effect_gettechnique(effect, tech_name);
|
||||
eparam_t diffuse = effect_getparambyname(effect, "diffuse");
|
||||
size_t passes, i;
|
||||
|
||||
effect_settexture(effect, diffuse, tex);
|
||||
|
||||
passes = technique_begin(tech);
|
||||
for (i = 0; i < passes; i++) {
|
||||
technique_beginpass(tech, i);
|
||||
gs_draw_sprite(tex, width, height, 0);
|
||||
technique_endpass(tech);
|
||||
}
|
||||
technique_end(tech);
|
||||
}
|
||||
|
||||
void obs_source_process_filter(obs_source_t filter, texrender_t texrender,
|
||||
effect_t effect, uint32_t width, uint32_t height)
|
||||
{
|
||||
obs_source_t target = obs_filter_gettarget(filter);
|
||||
obs_source_t parent = obs_filter_getparent(filter);
|
||||
uint32_t target_flags = obs_source_get_output_flags(target);
|
||||
uint32_t parent_flags = obs_source_get_output_flags(parent);
|
||||
int cx = obs_source_getwidth(target);
|
||||
int cy = obs_source_getheight(target);
|
||||
bool yuv = (target_flags & SOURCE_YUV) != 0;
|
||||
|
||||
/* if the parent does not use any custom effects, and this is the last
|
||||
* filter in the chain for the parent, then render the parent directly
|
||||
* using the filter effect instead of rendering to texture to reduce
|
||||
* the total number of passes */
|
||||
if ((parent_flags & SOURCE_DEFAULT_EFFECT) != 0 && target == parent) {
|
||||
render_filter_bypass(target, effect, width, height, yuv);
|
||||
return;
|
||||
}
|
||||
|
||||
if (texrender_begin(texrender, cx, cy)) {
|
||||
gs_ortho(0.0f, (float)cx, 0.0f, (float)cy, -100.0f, 100.0f);
|
||||
obs_source_video_render(target);
|
||||
texrender_end(texrender);
|
||||
}
|
||||
|
||||
/* --------------------------- */
|
||||
|
||||
render_filter_tex(texrender_gettexture(texrender), effect,
|
||||
width, height, yuv);
|
||||
}
|
||||
|
|
|
@ -484,3 +484,8 @@ obs_source_t obs_get_source_by_name(const char *name)
|
|||
pthread_mutex_unlock(&data->sources_mutex);
|
||||
return source;
|
||||
}
|
||||
|
||||
effect_t obs_get_default_effect(void)
|
||||
{
|
||||
return obs->video.default_effect;
|
||||
}
|
||||
|
|
11
libobs/obs.h
11
libobs/obs.h
|
@ -264,6 +264,9 @@ EXPORT obs_source_t obs_get_source_by_name(const char *name);
|
|||
*/
|
||||
EXPORT char *obs_find_plugin_file(const char *file);
|
||||
|
||||
/** Returns the default effect for generic RGB/YUV drawing */
|
||||
EXPORT effect_t obs_get_default_effect();
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* Display context */
|
||||
|
@ -356,6 +359,9 @@ EXPORT size_t obs_source_getparam(obs_source_t source, const char *param,
|
|||
EXPORT void obs_source_setparam(obs_source_t source, const char *param,
|
||||
const void *data, size_t size);
|
||||
|
||||
/** If the source is a filter, returns the parent source of the filter */
|
||||
EXPORT obs_source_t obs_filter_getparent(obs_source_t filter);
|
||||
|
||||
/** If the source is a filter, returns the target source of the filter */
|
||||
EXPORT obs_source_t obs_filter_gettarget(obs_source_t filter);
|
||||
|
||||
|
@ -403,6 +409,11 @@ EXPORT struct source_frame *obs_source_getframe(obs_source_t source);
|
|||
EXPORT void obs_source_releaseframe(obs_source_t source,
|
||||
struct source_frame *frame);
|
||||
|
||||
/** Default RGB filter handler for generic effect filters */
|
||||
EXPORT void obs_source_process_filter(obs_source_t filter,
|
||||
texrender_t texrender, effect_t effect,
|
||||
uint32_t width, uint32_t height);
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* Scenes */
|
||||
|
|
|
@ -55,31 +55,6 @@ void test_video_tick(struct test_filter *tf, float seconds)
|
|||
|
||||
void test_video_render(struct test_filter *tf)
|
||||
{
|
||||
obs_source_t filter_target = obs_filter_gettarget(tf->source);
|
||||
int cx = obs_source_getwidth(filter_target);
|
||||
int cy = obs_source_getheight(filter_target);
|
||||
float fcx = (float)cx;
|
||||
float fcy = (float)cy;
|
||||
technique_t tech;
|
||||
texture_t tex;
|
||||
|
||||
if (texrender_begin(tf->texrender, cx, cy)) {
|
||||
gs_ortho(0.0f, fcx, 0.0f, fcy, -100.0f, 100.0f);
|
||||
obs_source_video_render(filter_target);
|
||||
texrender_end(tf->texrender);
|
||||
}
|
||||
|
||||
/* --------------------------- */
|
||||
|
||||
tex = texrender_gettexture(tf->texrender);
|
||||
tech = effect_gettechnique(tf->whatever, "Default");
|
||||
effect_settexture(tf->whatever, effect_getparambyidx(tf->whatever, 1),
|
||||
tex);
|
||||
technique_begin(tech);
|
||||
technique_beginpass(tech, 0);
|
||||
|
||||
gs_draw_sprite(tex, 0, 0, 0);
|
||||
|
||||
technique_endpass(tech);
|
||||
technique_end(tech);
|
||||
obs_source_process_filter(tf->source, tf->texrender, tf->whatever,
|
||||
0, 0);
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ struct random_tex *random_create(const char *settings, obs_source_t source)
|
|||
{
|
||||
struct random_tex *rt = bmalloc(sizeof(struct random_tex));
|
||||
uint32_t *pixels = bmalloc(20*20*4);
|
||||
char *effect_file;
|
||||
size_t x, y;
|
||||
|
||||
memset(rt, 0, sizeof(struct random_tex));
|
||||
|
@ -37,15 +36,6 @@ struct random_tex *random_create(const char *settings, obs_source_t source)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
effect_file = obs_find_plugin_file("test-input/draw.effect");
|
||||
rt->whatever = gs_create_effect_from_file(effect_file, NULL);
|
||||
bfree(effect_file);
|
||||
|
||||
if (!rt->whatever) {
|
||||
random_destroy(rt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gs_leavecontext();
|
||||
|
||||
return rt;
|
||||
|
@ -56,7 +46,6 @@ void random_destroy(struct random_tex *rt)
|
|||
if (rt) {
|
||||
gs_entercontext(obs_graphics());
|
||||
|
||||
effect_destroy(rt->whatever);
|
||||
texture_destroy(rt->texture);
|
||||
bfree(rt);
|
||||
|
||||
|
@ -66,21 +55,16 @@ void random_destroy(struct random_tex *rt)
|
|||
|
||||
uint32_t random_get_output_flags(struct random_tex *rt)
|
||||
{
|
||||
return SOURCE_VIDEO;
|
||||
return SOURCE_VIDEO | SOURCE_DEFAULT_EFFECT;
|
||||
}
|
||||
|
||||
void random_video_render(struct random_tex *rt, obs_source_t filter_target)
|
||||
{
|
||||
technique_t tech = effect_gettechnique(rt->whatever, "Default");
|
||||
effect_settexture(rt->whatever, effect_getparambyidx(rt->whatever, 1),
|
||||
rt->texture);
|
||||
technique_begin(tech);
|
||||
technique_beginpass(tech, 0);
|
||||
effect_t effect = gs_geteffect();
|
||||
eparam_t diffuse = effect_getparambyname(effect, "diffuse");
|
||||
|
||||
effect_settexture(effect, diffuse, rt->texture);
|
||||
gs_draw_sprite(rt->texture, 0, 0, 0);
|
||||
|
||||
technique_endpass(tech);
|
||||
technique_end(tech);
|
||||
}
|
||||
|
||||
uint32_t random_getwidth(struct random_tex *rt)
|
||||
|
|
|
@ -8,16 +8,17 @@ extern "C" {
|
|||
|
||||
struct random_tex {
|
||||
texture_t texture;
|
||||
effect_t whatever;
|
||||
};
|
||||
|
||||
EXPORT const char *random_getname(const char *locale);
|
||||
|
||||
EXPORT struct random_tex *random_create(const char *settings, obs_source_t source);
|
||||
EXPORT struct random_tex *random_create(const char *settings,
|
||||
obs_source_t source);
|
||||
EXPORT void random_destroy(struct random_tex *rt);
|
||||
EXPORT uint32_t random_get_output_flags(struct random_tex *rt);
|
||||
|
||||
EXPORT void random_video_render(struct random_tex *rt, obs_source_t filter_target);
|
||||
EXPORT void random_video_render(struct random_tex *rt,
|
||||
obs_source_t filter_target);
|
||||
|
||||
EXPORT uint32_t random_getwidth(struct random_tex *rt);
|
||||
EXPORT uint32_t random_getheight(struct random_tex *rt);
|
||||
|
|
Loading…
Reference in a new issue