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