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