1
1
#include <obs-module.h>
2
+ #include <obs-nix-platform.h>
2
3
#include <glad/glad.h>
3
4
#include <glad/glad_glx.h>
4
5
#include <X11/Xlib-xcb.h>
@@ -58,7 +59,6 @@ struct xcompcap {
58
59
59
60
Pixmap pixmap ;
60
61
GLXPixmap glxpixmap ;
61
- gs_texture_t * tex ;
62
62
gs_texture_t * gltex ;
63
63
64
64
pthread_mutex_t lock ;
@@ -72,6 +72,7 @@ struct xcompcap {
72
72
// performance when this is done, so setting this to false allows working
73
73
// around it.
74
74
bool strict_binding ;
75
+ bool egl ;
75
76
};
76
77
77
78
static void xcompcap_update (void * data , obs_data_t * settings );
@@ -375,11 +376,6 @@ void xcomp_cleanup_pixmap(Display *disp, struct xcompcap *s)
375
376
XFreePixmap (disp , s -> pixmap );
376
377
s -> pixmap = 0 ;
377
378
}
378
-
379
- if (s -> tex ) {
380
- gs_texture_destroy (s -> tex );
381
- s -> tex = 0 ;
382
- }
383
379
}
384
380
385
381
static enum gs_color_format gs_format_from_tex ()
@@ -479,96 +475,102 @@ void xcomp_create_pixmap(xcb_connection_t *conn, Display *disp,
479
475
return ;
480
476
}
481
477
482
- const int config_attrs [] = {GLX_BIND_TO_TEXTURE_RGBA_EXT ,
483
- GL_TRUE ,
484
- GLX_DRAWABLE_TYPE ,
485
- GLX_PIXMAP_BIT ,
486
- GLX_BIND_TO_TEXTURE_TARGETS_EXT ,
487
- GLX_TEXTURE_2D_BIT_EXT ,
488
- GLX_DOUBLEBUFFER ,
489
- GL_FALSE ,
490
- None };
491
- int nelem = 0 ;
492
- GLXFBConfig * configs =
493
- glXChooseFBConfig (disp , xcb_get_screen_for_root (conn , root ),
494
- config_attrs , & nelem );
495
-
496
- bool found = false;
497
- GLXFBConfig config ;
498
- for (int i = 0 ; i < nelem ; i ++ ) {
499
- config = configs [i ];
500
- XVisualInfo * visual = glXGetVisualFromFBConfig (disp , config );
501
- if (!visual )
502
- continue ;
503
-
504
- found = depth == visual -> depth ;
505
- XFree (visual );
506
- if (found )
507
- break ;
508
- }
509
- XFree (configs );
510
- if (!found ) {
511
- blog (log_level , "no matching fb config found" );
512
- s -> pixmap = 0 ;
513
- return ;
514
- }
515
-
516
- // Should be consistent format with config we are using. Since we searched on RGBA let's use RGBA here.
517
- const int pixmap_attrs [] = {GLX_TEXTURE_TARGET_EXT , GLX_TEXTURE_2D_EXT ,
518
- GLX_TEXTURE_FORMAT_EXT ,
519
- GLX_TEXTURE_FORMAT_RGBA_EXT , None };
520
-
521
- // Try very hard to capture errors in glXCreatePixmap for NVIDIA drivers
522
- // where only one pixmap can be bound in GLX at a time.
523
- pixmap_err = false;
524
- XErrorHandler prev = XSetErrorHandler (catch_pixmap_errors );
525
- s -> glxpixmap = glXCreatePixmap (disp , config , s -> pixmap , pixmap_attrs );
526
- XSync (disp , false);
527
-
528
- s -> gltex = gs_texture_create (s -> width , s -> height , GS_RGBA_UNORM , 1 , 0 ,
529
- GS_GL_DUMMYTEX );
530
- GLuint gltex = * (GLuint * )gs_texture_get_obj (s -> gltex );
531
- glBindTexture (GL_TEXTURE_2D , gltex );
532
- // Not respecting a captured glXCreatePixmap error will result in Xorg closing our connection.
533
- if (!pixmap_err )
534
- glXBindTexImageEXT (disp , s -> glxpixmap , GLX_FRONT_EXT , NULL );
535
- glTexParameteri (GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR );
536
- glTexParameteri (GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR );
537
- // glxBindTexImageEXT might modify the textures format.
538
- enum gs_color_format format = gs_format_from_tex ();
539
- // Check if texture is invalid... because X11 hates us.
540
- int w ;
541
- int h ;
542
- glGetTexLevelParameteriv (GL_TEXTURE_2D , 0 , GL_TEXTURE_WIDTH , & w );
543
- glGetTexLevelParameteriv (GL_TEXTURE_2D , 0 , GL_TEXTURE_HEIGHT , & h );
544
- glBindTexture (GL_TEXTURE_2D , 0 );
545
- // We must sync OBS texture format based on any glxBindTexImageEXT changes.
546
- s -> gltex -> format = format ;
478
+ if (s -> egl ) {
479
+ s -> gltex = gs_texture_create_from_pixmap (s -> width , s -> height ,
480
+ GS_BGRA_UNORM ,
481
+ GL_TEXTURE_2D ,
482
+ (void * )s -> pixmap );
483
+
484
+ } else {
485
+ const int config_attrs [] = {GLX_BIND_TO_TEXTURE_RGBA_EXT ,
486
+ GL_TRUE ,
487
+ GLX_DRAWABLE_TYPE ,
488
+ GLX_PIXMAP_BIT ,
489
+ GLX_BIND_TO_TEXTURE_TARGETS_EXT ,
490
+ GLX_TEXTURE_2D_BIT_EXT ,
491
+ GLX_DOUBLEBUFFER ,
492
+ GL_FALSE ,
493
+ None };
494
+ int nelem = 0 ;
495
+ GLXFBConfig * configs = glXChooseFBConfig (
496
+ disp , xcb_get_screen_for_root (conn , root ), config_attrs ,
497
+ & nelem );
498
+
499
+ bool found = false;
500
+ GLXFBConfig config ;
501
+ for (int i = 0 ; i < nelem ; i ++ ) {
502
+ config = configs [i ];
503
+ XVisualInfo * visual =
504
+ glXGetVisualFromFBConfig (disp , config );
505
+ if (!visual )
506
+ continue ;
507
+
508
+ found = depth == visual -> depth ;
509
+ XFree (visual );
510
+ if (found )
511
+ break ;
512
+ }
513
+ XFree (configs );
514
+ if (!found ) {
515
+ blog (log_level , "no matching fb config found" );
516
+ s -> pixmap = 0 ;
517
+ return ;
518
+ }
547
519
548
- XSync (disp , false);
549
- if (pixmap_err || (uint32_t )w < s -> width || (uint32_t )h < s -> height ) {
550
- blog (log_level , "glXCreatePixmap failed: %s" , pixmap_err_text );
551
- glXDestroyPixmap (disp , s -> glxpixmap );
552
- XFreePixmap (disp , s -> pixmap );
553
- gs_texture_destroy (s -> gltex );
554
- s -> pixmap = 0 ;
555
- s -> glxpixmap = 0 ;
556
- s -> gltex = 0 ;
557
- XSetErrorHandler (prev );
558
- return ;
559
- }
560
- XSetErrorHandler (prev );
561
-
562
- s -> tex = gs_texture_create (
563
- s -> width - s -> crop_left - s -> crop_right - 2 * s -> border ,
564
- s -> height - s -> crop_top - s -> crop_bot - 2 * s -> border , format ,
565
- 1 , 0 , GS_GL_DUMMYTEX );
566
- if (s -> swapRedBlue ) {
567
- GLuint tex = * (GLuint * )gs_texture_get_obj (s -> tex );
568
- glBindTexture (GL_TEXTURE_2D , tex );
569
- glTexParameteri (GL_TEXTURE_2D , GL_TEXTURE_SWIZZLE_B , GL_RED );
570
- glTexParameteri (GL_TEXTURE_2D , GL_TEXTURE_SWIZZLE_R , GL_BLUE );
520
+ // Should be consistent format with config we are using. Since we searched on RGBA let's use RGBA here.
521
+ const int pixmap_attrs [] = {GLX_TEXTURE_TARGET_EXT ,
522
+ GLX_TEXTURE_2D_EXT ,
523
+ GLX_TEXTURE_FORMAT_EXT ,
524
+ GLX_TEXTURE_FORMAT_RGBA_EXT , None };
525
+
526
+ // Try very hard to capture errors in glXCreatePixmap for NVIDIA drivers
527
+ // where only one pixmap can be bound in GLX at a time.
528
+ pixmap_err = false;
529
+ XErrorHandler prev = XSetErrorHandler (catch_pixmap_errors );
530
+ s -> glxpixmap =
531
+ glXCreatePixmap (disp , config , s -> pixmap , pixmap_attrs );
532
+ XSync (disp , false);
533
+
534
+ s -> gltex = gs_texture_create (s -> width , s -> height , GS_RGBA_UNORM ,
535
+ 1 , 0 , GS_GL_DUMMYTEX );
536
+ GLuint gltex = * (GLuint * )gs_texture_get_obj (s -> gltex );
537
+ glBindTexture (GL_TEXTURE_2D , gltex );
538
+ // Not respecting a captured glXCreatePixmap error will result in Xorg closing our connection.
539
+ if (!pixmap_err )
540
+ glXBindTexImageEXT (disp , s -> glxpixmap , GLX_FRONT_EXT ,
541
+ NULL );
542
+ glTexParameteri (GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER ,
543
+ GL_LINEAR );
544
+ glTexParameteri (GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER ,
545
+ GL_LINEAR );
546
+ // glxBindTexImageEXT might modify the textures format.
547
+ enum gs_color_format format = gs_format_from_tex ();
548
+ // Check if texture is invalid... because X11 hates us.
549
+ int w ;
550
+ int h ;
551
+ glGetTexLevelParameteriv (GL_TEXTURE_2D , 0 , GL_TEXTURE_WIDTH ,
552
+ & w );
553
+ glGetTexLevelParameteriv (GL_TEXTURE_2D , 0 , GL_TEXTURE_HEIGHT ,
554
+ & h );
571
555
glBindTexture (GL_TEXTURE_2D , 0 );
556
+ // We must sync OBS texture format based on any glxBindTexImageEXT changes.
557
+ s -> gltex -> format = format ;
558
+
559
+ XSync (disp , false);
560
+ if (pixmap_err || (uint32_t )w < s -> width ||
561
+ (uint32_t )h < s -> height ) {
562
+ blog (log_level , "glXCreatePixmap failed: %s" ,
563
+ pixmap_err_text );
564
+ glXDestroyPixmap (disp , s -> glxpixmap );
565
+ XFreePixmap (disp , s -> pixmap );
566
+ gs_texture_destroy (s -> gltex );
567
+ s -> pixmap = 0 ;
568
+ s -> glxpixmap = 0 ;
569
+ s -> gltex = 0 ;
570
+ XSetErrorHandler (prev );
571
+ return ;
572
+ }
573
+ XSetErrorHandler (prev );
572
574
}
573
575
}
574
576
@@ -685,7 +687,7 @@ void watcher_unload()
685
687
static uint32_t xcompcap_get_width (void * data )
686
688
{
687
689
struct xcompcap * s = (struct xcompcap * )data ;
688
- if (!s -> tex || ! s -> gltex )
690
+ if (!s -> gltex )
689
691
return 0 ;
690
692
691
693
int32_t border = s -> crop_left + s -> crop_right + 2 * s -> border ;
@@ -696,7 +698,7 @@ static uint32_t xcompcap_get_width(void *data)
696
698
static uint32_t xcompcap_get_height (void * data )
697
699
{
698
700
struct xcompcap * s = (struct xcompcap * )data ;
699
- if (!s -> tex || ! s -> gltex )
701
+ if (!s -> gltex )
700
702
return 0 ;
701
703
702
704
int32_t border = s -> crop_bot + s -> crop_top + 2 * s -> border ;
@@ -712,6 +714,11 @@ static void *xcompcap_create(obs_data_t *settings, obs_source_t *source)
712
714
s -> show_cursor = true;
713
715
s -> strict_binding = true;
714
716
s -> source = source ;
717
+ enum obs_nix_platform_type platform = obs_get_nix_platform ();
718
+ s -> egl = platform == OBS_NIX_PLATFORM_X11_EGL ;
719
+ if (s -> egl ) {
720
+ s -> strict_binding = false;
721
+ }
715
722
716
723
obs_enter_graphics ();
717
724
if (strcmp (glGetString (GL_VENDOR ), "NVIDIA Corporation" ) == 0 ) {
@@ -736,9 +743,6 @@ static void xcompcap_destroy(void *data)
736
743
watcher_unregister (conn , s );
737
744
xcomp_cleanup_pixmap (disp , s );
738
745
739
- if (s -> tex )
740
- gs_texture_destroy (s -> tex );
741
-
742
746
if (s -> cursor )
743
747
xcb_xcursor_destroy (s -> cursor );
744
748
@@ -784,7 +788,7 @@ static void xcompcap_video_tick(void *data, float seconds)
784
788
s -> cursor -> y_org + s -> crop_top );
785
789
}
786
790
787
- if (!s -> tex || ! s -> gltex )
791
+ if (!s -> gltex )
788
792
goto done ;
789
793
790
794
if (xcompcap_get_height (s ) == 0 || xcompcap_get_width (s ) == 0 )
@@ -795,9 +799,6 @@ static void xcompcap_video_tick(void *data, float seconds)
795
799
glXReleaseTexImageEXT (disp , s -> glxpixmap , GLX_FRONT_EXT );
796
800
glXBindTexImageEXT (disp , s -> glxpixmap , GLX_FRONT_EXT , NULL );
797
801
}
798
- gs_copy_texture_region (s -> tex , 0 , 0 , s -> gltex , s -> crop_left + s -> border ,
799
- s -> crop_top + s -> border , xcompcap_get_width (s ),
800
- xcompcap_get_height (s ));
801
802
glBindTexture (GL_TEXTURE_2D , 0 );
802
803
803
804
if (s -> show_cursor ) {
@@ -820,19 +821,20 @@ static void xcompcap_video_render(void *data, gs_effect_t *effect)
820
821
821
822
pthread_mutex_lock (& s -> lock );
822
823
823
- if (!s -> tex || ! s -> gltex )
824
+ if (!s -> gltex )
824
825
goto done ;
825
826
827
+ effect = obs_get_base_effect (OBS_EFFECT_DEFAULT );
826
828
if (s -> exclude_alpha )
827
829
effect = obs_get_base_effect (OBS_EFFECT_OPAQUE );
828
- else
829
- effect = obs_get_base_effect (OBS_EFFECT_DEFAULT );
830
830
831
831
image = gs_effect_get_param_by_name (effect , "image" );
832
- gs_effect_set_texture (image , s -> tex );
832
+ gs_effect_set_texture (image , s -> gltex );
833
833
834
834
while (gs_effect_loop (effect , "Draw" )) {
835
- gs_draw_sprite (s -> tex , 0 , 0 , 0 );
835
+ gs_draw_sprite_subregion (s -> gltex , 0 , s -> crop_left , s -> crop_top ,
836
+ xcompcap_get_width (s ),
837
+ xcompcap_get_height (s ));
836
838
}
837
839
838
840
if (s -> gltex && s -> show_cursor && !s -> cursor_outside ) {
0 commit comments