| 1 | |
|---|
| 2 | |
|---|
| 3 | |
|---|
| 4 | |
|---|
| 5 | |
|---|
| 6 | |
|---|
| 7 | |
|---|
| 8 | |
|---|
| 9 | |
|---|
| 10 | |
|---|
| 11 | |
|---|
| 12 | |
|---|
| 13 | |
|---|
| 14 | |
|---|
| 15 | |
|---|
| 16 | |
|---|
| 17 | |
|---|
| 18 | |
|---|
| 19 | #include <osgViewer/api/X11/PixelBufferX11> |
|---|
| 20 | #include <osgViewer/api/X11/GraphicsWindowX11> |
|---|
| 21 | #include <osg/GLExtensions> |
|---|
| 22 | |
|---|
| 23 | #include <X11/Xlib.h> |
|---|
| 24 | |
|---|
| 25 | #include <unistd.h> |
|---|
| 26 | |
|---|
| 27 | using namespace osgViewer; |
|---|
| 28 | |
|---|
| 29 | PixelBufferX11::PixelBufferX11(osg::GraphicsContext::Traits* traits) |
|---|
| 30 | : _valid(false), |
|---|
| 31 | _pbuffer(0), |
|---|
| 32 | _visualInfo(0), |
|---|
| 33 | _initialized(false), |
|---|
| 34 | _realized(false), |
|---|
| 35 | _useGLX1_3(false) |
|---|
| 36 | { |
|---|
| 37 | _traits = traits; |
|---|
| 38 | |
|---|
| 39 | init(); |
|---|
| 40 | |
|---|
| 41 | if (valid()) |
|---|
| 42 | { |
|---|
| 43 | setState( new osg::State ); |
|---|
| 44 | getState()->setGraphicsContext(this); |
|---|
| 45 | |
|---|
| 46 | if (_traits.valid() && _traits->sharedContext) |
|---|
| 47 | { |
|---|
| 48 | getState()->setContextID( _traits->sharedContext->getState()->getContextID() ); |
|---|
| 49 | incrementContextIDUsageCount( getState()->getContextID() ); |
|---|
| 50 | } |
|---|
| 51 | else |
|---|
| 52 | { |
|---|
| 53 | getState()->setContextID( osg::GraphicsContext::createNewContextID() ); |
|---|
| 54 | } |
|---|
| 55 | |
|---|
| 56 | } |
|---|
| 57 | } |
|---|
| 58 | |
|---|
| 59 | PixelBufferX11::~PixelBufferX11() |
|---|
| 60 | { |
|---|
| 61 | close(true); |
|---|
| 62 | } |
|---|
| 63 | |
|---|
| 64 | #if defined(GLX_VERSION_1_3) || defined(GLX_SGIX_pbuffer) |
|---|
| 65 | bool PixelBufferX11::createVisualInfo() |
|---|
| 66 | { |
|---|
| 67 | typedef std::vector<int> Attributes; |
|---|
| 68 | Attributes attributes; |
|---|
| 69 | |
|---|
| 70 | attributes.push_back(GLX_USE_GL); |
|---|
| 71 | |
|---|
| 72 | attributes.push_back(GLX_RGBA); |
|---|
| 73 | |
|---|
| 74 | if (_traits->doubleBuffer) attributes.push_back(GLX_DOUBLEBUFFER); |
|---|
| 75 | |
|---|
| 76 | attributes.push_back(GLX_RED_SIZE); attributes.push_back(_traits->red); |
|---|
| 77 | attributes.push_back(GLX_GREEN_SIZE); attributes.push_back(_traits->green); |
|---|
| 78 | attributes.push_back(GLX_BLUE_SIZE); attributes.push_back(_traits->blue); |
|---|
| 79 | attributes.push_back(GLX_DEPTH_SIZE); attributes.push_back(_traits->depth); |
|---|
| 80 | |
|---|
| 81 | if (_traits->alpha) { attributes.push_back(GLX_ALPHA_SIZE); attributes.push_back(_traits->alpha); } |
|---|
| 82 | |
|---|
| 83 | if (_traits->stencil) { attributes.push_back(GLX_STENCIL_SIZE); attributes.push_back(_traits->stencil); } |
|---|
| 84 | |
|---|
| 85 | #if defined(GLX_SAMPLE_BUFFERS) && defined (GLX_SAMPLES) |
|---|
| 86 | |
|---|
| 87 | if (_traits->sampleBuffers) { attributes.push_back(GLX_SAMPLE_BUFFERS); attributes.push_back(_traits->sampleBuffers); } |
|---|
| 88 | if (_traits->sampleBuffers) { attributes.push_back(GLX_SAMPLES); attributes.push_back(_traits->samples); } |
|---|
| 89 | |
|---|
| 90 | #endif |
|---|
| 91 | |
|---|
| 92 | |
|---|
| 93 | |
|---|
| 94 | |
|---|
| 95 | |
|---|
| 96 | attributes.push_back(None); |
|---|
| 97 | |
|---|
| 98 | _visualInfo = glXChooseVisual( _display, _traits->screenNum, &(attributes.front()) ); |
|---|
| 99 | |
|---|
| 100 | return _visualInfo != 0; |
|---|
| 101 | } |
|---|
| 102 | |
|---|
| 103 | void PixelBufferX11::init() |
|---|
| 104 | { |
|---|
| 105 | if (_initialized) return; |
|---|
| 106 | |
|---|
| 107 | if (!_traits) |
|---|
| 108 | { |
|---|
| 109 | _valid = false; |
|---|
| 110 | return; |
|---|
| 111 | } |
|---|
| 112 | |
|---|
| 113 | if (_traits->target != 0) |
|---|
| 114 | { |
|---|
| 115 | |
|---|
| 116 | _valid = false; |
|---|
| 117 | return; |
|---|
| 118 | } |
|---|
| 119 | |
|---|
| 120 | |
|---|
| 121 | _display = XOpenDisplay(_traits->displayName().c_str()); |
|---|
| 122 | |
|---|
| 123 | unsigned int screen = _traits->screenNum; |
|---|
| 124 | |
|---|
| 125 | if (!_display) |
|---|
| 126 | { |
|---|
| 127 | OSG_NOTICE<<"Error: Unable to open display \"" << XDisplayName(_traits->displayName().c_str()) << "\"."<<std::endl; |
|---|
| 128 | _valid = false; |
|---|
| 129 | return; |
|---|
| 130 | } |
|---|
| 131 | |
|---|
| 132 | |
|---|
| 133 | int errorBase, eventBase; |
|---|
| 134 | if( glXQueryExtension( _display, &errorBase, &eventBase) == False ) |
|---|
| 135 | { |
|---|
| 136 | OSG_NOTICE<<"Error: " << XDisplayName(_traits->displayName().c_str()) <<" has no GLX extension." << std::endl; |
|---|
| 137 | |
|---|
| 138 | XCloseDisplay( _display ); |
|---|
| 139 | _display = 0; |
|---|
| 140 | _valid = false; |
|---|
| 141 | return; |
|---|
| 142 | } |
|---|
| 143 | |
|---|
| 144 | |
|---|
| 145 | |
|---|
| 146 | int major, minor; |
|---|
| 147 | if (glXQueryVersion(_display, &major, &minor) == False) |
|---|
| 148 | { |
|---|
| 149 | OSG_NOTICE << "Error: " << XDisplayName(_traits->displayName().c_str()) |
|---|
| 150 | << " can not query GLX version." << std::endl; |
|---|
| 151 | XCloseDisplay( _display ); |
|---|
| 152 | _display = 0; |
|---|
| 153 | _valid = false; |
|---|
| 154 | return; |
|---|
| 155 | } |
|---|
| 156 | |
|---|
| 157 | |
|---|
| 158 | if (major < 1 || (1 == major && minor < 1)) |
|---|
| 159 | { |
|---|
| 160 | OSG_NOTICE << "Error: " << XDisplayName(_traits->displayName().c_str()) |
|---|
| 161 | << " GLX version " << major << "." << minor << " is too old." << std::endl; |
|---|
| 162 | XCloseDisplay( _display ); |
|---|
| 163 | _display = 0; |
|---|
| 164 | _valid = false; |
|---|
| 165 | return; |
|---|
| 166 | } |
|---|
| 167 | |
|---|
| 168 | bool haveGLX1_3 = false; |
|---|
| 169 | bool haveSGIX_pbuffer = false; |
|---|
| 170 | |
|---|
| 171 | |
|---|
| 172 | if (1 < major || (1 == major && 3 <= minor)) |
|---|
| 173 | { |
|---|
| 174 | haveGLX1_3 = true; |
|---|
| 175 | } |
|---|
| 176 | |
|---|
| 177 | #if defined(GLX_VERSION_1_1) |
|---|
| 178 | |
|---|
| 179 | if (!haveGLX1_3 && 1 <= minor) |
|---|
| 180 | { |
|---|
| 181 | const char *extensions = glXQueryExtensionsString(_display, screen); |
|---|
| 182 | haveSGIX_pbuffer = osg::isExtensionInExtensionString("GLX_SGIX_pbuffer", extensions) |
|---|
| 183 | && osg::isExtensionInExtensionString("GLX_SGIX_fbconfig", extensions); |
|---|
| 184 | } |
|---|
| 185 | #endif |
|---|
| 186 | |
|---|
| 187 | if (!haveGLX1_3 && !haveSGIX_pbuffer) |
|---|
| 188 | { |
|---|
| 189 | OSG_NOTICE << "Error: " << XDisplayName(_traits->displayName().c_str()) |
|---|
| 190 | << " no Pbuffer support in GLX available." << std::endl; |
|---|
| 191 | XCloseDisplay( _display ); |
|---|
| 192 | _display = 0; |
|---|
| 193 | _valid = false; |
|---|
| 194 | return; |
|---|
| 195 | } |
|---|
| 196 | |
|---|
| 197 | |
|---|
| 198 | if (!createVisualInfo()) |
|---|
| 199 | { |
|---|
| 200 | _traits->red /= 2; |
|---|
| 201 | _traits->green /= 2; |
|---|
| 202 | _traits->blue /= 2; |
|---|
| 203 | _traits->alpha /= 2; |
|---|
| 204 | _traits->depth /= 2; |
|---|
| 205 | |
|---|
| 206 | OSG_INFO<<"Relaxing traits"<<std::endl; |
|---|
| 207 | |
|---|
| 208 | if (!createVisualInfo()) |
|---|
| 209 | { |
|---|
| 210 | OSG_NOTICE<<"Error: Not able to create requested visual." << std::endl; |
|---|
| 211 | XCloseDisplay( _display ); |
|---|
| 212 | _display = 0; |
|---|
| 213 | _valid = false; |
|---|
| 214 | return; |
|---|
| 215 | } |
|---|
| 216 | } |
|---|
| 217 | |
|---|
| 218 | |
|---|
| 219 | GraphicsHandleX11* graphicsHandleX11 = dynamic_cast<GraphicsHandleX11*>(_traits->sharedContext); |
|---|
| 220 | Context sharedContext = graphicsHandleX11 ? graphicsHandleX11->getContext() : 0; |
|---|
| 221 | |
|---|
| 222 | _context = glXCreateContext( _display, _visualInfo, sharedContext, True ); |
|---|
| 223 | |
|---|
| 224 | if (!_context) |
|---|
| 225 | { |
|---|
| 226 | OSG_NOTICE<<"Error: Unable to create OpenGL graphics context."<<std::endl; |
|---|
| 227 | XCloseDisplay( _display ); |
|---|
| 228 | _display = 0; |
|---|
| 229 | _valid = false; |
|---|
| 230 | return; |
|---|
| 231 | } |
|---|
| 232 | |
|---|
| 233 | #ifdef GLX_VERSION_1_3 |
|---|
| 234 | |
|---|
| 235 | if (haveGLX1_3) |
|---|
| 236 | { |
|---|
| 237 | int nelements; |
|---|
| 238 | GLXFBConfig *fbconfigs = glXGetFBConfigs( _display, screen, &nelements ); |
|---|
| 239 | for ( int i = 0; i < nelements; ++i ) |
|---|
| 240 | { |
|---|
| 241 | int visual_id; |
|---|
| 242 | if ( glXGetFBConfigAttrib( _display, fbconfigs[i], GLX_VISUAL_ID, &visual_id ) == 0 ) |
|---|
| 243 | { |
|---|
| 244 | if ( !_pbuffer && (unsigned int)visual_id == _visualInfo->visualid ) |
|---|
| 245 | { |
|---|
| 246 | typedef std::vector <int> AttributeList; |
|---|
| 247 | |
|---|
| 248 | AttributeList attributes; |
|---|
| 249 | attributes.push_back( GLX_PBUFFER_WIDTH ); |
|---|
| 250 | attributes.push_back( _traits->width ); |
|---|
| 251 | attributes.push_back( GLX_PBUFFER_HEIGHT ); |
|---|
| 252 | attributes.push_back( _traits->height ); |
|---|
| 253 | attributes.push_back( GLX_LARGEST_PBUFFER ); |
|---|
| 254 | attributes.push_back( GL_TRUE ); |
|---|
| 255 | attributes.push_back( 0L ); |
|---|
| 256 | |
|---|
| 257 | _pbuffer = glXCreatePbuffer(_display, fbconfigs[i], &attributes.front() ); |
|---|
| 258 | _useGLX1_3 = true; |
|---|
| 259 | } |
|---|
| 260 | } |
|---|
| 261 | } |
|---|
| 262 | if (_pbuffer) |
|---|
| 263 | { |
|---|
| 264 | int iWidth = 0; |
|---|
| 265 | int iHeight = 0; |
|---|
| 266 | glXQueryDrawable(_display, _pbuffer, GLX_WIDTH , (unsigned int *)&iWidth); |
|---|
| 267 | glXQueryDrawable(_display, _pbuffer, GLX_HEIGHT , (unsigned int *)&iHeight); |
|---|
| 268 | |
|---|
| 269 | if (_traits->width != iWidth || _traits->height != iHeight) |
|---|
| 270 | { |
|---|
| 271 | OSG_NOTICE << "PixelBufferX11::init(), pbuffer created with different size then requsted" << std::endl; |
|---|
| 272 | OSG_NOTICE << "\tRequested size (" << _traits->width << "," << _traits->height << ")" << std::endl; |
|---|
| 273 | OSG_NOTICE << "\tPbuffer size (" << iWidth << "," << iHeight << ")" << std::endl; |
|---|
| 274 | _traits->width = iWidth; |
|---|
| 275 | _traits->height = iHeight; |
|---|
| 276 | } |
|---|
| 277 | } |
|---|
| 278 | XFree( fbconfigs ); |
|---|
| 279 | } |
|---|
| 280 | #endif |
|---|
| 281 | |
|---|
| 282 | #ifdef GLX_SGIX_pbuffer |
|---|
| 283 | |
|---|
| 284 | if (!_pbuffer && haveSGIX_pbuffer) |
|---|
| 285 | { |
|---|
| 286 | GLXFBConfigSGIX fbconfig = glXGetFBConfigFromVisualSGIX( _display, _visualInfo ); |
|---|
| 287 | typedef std::vector <int> AttributeList; |
|---|
| 288 | |
|---|
| 289 | AttributeList attributes; |
|---|
| 290 | attributes.push_back( GLX_LARGEST_PBUFFER_SGIX ); |
|---|
| 291 | attributes.push_back( GL_TRUE ); |
|---|
| 292 | attributes.push_back( 0L ); |
|---|
| 293 | |
|---|
| 294 | _pbuffer = glXCreateGLXPbufferSGIX(_display, fbconfig, _traits->width, _traits->height, &attributes.front() ); |
|---|
| 295 | if (_pbuffer) |
|---|
| 296 | { |
|---|
| 297 | int iWidth = 0; |
|---|
| 298 | int iHeight = 0; |
|---|
| 299 | glXQueryGLXPbufferSGIX(_display, _pbuffer, GLX_WIDTH_SGIX , (unsigned int *)&iWidth); |
|---|
| 300 | glXQueryGLXPbufferSGIX(_display, _pbuffer, GLX_HEIGHT_SGIX, (unsigned int *)&iHeight); |
|---|
| 301 | |
|---|
| 302 | if (_traits->width != iWidth || _traits->height != iHeight) |
|---|
| 303 | { |
|---|
| 304 | OSG_NOTICE << "PixelBufferX11::init(), SGIX_pbuffer created with different size then requsted" << std::endl; |
|---|
| 305 | OSG_NOTICE << "\tRequested size (" << _traits->width << "," << _traits->height << ")" << std::endl; |
|---|
| 306 | OSG_NOTICE << "\tPbuffer size (" << iWidth << "," << iHeight << ")" << std::endl; |
|---|
| 307 | _traits->width = iWidth; |
|---|
| 308 | _traits->height = iHeight; |
|---|
| 309 | } |
|---|
| 310 | } |
|---|
| 311 | XFree( fbconfig ); |
|---|
| 312 | } |
|---|
| 313 | #endif |
|---|
| 314 | |
|---|
| 315 | if (!_pbuffer) |
|---|
| 316 | { |
|---|
| 317 | OSG_NOTICE<<"Error: Unable to create pbuffer."<<std::endl; |
|---|
| 318 | XCloseDisplay( _display ); |
|---|
| 319 | _display = 0; |
|---|
| 320 | _context = 0; |
|---|
| 321 | _valid = false; |
|---|
| 322 | return; |
|---|
| 323 | } |
|---|
| 324 | |
|---|
| 325 | |
|---|
| 326 | XFlush( _display ); |
|---|
| 327 | XSync( _display, 0 ); |
|---|
| 328 | |
|---|
| 329 | _valid = true; |
|---|
| 330 | _initialized = true; |
|---|
| 331 | } |
|---|
| 332 | |
|---|
| 333 | void PixelBufferX11::closeImplementation() |
|---|
| 334 | { |
|---|
| 335 | |
|---|
| 336 | if (_display) |
|---|
| 337 | { |
|---|
| 338 | if (_context) |
|---|
| 339 | { |
|---|
| 340 | glXDestroyContext(_display, _context ); |
|---|
| 341 | } |
|---|
| 342 | |
|---|
| 343 | if (_pbuffer) |
|---|
| 344 | { |
|---|
| 345 | if (_useGLX1_3) |
|---|
| 346 | { |
|---|
| 347 | #ifdef GLX_VERSION_1_3 |
|---|
| 348 | glXDestroyPbuffer(_display, _pbuffer); |
|---|
| 349 | #endif |
|---|
| 350 | } |
|---|
| 351 | else |
|---|
| 352 | { |
|---|
| 353 | #ifdef GLX_SGIX_pbuffer |
|---|
| 354 | glXDestroyGLXPbufferSGIX(_display, _pbuffer); |
|---|
| 355 | #endif |
|---|
| 356 | } |
|---|
| 357 | } |
|---|
| 358 | |
|---|
| 359 | XFlush( _display ); |
|---|
| 360 | XSync( _display,0 ); |
|---|
| 361 | } |
|---|
| 362 | |
|---|
| 363 | _pbuffer = 0; |
|---|
| 364 | _context = 0; |
|---|
| 365 | |
|---|
| 366 | if (_visualInfo) |
|---|
| 367 | { |
|---|
| 368 | XFree(_visualInfo); |
|---|
| 369 | _visualInfo = 0; |
|---|
| 370 | } |
|---|
| 371 | |
|---|
| 372 | if (_display) |
|---|
| 373 | { |
|---|
| 374 | XCloseDisplay( _display ); |
|---|
| 375 | _display = 0; |
|---|
| 376 | } |
|---|
| 377 | |
|---|
| 378 | _initialized = false; |
|---|
| 379 | _realized = false; |
|---|
| 380 | _valid = false; |
|---|
| 381 | } |
|---|
| 382 | |
|---|
| 383 | #else |
|---|
| 384 | |
|---|
| 385 | |
|---|
| 386 | |
|---|
| 387 | bool PixelBufferX11::createVisualInfo() |
|---|
| 388 | { |
|---|
| 389 | return false; |
|---|
| 390 | } |
|---|
| 391 | |
|---|
| 392 | void PixelBufferX11::init() |
|---|
| 393 | { |
|---|
| 394 | } |
|---|
| 395 | |
|---|
| 396 | void PixelBufferX11::closeImplementation() |
|---|
| 397 | { |
|---|
| 398 | |
|---|
| 399 | _pbuffer = 0; |
|---|
| 400 | _context = 0; |
|---|
| 401 | _initialized = false; |
|---|
| 402 | _realized = false; |
|---|
| 403 | _valid = false; |
|---|
| 404 | } |
|---|
| 405 | |
|---|
| 406 | #endif |
|---|
| 407 | |
|---|
| 408 | bool PixelBufferX11::realizeImplementation() |
|---|
| 409 | { |
|---|
| 410 | if (_realized) |
|---|
| 411 | { |
|---|
| 412 | OSG_NOTICE<<"PixelBufferX11::realizeImplementation() Already realized"<<std::endl; |
|---|
| 413 | return true; |
|---|
| 414 | } |
|---|
| 415 | |
|---|
| 416 | if (!_initialized) init(); |
|---|
| 417 | |
|---|
| 418 | if (!_initialized) return false; |
|---|
| 419 | |
|---|
| 420 | _realized = true; |
|---|
| 421 | |
|---|
| 422 | return true; |
|---|
| 423 | } |
|---|
| 424 | |
|---|
| 425 | bool PixelBufferX11::makeCurrentImplementation() |
|---|
| 426 | { |
|---|
| 427 | if (!_realized) |
|---|
| 428 | { |
|---|
| 429 | OSG_NOTICE<<"Warning: GraphicsWindow not realized, cannot do makeCurrent."<<std::endl; |
|---|
| 430 | return false; |
|---|
| 431 | } |
|---|
| 432 | |
|---|
| 433 | |
|---|
| 434 | |
|---|
| 435 | #ifdef OSG_USE_EGL |
|---|
| 436 | return eglMakeCurrent(_display, _pbuffer, _pbuffer, _context)==EGL_TRUE; |
|---|
| 437 | #else |
|---|
| 438 | return glXMakeCurrent( _display, _pbuffer, _context )==True; |
|---|
| 439 | #endif |
|---|
| 440 | } |
|---|
| 441 | |
|---|
| 442 | bool PixelBufferX11::makeContextCurrentImplementation(osg::GraphicsContext* readContext) |
|---|
| 443 | { |
|---|
| 444 | |
|---|
| 445 | return makeCurrentImplementation(); |
|---|
| 446 | } |
|---|
| 447 | |
|---|
| 448 | |
|---|
| 449 | bool PixelBufferX11::releaseContextImplementation() |
|---|
| 450 | { |
|---|
| 451 | if (!_realized) |
|---|
| 452 | { |
|---|
| 453 | OSG_NOTICE<<"Warning: GraphicsWindow not realized, cannot do makeCurrent."<<std::endl; |
|---|
| 454 | return false; |
|---|
| 455 | } |
|---|
| 456 | |
|---|
| 457 | |
|---|
| 458 | |
|---|
| 459 | #ifdef OSG_USE_EGL |
|---|
| 460 | return eglMakeCurrent( _display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT )==EGL_TRUE; |
|---|
| 461 | #else |
|---|
| 462 | return glXMakeCurrent( _display, None, NULL )==True; |
|---|
| 463 | #endif |
|---|
| 464 | } |
|---|
| 465 | |
|---|
| 466 | |
|---|
| 467 | void PixelBufferX11::bindPBufferToTextureImplementation(GLenum buffer) |
|---|
| 468 | { |
|---|
| 469 | OSG_NOTICE<<"PixelBufferX11::bindPBufferToTextureImplementation() not implementation yet."<<std::endl; |
|---|
| 470 | } |
|---|
| 471 | |
|---|
| 472 | void PixelBufferX11::swapBuffersImplementation() |
|---|
| 473 | { |
|---|
| 474 | if (!_realized) return; |
|---|
| 475 | |
|---|
| 476 | |
|---|
| 477 | |
|---|
| 478 | #ifdef OSG_USE_EGL |
|---|
| 479 | eglSwapBuffers( _display, _pbuffer ); |
|---|
| 480 | #else |
|---|
| 481 | glXSwapBuffers( _display, _pbuffer ); |
|---|
| 482 | #endif |
|---|
| 483 | } |
|---|