1/*
2 * fg_window_x11_glx.c
3 *
4 * Window management methods for X11 with GLX
5 *
6 * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
7 * Written by Pawel W. Olszta, <olszta@sourceforge.net>
8 * Copied for Platform code by Evan Felix <karcaw at gmail.com>
9 * Creation date: Thur Feb 2 2012
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included
19 * in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
25 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 */
28
29#define FREEGLUT_BUILDING_LIB
30#include <GL/freeglut.h>
31#include "fg_internal.h"
32
33/* pushing attribute/value pairs into an array */
34#define ATTRIB(a) attributes[where++]=(a)
35#define ATTRIB_VAL(a,v) {ATTRIB(a); ATTRIB(v);}
36
37/*
38 * Chooses a visual basing on the current display mode settings
39 */
40
41int fghChooseConfig(GLXFBConfig* fbconfig)
42{
43 GLboolean wantIndexedMode = GL_FALSE;
44 int attributes[ 100 ];
45 int where = 0, numAuxBuffers;
46
47 /* First we have to process the display mode settings... */
48 if( fgState.DisplayMode & GLUT_INDEX ) {
49 ATTRIB_VAL( GLX_BUFFER_SIZE, 8 );
50 /* Buffer size is selected later. */
51
52 ATTRIB_VAL( GLX_RENDER_TYPE, GLX_COLOR_INDEX_BIT );
53 wantIndexedMode = GL_TRUE;
54 } else {
55 ATTRIB_VAL( GLX_RED_SIZE, 1 );
56 ATTRIB_VAL( GLX_GREEN_SIZE, 1 );
57 ATTRIB_VAL( GLX_BLUE_SIZE, 1 );
58 if( fgState.DisplayMode & GLUT_ALPHA ) {
59 ATTRIB_VAL( GLX_ALPHA_SIZE, 1 );
60 }
61 }
62
63 if( fgState.DisplayMode & GLUT_DOUBLE ) {
64 ATTRIB_VAL( GLX_DOUBLEBUFFER, True );
65 }
66
67 if( fgState.DisplayMode & GLUT_STEREO ) {
68 ATTRIB_VAL( GLX_STEREO, True );
69 }
70
71 if( fgState.DisplayMode & GLUT_DEPTH ) {
72 ATTRIB_VAL( GLX_DEPTH_SIZE, 1 );
73 }
74
75 if( fgState.DisplayMode & GLUT_STENCIL ) {
76 ATTRIB_VAL( GLX_STENCIL_SIZE, 1 );
77 }
78
79 if( fgState.DisplayMode & GLUT_ACCUM ) {
80 ATTRIB_VAL( GLX_ACCUM_RED_SIZE, 1 );
81 ATTRIB_VAL( GLX_ACCUM_GREEN_SIZE, 1 );
82 ATTRIB_VAL( GLX_ACCUM_BLUE_SIZE, 1 );
83 if( fgState.DisplayMode & GLUT_ALPHA ) {
84 ATTRIB_VAL( GLX_ACCUM_ALPHA_SIZE, 1 );
85 }
86 }
87
88 numAuxBuffers = fghNumberOfAuxBuffersRequested();
89 if ( numAuxBuffers > 0 ) {
90 ATTRIB_VAL( GLX_AUX_BUFFERS, numAuxBuffers );
91 }
92
93 if( fgState.DisplayMode & GLUT_SRGB ) {
94 ATTRIB_VAL( GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, True );
95 }
96
97 if (fgState.DisplayMode & GLUT_MULTISAMPLE) {
98 ATTRIB_VAL(GLX_SAMPLE_BUFFERS, 1);
99 ATTRIB_VAL(GLX_SAMPLES, fgState.SampleNumber);
100 }
101
102 /* Push a terminator at the end of the list */
103 ATTRIB( None );
104
105 {
106 GLXFBConfig * fbconfigArray; /* Array of FBConfigs */
107 int fbconfigArraySize; /* Number of FBConfigs in the array */
108
109
110 /* Get all FBConfigs that match "attributes". */
111 fbconfigArray = glXChooseFBConfig( fgDisplay.pDisplay.Display,
112 fgDisplay.pDisplay.Screen,
113 attributes,
114 &fbconfigArraySize );
115
116 if (fbconfigArray != NULL)
117 {
118 int result __fg_unused; /* Returned by glXGetFBConfigAttrib, not checked. */
119
120
121 if( wantIndexedMode )
122 {
123 /*
124 * In index mode, we want the largest buffer size, i.e. visual
125 * depth. Here, FBConfigs are sorted by increasing buffer size
126 * first, so FBConfigs with the largest size come last.
127 */
128
129 int bufferSizeMin, bufferSizeMax;
130
131 /* Get bufferSizeMin. */
132 result =
133 glXGetFBConfigAttrib( fgDisplay.pDisplay.Display,
134 fbconfigArray[0],
135 GLX_BUFFER_SIZE,
136 &bufferSizeMin );
137 /* Get bufferSizeMax. */
138 result =
139 glXGetFBConfigAttrib( fgDisplay.pDisplay.Display,
140 fbconfigArray[fbconfigArraySize - 1],
141 GLX_BUFFER_SIZE,
142 &bufferSizeMax );
143
144 if (bufferSizeMax > bufferSizeMin)
145 {
146 /*
147 * Free and reallocate fbconfigArray, keeping only FBConfigs
148 * with the largest buffer size.
149 */
150 XFree(fbconfigArray);
151
152 /* Add buffer size token at the end of the list. */
153 where--;
154 ATTRIB_VAL( GLX_BUFFER_SIZE, bufferSizeMax );
155 ATTRIB( None );
156
157 fbconfigArray = glXChooseFBConfig( fgDisplay.pDisplay.Display,
158 fgDisplay.pDisplay.Screen,
159 attributes,
160 &fbconfigArraySize );
161 }
162 }
163
164 *fbconfig = fbconfigArray[0];
165 }
166 else
167 {
168 *fbconfig = NULL;
169 return 0;
170 }
171 XFree(fbconfigArray);
172
173 return 1;
174 }
175}
176
177static void fghFillContextAttributes( int *attributes ) {
178 int where = 0, contextFlags, contextProfile;
179
180 ATTRIB_VAL( GLX_CONTEXT_MAJOR_VERSION_ARB, fgState.MajorVersion );
181 ATTRIB_VAL( GLX_CONTEXT_MINOR_VERSION_ARB, fgState.MinorVersion );
182
183 contextFlags =
184 fghMapBit( fgState.ContextFlags, GLUT_DEBUG, GLX_CONTEXT_DEBUG_BIT_ARB ) |
185 fghMapBit( fgState.ContextFlags, GLUT_FORWARD_COMPATIBLE, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB );
186 if ( contextFlags != 0 ) {
187 ATTRIB_VAL( GLX_CONTEXT_FLAGS_ARB, contextFlags );
188 }
189
190 contextProfile =
191 fghMapBit( fgState.ContextProfile, GLUT_CORE_PROFILE, GLX_CONTEXT_CORE_PROFILE_BIT_ARB ) |
192 fghMapBit( fgState.ContextProfile, GLUT_COMPATIBILITY_PROFILE, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB );
193 if ( contextProfile != 0 ) {
194 ATTRIB_VAL( GLX_CONTEXT_PROFILE_MASK_ARB, contextProfile );
195 }
196
197 ATTRIB( 0 );
198}
199
200typedef GLXContext (*CreateContextAttribsProc)(Display *dpy, GLXFBConfig config,
201 GLXContext share_list, Bool direct,
202 const int *attrib_list);
203
204GLXContext fghCreateNewContext( SFG_Window* window )
205{
206 /* for color model calculation */
207 int menu = ( window->IsMenu && !fgStructure.MenuContext );
208 int index_mode = ( fgState.DisplayMode & GLUT_INDEX );
209
210 /* "classic" context creation */
211 Display *dpy = fgDisplay.pDisplay.Display;
212 GLXFBConfig config = window->Window.pContext.FBConfig;
213 int render_type = ( !menu && index_mode ) ? GLX_COLOR_INDEX_TYPE : GLX_RGBA_TYPE;
214 GLXContext share_list = NULL;
215 Bool direct = ( fgState.DirectContext != GLUT_FORCE_INDIRECT_CONTEXT );
216 GLXContext context;
217
218 /* new context creation */
219 int attributes[9];
220 CreateContextAttribsProc createContextAttribs = (CreateContextAttribsProc) fgPlatformGetProcAddress( "glXCreateContextAttribsARB" );
221
222 /* glXCreateContextAttribsARB not found, yet the user has requested the new context creation */
223 if ( !createContextAttribs && !fghIsLegacyContextRequested() ) {
224 fgWarning( "OpenGL >2.1 context requested but glXCreateContextAttribsARB is not available! Falling back to legacy context creation" );
225 fgState.MajorVersion = 2;
226 fgState.MinorVersion = 1;
227 }
228
229 /* If nothing fancy has been required, simply use the old context creation GLX API entry */
230 if ( fghIsLegacyContextRequested() || !createContextAttribs )
231 {
232 context = glXCreateNewContext( dpy, config, render_type, share_list, direct );
233 if ( context == NULL ) {
234 fghContextCreationError();
235 }
236 return context;
237 }
238
239 /* color index mode is not available anymore with OpenGL 3.0 */
240 if ( render_type == GLX_COLOR_INDEX_TYPE ) {
241 fgWarning( "color index mode is deprecated, using RGBA mode" );
242 }
243
244 fghFillContextAttributes( attributes );
245
246 context = createContextAttribs( dpy, config, share_list, direct, attributes );
247 if ( context == NULL ) {
248 fghContextCreationError();
249 }
250 return context;
251}
252
253void fgPlatformSetWindow ( SFG_Window *window )
254{
255 if ( window )
256 {
257 glXMakeContextCurrent(
258 fgDisplay.pDisplay.Display,
259 window->Window.Handle,
260 window->Window.Handle,
261 window->Window.Context
262 );
263 }
264}
265