diff options
Diffstat (limited to 'LibOVR/Src/Displays')
19 files changed, 2164 insertions, 55 deletions
diff --git a/LibOVR/Src/Displays/OVR_Display.cpp b/LibOVR/Src/Displays/OVR_Display.cpp index c7a624f..55eb8a9 100644 --- a/LibOVR/Src/Displays/OVR_Display.cpp +++ b/LibOVR/Src/Displays/OVR_Display.cpp @@ -6,16 +6,16 @@ Content : Common implementation for display device Created : May 6, 2014 Notes : -Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved. +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. -Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License"); +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); you may not use the Oculus VR Rift SDK except in compliance with the License, which is provided at the time of installation or download, or which otherwise accompanies this software in either electronic or hard copy form. You may obtain a copy of the License at -http://www.oculusvr.com/licenses/LICENSE-3.1 +http://www.oculusvr.com/licenses/LICENSE-3.2 Unless required by applicable law or agreed to in writing, the Oculus VR SDK distributed under the License is distributed on an "AS IS" BASIS, diff --git a/LibOVR/Src/Displays/OVR_Display.h b/LibOVR/Src/Displays/OVR_Display.h index bcba4bc..46e9f13 100644 --- a/LibOVR/Src/Displays/OVR_Display.h +++ b/LibOVR/Src/Displays/OVR_Display.h @@ -6,16 +6,16 @@ Content : Contains platform independent display management Created : May 6, 2014 Notes : -Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved. +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. -Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License"); +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); you may not use the Oculus VR Rift SDK except in compliance with the License, which is provided at the time of installation or download, or which otherwise accompanies this software in either electronic or hard copy form. You may obtain a copy of the License at -http://www.oculusvr.com/licenses/LICENSE-3.1 +http://www.oculusvr.com/licenses/LICENSE-3.2 Unless required by applicable law or agreed to in writing, the Oculus VR SDK distributed under the License is distributed on an "AS IS" BASIS, @@ -91,6 +91,7 @@ protected: const uint64_t devNumber, const uint32_t rotation, const bool appExclusive): + mirrorMode(MirrorDisabled), DeviceTypeGuess(deviceTypeGuess), DisplayID(displayID), ModelName(modelName), diff --git a/LibOVR/Src/Displays/OVR_Linux_Display.cpp b/LibOVR/Src/Displays/OVR_Linux_Display.cpp new file mode 100644 index 0000000..b983635 --- /dev/null +++ b/LibOVR/Src/Displays/OVR_Linux_Display.cpp @@ -0,0 +1,494 @@ +/************************************************************************************ + +Filename : OVR_Linux_Display.cpp +Content : Linux-specific Display declarations +Created : July 2, 2014 +Authors : James Hughes + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); +you may not use the Oculus VR Rift SDK except in compliance with the License, +which is provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +You may obtain a copy of the License at + +http://www.oculusvr.com/licenses/LICENSE-3.2 + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*************************************************************************************/ + +#include "OVR_Linux_Display.h" +#include "../Kernel/OVR_Log.h" + +#include "../../../3rdParty/EDID/edid.h" + +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/extensions/Xrandr.h> +#include <X11/Xatom.h> + +//------------------------------------------------------------------------------------- +// ***** Display enumeration Helpers + +namespace OVR { + +static const uint8_t edid_v1_header[] = { 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00 }; + +static const uint8_t edid_v1_descriptor_flag[] = { 0x00, 0x00 }; + +static const int DESCRIPTOR_DATA = 5; +static const int UNKNOWN_DESCRIPTOR = -1; +static const int DETAILED_TIMING_BLOCK = -2; + +// The following three functions were pulled from OVR_Linux_Display.cpp +// and modified slightly. +static int blockType(uint8_t* block) +{ + if (!strncmp((const char*)edid_v1_descriptor_flag, (const char*)block, 2)) + { + if (block[2] != 0) + { + return UNKNOWN_DESCRIPTOR; + } + else + { + return block[3]; + } + } + else + { + return DETAILED_TIMING_BLOCK; + } +} + +static char* getMonitorName(const uint8_t* block) +{ + static char name[13]; + uint8_t const* ptr = block + DESCRIPTOR_DATA; + + for (int i = 0; i < 13; i++, ptr++) + { + if (*ptr == 0xa) + { + name[i] = 0; + return name; + } + + name[i] = *ptr; + } + + return name; +} + +// Returns -1 on failure, 0 otherwise. +static int parseEdid(uint8_t* edid, Linux::DisplayEDID& edidResult) +{ + const int EDID_LENGTH = 0x80; + const int EDID_HEADER = 0x00; + const int EDID_HEADER_END = 0x07; + + // const int EDID_STRUCT_VERSION = 0x12; + // const int EDID_STRUCT_REVISION = 0x13; + + const int MONITOR_NAME = 0xfc; + // const int MONITOR_LIMITS = 0xfd; + const int MONITOR_SERIAL = 0xff; + + // const int ESTABLISHED_TIMING_1 = 0x23; + // const int ESTABLISHED_TIMING_2 = 0x24; + // const int MANUFACTURERS_TIMINGS = 0x25; + + const int DETAILED_TIMING_DESCRIPTIONS_START = 0x36; + const int DETAILED_TIMING_DESCRIPTION_SIZE = 18; + const int NO_DETAILED_TIMING_DESCRIPTIONS = 4; + + // const int DETAILED_TIMING_DESCRIPTION_1 = 0x36; + // const int DETAILED_TIMING_DESCRIPTION_2 = 0x48; + // const int DETAILED_TIMING_DESCRIPTION_3 = 0x5a; + // const int DETAILED_TIMING_DESCRIPTION_4 = 0x6c; + + const char* monitorName = "Unknown"; + uint8_t* block = NULL; + uint8_t checksum = 0; + + for (int i = 0; i < EDID_LENGTH; i++) + { + checksum += edid[i]; + } + + // Bad checksum, fail EDID + if (checksum != 0) + { + return -1; + } + + if (strncmp((const char*)edid + EDID_HEADER, + (const char*)edid_v1_header, EDID_HEADER_END + 1)) + { + // First bytes don't match EDID version 1 header + return -1; + } + + // Monitor name and timings + char serialNumber[14]; + memset(serialNumber, 0, 14); + + block = edid + DETAILED_TIMING_DESCRIPTIONS_START; + + for (int i = 0; i < NO_DETAILED_TIMING_DESCRIPTIONS; + i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) + { + + if (blockType(block) == MONITOR_NAME) + { + monitorName = getMonitorName(block); + } + + if (blockType(block) == MONITOR_SERIAL) + { + memcpy(serialNumber, block + 5, 13); + break; + } + } + + uint8_t vendorString[4] = {0}; + + vendorString[0] = (edid[8] >> 2 & 31) + 64; + vendorString[1] = (((edid[8] & 3) << 3) | (edid[9] >> 5)) + 64; + vendorString[2] = (edid[9] & 31) + 64; + + edidResult.ModelNumber = *(uint16_t*)&edid[10]; + edidResult.MonitorName = monitorName; + edidResult.VendorName = reinterpret_cast<const char*>(vendorString); + edidResult.SerialNumber = serialNumber; + + // FIXME: Get timings as well + + // std::cout << "# EDID version " << static_cast<int>(edid[EDID_STRUCT_VERSION]) + // << " revision " << static_cast<int>(edid[EDID_STRUCT_REVISION]) + // << std::endl; + + return 0; +} + + +// Returns -1 in the case of failure, 0 otherwise. +// Parameters: +// data OUT This pointer is modified to point to the output from +// XRRGetOutputProperty. You *must* call XFree on this pointer. +// dataLen OUT The length of the data returned in 'data'. +static int getXRRProperty(_XDisplay* display, RROutput output, Atom atom, + uint8_t** data, int* dataLen) +{ + unsigned long nitems; + unsigned long bytesAfter; + int actualFormat; + Atom actualType; + + int ret = XRRGetOutputProperty(display, output, atom, 0, 100, + False, False, AnyPropertyType, + &actualType, &actualFormat, &nitems, + &bytesAfter, data); + + if (None != ret) + { + *dataLen = nitems; + return 0; + } + else + { + return -1; + } +} + +static XRRModeInfo* findModeByXID(XRRScreenResources* screen, RRMode xid) +{ + for (int m = 0; m < screen->nmode; ++m) + { + XRRModeInfo* mode = &screen->modes[m]; + if (xid == mode->id) + { + return mode; + } + } + return NULL; +} + +static int discoverExtendedRifts(OVR::Linux::DisplayDesc* descriptorArray, int inputArraySize, bool /*edidInfo*/) +{ + int result = 0; + + _XDisplay* display = XOpenDisplay(NULL); + + if (display == NULL) + { + OVR::LogError("[Linux Display] Unable to open X Display!"); + return 0; + } + + Atom EDIDAtom = XInternAtom(display, RR_PROPERTY_RANDR_EDID, False); + int numScreens = XScreenCount(display); + for (int i = 0; i < numScreens; ++i) + { + Window sr = XRootWindow(display, i); + XRRScreenResources* screen = XRRGetScreenResources(display, sr); + + for (int ii = 0; ii < screen->ncrtc; ++ii) + { + XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(display, screen, screen->crtcs[ii]); + + if (0 == crtcInfo->noutput) + { + XRRFreeCrtcInfo(crtcInfo); + continue; + } + + bool foundOutput = false; + RROutput output = crtcInfo->outputs[0]; + for (int k = 0; k < crtcInfo->noutput; ++k) + { + XRROutputInfo* outputInfo = + XRRGetOutputInfo(display, screen, crtcInfo->outputs[k]); + + for (int kk = 0; kk < outputInfo->nmode; ++kk) + { + if (outputInfo->modes[kk] == crtcInfo->mode) + { + output = crtcInfo->outputs[k]; + foundOutput = true; + break; + } + } + XRRFreeOutputInfo(outputInfo); + if (foundOutput) + { + break; + } + } + + if (!foundOutput) + { + XRRFreeCrtcInfo(crtcInfo); + continue; + } + + XRROutputInfo* outputInfo = XRRGetOutputInfo(display, screen, output); + if (RR_Connected != outputInfo->connection) + { + XRRFreeOutputInfo(outputInfo); + XRRFreeCrtcInfo(crtcInfo); + continue; + } + + // Read EDID associated with crtc. + uint8_t* data = NULL; + int dataLen = 0; + if (getXRRProperty(display, output, EDIDAtom, &data, &dataLen) != 0) + { + // Identify rifts based on EDID. + Linux::DisplayEDID edid; + parseEdid(data, edid); + XFree(data); + data = NULL; + + // TODO: Remove either this 3rdParty call to read EDID data + // or remove our own parsing of the EDID. Probably opt + // to remove our parsing. + MonitorInfo* mi = read_edid_data(display, output); + if (mi == NULL) + { + XRRFreeOutputInfo(outputInfo); + XRRFreeCrtcInfo(crtcInfo); + continue; + } + + if (edid.VendorName == "OVR") + { + if( result >= inputArraySize ) + { + delete mi; + XRRFreeOutputInfo(outputInfo); + XRRFreeCrtcInfo(crtcInfo); + return result; + } + + XRRModeInfo* modeInfo = findModeByXID(screen, crtcInfo->mode); + + int width = modeInfo->width; + int height = modeInfo->height; + + if ( crtcInfo->rotation == RR_Rotate_90 + || crtcInfo->rotation == RR_Rotate_270 ) + { + width = modeInfo->height; + height = modeInfo->width; + } + + int x = crtcInfo->x; + int y = crtcInfo->y; + + // Generate a device ID string similar Windows does it + char device_id[32]; + OVR_sprintf(device_id, 32, "%s%04d-%d", + mi->manufacturer_code, mi->product_code, + screen->crtcs[ii]); + + OVR::Linux::DisplayDesc& desc = descriptorArray[result++]; + desc.DisplayID = device_id; + desc.ModelName = edid.MonitorName; + desc.EdidSerialNumber = edid.SerialNumber; + desc.LogicalResolutionInPixels = Sizei(width, height); + desc.DesktopDisplayOffset = Vector2i(x, y); + + switch (mi->product_code) + { + case 3: desc.DeviceTypeGuess = HmdType_DK2; break; + case 2: desc.DeviceTypeGuess = HmdType_DKHDProto; break; + case 1: desc.DeviceTypeGuess = HmdType_DK2; break; + + default: + case 0: desc.DeviceTypeGuess = HmdType_Unknown; break; + } + + // Hard-coded defaults in case the device doesn't have the + // data itself. DK2 prototypes (0003) or DK HD Prototypes (0002). + if ( desc.DeviceTypeGuess == HmdType_DK2 + || desc.DeviceTypeGuess == HmdType_DKHDProto) + { + desc.LogicalResolutionInPixels = Sizei(1920, 1080); + desc.NativeResolutionInPixels = Sizei(1080, 1920); + } + else + { + desc.LogicalResolutionInPixels = Sizei(width, height); + desc.NativeResolutionInPixels = Sizei(width, height); + } + } + + delete mi; + mi = NULL; + } + + XRRFreeOutputInfo(outputInfo); + XRRFreeCrtcInfo(crtcInfo); + } + + XRRFreeScreenResources(screen); + } + + XCloseDisplay(display); + + return result; +} + + +//------------------------------------------------------------------------------------- +// ***** Display + +bool Display::Initialize() +{ + // Nothing to initialize. OS X only supports compatibility mode. + return true; +} + +bool Display::GetDriverMode(bool& driverInstalled, bool& compatMode, bool& hideDK1Mode) +{ + driverInstalled = false; + compatMode = true; + hideDK1Mode = false; + return true; +} + +bool Display::SetDriverMode(bool /*compatMode*/, bool /*hideDK1Mode*/) +{ + return false; +} + +DisplaySearchHandle* Display::GetDisplaySearchHandle() +{ + return new Linux::LinuxDisplaySearchHandle(); +} + +bool Display::InCompatibilityMode( bool displaySearch ) +{ + OVR_UNUSED( displaySearch ); + return true; +} + +int Display::GetDisplayCount(DisplaySearchHandle* handle, bool extended, bool applicationOnly, bool edidInfo) +{ + OVR_UNUSED4(handle, extended, applicationOnly, edidInfo); + + static int extendedCount = -1; + + Linux::LinuxDisplaySearchHandle* localHandle = (Linux::LinuxDisplaySearchHandle*)handle; + if (localHandle == NULL) + { + OVR::LogError("[Linux Display] No search handle passed into GetDisplayCount. Return 0 rifts."); + return 0; + } + + if (extendedCount == -1 || extended) + { + extendedCount = discoverExtendedRifts(localHandle->cachedDescriptorArray, Linux::LinuxDisplaySearchHandle::DescArraySize, edidInfo); + } + + localHandle->extended = true; + localHandle->extendedDisplayCount = extendedCount; + int totalCount = extendedCount; + + /// FIXME: Implement application mode for OS X. + localHandle->application = false; + localHandle->applicationDisplayCount = 0; + + localHandle->displayCount = totalCount; + + return totalCount; +} + + +Ptr<Display> Display::GetDisplay( int index, DisplaySearchHandle* handle ) +{ + Ptr<Display> result = NULL; + + if (index < 0) + { + OVR::LogError("[Linux Display] Invalid index given to GetDisplay."); + return NULL; + } + + Linux::LinuxDisplaySearchHandle* localHandle = (Linux::LinuxDisplaySearchHandle*)handle; + if (localHandle == NULL) + { + OVR::LogError("[Linux Display] No search handle passed into GetDisplay. Return 0 rifts."); + return NULL; + } + + if (localHandle->extended) + { + if (index >= 0 && index < (int)localHandle->extendedDisplayCount) + { + return *new Linux::LinuxDisplayGeneric(localHandle->cachedDescriptorArray[index]); + } + + index -= localHandle->extendedDisplayCount; + } + + if (localHandle->application) + { + OVR::LogError("[Linux Display] Mac does not support application displays."); + } + + return result; +} + + +} // namespace OVR diff --git a/LibOVR/Src/Displays/OVR_Linux_Display.h b/LibOVR/Src/Displays/OVR_Linux_Display.h new file mode 100644 index 0000000..f685e6b --- /dev/null +++ b/LibOVR/Src/Displays/OVR_Linux_Display.h @@ -0,0 +1,133 @@ +/************************************************************************************ + +Filename : OVR_Linux_Display.h +Content : Linux-specific Display declarations +Created : July 2, 2014 +Authors : James Hughes + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); +you may not use the Oculus VR Rift SDK except in compliance with the License, +which is provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +You may obtain a copy of the License at + +http://www.oculusvr.com/licenses/LICENSE-3.2 + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*************************************************************************************/ + +#ifndef OVR_Linux_Display_h +#define OVR_Linux_Display_h + +#include "OVR_Display.h" + +namespace OVR { namespace Linux { + + +//------------------------------------------------------------------------------------- +// DisplayDesc + +// Display information enumerable through OS . +// TBD: Should we just move this to public header, so it's a const member of Display? +struct DisplayDesc +{ + HmdTypeEnum DeviceTypeGuess; + String DisplayID; // This is the device identifier string from MONITORINFO (for app usage) + String ModelName; // This is a "DK2" type string + String EdidSerialNumber; + Sizei LogicalResolutionInPixels; + Sizei NativeResolutionInPixels; + Vector2i DesktopDisplayOffset; +}; + + +//------------------------------------------------------------------------------------- +// DisplayEDID + +// Describes EDID information as reported from our display driver. +struct DisplayEDID +{ + DisplayEDID() : + ModelNumber(0) + {} + + String MonitorName; + UInt16 ModelNumber; + String VendorName; + String SerialNumber; +}; + + +//------------------------------------------------------------------------------------- +// Linux Display Search Handle +class LinuxDisplaySearchHandle : public DisplaySearchHandle +{ +public: + LinuxDisplaySearchHandle() : + extended(false), + application(false), + extendedDisplayCount(0), + applicationDisplayCount(0), + displayCount(0) + {} + virtual ~LinuxDisplaySearchHandle() {} + + static const int DescArraySize = 16; + + Linux::DisplayDesc cachedDescriptorArray[DescArraySize]; + bool extended; + bool application; + int extendedDisplayCount; + int applicationDisplayCount; + int displayCount; +}; + +//------------------------------------------------------------------------------------- +// LinuxDisplayGeneric + +// Describes Linux display in Compatibility mode, containing basic data +class LinuxDisplayGeneric : public Display +{ +public: + LinuxDisplayGeneric( const DisplayDesc& dd ) : + Display(dd.DeviceTypeGuess, + dd.DisplayID, + dd.ModelName, + dd.EdidSerialNumber, + dd.LogicalResolutionInPixels, + dd.NativeResolutionInPixels, + dd.DesktopDisplayOffset, + 0, + 0, + false) + { + } + + virtual ~LinuxDisplayGeneric() + { + } + + virtual bool InCompatibilityMode() const + { + return true; + } + + // Generic displays are not capable of mirroring + virtual MirrorMode SetMirrorMode( MirrorMode newMode ) + { + OVR_UNUSED( newMode ); + return MirrorDisabled; + } +}; + +}} // namespace OVR::Linux + +#endif // OVR_Linux_Display_h diff --git a/LibOVR/Src/Displays/OVR_Linux_SDKWindow.cpp b/LibOVR/Src/Displays/OVR_Linux_SDKWindow.cpp new file mode 100644 index 0000000..d056ac9 --- /dev/null +++ b/LibOVR/Src/Displays/OVR_Linux_SDKWindow.cpp @@ -0,0 +1,606 @@ +/******************************************************************************* + +Filename : OVR_Linux_SDKWindow.cpp +Content : SDK generated Linux window. +Created : October 1, 2014 +Authors : James Hughes + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); +you may not use the Oculus VR Rift SDK except in compliance with the License, +which is provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +You may obtain a copy of the License at + +http://www.oculusvr.com/licenses/LICENSE-3.2 + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*******************************************************************************/ + +#include "OVR_Linux_SDKWindow.h" +#include "../Kernel/OVR_Log.h" +#include "../Kernel/OVR_Log.h" +#include "../../../3rdParty/EDID/edid.h" + +namespace OVR { + +// Forward declarations +static Window constructWindow(_XDisplay* display, int xscreen, + XVisualInfo* xvisual, + const LinuxDeviceScreen& screen); + +static XRRModeInfo* findModeByXID(XRRScreenResources* screen, RRMode xid) +{ + for (int m = 0; m < screen->nmode; ++m) + { + XRRModeInfo* mode = &screen->modes[m]; + if (xid == mode->id) + { + return mode; + } + } + return NULL; +} + +/// Retrieves a list of available device screens on which we can build +/// SDK windows. Returns number of devices found. +/// screens Array which this function will populate. +/// maxNumScreens Maximum number of screens to store in screens. +static int getDeviceScreens(LinuxDeviceScreen* screens, int maxNumDevices) +{ + _XDisplay* disp = XOpenDisplay(NULL); + if (!disp) + { + OVR::LogError("[SDKWindow] Unable to open X Display."); + return 0; + } + + int numDevices = 0; + int numScreens = XScreenCount(disp); + for (int i = 0; i < numScreens; ++i) + { + // Screen root is used to detect what video output the crtc is using. + Window sr = XRootWindow(disp, i); + XRRScreenResources* screen = XRRGetScreenResources(disp, sr); + + for (int ii = 0; ii < screen->ncrtc; ++ii) + { + XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(disp, screen, screen->crtcs[ii]); + + if (0 == crtcInfo->noutput) + { + XRRFreeCrtcInfo(crtcInfo); + continue; + } + + bool foundOutput = false; + RROutput output = crtcInfo->outputs[0]; + for (int k = 0; k < crtcInfo->noutput; ++k) + { + XRROutputInfo* outputInfo = + XRRGetOutputInfo(disp, screen, crtcInfo->outputs[k]); + for (int kk = 0 ; kk < outputInfo->nmode; ++kk) + { + if (outputInfo->modes[kk] == crtcInfo->mode) + { + output = crtcInfo->outputs[k]; + foundOutput = true; + break; + } + } + XRRFreeOutputInfo(outputInfo); + if (foundOutput) { break; } + } + + if (!foundOutput) + { + XRRFreeCrtcInfo(crtcInfo); + continue; + } + + XRROutputInfo* outputInfo = XRRGetOutputInfo(disp, screen, output); + if (RR_Connected != outputInfo->connection) + { + XRRFreeOutputInfo(outputInfo); + XRRFreeCrtcInfo(crtcInfo); + continue; + } + + // Read EDID associated with crtc. + MonitorInfo* mi = read_edid_data(disp, output); + if (mi == NULL) + { + XRRFreeOutputInfo(outputInfo); + XRRFreeCrtcInfo(crtcInfo); + continue; + } + + if (strcmp(mi->manufacturer_code, "OVR") == 0) + { + XRRModeInfo* modeInfo = findModeByXID(screen, crtcInfo->mode); + + DistortionRotation desiredRot = DistRotateNone; + if (mi->product_code == 3) + { + // This is a DK2, we may have to rotate our output. + // If we don't have to, we should alert the user that + // rotating the display using the DM or graphics + // card settings is highly non-optimal. + desiredRot = DistRotateCCW90; + if (crtcInfo->rotation != RR_Rotate_0) + { + OVR::LogError("Please do not rotate your rift's screen."); + + if (crtcInfo->rotation == RR_Rotate_90) + { + // The user has manually rotated the screen. + // So apply no rotation on our end. + desiredRot = DistRotateNone; + } + } + } + else + { + if (crtcInfo->rotation != RR_Rotate_0) + { + OVR::LogError("Please do not rotate your rift's screen."); + } + } + + int width = modeInfo->width; + int height = modeInfo->height; + + // Swap width / height if display is rotated (shouldn't be on linux). + if ( crtcInfo->rotation == RR_Rotate_90 + || crtcInfo->rotation == RR_Rotate_270) + { + width = modeInfo->height; + height = modeInfo->width; + } + + // Push detected monitor. + screens[numDevices].set(i, screen->crtcs[ii], desiredRot, + mi->product_code, width, height, + crtcInfo->x, crtcInfo->y); + ++numDevices; + } + + delete mi; + + if (numDevices == maxNumDevices) + { + XRRFreeOutputInfo(outputInfo); + XRRFreeCrtcInfo(crtcInfo); + XRRFreeScreenResources(screen); + OVR::LogError("[SDKWindow] Maxed out number of devices.."); + XCloseDisplay(disp); + return numDevices; + } + + XRRFreeOutputInfo(outputInfo); + XRRFreeCrtcInfo(crtcInfo); + } + + XRRFreeScreenResources(screen); + } + XCloseDisplay(disp); + return numDevices; +} + + +LinuxDeviceScreen SDKWindow::findDevScreenForHMD(const ovrHmd& hmd) +{ + return findDevScreenForDevID(hmd->DisplayDeviceName); +} + +LinuxDeviceScreen SDKWindow::findDevScreenForDevID(const char* deviceIDIn) +{ + const int maxNumDevices = 5; + LinuxDeviceScreen screens[maxNumDevices]; + int numDevices = getDeviceScreens(screens, maxNumDevices); + + if (numDevices > 0) + { + // Identify target for SDK window via hmd info. + for (int i = 0; i < numDevices; ++i) + { + LinuxDeviceScreen& screen = screens[i]; + + char deviceID[32]; + OVR_sprintf(deviceID, 32, "OVR%04d-%d", + screen.productCode, screen.crtcid); + + if (strcmp(deviceIDIn, deviceID) == 0) + { + return screen; + } + } + } + + return LinuxDeviceScreen(); +} + +DistortionRotation SDKWindow::getRotation(const ovrHmd& hmd) +{ + LinuxDeviceScreen screen = findDevScreenForHMD(hmd); + if (screen.isValid()) + { + return screen.rotation; + } + else + { + return DistRotateNone; + } +} + + +bool SDKWindow::getVisualFromDrawable(GLXDrawable drawable, XVisualInfo* vinfoOut) +{ + _XDisplay* display = glXGetCurrentDisplay(); + + unsigned int value; + glXQueryDrawable(display, drawable, GLX_FBCONFIG_ID, &value); + XVisualInfo* chosen = glXGetVisualFromFBConfig(display, reinterpret_cast<GLXFBConfig>(value)); + *vinfoOut = *chosen; + return true; +} + +SDKWindow::SDKWindow(const ovrHmd& hmd) : + mXDisplay(NULL), + mXScreen(-1), + mXVisual(NULL), + mXUniqueContext(-1), + mXWindow(0), + mFBConfig(NULL) +{ + OVR_UNUSED(hmd); +} + +SDKWindow::~SDKWindow() +{ + if (mXWindow) + { + XDeleteContext(mXDisplay, mXWindow, mXUniqueContext); + XUnmapWindow(mXDisplay, mXWindow); + XDestroyWindow(mXDisplay, mXWindow); + mXWindow = static_cast<Window>(0); + } + + if (mXDisplay != NULL) + { + XCloseDisplay(mXDisplay); + } +} + +void SDKWindow::buildVisualAndWindow(const LinuxDeviceScreen& devScreen) +{ + mXDisplay = XOpenDisplay(NULL); + mXUniqueContext = XUniqueContext(); + mXScreen = devScreen.screen; + + mXVisual = chooseVisual(mXDisplay, mXScreen, &mFBConfig); + if (mXVisual != NULL) + { + mXWindow = constructWindow(mXDisplay, mXScreen, mXVisual, devScreen); + mDeviceScreen = devScreen; + } +} + +// Used in chooseVisual. May need to expose this to the end use so they can +// choose an appropriate framebuffer configuration. +struct FBConfig +{ + FBConfig() : + redBits(8), + greenBits(8), + blueBits(8), + alphaBits(8), + depthBits(8), + stencilBits(-1), + doubleBuffer(true), + auxBuffers(-1) + {} + + int redBits; + int greenBits; + int blueBits; + int alphaBits; + int depthBits; + int stencilBits; + bool doubleBuffer; + int auxBuffers; + + GLXFBConfig xcfg; +}; + +static int fbCalcContrib(int desired, int current) +{ + int diff = desired - current; + if (current != -1) { return diff * diff; } + else { return 0; } +} + +/// Selects ideal visual for the given screen. Returns NULL on error. +XVisualInfo* SDKWindow::chooseVisual(_XDisplay* display, int xscreen, + GLXFBConfig* cfg) +{ + // Select visual. + int nativeCount = 0; + GLXFBConfig* nativeConfigs = + glXGetFBConfigs(display, xscreen, &nativeCount); + if (!nativeCount) + { + OVR::LogError("[SDKWindow] No valid frame buffer configurations found."); + return NULL; + } + + FBConfig* usables = static_cast<FBConfig*>(calloc(nativeCount, sizeof(FBConfig))); + int numUsables = 0; + + for (int i = 0; i < nativeCount; ++i) + { + GLXFBConfig native = nativeConfigs[i]; + FBConfig* usable = &usables[numUsables]; + int v = 0; + + // Only frame buffer configcs with attached visuals. + glXGetFBConfigAttrib(display, native, GLX_VISUAL_ID, &v); + if (!v) { continue; } + + // Only RGBA frame buffers. + glXGetFBConfigAttrib(display, native, GLX_RENDER_TYPE, &v); + if (!(v & GLX_RGBA_BIT)) { continue; } + + glXGetFBConfigAttrib(display, native, GLX_DRAWABLE_TYPE, &v); + if (!(v & GLX_WINDOW_BIT)) { continue; } + + glXGetFBConfigAttrib(display, native, GLX_DEPTH_SIZE, &usable->depthBits); + glXGetFBConfigAttrib(display, native, GLX_STENCIL_SIZE, &usable->stencilBits); + + glXGetFBConfigAttrib(display, native, GLX_RED_SIZE, &usable->redBits); + glXGetFBConfigAttrib(display, native, GLX_GREEN_SIZE, &usable->greenBits); + glXGetFBConfigAttrib(display, native, GLX_BLUE_SIZE, &usable->blueBits); + glXGetFBConfigAttrib(display, native, GLX_ALPHA_SIZE, &usable->alphaBits); + + glXGetFBConfigAttrib(display, native, GLX_ALPHA_SIZE, &usable->auxBuffers); + + glXGetFBConfigAttrib(display, native, GLX_DOUBLEBUFFER, &v); + usable->doubleBuffer = v ? true : false; + + usable->xcfg = native; + + ++numUsables; + } + + // We really want std::numeric_limits<int>::max() instead of hardcoded vals. + const int MostMissing = 100; + int leastMissing = MostMissing; + int leastBias = MostMissing; + + const FBConfig* closest = NULL; + + // Desired is currently the default config built by constructor. + FBConfig desired; + + for (int i = 0; i < numUsables; ++i) + { + const FBConfig* cur = &usables[i]; + + if (desired.doubleBuffer != cur->doubleBuffer) { continue; } + + int missing = 0; + if (desired.alphaBits > 0 && cur->alphaBits == 0) { ++missing; } + if (desired.depthBits > 0 && cur->depthBits == 0) { ++missing; } + if (desired.stencilBits > 0 && cur->stencilBits == 0) { ++missing; } + if (desired.redBits > 0 && desired.redBits != cur->redBits) { ++missing; } + if (desired.greenBits > 0 && desired.greenBits != cur->greenBits) { ++missing; } + if (desired.blueBits > 0 && desired.blueBits != cur->blueBits) { ++missing; } + + int bias = fbCalcContrib(desired.redBits, cur->redBits) + + fbCalcContrib(desired.greenBits, cur->greenBits) + + fbCalcContrib(desired.blueBits, cur->blueBits) + + fbCalcContrib(desired.alphaBits, cur->alphaBits) + + fbCalcContrib(desired.depthBits, cur->depthBits) + + fbCalcContrib(desired.stencilBits, cur->stencilBits); + + if (missing < leastMissing) + { + closest = cur; + } + else if (missing == leastMissing) + { + // Now select against squared differences. + if (bias < leastBias) + { + closest = cur; + } + } + + if (closest == cur) + { + leastMissing = missing; + leastBias = bias; + } + } + + if (closest == NULL) + { + OVR::LogError("[SDKWindow] Failed to select appropriate frame buffer."); + XFree(nativeConfigs); + free(usables); + return NULL; + } + + OVR_DEBUG_LOG(("[C] Chosen framebuffer config:")); + OVR_DEBUG_LOG(("[C] Double buffer: %d", closest->doubleBuffer)); + OVR_DEBUG_LOG(("[C] RGBA bits: (%d,%d,%d,%d)", + closest->redBits, closest->greenBits, closest->blueBits, + closest->alphaBits)); + OVR_DEBUG_LOG(("[C] Depth bits: %d", closest->depthBits)); + + XVisualInfo* viOut = glXGetVisualFromFBConfig(display, closest->xcfg); + if (cfg != NULL) + { + *cfg = closest->xcfg; + } + + XFree(nativeConfigs); + free(usables); + + return viOut; +} + +static int gXLastError = -1; +static int handleXError(_XDisplay* display, XErrorEvent* event) +{ + OVR_UNUSED(display); + gXLastError = event->error_code; + return 0; +} + +static void obtainXErrorHandler() +{ + gXLastError = Success; + XSetErrorHandler(handleXError); +} + +static void releaseXErrorHandler(_XDisplay* display) +{ + XSync(display, False); + XSetErrorHandler(NULL); +} + +// Returns 0 on error, otherwise a valid X window is returned. +static Window constructWindow(_XDisplay* xDisp, int xScreen, + XVisualInfo* xVisual, + const LinuxDeviceScreen& devScreen) +{ + XSetWindowAttributes wa; + + Window root = XRootWindow(xDisp, xScreen); + Window xWindowOut = 0; + + // Create Window + { + Colormap xWinColorMapOut = XCreateColormap( + xDisp, root, xVisual->visual, AllocNone); + unsigned long wamask = CWBorderPixel | CWColormap | CWEventMask; + + wa.colormap = xWinColorMapOut; + wa.border_pixel = 0; + wa.event_mask = StructureNotifyMask | ExposureMask | FocusChangeMask + | VisibilityChangeMask | EnterWindowMask | LeaveWindowMask + | PropertyChangeMask; + + obtainXErrorHandler(); + + xWindowOut = XCreateWindow(xDisp, root, + 0, 0, + devScreen.width, devScreen.height, + 0, + xVisual->depth, + InputOutput, + xVisual->visual, + wamask, + &wa); + + releaseXErrorHandler(xDisp); + + if (!xWindowOut) + { + OVR::LogError("[SDKWindow] Failed to create SDK window."); + return 0; + } + + XFreeColormap(xDisp, xWinColorMapOut); + } + + // OVERRIDE REDIRECT. + XSetWindowAttributes attributes; + attributes.override_redirect = True; + XChangeWindowAttributes(xDisp, xWindowOut, + CWOverrideRedirect, &attributes); + + // Show the window (do this in full screen or windowed). + XMapRaised(xDisp, xWindowOut); + XFlush(xDisp); + + // Position ourselves manually since there should be no WM managing us. + XRaiseWindow(xDisp, xWindowOut); + XMoveWindow(xDisp, xWindowOut, devScreen.offsetX, devScreen.offsetY); + XResizeWindow(xDisp, xWindowOut, devScreen.width, devScreen.height); + + XFlush(xDisp); + + // WM Backup in case there still exists a WM managing us... + Atom NET_WM_BYPASS_COMPOSITOR = + XInternAtom(xDisp, "_NET_WM_BYPASS_COMPOSITOR", False); + Atom NET_WM_STATE = + XInternAtom(xDisp, "_NET_WM_STATE", False); + Atom NET_WM_STATE_FULLSCREEN = + XInternAtom(xDisp, "_NET_WM_STATE_FULLSCREEN", False); + Atom NET_ACTIVE_WINDOW = + XInternAtom(xDisp, "_NET_ACTIVE_WINDOW", False); + + // Bypass compositor if we are under a compositing WM. + // Just in case a WM ignores our override_redirect. + if (NET_WM_BYPASS_COMPOSITOR) + { + const unsigned long bypass = 1; + XChangeProperty(xDisp, xWindowOut, + NET_WM_BYPASS_COMPOSITOR, + XA_CARDINAL, 32, PropModeReplace, + (unsigned char*)&bypass, 1); + } + + if (NET_WM_STATE && NET_WM_STATE_FULLSCREEN) + { + // BACKUP: If we are still managed by a WM we want fullscreen. + const int EWMH_STATE_ADD = 1; + + if (NET_ACTIVE_WINDOW) + { + XEvent event; + memset(&event, 0, sizeof(event)); + + event.type = ClientMessage; + event.xclient.window = xWindowOut; + event.xclient.format = 32; + event.xclient.message_type = NET_ACTIVE_WINDOW; + event.xclient.data.l[0] = 1; + event.xclient.data.l[1] = 0; + + XSendEvent(xDisp, root, False, + SubstructureNotifyMask | SubstructureRedirectMask, + &event); + } + + XEvent event; + memset(&event, 0, sizeof(event)); + + event.type = ClientMessage; + event.xclient.window = xWindowOut; + event.xclient.format = 32; + event.xclient.message_type = NET_WM_STATE; + event.xclient.data.l[0] = EWMH_STATE_ADD; + event.xclient.data.l[1] = NET_WM_STATE_FULLSCREEN; + event.xclient.data.l[2] = 0; + event.xclient.data.l[3] = 1; + + XSendEvent(xDisp, root, False, + SubstructureNotifyMask | SubstructureRedirectMask, + &event); + } + + return xWindowOut; +} + +} // namespace OVR + diff --git a/LibOVR/Src/Displays/OVR_Linux_SDKWindow.h b/LibOVR/Src/Displays/OVR_Linux_SDKWindow.h new file mode 100644 index 0000000..62222b6 --- /dev/null +++ b/LibOVR/Src/Displays/OVR_Linux_SDKWindow.h @@ -0,0 +1,142 @@ +/******************************************************************************* + +Filename : OVR_Linux_SDKWindow.h +Content : SDK generated Linux window. +Created : October 1, 2014 +Authors : James Hughes + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); +you may not use the Oculus VR Rift SDK except in compliance with the License, +which is provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +You may obtain a copy of the License at + +http://www.oculusvr.com/licenses/LICENSE-3.2 + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*******************************************************************************/ + +#ifndef OVR_Linux_SDKWindow_h +#define OVR_Linux_SDKWindow_h + +#include "../OVR_CAPI.h" +#include "../CAPI/GL/CAPI_GL_Util.h" + +#include <X11/Xlib.h> +#include <X11/Xatom.h> +#include <X11/extensions/Xrandr.h> +#include <X11/Xresource.h> +#include <GL/glx.h> + +namespace OVR { + +enum DistortionRotation +{ + DistRotateNone, + DistRotateCCW90 +}; + +struct LinuxDeviceScreen +{ + LinuxDeviceScreen() : + screen(-1), + crtcid(0), + rotation(DistRotateNone), + productCode(-1), + width(-1), + height(-1), + offsetX(-1), + offsetY(-1) + {} + + void set(int xScreen, XID xid, DistortionRotation rot, int prodCode, + int w, int h, int x, int y) + { + screen = xScreen; + crtcid = xid; + rotation = rot; + productCode = prodCode; + + width = w; + height = h; + offsetX = x; + offsetY = y; + } + + bool isValid() {return (screen != -1);} + + int screen; ///< X Screen this device occupies. + XID crtcid; ///< XID uniquely identifying this device on XDisplay. + DistortionRotation rotation; + int productCode; + + // Actual width and height of screen. + int width; + int height; + + // Offset if using twinview + int offsetX; + int offsetY; +}; + +class SDKWindow +{ +public: + + SDKWindow(const ovrHmd& hmd); + ~SDKWindow(); + + /// Rotation necessary to correctly orient this SDK window. + DistortionRotation GetDistortionRotation() {return mDeviceScreen.rotation;} + + _XDisplay* GetDisplay() {return mXDisplay;} + XVisualInfo* GetVisual() {return mXVisual;} + GLXFBConfig GetFBConfig() {return mFBConfig;} + Window GetDrawable() {return mXWindow;} + bool HasValidWindow() {return (mXWindow != 0);} + + // If cfg is non-null it is populated with the chosen configuration. + static XVisualInfo* chooseVisual(_XDisplay* display, int xscreen, + GLXFBConfig* cfg = NULL); + + static LinuxDeviceScreen findDevScreenForHMD(const ovrHmd& hmd); + static LinuxDeviceScreen findDevScreenForDevID(const char* deviceID); + + static DistortionRotation getRotation(const ovrHmd& hmd); + + // Obtains XVisualInfo for currently bound context. Returns true if a + // visual was successfully obtained. False otherwise. + static bool getVisualFromDrawable(GLXDrawable drawable, XVisualInfo* vinfoOut); + + // TODO: Function which uses glXGetConfig to generate an FB config from + // a visual. Chooses first FBConfig if multiple matches found. + //static GLXFBConfig* getFBConfigFromVisual(XVisualInfo* vis); + +private: + + /// Constructs SDK window on the given device screen. + void buildVisualAndWindow(const LinuxDeviceScreen& devScreen); + + // Added m in front of variables so as to not conflict with X names. + _XDisplay* mXDisplay; + int mXScreen; + XVisualInfo* mXVisual; + XContext mXUniqueContext; + Window mXWindow; + GLXFBConfig mFBConfig; + + LinuxDeviceScreen mDeviceScreen; +}; + + +} // namespace OVR + +#endif // OVR_Linux_SDKWindow_h diff --git a/LibOVR/Src/Displays/OVR_OSX_Display.cpp b/LibOVR/Src/Displays/OVR_OSX_Display.cpp index c49daa5..262a2bf 100644 --- a/LibOVR/Src/Displays/OVR_OSX_Display.cpp +++ b/LibOVR/Src/Displays/OVR_OSX_Display.cpp @@ -5,16 +5,16 @@ Content : OSX-specific Display declarations Created : July 2, 2014 Authors : James Hughes -Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved. +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. -Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License"); +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); you may not use the Oculus VR Rift SDK except in compliance with the License, which is provided at the time of installation or download, or which otherwise accompanies this software in either electronic or hard copy form. You may obtain a copy of the License at -http://www.oculusvr.com/licenses/LICENSE-3.1 +http://www.oculusvr.com/licenses/LICENSE-3.2 Unless required by applicable law or agreed to in writing, the Oculus VR SDK distributed under the License is distributed on an "AS IS" BASIS, @@ -210,7 +210,11 @@ static int discoverExtendedRifts(OVR::OSX::DisplayDesc* descriptorArray, int inp if (vendor == 16082 && ( (product == 1)||(product == 2)||(product == 3) ) ) // 7" or HD { - if( result >= inputArraySize ) { return result; } + if( result >= inputArraySize ) + { + CFRelease(DispInfo); + return result; + } Sizei monitorResolution(1280, 800); @@ -355,7 +359,7 @@ Ptr<Display> Display::GetDisplay( int index, DisplaySearchHandle* handle ) return *new OSX::OSXDisplayGeneric(localHandle->cachedDescriptorArray[index]); } - index -= localHandle->extendedDisplayCount; + // index -= localHandle->extendedDisplayCount; } if (localHandle->application) diff --git a/LibOVR/Src/Displays/OVR_OSX_Display.h b/LibOVR/Src/Displays/OVR_OSX_Display.h index 1401121..a69c955 100644 --- a/LibOVR/Src/Displays/OVR_OSX_Display.h +++ b/LibOVR/Src/Displays/OVR_OSX_Display.h @@ -5,16 +5,16 @@ Content : OSX-specific Display declarations Created : July 2, 2014 Authors : James Hughes -Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved. +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. -Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License"); +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); you may not use the Oculus VR Rift SDK except in compliance with the License, which is provided at the time of installation or download, or which otherwise accompanies this software in either electronic or hard copy form. You may obtain a copy of the License at -http://www.oculusvr.com/licenses/LICENSE-3.1 +http://www.oculusvr.com/licenses/LICENSE-3.2 Unless required by applicable law or agreed to in writing, the Oculus VR SDK distributed under the License is distributed on an "AS IS" BASIS, diff --git a/LibOVR/Src/Displays/OVR_OSX_FocusObserver.h b/LibOVR/Src/Displays/OVR_OSX_FocusObserver.h index 66ed12f..e2f28e3 100644 --- a/LibOVR/Src/Displays/OVR_OSX_FocusObserver.h +++ b/LibOVR/Src/Displays/OVR_OSX_FocusObserver.h @@ -1,3 +1,31 @@ +/************************************************************************************ + +Filename : OVR_OSX_FocusObserver.h +Content : Observer for app focus on OSX +Created : August 5, 2014 +Authors : Jordan Tritell + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); +you may not use the Oculus VR Rift SDK except in compliance with the License, +which is provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +You may obtain a copy of the License at + +http://www.oculusvr.com/licenses/LICENSE-3.2 + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*************************************************************************************/ + +OVR_PRIVATE_FILE + #ifndef OVR_OSX_FocusObserver_h #define OVR_OSX_FocusObserver_h @@ -9,7 +37,7 @@ namespace OVR { namespace OSX{ - struct FocusReaderImpl; + struct FocusNotifierImpl; class AppFocusObserver : public SystemSingletonBase<AppFocusObserver> { @@ -19,7 +47,7 @@ public: Lock ListLock; Array<pid_t> AppList; Service::NetServerListener *listener; - FocusReaderImpl* impl; + FocusNotifierImpl* impl; void OnProcessFocus(pid_t pid); void SetListener(Service::NetServerListener *_listener); @@ -43,5 +71,5 @@ protected: }} // namespace OVR, OSX -#endif /* defined(__OVR_OSX_FocusReader__OVR_OSX_FocusObserver__) */ +#endif /* OVR_OSX_FocusObserver_h */ diff --git a/LibOVR/Src/Displays/OVR_OSX_FocusObserver.mm b/LibOVR/Src/Displays/OVR_OSX_FocusObserver.mm new file mode 100644 index 0000000..69a3f4d --- /dev/null +++ b/LibOVR/Src/Displays/OVR_OSX_FocusObserver.mm @@ -0,0 +1,490 @@ +/************************************************************************************ + + + +Filename : OVR_OSX_FocusObserver.mm + +Content : Observer for app focus on OSX + +Created : August 5, 2014 + +Authors : Jordan Tritell + + + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + + + +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); + +you may not use the Oculus VR Rift SDK except in compliance with the License, + +which is provided at the time of installation or download, or which + +otherwise accompanies this software in either electronic or hard copy form. + + + +You may obtain a copy of the License at + + + +http://www.oculusvr.com/licenses/LICENSE-3.2 + + + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK + +distributed under the License is distributed on an "AS IS" BASIS, + +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +See the License for the specific language governing permissions and + +limitations under the License. + + + +*************************************************************************************/ + + + +OVR_PRIVATE_FILE + + + +#include "OVR_OSX_FocusObserver.h" + + + +#include "../Service/Service_NetServer.h" + +#include "OVR_DisplayEnumerator.h" + + + +#include <Cocoa/Cocoa.h> + + + +OVR_DEFINE_SINGLETON(OVR::OSX::AppFocusObserver); + + + +extern bool ServiceRunningFlag; + + + +@interface FocusNotifier : NSObject <NSApplicationDelegate>{ + + NSWindow *window; + +} + + + +- (void)start; + + + +@property (assign) IBOutlet NSWindow *window; + + + +@end + + + + + +@implementation FocusNotifier + + + +@synthesize window; + + + +- (void) addActivationObserver + +{ + + //subscribe to focus notifications from the workspace + + [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self + + selector:@selector(activated:) + + name:NSWorkspaceDidActivateApplicationNotification + + object:nil]; + + + + //subscribe to termination notifications from the workspace + + [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self + + selector:@selector(terminated:) + + name:NSWorkspaceDidTerminateApplicationNotification + + object:nil]; + +} + + + +-(void) activated:(NSNotification *)notification + +{ + + NSRunningApplication *app = [[notification userInfo] objectForKey:@"NSWorkspaceApplicationKey"]; + + pid_t pid = [app processIdentifier]; + + OVR::OSX::AppFocusObserver::GetInstance()->OnProcessFocus(pid); + + // NSLog(@"Activated: %@", [activatedApp bundleIdentifier]); + +} + + + +-(void) terminated:(NSNotification *)notification + +{ + + NSRunningApplication *app = [[notification userInfo] objectForKey:@"NSWorkspaceApplicationKey"]; + + pid_t pid = [app processIdentifier]; + + OVR::OSX::AppFocusObserver::GetInstance()->RemoveProcess(pid); + + // NSLog(@"Activated: %@", [activatedApp bundleIdentifier]); + +} + + + +- (void)start + +{ + + //initialize with relevant variables + + [self addActivationObserver]; + +} + + + +@end + + + + + +namespace OVR { namespace OSX{ + + + +struct FocusNotifierImpl + +{ + + FocusNotifier* wrapped; + +}; + + + +AppFocusObserver::AppFocusObserver(): + + impl(new FocusNotifierImpl), + + listener(NULL) + +{ + + //initialize with correct values + + impl->wrapped = [[FocusNotifier alloc] init]; + + [impl->wrapped start]; + + ActiveProcessId = 0; + +} + + + +AppFocusObserver::~AppFocusObserver() + +{ + + [impl->wrapped dealloc]; + + delete impl; + +} + + + +void AppFocusObserver::SetListener(Service::NetServerListener *_listener) + +{ + + listener = _listener; + +} + + + +void AppFocusObserver::OnSystemDestroy() + +{ + +} + + + +void AppFocusObserver::OnProcessFocus(pid_t pid) + +{ + + // If the process changed, + + if (pid != LastProcessId) + + { + + LastProcessId = pid; + + + + Lock::Locker locker(&ListLock); + + + + // Find the process id in the list + + const int count = AppList.GetSizeI(); + + for (int i = 0; i < count; ++i) + + { + + // If it is a rift process, + + if (AppList[i] == pid) + + { + + onAppFocus(pid); + + OVR_DEBUG_LOG(("[AppFocusObserver] Oculus Process getting focus: pid=%d", pid)); + + return; + + } + + } + + + + OVR_DEBUG_LOG(("[AppFocusObserver] Focus change: %d (non-Oculus process)", pid)); + + } + +} + + + +void AppFocusObserver::AddProcess(pid_t pid) + +{ + + Lock::Locker locker(&ListLock); + + + + // If it already exists in the array, + + const int count = AppList.GetSizeI(); + + for (int i = 0; i < count; ++i) + + { + + // If we found it, + + if (AppList[i] == pid) + + { + + return; + + } + + } + + + + // If the process being added is already in focus, + + if (pid == LastProcessId) + + { + + // Set the active process + + OVR_DEBUG_LOG(("[AppFocusObserver] AddProcess: Recognizing the newly added process as in-focus pid=%d", pid)); + + } + + + + // Add it to the list + + AppList.PushBack(pid); + +} + + + +void AppFocusObserver::nextProcess() + +{ + + Lock::Locker locker(&ListLock); + + + + int count = AppList.GetSizeI(); + + + + // Pick the next available rift process + + if (count > 0) + + { + + ActiveProcessId = AppList[0]; + + OVR_DEBUG_LOG(("[AppFocusObserver] NextProcess: Switching active rift process to pid=%d", ActiveProcessId)); + + onAppFocus(ActiveProcessId); + + return; + + } + + + + // No process to use + + onAppFocus(ActiveProcessId); + + OVR_DEBUG_LOG(("[AppFocusObserver] NextProcess: No remaining rift processes")); + +} + + + + + +void AppFocusObserver::onAppFocus(pid_t pid) + +{ + + // Note: This is not necessarily the same as the FocusState->ActiveProcessId. + + + + ActiveProcessId = pid; + + + + if (ActiveProcessId == 0) return; + + + + if (pid != LastAppFocus) + + { + + LastAppFocus = pid; + + if(listener){ + + listener->onFocusChange(pid); + + } + +// FocusSubject->Call(pid); + + } + +} + + + +void AppFocusObserver::RemoveProcess(pid_t pid) + +{ + + Lock::Locker locker(&ListLock); + + + + // Find the pid in the app list: + + const int count = AppList.GetSizeI(); + + for (int i = 0; i < count; ++i) + + { + + // If the app was found, + + if (AppList[i] == pid) + + { + + // Remove from list here + + AppList.RemoveAtUnordered(i); + + + + // If the removed process is the active one, + + if (ActiveProcessId == pid) + + { + + OVR_DEBUG_LOG(("[AppFocusObserver] RemoveProcess: Active process going away")); + + // Find a new active process + + nextProcess(); + + } + + + + break; + + } + + } + +} + +}} //namespace OVR::OSX + + + diff --git a/LibOVR/Src/Displays/OVR_OSX_FocusReader.h b/LibOVR/Src/Displays/OVR_OSX_FocusReader.h index 74858c5..dbfe9f6 100644 --- a/LibOVR/Src/Displays/OVR_OSX_FocusReader.h +++ b/LibOVR/Src/Displays/OVR_OSX_FocusReader.h @@ -1,3 +1,31 @@ +/************************************************************************************ + +Filename : OVR_OSX_FocusReader.h +Content : Reader for current app with focus on OSX +Created : August 5, 2014 +Authors : Jordan Tritell + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); +you may not use the Oculus VR Rift SDK except in compliance with the License, +which is provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +You may obtain a copy of the License at + +http://www.oculusvr.com/licenses/LICENSE-3.2 + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*************************************************************************************/ + +OVR_PRIVATE_FILE + #ifndef OVR_OSX_FocusReader_h #define OVR_OSX_FocusReader_h @@ -13,5 +41,5 @@ @end -#endif +#endif /* OVR_OSX_FocusReader_h */ diff --git a/LibOVR/Src/Displays/OVR_OSX_FocusReader.mm b/LibOVR/Src/Displays/OVR_OSX_FocusReader.mm new file mode 100644 index 0000000..9354559 --- /dev/null +++ b/LibOVR/Src/Displays/OVR_OSX_FocusReader.mm @@ -0,0 +1,150 @@ +/************************************************************************************ + + + +Filename : OVR_OSX_FocusReader.mm + +Content : Reader for current app with focus on OSX + +Created : August 5, 2014 + +Authors : Jordan Tritell + + + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + + + +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); + +you may not use the Oculus VR Rift SDK except in compliance with the License, + +which is provided at the time of installation or download, or which + +otherwise accompanies this software in either electronic or hard copy form. + + + +You may obtain a copy of the License at + + + +http://www.oculusvr.com/licenses/LICENSE-3.2 + + + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK + +distributed under the License is distributed on an "AS IS" BASIS, + +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +See the License for the specific language governing permissions and + +limitations under the License. + + + +*************************************************************************************/ + + + +OVR_PRIVATE_FILE + + + +#import "OVR_OSX_FocusReader.h" + +#import "OVR_OSX_FocusObserver.h" + + + +@implementation FocusReader + + + +@synthesize window; + + + +- (void) addActivationObserver + +{ + + //subscribe to focus notifications from the workspace + + [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self + + selector:@selector(activated:) + + name:NSWorkspaceDidActivateApplicationNotification + + object:nil]; + + + + //subscribe to focus notifications from the workspace + + [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self + + selector:@selector(terminated:) + + name:NSWorkspaceDidTerminateApplicationNotification + + object:nil]; + +} + + + +-(void) activated:(NSNotification *)notification + +{ + + NSRunningApplication *app = [[notification userInfo] objectForKey:@"NSWorkspaceApplicationKey"]; + + pid_t pid = [app processIdentifier]; + + OVR::OSX::AppFocusObserver::GetInstance()->OnProcessFocus(pid); + + // NSLog(@"Activated: %@", [activatedApp bundleIdentifier]); + +} + + + +-(void) terminated:(NSNotification *)notification + +{ + + NSRunningApplication *app = [[notification userInfo] objectForKey:@"NSWorkspaceApplicationKey"]; + + pid_t pid = [app processIdentifier]; + + OVR::OSX::AppFocusObserver::GetInstance()->RemoveProcess(pid); + + // NSLog(@"Activated: %@", [activatedApp bundleIdentifier]); + +} + + + +- (void)start + +{ + + //initialize with relevant variables + + [self addActivationObserver]; + +} + + + +@end + + + + + diff --git a/LibOVR/Src/Displays/OVR_Win32_Display.cpp b/LibOVR/Src/Displays/OVR_Win32_Display.cpp index 6bebc7b..6ddf030 100644 --- a/LibOVR/Src/Displays/OVR_Win32_Display.cpp +++ b/LibOVR/Src/Displays/OVR_Win32_Display.cpp @@ -5,16 +5,16 @@ Content : Win32 Display implementation Created : May 6, 2014 Authors : Dean Beeler -Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved. +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. -Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License"); +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); you may not use the Oculus VR Rift SDK except in compliance with the License, which is provided at the time of installation or download, or which otherwise accompanies this software in either electronic or hard copy form. You may obtain a copy of the License at -http://www.oculusvr.com/licenses/LICENSE-3.1 +http://www.oculusvr.com/licenses/LICENSE-3.2 Unless required by applicable law or agreed to in writing, the Oculus VR SDK distributed under the License is distributed on an "AS IS" BASIS, @@ -713,13 +713,16 @@ static bool AccessDeviceRegistry(IN HDEVINFO devInfo, IN PSP_DEVINFO_DATA devInf EDIDdata, &edidsize); - if (FAILED(retValue)) + // If no more items in the enumeration, + if (retValue == ERROR_NO_MORE_ITEMS) { - if (retValue == ERROR_NO_MORE_ITEMS) - { - break; - } + // Stop here + break; + } + // If the request failed, + if (FAILED(retValue)) + { LogError("{ERR-098} [Display] WARNING: RegEnumValueA failed to read a key. LastErr=%d", retValue); OVR_ASSERT(false); } @@ -1033,9 +1036,16 @@ bool Display::Initialize() { HANDLE hDevice = INVALID_HANDLE_VALUE; - hDevice = CreateFile( L"\\\\.\\ovr_video" , + if (GlobalDisplayContext.hDevice == 0) + { + hDevice = CreateFile( L"\\\\.\\ovr_video" , GENERIC_READ | GENERIC_WRITE, NULL, NULL, OPEN_EXISTING, NULL, NULL); + } + else + { // The device has already been created + hDevice = GlobalDisplayContext.hDevice; + } if (hDevice != NULL && hDevice != INVALID_HANDLE_VALUE) { diff --git a/LibOVR/Src/Displays/OVR_Win32_Display.h b/LibOVR/Src/Displays/OVR_Win32_Display.h index b5cb03e..41229ac 100644 --- a/LibOVR/Src/Displays/OVR_Win32_Display.h +++ b/LibOVR/Src/Displays/OVR_Win32_Display.h @@ -5,16 +5,16 @@ Content : Win32-specific Display declarations Created : May 6, 2014 Authors : Dean Beeler -Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved. +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. -Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License"); +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); you may not use the Oculus VR Rift SDK except in compliance with the License, which is provided at the time of installation or download, or which otherwise accompanies this software in either electronic or hard copy form. You may obtain a copy of the License at -http://www.oculusvr.com/licenses/LICENSE-3.1 +http://www.oculusvr.com/licenses/LICENSE-3.2 Unless required by applicable law or agreed to in writing, the Oculus VR SDK distributed under the License is distributed on an "AS IS" BASIS, @@ -29,6 +29,8 @@ limitations under the License. #include "OVR_Display.h" +OVR_DISABLE_MSVC_WARNING(4351) // new behavior: elements of array will be default initialized + namespace OVR { namespace Win32 { @@ -74,8 +76,15 @@ public: int displayCount; Win32DisplaySearchHandle() + : cachedDescriptorArray(), + extended(), + application(false), + extendedDisplayCount(0), + applicationDisplayCount(0), + displayCount(0) { } + virtual ~Win32DisplaySearchHandle() { } @@ -166,4 +175,8 @@ public: }} // namespace OVR::Win32 + +OVR_RESTORE_MSVC_WARNING() + + #endif // OVR_Win32_Display_h diff --git a/LibOVR/Src/Displays/OVR_Win32_FocusReader.cpp b/LibOVR/Src/Displays/OVR_Win32_FocusReader.cpp index d665546..e98f95b 100644 --- a/LibOVR/Src/Displays/OVR_Win32_FocusReader.cpp +++ b/LibOVR/Src/Displays/OVR_Win32_FocusReader.cpp @@ -5,16 +5,16 @@ Content : Reader for current app with focus on Windows Created : July 2, 2014 Authors : Chris Taylor -Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved. +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. -Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License"); +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); you may not use the Oculus VR Rift SDK except in compliance with the License, which is provided at the time of installation or download, or which otherwise accompanies this software in either electronic or hard copy form. You may obtain a copy of the License at -http://www.oculusvr.com/licenses/LICENSE-3.1 +http://www.oculusvr.com/licenses/LICENSE-3.2 Unless required by applicable law or agreed to in writing, the Oculus VR SDK distributed under the License is distributed on an "AS IS" BASIS, @@ -35,8 +35,9 @@ namespace OVR { namespace Win32 { HWND RenderFocusReader::ReadActiveWindow() { - FocusState = Reader.Get(); - if (!FocusState || NoSharedMemory) + const LocklessFocusState* focusState = Reader.Get(); + + if (!focusState || NoSharedMemory) { if (!Reader.Open(OVR_FOCUS_OBSERVER_SHARE_NAME)) { @@ -46,8 +47,8 @@ HWND RenderFocusReader::ReadActiveWindow() return 0; } - FocusState = Reader.Get(); - if (!FocusState) + focusState = Reader.Get(); + if (!focusState) { OVR_DEBUG_LOG(("[Win32ShimFunctions] Unable to get the shared memory space")); NoSharedMemory = true; @@ -55,13 +56,13 @@ HWND RenderFocusReader::ReadActiveWindow() } } - return (HWND)Ptr64ToPtr(FocusState->ActiveWindowHandle); + return (HWND)Ptr64ToPtr(focusState->ActiveWindowHandle); } -RenderFocusReader::RenderFocusReader() +RenderFocusReader::RenderFocusReader() : + NoSharedMemory(false) { - NoSharedMemory = false; - + // Must be at end of function PushDestroyCallbacks(); } diff --git a/LibOVR/Src/Displays/OVR_Win32_FocusReader.h b/LibOVR/Src/Displays/OVR_Win32_FocusReader.h index 1d58264..b5e16b7 100644 --- a/LibOVR/Src/Displays/OVR_Win32_FocusReader.h +++ b/LibOVR/Src/Displays/OVR_Win32_FocusReader.h @@ -5,16 +5,16 @@ Content : Reader for current app with focus on Windows Created : July 2, 2014 Authors : Chris Taylor -Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved. +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. -Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License"); +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); you may not use the Oculus VR Rift SDK except in compliance with the License, which is provided at the time of installation or download, or which otherwise accompanies this software in either electronic or hard copy form. You may obtain a copy of the License at -http://www.oculusvr.com/licenses/LICENSE-3.1 +http://www.oculusvr.com/licenses/LICENSE-3.2 Unless required by applicable law or agreed to in writing, the Oculus VR SDK distributed under the License is distributed on an "AS IS" BASIS, @@ -69,7 +69,6 @@ class RenderFocusReader : public OVR::SystemSingletonBase<RenderFocusReader>, pu OVR_DECLARE_SINGLETON(RenderFocusReader); SharedFocusReader Reader; // Shared memory reader - const LocklessFocusState* FocusState; // Pointer to the current focus state bool NoSharedMemory; // Flag reporting that no shared memory has been detected; public: diff --git a/LibOVR/Src/Displays/OVR_Win32_RenderShim.cpp b/LibOVR/Src/Displays/OVR_Win32_RenderShim.cpp index 80b33a2..ed04804 100644 --- a/LibOVR/Src/Displays/OVR_Win32_RenderShim.cpp +++ b/LibOVR/Src/Displays/OVR_Win32_RenderShim.cpp @@ -6,7 +6,7 @@ Content : Shared static functions for inclusion that allow for an applicat Created : March 21, 2014 Authors : Dean Beeler -Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved. +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. Use of this software is subject to the terms of the Oculus Inc license agreement provided at the time of installation or download, or which @@ -14,6 +14,10 @@ otherwise accompanies this software in either electronic or hard copy form. ************************************************************************************/ +#ifndef AVOID_LIB_OVR +#include "../Kernel/OVR_Types.h" // Without this we can get warnings (due to VC++ bugs) about _malloca being redefined, and miss LibOVR overrides. +#endif + #include <windows.h> #include <DbgHelp.h> #include <malloc.h> @@ -641,7 +645,12 @@ static PROC SetProcAddressA( __in PROC newFunction ) { - PROC pfnHookAPIAddr = GetProcAddress( LoadLibraryA( lpLibFileName ), lpProcName ); + HMODULE hModule = LoadLibraryA( lpLibFileName ); + if(hModule == NULL) + return NULL; + + // To do: call FreeLibrary(hModule) at the appropriate time. + PROC pfnHookAPIAddr = GetProcAddress(hModule, lpProcName ); HINSTANCE hInstance = targetModule; @@ -795,7 +804,7 @@ void checkUMDriverOverrides(void* context) } } - rtFilterModule = (*oldProcA)( RTFilter ); + rtFilterModule = oldProcA ? (*oldProcA)(RTFilter) : NULL; IsCreatingBackBuffer backBufferFunc = NULL; ShouldVSync shouldVSyncFunc = NULL; diff --git a/LibOVR/Src/Displays/OVR_Win32_ShimFunctions.cpp b/LibOVR/Src/Displays/OVR_Win32_ShimFunctions.cpp index 907dc13..0246aae 100644 --- a/LibOVR/Src/Displays/OVR_Win32_ShimFunctions.cpp +++ b/LibOVR/Src/Displays/OVR_Win32_ShimFunctions.cpp @@ -5,16 +5,16 @@ Content : Client-side shim callbacks for usermode/rt hooks Created : May 6, 2014 Authors : Dean Beeler -Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved. +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. -Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License"); +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); you may not use the Oculus VR Rift SDK except in compliance with the License, which is provided at the time of installation or download, or which otherwise accompanies this software in either electronic or hard copy form. You may obtain a copy of the License at -http://www.oculusvr.com/licenses/LICENSE-3.1 +http://www.oculusvr.com/licenses/LICENSE-3.2 Unless required by applicable law or agreed to in writing, the Oculus VR SDK distributed under the License is distributed on an "AS IS" BASIS, @@ -184,7 +184,8 @@ DisplayShim::DisplayShim() : ExpectedHeight( 800 ), Rotation( 0 ), hWindow( 0 ), - UseMirroring( TRUE ) + UseMirroring( true ), + Active( false ) { } diff --git a/LibOVR/Src/Displays/OVR_Win32_ShimFunctions.h b/LibOVR/Src/Displays/OVR_Win32_ShimFunctions.h index 86de0d6..004779d 100644 --- a/LibOVR/Src/Displays/OVR_Win32_ShimFunctions.h +++ b/LibOVR/Src/Displays/OVR_Win32_ShimFunctions.h @@ -5,16 +5,16 @@ Content : Client-side shim callbacks for usermode/rt hooks Created : May 6, 2014 Authors : Dean Beeler -Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved. +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. -Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License"); +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); you may not use the Oculus VR Rift SDK except in compliance with the License, which is provided at the time of installation or download, or which otherwise accompanies this software in either electronic or hard copy form. You may obtain a copy of the License at -http://www.oculusvr.com/licenses/LICENSE-3.1 +http://www.oculusvr.com/licenses/LICENSE-3.2 Unless required by applicable law or agreed to in writing, the Oculus VR SDK distributed under the License is distributed on an "AS IS" BASIS, |