ovr_sdk

annotate LibOVR/Src/Displays/OVR_Linux_SDKWindow.cpp @ 0:1b39a1b46319

initial 0.4.4
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 14 Jan 2015 06:51:16 +0200
parents
children
rev   line source
nuclear@0 1 /*******************************************************************************
nuclear@0 2
nuclear@0 3 Filename : OVR_Linux_SDKWindow.cpp
nuclear@0 4 Content : SDK generated Linux window.
nuclear@0 5 Created : October 1, 2014
nuclear@0 6 Authors : James Hughes
nuclear@0 7
nuclear@0 8 Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
nuclear@0 9
nuclear@0 10 Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
nuclear@0 11 you may not use the Oculus VR Rift SDK except in compliance with the License,
nuclear@0 12 which is provided at the time of installation or download, or which
nuclear@0 13 otherwise accompanies this software in either electronic or hard copy form.
nuclear@0 14
nuclear@0 15 You may obtain a copy of the License at
nuclear@0 16
nuclear@0 17 http://www.oculusvr.com/licenses/LICENSE-3.2
nuclear@0 18
nuclear@0 19 Unless required by applicable law or agreed to in writing, the Oculus VR SDK
nuclear@0 20 distributed under the License is distributed on an "AS IS" BASIS,
nuclear@0 21 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
nuclear@0 22 See the License for the specific language governing permissions and
nuclear@0 23 limitations under the License.
nuclear@0 24
nuclear@0 25 *******************************************************************************/
nuclear@0 26
nuclear@0 27 #include "OVR_Linux_SDKWindow.h"
nuclear@0 28 #include "../Kernel/OVR_Log.h"
nuclear@0 29 #include "../Kernel/OVR_Log.h"
nuclear@0 30 #include "../../../3rdParty/EDID/edid.h"
nuclear@0 31
nuclear@0 32 namespace OVR {
nuclear@0 33
nuclear@0 34 // Forward declarations
nuclear@0 35 static Window constructWindow(struct _XDisplay* display, int xscreen,
nuclear@0 36 XVisualInfo* xvisual,
nuclear@0 37 const LinuxDeviceScreen& screen);
nuclear@0 38
nuclear@0 39 static XRRModeInfo* findModeByXID(XRRScreenResources* screen, RRMode xid)
nuclear@0 40 {
nuclear@0 41 for (int m = 0; m < screen->nmode; ++m)
nuclear@0 42 {
nuclear@0 43 XRRModeInfo* mode = &screen->modes[m];
nuclear@0 44 if (xid == mode->id)
nuclear@0 45 {
nuclear@0 46 return mode;
nuclear@0 47 }
nuclear@0 48 }
nuclear@0 49 return NULL;
nuclear@0 50 }
nuclear@0 51
nuclear@0 52 /// Retrieves a list of available device screens on which we can build
nuclear@0 53 /// SDK windows. Returns number of devices found.
nuclear@0 54 /// screens Array which this function will populate.
nuclear@0 55 /// maxNumScreens Maximum number of screens to store in screens.
nuclear@0 56 static int getDeviceScreens(LinuxDeviceScreen* screens, int maxNumDevices)
nuclear@0 57 {
nuclear@0 58 struct _XDisplay* disp = XOpenDisplay(NULL);
nuclear@0 59 if (!disp)
nuclear@0 60 {
nuclear@0 61 OVR::LogError("[SDKWindow] Unable to open X Display.");
nuclear@0 62 return 0;
nuclear@0 63 }
nuclear@0 64
nuclear@0 65 int numDevices = 0;
nuclear@0 66 int numScreens = XScreenCount(disp);
nuclear@0 67 for (int i = 0; i < numScreens; ++i)
nuclear@0 68 {
nuclear@0 69 // Screen root is used to detect what video output the crtc is using.
nuclear@0 70 Window sr = XRootWindow(disp, i);
nuclear@0 71 XRRScreenResources* screen = XRRGetScreenResources(disp, sr);
nuclear@0 72
nuclear@0 73 for (int ii = 0; ii < screen->ncrtc; ++ii)
nuclear@0 74 {
nuclear@0 75 XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(disp, screen, screen->crtcs[ii]);
nuclear@0 76
nuclear@0 77 if (0 == crtcInfo->noutput)
nuclear@0 78 {
nuclear@0 79 XRRFreeCrtcInfo(crtcInfo);
nuclear@0 80 continue;
nuclear@0 81 }
nuclear@0 82
nuclear@0 83 bool foundOutput = false;
nuclear@0 84 RROutput output = crtcInfo->outputs[0];
nuclear@0 85 for (int k = 0; k < crtcInfo->noutput; ++k)
nuclear@0 86 {
nuclear@0 87 XRROutputInfo* outputInfo =
nuclear@0 88 XRRGetOutputInfo(disp, screen, crtcInfo->outputs[k]);
nuclear@0 89 for (int kk = 0 ; kk < outputInfo->nmode; ++kk)
nuclear@0 90 {
nuclear@0 91 if (outputInfo->modes[kk] == crtcInfo->mode)
nuclear@0 92 {
nuclear@0 93 output = crtcInfo->outputs[k];
nuclear@0 94 foundOutput = true;
nuclear@0 95 break;
nuclear@0 96 }
nuclear@0 97 }
nuclear@0 98 XRRFreeOutputInfo(outputInfo);
nuclear@0 99 if (foundOutput) { break; }
nuclear@0 100 }
nuclear@0 101
nuclear@0 102 if (!foundOutput)
nuclear@0 103 {
nuclear@0 104 XRRFreeCrtcInfo(crtcInfo);
nuclear@0 105 continue;
nuclear@0 106 }
nuclear@0 107
nuclear@0 108 XRROutputInfo* outputInfo = XRRGetOutputInfo(disp, screen, output);
nuclear@0 109 if (RR_Connected != outputInfo->connection)
nuclear@0 110 {
nuclear@0 111 XRRFreeOutputInfo(outputInfo);
nuclear@0 112 XRRFreeCrtcInfo(crtcInfo);
nuclear@0 113 continue;
nuclear@0 114 }
nuclear@0 115
nuclear@0 116 // Read EDID associated with crtc.
nuclear@0 117 MonitorInfo* mi = read_edid_data(disp, output);
nuclear@0 118 if (mi == NULL)
nuclear@0 119 {
nuclear@0 120 XRRFreeOutputInfo(outputInfo);
nuclear@0 121 XRRFreeCrtcInfo(crtcInfo);
nuclear@0 122 continue;
nuclear@0 123 }
nuclear@0 124
nuclear@0 125 if (strcmp(mi->manufacturer_code, "OVR") == 0)
nuclear@0 126 {
nuclear@0 127 XRRModeInfo* modeInfo = findModeByXID(screen, crtcInfo->mode);
nuclear@0 128
nuclear@0 129 DistortionRotation desiredRot = DistRotateNone;
nuclear@0 130 if (mi->product_code == 3)
nuclear@0 131 {
nuclear@0 132 // This is a DK2, we may have to rotate our output.
nuclear@0 133 // If we don't have to, we should alert the user that
nuclear@0 134 // rotating the display using the DM or graphics
nuclear@0 135 // card settings is highly non-optimal.
nuclear@0 136 desiredRot = DistRotateCCW90;
nuclear@0 137 if (crtcInfo->rotation != RR_Rotate_0)
nuclear@0 138 {
nuclear@0 139 OVR::LogError("Please do not rotate your rift's screen.");
nuclear@0 140
nuclear@0 141 if (crtcInfo->rotation == RR_Rotate_90)
nuclear@0 142 {
nuclear@0 143 // The user has manually rotated the screen.
nuclear@0 144 // So apply no rotation on our end.
nuclear@0 145 desiredRot = DistRotateNone;
nuclear@0 146 }
nuclear@0 147 }
nuclear@0 148 }
nuclear@0 149 else
nuclear@0 150 {
nuclear@0 151 if (crtcInfo->rotation != RR_Rotate_0)
nuclear@0 152 {
nuclear@0 153 OVR::LogError("Please do not rotate your rift's screen.");
nuclear@0 154 }
nuclear@0 155 }
nuclear@0 156
nuclear@0 157 int width = modeInfo->width;
nuclear@0 158 int height = modeInfo->height;
nuclear@0 159
nuclear@0 160 // Swap width / height if display is rotated (shouldn't be on linux).
nuclear@0 161 if ( crtcInfo->rotation == RR_Rotate_90
nuclear@0 162 || crtcInfo->rotation == RR_Rotate_270)
nuclear@0 163 {
nuclear@0 164 width = modeInfo->height;
nuclear@0 165 height = modeInfo->width;
nuclear@0 166 }
nuclear@0 167
nuclear@0 168 // Push detected monitor.
nuclear@0 169 screens[numDevices].set(i, screen->crtcs[ii], desiredRot,
nuclear@0 170 mi->product_code, width, height,
nuclear@0 171 crtcInfo->x, crtcInfo->y);
nuclear@0 172 ++numDevices;
nuclear@0 173 }
nuclear@0 174
nuclear@0 175 delete mi;
nuclear@0 176
nuclear@0 177 if (numDevices == maxNumDevices)
nuclear@0 178 {
nuclear@0 179 XRRFreeOutputInfo(outputInfo);
nuclear@0 180 XRRFreeCrtcInfo(crtcInfo);
nuclear@0 181 XRRFreeScreenResources(screen);
nuclear@0 182 OVR::LogError("[SDKWindow] Maxed out number of devices..");
nuclear@0 183 XCloseDisplay(disp);
nuclear@0 184 return numDevices;
nuclear@0 185 }
nuclear@0 186
nuclear@0 187 XRRFreeOutputInfo(outputInfo);
nuclear@0 188 XRRFreeCrtcInfo(crtcInfo);
nuclear@0 189 }
nuclear@0 190
nuclear@0 191 XRRFreeScreenResources(screen);
nuclear@0 192 }
nuclear@0 193 XCloseDisplay(disp);
nuclear@0 194 return numDevices;
nuclear@0 195 }
nuclear@0 196
nuclear@0 197
nuclear@0 198 LinuxDeviceScreen SDKWindow::findDevScreenForHMD(const ovrHmd& hmd)
nuclear@0 199 {
nuclear@0 200 return findDevScreenForDevID(hmd->DisplayDeviceName);
nuclear@0 201 }
nuclear@0 202
nuclear@0 203 LinuxDeviceScreen SDKWindow::findDevScreenForDevID(const char* deviceIDIn)
nuclear@0 204 {
nuclear@0 205 const int maxNumDevices = 5;
nuclear@0 206 LinuxDeviceScreen screens[maxNumDevices];
nuclear@0 207 int numDevices = getDeviceScreens(screens, maxNumDevices);
nuclear@0 208
nuclear@0 209 if (numDevices > 0)
nuclear@0 210 {
nuclear@0 211 // Identify target for SDK window via hmd info.
nuclear@0 212 for (int i = 0; i < numDevices; ++i)
nuclear@0 213 {
nuclear@0 214 LinuxDeviceScreen& screen = screens[i];
nuclear@0 215
nuclear@0 216 char deviceID[32];
nuclear@0 217 OVR_sprintf(deviceID, 32, "OVR%04d-%d",
nuclear@0 218 screen.productCode, screen.crtcid);
nuclear@0 219
nuclear@0 220 if (strcmp(deviceIDIn, deviceID) == 0)
nuclear@0 221 {
nuclear@0 222 return screen;
nuclear@0 223 }
nuclear@0 224 }
nuclear@0 225 }
nuclear@0 226
nuclear@0 227 return LinuxDeviceScreen();
nuclear@0 228 }
nuclear@0 229
nuclear@0 230 DistortionRotation SDKWindow::getRotation(const ovrHmd& hmd)
nuclear@0 231 {
nuclear@0 232 LinuxDeviceScreen screen = findDevScreenForHMD(hmd);
nuclear@0 233 if (screen.isValid())
nuclear@0 234 {
nuclear@0 235 return screen.rotation;
nuclear@0 236 }
nuclear@0 237 else
nuclear@0 238 {
nuclear@0 239 return DistRotateNone;
nuclear@0 240 }
nuclear@0 241 }
nuclear@0 242
nuclear@0 243
nuclear@0 244 bool SDKWindow::getVisualFromDrawable(GLXDrawable drawable, XVisualInfo* vinfoOut)
nuclear@0 245 {
nuclear@0 246 struct _XDisplay* display = glXGetCurrentDisplay();
nuclear@0 247
nuclear@0 248 unsigned int value;
nuclear@0 249 glXQueryDrawable(display, drawable, GLX_FBCONFIG_ID, &value);
nuclear@0 250 const int attribs[] = {GLX_FBCONFIG_ID, (int)value, None};
nuclear@0 251 int screen;
nuclear@0 252 glXQueryContext(display, glXGetCurrentContext(), GLX_SCREEN, &screen);
nuclear@0 253 int numElems;
nuclear@0 254 GLXFBConfig* config = glXChooseFBConfig(display, screen, attribs, &numElems);
nuclear@0 255 if (numElems > 0)
nuclear@0 256 {
nuclear@0 257 XVisualInfo* chosen = glXGetVisualFromFBConfig(display, *config);
nuclear@0 258 *vinfoOut = *chosen;
nuclear@0 259 XFree(config);
nuclear@0 260 return true;
nuclear@0 261 }
nuclear@0 262 return false;
nuclear@0 263 }
nuclear@0 264
nuclear@0 265 SDKWindow::SDKWindow(const ovrHmd& hmd) :
nuclear@0 266 mXDisplay(NULL),
nuclear@0 267 mXScreen(-1),
nuclear@0 268 mXVisual(NULL),
nuclear@0 269 mXUniqueContext(-1),
nuclear@0 270 mXWindow(0),
nuclear@0 271 mFBConfigID(0)
nuclear@0 272 {
nuclear@0 273 OVR_UNUSED(hmd);
nuclear@0 274 }
nuclear@0 275
nuclear@0 276 SDKWindow::~SDKWindow()
nuclear@0 277 {
nuclear@0 278 if (mXWindow)
nuclear@0 279 {
nuclear@0 280 XDeleteContext(mXDisplay, mXWindow, mXUniqueContext);
nuclear@0 281 XUnmapWindow(mXDisplay, mXWindow);
nuclear@0 282 XDestroyWindow(mXDisplay, mXWindow);
nuclear@0 283 mXWindow = static_cast<Window>(0);
nuclear@0 284 }
nuclear@0 285
nuclear@0 286 if (mXVisual)
nuclear@0 287 {
nuclear@0 288 XFree(mXVisual);
nuclear@0 289 mXVisual = NULL;
nuclear@0 290 }
nuclear@0 291
nuclear@0 292 if (mXDisplay)
nuclear@0 293 {
nuclear@0 294 XCloseDisplay(mXDisplay);
nuclear@0 295 }
nuclear@0 296 }
nuclear@0 297
nuclear@0 298 void SDKWindow::buildVisualAndWindow(const LinuxDeviceScreen& devScreen)
nuclear@0 299 {
nuclear@0 300 mXDisplay = XOpenDisplay(NULL);
nuclear@0 301 mXUniqueContext = XUniqueContext();
nuclear@0 302 mXScreen = devScreen.screen;
nuclear@0 303 mFBConfigID = chooseFBConfigID(mXDisplay, mXScreen);
nuclear@0 304
nuclear@0 305 mXVisual = getVisual(mXDisplay, mFBConfigID, mXScreen);
nuclear@0 306 if (mXVisual != NULL)
nuclear@0 307 {
nuclear@0 308 mXWindow = constructWindow(mXDisplay, mXScreen, mXVisual, devScreen);
nuclear@0 309 mDeviceScreen = devScreen;
nuclear@0 310 }
nuclear@0 311 }
nuclear@0 312
nuclear@0 313 // Used in chooseVisual. May need to expose this to the end use so they can
nuclear@0 314 // choose an appropriate framebuffer configuration.
nuclear@0 315 struct FBConfig
nuclear@0 316 {
nuclear@0 317 FBConfig() :
nuclear@0 318 redBits(8),
nuclear@0 319 greenBits(8),
nuclear@0 320 blueBits(8),
nuclear@0 321 alphaBits(8),
nuclear@0 322 depthBits(8),
nuclear@0 323 stencilBits(-1),
nuclear@0 324 doubleBuffer(true),
nuclear@0 325 auxBuffers(-1)
nuclear@0 326 {}
nuclear@0 327
nuclear@0 328 int redBits;
nuclear@0 329 int greenBits;
nuclear@0 330 int blueBits;
nuclear@0 331 int alphaBits;
nuclear@0 332 int depthBits;
nuclear@0 333 int stencilBits;
nuclear@0 334 bool doubleBuffer;
nuclear@0 335 int auxBuffers;
nuclear@0 336
nuclear@0 337 int xcfg;
nuclear@0 338 };
nuclear@0 339
nuclear@0 340 static int fbCalcContrib(int desired, int current)
nuclear@0 341 {
nuclear@0 342 int diff = desired - current;
nuclear@0 343 if (current != -1) { return diff * diff; }
nuclear@0 344 else { return 0; }
nuclear@0 345 }
nuclear@0 346
nuclear@0 347 // Choose frame buffer configuration and return fbConfigID.
nuclear@0 348 int SDKWindow::chooseFBConfigID(struct _XDisplay* display, int xscreen)
nuclear@0 349 {
nuclear@0 350 int nativeCount = 0;
nuclear@0 351 GLXFBConfig* nativeConfigs =
nuclear@0 352 glXGetFBConfigs(display, xscreen, &nativeCount);
nuclear@0 353 if (!nativeCount)
nuclear@0 354 {
nuclear@0 355 OVR::LogError("[SDKWindow] No valid frame buffer configurations found.");
nuclear@0 356 return 0;
nuclear@0 357 }
nuclear@0 358
nuclear@0 359 FBConfig* usables = static_cast<FBConfig*>(calloc(nativeCount, sizeof(FBConfig)));
nuclear@0 360 int numUsables = 0;
nuclear@0 361
nuclear@0 362 for (int i = 0; i < nativeCount; ++i)
nuclear@0 363 {
nuclear@0 364 GLXFBConfig native = nativeConfigs[i];
nuclear@0 365 FBConfig* usable = &usables[numUsables];
nuclear@0 366 int v = 0;
nuclear@0 367
nuclear@0 368 // Only frame buffer configcs with attached visuals.
nuclear@0 369 glXGetFBConfigAttrib(display, native, GLX_VISUAL_ID, &v);
nuclear@0 370 if (!v) { continue; }
nuclear@0 371
nuclear@0 372 // Only RGBA frame buffers.
nuclear@0 373 glXGetFBConfigAttrib(display, native, GLX_RENDER_TYPE, &v);
nuclear@0 374 if (!(v & GLX_RGBA_BIT)) { continue; }
nuclear@0 375
nuclear@0 376 glXGetFBConfigAttrib(display, native, GLX_DRAWABLE_TYPE, &v);
nuclear@0 377 if (!(v & GLX_WINDOW_BIT)) { continue; }
nuclear@0 378
nuclear@0 379 glXGetFBConfigAttrib(display, native, GLX_DEPTH_SIZE, &usable->depthBits);
nuclear@0 380 glXGetFBConfigAttrib(display, native, GLX_STENCIL_SIZE, &usable->stencilBits);
nuclear@0 381
nuclear@0 382 glXGetFBConfigAttrib(display, native, GLX_RED_SIZE, &usable->redBits);
nuclear@0 383 glXGetFBConfigAttrib(display, native, GLX_GREEN_SIZE, &usable->greenBits);
nuclear@0 384 glXGetFBConfigAttrib(display, native, GLX_BLUE_SIZE, &usable->blueBits);
nuclear@0 385 glXGetFBConfigAttrib(display, native, GLX_ALPHA_SIZE, &usable->alphaBits);
nuclear@0 386
nuclear@0 387 glXGetFBConfigAttrib(display, native, GLX_ALPHA_SIZE, &usable->auxBuffers);
nuclear@0 388
nuclear@0 389 glXGetFBConfigAttrib(display, native, GLX_DOUBLEBUFFER, &v);
nuclear@0 390 usable->doubleBuffer = v ? true : false;
nuclear@0 391
nuclear@0 392 glXGetFBConfigAttrib(display, native, GLX_FBCONFIG_ID, &usable->xcfg);
nuclear@0 393
nuclear@0 394 ++numUsables;
nuclear@0 395 }
nuclear@0 396
nuclear@0 397 // We really want std::numeric_limits<int>::max() instead of hardcoded vals.
nuclear@0 398 const int MostMissing = 100;
nuclear@0 399 int leastMissing = MostMissing;
nuclear@0 400 int leastBias = MostMissing;
nuclear@0 401
nuclear@0 402 const FBConfig* closest = NULL;
nuclear@0 403
nuclear@0 404 // Desired is currently the default config built by constructor.
nuclear@0 405 FBConfig desired;
nuclear@0 406
nuclear@0 407 for (int i = 0; i < numUsables; ++i)
nuclear@0 408 {
nuclear@0 409 const FBConfig* cur = &usables[i];
nuclear@0 410
nuclear@0 411 if (desired.doubleBuffer != cur->doubleBuffer) { continue; }
nuclear@0 412
nuclear@0 413 int missing = 0;
nuclear@0 414 if (desired.alphaBits > 0 && cur->alphaBits == 0) { ++missing; }
nuclear@0 415 if (desired.depthBits > 0 && cur->depthBits == 0) { ++missing; }
nuclear@0 416 if (desired.stencilBits > 0 && cur->stencilBits == 0) { ++missing; }
nuclear@0 417 if (desired.redBits > 0 && desired.redBits != cur->redBits) { ++missing; }
nuclear@0 418 if (desired.greenBits > 0 && desired.greenBits != cur->greenBits) { ++missing; }
nuclear@0 419 if (desired.blueBits > 0 && desired.blueBits != cur->blueBits) { ++missing; }
nuclear@0 420
nuclear@0 421 int bias = fbCalcContrib(desired.redBits, cur->redBits)
nuclear@0 422 + fbCalcContrib(desired.greenBits, cur->greenBits)
nuclear@0 423 + fbCalcContrib(desired.blueBits, cur->blueBits)
nuclear@0 424 + fbCalcContrib(desired.alphaBits, cur->alphaBits)
nuclear@0 425 + fbCalcContrib(desired.depthBits, cur->depthBits)
nuclear@0 426 + fbCalcContrib(desired.stencilBits, cur->stencilBits);
nuclear@0 427
nuclear@0 428 if (missing < leastMissing)
nuclear@0 429 {
nuclear@0 430 closest = cur;
nuclear@0 431 }
nuclear@0 432 else if (missing == leastMissing)
nuclear@0 433 {
nuclear@0 434 // Now select against squared differences.
nuclear@0 435 if (bias < leastBias)
nuclear@0 436 {
nuclear@0 437 closest = cur;
nuclear@0 438 }
nuclear@0 439 }
nuclear@0 440
nuclear@0 441 if (closest == cur)
nuclear@0 442 {
nuclear@0 443 leastMissing = missing;
nuclear@0 444 leastBias = bias;
nuclear@0 445 }
nuclear@0 446 }
nuclear@0 447
nuclear@0 448 if (closest == NULL)
nuclear@0 449 {
nuclear@0 450 OVR::LogError("[SDKWindow] Failed to select appropriate frame buffer.");
nuclear@0 451 XFree(nativeConfigs);
nuclear@0 452 free(usables);
nuclear@0 453 return 0;
nuclear@0 454 }
nuclear@0 455
nuclear@0 456 int retVal = closest->xcfg;
nuclear@0 457
nuclear@0 458 XFree(nativeConfigs);
nuclear@0 459 free(usables);
nuclear@0 460
nuclear@0 461 return retVal;
nuclear@0 462 }
nuclear@0 463
nuclear@0 464 // Obtain visual from frame buffer configuration ID.
nuclear@0 465 XVisualInfo* SDKWindow::getVisual(struct _XDisplay* display,
nuclear@0 466 int fbConfigID, int xscreen)
nuclear@0 467 {
nuclear@0 468 GLXFBConfig* cfg = getGLXFBConfig(display, fbConfigID, xscreen);
nuclear@0 469 XVisualInfo* viOut = NULL;
nuclear@0 470 if (cfg != NULL)
nuclear@0 471 {
nuclear@0 472 viOut = glXGetVisualFromFBConfig(display, *cfg);
nuclear@0 473 XFree(cfg);
nuclear@0 474 cfg = NULL;
nuclear@0 475 }
nuclear@0 476 else
nuclear@0 477 {
nuclear@0 478 OVR::LogError("Unable to find fb config ID.");
nuclear@0 479 }
nuclear@0 480 return viOut;
nuclear@0 481 }
nuclear@0 482
nuclear@0 483 // GLXFBConfig pointer from frame buffer configuration ID. You must call
nuclear@0 484 // XFree on the GLXFBConfig pointer.
nuclear@0 485 GLXFBConfig* SDKWindow::getGLXFBConfig(struct _XDisplay* display,
nuclear@0 486 int fbConfigID, int xscreen)
nuclear@0 487 {
nuclear@0 488 const int attribs[] = {GLX_FBCONFIG_ID, (int)fbConfigID, None};
nuclear@0 489 int numElems;
nuclear@0 490
nuclear@0 491 GLXFBConfig* config = glXChooseFBConfig(display, xscreen, attribs, &numElems);
nuclear@0 492 if (numElems > 0)
nuclear@0 493 {
nuclear@0 494 return config;
nuclear@0 495 }
nuclear@0 496 else
nuclear@0 497 {
nuclear@0 498 return NULL;
nuclear@0 499 }
nuclear@0 500 }
nuclear@0 501
nuclear@0 502
nuclear@0 503 static int gXLastError = -1;
nuclear@0 504 static int handleXError(struct _XDisplay* display, XErrorEvent* event)
nuclear@0 505 {
nuclear@0 506 OVR_UNUSED(display);
nuclear@0 507 gXLastError = event->error_code;
nuclear@0 508 return 0;
nuclear@0 509 }
nuclear@0 510
nuclear@0 511 static void obtainXErrorHandler()
nuclear@0 512 {
nuclear@0 513 gXLastError = Success;
nuclear@0 514 XSetErrorHandler(handleXError);
nuclear@0 515 }
nuclear@0 516
nuclear@0 517 static void releaseXErrorHandler(struct _XDisplay* display)
nuclear@0 518 {
nuclear@0 519 XSync(display, False);
nuclear@0 520 XSetErrorHandler(NULL);
nuclear@0 521 }
nuclear@0 522
nuclear@0 523 // Returns 0 on error, otherwise a valid X window is returned.
nuclear@0 524 static Window constructWindow(struct _XDisplay* xDisp, int xScreen,
nuclear@0 525 XVisualInfo* xVisual,
nuclear@0 526 const LinuxDeviceScreen& devScreen)
nuclear@0 527 {
nuclear@0 528 XSetWindowAttributes wa;
nuclear@0 529
nuclear@0 530 Window root = XRootWindow(xDisp, xScreen);
nuclear@0 531 Window xWindowOut = 0;
nuclear@0 532
nuclear@0 533 // Create Window
nuclear@0 534 {
nuclear@0 535 Colormap xWinColorMapOut = XCreateColormap(
nuclear@0 536 xDisp, root, xVisual->visual, AllocNone);
nuclear@0 537 unsigned long wamask = CWBorderPixel | CWColormap | CWEventMask;
nuclear@0 538
nuclear@0 539 wa.colormap = xWinColorMapOut;
nuclear@0 540 wa.border_pixel = 0;
nuclear@0 541 wa.event_mask = StructureNotifyMask | ExposureMask | FocusChangeMask
nuclear@0 542 | VisibilityChangeMask | EnterWindowMask | LeaveWindowMask
nuclear@0 543 | PropertyChangeMask;
nuclear@0 544
nuclear@0 545 obtainXErrorHandler();
nuclear@0 546
nuclear@0 547 xWindowOut = XCreateWindow(xDisp, root,
nuclear@0 548 0, 0,
nuclear@0 549 devScreen.width, devScreen.height,
nuclear@0 550 0,
nuclear@0 551 xVisual->depth,
nuclear@0 552 InputOutput,
nuclear@0 553 xVisual->visual,
nuclear@0 554 wamask,
nuclear@0 555 &wa);
nuclear@0 556
nuclear@0 557 releaseXErrorHandler(xDisp);
nuclear@0 558
nuclear@0 559 if (!xWindowOut)
nuclear@0 560 {
nuclear@0 561 OVR::LogError("[SDKWindow] Failed to create SDK window.");
nuclear@0 562 return 0;
nuclear@0 563 }
nuclear@0 564
nuclear@0 565 XFreeColormap(xDisp, xWinColorMapOut);
nuclear@0 566 }
nuclear@0 567
nuclear@0 568 // OVERRIDE REDIRECT.
nuclear@0 569 XSetWindowAttributes attributes;
nuclear@0 570 attributes.override_redirect = True;
nuclear@0 571 XChangeWindowAttributes(xDisp, xWindowOut,
nuclear@0 572 CWOverrideRedirect, &attributes);
nuclear@0 573
nuclear@0 574 // Show the window (do this in full screen or windowed).
nuclear@0 575 XMapRaised(xDisp, xWindowOut);
nuclear@0 576 XFlush(xDisp);
nuclear@0 577
nuclear@0 578 // Position ourselves manually since there should be no WM managing us.
nuclear@0 579 XRaiseWindow(xDisp, xWindowOut);
nuclear@0 580 XMoveWindow(xDisp, xWindowOut, devScreen.offsetX, devScreen.offsetY);
nuclear@0 581 XResizeWindow(xDisp, xWindowOut, devScreen.width, devScreen.height);
nuclear@0 582
nuclear@0 583 XFlush(xDisp);
nuclear@0 584
nuclear@0 585 // WM Backup in case there still exists a WM managing us...
nuclear@0 586 Atom NET_WM_BYPASS_COMPOSITOR =
nuclear@0 587 XInternAtom(xDisp, "_NET_WM_BYPASS_COMPOSITOR", False);
nuclear@0 588 Atom NET_WM_STATE =
nuclear@0 589 XInternAtom(xDisp, "_NET_WM_STATE", False);
nuclear@0 590 Atom NET_WM_STATE_FULLSCREEN =
nuclear@0 591 XInternAtom(xDisp, "_NET_WM_STATE_FULLSCREEN", False);
nuclear@0 592 Atom NET_ACTIVE_WINDOW =
nuclear@0 593 XInternAtom(xDisp, "_NET_ACTIVE_WINDOW", False);
nuclear@0 594
nuclear@0 595 // Bypass compositor if we are under a compositing WM.
nuclear@0 596 // Just in case a WM ignores our override_redirect.
nuclear@0 597 if (NET_WM_BYPASS_COMPOSITOR)
nuclear@0 598 {
nuclear@0 599 const unsigned long bypass = 1;
nuclear@0 600 XChangeProperty(xDisp, xWindowOut,
nuclear@0 601 NET_WM_BYPASS_COMPOSITOR,
nuclear@0 602 XA_CARDINAL, 32, PropModeReplace,
nuclear@0 603 (unsigned char*)&bypass, 1);
nuclear@0 604 }
nuclear@0 605
nuclear@0 606 if (NET_WM_STATE && NET_WM_STATE_FULLSCREEN)
nuclear@0 607 {
nuclear@0 608 // BACKUP: If we are still managed by a WM we want fullscreen.
nuclear@0 609 const int EWMH_STATE_ADD = 1;
nuclear@0 610
nuclear@0 611 if (NET_ACTIVE_WINDOW)
nuclear@0 612 {
nuclear@0 613 XEvent event;
nuclear@0 614 memset(&event, 0, sizeof(event));
nuclear@0 615
nuclear@0 616 event.type = ClientMessage;
nuclear@0 617 event.xclient.window = xWindowOut;
nuclear@0 618 event.xclient.format = 32;
nuclear@0 619 event.xclient.message_type = NET_ACTIVE_WINDOW;
nuclear@0 620 event.xclient.data.l[0] = 1;
nuclear@0 621 event.xclient.data.l[1] = 0;
nuclear@0 622
nuclear@0 623 XSendEvent(xDisp, root, False,
nuclear@0 624 SubstructureNotifyMask | SubstructureRedirectMask,
nuclear@0 625 &event);
nuclear@0 626 }
nuclear@0 627
nuclear@0 628 XEvent event;
nuclear@0 629 memset(&event, 0, sizeof(event));
nuclear@0 630
nuclear@0 631 event.type = ClientMessage;
nuclear@0 632 event.xclient.window = xWindowOut;
nuclear@0 633 event.xclient.format = 32;
nuclear@0 634 event.xclient.message_type = NET_WM_STATE;
nuclear@0 635 event.xclient.data.l[0] = EWMH_STATE_ADD;
nuclear@0 636 event.xclient.data.l[1] = NET_WM_STATE_FULLSCREEN;
nuclear@0 637 event.xclient.data.l[2] = 0;
nuclear@0 638 event.xclient.data.l[3] = 1;
nuclear@0 639
nuclear@0 640 XSendEvent(xDisp, root, False,
nuclear@0 641 SubstructureNotifyMask | SubstructureRedirectMask,
nuclear@0 642 &event);
nuclear@0 643 }
nuclear@0 644
nuclear@0 645 return xWindowOut;
nuclear@0 646 }
nuclear@0 647
nuclear@0 648 } // namespace OVR
nuclear@0 649