Line data Source code
1 :
2 : /* Copyright (c) 2005-2015, Stefan Eilemann <eile@equalizergraphics.com>
3 : * Maxim Makhinya
4 : * Daniel Nachbaur <danielnachbaur@gmail.com>
5 : *
6 : * This library is free software; you can redistribute it and/or modify it under
7 : * the terms of the GNU Lesser General Public License version 2.1 as published
8 : * by the Free Software Foundation.
9 : *
10 : * This library is distributed in the hope that it will be useful, but WITHOUT
11 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
13 : * details.
14 : *
15 : * You should have received a copy of the GNU Lesser General Public License
16 : * along with this library; if not, write to the Free Software Foundation, Inc.,
17 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 : */
19 :
20 : #include "pipe.h"
21 :
22 : #include "../gl.h"
23 : #include "../global.h"
24 : #include "../log.h"
25 : #include "../pipe.h"
26 :
27 : #include <eq/fabric/gpuInfo.h>
28 : #include <lunchbox/os.h>
29 : #include <boost/lexical_cast.hpp>
30 :
31 : using boost::lexical_cast;
32 :
33 : namespace eq
34 : {
35 : namespace glx
36 : {
37 : #ifndef NDEBUG
38 : static int XErrorHandler( Display* display, XErrorEvent* event );
39 : #endif
40 :
41 : namespace detail
42 : {
43 : class Pipe
44 : {
45 : public:
46 1 : Pipe()
47 1 : : xDisplay( 0 )
48 : {
49 1 : lunchbox::setZero( &glxewContext, sizeof( GLXEWContext ));
50 1 : }
51 :
52 1 : ~Pipe()
53 : {
54 : #ifndef NDEBUG
55 1 : lunchbox::setZero( &glxewContext, sizeof( GLXEWContext ));
56 : #endif
57 1 : }
58 :
59 : /** Window-system specific display information. */
60 : Display* xDisplay;
61 :
62 : /** Extended GLX function entries. */
63 : GLXEWContext glxewContext;
64 : };
65 : }
66 :
67 1 : Pipe::Pipe( eq::Pipe* parent )
68 : : SystemPipe( parent )
69 1 : , _impl( new detail::Pipe )
70 : {
71 1 : }
72 :
73 3 : Pipe::~Pipe( )
74 : {
75 1 : delete _impl;
76 2 : }
77 :
78 0 : Display* Pipe::getXDisplay() const
79 : {
80 0 : return _impl->xDisplay;
81 : }
82 :
83 0 : GLXEWContext* Pipe::glxewGetContext()
84 : {
85 0 : return &_impl->glxewContext;
86 : }
87 :
88 : //---------------------------------------------------------------------------
89 : // GLX init
90 : //---------------------------------------------------------------------------
91 1 : bool Pipe::configInit()
92 : {
93 1 : const std::string displayName = getXDisplayString();
94 1 : Display* xDisplay = XOpenDisplay( displayName.c_str( ));
95 :
96 1 : if( !xDisplay )
97 : {
98 : sendError( ERROR_GLXPIPE_DEVICE_NOTFOUND )
99 1 : << displayName << lunchbox::sysError();
100 1 : return false;
101 : }
102 :
103 : int major, event, error;
104 0 : if( !XQueryExtension( xDisplay, "GLX", &major, &event, &error ))
105 : {
106 0 : sendError( ERROR_GLXPIPE_GLX_NOTFOUND );
107 0 : XCloseDisplay( xDisplay );
108 0 : return false;
109 : }
110 :
111 0 : setXDisplay( xDisplay );
112 0 : LBVERB << "Opened X display " << displayName << " @" << xDisplay
113 0 : << ", device " << getPipe()->getDevice() << std::endl;
114 :
115 0 : return _configInitGLXEW();
116 : }
117 :
118 0 : void Pipe::configExit()
119 : {
120 0 : Display* xDisplay = getXDisplay();
121 0 : if( !xDisplay )
122 0 : return;
123 :
124 0 : setXDisplay( 0 );
125 0 : XCloseDisplay( xDisplay );
126 0 : LBVERB << "Closed X display " << xDisplay << std::endl;
127 : }
128 :
129 1 : std::string Pipe::getXDisplayString()
130 : {
131 1 : std::ostringstream stringStream;
132 :
133 1 : const uint32_t port = getPipe()->getPort();
134 1 : const uint32_t device = getPipe()->getDevice();
135 :
136 1 : if( port != LB_UNDEFINED_UINT32 )
137 : {
138 0 : if( device == LB_UNDEFINED_UINT32 )
139 0 : stringStream << ":" << port;
140 : else
141 0 : stringStream << ":" << port << "." << device;
142 : }
143 1 : else if( device != LB_UNDEFINED_UINT32 )
144 1 : stringStream << ":0." << device;
145 :
146 2 : const std::string name( XDisplayName( stringStream.str().c_str( )));
147 2 : return name.empty() ? ":0" : name;
148 : }
149 :
150 0 : void Pipe::setXDisplay( Display* display )
151 : {
152 0 : if( _impl->xDisplay == display )
153 0 : return;
154 :
155 0 : _impl->xDisplay = display;
156 0 : XSetCurrentDisplay( display );
157 :
158 0 : GPUInfo info;
159 0 : if( getGPUInfo( display, info ))
160 : {
161 : #ifndef NDEBUG
162 : // somewhat reduntant since it is a global handler
163 0 : XSetErrorHandler( XErrorHandler );
164 : #endif
165 0 : const uint32_t port = getPipe()->getPort();
166 0 : const uint32_t device = getPipe()->getDevice();
167 :
168 0 : if( port != LB_UNDEFINED_UINT32 && info.port != port )
169 0 : LBWARN << "Display mismatch: provided display connection uses"
170 0 : << " display " << info.port << ", but pipe has port " << port
171 0 : << std::endl;
172 :
173 0 : if( device != LB_UNDEFINED_UINT32 && info.device != device )
174 0 : LBWARN << "Screen mismatch: provided display connection uses "
175 0 : << "default screen " << info.device
176 0 : << ", but pipe has screen " << device << std::endl;
177 : }
178 :
179 0 : const PixelViewport& pvp = getPipe()->getPixelViewport();
180 0 : if( !pvp.isValid( ))
181 0 : getPipe()->setPixelViewport( info.pvp );
182 : }
183 :
184 0 : bool Pipe::getGPUInfo( Display* display, GPUInfo& info )
185 : {
186 0 : if( !display )
187 0 : return false;
188 :
189 0 : std::string displayString = DisplayString( display );
190 0 : const size_t colonPos = displayString.find( ':' );
191 0 : if( colonPos != std::string::npos )
192 : {
193 0 : const std::string displayNumber = displayString.substr( colonPos+1 );
194 0 : info.port = atoi( displayNumber.c_str( ));
195 0 : info.device = DefaultScreen( display );
196 : }
197 :
198 0 : info.pvp.x = 0;
199 0 : info.pvp.y = 0;
200 0 : info.pvp.w = DisplayWidth( display, DefaultScreen( display ));
201 0 : info.pvp.h = DisplayHeight( display, DefaultScreen( display ));
202 :
203 0 : return true;
204 : }
205 :
206 0 : bool Pipe::_configInitGLXEW()
207 : {
208 0 : LBASSERT( _impl->xDisplay );
209 :
210 : //----- Create and make current a temporary GL context to initialize GLXEW
211 : // visual
212 0 : std::vector<int> attributes;
213 0 : attributes.push_back( GLX_RGBA );
214 0 : attributes.push_back( None );
215 :
216 0 : const int screen = DefaultScreen( _impl->xDisplay );
217 : XVisualInfo *visualInfo = glXChooseVisual( _impl->xDisplay, screen,
218 0 : &attributes.front( ));
219 0 : if( !visualInfo )
220 : {
221 0 : sendError( ERROR_SYSTEMPIPE_PIXELFORMAT_NOTFOUND );
222 0 : return false;
223 : }
224 :
225 : //context
226 : GLXContext context = glXCreateContext( _impl->xDisplay, visualInfo, 0,
227 0 : True );
228 0 : if( !context )
229 : {
230 0 : sendError( ERROR_SYSTEMPIPE_CREATECONTEXT_FAILED );
231 0 : return false;
232 : }
233 :
234 : // window
235 0 : const XID parent = RootWindow( _impl->xDisplay, screen );
236 : XSetWindowAttributes wa;
237 : wa.colormap = XCreateColormap( _impl->xDisplay, parent, visualInfo->visual,
238 0 : AllocNone );
239 0 : wa.background_pixmap = None;
240 0 : wa.border_pixel = 0;
241 : XID drawable = XCreateWindow( _impl->xDisplay, parent, 0, 0, 16, 16,
242 : 0, visualInfo->depth, InputOutput,
243 : visualInfo->visual,
244 : CWBackPixmap | CWBorderPixel | CWColormap,
245 0 : &wa );
246 0 : if( !drawable )
247 : {
248 0 : sendError( ERROR_SYSTEMPIPE_CREATEWINDOW_FAILED );
249 0 : return false;
250 : }
251 :
252 0 : XFree( visualInfo );
253 0 : XSync( _impl->xDisplay, False );
254 :
255 0 : glXMakeCurrent( _impl->xDisplay, drawable, context );
256 :
257 0 : const GLenum result = glxewInit();
258 0 : bool success = result == GLEW_OK;
259 0 : if( success )
260 : {
261 0 : LBVERB << "Pipe GLXEW initialization successful" << std::endl;
262 0 : success = configInitGL();
263 :
264 0 : const char* glVersion = (const char*)glGetString( GL_VERSION );
265 0 : if( success && glVersion )
266 0 : _maxOpenGLVersion = static_cast<float>( atof( glVersion ));
267 : }
268 : else
269 : sendError( ERROR_GLXPIPE_GLXEWINIT_FAILED )
270 0 : << lexical_cast< std::string >( result );
271 :
272 0 : XSync( _impl->xDisplay, False );
273 0 : glXDestroyContext( _impl->xDisplay, context );
274 0 : XDestroyWindow( _impl->xDisplay, drawable );
275 :
276 0 : return success;
277 : }
278 :
279 : #ifndef NDEBUG
280 0 : int XErrorHandler( Display* display, XErrorEvent* event )
281 : {
282 0 : LBWARN << lunchbox::disableFlush;
283 0 : LBWARN << "X Error occured: " << lunchbox::disableHeader
284 0 : << lunchbox::indent;
285 :
286 : char buffer[256];
287 0 : XGetErrorText( display, event->error_code, buffer, 256);
288 :
289 0 : LBWARN << buffer << std::endl;
290 0 : LBWARN << "Major opcode: " << (int)event->request_code << std::endl;
291 0 : LBWARN << "Minor opcode: " << (int)event->minor_code << std::endl;
292 0 : LBWARN << "Error code: " << (int)event->error_code << std::endl;
293 0 : LBWARN << "Request serial: " << event->serial << std::endl;
294 0 : LBWARN << "Current serial: " << NextRequest( display ) - 1 << std::endl;
295 :
296 0 : switch( event->error_code )
297 : {
298 : case BadValue:
299 0 : LBWARN << " Value: " << event->resourceid << std::endl;
300 0 : break;
301 :
302 : case BadAtom:
303 0 : LBWARN << " AtomID: " << event->resourceid << std::endl;
304 0 : break;
305 :
306 : default:
307 0 : LBWARN << " ResourceID: " << event->resourceid << std::endl;
308 0 : break;
309 : }
310 0 : LBWARN << lunchbox::enableFlush << lunchbox::exdent
311 0 : << lunchbox::enableHeader;
312 :
313 : #ifndef NDEBUG
314 0 : if( getenv( "EQ_ABORT_WAIT" ))
315 : {
316 0 : LBWARN << "Caught X Error, entering infinite loop for debugging"
317 0 : << std::endl;
318 : while( true ) ;
319 : }
320 : #endif
321 :
322 0 : return 0;
323 : }
324 : #endif // !NDEBUG
325 :
326 : }
327 42 : }
|