Kaynağa Gözat

add major optimization to filter processing, and as a nice side effect, make it easier to create new filters and sources

jp9000 12 yıl önce
ebeveyn
işleme
19c4ee995e

+ 4 - 4
build/data/libobs/default.effect

@@ -1,6 +1,6 @@
 uniform float4x4 ViewProj;
 uniform float4x4 ViewProj;
 uniform float4x4 yuv_matrix;
 uniform float4x4 yuv_matrix;
-uniform texture2d tex;
+uniform texture2d diffuse;
 
 
 sampler_state def_sampler {
 sampler_state def_sampler {
 	Filter   = Linear;
 	Filter   = Linear;
@@ -16,19 +16,19 @@ struct VertInOut {
 VertInOut VSDefault(VertInOut vert_in)
 VertInOut VSDefault(VertInOut vert_in)
 {
 {
 	VertInOut vert_out;
 	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;
 	vert_out.uv  = vert_in.uv;
 	return vert_out;
 	return vert_out;
 }
 }
 
 
 float4 PSDrawRGB(VertInOut vert_in) : TARGET
 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 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));
 	return saturate(mul(float4(yuv.xyz, 1.0), yuv_matrix));
 }
 }
 
 

+ 1 - 1
build/data/obs-plugins/test-input/test.effect

@@ -27,7 +27,7 @@ float4 PShader(VertexInOut fragment_in) : TARGET
 	return diffuse.Sample(texSampler, fragment_in.uv) * color;
 	return diffuse.Sample(texSampler, fragment_in.uv) * color;
 }
 }
 
 
-technique Default
+technique DrawRGB
 {
 {
 	pass
 	pass
 	{
 	{

+ 2 - 0
libobs/obs-defs.h

@@ -29,3 +29,5 @@
 #define SOURCE_VIDEO          (1<<0) /* Source has video */
 #define SOURCE_VIDEO          (1<<0) /* Source has video */
 #define SOURCE_AUDIO          (1<<1) /* Source has audio */
 #define SOURCE_AUDIO          (1<<1) /* Source has audio */
 #define SOURCE_ASYNC_VIDEO    (1<<2) /* Async video (use with SOURCE_VIDEO) */
 #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 */

+ 115 - 9
libobs/obs-source.c

@@ -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)
 static void obs_source_draw_texture(texture_t tex, struct source_frame *frame)
 {
 {
 	effect_t    effect = obs->video.default_effect;
 	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;
 	technique_t tech;
 	eparam_t    param;
 	eparam_t    param;
 
 
@@ -482,16 +482,49 @@ static void obs_source_render_async_video(obs_source_t source)
 	obs_source_releaseframe(source, frame);
 	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)
 void obs_source_video_render(obs_source_t source)
 {
 {
 	if (source->callbacks.video_render) {
 	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) {
 	} else if (source->filter_target) {
 		obs_source_video_render(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);
 		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)
 obs_source_t obs_filter_gettarget(obs_source_t filter)
 {
 {
 	return filter->filter_target;
 	return filter->filter_target;
@@ -892,3 +930,71 @@ void obs_source_getid(obs_source_t source, enum obs_source_type *type,
 	*type = source->type;
 	*type = source->type;
 	*id   = source->callbacks.id;
 	*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);
+}

+ 5 - 0
libobs/obs.c

@@ -484,3 +484,8 @@ obs_source_t obs_get_source_by_name(const char *name)
 	pthread_mutex_unlock(&data->sources_mutex);
 	pthread_mutex_unlock(&data->sources_mutex);
 	return source;
 	return source;
 }
 }
+
+effect_t obs_get_default_effect(void)
+{
+	return obs->video.default_effect;
+}

+ 11 - 0
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);
 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 */
 /* 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,
 EXPORT void obs_source_setparam(obs_source_t source, const char *param,
 		const void *data, size_t size);
 		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 */
 /** If the source is a filter, returns the target source of the filter */
 EXPORT obs_source_t obs_filter_gettarget(obs_source_t 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,
 EXPORT void obs_source_releaseframe(obs_source_t source,
 		struct source_frame *frame);
 		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 */
 /* Scenes */

+ 2 - 27
test/test-input/test-filter.c

@@ -55,31 +55,6 @@ void test_video_tick(struct test_filter *tf, float seconds)
 
 
 void test_video_render(struct test_filter *tf)
 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);
 }
 }

+ 4 - 20
test/test-input/test-random.c

@@ -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));
 	struct random_tex *rt = bmalloc(sizeof(struct random_tex));
 	uint32_t *pixels = bmalloc(20*20*4);
 	uint32_t *pixels = bmalloc(20*20*4);
-	char *effect_file;
 	size_t x, y;
 	size_t x, y;
 
 
 	memset(rt, 0, sizeof(struct random_tex));
 	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;
 		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();
 	gs_leavecontext();
 
 
 	return rt;
 	return rt;
@@ -56,7 +46,6 @@ void random_destroy(struct random_tex *rt)
 	if (rt) {
 	if (rt) {
 		gs_entercontext(obs_graphics());
 		gs_entercontext(obs_graphics());
 
 
-		effect_destroy(rt->whatever);
 		texture_destroy(rt->texture);
 		texture_destroy(rt->texture);
 		bfree(rt);
 		bfree(rt);
 
 
@@ -66,21 +55,16 @@ void random_destroy(struct random_tex *rt)
 
 
 uint32_t random_get_output_flags(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)
 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);
 	gs_draw_sprite(rt->texture, 0, 0, 0);
-
-	technique_endpass(tech);
-	technique_end(tech);
 }
 }
 
 
 uint32_t random_getwidth(struct random_tex *rt)
 uint32_t random_getwidth(struct random_tex *rt)

+ 4 - 3
test/test-input/test-random.h

@@ -8,16 +8,17 @@ extern "C" {
 
 
 struct random_tex {
 struct random_tex {
 	texture_t texture;
 	texture_t texture;
-	effect_t  whatever;
 };
 };
 
 
 EXPORT const char *random_getname(const char *locale);
 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 void random_destroy(struct random_tex *rt);
 EXPORT uint32_t random_get_output_flags(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_getwidth(struct random_tex *rt);
 EXPORT uint32_t random_getheight(struct random_tex *rt);
 EXPORT uint32_t random_getheight(struct random_tex *rt);