@@ -23,10 +23,11 @@ struct win_spout_filter
2323 spoutDX* filter_sender;
2424 obs_source_t * source_context;
2525 const char * sender_name;
26- pthread_mutex_t mutex;
2726 uint32_t width;
2827 uint32_t height;
29- gs_texrender_t * texrender;
28+ gs_texrender_t * texrender_curr;
29+ gs_texrender_t * texrender_prev;
30+ gs_texrender_t * texrender_intermediate;
3031 gs_stagesurf_t * stagesurface;
3132 video_t * video_output;
3233 uint8_t * video_data;
@@ -80,17 +81,6 @@ void win_spout_filter_getdefaults(obs_data_t* defaults)
8081 obs_module_text (" defaultfiltername" ));
8182}
8283
83- void win_spout_filter_raw_video (void * data, video_data* frame)
84- {
85- struct win_spout_filter * context = (win_spout_filter*)data;
86-
87- if (!frame|| !frame->data [0 ]) return ;
88-
89- pthread_mutex_lock (&context->mutex );
90- context->filter_sender ->SendImage (frame->data [0 ], context->width , context->height );
91- pthread_mutex_unlock (&context->mutex );
92- }
93-
9484void win_spout_offscreen_render (void * data, uint32_t cx, uint32_t cy)
9585{
9686
@@ -104,76 +94,76 @@ void win_spout_offscreen_render(void* data, uint32_t cx, uint32_t cy)
10494 uint32_t width = obs_source_get_base_width (target);
10595 uint32_t height = obs_source_get_base_height (target);
10696
107- gs_texrender_reset (context->texrender );
108-
109- if (gs_texrender_begin (context->texrender , width, height))
110- {
97+ // Render the target to an intemediate format in sRGB-aware format
98+ gs_texrender_reset (context->texrender_intermediate );
99+ if (gs_texrender_begin (context->texrender_intermediate , width, height)) {
111100 struct vec4 background;
112101 vec4_zero (&background);
113102
114103 gs_clear (GS_CLEAR_COLOR, &background, 0 .0f , 0 );
115- gs_ortho (0 .0f , (float )width, 0 .0f , (float )height, -100 .0f , 100 .0f );
104+ gs_ortho (0 .0f , (float )width, 0 .0f , (float )height, -100 .0f ,
105+ 100 .0f );
116106
117107 gs_blend_state_push ();
118108 gs_blend_function (GS_BLEND_ONE, GS_BLEND_ZERO);
119109
120110 obs_source_video_render (target);
121111
122112 gs_blend_state_pop ();
123- gs_texrender_end (context->texrender );
113+ gs_texrender_end (context->texrender_intermediate );
114+ }
115+
116+ // Use the default effect to render it back into a format Spout accepts
117+ gs_texrender_reset (context->texrender_curr );
118+ if (gs_texrender_begin (context->texrender_curr , width, height))
119+ {
120+ struct vec4 background;
121+ vec4_zero (&background);
124122
125- if (context-> width != width || context-> height != height)
126- {
123+ gs_clear (GS_CLEAR_COLOR, &background, 0 . 0f , 0 );
124+ gs_ortho ( 0 . 0f , ( float )width, 0 . 0f , ( float )height, - 100 . 0f , 100 . 0f );
127125
128- gs_stagesurface_destroy (context-> stagesurface );
129- context-> stagesurface = gs_stagesurface_create (width, height, GS_BGRA );
126+ gs_blend_state_push ( );
127+ gs_blend_function (GS_BLEND_ONE, GS_BLEND_ZERO );
130128
131- video_output_info video_out = { 0 };
132- video_out.format = VIDEO_FORMAT_BGRA;
133- video_out.width = width;
134- video_out.height = height;
135- video_out.fps_den = context->video_info .fps_den ;
136- video_out.fps_num = context->video_info .fps_num ;
137- video_out.cache_size = 16 ;
138- video_out.colorspace = VIDEO_CS_DEFAULT;
139- video_out.range = VIDEO_RANGE_DEFAULT;
140- video_out.name = obs_source_get_name (context->source_context );
129+ // To get sRGB handling, render with the default effect
130+ gs_effect_t *effect = obs_get_base_effect (OBS_EFFECT_DEFAULT);
131+ gs_texture_t *tex = gs_texrender_get_texture (context->texrender_intermediate );
132+ if (tex) {
133+ const bool linear_srgb = gs_get_linear_srgb ();
141134
142- video_output_close (context->video_output );
135+ const bool previous = gs_framebuffer_srgb_enabled ();
136+ gs_enable_framebuffer_srgb (linear_srgb);
143137
144- context->width = width;
145- context->height = height;
146- video_output_open (&context->video_output , &video_out);
147- video_output_connect (context->video_output , nullptr , win_spout_filter_raw_video, context);
138+ gs_eparam_t *image =
139+ gs_effect_get_param_by_name (effect, " image" );
140+ if (linear_srgb)
141+ gs_effect_set_texture_srgb (image, tex);
142+ else
143+ gs_effect_set_texture (image, tex);
148144
145+ while (gs_effect_loop (effect, " Draw" ))
146+ gs_draw_sprite (tex, 0 , width, height);
149147
148+ gs_enable_framebuffer_srgb (previous);
150149 }
151150
152- struct video_frame output_frame;
153- if (video_output_lock_frame (context->video_output ,
154- &output_frame, 1 , obs_get_video_frame_time ()))
155- {
156- if (context->video_data ) {
157- gs_stagesurface_unmap (context->stagesurface );
158- context->video_data = nullptr ;
159- }
160-
161- gs_stage_texture (context->stagesurface ,
162- gs_texrender_get_texture (context->texrender ));
163- gs_stagesurface_map (context->stagesurface ,
164- &context->video_data , &context->video_linesize );
165-
166- uint32_t linesize = output_frame.linesize [0 ];
167- for (uint32_t i = 0 ; i < context->height ; ++i) {
168- uint32_t dst_offset = linesize * i;
169- uint32_t src_offset = context->video_linesize * i;
170- memcpy (output_frame.data [0 ] + dst_offset,
171- context->video_data + src_offset,
172- linesize);
173- }
174-
175- video_output_unlock_frame (context->video_output );
151+ gs_blend_state_pop ();
152+ gs_texrender_end (context->texrender_curr );
153+
154+ gs_texture_t *prev_tex =
155+ gs_texrender_get_texture (context->texrender_prev );
156+ if (prev_tex) {
157+ context->filter_sender ->SendTexture ((
158+ ID3D11Texture2D *)gs_texture_get_obj (prev_tex));
176159 }
160+
161+ // Swap the buffers
162+ // Double-buffering avoids the need for a flush, and also fixes
163+ // some issues related to G-Sync.
164+ gs_texrender_t *tmp = context->texrender_curr ;
165+ context->texrender_curr = context->texrender_prev ;
166+ context->texrender_prev = tmp;
177167 }
178168}
179169
@@ -194,7 +184,11 @@ void* win_spout_filter_create(obs_data_t* settings, obs_source_t* source)
194184 struct win_spout_filter * context = (win_spout_filter*)bzalloc (sizeof (win_spout_filter));
195185
196186 context->source_context = source;
197- context->texrender = gs_texrender_create (GS_BGRA, GS_ZS_NONE);
187+ // Use a Spout-compatible texture format
188+ context->texrender_curr = gs_texrender_create (GS_BGRA_UNORM, GS_ZS_NONE);
189+ context->texrender_prev = gs_texrender_create (GS_BGRA_UNORM, GS_ZS_NONE);
190+ context->texrender_intermediate =
191+ gs_texrender_create (GS_BGRA, GS_ZS_NONE);
198192 context->sender_name = obs_data_get_string (settings, FILTER_PROP_NAME);
199193 context->video_data = nullptr ;
200194
@@ -203,15 +197,9 @@ void* win_spout_filter_create(obs_data_t* settings, obs_source_t* source)
203197 obs_get_video_info (&context->video_info );
204198 win_spout_filter_update (context, settings);
205199
206-
207-
208200 if (openDX11 (context))
209201 {
210- pthread_mutex_init_value (&context->mutex );
211- if (pthread_mutex_init (&context->mutex , NULL ) == 0 )
212- {
213- return context;
214- }
202+ return context;
215203 }
216204
217205 blog (LOG_ERROR, " Failed to create spout output!" );
@@ -234,8 +222,9 @@ void win_spout_filter_destroy(void* data)
234222 video_output_close (context->video_output );
235223 gs_stagesurface_unmap (context->stagesurface );
236224 gs_stagesurface_destroy (context->stagesurface );
237- gs_texrender_destroy (context->texrender );
238- pthread_mutex_destroy (&context->mutex );
225+ gs_texrender_destroy (context->texrender_intermediate );
226+ gs_texrender_destroy (context->texrender_prev );
227+ gs_texrender_destroy (context->texrender_curr );
239228 bfree (context);
240229 }
241230}
@@ -259,7 +248,7 @@ struct obs_source_info create_spout_filter_info()
259248 struct obs_source_info win_spout_filter_info = {};
260249 win_spout_filter_info.id = " win_spout_filter" ;
261250 win_spout_filter_info.type = OBS_SOURCE_TYPE_FILTER;
262- win_spout_filter_info.output_flags = OBS_SOURCE_VIDEO;
251+ win_spout_filter_info.output_flags = OBS_SOURCE_VIDEO | OBS_SOURCE_SRGB ;
263252 win_spout_filter_info.get_name = win_spout_filter_getname;
264253 win_spout_filter_info.get_properties = win_spout_filter_getproperties;
265254 win_spout_filter_info.get_defaults = win_spout_filter_getdefaults;
0 commit comments