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
|