Pārlūkot izejas kodu

Implement output scaling/conversion/downloading

- Implement texture scaling/conversion/downloading for the main view so
  we can finally start getting data to output.

  Also, redesign how it works a bit, it will now properly wait one full
  frame for each step in the process:  rendering the main texture,
  scaling the main texture to an output texture, staging/downloading the
  ouput texture, and then outputting that staged data.  This way, the
  GPU will have more than enough time to fully complete each step.

- Fix a bug with OpenGL plugin's texture staging function.  Was using
  glBindBuffer instead of what should have been used:  glBindTexture.

- Change the naming scheme of the variables in default.effect.  It's now
  named with the idea of just "color matrix" in mind instead of "yuv
  matrix", and instead of DrawRGBToYUV, it's now just DrawMatrix.
jp9000 11 gadi atpakaļ
vecāks
revīzija
ab4ab95790

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

@@ -1,5 +1,5 @@
 uniform float4x4 ViewProj;
-uniform float4x4 yuv_matrix;
+uniform float4x4 color_matrix;
 uniform texture2d diffuse;
 
 sampler_state def_sampler {
@@ -21,31 +21,31 @@ VertInOut VSDefault(VertInOut vert_in)
 	return vert_out;
 }
 
-float4 PSDrawRGB(VertInOut vert_in) : TARGET
+float4 PSDrawBare(VertInOut vert_in) : TARGET
 {
 	return diffuse.Sample(def_sampler, vert_in.uv);
 }
 
-float4 PSDrawYUVToRGB(VertInOut vert_in) : TARGET
+float4 PSDrawMatrix(VertInOut vert_in) : TARGET
 {
 	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), color_matrix));
 }
 
-technique DrawRGB
+technique Draw
 {
 	pass
 	{
 		vertex_shader = VSDefault(vert_in);
-		pixel_shader  = PSDrawRGB(vert_in);
+		pixel_shader  = PSDrawBare(vert_in);
 	}
 }
 
-technique DrawYUV
+technique DrawMatrix
 {
 	pass
 	{
 		vertex_shader = VSDefault(vert_in);
-		pixel_shader  = PSDrawYUVToRGB(vert_in);
+		pixel_shader  = PSDrawMatrix(vert_in);
 	}
 }

+ 1 - 1
libobs-opengl/gl-stagesurf.c

@@ -144,7 +144,7 @@ void device_stage_texture(device_t device, stagesurf_t dst, texture_t src)
 				dst->width, dst->height))
 		goto failed;
 
-	if (!gl_bind_buffer(GL_TEXTURE_2D, dst->texture))
+	if (!gl_bind_texture(GL_TEXTURE_2D, dst->texture))
 		goto failed;
 	if (!gl_bind_buffer(GL_PIXEL_PACK_BUFFER, dst->pack_buffer))
 		goto failed;

+ 4 - 2
libobs/obs-internal.h

