|
166 | 166 | ;; GLX #defines/typedefs/enums |
167 | 167 | (define _GLXFBConfig (_cpointer 'GLXFBConfig)) |
168 | 168 | (define _GLXContext (_cpointer/null 'GLXContext)) |
169 | | -(define _XVisualInfo (_cpointer 'XVisualInfo)) |
170 | 169 | ;; Attribute tokens for glXGetConfig variants (all GLX versions): |
171 | 170 | (define GLX_DOUBLEBUFFER 5) |
172 | 171 | (define GLX_STEREO 6) |
|
237 | 236 | (_fun _Display _GLXContext -> _bool)) |
238 | 237 |
|
239 | 238 | (define-glx glXGetVisualFromFBConfig |
240 | | - (_fun _Display _GLXFBConfig -> _XVisualInfo) |
| 239 | + (_fun _Display _GLXFBConfig -> _XVisualInfo-pointer) |
241 | 240 | #:wrap (allocator XFree)) |
242 | 241 |
|
243 | 242 | (define-glx glXCreateGLXPixmap |
244 | | - (_fun _Display _XVisualInfo _XID -> _XID)) |
| 243 | + (_fun _Display _XVisualInfo-pointer _XID -> _XID)) |
245 | 244 |
|
246 | 245 | (define-glx glXDestroyGLXPixmap |
247 | 246 | (_fun _Display _XID -> _void)) |
|
573 | 572 | (define-values (err value) (glXGetFBConfigAttrib xdisplay cfg attrib)) |
574 | 573 | (if (= err Success) value bad-value)) |
575 | 574 |
|
| 575 | +;; (or/c #f _GtkWidget) gl-config% boolean? -> (or/c _GLXFBConfig #f) |
| 576 | +(define (choose-glx-fbconfig widget conf wants-double?) |
| 577 | + (define glx-version (get-glx-version)) |
| 578 | + |
| 579 | + ;; If widget isn't #f, use its display and screen |
| 580 | + (define display (gtk-maybe-widget-get-display widget)) |
| 581 | + (define screen (gtk-maybe-widget-get-screen widget)) |
| 582 | + |
| 583 | + ;; Get the X objects wrapped by the GDK objects |
| 584 | + (define xdisplay (gdk_x11_display_get_xdisplay display)) |
| 585 | + (define xscreen (gdk_x11_screen_get_screen_number screen)) |
| 586 | + |
| 587 | + ;; Create an attribute list using the GL config |
| 588 | + (define xattribs |
| 589 | + (append |
| 590 | + ;; Be aware: we may get double buffering even if we don't ask for it |
| 591 | + (if wants-double? |
| 592 | + (if (send conf get-double-buffered) (list GLX_DOUBLEBUFFER True) null) |
| 593 | + null) |
| 594 | + (if (send conf get-stereo) (list GLX_STEREO True) null) |
| 595 | + ;; Finish out with standard GLX 1.3 attributes |
| 596 | + (list |
| 597 | + GLX_X_RENDERABLE True ; yes, we want to use OpenGL to render today |
| 598 | + GLX_DEPTH_SIZE (send conf get-depth-size) |
| 599 | + GLX_STENCIL_SIZE (send conf get-stencil-size) |
| 600 | + GLX_ACCUM_RED_SIZE (send conf get-accum-size) |
| 601 | + GLX_ACCUM_GREEN_SIZE (send conf get-accum-size) |
| 602 | + GLX_ACCUM_BLUE_SIZE (send conf get-accum-size) |
| 603 | + GLX_ACCUM_ALPHA_SIZE (send conf get-accum-size) |
| 604 | + ;; GLX_SAMPLES is handled below - GLX regards it as an absolute lower bound, which makes it |
| 605 | + ;; too easy for user programs to fail to get a context |
| 606 | + None))) |
| 607 | + |
| 608 | + (define multisample-size (send conf get-multisample-size)) |
| 609 | + |
| 610 | + ;; Get all framebuffer configs for this display and screen that match the requested attributes, |
| 611 | + ;; then sort them to put the best in front |
| 612 | + ;; GLX already sorts them pretty well, so we just need a stable sort on multisamples at the moment |
| 613 | + (define cfgs |
| 614 | + (let* ([cfgs (cvector->list (glXChooseFBConfig xdisplay xscreen xattribs))] |
| 615 | + ;; Keep all configs with multisample size <= requested (i.e. make multisample-size an |
| 616 | + ;; abolute upper bound) |
| 617 | + [cfgs (if (< glx-version #e1.4) |
| 618 | + cfgs |
| 619 | + (filter (λ (cfg) |
| 620 | + (define m (glx-get-fbconfig-attrib xdisplay cfg GLX_SAMPLES 0)) |
| 621 | + (<= m multisample-size)) |
| 622 | + cfgs))] |
| 623 | + ;; Sort all configs by multisample size, decreasing |
| 624 | + [cfgs (if (< glx-version #e1.4) |
| 625 | + cfgs |
| 626 | + (sort cfgs > |
| 627 | + #:key (λ (cfg) (glx-get-fbconfig-attrib xdisplay cfg GLX_SAMPLES 0)) |
| 628 | + #:cache-keys? #t))]) |
| 629 | + cfgs)) |
| 630 | + |
| 631 | + ;; The framebuffer configs are sorted best-first, so choose the first |
| 632 | + (if (null? cfgs) |
| 633 | + #f |
| 634 | + (car cfgs))) |
| 635 | + |
576 | 636 | ;; (or/c #f _GtkWidget) (or/c _GdkDrawable (is-a/c bitmap%) gl-config% boolean? -> gl-context% |
577 | 637 | ;; where X11 uses _GdkDrawable = (or/c _GtkWindow _GdkPixmap) |
578 | 638 | ;; and Wayland uses bitmap% that holds a Cairo ARGB32 image surface |
|
711 | 771 | ctxt] |
712 | 772 | [else |
713 | 773 | (define glx-version (get-glx-version)) |
714 | | - |
715 | | - ;; If widget isn't #f, use its display and screen |
716 | 774 | (define display (gtk-maybe-widget-get-display widget)) |
717 | | - (define screen (gtk-maybe-widget-get-screen widget)) |
718 | | - |
719 | | - ;; Get the X objects wrapped by the GDK objects |
720 | 775 | (define xdisplay (gdk_x11_display_get_xdisplay display)) |
721 | | - (define xscreen (gdk_x11_screen_get_screen_number screen)) |
722 | | - |
723 | | - ;; Create an attribute list using the GL config |
724 | | - (define xattribs |
725 | | - (append |
726 | | - ;; Be aware: we may get double buffering even if we don't ask for it |
727 | | - (if wants-double? |
728 | | - (if (send conf get-double-buffered) (list GLX_DOUBLEBUFFER True) null) |
729 | | - null) |
730 | | - (if (send conf get-stereo) (list GLX_STEREO True) null) |
731 | | - ;; Finish out with standard GLX 1.3 attributes |
732 | | - (list |
733 | | - GLX_X_RENDERABLE True ; yes, we want to use OpenGL to render today |
734 | | - GLX_DEPTH_SIZE (send conf get-depth-size) |
735 | | - GLX_STENCIL_SIZE (send conf get-stencil-size) |
736 | | - GLX_ACCUM_RED_SIZE (send conf get-accum-size) |
737 | | - GLX_ACCUM_GREEN_SIZE (send conf get-accum-size) |
738 | | - GLX_ACCUM_BLUE_SIZE (send conf get-accum-size) |
739 | | - GLX_ACCUM_ALPHA_SIZE (send conf get-accum-size) |
740 | | - ;; GLX_SAMPLES is handled below - GLX regards it as an absolute lower bound, which makes it |
741 | | - ;; too easy for user programs to fail to get a context |
742 | | - None))) |
743 | | - |
744 | | - (define multisample-size (send conf get-multisample-size)) |
745 | | - |
746 | | - ;; Get all framebuffer configs for this display and screen that match the requested attributes, |
747 | | - ;; then sort them to put the best in front |
748 | | - ;; GLX already sorts them pretty well, so we just need a stable sort on multisamples at the moment |
749 | | - (define cfgs |
750 | | - (let* ([cfgs (cvector->list (glXChooseFBConfig xdisplay xscreen xattribs))] |
751 | | - ;; Keep all configs with multisample size <= requested (i.e. make multisample-size an |
752 | | - ;; abolute upper bound) |
753 | | - [cfgs (if (< glx-version #e1.4) |
754 | | - cfgs |
755 | | - (filter (λ (cfg) |
756 | | - (define m (glx-get-fbconfig-attrib xdisplay cfg GLX_SAMPLES 0)) |
757 | | - (<= m multisample-size)) |
758 | | - cfgs))] |
759 | | - ;; Sort all configs by multisample size, decreasing |
760 | | - [cfgs (if (< glx-version #e1.4) |
761 | | - cfgs |
762 | | - (sort cfgs > |
763 | | - #:key (λ (cfg) (glx-get-fbconfig-attrib xdisplay cfg GLX_SAMPLES 0)) |
764 | | - #:cache-keys? #t))]) |
765 | | - cfgs)) |
766 | | - |
| 776 | + (define cfg (choose-glx-fbconfig widget conf wants-double?)) |
767 | 777 | (cond |
768 | | - [(null? cfgs) #f] |
769 | | - [else |
770 | | - ;; The framebuffer configs are sorted best-first, so choose the first |
771 | | - (define cfg (car cfgs)) |
| 778 | + [cfg |
772 | 779 | (define share-gl |
773 | 780 | (let ([share-ctxt (send conf get-share-context)]) |
774 | 781 | (and share-ctxt (send share-ctxt get-handle)))) |
775 | 782 |
|
| 783 | + (when (and widget (send conf get-sync-swap)) |
| 784 | + (glXSwapIntervalEXT xdisplay (gdk_x11_drawable_get_xid drawable) 1)) |
| 785 | + |
776 | 786 | ;; Get a GL context |
777 | 787 | (define gl |
778 | 788 | (if (and (>= glx-version #e1.4) |
|
788 | 798 | ;; If it doesn't, the context will be version 1.4 or lower, unless GLX is implemented with |
789 | 799 | ;; proprietary extensions (NVIDIA's drivers sometimes do this) |
790 | 800 |
|
791 | | - (when (and widget (send conf get-sync-swap)) |
792 | | - (glXSwapIntervalEXT xdisplay (gdk_x11_drawable_get_xid drawable) 1)) |
793 | | - |
794 | 801 | ;; Now wrap the GLX context in a gl-context% |
795 | 802 | (cond |
796 | 803 | [gl |
|
820 | 827 | (unless (and gtk3? (not widget)) (g_object_unref drawable)) |
821 | 828 | (g_object_unref display))) |
822 | 829 | ctxt] |
823 | | - [else #f])])])) |
| 830 | + [else #f])] |
| 831 | + [else #f])])) |
824 | 832 |
|
825 | 833 | (define (make-gtk-widget-gl-context widget conf) |
826 | 834 | (call-as-atomic |
|
842 | 850 | (define widget-config-hash (make-weak-hasheq)) |
843 | 851 |
|
844 | 852 | (define (prepare-widget-gl-context widget conf) |
845 | | - (hash-set! widget-config-hash widget (if conf conf (make-object gl-config%)))) |
| 853 | + (hash-set! widget-config-hash widget (if conf conf (make-object gl-config%))) |
| 854 | + |
| 855 | + (when (and gtk_widget_set_visual (not wayland?)) |
| 856 | + (cond |
| 857 | + [(and gtk_widget_get_realized |
| 858 | + (gtk_widget_get_realized widget)) |
| 859 | + (log-warning "prepare-widget-gl-context: widget is already realized, cannot set visual from FBConfig")] |
| 860 | + [else |
| 861 | + (define cfg (choose-glx-fbconfig widget conf #t)) |
| 862 | + (define display (gtk-maybe-widget-get-display widget)) |
| 863 | + (define screen (gtk-maybe-widget-get-screen widget)) |
| 864 | + (define xdisplay (gdk_x11_display_get_xdisplay display)) |
| 865 | + (define xvisual-id (XVisualInfo-visual-id (glXGetVisualFromFBConfig xdisplay cfg))) |
| 866 | + (gtk_widget_set_visual widget (gdk_x11_screen_lookup_visual screen xvisual-id))]))) |
846 | 867 |
|
847 | 868 | (define (create-widget-gl-context widget) |
848 | 869 | (define conf (hash-ref widget-config-hash widget #f)) |
|
0 commit comments