@@ -56,9 +56,11 @@ struct obs_video {
 	stagesurf_t                 copy_surfaces[NUM_TEXTURES];
 	texture_t                   render_textures[NUM_TEXTURES];
 	texture_t                   output_textures[NUM_TEXTURES];
-	effect_t                    default_effect;
+	bool                        textures_rendered[NUM_TEXTURES];
+	bool                        textures_output[NUM_TEXTURES];
 	bool                        textures_copied[NUM_TEXTURES];
-	bool                        copy_mapped;
+	effect_t                    default_effect;
+	stagesurf_t                 mapped_surface;
 	int                         cur_texture;
 
 	video_t                     video;

+ 6 - 6
libobs/obs-source.c

@@ -485,7 +485,7 @@ 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 ? "DrawYUV" : "DrawRGB";
+	const char  *type  = yuv ? "DrawMatrix" : "Draw";
 	technique_t tech;
 	eparam_t    param;
 
@@ -497,8 +497,8 @@ static void obs_source_draw_texture(texture_t tex, struct source_frame *frame)
 	technique_beginpass(tech, 0);
 
 	if (yuv) {
-		param = effect_getparambyname(effect, "yuv_matrix");
-		effect_setval(effect, param, frame->yuv_matrix,
+		param = effect_getparambyname(effect, "color_matrix");
+		effect_setval(effect, param, frame->color_matrix,
 				sizeof(float) * 16);
 	}
 
@@ -533,7 +533,7 @@ static inline void obs_source_render_filters(obs_source_t source)
 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";
+	const char  *tech_name = yuv ? "DrawMatrix" : "Draw";
 	technique_t tech       = effect_gettechnique(effect, tech_name);
 	size_t      passes, i;
 
@@ -979,7 +979,7 @@ void obs_source_gettype(obs_source_t source, enum obs_source_type *type,
 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";
+	const char  *tech_name = yuv ? "DrawMatrix" : "Draw";
 	technique_t tech       = effect_gettechnique(effect, tech_name);
 	eparam_t    diffuse    = effect_getparambyname(effect, "diffuse");
 	size_t      passes, i;
@@ -996,7 +996,7 @@ static inline void render_filter_bypass(obs_source_t target, effect_t effect,
 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";
+	const char  *tech_name = yuv ? "DrawMatrix" : "Draw";
 	technique_t tech       = effect_gettechnique(effect, tech_name);
 	eparam_t    diffuse    = effect_getparambyname(effect, "diffuse");
 	size_t      passes, i;

+ 145 - 35
libobs/obs-video.c

@@ -36,7 +36,7 @@ static void tick_sources(uint64_t cur_time, uint64_t *last_time)
 	*last_time = cur_time;
 }
 
-static inline void render_begin(struct obs_display *display)
+static inline void render_display_begin(struct obs_display *display)
 {
 	struct vec4 clear_color;
 	uint32_t width, height;
@@ -54,11 +54,12 @@ static inline void render_begin(struct obs_display *display)
 	/* gs_enable_blending(false); */
 	gs_setcullmode(GS_NEITHER);
 
-	gs_ortho(0.0f, (float)width, 0.0f, (float)height, -100.0f, 100.0f);
+	gs_ortho(0.0f, (float)obs->video.base_width,
+			0.0f, (float)obs->video.base_height, -100.0f, 100.0f);
 	gs_setviewport(0, 0, width, height);
 }
 
-static inline void render_end(struct obs_display *display)
+static inline void render_display_end(struct obs_display *display)
 {
 	gs_endscene();
 	gs_present();
@@ -66,10 +67,9 @@ static inline void render_end(struct obs_display *display)
 
 static void render_display(struct obs_display *display)
 {
-	size_t i;
-	render_begin(display);
+	render_display_begin(display);
 
-	for (i = 0; i < MAX_CHANNELS; i++) {
+	for (size_t i = 0; i < MAX_CHANNELS; i++) {
 		struct obs_source **p_source;
 
 		p_source = (display) ? display->channels+i :
@@ -85,22 +85,19 @@ static void render_display(struct obs_display *display)
 		}
 	}
 
-	render_end(display);
+	render_display_end(display);
 }
 
 static inline void render_displays(void)
 {
-	size_t i;
-
 	if (!obs->data.valid)
 		return;
 
 	/* render extra displays/swaps */
 	pthread_mutex_lock(&obs->data.displays_mutex);
 
-	for (i = 0; i < obs->data.displays.num; i++) {
+	for (size_t i = 0; i < obs->data.displays.num; i++)
 		render_display(obs->data.displays.array[i]);
-	}
 
 	pthread_mutex_unlock(&obs->data.displays_mutex);
 
@@ -108,38 +105,151 @@ static inline void render_displays(void)
 	render_display(NULL);
 }
 
-static bool swap_frame(uint64_t timestamp)
+static inline void set_render_size(uint32_t width, uint32_t height)
 {
-	struct obs_video *video = &obs->video;
-	stagesurf_t last_surface = video->copy_surfaces[video->cur_texture];
-	stagesurf_t surface;
-	struct video_frame frame;
+	gs_ortho(0.0f, (float)width, 0.0f, (float)height, -100.0f, 100.0f);
+	gs_setviewport(0, 0, width, height);
+}
+
+static inline void render_channels(void)
+{
+	struct obs_program_data *data = &obs->data;
 
-	/* the last frame stays mapped until rendering starts with the next */
-	if (video->copy_mapped) {
-		stagesurface_unmap(last_surface);
-		video->copy_mapped = false;
+	for (size_t i = 0; i < MAX_CHANNELS; i++) {
+		struct obs_source *source = data->channels[i];
+		if (source)
+			obs_source_video_render(source);
+	}
+}
+
+static inline void unmap_last_surface(struct obs_video *video)
+{
+	if (video->mapped_surface) {
+		stagesurface_unmap(video->mapped_surface);
+		video->mapped_surface = NULL;
 	}
+}
 
-	video->textures_copied[video->cur_texture] = true;
-	/* TODO: texture staging */
-	//gs_stage_texture(last_surface, );
+static inline void render_main_texture(struct obs_video *video, int cur_texture,
+		int prev_texture)
+{
+	struct vec4 clear_color;
+	vec4_set(&clear_color, 0.3f, 0.0f, 0.0f, 1.0f);
 
-	if (++video->cur_texture == NUM_TEXTURES)
-		video->cur_texture = 0;
+	gs_setrendertarget(video->render_textures[cur_texture], NULL);
+	gs_clear(GS_CLEAR_COLOR, &clear_color, 1.0f, 0);
 
-	if (video->textures_copied[video->cur_texture]) {
-		surface = video->copy_surfaces[video->cur_texture];
-		video->copy_mapped = stagesurface_map(surface, &frame.data,
-				&frame.row_size);
+	set_render_size(video->base_width, video->base_height);
+	render_channels();
 
-		if (video->copy_mapped) {
-			frame.timestamp = timestamp;
-			video_output_frame(video->video, &frame);
-		}
+	video->textures_rendered[cur_texture] = true;
+}
+
+static inline void render_output_texture(struct obs_video *video,
+		int cur_texture, int prev_texture)
+{
+	texture_t   texture = video->render_textures[prev_texture];
+	texture_t   target  = video->output_textures[cur_texture];
+	uint32_t    width   = texture_getwidth(target);
+	uint32_t    height  = texture_getheight(target);
+
+	/* TODO: replace with actual downscalers or unpackers */
+	effect_t    effect  = video->default_effect;
+	technique_t tech    = effect_gettechnique(effect, "DrawMatrix");
+	eparam_t    diffuse = effect_getparambyname(effect, "diffuse");
+	eparam_t    matrix  = effect_getparambyname(effect, "color_matrix");
+	size_t      passes, i;
+
+	if (!video->textures_rendered[prev_texture])
+		return;
+
+	gs_setrendertarget(target, NULL);
+	set_render_size(width, height);
+
+	/* TODO: replace with programmable code */
+	const float mat_val[16] =
+	{
+		 0.256788f,  0.504129f,  0.097906f,  0.062745f,
+		-0.148223f, -0.290993f,  0.439216f,  0.501961f,
+		 0.439216f, -0.367788f, -0.071427f,  0.501961f,
+		 0.000000f,  0.000000f,  0.000000f,  1.000000f
+	};
+
+	effect_setval(effect, matrix, mat_val, sizeof(mat_val));
+	effect_settexture(effect, diffuse, texture);
+
+	passes = technique_begin(tech);
+	for (i = 0; i < passes; i++) {
+		technique_beginpass(tech, i);
+		gs_draw_sprite(texture, 0, width, height);
+		technique_endpass(tech);
+	}
+	technique_end(tech);
+
+	video->textures_output[cur_texture] = true;
+}
+
+static inline void stage_output_texture(struct obs_video *video,
+		int cur_texture, int prev_texture)
+{
+	texture_t   texture = video->output_textures[prev_texture];
+	stagesurf_t copy    = video->copy_surfaces[cur_texture];
+
+	unmap_last_surface(video);
+
+	if (!video->textures_output[prev_texture])
+		return;
+
+	gs_stage_texture(copy, texture);
+
+	video->textures_copied[cur_texture] = true;
+}
+
+static inline void render_video(struct obs_video *video, int cur_texture,
+		int prev_texture)
+{
+	gs_beginscene();
+
+	gs_enable_depthtest(false);
+	gs_setcullmode(GS_NEITHER);
+
+	render_main_texture(video, cur_texture, prev_texture);
+	render_output_texture(video, cur_texture, prev_texture);
+	stage_output_texture(video, cur_texture, prev_texture);
+
+	gs_setrendertarget(NULL, NULL);
+
+	gs_endscene();
+}
+
+static inline void output_video(struct obs_video *video, int cur_texture,
+		int prev_texture, uint64_t timestamp)
+{
+	stagesurf_t surface = video->copy_surfaces[prev_texture];
+	struct video_frame frame;
+
+	if (!video->textures_copied[prev_texture])
+		return;
+
+	frame.timestamp = timestamp;
+
+	if (stagesurface_map(surface, &frame.data, &frame.row_size)) {
+		video->mapped_surface = surface;
+		video_output_frame(video->video, &frame);
 	}
+}
+
+static inline void output_frame(uint64_t timestamp)
+{
+	struct obs_video *video = &obs->video;
+	int cur_texture  = video->cur_texture;
+	int prev_texture = cur_texture == 0 ? NUM_TEXTURES-1 : cur_texture-1;
+
+	render_video(video, cur_texture, prev_texture);
+	output_video(video, cur_texture, prev_texture, timestamp);
 
-	return video->copy_mapped;
+	if (++video->cur_texture == NUM_TEXTURES)
+		video->cur_texture = 0;
 }
 
 void *obs_video_thread(void *param)
@@ -153,7 +263,7 @@ void *obs_video_thread(void *param)
 
 		tick_sources(cur_time, &last_time);
 		render_displays();
-		swap_frame(cur_time);
+		output_frame(cur_time);
 
 		gs_leavecontext();
 	}

+ 2 - 2
libobs/obs.c

@@ -171,8 +171,8 @@ static void obs_free_graphics()
 		int cur_texture = video->cur_texture;
 		gs_entercontext(video->graphics);
 
-		if (video->copy_mapped)
-			stagesurface_unmap(video->copy_surfaces[cur_texture]);
+		if (video->mapped_surface)
+			stagesurface_unmap(video->mapped_surface);
 
 		for (i = 0; i < NUM_TEXTURES; i++) {
 			stagesurface_destroy(video->copy_surfaces[i]);

+ 1 - 1
libobs/obs.h

@@ -122,7 +122,7 @@ struct source_frame {
 	uint64_t            timestamp;
 
 	enum video_format   format;
-	float               yuv_matrix[16];
+	float               color_matrix[16];
 	bool                flip;
 };