added linux makefile

This commit is contained in:
Colin Sherratt
2014-05-26 03:42:23 -04:00
parent cb5a46cd58
commit 6b733ba3a3
141 changed files with 53997 additions and 6 deletions

11
configure vendored
View File

@ -329,17 +329,16 @@ def set_source_dir(modules, source_dir):
_base = os.path.abspath(os.path.dirname(__file__))
modules = [Bin("oculus-info", ["oculus-vr"]),
Lib("oculus-vr", ["libovr.a", "cgmath"]),
Lib("cgmath")]
if platform.system() == "Linux":
modules += [Lib("oculus-vr", ["libOVR_C.so", "cgmath"]),
LibCMake("libOVR_C.so",
"modules/OculusSDK/",
"modules/OculusSDK/output/libOVR_C.so")]
modules += [LibMakefile("libovr.a",
"modules/oculus_sdk_linux/",
["modules/oculus_sdk_linux/LibOVR/Lib/Linux/Release/x86_64/libovr.a"])]
elif platform.system() == "Darwin":
modules += [Lib("oculus-vr", ["libovr.a", "cgmath"]),
LibXcodebuild("libovr.a",
modules += [LibXcodebuild("libovr.a",
"modules/oculus_sdk_mac/LibOVR/Projects/Mac/Xcode/LibOVR.xcodeproj",
["modules/oculus_sdk_mac/LibOVR/Lib/MacOS/Release/libovr.a"])]

View File

@ -0,0 +1,446 @@
/*
* Copyright 2007 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/* Author: Soren Sandmann <sandmann@redhat.com> */
#include "edid.h"
#include <stdint.h>
#include <math.h>
#include <memory.h>
#include <X11/Xatom.h>
static int get_bit(int in, int bit) {
return (in & (1 << bit)) >> bit;
}
static int get_bits(int in, int begin, int end) {
int mask = (1 << (end - begin + 1)) - 1;
return (in >> begin) & mask;
}
static bool decode_header(const uint8_t *edid) {
if (memcmp(edid, "\x00\xff\xff\xff\xff\xff\xff\x00", 8) == 0)
return true;
return false;
}
static int decode_vendor_and_product_identification(const uint8_t *edid, MonitorInfo *info) {
/* Manufacturer Code */
info->manufacturer_code[0] = get_bits(edid[0x08], 2, 6);
info->manufacturer_code[1] = get_bits(edid[0x08], 0, 1) << 3;
info->manufacturer_code[1] |= get_bits(edid[0x09], 5, 7);
info->manufacturer_code[2] = get_bits(edid[0x09], 0, 4);
info->manufacturer_code[3] = '\0';
info->manufacturer_code[0] += 'A' - 1;
info->manufacturer_code[1] += 'A' - 1;
info->manufacturer_code[2] += 'A' - 1;
/* Product Code */
info->product_code = edid[0x0b] << 8 | edid[0x0a];
/* Serial Number */
info->serial_number = edid[0x0c] | edid[0x0d] << 8 | edid[0x0e] << 16 | edid[0x0f] << 24;
/* Week and Year */
bool is_model_year = false;
switch (edid[0x10]) {
case 0x00:
info->production_week = -1;
break;
case 0xff:
info->production_week = -1;
is_model_year = true;
break;
default:
info->production_week = edid[0x10];
break;
}
if (is_model_year) {
info->production_year = -1;
info->model_year = 1990 + edid[0x11];
} else {
info->production_year = 1990 + edid[0x11];
info->model_year = -1;
}
return true;
}
static bool decode_edid_version(const uint8_t *edid, MonitorInfo *info) {
info->major_version = edid[0x12];
info->minor_version = edid[0x13];
return true;
}
static bool decode_display_parameters(const uint8_t *edid, MonitorInfo *info) {
/* Digital vs Analog */
info->is_digital = get_bit(edid[0x14], 7);
if (info->is_digital) {
static const int bit_depth[8] = { -1, 6, 8, 10, 12, 14, 16, -1 };
static const Interface interfaces[6] = { UNDEFINED, DVI, HDMI_A, HDMI_B, MDDI, DISPLAY_PORT };
int bits = get_bits(edid[0x14], 4, 6);
info->connector.digital.bits_per_primary = bit_depth[bits];
bits = get_bits(edid[0x14], 0, 3);
if (bits <= 5)
info->connector.digital.interface = interfaces[bits];
else
info->connector.digital.interface = UNDEFINED;
} else {
int bits = get_bits(edid[0x14], 5, 6);
static const double levels[][3] = { //
{ 0.7, 0.3, 1.0 }, //
{ 0.714, 0.286, 1.0 }, //
{ 1.0, 0.4, 1.4 }, //
{ 0.7, 0.0, 0.7 }, //
};
info->connector.analog.video_signal_level = levels[bits][0];
info->connector.analog.sync_signal_level = levels[bits][1];
info->connector.analog.total_signal_level = levels[bits][2];
info->connector.analog.blank_to_black = get_bit(edid[0x14], 4);
info->connector.analog.separate_hv_sync = get_bit(edid[0x14], 3);
info->connector.analog.composite_sync_on_h = get_bit(edid[0x14], 2);
info->connector.analog.composite_sync_on_green = get_bit(edid[0x14], 1);
info->connector.analog.serration_on_vsync = get_bit(edid[0x14], 0);
}
/* Screen Size / Aspect Ratio */
if (edid[0x15] == 0 && edid[0x16] == 0) {
info->width_mm = -1;
info->height_mm = -1;
info->aspect_ratio = -1.0;
} else if (edid[0x16] == 0) {
info->width_mm = -1;
info->height_mm = -1;
info->aspect_ratio = 100.0 / (edid[0x15] + 99);
} else if (edid[0x15] == 0) {
info->width_mm = -1;
info->height_mm = -1;
info->aspect_ratio = 100.0 / (edid[0x16] + 99);
info->aspect_ratio = 1 / info->aspect_ratio; /* portrait */
} else {
info->width_mm = 10 * edid[0x15];
info->height_mm = 10 * edid[0x16];
}
/* Gamma */
if (edid[0x17] == 0xFF)
info->gamma = -1.0;
else
info->gamma = (edid[0x17] + 100.0) / 100.0;
/* Features */
info->standby = get_bit(edid[0x18], 7);
info->suspend = get_bit(edid[0x18], 6);
info->active_off = get_bit(edid[0x18], 5);
if (info->is_digital) {
info->connector.digital.rgb444 = 1;
if (get_bit(edid[0x18], 3))
info->connector.digital.ycrcb444 = 1;
if (get_bit(edid[0x18], 4))
info->connector.digital.ycrcb422 = 1;
} else {
int bits = get_bits(edid[0x18], 3, 4);
ColorType color_type[4] = { MONOCHROME, RGB, OTHER_COLOR, UNDEFINED_COLOR };
info->connector.analog.color_type = color_type[bits];
}
info->srgb_is_standard = get_bit(edid[0x18], 2);
/* In 1.3 this is called "has preferred timing" */
info->preferred_timing_includes_native = get_bit(edid[0x18], 1);
/* FIXME: In 1.3 this indicates whether the monitor accepts GTF */
info->continuous_frequency = get_bit(edid[0x18], 0);
return true;
}
static double decode_fraction(int high, int low) {
double result = 0.0;
high = (high << 2) | low;
for (int i = 0; i < 10; ++i)
result += get_bit(high, i) * pow(2, i - 10);
return result;
}
static bool decode_color_characteristics(const uint8_t *edid, MonitorInfo *info) {
info->red_x = decode_fraction(edid[0x1b], get_bits(edid[0x19], 6, 7));
info->red_y = decode_fraction(edid[0x1c], get_bits(edid[0x19], 5, 4));
info->green_x = decode_fraction(edid[0x1d], get_bits(edid[0x19], 2, 3));
info->green_y = decode_fraction(edid[0x1e], get_bits(edid[0x19], 0, 1));
info->blue_x = decode_fraction(edid[0x1f], get_bits(edid[0x1a], 6, 7));
info->blue_y = decode_fraction(edid[0x20], get_bits(edid[0x1a], 4, 5));
info->white_x = decode_fraction(edid[0x21], get_bits(edid[0x1a], 2, 3));
info->white_y = decode_fraction(edid[0x22], get_bits(edid[0x1a], 0, 1));
return true;
}
static bool decode_established_timings(const uint8_t *edid, MonitorInfo *info) {
static const Timing established[][8] = { //
{ { 800, 600, 60 }, { 800, 600, 56 }, //
{ 640, 480, 75 }, { 640, 480, 72 }, //
{ 640, 480, 67 }, { 640, 480, 60 }, //
{ 720, 400, 88 }, { 720, 400, 70 } }, //
{ { 1280, 1024, 75 }, { 1024, 768, 75 }, //
{ 1024, 768, 70 }, { 1024, 768, 60 }, //
{ 1024, 768, 87 }, { 832, 624, 75 }, //
{ 800, 600, 75 }, { 800, 600, 72 } }, //
{ { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, //
{ 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 1152, 870, 75 } }, //
};
int idx = 0;
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 8; ++j) {
int byte = edid[0x23 + i];
if (get_bit(byte, j) && established[i][j].frequency != 0)
info->established[idx++] = established[i][j];
}
}
return true;
}
static bool decode_standard_timings(const uint8_t *edid, MonitorInfo *info) {
int i;
for (i = 0; i < 8; i++) {
int first = edid[0x26 + 2 * i];
int second = edid[0x27 + 2 * i];
if (first != 0x01 && second != 0x01) {
int w = 8 * (first + 31);
int h = 0;
switch (get_bits(second, 6, 7)) {
case 0x00:
h = (w / 16) * 10;
break;
case 0x01:
h = (w / 4) * 3;
break;
case 0x02:
h = (w / 5) * 4;
break;
case 0x03:
h = (w / 16) * 9;
break;
}
info->standard[i].width = w;
info->standard[i].height = h;
info->standard[i].frequency = get_bits(second, 0, 5) + 60;
}
}
return true;
}
static void decode_lf_string(const uint8_t *s, int n_chars, char *result) {
int i;
for (i = 0; i < n_chars; ++i) {
if (s[i] == 0x0a) {
*result++ = '\0';
break;
} else if (s[i] == 0x00) {
/* Convert embedded 0's to spaces */
*result++ = ' ';
} else {
*result++ = s[i];
}
}
}
static void decode_display_descriptor(const uint8_t *desc, MonitorInfo *info) {
switch (desc[0x03]) {
case 0xFC:
decode_lf_string(desc + 5, 13, info->dsc_product_name);
break;
case 0xFF:
decode_lf_string(desc + 5, 13, info->dsc_serial_number);
break;
case 0xFE:
decode_lf_string(desc + 5, 13, info->dsc_string);
break;
case 0xFD:
/* Range Limits */
break;
case 0xFB:
/* Color Point */
break;
case 0xFA:
/* Timing Identifications */
break;
case 0xF9:
/* Color Management */
break;
case 0xF8:
/* Timing Codes */
break;
case 0xF7:
/* Established Timings */
break;
case 0x10:
break;
}
}
static void decode_detailed_timing(const uint8_t *timing, DetailedTiming *detailed) {
int bits;
StereoType stereo[] = { //
NO_STEREO, NO_STEREO, //
FIELD_RIGHT, FIELD_LEFT, //
TWO_WAY_RIGHT_ON_EVEN, TWO_WAY_LEFT_ON_EVEN, //
FOUR_WAY_INTERLEAVED, //
SIDE_BY_SIDE //
};
detailed->pixel_clock = (timing[0x00] | timing[0x01] << 8) * 10000;
detailed->h_addr = timing[0x02] | ((timing[0x04] & 0xf0) << 4);
detailed->h_blank = timing[0x03] | ((timing[0x04] & 0x0f) << 8);
detailed->v_addr = timing[0x05] | ((timing[0x07] & 0xf0) << 4);
detailed->v_blank = timing[0x06] | ((timing[0x07] & 0x0f) << 8);
detailed->h_front_porch = timing[0x08] | get_bits(timing[0x0b], 6, 7) << 8;
detailed->h_sync = timing[0x09] | get_bits(timing[0x0b], 4, 5) << 8;
detailed->v_front_porch = get_bits(timing[0x0a], 4, 7) | get_bits(timing[0x0b], 2, 3) << 4;
detailed->v_sync = get_bits(timing[0x0a], 0, 3) | get_bits(timing[0x0b], 0, 1) << 4;
detailed->width_mm = timing[0x0c] | get_bits(timing[0x0e], 4, 7) << 8;
detailed->height_mm = timing[0x0d] | get_bits(timing[0x0e], 0, 3) << 8;
detailed->right_border = timing[0x0f];
detailed->top_border = timing[0x10];
detailed->interlaced = get_bit(timing[0x11], 7);
/* Stereo */
bits = get_bits(timing[0x11], 5, 6) << 1 | get_bit(timing[0x11], 0);
detailed->stereo = stereo[bits];
/* Sync */
bits = timing[0x11];
detailed->digital_sync = get_bit(bits, 4);
if (detailed->digital_sync) {
detailed->connector.digital.composite = !get_bit(bits, 3);
if (detailed->connector.digital.composite) {
detailed->connector.digital.serrations = get_bit(bits, 2);
detailed->connector.digital.negative_vsync = 0;
} else {
detailed->connector.digital.serrations = 0;
detailed->connector.digital.negative_vsync = !get_bit(bits, 2);
}
detailed->connector.digital.negative_hsync = !get_bit(bits, 0);
} else {
detailed->connector.analog.bipolar = get_bit(bits, 3);
detailed->connector.analog.serrations = get_bit(bits, 2);
detailed->connector.analog.sync_on_green = !get_bit(bits, 1);
}
}
static bool decode_descriptors(const uint8_t *edid, MonitorInfo *info) {
int timing_idx = 0;
for (int i = 0; i < 4; ++i) {
int index = 0x36 + i * 18;
if (edid[index + 0] == 0x00 && edid[index + 1] == 0x00) {
decode_display_descriptor(edid + index, info);
} else {
decode_detailed_timing(edid + index, &(info->detailed_timings[timing_idx++]));
}
}
info->n_detailed_timings = timing_idx;
return true;
}
static void decode_check_sum(const uint8_t *edid, MonitorInfo *info) {
uint8_t check = 0;
for (int i = 0; i < 128; ++i)
check += edid[i];
info->checksum = check;
}
MonitorInfo * decode_edid(const uint8_t *edid) {
MonitorInfo *info = new MonitorInfo();
decode_check_sum(edid, info);
if (decode_header(edid) && //
decode_vendor_and_product_identification(edid, info) && //
decode_edid_version(edid, info) && //
decode_display_parameters(edid, info) && //
decode_color_characteristics(edid, info) && //
decode_established_timings(edid, info) && //
decode_standard_timings(edid, info) && //
decode_descriptors(edid, info)) {
return info;
} else {
delete info;
return 0;
}
}
static uint8_t * get_property(Display *dpy, RROutput output, Atom atom, int *len) {
unsigned char *prop;
int actual_format;
unsigned long nitems, bytes_after;
Atom actual_type;
uint8_t *result = NULL;
XRRGetOutputProperty(dpy, output, atom, 0, 100, False, False,
AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, &prop);
if (actual_type == XA_INTEGER && actual_format == 8) {
result = new uint8_t[nitems];
memcpy(result, prop, nitems);
if (len)
*len = nitems;
}
XFree(prop);
return result;
}
MonitorInfo * read_edid_data(Display * disp, RROutput id) {
int len;
Atom edid_atom = XInternAtom(disp, "EDID", false);
uint8_t *edid = get_property(disp, id, edid_atom, &len);
if (!edid) {
edid_atom = XInternAtom(disp, "EDID_DATA", false);
edid = get_property(disp, id, edid_atom, &len);
}
MonitorInfo * result = 0;
if (edid) {
if (len % 128 == 0) {
result = decode_edid(edid);
}
delete[] edid;
}
return result;
}

View File

@ -0,0 +1,174 @@
#include <X11/extensions/Xrandr.h>
#include <X11/Xlib.h>
/*
* Copyright 2007 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/* Author: Soren Sandmann <sandmann@redhat.com> */
typedef enum {
UNDEFINED,
DVI,
HDMI_A,
HDMI_B,
MDDI,
DISPLAY_PORT
} Interface;
typedef enum {
UNDEFINED_COLOR,
MONOCHROME,
RGB,
OTHER_COLOR
} ColorType;
typedef enum {
NO_STEREO,
FIELD_RIGHT,
FIELD_LEFT,
TWO_WAY_RIGHT_ON_EVEN,
TWO_WAY_LEFT_ON_EVEN,
FOUR_WAY_INTERLEAVED,
SIDE_BY_SIDE
} StereoType;
struct Timing {
int width;
int height;
int frequency;
};
struct DetailedTiming {
int pixel_clock;
int h_addr;
int h_blank;
int h_sync;
int h_front_porch;
int v_addr;
int v_blank;
int v_sync;
int v_front_porch;
int width_mm;
int height_mm;
int right_border;
int top_border;
int interlaced;
StereoType stereo;
int digital_sync;
union {
struct {
int bipolar;
int serrations;
int sync_on_green;
} analog;
struct {
int composite;
int serrations;
int negative_vsync;
int negative_hsync;
} digital;
} connector;
};
struct MonitorInfo {
int checksum;
char manufacturer_code[4];
int product_code;
unsigned int serial_number;
int production_week; /* -1 if not specified */
int production_year; /* -1 if not specified */
int model_year; /* -1 if not specified */
int major_version;
int minor_version;
int is_digital;
union {
struct {
int bits_per_primary;
Interface interface;
int rgb444;
int ycrcb444;
int ycrcb422;
} digital;
struct {
double video_signal_level;
double sync_signal_level;
double total_signal_level;
int blank_to_black;
int separate_hv_sync;
int composite_sync_on_h;
int composite_sync_on_green;
int serration_on_vsync;
ColorType color_type;
} analog;
} connector;
int width_mm; /* -1 if not specified */
int height_mm; /* -1 if not specified */
double aspect_ratio; /* -1.0 if not specififed */
double gamma; /* -1.0 if not specified */
int standby;
int suspend;
int active_off;
int srgb_is_standard;
int preferred_timing_includes_native;
int continuous_frequency;
double red_x;
double red_y;
double green_x;
double green_y;
double blue_x;
double blue_y;
double white_x;
double white_y;
Timing established[24]; /* Terminated by 0x0x0 */
Timing standard[8];
int n_detailed_timings;
DetailedTiming detailed_timings[4]; /* If monitor has a preferred
* mode, it is the first one
* (whether it has, is
* determined by the
* preferred_timing_includes
* bit.
*/
/* Optional product description */
char dsc_serial_number[14];
char dsc_product_name[14];
char dsc_string[14]; /* Unspecified ASCII data */
};
MonitorInfo * read_edid_data(Display * disp, RROutput id);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,19 @@
Firmware packages for Oculus products are stored in this folder.
Use the OculusConfigUtil to load them and update your products.
Tracker DK Firmware Version History
===================================
0.18 - 2013-10-03
* Resolve a calibration issue that could result in additional
drift in certain conditions.
* Resolve a calibration issue that resulted in additional drift
after fast motions.
0.17 - 2013-04-24
* Fix an issue where the Tracker can fail to initialize with
Logitech software running.
0.16 - 2013-03-13
* Release firmware for the Oculus Rift DK.

View File

@ -0,0 +1,264 @@
Oculus VR Rift SDK Software License
Oculus VR, Inc. Software Development Kit License Agreement
Copyright © 2014 Oculus VR, Inc. All rights reserved.
The text of this may be found at: http://www.oculusvr.com/licenses/LICENSE-3.1
Human-Readable Summary*:
You are Free to:
Use, modify, and distribute the Oculus VR Rift SDK in source and binary
form with your applications/software.
With the Following Restrictions:
You can only distribute or re-distribute the source code to LibOVR in
whole, not in part.
Modifications to the Oculus VR Rift SDK in source or binary form must
be shared with Oculus VR.
If your applications cause health and safety issues, you may lose your
right to use the Oculus VR Rift SDK, including LibOVR.
The Oculus VR Rift SDK may not be used to interface with unapproved commercial
virtual reality mobile or non-mobile products or hardware.
* - This human-readable Summary is not a license. It is simply a convenient
reference for understanding the full Oculus VR Rift SDK License Agreement.
The Summary is written as a user-friendly interface to the full Oculus VR Rift
SDK License below. This Summary itself has no legal value, and its contents do
not appear in the actual license.
Full-length Legal Copy:
1. Subject to the terms and conditions of this License Agreement (the "License"),
Oculus VR, Inc. ("Oculus VR") hereby grants to you a perpetual, worldwide,
non-exclusive, no-charge, royalty-free, sublicenseable copyright license to use,
reproduce, redistribute (subject to restrictions below), modify, and improve the
software contained in this Oculus VR Rift Software Development Kit ("RIFT SDK"),
including, but not limited to, the samples, headers, LibOVR headers, and LibOVR
source. This license is subject to the following terms and conditions:
1.1. This license includes the non-exclusive license and right to use (i) the RIFT
SDK to make applications, content, games and demos (collectively and generally
referred to as “Developer Content”) that run on the Oculus VR approved mobile hardware
and software products (“Oculus Approved Rift Products”) and which may incorporate
the RIFT SDK in whole or in part in binary or object code; and (ii) to use the
RIFT SDK to create derivative works of the RIFT SDK itself ("RIFT SDK Derivatives"),
whether in source, binary, or object form, in whole or in part, including third
party software unless otherwise noted.
1.2. RIFT SDK Derivatives are further defined as source, binary or object code
derived exclusively from the RIFT SDK by you; provided, however, that RIFT SDK
Derivatives do not include the Developer Content (engines, utilities, applications,
content, games or demos) which may be developed using the RIFT SDK. By way of example
a mobile application or game or demo that is developed using the RIFT SDK would not
be a RIFT SDK Derivative , nor would a utility or tool set in a pre-existing game
engine that is adapted to work with the RIFT SDK be a RIFT SDK Derivative.
By way of example, but not limitation, a RIFT SDK Derivative is or would be: either (i)
an adaptation of a utility or piece of code from the RIFT SDK to improve efficiency;
or (ii) an addition of code or improvement to the RIFT SDK that adds functionality.
1.3 For the sake of clarification when you use the RIFT SDK (including RIFT SDK
Derivatives) in or with Developer Content, you retain all rights to your Developer
Content, and you have no obligations to share or license Developer Content (including
your source and object code) to Oculus VR or any third parties; provided, however,
Oculus VR retains all rights to the RIFT SDK and the RIFT SDK Derivatives that may
be incorporated into your Developer Content.
1.4 You agree to and you will use the Flash Screen Warning and the Health and
Safety Warnings (collectively the “Oculus Warnings”) and the Oculus VR health and
safety protocols found in the Oculus Best Practices Guide (“Oculus H&S Protocols”),
and your use of the Oculus Warnings and the Oculus end user license agreement
(“Oculus EULA”) with your Developer Content as provided for in the Oculus Developer
Center, all of which can be found at the following link:
https://developer.oculusvr.com/?action=doc.
2. You, the recipient and user of the RIFT SDK, hereby agree and accept that that
Oculus VR shall own all right, title and interest to the intellectual property
rights, including, but limited to copyright, trademark and patent rights, to any
RIFT SDK Derivatives that you may create, and you hereby assign any and all such
rights to such RIFT SDK Derivatives to Oculus VR, subject to the following.
2.1 We hereby grant to you the a fully paid up, no-charge, royalty-free,
world-wide, in perpetuity, non-exclusive right and license back to use these RIFT
SDK Derivatives solely in conjunction with the RIFT SDK (or any components of the
RIFT SDK) and/or Developer Content on Oculus Rift Products as set forth herein.
2.2 Furthermore, for the sake of clarification, Oculus VR and its assignees and
licensees shall be free to use such RIFT SDK Derivatives without any approval
from you and without compensation or attribution to you.
2.3 You also agree upon Oculus VR's request to provide the source and binary code
of any RIFT SDK Derivatives to Oculus VR. FAILURE TO COMPLY WITH THIS REQUEST
IS THE BASIS FOR AUTOMATIC TERMINATION OF THIS LICENSE BY OCULUS VR.
3. Subject to the terms and conditions of this License, your license to redistribute
and sublicense the RIFT SDK and RIFT SDK Derivatives is also expressly made
subject to the following conditions:
3.1. You may sublicense and redistribute the source, binary, or object code of
the RIFT SDK in whole or in part by itself for no charge or as part of a for charge
piece of Developer Content; provided, however, you may only license, sublicense
or redistribute the source, binary or object code of LibOVR in whole, and you may
not license, sublicense or redistribute any portion or element of LibOVR separately
or in part (in either source, binary or object form). If you license, sublicense
or redistribute RIFT SDK Derivatives in and of themselves (not as a part of a
piece of Developer Content) then you may only do that solely with and in conjunction
with either the RIFT SDK or LibOVR. The RIFT SDK (including, but not limited to
LibOVR), any RIFT SDK Derivatives, and any Developer Content may only be used
with Oculus Approved Rift Products and may not be used, licensed, or sublicensed
to interface with mobile software or hardware or other commercial headsets,
mobile tablets or phones that are not authorized and approved by Oculus VR;
3.2. You must include with all such redistributed or sublicensed RIFT SDK
or RIFT SDK Derivatives code the following copyright notice:
"Copyright © 2014 Oculus VR, Inc. All rights reserved," and include the
list of conditions contained in this Section 3, including the full text of
the disclaimer in Section 3.6 below;
3.3. Neither the name of Oculus VR, Inc. nor the names of Oculus VR, Inc.'s
contributors, licensors, employees, or contractors, may be used to endorse or promote
products derived from this RIFT SDK without specific prior written permission
of Oculus VR, Inc.;
3.4. You must give any other recipients of the RIFT SDK or any elements thereof,
including LibOVR or RIFT SDK Derivatives, a copy of this License as such recipients,
licensees or sublicensees may only use the RIFT SDK or any RIFT SDK Derivatives
or any elements thereof subject to the terms of this Licence and such recipients,
licensees or sublicensees agreement and acceptance of this License with Oculus VR
(which will convey all rights to the recipients or licensees or sublicensees
RIFT SDK Derivatives to Oculus VR), and you must cause any modified files to
carry prominent notices stating that you changed the files;
3.5. If the RIFT SDK or a specific element thereof such as LibOVR includes a
"LICENSE" text file as part of its distribution (the “License Notice”), then
any RIFT SDK Derivatives that you distribute with the RIFT SDK in whole or in
part must include a readable copy of such attribution notices as are contained
within the applicable License Notice file (excluding those notices that do not
pertain to any part of the RIFT SDK Derivatives), in at least one of the following
places: within a License Notice text file distributed as part of the RIFT SDK
Derivatives; within the source form or documentation, if provided along with
the RIFT SDK Derivatives; or, within a display generated by the RIFT SDK Derivatives,
if and wherever such third-party notices normally appear. You must also include
in the License Notice file for all RIFT SDK Derivatives a copy of all notices
(including any product liability or health and safety notices). The contents
of the License Notice file are for informational purposes only and do not modify
the License. You may add your own attribution notices within RIFT SDK Derivatives
that you distribute, alongside or as an addendum to the License Notice text from
the RIFT SDK or any part thereof, provided that such additional attribution notices
cannot be construed as modifying the License.
3.6. THIS RIFT SDK AND ANY COMPONENT THEREOF IS PROVIDED BY OCULUS VR AND
ITS CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OCULUS VR AS THE
COPYRIGHT OWNER OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS RIFT
SDK OR THE RIFT SDK DERIVATIVES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4. This License does not grant permission to use the trade names, trademarks,
service marks, or product names of Oculus VR, except as required for reasonable
and customary use in describing the origin of the RIFT SDK, LibOVR, or any
element thereof, and reproducing the content of the License Notice file.
5. In no event and under no legal theory, whether in tort (including negligence),
contract, or otherwise, unless required by applicable law (such as
deliberate and grossly negligent acts) or agreed to in writing, shall Oculus VR
or any contributor be liable to you or your licensees or sublicensees for
damages, including any direct, indirect, special, incidental, or consequential
damages of any character arising as a result of this License or out of the use
or inability to use the RIFT SDK, LibOVR, any element thereof or any RIFT SDK
Derivatives (including but not limited to damages for loss of goodwill, work
stoppage, computer failure or malfunction, or any and all other commercial
damages or losses), even if you or such contributor has been advised of the
possibility of such damages.
6. Your acceptance of the terms and conditions of this License in and of
itself and for all Developer Content created as of March 1, 2014, may be
evidenced by any of the following: your usage of the RIFT SDK or any element
thereof, acceptance of the click-through agreement, or opening the packaging
of the CD-ROM containing the RIFT SDK or any element thereof, including LibOVR.
As this License is updated for future releases of the RIFT SDK and/or LibOVR,
you agree to abide by and meet all requirements of future updates of this
License for those future RIFT SDK releases as evidenced by the same usage of
the RIFT SDK or any element thereof and the future updates of this License
will apply for that future Developer Content that may developed for or with
that future RIFT SDK or any element thereof (i.e., you cannot sidestep out
of the requirements of future updates of the License by developing against
an older release of the RIFT SDK or License).
7. Oculus VR reserves the right to terminate this License and all your
rights hereunder in the event you materially breach this License and fail
to cure such breach within ten (10) business days after notice of breach
from Oculus VR.
8. Furthermore, Oculus VR also reserves the right to cancel or terminate
this License for any of the following reasons upon notice to you, subject
to the appeal process set forth in Section 14 for a wrongful termination:
a) Intellectual property infringement by you with Developer Content
or RIFT SDK Derivatives created by you that is used with or by the
RIFT SDK or any part thereof, or any of the RIFT SDK Derivatives;
b) Developer Content that violates or infringes upon applicable law;
c) Health and safety issues associated with your Developer Content;
d) Failure to comply with or use properly the Oculus Warnings,
Oculus H&S Protocols, or Oculus EULA;
e) Use of the RIFT SDK, RIFT SDK Derivatives or LibOVR with a
commercial product other than an Oculus Approved Product; and
f) Failure to provide required notices or deliver source code
and/or binary of RIFT SDK Derivatives as set forth above.
If you believe that you have been wrongfully terminated under this Section 8
with respect to material breach or with respect to these above conditions,
you have the right to appeal the termination of this License under Section 14.
9. This License may be amended by Oculus VR on a prospective basis, and your
usage of the License after such amendments or changes signifies your consent
to and acceptance of any such amendments or changes on a going forward basis.
10. In the event any provision of this License is determined to be invalid,
prohibited or unenforceable by a court or other body of competent jurisdiction,
this License shall be construed as if such invalid, prohibited or unenforceable
provision has been more narrowly drawn so as not to be invalid, prohibited or
unenforceable.
11. You may not assign any rights or obligations under this License without
the advance written consent of Oculus VR, which may be withheld in its sole
discretion. Oculus VR may assign its rights or obligations under this License
in its sole discretion.
12. Failure of either party at any time to enforce any of the provisions of
this License will not be construed as a waiver of such provisions or in any way
affect the validity of this License or parts thereof.
13. Your remedies under this License shall be limited to the right to collect
money damages, if any, and you hereby waive your right to injunctive or other
equitable relief.
14. This License shall be governed by the laws of the State of California,
without giving effect to choice of law principles. All disputes relating to
this License shall be resolved by binding non-appearance-based arbitration
before a neutral arbitrator in Orange County, California. If your License
has been terminated hereunder by Oculus, you may appeal your termination
through this arbitration process on an expedited basis with an arbitration
within thirty days of your giving Oculus VR notice of the appeal. The
arbitration shall be conducted in accordance with the rules and procedures
of JAMS then in effect, and the judgment of the arbitrator shall be final
and capable of entry in any court of competent jurisdiction. You agree
to submit to the personal jurisdiction of the courts located within Orange
County, California in connection with any entrance of an arbitrators judgment
or decision or any dispute with respect to the arbitration process or procedure
or Oculus VRs exercise of its equitable rights or remedies.

View File

@ -0,0 +1,2 @@
# Oculus HID Sensor naming and permissioning
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2833", MODE="0666"

View File

@ -0,0 +1,47 @@
/************************************************************************************
Filename : OVR.h
Content : This contains references to all OVR-specific headers in Src folder.
Should be generated automatically based on PublicHeader tags.
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_h
#define OVR_h
#include "../Src/Kernel/OVR_Allocator.h"
#include "../Src/Kernel/OVR_Log.h"
#include "../Src/Kernel/OVR_Math.h"
#include "../Src/Kernel/OVR_System.h"
#include "../Src/Kernel/OVR_Types.h"
#include "../Src/OVR_Device.h"
#include "../Src/OVR_DeviceConstants.h"
#include "../Src/OVR_DeviceHandle.h"
#include "../Src/OVR_DeviceMessages.h"
#include "../Src/OVR_SensorFusion.h"
#include "../Src/OVR_Stereo.h"
#include "../Src/OVR_Profile.h"
#include "../Src/Util/Util_LatencyTest.h"
#include "../Src/Util/Util_Render_Stereo.h"
#include "../Src/Util/Util_Interface.h"
#endif

View File

@ -0,0 +1,33 @@
/************************************************************************************
Filename : OVRVersion.h
Content :
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_VERSION_H
#define _OVR_VERSION_H
#define OVR_MAJOR_VERSION 0
#define OVR_MINOR_VERSION 3
#define OVR_BUILD_VERSION 2
#define OVR_VERSION_STRING "0.3.2"
#endif

View File

@ -0,0 +1,2 @@
This document exits to ensure that the required directory structure gets created correctly.

View File

@ -0,0 +1,2 @@
This document exits to ensure that the required directory structure gets created correctly.

View File

@ -0,0 +1,2 @@
This document exits to ensure that the required directory structure gets created correctly.

View File

@ -0,0 +1,2 @@
This document exits to ensure that the required directory structure gets created correctly.

View File

@ -0,0 +1,278 @@
#############################################################################
#
# Filename : Makefile
# Content : Makefile for building linux version of: libovr
# Created : 2013
# Authors : Simon Hallam and Peter Giokaris
# Copyright : Copyright 2013 OculusVR, Inc. All Rights Reserved
# Instruction : The g++ compiler and stdndard lib packages need to be
# installed on the system. Navigate in a shell to the
# directory where this Makefile is located and enter:
#
# make builds the release version for the
# current architechture
# make clean delete intermediate release object files
# and the library file
# make DEBUG=1 builds the debug version for the current
# architechture
# make clean DEBUG=1 deletes intermediate debug object files
# and the library file
#
# Output : Relative to the directory this Makefile lives in, libraries
# are built at the following locations depending upon the
# architechture of the system you are running:
#
# ./Lib/Linux/Debug/i386/libovr.a
# ./Lib/Linux/Debug/x86_64/libovr.a
# ./Lib/Linux/Release/i386/libovr.a
# ./Lib/Linux/Release/x86_64/libovr.a
#
#############################################################################
####### Detect system architecture
SYSARCH = i386
ifeq ($(shell uname -m),x86_64)
SYSARCH = x86_64
endif
####### Compiler, tools and options
CXX = g++
LINK = ar rvs
DELETEFILE = rm -f
####### Detect debug or release
DEBUG = 0
ifeq ($(DEBUG), 1)
CXXFLAGS = -pipe -fPIC -DDEBUG -DOVR_BUILD_DEBUG -g
RELEASETYPE = Debug
else
CXXFLAGS = -pipe -fPIC -O2
RELEASETYPE = Release
endif
####### Paths
LIBOVRPATH = .
3RDPARTYPATH = ../3rdParty
INCPATH = -I. -I.. -I$(LIBOVRPATH)/Include -I$(LIBOVRPATH)/Src
OBJPATH = ./Obj/Linux/$(RELEASETYPE)/$(SYSARCH)
CXXBUILD = $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $(OBJPATH)/
####### Files
TARGET = ./Lib/Linux/$(RELEASETYPE)/$(SYSARCH)/libovr.a
OBJECTS = $(OBJPATH)/OVR_CAPI.o \
$(OBJPATH)/CAPI_DistortionRenderer.o \
$(OBJPATH)/CAPI_GL_DistortionRenderer.o \
$(OBJPATH)/CAPI_GL_Util.o \
$(OBJPATH)/CAPI_FrameTimeManager.o \
$(OBJPATH)/CAPI_GlobalState.o \
$(OBJPATH)/CAPI_HMDRenderState.o \
$(OBJPATH)/CAPI_HMDState.o \
$(OBJPATH)/OVR_DeviceHandle.o \
$(OBJPATH)/OVR_DeviceImpl.o \
$(OBJPATH)/OVR_JSON.o \
$(OBJPATH)/OVR_LatencyTestImpl.o \
$(OBJPATH)/OVR_Profile.o \
$(OBJPATH)/OVR_Linux_SensorDevice.o\
$(OBJPATH)/OVR_SensorCalibration.o\
$(OBJPATH)/OVR_SensorFilter.o\
$(OBJPATH)/OVR_SensorFusion.o\
$(OBJPATH)/OVR_SensorImpl.o \
$(OBJPATH)/OVR_Sensor2Impl.o \
$(OBJPATH)/OVR_SensorImpl_Common.o \
$(OBJPATH)/OVR_SensorTimeFilter.o \
$(OBJPATH)/OVR_Stereo.o \
$(OBJPATH)/OVR_ThreadCommandQueue.o \
$(OBJPATH)/OVR_Alg.o \
$(OBJPATH)/OVR_Allocator.o \
$(OBJPATH)/OVR_Atomic.o \
$(OBJPATH)/OVR_File.o \
$(OBJPATH)/OVR_FileFILE.o \
$(OBJPATH)/OVR_Log.o \
$(OBJPATH)/OVR_Math.o \
$(OBJPATH)/OVR_Recording.o \
$(OBJPATH)/OVR_RefCount.o \
$(OBJPATH)/OVR_Std.o \
$(OBJPATH)/OVR_String.o \
$(OBJPATH)/OVR_String_FormatUtil.o \
$(OBJPATH)/OVR_String_PathUtil.o \
$(OBJPATH)/OVR_SysFile.o \
$(OBJPATH)/OVR_System.o \
$(OBJPATH)/OVR_Timer.o \
$(OBJPATH)/OVR_UTF8Util.o \
$(OBJPATH)/Util_LatencyTest.o \
$(OBJPATH)/Util_LatencyTest2.o \
$(OBJPATH)/Util_Render_Stereo.o \
$(OBJPATH)/OVR_ThreadsPthread.o \
$(OBJPATH)/OVR_Linux_HIDDevice.o \
$(OBJPATH)/OVR_Linux_SensorDevice.o \
$(OBJPATH)/OVR_Linux_DeviceManager.o \
$(OBJPATH)/OVR_Linux_HMDDevice.o \
$(OBJPATH)/edid.o
####### Rules
all: $(TARGET)
$(TARGET): $(OBJECTS)
$(LINK) $(TARGET) $(OBJECTS)
$(OBJPATH)/OVR_CAPI.o: $(LIBOVRPATH)/Src/OVR_CAPI.cpp
$(CXXBUILD)OVR_CAPI.o $(LIBOVRPATH)/Src/OVR_CAPI.cpp
$(OBJPATH)/CAPI_DistortionRenderer.o: $(LIBOVRPATH)/Src/CAPI/CAPI_DistortionRenderer.cpp
$(CXXBUILD)CAPI_DistortionRenderer.o $(LIBOVRPATH)/Src/CAPI/CAPI_DistortionRenderer.cpp
$(OBJPATH)/CAPI_GL_DistortionRenderer.o: $(LIBOVRPATH)/Src/CAPI/GL/CAPI_GL_DistortionRenderer.cpp
$(CXXBUILD)CAPI_GL_DistortionRenderer.o $(LIBOVRPATH)/Src/CAPI/GL/CAPI_GL_DistortionRenderer.cpp
$(OBJPATH)/CAPI_GL_Util.o: $(LIBOVRPATH)/Src/CAPI/GL/CAPI_GL_Util.cpp
$(CXXBUILD)CAPI_GL_Util.o $(LIBOVRPATH)/Src/CAPI/GL/CAPI_GL_Util.cpp
$(OBJPATH)/CAPI_FrameTimeManager.o: $(LIBOVRPATH)/Src/CAPI/CAPI_FrameTimeManager.cpp
$(CXXBUILD)CAPI_FrameTimeManager.o $(LIBOVRPATH)/Src/CAPI/CAPI_FrameTimeManager.cpp
$(OBJPATH)/CAPI_GlobalState.o: $(LIBOVRPATH)/Src/CAPI/CAPI_GlobalState.cpp
$(CXXBUILD)CAPI_GlobalState.o $(LIBOVRPATH)/Src/CAPI/CAPI_GlobalState.cpp
$(OBJPATH)/CAPI_HMDRenderState.o: $(LIBOVRPATH)/Src/CAPI/CAPI_HMDRenderState.cpp
$(CXXBUILD)CAPI_HMDRenderState.o $(LIBOVRPATH)/Src/CAPI/CAPI_HMDRenderState.cpp
$(OBJPATH)/CAPI_HMDState.o: $(LIBOVRPATH)/Src/CAPI/CAPI_HMDState.cpp
$(CXXBUILD)CAPI_HMDState.o $(LIBOVRPATH)/Src/CAPI/CAPI_HMDState.cpp
$(OBJPATH)/OVR_DeviceHandle.o: $(LIBOVRPATH)/Src/OVR_DeviceHandle.cpp
$(CXXBUILD)OVR_DeviceHandle.o $(LIBOVRPATH)/Src/OVR_DeviceHandle.cpp
$(OBJPATH)/OVR_DeviceImpl.o: $(LIBOVRPATH)/Src/OVR_DeviceImpl.cpp
$(CXXBUILD)OVR_DeviceImpl.o $(LIBOVRPATH)/Src/OVR_DeviceImpl.cpp
$(OBJPATH)/OVR_JSON.o: $(LIBOVRPATH)/Src/OVR_JSON.cpp
$(CXXBUILD)OVR_JSON.o $(LIBOVRPATH)/Src/OVR_JSON.cpp
$(OBJPATH)/OVR_LatencyTestImpl.o: $(LIBOVRPATH)/Src/OVR_LatencyTestImpl.cpp
$(CXXBUILD)OVR_LatencyTestImpl.o $(LIBOVRPATH)/Src/OVR_LatencyTestImpl.cpp
$(OBJPATH)/OVR_Profile.o: $(LIBOVRPATH)/Src/OVR_Profile.cpp
$(CXXBUILD)OVR_Profile.o $(LIBOVRPATH)/Src/OVR_Profile.cpp
$(OBJPATH)/OVR_SensorDevice.o: $(LIBOVRPATH)/Src/OVR_Linux_SensorDevice.cpp
$(CXXBUILD)OVR_Linux_SensorDevice.o $(LIBOVRPATH)/Src/OVR_Linux_SensorDevice.cpp
$(OBJPATH)/OVR_SensorCalibration.o: $(LIBOVRPATH)/Src/OVR_SensorCalibration.cpp
$(CXXBUILD)OVR_SensorCalibration.o $(LIBOVRPATH)/Src/OVR_SensorCalibration.cpp
$(OBJPATH)/OVR_SensorFilter.o: $(LIBOVRPATH)/Src/OVR_SensorFilter.cpp
$(CXXBUILD)OVR_SensorFilter.o $(LIBOVRPATH)/Src/OVR_SensorFilter.cpp
$(OBJPATH)/OVR_SensorFusion.o: $(LIBOVRPATH)/Src/OVR_SensorFusion.cpp
$(CXXBUILD)OVR_SensorFusion.o $(LIBOVRPATH)/Src/OVR_SensorFusion.cpp
$(OBJPATH)/OVR_SensorImpl.o: $(LIBOVRPATH)/Src/OVR_SensorImpl.cpp
$(CXXBUILD)OVR_SensorImpl.o $(LIBOVRPATH)/Src/OVR_SensorImpl.cpp
$(OBJPATH)/OVR_Sensor2Impl.o: $(LIBOVRPATH)/Src/OVR_Sensor2Impl.cpp
$(CXXBUILD)OVR_Sensor2Impl.o $(LIBOVRPATH)/Src/OVR_Sensor2Impl.cpp
$(OBJPATH)/OVR_SensorImpl_Common.o: $(LIBOVRPATH)/Src/OVR_SensorImpl_Common.cpp
$(CXXBUILD)OVR_SensorImpl_Common.o $(LIBOVRPATH)/Src/OVR_SensorImpl_Common.cpp
$(OBJPATH)/OVR_SensorTimeFilter.o: $(LIBOVRPATH)/Src/OVR_SensorTimeFilter.cpp
$(CXXBUILD)OVR_SensorTimeFilter.o $(LIBOVRPATH)/Src/OVR_SensorTimeFilter.cpp
$(OBJPATH)/OVR_Stereo.o: $(LIBOVRPATH)/Src/OVR_Stereo.cpp
$(CXXBUILD)OVR_Stereo.o $(LIBOVRPATH)/Src/OVR_Stereo.cpp
$(OBJPATH)/OVR_ThreadCommandQueue.o: $(LIBOVRPATH)/Src/OVR_ThreadCommandQueue.cpp
$(CXXBUILD)OVR_ThreadCommandQueue.o $(LIBOVRPATH)/Src/OVR_ThreadCommandQueue.cpp
$(OBJPATH)/OVR_Alg.o: $(LIBOVRPATH)/Src/Kernel/OVR_Alg.cpp
$(CXXBUILD)OVR_Alg.o $(LIBOVRPATH)/Src/Kernel/OVR_Alg.cpp
$(OBJPATH)/OVR_Allocator.o: $(LIBOVRPATH)/Src/Kernel/OVR_Allocator.cpp
$(CXXBUILD)OVR_Allocator.o $(LIBOVRPATH)/Src/Kernel/OVR_Allocator.cpp
$(OBJPATH)/OVR_Atomic.o: $(LIBOVRPATH)/Src/Kernel/OVR_Atomic.cpp
$(CXXBUILD)OVR_Atomic.o $(LIBOVRPATH)/Src/Kernel/OVR_Atomic.cpp
$(OBJPATH)/OVR_File.o: $(LIBOVRPATH)/Src/Kernel/OVR_File.cpp
$(CXXBUILD)OVR_File.o $(LIBOVRPATH)/Src/Kernel/OVR_File.cpp
$(OBJPATH)/OVR_FileFILE.o: $(LIBOVRPATH)/Src/Kernel/OVR_FileFILE.cpp
$(CXXBUILD)OVR_FileFILE.o $(LIBOVRPATH)/Src/Kernel/OVR_FileFILE.cpp
$(OBJPATH)/OVR_Log.o: $(LIBOVRPATH)/Src/Kernel/OVR_Log.cpp
$(CXXBUILD)OVR_Log.o $(LIBOVRPATH)/Src/Kernel/OVR_Log.cpp
$(OBJPATH)/OVR_Math.o: $(LIBOVRPATH)/Src/Kernel/OVR_Math.cpp
$(CXXBUILD)OVR_Math.o $(LIBOVRPATH)/Src/Kernel/OVR_Math.cpp
$(OBJPATH)/OVR_Recording.o: $(LIBOVRPATH)/Src/OVR_Recording.cpp
$(CXXBUILD)OVR_Recording.o $(LIBOVRPATH)/Src/OVR_Recording.cpp
$(OBJPATH)/OVR_RefCount.o: $(LIBOVRPATH)/Src/Kernel/OVR_RefCount.cpp
$(CXXBUILD)OVR_RefCount.o $(LIBOVRPATH)/Src/Kernel/OVR_RefCount.cpp
$(OBJPATH)/OVR_Std.o: $(LIBOVRPATH)/Src/Kernel/OVR_Std.cpp
$(CXXBUILD)OVR_Std.o $(LIBOVRPATH)/Src/Kernel/OVR_Std.cpp
$(OBJPATH)/OVR_String.o: $(LIBOVRPATH)/Src/Kernel/OVR_String.cpp
$(CXXBUILD)OVR_String.o $(LIBOVRPATH)/Src/Kernel/OVR_String.cpp
$(OBJPATH)/OVR_String_FormatUtil.o: $(LIBOVRPATH)/Src/Kernel/OVR_String_FormatUtil.cpp
$(CXXBUILD)OVR_String_FormatUtil.o $(LIBOVRPATH)/Src/Kernel/OVR_String_FormatUtil.cpp
$(OBJPATH)/OVR_String_PathUtil.o: $(LIBOVRPATH)/Src/Kernel/OVR_String_PathUtil.cpp
$(CXXBUILD)OVR_String_PathUtil.o $(LIBOVRPATH)/Src/Kernel/OVR_String_PathUtil.cpp
$(OBJPATH)/OVR_SysFile.o: $(LIBOVRPATH)/Src/Kernel/OVR_SysFile.cpp
$(CXXBUILD)OVR_SysFile.o $(LIBOVRPATH)/Src/Kernel/OVR_SysFile.cpp
$(OBJPATH)/OVR_System.o: $(LIBOVRPATH)/Src/Kernel/OVR_System.cpp
$(CXXBUILD)OVR_System.o $(LIBOVRPATH)/Src/Kernel/OVR_System.cpp
$(OBJPATH)/OVR_Timer.o: $(LIBOVRPATH)/Src/Kernel/OVR_Timer.cpp
$(CXXBUILD)OVR_Timer.o $(LIBOVRPATH)/Src/Kernel/OVR_Timer.cpp
$(OBJPATH)/OVR_UTF8Util.o: $(LIBOVRPATH)/Src/Kernel/OVR_UTF8Util.cpp
$(CXXBUILD)OVR_UTF8Util.o $(LIBOVRPATH)/Src/Kernel/OVR_UTF8Util.cpp
$(OBJPATH)/Util_LatencyTest.o: $(LIBOVRPATH)/Src/Util/Util_LatencyTest.cpp
$(CXXBUILD)Util_LatencyTest.o $(LIBOVRPATH)/Src/Util/Util_LatencyTest.cpp
$(OBJPATH)/Util_LatencyTest2.o: $(LIBOVRPATH)/Src/Util/Util_LatencyTest2.cpp
$(CXXBUILD)Util_LatencyTest2.o $(LIBOVRPATH)/Src/Util/Util_LatencyTest2.cpp
$(OBJPATH)/Util_Render_Stereo.o: $(LIBOVRPATH)/Src/Util/Util_Render_Stereo.cpp
$(CXXBUILD)Util_Render_Stereo.o $(LIBOVRPATH)/Src/Util/Util_Render_Stereo.cpp
$(OBJPATH)/OVR_ThreadsPthread.o: $(LIBOVRPATH)/Src/Kernel/OVR_ThreadsPthread.cpp
$(CXXBUILD)OVR_ThreadsPthread.o $(LIBOVRPATH)/Src/Kernel/OVR_ThreadsPthread.cpp
$(OBJPATH)/OVR_Linux_HIDDevice.o: $(LIBOVRPATH)/Src/OVR_Linux_HIDDevice.cpp
$(CXXBUILD)OVR_Linux_HIDDevice.o $(LIBOVRPATH)/Src/OVR_Linux_HIDDevice.cpp
$(OBJPATH)/OVR_Linux_SensorDevice.o: $(LIBOVRPATH)/Src/OVR_Linux_SensorDevice.cpp
$(CXXBUILD)OVR_Linux_SensorDevice.o $(LIBOVRPATH)/Src/OVR_Linux_SensorDevice.cpp
$(OBJPATH)/OVR_Linux_DeviceManager.o: $(LIBOVRPATH)/Src/OVR_Linux_DeviceManager.cpp
$(CXXBUILD)OVR_Linux_DeviceManager.o $(LIBOVRPATH)/Src/OVR_Linux_DeviceManager.cpp
$(OBJPATH)/OVR_Linux_HMDDevice.o: $(LIBOVRPATH)/Src/OVR_Linux_HMDDevice.cpp
$(CXXBUILD)OVR_Linux_HMDDevice.o $(LIBOVRPATH)/Src/OVR_Linux_HMDDevice.cpp
$(OBJPATH)/tinyxml2.o: $(3RDPARTYPATH)/TinyXml/tinyxml2.cpp
$(CXXBUILD)tinyxml2.o $(3RDPARTYPATH)/TinyXml/tinyxml2.cpp
$(OBJPATH)/edid.o: $(3RDPARTYPATH)/EDID/edid.cpp
$(CXXBUILD)edid.o $(3RDPARTYPATH)/EDID/edid.cpp
clean:
-$(DELETEFILE) $(OBJECTS)
-$(DELETEFILE) $(TARGET)

View File

@ -0,0 +1,2 @@
This document exits to ensure that the required directory structure gets created correctly.

View File

@ -0,0 +1,2 @@
This document exits to ensure that the required directory structure gets created correctly.

View File

@ -0,0 +1,2 @@
This document exits to ensure that the required directory structure gets created correctly.

View File

@ -0,0 +1,2 @@
This document exits to ensure that the required directory structure gets created correctly.

View File

@ -0,0 +1,73 @@
/************************************************************************************
Filename : CAPI_DistortionRenderer.cpp
Content : Combines all of the rendering state associated with the HMD
Created : February 2, 2014
Authors : Michael Antonov
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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 "CAPI_DistortionRenderer.h"
#if defined (OVR_OS_WIN32)
// TBD: Move to separate config file that handles back-ends.
#define OVR_D3D_VERSION 11
#include "D3D1X/CAPI_D3D1X_DistortionRenderer.h"
#undef OVR_D3D_VERSION
#define OVR_D3D_VERSION 10
#include "D3D1X/CAPI_D3D1X_DistortionRenderer.h"
#undef OVR_D3D_VERSION
#define OVR_D3D_VERSION 9
#include "D3D1X/CAPI_D3D9_DistortionRenderer.h"
#undef OVR_D3D_VERSION
#endif
#include "GL/CAPI_GL_DistortionRenderer.h"
namespace OVR { namespace CAPI {
//-------------------------------------------------------------------------------------
// ***** DistortionRenderer
// TBD: Move to separate config file that handles back-ends.
DistortionRenderer::CreateFunc DistortionRenderer::APICreateRegistry[ovrRenderAPI_Count] =
{
0, // None
&GL::DistortionRenderer::Create,
0, // Android_GLES
#if defined (OVR_OS_WIN32)
&D3D9::DistortionRenderer::Create,
&D3D10::DistortionRenderer::Create,
&D3D11::DistortionRenderer::Create
#else
0,
0,
0
#endif
};
}} // namespace OVR::CAPI

View File

@ -0,0 +1,118 @@
/************************************************************************************
Filename : CAPI_DistortionRenderer.h
Content : Abstract interface for platform-specific rendering of distortion
Created : February 2, 2014
Authors : Michael Antonov
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_CAPI_DistortionRenderer_h
#define OVR_CAPI_DistortionRenderer_h
#include "CAPI_HMDRenderState.h"
#include "CAPI_FrameTimeManager.h"
namespace OVR { namespace CAPI {
//-------------------------------------------------------------------------------------
// ***** CAPI::DistortionRenderer
// DistortionRenderer implements rendering of distortion and other overlay elements
// in platform-independent way.
// Platform-specific renderer back ends for CAPI are derived from this class.
class DistortionRenderer : public RefCountBase<DistortionRenderer>
{
// Quiet assignment compiler warning.
void operator = (const DistortionRenderer&) { }
public:
DistortionRenderer(ovrRenderAPIType api, ovrHmd hmd,
FrameTimeManager& timeManager,
const HMDRenderState& renderState)
: RenderAPI(api), HMD(hmd), TimeManager(timeManager), RState(renderState)
{ }
virtual ~DistortionRenderer()
{ }
// Configures the Renderer based on externally passed API settings. Must be
// called before use.
// Under D3D, apiConfig includes D3D Device pointer, back buffer and other
// needed structures.
virtual bool Initialize(const ovrRenderAPIConfig* apiConfig,
unsigned distortionCaps) = 0;
// Submits one eye texture for rendering. This is in the separate method to
// allow "submit as you render" scenarios on horizontal screens where one
// eye can be scanned out before the other.
virtual void SubmitEye(int eyeId, ovrTexture* eyeTexture) = 0;
// Finish the frame, optionally swapping buffers.
// Many implementations may actually apply the distortion here.
virtual void EndFrame(bool swapBuffers, unsigned char* latencyTesterDrawColor,
unsigned char* latencyTester2DrawColor) = 0;
// Stores the current graphics pipeline state so it can be restored later.
void SaveGraphicsState() { if (!(RState.EnabledHmdCaps & ovrHmdCap_NoRestore)) GfxState->Save(); }
// Restores the saved graphics pipeline state.
void RestoreGraphicsState() { if (!(RState.EnabledHmdCaps & ovrHmdCap_NoRestore)) GfxState->Restore(); }
// *** Creation Factory logic
ovrRenderAPIType GetRenderAPI() const { return RenderAPI; }
// Creation function for this interface, registered for API.
typedef DistortionRenderer* (*CreateFunc)(ovrHmd hmd,
FrameTimeManager &timeManager,
const HMDRenderState& renderState);
static CreateFunc APICreateRegistry[ovrRenderAPI_Count];
protected:
class GraphicsState : public RefCountBase<GraphicsState>
{
public:
GraphicsState() : IsValid(false) {}
virtual ~GraphicsState() {}
virtual void Save() = 0;
virtual void Restore() = 0;
protected:
bool IsValid;
};
const ovrRenderAPIType RenderAPI;
const ovrHmd HMD;
FrameTimeManager& TimeManager;
const HMDRenderState& RState;
Ptr<GraphicsState> GfxState;
};
}} // namespace OVR::CAPI
#endif // OVR_CAPI_DistortionRenderer_h

View File

@ -0,0 +1,675 @@
/************************************************************************************
Filename : CAPI_FrameTimeManager.cpp
Content : Manage frame timing and pose prediction for rendering
Created : November 30, 2013
Authors : Volga Aksoy, Michael Antonov
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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 "CAPI_FrameTimeManager.h"
namespace OVR { namespace CAPI {
//-------------------------------------------------------------------------------------
// ***** FrameLatencyTracker
FrameLatencyTracker::FrameLatencyTracker()
{
Reset();
}
void FrameLatencyTracker::Reset()
{
TrackerEnabled = true;
WaitMode = SampleWait_Zeroes;
FrameIndex = 0;
MatchCount = 0;
RenderLatencySeconds = 0.0;
TimewarpLatencySeconds = 0.0;
FrameDeltas.Clear();
}
unsigned char FrameLatencyTracker::GetNextDrawColor()
{
if (!TrackerEnabled || (WaitMode == SampleWait_Zeroes) ||
(FrameIndex >= FramesTracked))
{
return (unsigned char)Util::FrameTimeRecord::ReadbackIndexToColor(0);
}
OVR_ASSERT(FrameIndex < FramesTracked);
return (unsigned char)Util::FrameTimeRecord::ReadbackIndexToColor(FrameIndex+1);
}
void FrameLatencyTracker::SaveDrawColor(unsigned char drawColor, double endFrameTime,
double renderIMUTime, double timewarpIMUTime )
{
if (!TrackerEnabled || (WaitMode == SampleWait_Zeroes))
return;
if (FrameIndex < FramesTracked)
{
OVR_ASSERT(Util::FrameTimeRecord::ReadbackIndexToColor(FrameIndex+1) == drawColor);
OVR_UNUSED(drawColor);
// saves {color, endFrame time}
FrameEndTimes[FrameIndex].ReadbackIndex = FrameIndex + 1;
FrameEndTimes[FrameIndex].TimeSeconds = endFrameTime;
FrameEndTimes[FrameIndex].RenderIMUTimeSeconds = renderIMUTime;
FrameEndTimes[FrameIndex].TimewarpIMUTimeSeconds= timewarpIMUTime;
FrameEndTimes[FrameIndex].MatchedRecord = false;
FrameIndex++;
}
else
{
// If the request was outstanding for too long, switch to zero mode to restart.
if (endFrameTime > (FrameEndTimes[FrameIndex-1].TimeSeconds + 0.15))
{
if (MatchCount == 0)
{
// If nothing was matched, we have no latency reading.
RenderLatencySeconds = 0.0;
TimewarpLatencySeconds = 0.0;
}
WaitMode = SampleWait_Zeroes;
MatchCount = 0;
FrameIndex = 0;
}
}
}
void FrameLatencyTracker::MatchRecord(const Util::FrameTimeRecordSet &r)
{
if (!TrackerEnabled)
return;
if (WaitMode == SampleWait_Zeroes)
{
// Do we have all zeros?
if (r.IsAllZeroes())
{
OVR_ASSERT(FrameIndex == 0);
WaitMode = SampleWait_Match;
MatchCount = 0;
}
return;
}
// We are in Match Mode. Wait until all colors are matched or timeout,
// at which point we go back to zeros.
for (int i = 0; i < FrameIndex; i++)
{
int recordIndex = 0;
int consecutiveMatch = 0;
OVR_ASSERT(FrameEndTimes[i].ReadbackIndex != 0);
if (r.FindReadbackIndex(&recordIndex, FrameEndTimes[i].ReadbackIndex))
{
// Advance forward to see that we have several more matches.
int ri = recordIndex + 1;
int j = i + 1;
consecutiveMatch++;
for (; (j < FrameIndex) && (ri < Util::FrameTimeRecordSet::RecordCount); j++, ri++)
{
if (r[ri].ReadbackIndex != FrameEndTimes[j].ReadbackIndex)
break;
consecutiveMatch++;
}
// Match at least 2 items in the row, to avoid accidentally matching color.
if (consecutiveMatch > 1)
{
// Record latency values for all but last samples. Keep last 2 samples
// for the future to simplify matching.
for (int q = 0; q < consecutiveMatch; q++)
{
const Util::FrameTimeRecord &scanoutFrame = r[recordIndex+q];
FrameTimeRecordEx &renderFrame = FrameEndTimes[i+q];
if (!renderFrame.MatchedRecord)
{
double deltaSeconds = scanoutFrame.TimeSeconds - renderFrame.TimeSeconds;
if (deltaSeconds > 0.0)
{
FrameDeltas.AddTimeDelta(deltaSeconds);
LatencyRecordTime = scanoutFrame.TimeSeconds;
RenderLatencySeconds = scanoutFrame.TimeSeconds - renderFrame.RenderIMUTimeSeconds;
TimewarpLatencySeconds = (renderFrame.TimewarpIMUTimeSeconds == 0.0) ? 0.0 :
(scanoutFrame.TimeSeconds - renderFrame.TimewarpIMUTimeSeconds);
}
renderFrame.MatchedRecord = true;
MatchCount++;
}
}
// Exit for.
break;
}
}
} // for ( i => FrameIndex )
// If we matched all frames, start over.
if (MatchCount == FramesTracked)
{
WaitMode = SampleWait_Zeroes;
MatchCount = 0;
FrameIndex = 0;
}
}
void FrameLatencyTracker::GetLatencyTimings(float latencies[3])
{
if (ovr_GetTimeInSeconds() > (LatencyRecordTime + 2.0))
{
latencies[0] = 0.0f;
latencies[1] = 0.0f;
latencies[2] = 0.0f;
}
else
{
latencies[0] = (float)RenderLatencySeconds;
latencies[1] = (float)TimewarpLatencySeconds;
latencies[2] = (float)FrameDeltas.GetMedianTimeDelta();
}
}
//-------------------------------------------------------------------------------------
FrameTimeManager::FrameTimeManager(bool vsyncEnabled)
: VsyncEnabled(vsyncEnabled), DynamicPrediction(true), SdkRender(false),
FrameTiming()
{
RenderIMUTimeSeconds = 0.0;
TimewarpIMUTimeSeconds = 0.0;
// HACK: SyncToScanoutDelay observed close to 1 frame in video cards.
// Overwritten by dynamic latency measurement on DK2.
VSyncToScanoutDelay = 0.013f;
NoVSyncToScanoutDelay = 0.004f;
}
void FrameTimeManager::Init(HmdRenderInfo& renderInfo)
{
// Set up prediction distances.
// With-Vsync timings.
RenderInfo = renderInfo;
ScreenSwitchingDelay = RenderInfo.Shutter.PixelSettleTime * 0.5f +
RenderInfo.Shutter.PixelPersistence * 0.5f;
}
void FrameTimeManager::ResetFrameTiming(unsigned frameIndex,
bool dynamicPrediction,
bool sdkRender)
{
DynamicPrediction = dynamicPrediction;
SdkRender = sdkRender;
FrameTimeDeltas.Clear();
DistortionRenderTimes.Clear();
ScreenLatencyTracker.Reset();
FrameTiming.FrameIndex = frameIndex;
FrameTiming.NextFrameTime = 0.0;
FrameTiming.ThisFrameTime = 0.0;
FrameTiming.Inputs.FrameDelta = calcFrameDelta();
FrameTiming.Inputs.ScreenDelay = calcScreenDelay();
FrameTiming.Inputs.TimewarpWaitDelta = 0.0f;
LocklessTiming.SetState(FrameTiming);
}
double FrameTimeManager::calcFrameDelta() const
{
// Timing difference between frame is tracked by FrameTimeDeltas, or
// is a hard-coded value of 1/FrameRate.
double frameDelta;
if (!VsyncEnabled)
{
frameDelta = 0.0;
}
else if (FrameTimeDeltas.GetCount() > 3)
{
frameDelta = FrameTimeDeltas.GetMedianTimeDelta();
if (frameDelta > (RenderInfo.Shutter.VsyncToNextVsync + 0.001))
frameDelta = RenderInfo.Shutter.VsyncToNextVsync;
}
else
{
frameDelta = RenderInfo.Shutter.VsyncToNextVsync;
}
return frameDelta;
}
double FrameTimeManager::calcScreenDelay() const
{
double screenDelay = ScreenSwitchingDelay;
double measuredVSyncToScanout;
// Use real-time DK2 latency tester HW for prediction if its is working.
// Do sanity check under 60 ms
if (!VsyncEnabled)
{
screenDelay += NoVSyncToScanoutDelay;
}
else if ( DynamicPrediction &&
(ScreenLatencyTracker.FrameDeltas.GetCount() > 3) &&
(measuredVSyncToScanout = ScreenLatencyTracker.FrameDeltas.GetMedianTimeDelta(),
(measuredVSyncToScanout > 0.0001) && (measuredVSyncToScanout < 0.06)) )
{
screenDelay += measuredVSyncToScanout;
}
else
{
screenDelay += VSyncToScanoutDelay;
}
return screenDelay;
}
double FrameTimeManager::calcTimewarpWaitDelta() const
{
// If timewarp timing hasn't been calculated, we should wait.
if (!VsyncEnabled)
return 0.0;
if (SdkRender)
{
if (NeedDistortionTimeMeasurement())
return 0.0;
return -(DistortionRenderTimes.GetMedianTimeDelta() + 0.002);
}
// Just a hard-coded "high" value for game-drawn code.
// TBD: Just return 0 and let users calculate this themselves?
return -0.003;
}
void FrameTimeManager::Timing::InitTimingFromInputs(const FrameTimeManager::TimingInputs& inputs,
HmdShutterTypeEnum shutterType,
double thisFrameTime, unsigned int frameIndex)
{
// ThisFrameTime comes from the end of last frame, unless it it changed.
double nextFrameBase;
double frameDelta = inputs.FrameDelta;
FrameIndex = frameIndex;
ThisFrameTime = thisFrameTime;
NextFrameTime = ThisFrameTime + frameDelta;
nextFrameBase = NextFrameTime + inputs.ScreenDelay;
MidpointTime = nextFrameBase + frameDelta * 0.5;
TimewarpPointTime = (inputs.TimewarpWaitDelta == 0.0) ?
0.0 : (NextFrameTime + inputs.TimewarpWaitDelta);
// Calculate absolute points in time when eye rendering or corresponding time-warp
// screen edges will become visible.
// This only matters with VSync.
switch(shutterType)
{
case HmdShutter_RollingTopToBottom:
EyeRenderTimes[0] = MidpointTime;
EyeRenderTimes[1] = MidpointTime;
TimeWarpStartEndTimes[0][0] = nextFrameBase;
TimeWarpStartEndTimes[0][1] = nextFrameBase + frameDelta;
TimeWarpStartEndTimes[1][0] = nextFrameBase;
TimeWarpStartEndTimes[1][1] = nextFrameBase + frameDelta;
break;
case HmdShutter_RollingLeftToRight:
EyeRenderTimes[0] = nextFrameBase + frameDelta * 0.25;
EyeRenderTimes[1] = nextFrameBase + frameDelta * 0.75;
/*
// TBD: MA: It is probably better if mesh sets it up per-eye.
// Would apply if screen is 0 -> 1 for each eye mesh
TimeWarpStartEndTimes[0][0] = nextFrameBase;
TimeWarpStartEndTimes[0][1] = MidpointTime;
TimeWarpStartEndTimes[1][0] = MidpointTime;
TimeWarpStartEndTimes[1][1] = nextFrameBase + frameDelta;
*/
// Mesh is set up to vary from Edge of scree 0 -> 1 across both eyes
TimeWarpStartEndTimes[0][0] = nextFrameBase;
TimeWarpStartEndTimes[0][1] = nextFrameBase + frameDelta;
TimeWarpStartEndTimes[1][0] = nextFrameBase;
TimeWarpStartEndTimes[1][1] = nextFrameBase + frameDelta;
break;
case HmdShutter_RollingRightToLeft:
EyeRenderTimes[0] = nextFrameBase + frameDelta * 0.75;
EyeRenderTimes[1] = nextFrameBase + frameDelta * 0.25;
// This is *Correct* with Tom's distortion mesh organization.
TimeWarpStartEndTimes[0][0] = nextFrameBase ;
TimeWarpStartEndTimes[0][1] = nextFrameBase + frameDelta;
TimeWarpStartEndTimes[1][0] = nextFrameBase ;
TimeWarpStartEndTimes[1][1] = nextFrameBase + frameDelta;
break;
case HmdShutter_Global:
// TBD
EyeRenderTimes[0] = MidpointTime;
EyeRenderTimes[1] = MidpointTime;
TimeWarpStartEndTimes[0][0] = MidpointTime;
TimeWarpStartEndTimes[0][1] = MidpointTime;
TimeWarpStartEndTimes[1][0] = MidpointTime;
TimeWarpStartEndTimes[1][1] = MidpointTime;
break;
default:
break;
}
}
double FrameTimeManager::BeginFrame(unsigned frameIndex)
{
RenderIMUTimeSeconds = 0.0;
TimewarpIMUTimeSeconds = 0.0;
// ThisFrameTime comes from the end of last frame, unless it it changed.
double thisFrameTime = (FrameTiming.NextFrameTime != 0.0) ?
FrameTiming.NextFrameTime : ovr_GetTimeInSeconds();
// We are starting to process a new frame...
FrameTiming.InitTimingFromInputs(FrameTiming.Inputs, RenderInfo.Shutter.Type,
thisFrameTime, frameIndex);
return FrameTiming.ThisFrameTime;
}
void FrameTimeManager::EndFrame()
{
// Record timing since last frame; must be called after Present & sync.
FrameTiming.NextFrameTime = ovr_GetTimeInSeconds();
if (FrameTiming.ThisFrameTime > 0.0)
{
FrameTimeDeltas.AddTimeDelta(FrameTiming.NextFrameTime - FrameTiming.ThisFrameTime);
FrameTiming.Inputs.FrameDelta = calcFrameDelta();
}
// Write to Lock-less
LocklessTiming.SetState(FrameTiming);
}
// Thread-safe function to query timing for a future frame
FrameTimeManager::Timing FrameTimeManager::GetFrameTiming(unsigned frameIndex)
{
Timing frameTiming = LocklessTiming.GetState();
if (frameTiming.ThisFrameTime != 0.0)
{
// If timing hasn't been initialized, starting based on "now" is the best guess.
frameTiming.InitTimingFromInputs(frameTiming.Inputs, RenderInfo.Shutter.Type,
ovr_GetTimeInSeconds(), frameIndex);
}
else if (frameIndex > frameTiming.FrameIndex)
{
unsigned frameDelta = frameIndex - frameTiming.FrameIndex;
double thisFrameTime = frameTiming.NextFrameTime +
double(frameDelta-1) * frameTiming.Inputs.FrameDelta;
// Don't run away too far into the future beyond rendering.
OVR_ASSERT(frameDelta < 6);
frameTiming.InitTimingFromInputs(frameTiming.Inputs, RenderInfo.Shutter.Type,
thisFrameTime, frameIndex);
}
return frameTiming;
}
double FrameTimeManager::GetEyePredictionTime(ovrEyeType eye)
{
if (VsyncEnabled)
{
return FrameTiming.EyeRenderTimes[eye];
}
// No VSync: Best guess for the near future
return ovr_GetTimeInSeconds() + ScreenSwitchingDelay + NoVSyncToScanoutDelay;
}
Transformf FrameTimeManager::GetEyePredictionPose(ovrHmd hmd, ovrEyeType eye)
{
double eyeRenderTime = GetEyePredictionTime(eye);
ovrSensorState eyeState = ovrHmd_GetSensorState(hmd, eyeRenderTime);
// EyeRenderPoses[eye] = eyeState.Predicted.Pose;
// Record view pose sampling time for Latency reporting.
if (RenderIMUTimeSeconds == 0.0)
RenderIMUTimeSeconds = eyeState.Recorded.TimeInSeconds;
return eyeState.Predicted.Pose;
}
void FrameTimeManager::GetTimewarpPredictions(ovrEyeType eye, double timewarpStartEnd[2])
{
if (VsyncEnabled)
{
timewarpStartEnd[0] = FrameTiming.TimeWarpStartEndTimes[eye][0];
timewarpStartEnd[1] = FrameTiming.TimeWarpStartEndTimes[eye][1];
return;
}
// Free-running, so this will be displayed immediately.
// Unfortunately we have no idea which bit of the screen is actually going to be displayed.
// TODO: guess which bit of the screen is being displayed!
// (e.g. use DONOTWAIT on present and see when the return isn't WASSTILLWAITING?)
// We have no idea where scan-out is currently, so we can't usefully warp the screen spatially.
timewarpStartEnd[0] = ovr_GetTimeInSeconds() + ScreenSwitchingDelay + NoVSyncToScanoutDelay;
timewarpStartEnd[1] = timewarpStartEnd[0];
}
void FrameTimeManager::GetTimewarpMatrices(ovrHmd hmd, ovrEyeType eyeId,
ovrPosef renderPose, ovrMatrix4f twmOut[2])
{
if (!hmd)
{
return;
}
double timewarpStartEnd[2] = { 0.0, 0.0 };
GetTimewarpPredictions(eyeId, timewarpStartEnd);
ovrSensorState startState = ovrHmd_GetSensorState(hmd, timewarpStartEnd[0]);
ovrSensorState endState = ovrHmd_GetSensorState(hmd, timewarpStartEnd[1]);
if (TimewarpIMUTimeSeconds == 0.0)
TimewarpIMUTimeSeconds = startState.Recorded.TimeInSeconds;
Quatf quatFromStart = startState.Predicted.Pose.Orientation;
Quatf quatFromEnd = endState.Predicted.Pose.Orientation;
Quatf quatFromEye = renderPose.Orientation; //EyeRenderPoses[eyeId].Orientation;
quatFromEye.Invert();
Quatf timewarpStartQuat = quatFromEye * quatFromStart;
Quatf timewarpEndQuat = quatFromEye * quatFromEnd;
Matrix4f timewarpStart(timewarpStartQuat);
Matrix4f timewarpEnd(timewarpEndQuat);
// The real-world orientations have: X=right, Y=up, Z=backwards.
// The vectors inside the mesh are in NDC to keep the shader simple: X=right, Y=down, Z=forwards.
// So we need to perform a similarity transform on this delta matrix.
// The verbose code would look like this:
/*
Matrix4f matBasisChange;
matBasisChange.SetIdentity();
matBasisChange.M[0][0] = 1.0f;
matBasisChange.M[1][1] = -1.0f;
matBasisChange.M[2][2] = -1.0f;
Matrix4f matBasisChangeInv = matBasisChange.Inverted();
matRenderFromNow = matBasisChangeInv * matRenderFromNow * matBasisChange;
*/
// ...but of course all the above is a constant transform and much more easily done.
// We flip the signs of the Y&Z row, then flip the signs of the Y&Z column,
// and of course most of the flips cancel:
// +++ +-- +--
// +++ -> flip Y&Z columns -> +-- -> flip Y&Z rows -> -++
// +++ +-- -++
timewarpStart.M[0][1] = -timewarpStart.M[0][1];
timewarpStart.M[0][2] = -timewarpStart.M[0][2];
timewarpStart.M[1][0] = -timewarpStart.M[1][0];
timewarpStart.M[2][0] = -timewarpStart.M[2][0];
timewarpEnd .M[0][1] = -timewarpEnd .M[0][1];
timewarpEnd .M[0][2] = -timewarpEnd .M[0][2];
timewarpEnd .M[1][0] = -timewarpEnd .M[1][0];
timewarpEnd .M[2][0] = -timewarpEnd .M[2][0];
twmOut[0] = timewarpStart;
twmOut[1] = timewarpEnd;
}
// Used by renderer to determine if it should time distortion rendering.
bool FrameTimeManager::NeedDistortionTimeMeasurement() const
{
if (!VsyncEnabled)
return false;
return DistortionRenderTimes.GetCount() < 10;
}
void FrameTimeManager::AddDistortionTimeMeasurement(double distortionTimeSeconds)
{
DistortionRenderTimes.AddTimeDelta(distortionTimeSeconds);
// If timewarp timing changes based on this sample, update it.
double newTimewarpWaitDelta = calcTimewarpWaitDelta();
if (newTimewarpWaitDelta != FrameTiming.Inputs.TimewarpWaitDelta)
{
FrameTiming.Inputs.TimewarpWaitDelta = newTimewarpWaitDelta;
LocklessTiming.SetState(FrameTiming);
}
}
void FrameTimeManager::UpdateFrameLatencyTrackingAfterEndFrame(
unsigned char frameLatencyTestColor,
const Util::FrameTimeRecordSet& rs)
{
// FrameTiming.NextFrameTime in this context (after EndFrame) is the end frame time.
ScreenLatencyTracker.SaveDrawColor(frameLatencyTestColor,
FrameTiming.NextFrameTime,
RenderIMUTimeSeconds,
TimewarpIMUTimeSeconds);
ScreenLatencyTracker.MatchRecord(rs);
// If screen delay changed, update timing.
double newScreenDelay = calcScreenDelay();
if (newScreenDelay != FrameTiming.Inputs.ScreenDelay)
{
FrameTiming.Inputs.ScreenDelay = newScreenDelay;
LocklessTiming.SetState(FrameTiming);
}
}
//-----------------------------------------------------------------------------------
// ***** TimeDeltaCollector
void TimeDeltaCollector::AddTimeDelta(double timeSeconds)
{
// avoid adding invalid timing values
if(timeSeconds < 0.0f)
return;
if (Count == Capacity)
{
for(int i=0; i< Count-1; i++)
TimeBufferSeconds[i] = TimeBufferSeconds[i+1];
Count--;
}
TimeBufferSeconds[Count++] = timeSeconds;
}
double TimeDeltaCollector::GetMedianTimeDelta() const
{
double SortedList[Capacity];
bool used[Capacity];
memset(used, 0, sizeof(used));
SortedList[0] = 0.0; // In case Count was 0...
// Probably the slowest way to find median...
for (int i=0; i<Count; i++)
{
double smallestDelta = 1000000.0;
int index = 0;
for (int j = 0; j < Count; j++)
{
if (!used[j])
{
if (TimeBufferSeconds[j] < smallestDelta)
{
smallestDelta = TimeBufferSeconds[j];
index = j;
}
}
}
// Mark as used
used[index] = true;
SortedList[i] = smallestDelta;
}
return SortedList[Count/2];
}
}} // namespace OVR::CAPI

View File

@ -0,0 +1,264 @@
/************************************************************************************
Filename : CAPI_FrameTimeManager.h
Content : Manage frame timing and pose prediction for rendering
Created : November 30, 2013
Authors : Volga Aksoy, Michael Antonov
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_CAPI_FrameTimeManager_h
#define OVR_CAPI_FrameTimeManager_h
#include "../OVR_CAPI.h"
#include "../Kernel/OVR_Timer.h"
#include "../Kernel/OVR_Math.h"
#include "../Util/Util_Render_Stereo.h"
#include "../Util/Util_LatencyTest2.h"
namespace OVR { namespace CAPI {
//-------------------------------------------------------------------------------------
// Helper class to collect median times between frames, so that we know
// how long to wait.
struct TimeDeltaCollector
{
TimeDeltaCollector() : Count(0) { }
void AddTimeDelta(double timeSeconds);
void Clear() { Count = 0; }
double GetMedianTimeDelta() const;
double GetCount() const { return Count; }
enum { Capacity = 12 };
private:
int Count;
double TimeBufferSeconds[Capacity];
};
//-------------------------------------------------------------------------------------
// ***** FrameLatencyTracker
// FrameLatencyTracker tracks frame Present to display Scan-out timing, as reported by
// the DK2 internal latency tester pixel read-back. The computed value is used in
// FrameTimeManager for prediction. View Render and TimeWarp to scan-out latencies are
// also reported for debugging.
//
// The class operates by generating color values from GetNextDrawColor() that must
// be rendered on the back end and then looking for matching values in FrameTimeRecordSet
// structure as reported by HW.
class FrameLatencyTracker
{
public:
enum { FramesTracked = Util::LT2_IncrementCount-1 };
FrameLatencyTracker();
// DrawColor == 0 is special in that it doesn't need saving of timestamp
unsigned char GetNextDrawColor();
void SaveDrawColor(unsigned char drawColor, double endFrameTime,
double renderIMUTime, double timewarpIMUTime );
void MatchRecord(const Util::FrameTimeRecordSet &r);
void GetLatencyTimings(float latencies[3]);
void Reset();
public:
struct FrameTimeRecordEx : public Util::FrameTimeRecord
{
bool MatchedRecord;
double RenderIMUTimeSeconds;
double TimewarpIMUTimeSeconds;
};
// True if rendering read-back is enabled.
bool TrackerEnabled;
enum SampleWaitType {
SampleWait_Zeroes, // We are waiting for a record with all zeros.
SampleWait_Match // We are issuing & matching colors.
};
SampleWaitType WaitMode;
int MatchCount;
// Records of frame timings that we are trying to measure.
FrameTimeRecordEx FrameEndTimes[FramesTracked];
int FrameIndex;
// Median filter for (ScanoutTimeSeconds - PostPresent frame time)
TimeDeltaCollector FrameDeltas;
// Latency reporting results
double RenderLatencySeconds;
double TimewarpLatencySeconds;
double LatencyRecordTime;
};
//-------------------------------------------------------------------------------------
// ***** FrameTimeManager
// FrameTimeManager keeps track of rendered frame timing and handles predictions for
// orientations and time-warp.
class FrameTimeManager
{
public:
FrameTimeManager(bool vsyncEnabled = true);
// Data that affects frame timing computation.
struct TimingInputs
{
// Hard-coded value or dynamic as reported by FrameTimeDeltas.GetMedianTimeDelta().
double FrameDelta;
// Screen delay from present to scan-out, as potentially reported by ScreenLatencyTracker.
double ScreenDelay;
// Negative value of how many seconds before EndFrame we start timewarp. 0.0 if not used.
double TimewarpWaitDelta;
TimingInputs()
: FrameDelta(0), ScreenDelay(0), TimewarpWaitDelta(0)
{ }
};
// Timing values for a specific frame.
struct Timing
{
TimingInputs Inputs;
// Index of a frame that started at ThisFrameTime.
unsigned int FrameIndex;
// Predicted absolute times for when this frame will show up on screen.
// Generally, all values will be >= NextFrameTime, since that's the time we expect next
// vsync to succeed.
double ThisFrameTime;
double TimewarpPointTime;
double NextFrameTime;
double MidpointTime;
double EyeRenderTimes[2];
double TimeWarpStartEndTimes[2][2];
Timing()
{
memset(this, 0, sizeof(Timing));
}
void InitTimingFromInputs(const TimingInputs& inputs, HmdShutterTypeEnum shutterType,
double thisFrameTime, unsigned int frameIndex);
};
// Called on startup to provided data on HMD timing.
void Init(HmdRenderInfo& renderInfo);
// Called with each new ConfigureRendering.
void ResetFrameTiming(unsigned frameIndex,
bool dynamicPrediction, bool sdkRender);
void SetVsync(bool enabled) { VsyncEnabled = enabled; }
// BeginFrame returns time of the call
// TBD: Should this be a predicted time value instead ?
double BeginFrame(unsigned frameIndex);
void EndFrame();
// Thread-safe function to query timing for a future frame
Timing GetFrameTiming(unsigned frameIndex);
double GetEyePredictionTime(ovrEyeType eye);
Transformf GetEyePredictionPose(ovrHmd hmd, ovrEyeType eye);
void GetTimewarpPredictions(ovrEyeType eye, double timewarpStartEnd[2]);
void GetTimewarpMatrices(ovrHmd hmd, ovrEyeType eye, ovrPosef renderPose, ovrMatrix4f twmOut[2]);
// Used by renderer to determine if it should time distortion rendering.
bool NeedDistortionTimeMeasurement() const;
void AddDistortionTimeMeasurement(double distortionTimeSeconds);
// DK2 Lateny test interface
// Get next draw color for DK2 latency tester
unsigned char GetFrameLatencyTestDrawColor()
{ return ScreenLatencyTracker.GetNextDrawColor(); }
// Must be called after EndFrame() to update latency tester timings.
// Must pass color reported by NextFrameColor for this frame.
void UpdateFrameLatencyTrackingAfterEndFrame(unsigned char frameLatencyTestColor,
const Util::FrameTimeRecordSet& rs);
void GetLatencyTimings(float latencies[3])
{ return ScreenLatencyTracker.GetLatencyTimings(latencies); }
const Timing& GetFrameTiming() const { return FrameTiming; }
private:
double calcFrameDelta() const;
double calcScreenDelay() const;
double calcTimewarpWaitDelta() const;
HmdRenderInfo RenderInfo;
// Timings are collected through a median filter, to avoid outliers.
TimeDeltaCollector FrameTimeDeltas;
TimeDeltaCollector DistortionRenderTimes;
FrameLatencyTracker ScreenLatencyTracker;
// Timing changes if we have no Vsync (all prediction is reduced to fixed interval).
bool VsyncEnabled;
// Set if we are rendering via the SDK, so DistortionRenderTimes is valid.
bool DynamicPrediction;
// Set if SDk is doing teh rendering.
bool SdkRender;
// Total frame delay due to VsyncToFirstScanline, persistence and settle time.
// Computed from RenderInfor.Shutter.
double VSyncToScanoutDelay;
double NoVSyncToScanoutDelay;
double ScreenSwitchingDelay;
// Current (or last) frame timing info. Used as a source for LocklessTiming.
Timing FrameTiming;
// TBD: Don't we need NextFrame here as well?
LocklessUpdater<Timing> LocklessTiming;
// IMU Read timings
double RenderIMUTimeSeconds;
double TimewarpIMUTimeSeconds;
};
}} // namespace OVR::CAPI
#endif // OVR_CAPI_FrameTimeManager_h

View File

@ -0,0 +1,142 @@
/************************************************************************************
Filename : CAPI_GlobalState.cpp
Content : Maintains global state of the CAPI
Created : January 24, 2014
Authors : Michael Antonov
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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 "CAPI_GlobalState.h"
namespace OVR { namespace CAPI {
//-------------------------------------------------------------------------------------
// Open Questions / Notes
// 2. Detect HMDs.
// Challenge: If we do everything through polling, it would imply we want all the devices
// initialized. However, there may be multiple rifts, extra sensors, etc,
// which shouldn't be allocated.
//
// How do you reset orientation Quaternion?
// Can you change IPD?
//-------------------------------------------------------------------------------------
// ***** OVRGlobalState
// Global instance
GlobalState* GlobalState::pInstance = 0;
GlobalState::GlobalState()
{
pManager = *DeviceManager::Create();
// Handle the DeviceManager's messages
pManager->AddMessageHandler( this );
EnumerateDevices();
// PhoneSensors::Init();
}
GlobalState::~GlobalState()
{
RemoveHandlerFromDevices();
OVR_ASSERT(HMDs.IsEmpty());
}
int GlobalState::EnumerateDevices()
{
// Need to use separate lock for device enumeration, as pManager->GetHandlerLock()
// would produce deadlocks here.
Lock::Locker lock(&EnumerationLock);
EnumeratedDevices.Clear();
DeviceEnumerator<HMDDevice> e = pManager->EnumerateDevices<HMDDevice>();
while(e.IsAvailable())
{
EnumeratedDevices.PushBack(DeviceHandle(e));
e.Next();
}
return (int)EnumeratedDevices.GetSize();
}
HMDDevice* GlobalState::CreateDevice(int index)
{
Lock::Locker lock(&EnumerationLock);
if (index >= (int)EnumeratedDevices.GetSize())
return 0;
return EnumeratedDevices[index].CreateDeviceTyped<HMDDevice>();
}
void GlobalState::AddHMD(HMDState* hmd)
{
Lock::Locker lock(pManager->GetHandlerLock());
HMDs.PushBack(hmd);
}
void GlobalState::RemoveHMD(HMDState* hmd)
{
Lock::Locker lock(pManager->GetHandlerLock());
hmd->RemoveNode();
}
void GlobalState::NotifyHMDs_AddDevice(DeviceType deviceType)
{
Lock::Locker lock(pManager->GetHandlerLock());
for(HMDState* hmd = HMDs.GetFirst(); !HMDs.IsNull(hmd); hmd = hmd->pNext)
hmd->NotifyAddDevice(deviceType);
}
void GlobalState::OnMessage(const Message& msg)
{
if (msg.Type == Message_DeviceAdded || msg.Type == Message_DeviceRemoved)
{
if (msg.pDevice == pManager)
{
const MessageDeviceStatus& statusMsg =
static_cast<const MessageDeviceStatus&>(msg);
if (msg.Type == Message_DeviceAdded)
{
//LogText("OnMessage DeviceAdded.\n");
// We may have added a sensor/other device; notify any HMDs that might
// need it to check for it later.
NotifyHMDs_AddDevice(statusMsg.Handle.GetType());
}
else
{
//LogText("OnMessage DeviceRemoved.\n");
}
}
}
}
}} // namespace OVR::CAPI

View File

@ -0,0 +1,84 @@
/************************************************************************************
Filename : CAPI_GlobalState.h
Content : Maintains global state of the CAPI
Created : January 24, 2013
Authors : Michael Antonov
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_CAPI_GlobalState_h
#define OVR_CAPI_GlobalState_h
#include "../OVR_CAPI.h"
#include "../OVR_Device.h"
#include "../Kernel/OVR_Timer.h"
#include "../Kernel/OVR_Math.h"
#include "CAPI_HMDState.h"
namespace OVR { namespace CAPI {
//-------------------------------------------------------------------------------------
// ***** OVRGlobalState
// Global DeviceManager state - singleton instance of this is created
// by ovr_Initialize().
class GlobalState : public MessageHandler, public NewOverrideBase
{
public:
GlobalState();
~GlobalState();
static GlobalState *pInstance;
int EnumerateDevices();
HMDDevice* CreateDevice(int index);
// MessageHandler implementation
void OnMessage(const Message& msg);
// Helpers used to keep track of HMDs and notify them of sensor changes.
void AddHMD(HMDState* hmd);
void RemoveHMD(HMDState* hmd);
void NotifyHMDs_AddDevice(DeviceType deviceType);
const char* GetLastError()
{
return 0;
}
DeviceManager* GetManager() { return pManager; }
protected:
Ptr<DeviceManager> pManager;
Lock EnumerationLock;
Array<DeviceHandle> EnumeratedDevices;
// Currently created hmds; protected by Manager lock.
List<HMDState> HMDs;
};
}} // namespace OVR::CAPI
#endif

View File

@ -0,0 +1,143 @@
/************************************************************************************
Filename : OVR_CAPI_HMDRenderState.cpp
Content : Combines all of the rendering state associated with the HMD
Created : February 2, 2014
Authors : Michael Antonov
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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 "CAPI_HMDRenderState.h"
namespace OVR { namespace CAPI {
//-------------------------------------------------------------------------------------
// ***** HMDRenderState
HMDRenderState::HMDRenderState(ovrHmd hmd, Profile* userProfile, const OVR::HMDInfo& hmdInfo)
: HMD(hmd), HMDInfo(hmdInfo)
{
RenderInfo = GenerateHmdRenderInfoFromHmdInfo( HMDInfo, userProfile );
Distortion[0] = CalculateDistortionRenderDesc(StereoEye_Left, RenderInfo, 0);
Distortion[1] = CalculateDistortionRenderDesc(StereoEye_Right, RenderInfo, 0);
ClearColor[0] = ClearColor[1] = ClearColor[2] = ClearColor[3] =0.0f;
EnabledHmdCaps = 0;
}
HMDRenderState::~HMDRenderState()
{
}
ovrHmdDesc HMDRenderState::GetDesc()
{
ovrHmdDesc d;
memset(&d, 0, sizeof(d));
d.Type = ovrHmd_Other;
d.ProductName = HMDInfo.ProductName;
d.Manufacturer = HMDInfo.Manufacturer;
d.Resolution.w = HMDInfo.ResolutionInPixels.w;
d.Resolution.h = HMDInfo.ResolutionInPixels.h;
d.WindowsPos.x = HMDInfo.DesktopX;
d.WindowsPos.y = HMDInfo.DesktopY;
d.DisplayDeviceName = HMDInfo.DisplayDeviceName;
d.DisplayId = HMDInfo.DisplayId;
d.HmdCaps = ovrHmdCap_Present | ovrHmdCap_NoVSync;
d.SensorCaps = ovrSensorCap_YawCorrection | ovrSensorCap_Orientation;
d.DistortionCaps = ovrDistortionCap_Chromatic | ovrDistortionCap_TimeWarp | ovrDistortionCap_Vignette;
if (strstr(HMDInfo.ProductName, "DK1"))
{
d.Type = ovrHmd_DK1;
}
else if (strstr(HMDInfo.ProductName, "DK2"))
{
d.Type = ovrHmd_DK2;
d.HmdCaps |= ovrHmdCap_LowPersistence |
ovrHmdCap_LatencyTest | ovrHmdCap_DynamicPrediction;
d.SensorCaps |= ovrSensorCap_Position;
}
DistortionRenderDesc& leftDistortion = Distortion[0];
DistortionRenderDesc& rightDistortion = Distortion[1];
// The suggested FOV (assuming eye rotation)
d.DefaultEyeFov[0] = CalculateFovFromHmdInfo(StereoEye_Left, leftDistortion, RenderInfo, OVR_DEFAULT_EXTRA_EYE_ROTATION);
d.DefaultEyeFov[1] = CalculateFovFromHmdInfo(StereoEye_Right, rightDistortion, RenderInfo, OVR_DEFAULT_EXTRA_EYE_ROTATION);
// FOV extended across the entire screen
d.MaxEyeFov[0] = GetPhysicalScreenFov(StereoEye_Left, leftDistortion);
d.MaxEyeFov[1] = GetPhysicalScreenFov(StereoEye_Right, rightDistortion);
if (HMDInfo.Shutter.Type == HmdShutter_RollingRightToLeft)
{
d.EyeRenderOrder[0] = ovrEye_Right;
d.EyeRenderOrder[1] = ovrEye_Left;
}
else
{
d.EyeRenderOrder[0] = ovrEye_Left;
d.EyeRenderOrder[1] = ovrEye_Right;
}
return d;
}
ovrSizei HMDRenderState::GetFOVTextureSize(int eye, ovrFovPort fov, float pixelsPerDisplayPixel)
{
OVR_ASSERT((unsigned)eye < 2);
StereoEye seye = (eye == ovrEye_Left) ? StereoEye_Left : StereoEye_Right;
return CalculateIdealPixelSize(seye, Distortion[eye], fov, pixelsPerDisplayPixel);
}
ovrEyeRenderDesc HMDRenderState::calcRenderDesc(ovrEyeType eyeType, const ovrFovPort& fov)
{
HmdRenderInfo& hmdri = RenderInfo;
StereoEye eye = (eyeType == ovrEye_Left) ? StereoEye_Left : StereoEye_Right;
ovrEyeRenderDesc e0;
e0.Eye = eyeType;
e0.Fov = fov;
e0.ViewAdjust = CalculateEyeVirtualCameraOffset(hmdri, eye, false);
e0.DistortedViewport = GetFramebufferViewport(eye, hmdri);
e0.PixelsPerTanAngleAtCenter = Distortion[0].PixelsPerTanAngleAtCenter;
return e0;
}
void HMDRenderState::setupRenderDesc( ovrEyeRenderDesc eyeRenderDescOut[2],
const ovrFovPort eyeFovIn[2] )
{
eyeRenderDescOut[0] = EyeRenderDesc[0] = calcRenderDesc(ovrEye_Left, eyeFovIn[0]);
eyeRenderDescOut[1] = EyeRenderDesc[1] = calcRenderDesc(ovrEye_Right, eyeFovIn[1]);
}
}} // namespace OVR::CAPI

View File

@ -0,0 +1,93 @@
/************************************************************************************
Filename : CAPI_HMDRenderState.h
Content : Combines all of the rendering state associated with the HMD
Created : February 2, 2014
Authors : Michael Antonov
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_CAPI_HMDRenderState_h
#define OVR_CAPI_HMDRenderState_h
#include "../OVR_CAPI.h"
#include "../Kernel/OVR_Math.h"
#include "../Util/Util_Render_Stereo.h"
namespace OVR { namespace CAPI {
using namespace OVR::Util::Render;
//-------------------------------------------------------------------------------------
// ***** HMDRenderState
// Combines all of the rendering setup information about one HMD.
class HMDRenderState : public NewOverrideBase
{
// Quiet assignment compiler warning.
void operator = (const HMDRenderState&) { }
public:
HMDRenderState(ovrHmd hmd, Profile* userProfile, const OVR::HMDInfo& hmdInfo);
virtual ~HMDRenderState();
// *** Rendering Setup
// Delegated access APIs
ovrHmdDesc GetDesc();
ovrSizei GetFOVTextureSize(int eye, ovrFovPort fov, float pixelsPerDisplayPixel);
ovrEyeRenderDesc calcRenderDesc(ovrEyeType eyeType, const ovrFovPort& fov);
void setupRenderDesc(ovrEyeRenderDesc eyeRenderDescOut[2],
const ovrFovPort eyeFovIn[2]);
public:
// HMDInfo shouldn't change, as its string pointers are passed out.
ovrHmd HMD;
const OVR::HMDInfo& HMDInfo;
//const char* pLastError;
HmdRenderInfo RenderInfo;
DistortionRenderDesc Distortion[2];
ovrEyeRenderDesc EyeRenderDesc[2];
// Clear color used for distortion
float ClearColor[4];
// Pose at which last time the eye was rendered, as submitted by EndEyeRender.
ovrPosef EyeRenderPoses[2];
// Capabilities passed to Configure.
unsigned EnabledHmdCaps;
unsigned DistortionCaps;
};
}} // namespace OVR::CAPI
#endif // OVR_CAPI_HMDState_h

View File

@ -0,0 +1,804 @@
/************************************************************************************
Filename : CAPI_HMDState.cpp
Content : State associated with a single HMD
Created : January 24, 2014
Authors : Michael Antonov
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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 "CAPI_HMDState.h"
#include "CAPI_GlobalState.h"
#include "../OVR_Profile.h"
namespace OVR { namespace CAPI {
//-------------------------------------------------------------------------------------
// ***** HMDState
HMDState::HMDState(HMDDevice* device)
: pHMD(device), HMDInfoW(device), HMDInfo(HMDInfoW.h),
EnabledHmdCaps(0), HmdCapsAppliedToSensor(0),
SensorStarted(0), SensorCreated(0), SensorCaps(0),
AddSensorCount(0), AddLatencyTestCount(0), AddLatencyTestDisplayCount(0),
RenderState(getThis(), pHMD->GetProfile(), HMDInfoW.h),
LastFrameTimeSeconds(0.0f), LastGetFrameTimeSeconds(0.0),
LatencyTestActive(false),
LatencyTest2Active(false)
{
pLastError = 0;
GlobalState::pInstance->AddHMD(this);
// Should be in renderer?
TimeManager.Init(RenderState.RenderInfo);
EyeRenderActive[0] = false;
EyeRenderActive[1] = false;
LatencyTestDrawColor[0] = 0;
LatencyTestDrawColor[1] = 0;
LatencyTestDrawColor[2] = 0;
OVR_CAPI_VISION_CODE( pPoseTracker = 0; )
RenderingConfigured = false;
BeginFrameCalled = false;
BeginFrameThreadId = 0;
BeginFrameTimingCalled = false;
}
HMDState::HMDState(ovrHmdType hmdType)
: pHMD(0), HMDInfoW(hmdType), HMDInfo(HMDInfoW.h),
EnabledHmdCaps(0),
SensorStarted(0), SensorCreated(0), SensorCaps(0),
AddSensorCount(0), AddLatencyTestCount(0), AddLatencyTestDisplayCount(0),
RenderState(getThis(), 0, HMDInfoW.h), // No profile.
LastFrameTimeSeconds(0.0), LastGetFrameTimeSeconds(0.0)
{
// TBD: We should probably be looking up the default profile for the given
// device type + user.
pLastError = 0;
GlobalState::pInstance->AddHMD(this);
// Should be in renderer?
TimeManager.Init(RenderState.RenderInfo);
EyeRenderActive[0] = false;
EyeRenderActive[1] = false;
OVR_CAPI_VISION_CODE( pPoseTracker = 0; )
RenderingConfigured = false;
BeginFrameCalled = false;
BeginFrameThreadId = 0;
BeginFrameTimingCalled = false;
}
HMDState::~HMDState()
{
OVR_ASSERT(GlobalState::pInstance);
StopSensor();
ConfigureRendering(0,0,0,0);
OVR_CAPI_VISION_CODE( OVR_ASSERT(pPoseTracker == 0); )
GlobalState::pInstance->RemoveHMD(this);
}
//-------------------------------------------------------------------------------------
// *** Sensor
bool HMDState::StartSensor(unsigned supportedCaps, unsigned requiredCaps)
{
Lock::Locker lockScope(&DevicesLock);
bool crystalCoveOrBetter = (HMDInfo.HmdType == HmdType_CrystalCoveProto) ||
(HMDInfo.HmdType == HmdType_DK2);
bool sensorCreatedJustNow = false;
// TBD: In case of sensor not being immediately available, it would be good to check
// yaw config availability to match it with ovrHmdCap_YawCorrection requirement.
//
if (!crystalCoveOrBetter)
{
if (requiredCaps & ovrSensorCap_Position)
{
pLastError = "ovrSensorCap_Position not supported on this HMD.";
return false;
}
}
supportedCaps |= requiredCaps;
if (pHMD && !pSensor)
{
// Zero AddSensorCount before creation, in case it fails (or succeeds but then
// immediately gets disconnected) followed by another Add notification.
AddSensorCount = 0;
pSensor = *pHMD->GetSensor();
sensorCreatedJustNow= true;
if (pSensor)
{
pSensor->SetReportRate(500);
SFusion.AttachToSensor(pSensor);
applyProfileToSensorFusion();
}
else
{
if (requiredCaps & ovrSensorCap_Orientation)
{
pLastError = "Failed to create sensor.";
return false;
}
}
}
if ((requiredCaps & ovrSensorCap_YawCorrection) && !pSensor->IsMagCalibrated())
{
pLastError = "ovrHmdCap_YawCorrection not available.";
if (sensorCreatedJustNow)
{
SFusion.AttachToSensor(0);
SFusion.Reset();
pSensor.Clear();
}
return false;
}
SFusion.SetYawCorrectionEnabled((supportedCaps & ovrSensorCap_YawCorrection) != 0);
if (pSensor && sensorCreatedJustNow)
{
LogText("Sensor created.\n");
SensorCreated = true;
}
updateDK2FeaturesTiedToSensor(sensorCreatedJustNow);
#ifdef OVR_CAPI_VISIONSUPPORT
if (crystalCoveOrBetter && (supportedCaps & ovrSensorCap_Position))
{
if (!pPoseTracker)
{
pPoseTracker = new Vision::PoseTracker(SFusion);
if (pPoseTracker)
{
pPoseTracker->AssociateHMD(pSensor);
LogText("Sensor Pose tracker created.\n");
}
}
// TBD: How do we verify that position tracking is actually available
// i.e. camera is plugged in?
}
else if (pPoseTracker)
{
// TBD: Internals not thread safe - must fix!!
delete pPoseTracker;
pPoseTracker = 0;
LogText("Sensor Pose tracker destroyed.\n");
}
#endif // OVR_CAPI_VISIONSUPPORT
SensorCaps = supportedCaps;
SensorStarted = true;
return true;
}
// Stops sensor sampling, shutting down internal resources.
void HMDState::StopSensor()
{
Lock::Locker lockScope(&DevicesLock);
if (SensorStarted)
{
#ifdef OVR_CAPI_VISIONSUPPORT
if (pPoseTracker)
{
// TBD: Internals not thread safe - must fix!!
delete pPoseTracker;
pPoseTracker = 0;
LogText("Sensor Pose tracker destroyed.\n");
}
#endif // OVR_CAPI_VISION_CODE
SFusion.AttachToSensor(0);
SFusion.Reset();
pSensor.Clear();
HmdCapsAppliedToSensor = 0;
AddSensorCount = 0;
SensorCaps = 0;
SensorCreated = false;
SensorStarted = false;
LogText("StopSensor succeeded.\n");
}
}
// Resets sensor orientation.
void HMDState::ResetSensor()
{
SFusion.Reset();
}
// Returns prediction for time.
ovrSensorState HMDState::PredictedSensorState(double absTime)
{
SensorState ss;
// We are trying to keep this path lockless unless we are notified of new device
// creation while not having a sensor yet. It's ok to check SensorCreated volatile
// flag here, since GetSensorStateAtTime() is internally lockless and safe.
if (SensorCreated || checkCreateSensor())
{
ss = SFusion.GetSensorStateAtTime(absTime);
if (!(ss.StatusFlags & ovrStatus_OrientationTracked))
{
Lock::Locker lockScope(&DevicesLock);
#ifdef OVR_CAPI_VISIONSUPPORT
if (pPoseTracker)
{
// TBD: Internals not thread safe - must fix!!
delete pPoseTracker;
pPoseTracker = 0;
LogText("Sensor Pose tracker destroyed.\n");
}
#endif // OVR_CAPI_VISION_CODE
// Not needed yet; SFusion.AttachToSensor(0);
// This seems to reset orientation anyway...
pSensor.Clear();
SensorCreated = false;
HmdCapsAppliedToSensor = 0;
}
}
else
{
// SensorState() defaults to 0s.
// ss.Pose.Orientation = Quatf();
// ..
// John:
// We still want valid times so frames will get a delta-time
// and allow operation with a joypad when the sensor isn't
// connected.
ss.Recorded.TimeInSeconds = absTime;
ss.Predicted.TimeInSeconds = absTime;
}
ss.StatusFlags |= ovrStatus_HmdConnected;
return ss;
}
bool HMDState::checkCreateSensor()
{
if (!(SensorStarted && !SensorCreated && AddSensorCount))
return false;
Lock::Locker lockScope(&DevicesLock);
// Re-check condition once in the lock, in case the state changed.
if (SensorStarted && !SensorCreated && AddSensorCount)
{
if (pHMD)
{
AddSensorCount = 0;
pSensor = *pHMD->GetSensor();
}
if (pSensor)
{
pSensor->SetReportRate(500);
SFusion.AttachToSensor(pSensor);
SFusion.SetYawCorrectionEnabled((SensorCaps & ovrSensorCap_YawCorrection) != 0);
applyProfileToSensorFusion();
#ifdef OVR_CAPI_VISIONSUPPORT
if (SensorCaps & ovrSensorCap_Position)
{
pPoseTracker = new Vision::PoseTracker(SFusion);
if (pPoseTracker)
{
pPoseTracker->AssociateHMD(pSensor);
}
LogText("Sensor Pose tracker created.\n");
}
#endif // OVR_CAPI_VISION_CODE
LogText("Sensor created.\n");
SensorCreated = true;
return true;
}
}
return SensorCreated;
}
bool HMDState::GetSensorDesc(ovrSensorDesc* descOut)
{
Lock::Locker lockScope(&DevicesLock);
if (SensorCreated)
{
OVR_ASSERT(pSensor);
OVR::SensorInfo si;
pSensor->GetDeviceInfo(&si);
descOut->VendorId = si.VendorId;
descOut->ProductId = si.ProductId;
OVR_ASSERT(si.SerialNumber.GetSize() <= sizeof(descOut->SerialNumber));
OVR_strcpy(descOut->SerialNumber, sizeof(descOut->SerialNumber), si.SerialNumber.ToCStr());
return true;
}
return false;
}
void HMDState::applyProfileToSensorFusion()
{
if (!pHMD)
return;
Profile* profile = pHMD->GetProfile();
if (!profile)
{
OVR_ASSERT(false);
return;
}
SFusion.SetUserHeadDimensions ( *profile, RenderState.RenderInfo );
}
void HMDState::updateLowPersistenceMode(bool lowPersistence) const
{
OVR_ASSERT(pSensor);
DisplayReport dr;
if (pSensor.GetPtr())
{
pSensor->GetDisplayReport(&dr);
dr.Persistence = (UInt16) (dr.TotalRows * (lowPersistence ? 0.18f : 1.0f));
dr.Brightness = lowPersistence ? 255 : 0;
pSensor->SetDisplayReport(dr);
}
}
void HMDState::updateLatencyTestForHmd(bool latencyTesting)
{
if (pSensor.GetPtr())
{
DisplayReport dr;
pSensor->GetDisplayReport(&dr);
dr.ReadPixel = latencyTesting;
pSensor->SetDisplayReport(dr);
}
if (latencyTesting)
{
LatencyUtil2.SetSensorDevice(pSensor.GetPtr());
}
else
{
LatencyUtil2.SetSensorDevice(NULL);
}
}
void HMDState::updateDK2FeaturesTiedToSensor(bool sensorCreatedJustNow)
{
Lock::Locker lockScope(&DevicesLock);
if (!SensorCreated || (HMDInfo.HmdType != HmdType_DK2))
return;
// Only send display reports if state changed or sensor initializing first time.
if (sensorCreatedJustNow ||
((HmdCapsAppliedToSensor ^ EnabledHmdCaps) & ovrHmdCap_LowPersistence))
{
updateLowPersistenceMode((EnabledHmdCaps & ovrHmdCap_LowPersistence) ? true : false);
}
if (sensorCreatedJustNow || ((HmdCapsAppliedToSensor ^ EnabledHmdCaps) & ovrHmdCap_LatencyTest))
{
updateLatencyTestForHmd((EnabledHmdCaps & ovrHmdCap_LatencyTest) != 0);
}
HmdCapsAppliedToSensor = EnabledHmdCaps & (ovrHmdCap_LowPersistence|ovrHmdCap_LatencyTest);
}
void HMDState::SetEnabledHmdCaps(unsigned hmdCaps)
{
if (HMDInfo.HmdType == HmdType_DK2)
{
if ((EnabledHmdCaps ^ hmdCaps) & ovrHmdCap_DynamicPrediction)
{
// DynamicPrediction change
TimeManager.ResetFrameTiming(TimeManager.GetFrameTiming().FrameIndex,
(hmdCaps & ovrHmdCap_DynamicPrediction) ? true : false,
RenderingConfigured);
}
}
if ((EnabledHmdCaps ^ hmdCaps) & ovrHmdCap_NoVSync)
{
TimeManager.SetVsync((hmdCaps & ovrHmdCap_NoVSync) ? false : true);
}
EnabledHmdCaps = hmdCaps & ovrHmdCap_Writable_Mask;
RenderState.EnabledHmdCaps = EnabledHmdCaps;
// Unfortunately, LowPersistance and other flags are tied to sensor.
// This flag will apply the state of sensor is created; otherwise this will be delayed
// till StartSensor.
// Such behavior is less then ideal, but should be resolved with the service model.
updateDK2FeaturesTiedToSensor(false);
}
//-------------------------------------------------------------------------------------
// ***** Property Access
// TBD: This all needs to be cleaned up and organized into namespaces.
float HMDState::getFloatValue(const char* propertyName, float defaultVal)
{
if (OVR_strcmp(propertyName, "LensSeparation") == 0)
{
return HMDInfo.LensSeparationInMeters;
}
else if (OVR_strcmp(propertyName, "CenterPupilDepth") == 0)
{
return SFusion.GetCenterPupilDepth();
}
else if (pHMD)
{
Profile* p = pHMD->GetProfile();
if (p)
{
return p->GetFloatValue(propertyName, defaultVal);
}
}
return defaultVal;
}
bool HMDState::setFloatValue(const char* propertyName, float value)
{
if (OVR_strcmp(propertyName, "CenterPupilDepth") == 0)
{
SFusion.SetCenterPupilDepth(value);
return true;
}
return false;
}
static unsigned CopyFloatArrayWithLimit(float dest[], unsigned destSize,
float source[], unsigned sourceSize)
{
unsigned count = Alg::Min(destSize, sourceSize);
for (unsigned i = 0; i < count; i++)
dest[i] = source[i];
return count;
}
unsigned HMDState::getFloatArray(const char* propertyName, float values[], unsigned arraySize)
{
if (arraySize)
{
if (OVR_strcmp(propertyName, "ScreenSize") == 0)
{
float data[2] = { HMDInfo.ScreenSizeInMeters.w, HMDInfo.ScreenSizeInMeters.h };
return CopyFloatArrayWithLimit(values, arraySize, data, 2);
}
else if (OVR_strcmp(propertyName, "DistortionClearColor") == 0)
{
return CopyFloatArrayWithLimit(values, arraySize, RenderState.ClearColor, 4);
}
else if (OVR_strcmp(propertyName, "DK2Latency") == 0)
{
if (HMDInfo.HmdType != HmdType_DK2)
return 0;
float data[3];
TimeManager.GetLatencyTimings(data);
return CopyFloatArrayWithLimit(values, arraySize, data, 3);
}
/*
else if (OVR_strcmp(propertyName, "CenterPupilDepth") == 0)
{
if (arraySize >= 1)
{
values[0] = SFusion.GetCenterPupilDepth();
return 1;
}
return 0;
} */
else if (pHMD)
{
Profile* p = pHMD->GetProfile();
// TBD: Not quite right. Should update profile interface, so that
// we can return 0 in all conditions if property doesn't exist.
if (p)
{
unsigned count = p->GetFloatValues(propertyName, values, arraySize);
return count;
}
}
}
return 0;
}
bool HMDState::setFloatArray(const char* propertyName, float values[], unsigned arraySize)
{
if (!arraySize)
return false;
if (OVR_strcmp(propertyName, "DistortionClearColor") == 0)
{
CopyFloatArrayWithLimit(RenderState.ClearColor, 4, values, arraySize);
return true;
}
return false;
}
const char* HMDState::getString(const char* propertyName, const char* defaultVal)
{
if (pHMD)
{
// For now, just access the profile.
Profile* p = pHMD->GetProfile();
LastGetStringValue[0] = 0;
if (p && p->GetValue(propertyName, LastGetStringValue, sizeof(LastGetStringValue)))
{
return LastGetStringValue;
}
}
return defaultVal;
}
//-------------------------------------------------------------------------------------
// *** Latency Test
bool HMDState::ProcessLatencyTest(unsigned char rgbColorOut[3])
{
bool result = false;
// Check create.
if (pLatencyTester)
{
if (pLatencyTester->IsConnected())
{
Color colorToDisplay;
LatencyUtil.ProcessInputs();
result = LatencyUtil.DisplayScreenColor(colorToDisplay);
rgbColorOut[0] = colorToDisplay.R;
rgbColorOut[1] = colorToDisplay.G;
rgbColorOut[2] = colorToDisplay.B;
}
else
{
// Disconnect.
LatencyUtil.SetDevice(NULL);
pLatencyTester = 0;
LogText("LATENCY SENSOR disconnected.\n");
}
}
else if (AddLatencyTestCount > 0)
{
// This might have some unlikely race condition issue which could cause us to miss a device...
AddLatencyTestCount = 0;
pLatencyTester = *GlobalState::pInstance->GetManager()->
EnumerateDevices<LatencyTestDevice>().CreateDevice();
if (pLatencyTester)
{
LatencyUtil.SetDevice(pLatencyTester);
LogText("LATENCY TESTER connected\n");
}
}
return result;
}
void HMDState::ProcessLatencyTest2(unsigned char rgbColorOut[3], double startTime)
{
// Check create.
if (!(EnabledHmdCaps & ovrHmdCap_LatencyTest))
return;
if (pLatencyTesterDisplay && !LatencyUtil2.HasDisplayDevice())
{
if (!pLatencyTesterDisplay->IsConnected())
{
LatencyUtil2.SetDisplayDevice(NULL);
}
}
else if (AddLatencyTestDisplayCount > 0)
{
// This might have some unlikely race condition issue
// which could cause us to miss a device...
AddLatencyTestDisplayCount = 0;
pLatencyTesterDisplay = *GlobalState::pInstance->GetManager()->
EnumerateDevices<LatencyTestDevice>().CreateDevice();
if (pLatencyTesterDisplay)
{
LatencyUtil2.SetDisplayDevice(pLatencyTesterDisplay);
}
}
if (LatencyUtil2.HasDevice() && pSensor && pSensor->IsConnected())
{
LatencyUtil2.BeginTest(startTime);
Color colorToDisplay;
LatencyTest2Active = LatencyUtil2.DisplayScreenColor(colorToDisplay);
rgbColorOut[0] = colorToDisplay.R;
rgbColorOut[1] = colorToDisplay.G;
rgbColorOut[2] = colorToDisplay.B;
}
else
{
LatencyTest2Active = false;
}
}
//-------------------------------------------------------------------------------------
// *** Rendering
bool HMDState::ConfigureRendering(ovrEyeRenderDesc eyeRenderDescOut[2],
const ovrFovPort eyeFovIn[2],
const ovrRenderAPIConfig* apiConfig,
unsigned distortionCaps)
{
ThreadChecker::Scope checkScope(&RenderAPIThreadChecker, "ovrHmd_ConfigureRendering");
// null -> shut down.
if (!apiConfig)
{
if (pRenderer)
pRenderer.Clear();
RenderingConfigured = false;
return true;
}
if (pRenderer &&
(apiConfig->Header.API != pRenderer->GetRenderAPI()))
{
// Shutdown old renderer.
if (pRenderer)
pRenderer.Clear();
}
// Step 1: do basic setup configuration
RenderState.setupRenderDesc(eyeRenderDescOut, eyeFovIn);
RenderState.EnabledHmdCaps = EnabledHmdCaps; // This is a copy... Any cleaner way?
RenderState.DistortionCaps = distortionCaps;
TimeManager.ResetFrameTiming(0,
(EnabledHmdCaps & ovrHmdCap_DynamicPrediction) ? true : false,
true);
LastFrameTimeSeconds = 0.0f;
// Set RenderingConfigured early to avoid ASSERTs in renderer initialization.
RenderingConfigured = true;
if (!pRenderer)
{
pRenderer = *DistortionRenderer::APICreateRegistry
[apiConfig->Header.API](this, TimeManager, RenderState);
}
if (!pRenderer ||
!pRenderer->Initialize(apiConfig, distortionCaps))
{
RenderingConfigured = false;
return false;
}
return true;
}
ovrPosef HMDState::BeginEyeRender(ovrEyeType eye)
{
// Debug checks.
checkBeginFrameScope("ovrHmd_BeginEyeRender");
ThreadChecker::Scope checkScope(&RenderAPIThreadChecker, "ovrHmd_BeginEyeRender");
// Unknown eyeId provided in ovrHmd_BeginEyeRender
OVR_ASSERT_LOG(eye == ovrEye_Left || eye == ovrEye_Right,
("ovrHmd_BeginEyeRender eyeId out of range."));
OVR_ASSERT_LOG(EyeRenderActive[eye] == false,
("Multiple calls to ovrHmd_BeginEyeRender for the same eye."));
EyeRenderActive[eye] = true;
// Only process latency tester for drawing the left eye (assumes left eye is drawn first)
if (pRenderer && eye == 0)
{
LatencyTestActive = ProcessLatencyTest(LatencyTestDrawColor);
}
return ovrHmd_GetEyePose(this, eye);
}
void HMDState::EndEyeRender(ovrEyeType eye, ovrPosef renderPose, ovrTexture* eyeTexture)
{
// Debug checks.
checkBeginFrameScope("ovrHmd_EndEyeRender");
ThreadChecker::Scope checkScope(&RenderAPIThreadChecker, "ovrHmd_EndEyeRender");
if (!EyeRenderActive[eye])
{
OVR_ASSERT_LOG(false,
("ovrHmd_EndEyeRender called without ovrHmd_BeginEyeRender."));
return;
}
RenderState.EyeRenderPoses[eye] = renderPose;
if (pRenderer)
pRenderer->SubmitEye(eye, eyeTexture);
EyeRenderActive[eye] = false;
}
}} // namespace OVR::CAPI

View File

@ -0,0 +1,347 @@
/************************************************************************************
Filename : CAPI_HMDState.h
Content : State associated with a single HMD
Created : January 24, 2014
Authors : Michael Antonov
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_CAPI_HMDState_h
#define OVR_CAPI_HMDState_h
#include "../Kernel/OVR_Math.h"
#include "../Kernel/OVR_List.h"
#include "../Kernel/OVR_Log.h"
#include "../OVR_CAPI.h"
#include "../OVR_SensorFusion.h"
#include "../Util/Util_LatencyTest.h"
#include "../Util/Util_LatencyTest2.h"
#include "CAPI_FrameTimeManager.h"
#include "CAPI_HMDRenderState.h"
#include "CAPI_DistortionRenderer.h"
// Define OVR_CAPI_VISIONSUPPORT to compile in vision support
#ifdef OVR_CAPI_VISIONSUPPORT
#define OVR_CAPI_VISION_CODE(c) c
#include "../Vision/Vision_PoseTracker.h"
#else
#define OVR_CAPI_VISION_CODE(c)
#endif
struct ovrHmdStruct { };
namespace OVR { namespace CAPI {
using namespace OVR::Util::Render;
//-------------------------------------------------------------------------------------
// ***** ThreadChecker
// This helper class is used to verify that the API is used according to supported
// thread safety constraints (is not re-entrant for this and related functions).
class ThreadChecker
{
public:
#ifndef OVR_BUILD_DEBUG
// In release build, thread checks are disabled.
ThreadChecker() { }
void Begin(const char* functionName) { OVR_UNUSED1(functionName); }
void End() { }
// Add thread-re-entrancy check for function scope
struct Scope
{
Scope(ThreadChecker*, const char *) { }
~Scope() { }
};
#else // OVR_BUILD_DEBUG
ThreadChecker() : pFunctionName(0), FirstThread(0)
{ }
void Begin(const char* functionName)
{
if (!pFunctionName)
{
pFunctionName = functionName;
FirstThread = GetCurrentThreadId();
}
else
{
// pFunctionName may be not null here if function is called internally on the same thread.
OVR_ASSERT_LOG((FirstThread == GetCurrentThreadId()),
("%s (threadId=%p) called at the same times as %s (threadId=%p)\n",
functionName, GetCurrentThreadId(), pFunctionName, FirstThread) );
}
}
void End()
{
pFunctionName = 0;
FirstThread = 0;
}
// Add thread-re-entrancy check for function scope.
struct Scope
{
Scope(ThreadChecker* threadChecker, const char *functionName) : pChecker(threadChecker)
{ pChecker->Begin(functionName); }
~Scope()
{ pChecker->End(); }
private:
ThreadChecker* pChecker;
};
private:
// If not 0, contains the name of the function that first entered the scope.
const char * pFunctionName;
ThreadId FirstThread;
#endif // OVR_BUILD_DEBUG
};
//-------------------------------------------------------------------------------------
// ***** HMDState
// Describes a single HMD.
class HMDState : public ListNode<HMDState>,
public ovrHmdStruct, public NewOverrideBase
{
public:
HMDState(HMDDevice* device);
HMDState(ovrHmdType hmdType);
virtual ~HMDState();
// *** Sensor Setup
bool StartSensor(unsigned supportedCaps, unsigned requiredCaps);
void StopSensor();
void ResetSensor();
ovrSensorState PredictedSensorState(double absTime);
bool GetSensorDesc(ovrSensorDesc* descOut);
// Changes HMD Caps.
// Capability bits that are not directly or logically tied to one system (such as sensor)
// are grouped here. ovrHmdCap_VSync, for example, affects rendering and timing.
void SetEnabledHmdCaps(unsigned caps);
bool ProcessLatencyTest(unsigned char rgbColorOut[3]);
void ProcessLatencyTest2(unsigned char rgbColorOut[3], double startTime);
// *** Rendering Setup
bool ConfigureRendering(ovrEyeRenderDesc eyeRenderDescOut[2],
const ovrFovPort eyeFovIn[2],
const ovrRenderAPIConfig* apiConfig,
unsigned distortionCaps);
ovrPosef BeginEyeRender(ovrEyeType eye);
void EndEyeRender(ovrEyeType eye, ovrPosef renderPose, ovrTexture* eyeTexture);
const char* GetLastError()
{
const char* p = pLastError;
pLastError = 0;
return p;
}
void NotifyAddDevice(DeviceType deviceType)
{
if (deviceType == Device_Sensor)
AddSensorCount++;
else if (deviceType == Device_LatencyTester)
{
AddLatencyTestCount++;
AddLatencyTestDisplayCount++;
}
}
bool checkCreateSensor();
void applyProfileToSensorFusion();
// INlines so that they can be easily compiled out.
// Does debug ASSERT checks for functions that require BeginFrame.
// Also verifies that we are on the right thread.
void checkBeginFrameScope(const char* functionName)
{
OVR_UNUSED1(functionName); // for Release build.
OVR_ASSERT_LOG(BeginFrameCalled == true,
("%s called outside ovrHmd_BeginFrame.", functionName));
OVR_ASSERT_LOG(BeginFrameThreadId == OVR::GetCurrentThreadId(),
("%s called on a different thread then ovrHmd_BeginFrame.", functionName));
}
void checkRenderingConfigured(const char* functionName)
{
OVR_UNUSED1(functionName); // for Release build.
OVR_ASSERT_LOG(RenderingConfigured == true,
("%s called without ovrHmd_ConfigureRendering.", functionName));
}
void checkBeginFrameTimingScope(const char* functionName)
{
OVR_UNUSED1(functionName); // for Release build.
OVR_ASSERT_LOG(BeginFrameTimingCalled == true,
("%s called outside ovrHmd_BeginFrameTiming.", functionName));
}
HMDState* getThis() { return this; }
void updateLowPersistenceMode(bool lowPersistence) const;
void updateLatencyTestForHmd(bool latencyTesting);
void updateDK2FeaturesTiedToSensor(bool sensorCreatedJustNow);
// Get properties by name.
float getFloatValue(const char* propertyName, float defaultVal);
bool setFloatValue(const char* propertyName, float value);
unsigned getFloatArray(const char* propertyName, float values[], unsigned arraySize);
bool setFloatArray(const char* propertyName, float values[], unsigned arraySize);
const char* getString(const char* propertyName, const char* defaultVal);
public:
// Wrapper to support 'const'
struct HMDInfoWrapper
{
HMDInfoWrapper(ovrHmdType hmdType)
{
HmdTypeEnum t = HmdType_None;
if (hmdType == ovrHmd_DK1)
t = HmdType_DK1;
else if (hmdType == ovrHmd_CrystalCoveProto)
t = HmdType_CrystalCoveProto;
else if (hmdType == ovrHmd_DK2)
t = HmdType_DK2;
h = CreateDebugHMDInfo(t);
}
HMDInfoWrapper(HMDDevice* device) { if (device) device->GetDeviceInfo(&h); }
OVR::HMDInfo h;
};
// Note: pHMD can be null if we are representing a virtualized debug HMD.
Ptr<HMDDevice> pHMD;
// HMDInfo shouldn't change, as its string pointers are passed out.
const HMDInfoWrapper HMDInfoW;
const OVR::HMDInfo& HMDInfo;
const char* pLastError;
// Caps enabled for the HMD.
unsigned EnabledHmdCaps;
// These are the flags actually applied to the Sensor device,
// used to track whether SetDisplayReport calls are necessary.
unsigned HmdCapsAppliedToSensor;
// *** Sensor
// Lock used to support thread-safe lifetime access to sensor.
Lock DevicesLock;
// Atomic integer used as a flag that we should check the sensor device.
AtomicInt<int> AddSensorCount;
// All of Sensor variables may be modified/used with DevicesLock, with exception that
// the {SensorStarted, SensorCreated} can be read outside the lock to see
// if device creation check is necessary.
// Whether we called StartSensor() and requested sensor caps.
volatile bool SensorStarted;
volatile bool SensorCreated;
// pSensor may still be null or non-running after start if it wasn't yet available
Ptr<SensorDevice> pSensor; // Head
unsigned SensorCaps;
// SensorFusion state may be accessible without a lock.
SensorFusion SFusion;
// Vision pose tracker is currently new-allocated
OVR_CAPI_VISION_CODE(
Vision::PoseTracker* pPoseTracker;
)
// Latency tester
Ptr<LatencyTestDevice> pLatencyTester;
Util::LatencyTest LatencyUtil;
AtomicInt<int> AddLatencyTestCount;
bool LatencyTestActive;
unsigned char LatencyTestDrawColor[3];
// Using latency tester as debug display
Ptr<LatencyTestDevice> pLatencyTesterDisplay;
AtomicInt<int> AddLatencyTestDisplayCount;
Util::LatencyTest2 LatencyUtil2;
bool LatencyTest2Active;
unsigned char LatencyTest2DrawColor[3];
//bool ReadbackColor;
// Rendering part
FrameTimeManager TimeManager;
HMDRenderState RenderState;
Ptr<DistortionRenderer> pRenderer;
// Last timing value reported by BeginFrame.
double LastFrameTimeSeconds;
// Last timing value reported by GetFrameTime. These are separate since the intended
// use is from different threads. TBD: Move to FrameTimeManager? Make atomic?
double LastGetFrameTimeSeconds;
// Last cached value returned by ovrHmd_GetString/ovrHmd_GetStringArray.
char LastGetStringValue[256];
// Debug flag set after ovrHmd_ConfigureRendering succeeds.
bool RenderingConfigured;
// Set after BeginFrame succeeds, and its corresponding thread id for debug checks.
bool BeginFrameCalled;
ThreadId BeginFrameThreadId;
// Graphics functions are not re-entrant from other threads.
ThreadChecker RenderAPIThreadChecker;
//
bool BeginFrameTimingCalled;
// Flags set when we've called BeginEyeRender on a given eye.
bool EyeRenderActive[2];
};
}} // namespace OVR::CAPI
#endif // OVR_CAPI_HMDState_h

View File

@ -0,0 +1,784 @@
/************************************************************************************
Filename : CAPI_GL_DistortionRenderer.h
Content : Distortion renderer header for GL
Created : November 11, 2013
Authors : David Borel, Lee Cooper
Copyright : Copyright 2013 Oculus VR, Inc. 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
otherwise accompanies this software in either electronic or hard copy form.
************************************************************************************/
#include "CAPI_GL_DistortionRenderer.h"
#include "CAPI_GL_DistortionShaders.h"
#include "../../OVR_CAPI_GL.h"
namespace OVR { namespace CAPI { namespace GL {
// Distortion pixel shader lookup.
// Bit 0: Chroma Correction
// Bit 1: Timewarp
enum {
DistortionVertexShaderBitMask = 3,
DistortionVertexShaderCount = DistortionVertexShaderBitMask + 1,
DistortionPixelShaderBitMask = 1,
DistortionPixelShaderCount = DistortionPixelShaderBitMask + 1
};
struct ShaderInfo
{
const char* ShaderData;
size_t ShaderSize;
const ShaderBase::Uniform* ReflectionData;
size_t ReflectionSize;
};
// Do add a new distortion shader use these macros (with or w/o reflection)
#define SI_NOREFL(shader) { shader, sizeof(shader), NULL, 0 }
#define SI_REFL__(shader) { shader, sizeof(shader), shader ## _refl, sizeof( shader ## _refl )/sizeof(*(shader ## _refl)) }
static ShaderInfo DistortionVertexShaderLookup[DistortionVertexShaderCount] =
{
SI_REFL__(Distortion_vs),
SI_REFL__(DistortionChroma_vs),
SI_REFL__(DistortionTimewarp_vs),
SI_REFL__(DistortionTimewarpChroma_vs)
};
static ShaderInfo DistortionPixelShaderLookup[DistortionPixelShaderCount] =
{
SI_NOREFL(Distortion_fs),
SI_NOREFL(DistortionChroma_fs)
};
void DistortionShaderBitIndexCheck()
{
OVR_COMPILER_ASSERT(ovrDistortionCap_Chromatic == 1);
OVR_COMPILER_ASSERT(ovrDistortionCap_TimeWarp == 2);
}
struct DistortionVertex
{
Vector2f Pos;
Vector2f TexR;
Vector2f TexG;
Vector2f TexB;
Color Col;
};
// Vertex type; same format is used for all shapes for simplicity.
// Shapes are built by adding vertices to Model.
struct LatencyVertex
{
Vector3f Pos;
LatencyVertex (const Vector3f& p) : Pos(p) {}
};
//----------------------------------------------------------------------------
// ***** GL::DistortionRenderer
DistortionRenderer::DistortionRenderer(ovrHmd hmd, FrameTimeManager& timeManager,
const HMDRenderState& renderState)
: CAPI::DistortionRenderer(ovrRenderAPI_OpenGL, hmd, timeManager, renderState)
, LatencyVAO(0)
{
DistortionMeshVAOs[0] = 0;
DistortionMeshVAOs[1] = 0;
}
DistortionRenderer::~DistortionRenderer()
{
destroy();
}
// static
CAPI::DistortionRenderer* DistortionRenderer::Create(ovrHmd hmd,
FrameTimeManager& timeManager,
const HMDRenderState& renderState)
{
#if !defined(OVR_OS_MAC)
InitGLExtensions();
#endif
return new DistortionRenderer(hmd, timeManager, renderState);
}
bool DistortionRenderer::Initialize(const ovrRenderAPIConfig* apiConfig,
unsigned distortionCaps)
{
GfxState = *new GraphicsState();
const ovrGLConfig* config = (const ovrGLConfig*)apiConfig;
if (!config)
{
// Cleanup
pEyeTextures[0].Clear();
pEyeTextures[1].Clear();
memset(&RParams, 0, sizeof(RParams));
return true;
}
RParams.Multisample = config->OGL.Header.Multisample;
RParams.RTSize = config->OGL.Header.RTSize;
#if defined(OVR_OS_WIN32)
RParams.Window = (config->OGL.Window) ? config->OGL.Window : GetActiveWindow();
#elif defined(OVR_OS_LINUX)
RParams.Disp = (config->OGL.Disp) ? config->OGL.Disp : XOpenDisplay(NULL);
RParams.Win = config->OGL.Win;
if (!RParams.Win)
{
int unused;
XGetInputFocus(RParams.Disp, &RParams.Win, &unused);
}
#endif
DistortionCaps = distortionCaps;
//DistortionWarper.SetVsync((hmdCaps & ovrHmdCap_NoVSync) ? false : true);
pEyeTextures[0] = *new Texture(&RParams, 0, 0);
pEyeTextures[1] = *new Texture(&RParams, 0, 0);
initBuffersAndShaders();
return true;
}
void DistortionRenderer::SubmitEye(int eyeId, ovrTexture* eyeTexture)
{
// Doesn't do a lot in here??
const ovrGLTexture* tex = (const ovrGLTexture*)eyeTexture;
// Write in values
eachEye[eyeId].texture = tex->OGL.TexId;
if (tex)
{
// Its only at this point we discover what the viewport of the texture is.
// because presumably we allow users to realtime adjust the resolution.
eachEye[eyeId].TextureSize = tex->OGL.Header.TextureSize;
eachEye[eyeId].RenderViewport = tex->OGL.Header.RenderViewport;
const ovrEyeRenderDesc& erd = RState.EyeRenderDesc[eyeId];
ovrHmd_GetRenderScaleAndOffset( erd.Fov,
eachEye[eyeId].TextureSize, eachEye[eyeId].RenderViewport,
eachEye[eyeId].UVScaleOffset );
pEyeTextures[eyeId]->UpdatePlaceholderTexture(tex->OGL.TexId,
tex->OGL.Header.TextureSize);
}
}
void DistortionRenderer::EndFrame(bool swapBuffers,
unsigned char* latencyTesterDrawColor, unsigned char* latencyTester2DrawColor)
{
if (!TimeManager.NeedDistortionTimeMeasurement())
{
if (RState.DistortionCaps & ovrDistortionCap_TimeWarp)
{
// Wait for timewarp distortion if it is time and Gpu idle
FlushGpuAndWaitTillTime(TimeManager.GetFrameTiming().TimewarpPointTime);
}
renderDistortion(pEyeTextures[0], pEyeTextures[1]);
}
else
{
// If needed, measure distortion time so that TimeManager can better estimate
// latency-reducing time-warp wait timing.
WaitUntilGpuIdle();
double distortionStartTime = ovr_GetTimeInSeconds();
renderDistortion(pEyeTextures[0], pEyeTextures[1]);
WaitUntilGpuIdle();
TimeManager.AddDistortionTimeMeasurement(ovr_GetTimeInSeconds() - distortionStartTime);
}
if(latencyTesterDrawColor)
{
renderLatencyQuad(latencyTesterDrawColor);
}
else if(latencyTester2DrawColor)
{
renderLatencyPixel(latencyTester2DrawColor);
}
if (swapBuffers)
{
bool useVsync = ((RState.EnabledHmdCaps & ovrHmdCap_NoVSync) == 0);
int swapInterval = (useVsync) ? 1 : 0;
#if defined(OVR_OS_WIN32)
if (wglGetSwapIntervalEXT() != swapInterval)
wglSwapIntervalEXT(swapInterval);
HDC dc = GetDC(RParams.Window);
BOOL success = SwapBuffers(dc);
ReleaseDC(RParams.Window, dc);
OVR_ASSERT(success);
OVR_UNUSED(success);
#elif defined(OVR_OS_MAC)
CGLContextObj context = CGLGetCurrentContext();
GLint currentSwapInterval = 0;
CGLGetParameter(context, kCGLCPSwapInterval, &currentSwapInterval);
if (currentSwapInterval != swapInterval)
CGLSetParameter(context, kCGLCPSwapInterval, &swapInterval);
CGLFlushDrawable(context);
#elif defined(OVR_OS_LINUX)
static const char* extensions = glXQueryExtensionsString(RParams.Disp, 0);
static bool supportsVSync = (extensions != NULL && strstr(extensions, "GLX_EXT_swap_control"));
if (supportsVSync)
{
GLuint currentSwapInterval = 0;
glXQueryDrawable(RParams.Disp, RParams.Win, GLX_SWAP_INTERVAL_EXT, &currentSwapInterval);
if (currentSwapInterval != swapInterval)
glXSwapIntervalEXT(RParams.Disp, RParams.Win, swapInterval);
}
glXSwapBuffers(RParams.Disp, RParams.Win);
#endif
}
}
void DistortionRenderer::WaitUntilGpuIdle()
{
glFlush();
glFinish();
}
double DistortionRenderer::FlushGpuAndWaitTillTime(double absTime)
{
double initialTime = ovr_GetTimeInSeconds();
if (initialTime >= absTime)
return 0.0;
glFlush();
glFinish();
double newTime = initialTime;
volatile int i;
while (newTime < absTime)
{
for (int j = 0; j < 50; j++)
i = 0;
newTime = ovr_GetTimeInSeconds();
}
// How long we waited
return newTime - initialTime;
}
DistortionRenderer::GraphicsState::GraphicsState()
{
const char* glVersionString = (const char*)glGetString(GL_VERSION);
OVR_DEBUG_LOG(("GL_VERSION STRING: %s", (const char*)glVersionString));
char prefix[64];
bool foundVersion = false;
for (int i = 10; i < 30; ++i)
{
int major = i / 10;
int minor = i % 10;
OVR_sprintf(prefix, 64, "%d.%d", major, minor);
if (strstr(glVersionString, prefix) == glVersionString)
{
GlMajorVersion = major;
GlMinorVersion = minor;
foundVersion = true;
break;
}
}
if (!foundVersion)
{
glGetIntegerv(GL_MAJOR_VERSION, &GlMajorVersion);
glGetIntegerv(GL_MAJOR_VERSION, &GlMinorVersion);
}
OVR_ASSERT(GlMajorVersion >= 2);
if (GlMajorVersion >= 3)
{
SupportsVao = true;
}
else
{
const char* extensions = (const char*)glGetString(GL_EXTENSIONS);
SupportsVao = (strstr("GL_ARB_vertex_array_object", extensions) != NULL);
}
}
void DistortionRenderer::GraphicsState::ApplyBool(GLenum Name, GLint Value)
{
if (Value != 0)
glEnable(Name);
else
glDisable(Name);
}
void DistortionRenderer::GraphicsState::Save()
{
glGetIntegerv(GL_VIEWPORT, Viewport);
glGetFloatv(GL_COLOR_CLEAR_VALUE, ClearColor);
glGetIntegerv(GL_DEPTH_TEST, &DepthTest);
glGetIntegerv(GL_CULL_FACE, &CullFace);
glGetIntegerv(GL_CURRENT_PROGRAM, &Program);
glGetIntegerv(GL_ACTIVE_TEXTURE, &ActiveTexture);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &TextureBinding);
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &VertexArray);
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &FrameBufferBinding);
glGetIntegerv(GL_BLEND, &Blend);
glGetIntegerv(GL_COLOR_WRITEMASK, ColorWritemask);
glGetIntegerv(GL_DITHER, &Dither);
glGetIntegerv(GL_RASTERIZER_DISCARD, &RasterizerDiscard);
if (GlMajorVersion >= 3 && GlMajorVersion >= 2)
glGetIntegerv(GL_SAMPLE_MASK, &SampleMask);
glGetIntegerv(GL_SCISSOR_TEST, &ScissorTest);
IsValid = true;
}
void DistortionRenderer::GraphicsState::Restore()
{
// Don't allow restore-before-save.
if (!IsValid)
return;
glViewport(Viewport[0], Viewport[1], Viewport[2], Viewport[3]);
glClearColor(ClearColor[0], ClearColor[1], ClearColor[2], ClearColor[3]);
ApplyBool(GL_DEPTH_TEST, DepthTest);
ApplyBool(GL_CULL_FACE, CullFace);
glUseProgram(Program);
glActiveTexture(ActiveTexture);
glBindTexture(GL_TEXTURE_2D, TextureBinding);
if (SupportsVao)
glBindVertexArray(VertexArray);
glBindFramebuffer(GL_FRAMEBUFFER, FrameBufferBinding);
ApplyBool(GL_BLEND, Blend);
glColorMask((GLboolean)ColorWritemask[0], (GLboolean)ColorWritemask[1], (GLboolean)ColorWritemask[2], (GLboolean)ColorWritemask[3]);
ApplyBool(GL_DITHER, Dither);
ApplyBool(GL_RASTERIZER_DISCARD, RasterizerDiscard);
if (GlMajorVersion >= 3 && GlMajorVersion >= 2)
ApplyBool(GL_SAMPLE_MASK, SampleMask);
ApplyBool(GL_SCISSOR_TEST, ScissorTest);
}
void DistortionRenderer::initBuffersAndShaders()
{
for ( int eyeNum = 0; eyeNum < 2; eyeNum++ )
{
// Allocate & generate distortion mesh vertices.
ovrDistortionMesh meshData;
// double startT = ovr_GetTimeInSeconds();
if (!ovrHmd_CreateDistortionMesh( HMD,
RState.EyeRenderDesc[eyeNum].Eye,
RState.EyeRenderDesc[eyeNum].Fov,
RState.DistortionCaps,
&meshData) )
{
OVR_ASSERT(false);
continue;
}
// Now parse the vertex data and create a render ready vertex buffer from it
DistortionVertex * pVBVerts = (DistortionVertex*)OVR_ALLOC ( sizeof(DistortionVertex) * meshData.VertexCount );
DistortionVertex * pCurVBVert = pVBVerts;
ovrDistortionVertex* pCurOvrVert = meshData.pVertexData;
for ( unsigned vertNum = 0; vertNum < meshData.VertexCount; vertNum++ )
{
pCurVBVert->Pos.x = pCurOvrVert->Pos.x;
pCurVBVert->Pos.y = pCurOvrVert->Pos.y;
pCurVBVert->TexR = (*(Vector2f*)&pCurOvrVert->TexR);
pCurVBVert->TexG = (*(Vector2f*)&pCurOvrVert->TexG);
pCurVBVert->TexB = (*(Vector2f*)&pCurOvrVert->TexB);
// Convert [0.0f,1.0f] to [0,255]
pCurVBVert->Col.R = (OVR::UByte)( pCurOvrVert->VignetteFactor * 255.99f );
pCurVBVert->Col.G = pCurVBVert->Col.R;
pCurVBVert->Col.B = pCurVBVert->Col.R;
pCurVBVert->Col.A = (OVR::UByte)( pCurOvrVert->TimeWarpFactor * 255.99f );;
pCurOvrVert++;
pCurVBVert++;
}
DistortionMeshVBs[eyeNum] = *new Buffer(&RParams);
DistortionMeshVBs[eyeNum]->Data ( Buffer_Vertex | Buffer_ReadOnly, pVBVerts, sizeof(DistortionVertex) * meshData.VertexCount );
DistortionMeshIBs[eyeNum] = *new Buffer(&RParams);
DistortionMeshIBs[eyeNum]->Data ( Buffer_Index | Buffer_ReadOnly, meshData.pIndexData, ( sizeof(SInt16) * meshData.IndexCount ) );
OVR_FREE ( pVBVerts );
ovrHmd_DestroyDistortionMesh( &meshData );
}
initShaders();
}
void DistortionRenderer::renderDistortion(Texture* leftEyeTexture, Texture* rightEyeTexture)
{
GraphicsState* glState = (GraphicsState*)GfxState.GetPtr();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
setViewport( Recti(0,0, RParams.RTSize.w, RParams.RTSize.h) );
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
glDisable(GL_DITHER);
glDisable(GL_RASTERIZER_DISCARD);
if (glState->GlMajorVersion >= 3 && glState->GlMajorVersion >= 2)
glDisable(GL_SAMPLE_MASK);
glDisable(GL_SCISSOR_TEST);
glClearColor(
RState.ClearColor[0],
RState.ClearColor[1],
RState.ClearColor[2],
RState.ClearColor[3] );
glClear(GL_COLOR_BUFFER_BIT);
for (int eyeNum = 0; eyeNum < 2; eyeNum++)
{
ShaderFill distortionShaderFill(DistortionShader);
distortionShaderFill.SetTexture(0, eyeNum == 0 ? leftEyeTexture : rightEyeTexture);
DistortionShader->SetUniform2f("EyeToSourceUVScale", eachEye[eyeNum].UVScaleOffset[0].x, eachEye[eyeNum].UVScaleOffset[0].y);
DistortionShader->SetUniform2f("EyeToSourceUVOffset", eachEye[eyeNum].UVScaleOffset[1].x, eachEye[eyeNum].UVScaleOffset[1].y);
if (DistortionCaps & ovrDistortionCap_TimeWarp)
{
ovrMatrix4f timeWarpMatrices[2];
ovrHmd_GetEyeTimewarpMatrices(HMD, (ovrEyeType)eyeNum,
RState.EyeRenderPoses[eyeNum], timeWarpMatrices);
// Feed identity like matrices in until we get proper timewarp calculation going on
DistortionShader->SetUniform4x4f("EyeRotationStart", Matrix4f(timeWarpMatrices[0]).Transposed());
DistortionShader->SetUniform4x4f("EyeRotationEnd", Matrix4f(timeWarpMatrices[1]).Transposed());
renderPrimitives(&distortionShaderFill, DistortionMeshVBs[eyeNum], DistortionMeshIBs[eyeNum],
0, (int)DistortionMeshIBs[eyeNum]->GetSize()/2, Prim_Triangles, &DistortionMeshVAOs[eyeNum], true);
}
else
{
renderPrimitives(&distortionShaderFill, DistortionMeshVBs[eyeNum], DistortionMeshIBs[eyeNum],
0, (int)DistortionMeshIBs[eyeNum]->GetSize()/2, Prim_Triangles, &DistortionMeshVAOs[eyeNum], true);
}
}
}
void DistortionRenderer::createDrawQuad()
{
const int numQuadVerts = 4;
LatencyTesterQuadVB = *new Buffer(&RParams);
if(!LatencyTesterQuadVB)
{
return;
}
LatencyTesterQuadVB->Data(Buffer_Vertex, NULL, numQuadVerts * sizeof(LatencyVertex));
LatencyVertex* vertices = (LatencyVertex*)LatencyTesterQuadVB->Map(0, numQuadVerts * sizeof(LatencyVertex), Map_Discard);
if(!vertices)
{
OVR_ASSERT(false); // failed to lock vertex buffer
return;
}
const float left = -1.0f;
const float top = -1.0f;
const float right = 1.0f;
const float bottom = 1.0f;
vertices[0] = LatencyVertex(Vector3f(left, top, 0.0f));
vertices[1] = LatencyVertex(Vector3f(left, bottom, 0.0f));
vertices[2] = LatencyVertex(Vector3f(right, top, 0.0f));
vertices[3] = LatencyVertex(Vector3f(right, bottom, 0.0f));
LatencyTesterQuadVB->Unmap(vertices);
}
void DistortionRenderer::renderLatencyQuad(unsigned char* latencyTesterDrawColor)
{
const int numQuadVerts = 4;
if(!LatencyTesterQuadVB)
{
createDrawQuad();
}
ShaderFill quadFill(SimpleQuadShader);
//quadFill.SetInputLayout(SimpleQuadVertexIL);
setViewport(Recti(0,0, RParams.RTSize.w, RParams.RTSize.h));
SimpleQuadShader->SetUniform2f("Scale", 0.2f, 0.2f);
SimpleQuadShader->SetUniform4f("Color", (float)latencyTesterDrawColor[0] / 255.99f,
(float)latencyTesterDrawColor[0] / 255.99f,
(float)latencyTesterDrawColor[0] / 255.99f,
1.0f);
for(int eyeNum = 0; eyeNum < 2; eyeNum++)
{
SimpleQuadShader->SetUniform2f("PositionOffset", eyeNum == 0 ? -0.4f : 0.4f, 0.0f);
renderPrimitives(&quadFill, LatencyTesterQuadVB, NULL, 0, numQuadVerts, Prim_TriangleStrip, &LatencyVAO, false);
}
}
void DistortionRenderer::renderLatencyPixel(unsigned char* latencyTesterPixelColor)
{
const int numQuadVerts = 4;
if(!LatencyTesterQuadVB)
{
createDrawQuad();
}
ShaderFill quadFill(SimpleQuadShader);
setViewport(Recti(0,0, RParams.RTSize.w, RParams.RTSize.h));
SimpleQuadShader->SetUniform4f("Color", (float)latencyTesterPixelColor[0] / 255.99f,
(float)latencyTesterPixelColor[0] / 255.99f,
(float)latencyTesterPixelColor[0] / 255.99f,
1.0f);
Vector2f scale(2.0f / RParams.RTSize.w, 2.0f / RParams.RTSize.h);
SimpleQuadShader->SetUniform2f("Scale", scale.x, scale.y);
SimpleQuadShader->SetUniform2f("PositionOffset", 1.0f, 1.0f);
renderPrimitives(&quadFill, LatencyTesterQuadVB, NULL, 0, numQuadVerts, Prim_TriangleStrip, &LatencyVAO, false);
}
void DistortionRenderer::renderPrimitives(
const ShaderFill* fill,
Buffer* vertices, Buffer* indices,
int offset, int count,
PrimitiveType rprim, GLuint* vao, bool isDistortionMesh)
{
GraphicsState* glState = (GraphicsState*)GfxState.GetPtr();
GLenum prim;
switch (rprim)
{
case Prim_Triangles:
prim = GL_TRIANGLES;
break;
case Prim_Lines:
prim = GL_LINES;
break;
case Prim_TriangleStrip:
prim = GL_TRIANGLE_STRIP;
break;
default:
OVR_ASSERT(false);
return;
}
fill->Set();
GLuint prog = fill->GetShaders()->Prog;
if (vao != NULL)
{
if (*vao != 0)
{
glBindVertexArray(*vao);
if (isDistortionMesh)
glDrawElements(prim, count, GL_UNSIGNED_SHORT, NULL);
else
glDrawArrays(prim, 0, count);
}
else
{
if (glState->SupportsVao)
{
glGenVertexArrays(1, vao);
glBindVertexArray(*vao);
}
int attributeCount = (isDistortionMesh) ? 5 : 1;
int* locs = new int[attributeCount];
glBindBuffer(GL_ARRAY_BUFFER, ((Buffer*)vertices)->GLBuffer);
if (isDistortionMesh)
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ((Buffer*)indices)->GLBuffer);
locs[0] = glGetAttribLocation(prog, "Position");
locs[1] = glGetAttribLocation(prog, "Color");
locs[2] = glGetAttribLocation(prog, "TexCoord0");
locs[3] = glGetAttribLocation(prog, "TexCoord1");
locs[4] = glGetAttribLocation(prog, "TexCoord2");
glVertexAttribPointer(locs[0], 2, GL_FLOAT, false, sizeof(DistortionVertex), reinterpret_cast<char*>(offset)+offsetof(DistortionVertex, Pos));
glVertexAttribPointer(locs[1], 4, GL_UNSIGNED_BYTE, true, sizeof(DistortionVertex), reinterpret_cast<char*>(offset)+offsetof(DistortionVertex, Col));
glVertexAttribPointer(locs[2], 2, GL_FLOAT, false, sizeof(DistortionVertex), reinterpret_cast<char*>(offset)+offsetof(DistortionVertex, TexR));
glVertexAttribPointer(locs[3], 2, GL_FLOAT, false, sizeof(DistortionVertex), reinterpret_cast<char*>(offset)+offsetof(DistortionVertex, TexG));
glVertexAttribPointer(locs[4], 2, GL_FLOAT, false, sizeof(DistortionVertex), reinterpret_cast<char*>(offset)+offsetof(DistortionVertex, TexB));
}
else
{
locs[0] = glGetAttribLocation(prog, "Position");
glVertexAttribPointer(locs[0], 3, GL_FLOAT, false, sizeof(LatencyVertex), reinterpret_cast<char*>(offset)+offsetof(LatencyVertex, Pos));
}
for (int i = 0; i < attributeCount; ++i)
glEnableVertexAttribArray(locs[i]);
if (isDistortionMesh)
glDrawElements(prim, count, GL_UNSIGNED_SHORT, NULL);
else
glDrawArrays(prim, 0, count);
if (!glState->SupportsVao)
{
for (int i = 0; i < attributeCount; ++i)
glDisableVertexAttribArray(locs[i]);
}
delete[] locs;
}
}
}
void DistortionRenderer::setViewport(const Recti& vp)
{
glViewport(vp.x, vp.y, vp.w, vp.h);
}
void DistortionRenderer::initShaders()
{
GraphicsState* glState = (GraphicsState*)GfxState.GetPtr();
const char* shaderPrefix =
(glState->GlMajorVersion < 3 || (glState->GlMajorVersion == 3 && glState->GlMinorVersion < 2)) ?
glsl2Prefix : glsl3Prefix;
{
ShaderInfo vsInfo = DistortionVertexShaderLookup[DistortionVertexShaderBitMask & DistortionCaps];
size_t vsSize = strlen(shaderPrefix)+vsInfo.ShaderSize;
char* vsSource = new char[vsSize];
OVR_strcpy(vsSource, vsSize, shaderPrefix);
OVR_strcat(vsSource, vsSize, vsInfo.ShaderData);
Ptr<GL::VertexShader> vs = *new GL::VertexShader(
&RParams,
(void*)vsSource, vsSize,
vsInfo.ReflectionData, vsInfo.ReflectionSize);
DistortionShader = *new ShaderSet;
DistortionShader->SetShader(vs);
delete[](vsSource);
ShaderInfo psInfo = DistortionPixelShaderLookup[DistortionPixelShaderBitMask & DistortionCaps];
size_t psSize = strlen(shaderPrefix)+psInfo.ShaderSize;
char* psSource = new char[psSize];
OVR_strcpy(psSource, psSize, shaderPrefix);
OVR_strcat(psSource, psSize, psInfo.ShaderData);
Ptr<GL::FragmentShader> ps = *new GL::FragmentShader(
&RParams,
(void*)psSource, psSize,
psInfo.ReflectionData, psInfo.ReflectionSize);
DistortionShader->SetShader(ps);
delete[](psSource);
}
{
size_t vsSize = strlen(shaderPrefix)+sizeof(SimpleQuad_vs);
char* vsSource = new char[vsSize];
OVR_strcpy(vsSource, vsSize, shaderPrefix);
OVR_strcat(vsSource, vsSize, SimpleQuad_vs);
Ptr<GL::VertexShader> vs = *new GL::VertexShader(
&RParams,
(void*)vsSource, vsSize,
SimpleQuad_vs_refl, sizeof(SimpleQuad_vs_refl) / sizeof(SimpleQuad_vs_refl[0]));
SimpleQuadShader = *new ShaderSet;
SimpleQuadShader->SetShader(vs);
delete[](vsSource);
size_t psSize = strlen(shaderPrefix)+sizeof(SimpleQuad_fs);
char* psSource = new char[psSize];
OVR_strcpy(psSource, psSize, shaderPrefix);
OVR_strcat(psSource, psSize, SimpleQuad_fs);
Ptr<GL::FragmentShader> ps = *new GL::FragmentShader(
&RParams,
(void*)psSource, psSize,
SimpleQuad_fs_refl, sizeof(SimpleQuad_fs_refl) / sizeof(SimpleQuad_fs_refl[0]));
SimpleQuadShader->SetShader(ps);
delete[](psSource);
}
}
void DistortionRenderer::destroy()
{
GraphicsState* glState = (GraphicsState*)GfxState.GetPtr();
for(int eyeNum = 0; eyeNum < 2; eyeNum++)
{
if (glState->SupportsVao)
glDeleteVertexArrays(1, &DistortionMeshVAOs[eyeNum]);
DistortionMeshVAOs[eyeNum] = 0;
DistortionMeshVBs[eyeNum].Clear();
DistortionMeshIBs[eyeNum].Clear();
}
if (DistortionShader)
{
DistortionShader->UnsetShader(Shader_Vertex);
DistortionShader->UnsetShader(Shader_Pixel);
DistortionShader.Clear();
}
LatencyTesterQuadVB.Clear();
LatencyVAO = 0;
}
}}} // OVR::CAPI::GL

View File

@ -0,0 +1,178 @@
/************************************************************************************
Filename : CAPI_GL_DistortionRenderer.h
Content : Distortion renderer header for GL
Created : November 11, 2013
Authors : David Borel, Lee Cooper
Copyright : Copyright 2013 Oculus VR, Inc. 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
otherwise accompanies this software in either electronic or hard copy form.
************************************************************************************/
#ifndef OVR_CAPI_GL_DistortionRenderer_h
#define OVR_CAPI_GL_DistortionRenderer_h
#include "../CAPI_DistortionRenderer.h"
#include "../../Kernel/OVR_Log.h"
#include "CAPI_GL_Util.h"
namespace OVR { namespace CAPI { namespace GL {
// ***** GL::DistortionRenderer
// Implementation of DistortionRenderer for GL.
class DistortionRenderer : public CAPI::DistortionRenderer
{
public:
DistortionRenderer(ovrHmd hmd,
FrameTimeManager& timeManager,
const HMDRenderState& renderState);
~DistortionRenderer();
// Creation function for the device.
static CAPI::DistortionRenderer* Create(ovrHmd hmd,
FrameTimeManager& timeManager,
const HMDRenderState& renderState);
// ***** Public DistortionRenderer interface
virtual bool Initialize(const ovrRenderAPIConfig* apiConfig,
unsigned distortionCaps);
virtual void SubmitEye(int eyeId, ovrTexture* eyeTexture);
virtual void EndFrame(bool swapBuffers, unsigned char* latencyTesterDrawColor, unsigned char* latencyTester2DrawColor);
void WaitUntilGpuIdle();
// Similar to ovr_WaitTillTime but it also flushes GPU.
// Note, it exits when time expires, even if GPU is not in idle state yet.
double FlushGpuAndWaitTillTime(double absTime);
protected:
class GraphicsState : public CAPI::DistortionRenderer::GraphicsState
{
public:
GraphicsState();
virtual void Save();
virtual void Restore();
protected:
void ApplyBool(GLenum Name, GLint Value);
public:
GLint GlMajorVersion;
GLint GlMinorVersion;
bool SupportsVao;
GLint Viewport[4];
GLfloat ClearColor[4];
GLint DepthTest;
GLint CullFace;
GLint Program;
GLint ActiveTexture;
GLint TextureBinding;
GLint VertexArray;
GLint FrameBufferBinding;
GLint Blend;
GLint ColorWritemask[4];
GLint Dither;
GLint Fog;
GLint Lighting;
GLint RasterizerDiscard;
GLint RenderMode;
GLint SampleMask;
GLint ScissorTest;
GLfloat ZoomX;
GLfloat ZoomY;
};
// TBD: Should we be using oe from RState instead?
unsigned DistortionCaps;
struct FOR_EACH_EYE
{
FOR_EACH_EYE() : TextureSize(0), RenderViewport(Sizei(0)) { }
#if 0
IDirect3DVertexBuffer9 * dxVerts;
IDirect3DIndexBuffer9 * dxIndices;
#endif
int numVerts;
int numIndices;
GLuint texture;
ovrVector2f UVScaleOffset[2];
Sizei TextureSize;
Recti RenderViewport;
} eachEye[2];
// GL context and utility variables.
RenderParams RParams;
// Helpers
void initBuffersAndShaders();
void initShaders();
void initFullscreenQuad();
void destroy();
void setViewport(const Recti& vp);
void renderDistortion(Texture* leftEyeTexture, Texture* rightEyeTexture);
void renderPrimitives(const ShaderFill* fill, Buffer* vertices, Buffer* indices,
int offset, int count,
PrimitiveType rprim, GLuint* vao, bool isDistortionMesh);
void createDrawQuad();
void renderLatencyQuad(unsigned char* latencyTesterDrawColor);
void renderLatencyPixel(unsigned char* latencyTesterPixelColor);
Ptr<Texture> pEyeTextures[2];
Ptr<Buffer> DistortionMeshVBs[2]; // one per-eye
Ptr<Buffer> DistortionMeshIBs[2]; // one per-eye
GLuint DistortionMeshVAOs[2]; // one per-eye
Ptr<ShaderSet> DistortionShader;
struct StandardUniformData
{
Matrix4f Proj;
Matrix4f View;
} StdUniforms;
GLuint LatencyVAO;
Ptr<Buffer> LatencyTesterQuadVB;
Ptr<ShaderSet> SimpleQuadShader;
Ptr<Texture> CurRenderTarget;
Array<Ptr<Texture> > DepthBuffers;
GLuint CurrentFbo;
GLint SavedViewport[4];
GLfloat SavedClearColor[4];
GLint SavedDepthTest;
GLint SavedCullFace;
GLint SavedProgram;
GLint SavedActiveTexture;
GLint SavedBoundTexture;
GLint SavedVertexArray;
GLint SavedBoundFrameBuffer;
};
}}} // OVR::CAPI::GL
#endif // OVR_CAPI_GL_DistortionRenderer_h

View File

@ -0,0 +1,326 @@
/************************************************************************************
Filename : CAPI_GL_Shaders.h
Content : Distortion shader header for GL
Created : November 11, 2013
Authors : David Borel, Volga Aksoy
Copyright : Copyright 2013 Oculus VR, Inc. 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
otherwise accompanies this software in either electronic or hard copy form.
************************************************************************************/
#ifndef OVR_CAPI_GL_Shaders_h
#define OVR_CAPI_GL_Shaders_h
#include "CAPI_GL_Util.h"
namespace OVR { namespace CAPI { namespace GL {
static const char glsl2Prefix[] =
"#version 110\n"
"#extension GL_ARB_shader_texture_lod : enable\n"
"#define _FRAGCOLOR_DECLARATION\n"
"#define _VS_IN attribute\n"
"#define _VS_OUT varying\n"
"#define _FS_IN varying\n"
"#define _TEXTURELOD texture2DLod\n"
"#define _FRAGCOLOR gl_FragColor\n";
static const char glsl3Prefix[] =
"#version 150\n"
"#define _FRAGCOLOR_DECLARATION out vec4 FragColor;\n"
"#define _VS_IN in\n"
"#define _VS_OUT out\n"
"#define _FS_IN in\n"
"#define _TEXTURELOD textureLod\n"
"#define _FRAGCOLOR FragColor\n";
static const char SimpleQuad_vs[] =
"uniform vec2 PositionOffset;\n"
"uniform vec2 Scale;\n"
"_VS_IN vec3 Position;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(Position.xy * Scale + PositionOffset, 0.5, 1.0);\n"
"}\n";
const OVR::CAPI::GL::ShaderBase::Uniform SimpleQuad_vs_refl[] =
{
{ "PositionOffset", OVR::CAPI::GL::ShaderBase::VARTYPE_FLOAT, 0, 8 },
{ "Scale", OVR::CAPI::GL::ShaderBase::VARTYPE_FLOAT, 8, 8 },
};
static const char SimpleQuad_fs[] =
"uniform vec4 Color;\n"
"_FRAGCOLOR_DECLARATION\n"
"void main()\n"
"{\n"
" _FRAGCOLOR = Color;\n"
"}\n";
const OVR::CAPI::GL::ShaderBase::Uniform SimpleQuad_fs_refl[] =
{
{ "Color", OVR::CAPI::GL::ShaderBase::VARTYPE_FLOAT, 0, 16 },
};
static const char Distortion_vs[] =
"uniform vec2 EyeToSourceUVScale;\n"
"uniform vec2 EyeToSourceUVOffset;\n"
"_VS_IN vec2 Position;\n"
"_VS_IN vec4 Color;\n"
"_VS_IN vec2 TexCoord0;\n"
"_VS_OUT vec4 oColor;\n"
"_VS_OUT vec2 oTexCoord0;\n"
"void main()\n"
"{\n"
" gl_Position.x = Position.x;\n"
" gl_Position.y = Position.y;\n"
" gl_Position.z = 0.5;\n"
" gl_Position.w = 1.0;\n"
// Vertex inputs are in TanEyeAngle space for the R,G,B channels (i.e. after chromatic aberration and distortion).
// Scale them into the correct [0-1],[0-1] UV lookup space (depending on eye)
" oTexCoord0 = TexCoord0 * EyeToSourceUVScale + EyeToSourceUVOffset;\n"
" oTexCoord0.y = 1.0 - oTexCoord0.y;\n"
" oColor = Color;\n" // Used for vignette fade.
"}\n";
const OVR::CAPI::GL::ShaderBase::Uniform Distortion_vs_refl[] =
{
{ "EyeToSourceUVScale", OVR::CAPI::GL::ShaderBase::VARTYPE_FLOAT, 0, 8 },
{ "EyeToSourceUVOffset", OVR::CAPI::GL::ShaderBase::VARTYPE_FLOAT, 8, 8 },
};
static const char Distortion_fs[] =
"uniform sampler2D Texture0;\n"
"_FS_IN vec4 oColor;\n"
"_FS_IN vec2 oTexCoord0;\n"
"_FRAGCOLOR_DECLARATION\n"
"void main()\n"
"{\n"
" _FRAGCOLOR = _TEXTURELOD(Texture0, oTexCoord0, 0.0);\n"
" _FRAGCOLOR.a = 1.0;\n"
"}\n";
static const char DistortionTimewarp_vs[] =
"uniform vec2 EyeToSourceUVScale;\n"
"uniform vec2 EyeToSourceUVOffset;\n"
"uniform mat4 EyeRotationStart;\n"
"uniform mat4 EyeRotationEnd;\n"
"_VS_IN vec2 Position;\n"
"_VS_IN vec4 Color;\n"
"_VS_IN vec2 TexCoord0;\n"
"_FS_IN vec4 oColor;\n"
"_FS_IN vec2 oTexCoord0;\n"
"void main()\n"
"{\n"
" gl_Position.x = Position.x;\n"
" gl_Position.y = Position.y;\n"
" gl_Position.z = 0.0;\n"
" gl_Position.w = 1.0;\n"
// Vertex inputs are in TanEyeAngle space for the R,G,B channels (i.e. after chromatic aberration and distortion).
// These are now "real world" vectors in direction (x,y,1) relative to the eye of the HMD.
" vec3 TanEyeAngle = vec3 ( TexCoord0.x, TexCoord0.y, 1.0 );\n"
// Accurate time warp lerp vs. faster
#if 1
// Apply the two 3x3 timewarp rotations to these vectors.
" vec3 TransformedStart = (EyeRotationStart * vec4(TanEyeAngle, 0)).xyz;\n"
" vec3 TransformedEnd = (EyeRotationEnd * vec4(TanEyeAngle, 0)).xyz;\n"
// And blend between them.
" vec3 Transformed = mix ( TransformedStart, TransformedEnd, Color.a );\n"
#else
" mat4 EyeRotation = mix ( EyeRotationStart, EyeRotationEnd, Color.a );\n"
" vec3 Transformed = EyeRotation * TanEyeAngle;\n"
#endif
// Project them back onto the Z=1 plane of the rendered images.
" float RecipZ = 1.0 / Transformed.z;\n"
" vec2 Flattened = vec2 ( Transformed.x * RecipZ, Transformed.y * RecipZ );\n"
// These are now still in TanEyeAngle space.
// Scale them into the correct [0-1],[0-1] UV lookup space (depending on eye)
" vec2 SrcCoord = Flattened * EyeToSourceUVScale + EyeToSourceUVOffset;\n"
" oTexCoord0 = SrcCoord;\n"
" oTexCoord0.y = 1.0-oTexCoord0.y;\n"
" oColor = vec4(Color.r, Color.r, Color.r, Color.r);\n" // Used for vignette fade.
"}\n";
const OVR::CAPI::GL::ShaderBase::Uniform DistortionTimewarp_vs_refl[] =
{
{ "EyeToSourceUVScale", OVR::CAPI::GL::ShaderBase::VARTYPE_FLOAT, 0, 8 },
{ "EyeToSourceUVOffset", OVR::CAPI::GL::ShaderBase::VARTYPE_FLOAT, 8, 8 },
};
static const char DistortionChroma_vs[] =
"uniform vec2 EyeToSourceUVScale;\n"
"uniform vec2 EyeToSourceUVOffset;\n"
"_VS_IN vec2 Position;\n"
"_VS_IN vec4 Color;\n"
"_VS_IN vec2 TexCoord0;\n"
"_VS_IN vec2 TexCoord1;\n"
"_VS_IN vec2 TexCoord2;\n"
"_VS_OUT vec4 oColor;\n"
"_VS_OUT vec2 oTexCoord0;\n"
"_VS_OUT vec2 oTexCoord1;\n"
"_VS_OUT vec2 oTexCoord2;\n"
"void main()\n"
"{\n"
" gl_Position.x = Position.x;\n"
" gl_Position.y = Position.y;\n"
" gl_Position.z = 0.5;\n"
" gl_Position.w = 1.0;\n"
// Vertex inputs are in TanEyeAngle space for the R,G,B channels (i.e. after chromatic aberration and distortion).
// Scale them into the correct [0-1],[0-1] UV lookup space (depending on eye)
" oTexCoord0 = TexCoord0 * EyeToSourceUVScale + EyeToSourceUVOffset;\n"
" oTexCoord0.y = 1.0-oTexCoord0.y;\n"
" oTexCoord1 = TexCoord1 * EyeToSourceUVScale + EyeToSourceUVOffset;\n"
" oTexCoord1.y = 1.0-oTexCoord1.y;\n"
" oTexCoord2 = TexCoord2 * EyeToSourceUVScale + EyeToSourceUVOffset;\n"
" oTexCoord2.y = 1.0-oTexCoord2.y;\n"
" oColor = Color;\n" // Used for vignette fade.
"}\n";
const OVR::CAPI::GL::ShaderBase::Uniform DistortionChroma_vs_refl[] =
{
{ "EyeToSourceUVScale", OVR::CAPI::GL::ShaderBase::VARTYPE_FLOAT, 0, 8 },
{ "EyeToSourceUVOffset", OVR::CAPI::GL::ShaderBase::VARTYPE_FLOAT, 8, 8 },
};
static const char DistortionChroma_fs[] =
"uniform sampler2D Texture0;\n"
"_FS_IN vec4 oColor;\n"
"_FS_IN vec2 oTexCoord0;\n"
"_FS_IN vec2 oTexCoord1;\n"
"_FS_IN vec2 oTexCoord2;\n"
"_FRAGCOLOR_DECLARATION\n"
"void main()\n"
"{\n"
" float ResultR = _TEXTURELOD(Texture0, oTexCoord0, 0.0).r;\n"
" float ResultG = _TEXTURELOD(Texture0, oTexCoord1, 0.0).g;\n"
" float ResultB = _TEXTURELOD(Texture0, oTexCoord2, 0.0).b;\n"
" _FRAGCOLOR = vec4(ResultR * oColor.r, ResultG * oColor.g, ResultB * oColor.b, 1.0);\n"
"}\n";
static const char DistortionTimewarpChroma_vs[] =
"uniform vec2 EyeToSourceUVScale;\n"
"uniform vec2 EyeToSourceUVOffset;\n"
"uniform mat4 EyeRotationStart;\n"
"uniform mat4 EyeRotationEnd;\n"
"_VS_IN vec2 Position;\n"
"_VS_IN vec4 Color;\n"
"_VS_IN vec2 TexCoord0;\n"
"_VS_IN vec2 TexCoord1;\n"
"_VS_IN vec2 TexCoord2;\n"
"_VS_OUT vec4 oColor;\n"
"_VS_OUT vec2 oTexCoord0;\n"
"_VS_OUT vec2 oTexCoord1;\n"
"_VS_OUT vec2 oTexCoord2;\n"
"void main()\n"
"{\n"
" gl_Position.x = Position.x;\n"
" gl_Position.y = Position.y;\n"
" gl_Position.z = 0.0;\n"
" gl_Position.w = 1.0;\n"
// Vertex inputs are in TanEyeAngle space for the R,G,B channels (i.e. after chromatic aberration and distortion).
// These are now "real world" vectors in direction (x,y,1) relative to the eye of the HMD.
" vec3 TanEyeAngleR = vec3 ( TexCoord0.x, TexCoord0.y, 1.0 );\n"
" vec3 TanEyeAngleG = vec3 ( TexCoord1.x, TexCoord1.y, 1.0 );\n"
" vec3 TanEyeAngleB = vec3 ( TexCoord2.x, TexCoord2.y, 1.0 );\n"
// Accurate time warp lerp vs. faster
#if 1
// Apply the two 3x3 timewarp rotations to these vectors.
" vec3 TransformedRStart = (EyeRotationStart * vec4(TanEyeAngleR, 0)).xyz;\n"
" vec3 TransformedGStart = (EyeRotationStart * vec4(TanEyeAngleG, 0)).xyz;\n"
" vec3 TransformedBStart = (EyeRotationStart * vec4(TanEyeAngleB, 0)).xyz;\n"
" vec3 TransformedREnd = (EyeRotationEnd * vec4(TanEyeAngleR, 0)).xyz;\n"
" vec3 TransformedGEnd = (EyeRotationEnd * vec4(TanEyeAngleG, 0)).xyz;\n"
" vec3 TransformedBEnd = (EyeRotationEnd * vec4(TanEyeAngleB, 0)).xyz;\n"
// And blend between them.
" vec3 TransformedR = mix ( TransformedRStart, TransformedREnd, Color.a );\n"
" vec3 TransformedG = mix ( TransformedGStart, TransformedGEnd, Color.a );\n"
" vec3 TransformedB = mix ( TransformedBStart, TransformedBEnd, Color.a );\n"
#else
" mat3 EyeRotation;\n"
" EyeRotation[0] = mix ( EyeRotationStart[0], EyeRotationEnd[0], Color.a ).xyz;\n"
" EyeRotation[1] = mix ( EyeRotationStart[1], EyeRotationEnd[1], Color.a ).xyz;\n"
" EyeRotation[2] = mix ( EyeRotationStart[2], EyeRotationEnd[2], Color.a ).xyz;\n"
" vec3 TransformedR = EyeRotation * TanEyeAngleR;\n"
" vec3 TransformedG = EyeRotation * TanEyeAngleG;\n"
" vec3 TransformedB = EyeRotation * TanEyeAngleB;\n"
#endif
// Project them back onto the Z=1 plane of the rendered images.
" float RecipZR = 1.0 / TransformedR.z;\n"
" float RecipZG = 1.0 / TransformedG.z;\n"
" float RecipZB = 1.0 / TransformedB.z;\n"
" vec2 FlattenedR = vec2 ( TransformedR.x * RecipZR, TransformedR.y * RecipZR );\n"
" vec2 FlattenedG = vec2 ( TransformedG.x * RecipZG, TransformedG.y * RecipZG );\n"
" vec2 FlattenedB = vec2 ( TransformedB.x * RecipZB, TransformedB.y * RecipZB );\n"
// These are now still in TanEyeAngle space.
// Scale them into the correct [0-1],[0-1] UV lookup space (depending on eye)
" vec2 SrcCoordR = FlattenedR * EyeToSourceUVScale + EyeToSourceUVOffset;\n"
" vec2 SrcCoordG = FlattenedG * EyeToSourceUVScale + EyeToSourceUVOffset;\n"
" vec2 SrcCoordB = FlattenedB * EyeToSourceUVScale + EyeToSourceUVOffset;\n"
" oTexCoord0 = SrcCoordR;\n"
" oTexCoord0.y = 1.0-oTexCoord0.y;\n"
" oTexCoord1 = SrcCoordG;\n"
" oTexCoord1.y = 1.0-oTexCoord1.y;\n"
" oTexCoord2 = SrcCoordB;\n"
" oTexCoord2.y = 1.0-oTexCoord2.y;\n"
" oColor = vec4(Color.r, Color.r, Color.r, Color.r);\n" // Used for vignette fade.
"}\n";
const OVR::CAPI::GL::ShaderBase::Uniform DistortionTimewarpChroma_vs_refl[] =
{
{ "EyeToSourceUVScale", OVR::CAPI::GL::ShaderBase::VARTYPE_FLOAT, 0, 8 },
{ "EyeToSourceUVOffset", OVR::CAPI::GL::ShaderBase::VARTYPE_FLOAT, 8, 8 },
{ "EyeRotationStart", OVR::CAPI::GL::ShaderBase::VARTYPE_FLOAT, 16, 64 },
{ "EyeRotationEnd", OVR::CAPI::GL::ShaderBase::VARTYPE_FLOAT, 80, 64 },
};
}}} // OVR::CAPI::GL
#endif // OVR_CAPI_GL_Shaders_h

View File

@ -0,0 +1,530 @@
/************************************************************************************
Filename : Render_GL_Device.cpp
Content : RenderDevice implementation for OpenGL
Created : September 10, 2012
Authors : David Borel, Andrew Reisse
Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
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 "CAPI_GL_Util.h"
#include "../../Kernel/OVR_Log.h"
#include <string.h>
namespace OVR { namespace CAPI { namespace GL {
// GL Hooks for non-Mac.
#if !defined(OVR_OS_MAC)
#if defined(OVR_OS_WIN32)
PFNWGLGETPROCADDRESS wglGetProcAddress;
PFNGLENABLEPROC glEnable;
PFNGLDISABLEPROC glDisable;
PFNGLGETFLOATVPROC glGetFloatv;
PFNGLGETINTEGERVPROC glGetIntegerv;
PFNGLGETSTRINGPROC glGetString;
PFNGLCOLORMASKPROC glColorMask;
PFNGLCLEARPROC glClear;
PFNGLCLEARCOLORPROC glClearColor;
PFNGLCLEARDEPTHPROC glClearDepth;
PFNGLVIEWPORTPROC glViewport;
PFNGLDRAWELEMENTSPROC glDrawElements;
PFNGLTEXPARAMETERIPROC glTexParameteri;
PFNGLFLUSHPROC glFlush;
PFNGLFINISHPROC glFinish;
PFNGLDRAWARRAYSPROC glDrawArrays;
PFNGLGENTEXTURESPROC glGenTextures;
PFNGLDELETETEXTURESPROC glDeleteTextures;
PFNGLBINDTEXTUREPROC glBindTexture;
PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT;
PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT;
#elif defined(OVR_OS_LINUX)
PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT;
#endif
PFNGLDELETESHADERPROC glDeleteShader;
PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
PFNGLACTIVETEXTUREPROC glActiveTexture;
PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray;
PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer;
PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray;
PFNGLBINDBUFFERPROC glBindBuffer;
PFNGLUNIFORMMATRIX3FVPROC glUniformMatrix3fv;
PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv;
PFNGLDELETEBUFFERSPROC glDeleteBuffers;
PFNGLBUFFERDATAPROC glBufferData;
PFNGLGENBUFFERSPROC glGenBuffers;
PFNGLMAPBUFFERPROC glMapBuffer;
PFNGLUNMAPBUFFERPROC glUnmapBuffer;
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
PFNGLGETSHADERIVPROC glGetShaderiv;
PFNGLCOMPILESHADERPROC glCompileShader;
PFNGLSHADERSOURCEPROC glShaderSource;
PFNGLCREATESHADERPROC glCreateShader;
PFNGLCREATEPROGRAMPROC glCreateProgram;
PFNGLATTACHSHADERPROC glAttachShader;
PFNGLDETACHSHADERPROC glDetachShader;
PFNGLDELETEPROGRAMPROC glDeleteProgram;
PFNGLUNIFORM1IPROC glUniform1i;
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
PFNGLGETACTIVEUNIFORMPROC glGetActiveUniform;
PFNGLUSEPROGRAMPROC glUseProgram;
PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
PFNGLGETPROGRAMIVPROC glGetProgramiv;
PFNGLLINKPROGRAMPROC glLinkProgram;
PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation;
PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation;
PFNGLUNIFORM4FVPROC glUniform4fv;
PFNGLUNIFORM3FVPROC glUniform3fv;
PFNGLUNIFORM2FVPROC glUniform2fv;
PFNGLUNIFORM1FVPROC glUniform1fv;
PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;
PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays;
PFNGLBINDVERTEXARRAYPROC glBindVertexArray;
#if defined(OVR_OS_WIN32)
void* GetFunction(const char* functionName)
{
return wglGetProcAddress(functionName);
}
#else
void (*GetFunction(const char *functionName))( void )
{
return glXGetProcAddress((GLubyte*)functionName);
}
#endif
void InitGLExtensions()
{
if (glGenVertexArrays)
return;
#if defined(OVR_OS_WIN32)
HINSTANCE hInst = LoadLibrary(L"Opengl32.dll");
if (!hInst)
return;
glGetFloatv = (PFNGLGETFLOATVPROC) GetProcAddress(hInst, "glGetFloatv");
glGetIntegerv = (PFNGLGETINTEGERVPROC) GetProcAddress(hInst, "glGetIntegerv");
glGetString = (PFNGLGETSTRINGPROC) GetProcAddress(hInst, "glGetString");
glEnable = (PFNGLENABLEPROC) GetProcAddress(hInst, "glEnable");
glDisable = (PFNGLDISABLEPROC) GetProcAddress(hInst, "glDisable");
glColorMask = (PFNGLCOLORMASKPROC) GetProcAddress(hInst, "glColorMask");
glClear = (PFNGLCLEARPROC) GetProcAddress(hInst, "glClear" );
glClearColor = (PFNGLCLEARCOLORPROC) GetProcAddress(hInst, "glClearColor");
glClearDepth = (PFNGLCLEARDEPTHPROC) GetProcAddress(hInst, "glClearDepth");
glViewport = (PFNGLVIEWPORTPROC) GetProcAddress(hInst, "glViewport");
glFlush = (PFNGLFLUSHPROC) GetProcAddress(hInst, "glFlush");
glFinish = (PFNGLFINISHPROC) GetProcAddress(hInst, "glFinish");
glDrawArrays = (PFNGLDRAWARRAYSPROC) GetProcAddress(hInst, "glDrawArrays");
glDrawElements = (PFNGLDRAWELEMENTSPROC) GetProcAddress(hInst, "glDrawElements");
glGenTextures = (PFNGLGENTEXTURESPROC) GetProcAddress(hInst,"glGenTextures");
glDeleteTextures = (PFNGLDELETETEXTURESPROC) GetProcAddress(hInst,"glDeleteTextures");
glBindTexture = (PFNGLBINDTEXTUREPROC) GetProcAddress(hInst,"glBindTexture");
glTexParameteri = (PFNGLTEXPARAMETERIPROC) GetProcAddress(hInst, "glTexParameteri");
wglGetProcAddress = (PFNWGLGETPROCADDRESS) GetProcAddress(hInst, "wglGetProcAddress");
wglGetSwapIntervalEXT = (PFNWGLGETSWAPINTERVALEXTPROC) GetFunction("wglGetSwapIntervalEXT");
wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC) GetFunction("wglSwapIntervalEXT");
#elif defined(OVR_OS_LINUX)
glXSwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC) GetFunction("glXSwapIntervalEXT");
#endif
glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC) GetFunction("glBindFramebufferEXT");
glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC) GetFunction("glGenVertexArrays");
glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC) GetFunction("glDeleteVertexArrays");
glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC) GetFunction("glBindVertexArray");
glGenBuffers = (PFNGLGENBUFFERSPROC) GetFunction("glGenBuffers");
glDeleteBuffers = (PFNGLDELETEBUFFERSPROC) GetFunction("glDeleteBuffers");
glBindBuffer = (PFNGLBINDBUFFERPROC) GetFunction("glBindBuffer");
glBufferData = (PFNGLBUFFERDATAPROC) GetFunction("glBufferData");
glMapBuffer = (PFNGLMAPBUFFERPROC) GetFunction("glMapBuffer");
glUnmapBuffer = (PFNGLUNMAPBUFFERPROC) GetFunction("glUnmapBuffer");
glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC) GetFunction("glDisableVertexAttribArray");
glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC) GetFunction("glVertexAttribPointer");
glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC) GetFunction("glEnableVertexAttribArray");
glActiveTexture = (PFNGLACTIVETEXTUREPROC) GetFunction("glActiveTexture");
glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC) GetFunction("glUniformMatrix3fv");
glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC) GetFunction("glUniformMatrix4fv");
glUniform1i = (PFNGLUNIFORM1IPROC) GetFunction("glUniform1i");
glUniform1fv = (PFNGLUNIFORM1FVPROC) GetFunction("glUniform1fv");
glUniform2fv = (PFNGLUNIFORM2FVPROC) GetFunction("glUniform2fv");
glUniform3fv = (PFNGLUNIFORM3FVPROC) GetFunction("glUniform3fv");
glUniform2fv = (PFNGLUNIFORM2FVPROC) GetFunction("glUniform2fv");
glUniform4fv = (PFNGLUNIFORM4FVPROC) GetFunction("glUniform4fv");
glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) GetFunction("glGetUniformLocation");
glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC) GetFunction("glGetActiveUniform");
glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) GetFunction("glGetShaderInfoLog");
glGetShaderiv = (PFNGLGETSHADERIVPROC) GetFunction("glGetShaderiv");
glCompileShader = (PFNGLCOMPILESHADERPROC) GetFunction("glCompileShader");
glShaderSource = (PFNGLSHADERSOURCEPROC) GetFunction("glShaderSource");
glCreateShader = (PFNGLCREATESHADERPROC) GetFunction("glCreateShader");
glDeleteShader = (PFNGLDELETESHADERPROC) GetFunction("glDeleteShader");
glCreateProgram = (PFNGLCREATEPROGRAMPROC) GetFunction("glCreateProgram");
glDeleteProgram = (PFNGLDELETEPROGRAMPROC) GetFunction("glDeleteProgram");
glUseProgram = (PFNGLUSEPROGRAMPROC) GetFunction("glUseProgram");
glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) GetFunction("glGetProgramInfoLog");
glGetProgramiv = (PFNGLGETPROGRAMIVPROC) GetFunction("glGetProgramiv");
glLinkProgram = (PFNGLLINKPROGRAMPROC) GetFunction("glLinkProgram");
glAttachShader = (PFNGLATTACHSHADERPROC) GetFunction("glAttachShader");
glDetachShader = (PFNGLDETACHSHADERPROC) GetFunction("glDetachShader");
glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC) GetFunction("glBindAttribLocation");
glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC) GetFunction("glGetAttribLocation");
}
#endif
Buffer::Buffer(RenderParams* rp) : pParams(rp), Size(0), Use(0), GLBuffer(0)
{
}
Buffer::~Buffer()
{
if (GLBuffer)
glDeleteBuffers(1, &GLBuffer);
}
bool Buffer::Data(int use, const void* buffer, size_t size)
{
Size = size;
switch (use & Buffer_TypeMask)
{
case Buffer_Index: Use = GL_ELEMENT_ARRAY_BUFFER; break;
default: Use = GL_ARRAY_BUFFER; break;
}
if (!GLBuffer)
glGenBuffers(1, &GLBuffer);
int mode = GL_DYNAMIC_DRAW;
if (use & Buffer_ReadOnly)
mode = GL_STATIC_DRAW;
glBindBuffer(Use, GLBuffer);
glBufferData(Use, size, buffer, mode);
return 1;
}
void* Buffer::Map(size_t, size_t, int)
{
int mode = GL_WRITE_ONLY;
//if (flags & Map_Unsynchronized)
// mode |= GL_MAP_UNSYNCHRONIZED;
glBindBuffer(Use, GLBuffer);
void* v = glMapBuffer(Use, mode);
return v;
}
bool Buffer::Unmap(void*)
{
glBindBuffer(Use, GLBuffer);
int r = glUnmapBuffer(Use);
return r != 0;
}
ShaderSet::ShaderSet()
{
Prog = glCreateProgram();
}
ShaderSet::~ShaderSet()
{
glDeleteProgram(Prog);
}
GLint ShaderSet::GetGLShader(Shader* s)
{
switch (s->Stage)
{
case Shader_Vertex: {
ShaderImpl<Shader_Vertex, GL_VERTEX_SHADER>* gls = (ShaderImpl<Shader_Vertex, GL_VERTEX_SHADER>*)s;
return gls->GLShader;
} break;
case Shader_Fragment: {
ShaderImpl<Shader_Fragment, GL_FRAGMENT_SHADER>* gls = (ShaderImpl<Shader_Fragment, GL_FRAGMENT_SHADER>*)s;
return gls->GLShader;
} break;
default: break;
}
return -1;
}
void ShaderSet::SetShader(Shader *s)
{
Shaders[s->Stage] = s;
GLint GLShader = GetGLShader(s);
glAttachShader(Prog, GLShader);
if (Shaders[Shader_Vertex] && Shaders[Shader_Fragment])
Link();
}
void ShaderSet::UnsetShader(int stage)
{
if (Shaders[stage] == NULL)
return;
GLint GLShader = GetGLShader(Shaders[stage]);
glDetachShader(Prog, GLShader);
Shaders[stage] = NULL;
}
bool ShaderSet::SetUniform(const char* name, int n, const float* v)
{
for (unsigned int i = 0; i < UniformInfo.GetSize(); i++)
if (!strcmp(UniformInfo[i].Name.ToCStr(), name))
{
OVR_ASSERT(UniformInfo[i].Location >= 0);
glUseProgram(Prog);
switch (UniformInfo[i].Type)
{
case 1: glUniform1fv(UniformInfo[i].Location, n, v); break;
case 2: glUniform2fv(UniformInfo[i].Location, n/2, v); break;
case 3: glUniform3fv(UniformInfo[i].Location, n/3, v); break;
case 4: glUniform4fv(UniformInfo[i].Location, n/4, v); break;
case 12: glUniformMatrix3fv(UniformInfo[i].Location, 1, 1, v); break;
case 16: glUniformMatrix4fv(UniformInfo[i].Location, 1, 1, v); break;
default: OVR_ASSERT(0);
}
return 1;
}
OVR_DEBUG_LOG(("Warning: uniform %s not present in selected shader", name));
return 0;
}
bool ShaderSet::Link()
{
glLinkProgram(Prog);
GLint r;
glGetProgramiv(Prog, GL_LINK_STATUS, &r);
if (!r)
{
GLchar msg[1024];
glGetProgramInfoLog(Prog, sizeof(msg), 0, msg);
OVR_DEBUG_LOG(("Linking shaders failed: %s\n", msg));
if (!r)
return 0;
}
glUseProgram(Prog);
UniformInfo.Clear();
LightingVer = 0;
UsesLighting = 0;
GLint uniformCount = 0;
glGetProgramiv(Prog, GL_ACTIVE_UNIFORMS, &uniformCount);
OVR_ASSERT(uniformCount >= 0);
for(GLuint i = 0; i < (GLuint)uniformCount; i++)
{
GLsizei namelen;
GLint size = 0;
GLenum type;
GLchar name[32];
glGetActiveUniform(Prog, i, sizeof(name), &namelen, &size, &type, name);
if (size)
{
int l = glGetUniformLocation(Prog, name);
char *np = name;
while (*np)
{
if (*np == '[')
*np = 0;
np++;
}
Uniform u;
u.Name = name;
u.Location = l;
u.Size = size;
switch (type)
{
case GL_FLOAT: u.Type = 1; break;
case GL_FLOAT_VEC2: u.Type = 2; break;
case GL_FLOAT_VEC3: u.Type = 3; break;
case GL_FLOAT_VEC4: u.Type = 4; break;
case GL_FLOAT_MAT3: u.Type = 12; break;
case GL_FLOAT_MAT4: u.Type = 16; break;
default:
continue;
}
UniformInfo.PushBack(u);
if (!strcmp(name, "LightCount"))
UsesLighting = 1;
}
else
break;
}
ProjLoc = glGetUniformLocation(Prog, "Proj");
ViewLoc = glGetUniformLocation(Prog, "View");
for (int i = 0; i < 8; i++)
{
char texv[32];
OVR_sprintf(texv, 10, "Texture%d", i);
TexLoc[i] = glGetUniformLocation(Prog, texv);
if (TexLoc[i] < 0)
break;
glUniform1i(TexLoc[i], i);
}
if (UsesLighting)
OVR_ASSERT(ProjLoc >= 0 && ViewLoc >= 0);
return 1;
}
bool ShaderBase::SetUniform(const char* name, int n, const float* v)
{
for(unsigned i = 0; i < UniformReflSize; i++)
{
if (!strcmp(UniformRefl[i].Name, name))
{
memcpy(UniformData + UniformRefl[i].Offset, v, n * sizeof(float));
return 1;
}
}
return 0;
}
bool ShaderBase::SetUniformBool(const char* name, int n, const bool* v)
{
OVR_UNUSED(n);
for(unsigned i = 0; i < UniformReflSize; i++)
{
if (!strcmp(UniformRefl[i].Name, name))
{
memcpy(UniformData + UniformRefl[i].Offset, v, UniformRefl[i].Size);
return 1;
}
}
return 0;
}
void ShaderBase::InitUniforms(const Uniform* refl, size_t reflSize)
{
if(!refl)
{
UniformRefl = NULL;
UniformReflSize = 0;
UniformsSize = 0;
if (UniformData)
{
OVR_FREE(UniformData);
UniformData = 0;
}
return; // no reflection data
}
UniformRefl = refl;
UniformReflSize = reflSize;
UniformsSize = UniformRefl[UniformReflSize-1].Offset + UniformRefl[UniformReflSize-1].Size;
UniformData = (unsigned char*)OVR_ALLOC(UniformsSize);
}
Texture::Texture(RenderParams* rp, int w, int h) : IsUserAllocated(true), pParams(rp), TexId(0), Width(w), Height(h)
{
if (w && h)
glGenTextures(1, &TexId);
}
Texture::~Texture()
{
if (TexId && !IsUserAllocated)
glDeleteTextures(1, &TexId);
}
void Texture::Set(int slot, ShaderStage) const
{
glActiveTexture(GL_TEXTURE0 + slot);
glBindTexture(GL_TEXTURE_2D, TexId);
}
void Texture::SetSampleMode(int sm)
{
glBindTexture(GL_TEXTURE_2D, TexId);
switch (sm & Sample_FilterMask)
{
case Sample_Linear:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1);
break;
case Sample_Anisotropic:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 8);
break;
case Sample_Nearest:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1);
break;
}
switch (sm & Sample_AddressMask)
{
case Sample_Repeat:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
break;
case Sample_Clamp:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
break;
case Sample_ClampBorder:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
break;
}
}
void Texture::UpdatePlaceholderTexture(GLuint texId, const Sizei& textureSize)
{
if (!IsUserAllocated && TexId && texId != TexId)
glDeleteTextures(1, &TexId);
TexId = texId;
Width = textureSize.w;
Height = textureSize.h;
IsUserAllocated = true;
}
}}}

View File

@ -0,0 +1,537 @@
/************************************************************************************
Filename : CAPI_GL_Util.h
Content : Utility header for OpenGL
Created : March 27, 2014
Authors : Andrew Reisse, David Borel
Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
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 INC_OVR_CAPI_GL_Util_h
#define INC_OVR_CAPI_GL_Util_h
#include "../../OVR_CAPI.h"
#include "../../Kernel/OVR_Array.h"
#include "../../Kernel/OVR_Math.h"
#include "../../Kernel/OVR_RefCount.h"
#include "../../Kernel/OVR_String.h"
#include "../../Kernel/OVR_Types.h"
#include "../../Kernel/OVR_Log.h"
#if defined(OVR_OS_WIN32)
#include <Windows.h>
#endif
#if defined(OVR_OS_MAC)
#include <OpenGL/gl3.h>
#include <OpenGL/gl3ext.h>
#else
#ifndef GL_GLEXT_PROTOTYPES
#define GL_GLEXT_PROTOTYPES
#endif
#include <GL/gl.h>
#include <GL/glext.h>
#if defined(OVR_OS_WIN32)
#include <GL/wglext.h>
#elif defined(OVR_OS_LINUX)
#include <GL/glx.h>
#endif
#endif
namespace OVR { namespace CAPI { namespace GL {
// GL extension Hooks for Non-Mac.
#if !defined(OVR_OS_MAC)
// Let Windows apps build without linking GL.
#if defined(OVR_OS_WIN32)
typedef void (__stdcall *PFNGLENABLEPROC) (GLenum);
typedef void (__stdcall *PFNGLDISABLEPROC) (GLenum);
typedef void (__stdcall *PFNGLGETFLOATVPROC) (GLenum, GLfloat*);
typedef const GLubyte * (__stdcall *PFNGLGETSTRINGPROC) (GLenum);
typedef void (__stdcall *PFNGLGETINTEGERVPROC) (GLenum, GLint*);
typedef PROC (__stdcall *PFNWGLGETPROCADDRESS) (LPCSTR);
typedef void (__stdcall *PFNGLFLUSHPROC) ();
typedef void (__stdcall *PFNGLFINISHPROC) ();
typedef void (__stdcall *PFNGLDRAWARRAYSPROC) (GLenum mode, GLint first, GLsizei count);
typedef void (__stdcall *PFNGLCLEARPROC) (GLbitfield);
typedef void (__stdcall *PFNGLCOLORMASKPROC) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
typedef void (__stdcall *PFNGLDRAWELEMENTSPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
typedef void (__stdcall *PFNGLGENTEXTURESPROC) (GLsizei n, GLuint *textures);
typedef void (__stdcall *PFNGLDELETETEXTURESPROC) (GLsizei n, GLuint *textures);
typedef void (__stdcall *PFNGLBINDTEXTUREPROC) (GLenum target, GLuint texture);
typedef void (__stdcall *PFNGLCLEARCOLORPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat a);
typedef void (__stdcall *PFNGLCLEARDEPTHPROC) (GLclampd depth);
typedef void (__stdcall *PFNGLTEXPARAMETERIPROC) (GLenum target, GLenum pname, GLint param);
typedef void (__stdcall *PFNGLVIEWPORTPROC) (GLint x, GLint y, GLsizei width, GLsizei height);
extern PFNWGLGETPROCADDRESS wglGetProcAddress;
extern PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT;
extern PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT;
extern PFNGLENABLEPROC glEnable;
extern PFNGLDISABLEPROC glDisable;
extern PFNGLCOLORMASKPROC glColorMask;
extern PFNGLGETFLOATVPROC glGetFloatv;
extern PFNGLGETSTRINGPROC glGetString;
extern PFNGLGETINTEGERVPROC glGetIntegerv;
extern PFNGLCLEARPROC glClear;
extern PFNGLCLEARCOLORPROC glClearColor;
extern PFNGLCLEARDEPTHPROC glClearDepth;
extern PFNGLVIEWPORTPROC glViewport;
extern PFNGLDRAWARRAYSPROC glDrawArrays;
extern PFNGLDRAWELEMENTSPROC glDrawElements;
extern PFNGLGENTEXTURESPROC glGenTextures;
extern PFNGLDELETETEXTURESPROC glDeleteTextures;
extern PFNGLBINDTEXTUREPROC glBindTexture;
extern PFNGLTEXPARAMETERIPROC glTexParameteri;
extern PFNGLFLUSHPROC glFlush;
extern PFNGLFINISHPROC glFinish;
#elif defined(OVR_OS_LINUX)
extern PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT;
#endif // defined(OVR_OS_WIN32)
extern PFNGLDELETESHADERPROC glDeleteShader;
extern PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
extern PFNGLACTIVETEXTUREPROC glActiveTexture;
extern PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray;
extern PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer;
extern PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray;
extern PFNGLBINDBUFFERPROC glBindBuffer;
extern PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv;
extern PFNGLDELETEBUFFERSPROC glDeleteBuffers;
extern PFNGLBUFFERDATAPROC glBufferData;
extern PFNGLGENBUFFERSPROC glGenBuffers;
extern PFNGLMAPBUFFERPROC glMapBuffer;
extern PFNGLUNMAPBUFFERPROC glUnmapBuffer;
extern PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
extern PFNGLGETSHADERIVPROC glGetShaderiv;
extern PFNGLCOMPILESHADERPROC glCompileShader;
extern PFNGLSHADERSOURCEPROC glShaderSource;
extern PFNGLCREATESHADERPROC glCreateShader;
extern PFNGLCREATEPROGRAMPROC glCreateProgram;
extern PFNGLATTACHSHADERPROC glAttachShader;
extern PFNGLDETACHSHADERPROC glDetachShader;
extern PFNGLDELETEPROGRAMPROC glDeleteProgram;
extern PFNGLUNIFORM1IPROC glUniform1i;
extern PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
extern PFNGLGETACTIVEUNIFORMPROC glGetActiveUniform;
extern PFNGLUSEPROGRAMPROC glUseProgram;
extern PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
extern PFNGLGETPROGRAMIVPROC glGetProgramiv;
extern PFNGLLINKPROGRAMPROC glLinkProgram;
extern PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation;
extern PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation;
extern PFNGLUNIFORM4FVPROC glUniform4fv;
extern PFNGLUNIFORM3FVPROC glUniform3fv;
extern PFNGLUNIFORM2FVPROC glUniform2fv;
extern PFNGLUNIFORM1FVPROC glUniform1fv;
extern PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;
extern PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays;
extern PFNGLBINDVERTEXARRAYPROC glBindVertexArray;
extern void InitGLExtensions();
#endif // !defined(OVR_OS_MAC)
// Rendering primitive type used to render Model.
enum PrimitiveType
{
Prim_Triangles,
Prim_Lines,
Prim_TriangleStrip,
Prim_Unknown,
Prim_Count
};
// Types of shaders that can be stored together in a ShaderSet.
enum ShaderStage
{
Shader_Vertex = 0,
Shader_Fragment = 2,
Shader_Pixel = 2,
Shader_Count = 3,
};
enum MapFlags
{
Map_Discard = 1,
Map_Read = 2, // do not use
Map_Unsynchronized = 4, // like D3D11_MAP_NO_OVERWRITE
};
// Buffer types used for uploading geometry & constants.
enum BufferUsage
{
Buffer_Unknown = 0,
Buffer_Vertex = 1,
Buffer_Index = 2,
Buffer_Uniform = 4,
Buffer_TypeMask = 0xff,
Buffer_ReadOnly = 0x100, // Buffer must be created with Data().
};
enum TextureFormat
{
Texture_RGBA = 0x0100,
Texture_Depth = 0x8000,
Texture_TypeMask = 0xff00,
Texture_SamplesMask = 0x00ff,
Texture_RenderTarget = 0x10000,
Texture_GenMipmaps = 0x20000,
};
// Texture sampling modes.
enum SampleMode
{
Sample_Linear = 0,
Sample_Nearest = 1,
Sample_Anisotropic = 2,
Sample_FilterMask = 3,
Sample_Repeat = 0,
Sample_Clamp = 4,
Sample_ClampBorder = 8, // If unsupported Clamp is used instead.
Sample_AddressMask =12,
Sample_Count =13,
};
// Rendering parameters/pointers describing GL rendering setup.
struct RenderParams
{
#if defined(OVR_OS_WIN32)
HWND Window;
#elif defined(OVR_OS_LINUX)
Display* Disp;
Window Win;
#endif
ovrSizei RTSize;
int Multisample;
};
class Buffer : public RefCountBase<Buffer>
{
public:
RenderParams* pParams;
size_t Size;
GLenum Use;
GLuint GLBuffer;
public:
Buffer(RenderParams* r);
~Buffer();
GLuint GetBuffer() { return GLBuffer; }
virtual size_t GetSize() { return Size; }
virtual void* Map(size_t start, size_t size, int flags = 0);
virtual bool Unmap(void *m);
virtual bool Data(int use, const void* buffer, size_t size);
};
class Texture : public RefCountBase<Texture>
{
bool IsUserAllocated;
public:
RenderParams* pParams;
GLuint TexId;
int Width, Height;
Texture(RenderParams* rp, int w, int h);
~Texture();
virtual int GetWidth() const { return Width; }
virtual int GetHeight() const { return Height; }
virtual void SetSampleMode(int sm);
// Updates texture to point to specified resources
// - used for slave rendering.
void UpdatePlaceholderTexture(GLuint texId,
const Sizei& textureSize);
virtual void Set(int slot, ShaderStage stage = Shader_Fragment) const;
};
// Base class for vertex and pixel shaders. Stored in ShaderSet.
class Shader : public RefCountBase<Shader>
{
friend class ShaderSet;
protected:
ShaderStage Stage;
public:
Shader(ShaderStage s) : Stage(s) {}
virtual ~Shader() {}
ShaderStage GetStage() const { return Stage; }
virtual void Set(PrimitiveType) const { }
virtual void SetUniformBuffer(class Buffer* buffers, int i = 0) { OVR_UNUSED2(buffers, i); }
protected:
virtual bool SetUniform(const char* name, int n, const float* v) { OVR_UNUSED3(name, n, v); return false; }
virtual bool SetUniformBool(const char* name, int n, const bool* v) { OVR_UNUSED3(name, n, v); return false; }
};
// A group of shaders, one per stage.
// A ShaderSet is applied for rendering with a given fill.
class ShaderSet : public RefCountBase<ShaderSet>
{
protected:
Ptr<Shader> Shaders[Shader_Count];
struct Uniform
{
String Name;
int Location, Size;
int Type; // currently number of floats in vector
};
Array<Uniform> UniformInfo;
public:
GLuint Prog;
GLint ProjLoc, ViewLoc;
GLint TexLoc[8];
bool UsesLighting;
int LightingVer;
ShaderSet();
~ShaderSet();
virtual void SetShader(Shader *s);
virtual void UnsetShader(int stage);
Shader* GetShader(int stage) { return Shaders[stage]; }
virtual void Set(PrimitiveType prim) const
{
glUseProgram(Prog);
for (int i = 0; i < Shader_Count; i++)
if (Shaders[i])
Shaders[i]->Set(prim);
}
// Set a uniform (other than the standard matrices). It is undefined whether the
// uniforms from one shader occupy the same space as those in other shaders
// (unless a buffer is used, then each buffer is independent).
virtual bool SetUniform(const char* name, int n, const float* v);
bool SetUniform1f(const char* name, float x)
{
const float v[] = {x};
return SetUniform(name, 1, v);
}
bool SetUniform2f(const char* name, float x, float y)
{
const float v[] = {x,y};
return SetUniform(name, 2, v);
}
bool SetUniform3f(const char* name, float x, float y, float z)
{
const float v[] = {x,y,z};
return SetUniform(name, 3, v);
}
bool SetUniform4f(const char* name, float x, float y, float z, float w = 1)
{
const float v[] = {x,y,z,w};
return SetUniform(name, 4, v);
}
bool SetUniformv(const char* name, const Vector3f& v)
{
const float a[] = {v.x,v.y,v.z,1};
return SetUniform(name, 4, a);
}
virtual bool SetUniform4x4f(const char* name, const Matrix4f& m)
{
Matrix4f mt = m.Transposed();
return SetUniform(name, 16, &mt.M[0][0]);
}
protected:
GLint GetGLShader(Shader* s);
bool Link();
};
// Fill combines a ShaderSet (vertex, pixel) with textures, if any.
// Every model has a fill.
class ShaderFill : public RefCountBase<ShaderFill>
{
Ptr<ShaderSet> Shaders;
Ptr<class Texture> Textures[8];
void* InputLayout; // HACK this should be abstracted
public:
ShaderFill(ShaderSet* sh) : Shaders(sh) { InputLayout = NULL; }
ShaderFill(ShaderSet& sh) : Shaders(sh) { InputLayout = NULL; }
ShaderSet* GetShaders() const { return Shaders; }
void* GetInputLayout() const { return InputLayout; }
virtual void Set(PrimitiveType prim = Prim_Unknown) const {
Shaders->Set(prim);
for(int i = 0; i < 8; i++)
{
if(Textures[i])
{
Textures[i]->Set(i);
}
}
}
virtual void SetTexture(int i, class Texture* tex) { if (i < 8) Textures[i] = tex; }
};
struct DisplayId
{
// Windows
String MonitorName; // Monitor name for fullscreen mode
// MacOS
long CgDisplayId; // CGDirectDisplayID
DisplayId() : CgDisplayId(0) {}
DisplayId(long id) : CgDisplayId(id) {}
DisplayId(String m, long id=0) : MonitorName(m), CgDisplayId(id) {}
operator bool () const
{
return MonitorName.GetLength() || CgDisplayId;
}
bool operator== (const DisplayId& b) const
{
return CgDisplayId == b.CgDisplayId &&
(strstr(MonitorName.ToCStr(), b.MonitorName.ToCStr()) ||
strstr(b.MonitorName.ToCStr(), MonitorName.ToCStr()));
}
};
class ShaderBase : public Shader
{
public:
RenderParams* pParams;
unsigned char* UniformData;
int UniformsSize;
enum VarType
{
VARTYPE_FLOAT,
VARTYPE_INT,
VARTYPE_BOOL,
};
struct Uniform
{
const char* Name;
VarType Type;
int Offset, Size;
};
const Uniform* UniformRefl;
size_t UniformReflSize;
ShaderBase(RenderParams* rp, ShaderStage stage) : Shader(stage), pParams(rp), UniformData(0), UniformsSize(0) {}
~ShaderBase()
{
if (UniformData)
OVR_FREE(UniformData);
}
void InitUniforms(const Uniform* refl, size_t reflSize);
bool SetUniform(const char* name, int n, const float* v);
bool SetUniformBool(const char* name, int n, const bool* v);
};
template<ShaderStage SStage, GLenum SType>
class ShaderImpl : public ShaderBase
{
friend class ShaderSet;
public:
ShaderImpl(RenderParams* rp, void* s, size_t size, const Uniform* refl, size_t reflSize)
: ShaderBase(rp, SStage)
, GLShader(0)
{
bool success;
OVR_UNUSED(size);
success = Compile((const char*) s);
OVR_ASSERT(success);
InitUniforms(refl, reflSize);
}
~ShaderImpl()
{
if (GLShader)
{
glDeleteShader(GLShader);
GLShader = 0;
}
}
bool Compile(const char* src)
{
if (!GLShader)
GLShader = glCreateShader(GLStage());
glShaderSource(GLShader, 1, &src, 0);
glCompileShader(GLShader);
GLint r;
glGetShaderiv(GLShader, GL_COMPILE_STATUS, &r);
if (!r)
{
GLchar msg[1024];
glGetShaderInfoLog(GLShader, sizeof(msg), 0, msg);
if (msg[0])
OVR_DEBUG_LOG(("Compiling shader\n%s\nfailed: %s\n", src, msg));
return 0;
}
return 1;
}
GLenum GLStage() const
{
return SType;
}
private:
GLuint GLShader;
};
typedef ShaderImpl<Shader_Vertex, GL_VERTEX_SHADER> VertexShader;
typedef ShaderImpl<Shader_Fragment, GL_FRAGMENT_SHADER> FragmentShader;
}}}
#endif // INC_OVR_CAPI_GL_Util_h

View File

@ -0,0 +1,57 @@
/************************************************************************************
Filename : OVR_Alg.cpp
Content : Static lookup tables for Alg functions
Created : September 19, 2012
Notes :
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_Types.h"
namespace OVR { namespace Alg {
//------------------------------------------------------------------------
extern const UByte UpperBitTable[256] =
{
0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
};
extern const UByte LowerBitTable[256] =
{
8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
};
}} // OVE::Alg

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,95 @@
/************************************************************************************
Filename : OVR_Allocator.cpp
Content : Installable memory allocator implementation
Created : September 19, 2012
Notes :
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_Allocator.h"
#ifdef OVR_OS_MAC
#include <stdlib.h>
#else
#include <malloc.h>
#endif
namespace OVR {
//-----------------------------------------------------------------------------------
// ***** Allocator
Allocator* Allocator::pInstance = 0;
// Default AlignedAlloc implementation will delegate to Alloc/Free after doing rounding.
void* Allocator::AllocAligned(UPInt size, UPInt align)
{
OVR_ASSERT((align & (align-1)) == 0);
align = (align > sizeof(UPInt)) ? align : sizeof(UPInt);
UPInt p = (UPInt)Alloc(size+align);
UPInt aligned = 0;
if (p)
{
aligned = (UPInt(p) + align-1) & ~(align-1);
if (aligned == p)
aligned += align;
*(((UPInt*)aligned)-1) = aligned-p;
}
return (void*)aligned;
}
void Allocator::FreeAligned(void* p)
{
UPInt src = UPInt(p) - *(((UPInt*)p)-1);
Free((void*)src);
}
//------------------------------------------------------------------------
// ***** Default Allocator
// This allocator is created and used if no other allocator is installed.
// Default allocator delegates to system malloc.
void* DefaultAllocator::Alloc(UPInt size)
{
return malloc(size);
}
void* DefaultAllocator::AllocDebug(UPInt size, const char* file, unsigned line)
{
#if defined(OVR_CC_MSVC) && defined(_CRTDBG_MAP_ALLOC)
return _malloc_dbg(size, _NORMAL_BLOCK, file, line);
#else
OVR_UNUSED2(file, line);
return malloc(size);
#endif
}
void* DefaultAllocator::Realloc(void* p, UPInt newSize)
{
return realloc(p, newSize);
}
void DefaultAllocator::Free(void *p)
{
return free(p);
}
} // OVR

View File

@ -0,0 +1,347 @@
/************************************************************************************
PublicHeader: OVR.h
Filename : OVR_Allocator.h
Content : Installable memory allocator
Created : September 19, 2012
Notes :
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_Allocator_h
#define OVR_Allocator_h
#include "OVR_Types.h"
//-----------------------------------------------------------------------------------
// ***** Disable template-unfriendly MS VC++ warnings
#if defined(OVR_CC_MSVC)
// Pragma to prevent long name warnings in in VC++
#pragma warning(disable : 4503)
#pragma warning(disable : 4786)
// In MSVC 7.1, warning about placement new POD default initializer
#pragma warning(disable : 4345)
#endif
// Un-define new so that placement constructors work
#undef new
//-----------------------------------------------------------------------------------
// ***** Placement new overrides
// Calls constructor on own memory created with "new(ptr) type"
#ifndef __PLACEMENT_NEW_INLINE
#define __PLACEMENT_NEW_INLINE
# if defined(OVR_CC_MWERKS) || defined(OVR_CC_BORLAND) || defined(OVR_CC_GNU)
# include <new>
# else
// Useful on MSVC
OVR_FORCE_INLINE void* operator new (OVR::UPInt n, void *ptr) { OVR_UNUSED(n); return ptr; }
OVR_FORCE_INLINE void operator delete (void *, void *) { }
# endif
#endif // __PLACEMENT_NEW_INLINE
//------------------------------------------------------------------------
// ***** Macros to redefine class new/delete operators
// Types specifically declared to allow disambiguation of address in
// class member operator new.
#define OVR_MEMORY_REDEFINE_NEW_IMPL(class_name, check_delete) \
void* operator new(UPInt sz) \
{ void *p = OVR_ALLOC_DEBUG(sz, __FILE__, __LINE__); return p; } \
void* operator new(UPInt sz, const char* file, int line) \
{ void* p = OVR_ALLOC_DEBUG(sz, file, line); OVR_UNUSED2(file, line); return p; } \
void operator delete(void *p) \
{ check_delete(class_name, p); OVR_FREE(p); } \
void operator delete(void *p, const char*, int) \
{ check_delete(class_name, p); OVR_FREE(p); }
#define OVR_MEMORY_DEFINE_PLACEMENT_NEW \
void* operator new (UPInt n, void *ptr) { OVR_UNUSED(n); return ptr; } \
void operator delete (void *ptr, void *ptr2) { OVR_UNUSED2(ptr,ptr2); }
#define OVR_MEMORY_CHECK_DELETE_NONE(class_name, p)
// Redefined all delete/new operators in a class without custom memory initialization
#define OVR_MEMORY_REDEFINE_NEW(class_name) \
OVR_MEMORY_REDEFINE_NEW_IMPL(class_name, OVR_MEMORY_CHECK_DELETE_NONE)
namespace OVR {
//-----------------------------------------------------------------------------------
// ***** Construct / Destruct
// Construct/Destruct functions are useful when new is redefined, as they can
// be called instead of placement new constructors.
template <class T>
OVR_FORCE_INLINE T* Construct(void *p)
{
return ::new(p) T();
}
template <class T>
OVR_FORCE_INLINE T* Construct(void *p, const T& source)
{
return ::new(p) T(source);
}
// Same as above, but allows for a different type of constructor.
template <class T, class S>
OVR_FORCE_INLINE T* ConstructAlt(void *p, const S& source)
{
return ::new(p) T(source);
}
template <class T, class S1, class S2>
OVR_FORCE_INLINE T* ConstructAlt(void *p, const S1& src1, const S2& src2)
{
return ::new(p) T(src1, src2);
}
template <class T>
OVR_FORCE_INLINE void ConstructArray(void *p, UPInt count)
{
UByte *pdata = (UByte*)p;
for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
{
Construct<T>(pdata);
}
}
template <class T>
OVR_FORCE_INLINE void ConstructArray(void *p, UPInt count, const T& source)
{
UByte *pdata = (UByte*)p;
for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
{
Construct<T>(pdata, source);
}
}
template <class T>
OVR_FORCE_INLINE void Destruct(T *pobj)
{
pobj->~T();
OVR_UNUSED1(pobj); // Fix incorrect 'unused variable' MSVC warning.
}
template <class T>
OVR_FORCE_INLINE void DestructArray(T *pobj, UPInt count)
{
for (UPInt i=0; i<count; ++i, ++pobj)
pobj->~T();
}
//-----------------------------------------------------------------------------------
// ***** Allocator
// Allocator defines a memory allocation interface that developers can override
// to to provide memory for OVR; an instance of this class is typically created on
// application startup and passed into System or OVR::System constructor.
//
//
// Users implementing this interface must provide three functions: Alloc, Free,
// and Realloc. Implementations of these functions must honor the requested alignment.
// Although arbitrary alignment requests are possible, requested alignment will
// typically be small, such as 16 bytes or less.
class Allocator
{
friend class System;
public:
// *** Standard Alignment Alloc/Free
// Allocate memory of specified size with default alignment.
// Alloc of size==0 will allocate a tiny block & return a valid pointer;
// this makes it suitable for new operator.
virtual void* Alloc(UPInt size) = 0;
// Same as Alloc, but provides an option of passing debug data.
virtual void* AllocDebug(UPInt size, const char* file, unsigned line)
{ OVR_UNUSED2(file, line); return Alloc(size); }
// Reallocate memory block to a new size, copying data if necessary. Returns the pointer to
// new memory block, which may be the same as original pointer. Will return 0 if reallocation
// failed, in which case previous memory is still valid.
// Realloc to decrease size will never fail.
// Realloc of pointer == 0 is equivalent to Alloc
// Realloc to size == 0, shrinks to the minimal size, pointer remains valid and requires Free().
virtual void* Realloc(void* p, UPInt newSize) = 0;
// Frees memory allocated by Alloc/Realloc.
// Free of null pointer is valid and will do nothing.
virtual void Free(void *p) = 0;
// *** Standard Alignment Alloc/Free
// Allocate memory of specified alignment.
// Memory allocated with AllocAligned MUST be freed with FreeAligned.
// Default implementation will delegate to Alloc/Free after doing rounding.
virtual void* AllocAligned(UPInt size, UPInt align);
// Frees memory allocated with AllocAligned.
virtual void FreeAligned(void* p);
// Returns the pointer to the current globally installed Allocator instance.
// This pointer is used for most of the memory allocations.
static Allocator* GetInstance() { return pInstance; }
protected:
// onSystemShutdown is called on the allocator during System::Shutdown.
// At this point, all allocations should've been freed.
virtual void onSystemShutdown() { }
public:
static void setInstance(Allocator* palloc)
{
OVR_ASSERT((pInstance == 0) || (palloc == 0));
pInstance = palloc;
}
private:
static Allocator* pInstance;
};
//------------------------------------------------------------------------
// ***** Allocator_SingletonSupport
// Allocator_SingletonSupport is a Allocator wrapper class that implements
// the InitSystemSingleton static function, used to create a global singleton
// used for the OVR::System default argument initialization.
//
// End users implementing custom Allocator interface don't need to make use of this base
// class; they can just create an instance of their own class on stack and pass it to System.
template<class D>
class Allocator_SingletonSupport : public Allocator
{
struct AllocContainer
{
UPInt Data[(sizeof(D) + sizeof(UPInt)-1) / sizeof(UPInt)];
bool Initialized;
AllocContainer() : Initialized(0) { }
};
AllocContainer* pContainer;
public:
Allocator_SingletonSupport() : pContainer(0) { }
// Creates a singleton instance of this Allocator class used
// on OVR_DEFAULT_ALLOCATOR during System initialization.
static D* InitSystemSingleton()
{
static AllocContainer Container;
OVR_ASSERT(Container.Initialized == false);
Allocator_SingletonSupport<D> *presult = Construct<D>((void*)Container.Data);
presult->pContainer = &Container;
Container.Initialized = true;
return (D*)presult;
}
protected:
virtual void onSystemShutdown()
{
Allocator::onSystemShutdown();
if (pContainer)
{
pContainer->Initialized = false;
Destruct((D*)this);
pContainer = 0;
}
}
};
//------------------------------------------------------------------------
// ***** Default Allocator
// This allocator is created and used if no other allocator is installed.
// Default allocator delegates to system malloc.
class DefaultAllocator : public Allocator_SingletonSupport<DefaultAllocator>
{
public:
virtual void* Alloc(UPInt size);
virtual void* AllocDebug(UPInt size, const char* file, unsigned line);
virtual void* Realloc(void* p, UPInt newSize);
virtual void Free(void *p);
};
//------------------------------------------------------------------------
// ***** Memory Allocation Macros
// These macros should be used for global allocation. In the future, these
// macros will allows allocation to be extended with debug file/line information
// if necessary.
#define OVR_REALLOC(p,s) OVR::Allocator::GetInstance()->Realloc((p),(s))
#define OVR_FREE(p) OVR::Allocator::GetInstance()->Free((p))
#define OVR_ALLOC_ALIGNED(s,a) OVR::Allocator::GetInstance()->AllocAligned((s),(a))
#define OVR_FREE_ALIGNED(p) OVR::Allocator::GetInstance()->FreeAligned((p))
#ifdef OVR_BUILD_DEBUG
#define OVR_ALLOC(s) OVR::Allocator::GetInstance()->AllocDebug((s), __FILE__, __LINE__)
#define OVR_ALLOC_DEBUG(s,f,l) OVR::Allocator::GetInstance()->AllocDebug((s), f, l)
#else
#define OVR_ALLOC(s) OVR::Allocator::GetInstance()->Alloc((s))
#define OVR_ALLOC_DEBUG(s,f,l) OVR::Allocator::GetInstance()->Alloc((s))
#endif
//------------------------------------------------------------------------
// Base class that overrides the new and delete operators.
// Deriving from this class, even as a multiple base, incurs no space overhead.
class NewOverrideBase
{
public:
// Redefine all new & delete operators.
OVR_MEMORY_REDEFINE_NEW(NewOverrideBase)
};
} // OVR
// Redefine operator 'new' if necessary.
#if defined(OVR_DEFINE_NEW)
#define new OVR_DEFINE_NEW
#endif
#endif // OVR_Memory

View File

@ -0,0 +1,833 @@
/************************************************************************************
PublicHeader: OVR.h
Filename : OVR_Array.h
Content : Template implementation for Array
Created : September 19, 2012
Notes :
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_Array_h
#define OVR_Array_h
#include "OVR_ContainerAllocator.h"
namespace OVR {
//-----------------------------------------------------------------------------------
// ***** ArrayDefaultPolicy
//
// Default resize behavior. No minimal capacity, Granularity=4,
// Shrinking as needed. ArrayConstPolicy actually is the same as
// ArrayDefaultPolicy, but parametrized with constants.
// This struct is used only in order to reduce the template "matroska".
struct ArrayDefaultPolicy
{
ArrayDefaultPolicy() : Capacity(0) {}
ArrayDefaultPolicy(const ArrayDefaultPolicy&) : Capacity(0) {}
UPInt GetMinCapacity() const { return 0; }
UPInt GetGranularity() const { return 4; }
bool NeverShrinking() const { return 0; }
UPInt GetCapacity() const { return Capacity; }
void SetCapacity(UPInt capacity) { Capacity = capacity; }
private:
UPInt Capacity;
};
//-----------------------------------------------------------------------------------
// ***** ArrayConstPolicy
//
// Statically parametrized resizing behavior:
// MinCapacity, Granularity, and Shrinking flag.
template<int MinCapacity=0, int Granularity=4, bool NeverShrink=false>
struct ArrayConstPolicy
{
typedef ArrayConstPolicy<MinCapacity, Granularity, NeverShrink> SelfType;
ArrayConstPolicy() : Capacity(0) {}
ArrayConstPolicy(const SelfType&) : Capacity(0) {}
UPInt GetMinCapacity() const { return MinCapacity; }
UPInt GetGranularity() const { return Granularity; }
bool NeverShrinking() const { return NeverShrink; }
UPInt GetCapacity() const { return Capacity; }
void SetCapacity(UPInt capacity) { Capacity = capacity; }
private:
UPInt Capacity;
};
//-----------------------------------------------------------------------------------
// ***** ArrayDataBase
//
// Basic operations with array data: Reserve, Resize, Free, ArrayPolicy.
// For internal use only: ArrayData,ArrayDataCC and others.
template<class T, class Allocator, class SizePolicy>
struct ArrayDataBase
{
typedef T ValueType;
typedef Allocator AllocatorType;
typedef SizePolicy SizePolicyType;
typedef ArrayDataBase<T, Allocator, SizePolicy> SelfType;
ArrayDataBase()
: Data(0), Size(0), Policy() {}
ArrayDataBase(const SizePolicy& p)
: Data(0), Size(0), Policy(p) {}
~ArrayDataBase()
{
Allocator::DestructArray(Data, Size);
Allocator::Free(Data);
}
UPInt GetCapacity() const
{
return Policy.GetCapacity();
}
void ClearAndRelease()
{
Allocator::DestructArray(Data, Size);
Allocator::Free(Data);
Data = 0;
Size = 0;
Policy.SetCapacity(0);
}
void Reserve(UPInt newCapacity)
{
if (Policy.NeverShrinking() && newCapacity < GetCapacity())
return;
if (newCapacity < Policy.GetMinCapacity())
newCapacity = Policy.GetMinCapacity();
// Resize the buffer.
if (newCapacity == 0)
{
if (Data)
{
Allocator::Free(Data);
Data = 0;
}
Policy.SetCapacity(0);
}
else
{
UPInt gran = Policy.GetGranularity();
newCapacity = (newCapacity + gran - 1) / gran * gran;
if (Data)
{
if (Allocator::IsMovable())
{
Data = (T*)Allocator::Realloc(Data, sizeof(T) * newCapacity);
}
else
{
T* newData = (T*)Allocator::Alloc(sizeof(T) * newCapacity);
UPInt i, s;
s = (Size < newCapacity) ? Size : newCapacity;
for (i = 0; i < s; ++i)
{
Allocator::Construct(&newData[i], Data[i]);
Allocator::Destruct(&Data[i]);
}
for (i = s; i < Size; ++i)
{
Allocator::Destruct(&Data[i]);
}
Allocator::Free(Data);
Data = newData;
}
}
else
{
Data = (T*)Allocator::Alloc(sizeof(T) * newCapacity);
//memset(Buffer, 0, (sizeof(ValueType) * newSize)); // Do we need this?
}
Policy.SetCapacity(newCapacity);
// OVR_ASSERT(Data); // need to throw (or something) on alloc failure!
}
}
// This version of Resize DOES NOT construct the elements.
// It's done to optimize PushBack, which uses a copy constructor
// instead of the default constructor and assignment
void ResizeNoConstruct(UPInt newSize)
{
UPInt oldSize = Size;
if (newSize < oldSize)
{
Allocator::DestructArray(Data + newSize, oldSize - newSize);
if (newSize < (Policy.GetCapacity() >> 1))
{
Reserve(newSize);
}
}
else if(newSize >= Policy.GetCapacity())
{
Reserve(newSize + (newSize >> 2));
}
//! IMPORTANT to modify Size only after Reserve completes, because garbage collectable
// array may use this array and may traverse it during Reserve (in the case, if
// collection occurs because of heap limit exceeded).
Size = newSize;
}
ValueType* Data;
UPInt Size;
SizePolicy Policy;
};
//-----------------------------------------------------------------------------------
// ***** ArrayData
//
// General purpose array data.
// For internal use only in Array, ArrayLH, ArrayPOD and so on.
template<class T, class Allocator, class SizePolicy>
struct ArrayData : ArrayDataBase<T, Allocator, SizePolicy>
{
typedef T ValueType;
typedef Allocator AllocatorType;
typedef SizePolicy SizePolicyType;
typedef ArrayDataBase<T, Allocator, SizePolicy> BaseType;
typedef ArrayData <T, Allocator, SizePolicy> SelfType;
ArrayData()
: BaseType() { }
ArrayData(UPInt size)
: BaseType() { Resize(size); }
ArrayData(const SelfType& a)
: BaseType(a.Policy) { Append(a.Data, a.Size); }
void Resize(UPInt newSize)
{
UPInt oldSize = this->Size;
BaseType::ResizeNoConstruct(newSize);
if(newSize > oldSize)
Allocator::ConstructArray(this->Data + oldSize, newSize - oldSize);
}
void PushBack(const ValueType& val)
{
BaseType::ResizeNoConstruct(this->Size + 1);
Allocator::Construct(this->Data + this->Size - 1, val);
}
template<class S>
void PushBackAlt(const S& val)
{
BaseType::ResizeNoConstruct(this->Size + 1);
Allocator::ConstructAlt(this->Data + this->Size - 1, val);
}
// Append the given data to the array.
void Append(const ValueType other[], UPInt count)
{
if (count)
{
UPInt oldSize = this->Size;
BaseType::ResizeNoConstruct(this->Size + count);
Allocator::ConstructArray(this->Data + oldSize, count, other);
}
}
};
//-----------------------------------------------------------------------------------
// ***** ArrayDataCC
//
// A modification of ArrayData that always copy-constructs new elements
// using a specified DefaultValue. For internal use only in ArrayCC.
template<class T, class Allocator, class SizePolicy>
struct ArrayDataCC : ArrayDataBase<T, Allocator, SizePolicy>
{
typedef T ValueType;
typedef Allocator AllocatorType;
typedef SizePolicy SizePolicyType;
typedef ArrayDataBase<T, Allocator, SizePolicy> BaseType;
typedef ArrayDataCC <T, Allocator, SizePolicy> SelfType;
ArrayDataCC(const ValueType& defval)
: BaseType(), DefaultValue(defval) { }
ArrayDataCC(const ValueType& defval, UPInt size)
: BaseType(), DefaultValue(defval) { Resize(size); }
ArrayDataCC(const SelfType& a)
: BaseType(a.Policy), DefaultValue(a.DefaultValue) { Append(a.Data, a.Size); }
void Resize(UPInt newSize)
{
UPInt oldSize = this->Size;
BaseType::ResizeNoConstruct(newSize);
if(newSize > oldSize)
Allocator::ConstructArray(this->Data + oldSize, newSize - oldSize, DefaultValue);
}
void PushBack(const ValueType& val)
{
BaseType::ResizeNoConstruct(this->Size + 1);
Allocator::Construct(this->Data + this->Size - 1, val);
}
template<class S>
void PushBackAlt(const S& val)
{
BaseType::ResizeNoConstruct(this->Size + 1);
Allocator::ConstructAlt(this->Data + this->Size - 1, val);
}
// Append the given data to the array.
void Append(const ValueType other[], UPInt count)
{
if (count)
{
UPInt oldSize = this->Size;
BaseType::ResizeNoConstruct(this->Size + count);
Allocator::ConstructArray(this->Data + oldSize, count, other);
}
}
ValueType DefaultValue;
};
//-----------------------------------------------------------------------------------
// ***** ArrayBase
//
// Resizable array. The behavior can be POD (suffix _POD) and
// Movable (no suffix) depending on the allocator policy.
// In case of _POD the constructors and destructors are not called.
//
// Arrays can't handle non-movable objects! Don't put anything in here
// that can't be moved around by bitwise copy.
//
// The addresses of elements are not persistent! Don't keep the address
// of an element; the array contents will move around as it gets resized.
template<class ArrayData>
class ArrayBase
{
public:
typedef typename ArrayData::ValueType ValueType;
typedef typename ArrayData::AllocatorType AllocatorType;
typedef typename ArrayData::SizePolicyType SizePolicyType;
typedef ArrayBase<ArrayData> SelfType;
#undef new
OVR_MEMORY_REDEFINE_NEW(ArrayBase)
// Redefine operator 'new' if necessary.
#if defined(OVR_DEFINE_NEW)
#define new OVR_DEFINE_NEW
#endif
ArrayBase()
: Data() {}
ArrayBase(UPInt size)
: Data(size) {}
ArrayBase(const SelfType& a)
: Data(a.Data) {}
ArrayBase(const ValueType& defval)
: Data(defval) {}
ArrayBase(const ValueType& defval, UPInt size)
: Data(defval, size) {}
SizePolicyType* GetSizePolicy() const { return Data.Policy; }
void SetSizePolicy(const SizePolicyType& p) { Data.Policy = p; }
bool NeverShrinking()const { return Data.Policy.NeverShrinking(); }
UPInt GetSize() const { return Data.Size; }
bool IsEmpty() const { return Data.Size == 0; }
UPInt GetCapacity() const { return Data.GetCapacity(); }
UPInt GetNumBytes() const { return Data.GetCapacity() * sizeof(ValueType); }
void ClearAndRelease() { Data.ClearAndRelease(); }
void Clear() { Data.Resize(0); }
void Resize(UPInt newSize) { Data.Resize(newSize); }
// Reserve can only increase the capacity
void Reserve(UPInt newCapacity)
{
if (newCapacity > Data.GetCapacity())
Data.Reserve(newCapacity);
}
// Basic access.
ValueType& At(UPInt index)
{
OVR_ASSERT(index < Data.Size);
return Data.Data[index];
}
const ValueType& At(UPInt index) const
{
OVR_ASSERT(index < Data.Size);
return Data.Data[index];
}
ValueType ValueAt(UPInt index) const
{
OVR_ASSERT(index < Data.Size);
return Data.Data[index];
}
// Basic access.
ValueType& operator [] (UPInt index)
{
OVR_ASSERT(index < Data.Size);
return Data.Data[index];
}
const ValueType& operator [] (UPInt index) const
{
OVR_ASSERT(index < Data.Size);
return Data.Data[index];
}
// Raw pointer to the data. Use with caution!
const ValueType* GetDataPtr() const { return Data.Data; }
ValueType* GetDataPtr() { return Data.Data; }
// Insert the given element at the end of the array.
void PushBack(const ValueType& val)
{
// DO NOT pass elements of your own vector into
// push_back()! Since we're using references,
// resize() may munge the element storage!
// OVR_ASSERT(&val < &Buffer[0] || &val > &Buffer[BufferSize]);
Data.PushBack(val);
}
template<class S>
void PushBackAlt(const S& val)
{
Data.PushBackAlt(val);
}
// Remove the last element.
void PopBack(UPInt count = 1)
{
OVR_ASSERT(Data.Size >= count);
Data.Resize(Data.Size - count);
}
ValueType& PushDefault()
{
Data.PushBack(ValueType());
return Back();
}
ValueType Pop()
{
ValueType t = Back();
PopBack();
return t;
}
// Access the first element.
ValueType& Front() { return At(0); }
const ValueType& Front() const { return At(0); }
// Access the last element.
ValueType& Back() { return At(Data.Size - 1); }
const ValueType& Back() const { return At(Data.Size - 1); }
// Array copy. Copies the contents of a into this array.
const SelfType& operator = (const SelfType& a)
{
Resize(a.GetSize());
for (UPInt i = 0; i < Data.Size; i++) {
*(Data.Data + i) = a[i];
}
return *this;
}
// Removing multiple elements from the array.
void RemoveMultipleAt(UPInt index, UPInt num)
{
OVR_ASSERT(index + num <= Data.Size);
if (Data.Size == num)
{
Clear();
}
else
{
AllocatorType::DestructArray(Data.Data + index, num);
AllocatorType::CopyArrayForward(
Data.Data + index,
Data.Data + index + num,
Data.Size - num - index);
Data.Size -= num;
}
}
// Removing an element from the array is an expensive operation!
// It compacts only after removing the last element.
// If order of elements in the array is not important then use
// RemoveAtUnordered, that could be much faster than the regular
// RemoveAt.
void RemoveAt(UPInt index)
{
OVR_ASSERT(index < Data.Size);
if (Data.Size == 1)
{
Clear();
}
else
{
AllocatorType::Destruct(Data.Data + index);
AllocatorType::CopyArrayForward(
Data.Data + index,
Data.Data + index + 1,
Data.Size - 1 - index);
--Data.Size;
}
}
// Removes an element from the array without respecting of original order of
// elements for better performance. Do not use on array where order of elements
// is important, otherwise use it instead of regular RemoveAt().
void RemoveAtUnordered(UPInt index)
{
OVR_ASSERT(index < Data.Size);
if (Data.Size == 1)
{
Clear();
}
else
{
// copy the last element into the 'index' position
// and decrement the size (instead of moving all elements
// in [index + 1 .. size - 1] range).
const UPInt lastElemIndex = Data.Size - 1;
if (index < lastElemIndex)
{
AllocatorType::Destruct(Data.Data + index);
AllocatorType::Construct(Data.Data + index, Data.Data[lastElemIndex]);
}
AllocatorType::Destruct(Data.Data + lastElemIndex);
--Data.Size;
}
}
// Insert the given object at the given index shifting all the elements up.
void InsertAt(UPInt index, const ValueType& val = ValueType())
{
OVR_ASSERT(index <= Data.Size);
Data.Resize(Data.Size + 1);
if (index < Data.Size - 1)
{
AllocatorType::CopyArrayBackward(
Data.Data + index + 1,
Data.Data + index,
Data.Size - 1 - index);
}
AllocatorType::Construct(Data.Data + index, val);
}
// Insert the given object at the given index shifting all the elements up.
void InsertMultipleAt(UPInt index, UPInt num, const ValueType& val = ValueType())
{
OVR_ASSERT(index <= Data.Size);
Data.Resize(Data.Size + num);
if (index < Data.Size - num)
{
AllocatorType::CopyArrayBackward(
Data.Data + index + num,
Data.Data + index,
Data.Size - num - index);
}
for (UPInt i = 0; i < num; ++i)
AllocatorType::Construct(Data.Data + index + i, val);
}
// Append the given data to the array.
void Append(const SelfType& other)
{
Append(other.Data.Data, other.GetSize());
}
// Append the given data to the array.
void Append(const ValueType other[], UPInt count)
{
Data.Append(other, count);
}
class Iterator
{
SelfType* pArray;
SPInt CurIndex;
public:
Iterator() : pArray(0), CurIndex(-1) {}
Iterator(SelfType* parr, SPInt idx = 0) : pArray(parr), CurIndex(idx) {}
bool operator==(const Iterator& it) const { return pArray == it.pArray && CurIndex == it.CurIndex; }
bool operator!=(const Iterator& it) const { return pArray != it.pArray || CurIndex != it.CurIndex; }
Iterator& operator++()
{
if (pArray)
{
if (CurIndex < (SPInt)pArray->GetSize())
++CurIndex;
}
return *this;
}
Iterator operator++(int)
{
Iterator it(*this);
operator++();
return it;
}
Iterator& operator--()
{
if (pArray)
{
if (CurIndex >= 0)
--CurIndex;
}
return *this;
}
Iterator operator--(int)
{
Iterator it(*this);
operator--();
return it;
}
Iterator operator+(int delta) const
{
return Iterator(pArray, CurIndex + delta);
}
Iterator operator-(int delta) const
{
return Iterator(pArray, CurIndex - delta);
}
SPInt operator-(const Iterator& right) const
{
OVR_ASSERT(pArray == right.pArray);
return CurIndex - right.CurIndex;
}
ValueType& operator*() const { OVR_ASSERT(pArray); return (*pArray)[CurIndex]; }
ValueType* operator->() const { OVR_ASSERT(pArray); return &(*pArray)[CurIndex]; }
ValueType* GetPtr() const { OVR_ASSERT(pArray); return &(*pArray)[CurIndex]; }
bool IsFinished() const { return !pArray || CurIndex < 0 || CurIndex >= (int)pArray->GetSize(); }
void Remove()
{
if (!IsFinished())
pArray->RemoveAt(CurIndex);
}
SPInt GetIndex() const { return CurIndex; }
};
Iterator Begin() { return Iterator(this); }
Iterator End() { return Iterator(this, (SPInt)GetSize()); }
Iterator Last() { return Iterator(this, (SPInt)GetSize() - 1); }
class ConstIterator
{
const SelfType* pArray;
SPInt CurIndex;
public:
ConstIterator() : pArray(0), CurIndex(-1) {}
ConstIterator(const SelfType* parr, SPInt idx = 0) : pArray(parr), CurIndex(idx) {}
bool operator==(const ConstIterator& it) const { return pArray == it.pArray && CurIndex == it.CurIndex; }
bool operator!=(const ConstIterator& it) const { return pArray != it.pArray || CurIndex != it.CurIndex; }
ConstIterator& operator++()
{
if (pArray)
{
if (CurIndex < (int)pArray->GetSize())
++CurIndex;
}
return *this;
}
ConstIterator operator++(int)
{
ConstIterator it(*this);
operator++();
return it;
}
ConstIterator& operator--()
{
if (pArray)
{
if (CurIndex >= 0)
--CurIndex;
}
return *this;
}
ConstIterator operator--(int)
{
ConstIterator it(*this);
operator--();
return it;
}
ConstIterator operator+(int delta) const
{
return ConstIterator(pArray, CurIndex + delta);
}
ConstIterator operator-(int delta) const
{
return ConstIterator(pArray, CurIndex - delta);
}
SPInt operator-(const ConstIterator& right) const
{
OVR_ASSERT(pArray == right.pArray);
return CurIndex - right.CurIndex;
}
const ValueType& operator*() const { OVR_ASSERT(pArray); return (*pArray)[CurIndex]; }
const ValueType* operator->() const { OVR_ASSERT(pArray); return &(*pArray)[CurIndex]; }
const ValueType* GetPtr() const { OVR_ASSERT(pArray); return &(*pArray)[CurIndex]; }
bool IsFinished() const { return !pArray || CurIndex < 0 || CurIndex >= (int)pArray->GetSize(); }
SPInt GetIndex() const { return CurIndex; }
};
ConstIterator Begin() const { return ConstIterator(this); }
ConstIterator End() const { return ConstIterator(this, (SPInt)GetSize()); }
ConstIterator Last() const { return ConstIterator(this, (SPInt)GetSize() - 1); }
protected:
ArrayData Data;
};
//-----------------------------------------------------------------------------------
// ***** Array
//
// General purpose array for movable objects that require explicit
// construction/destruction.
template<class T, class SizePolicy=ArrayDefaultPolicy>
class Array : public ArrayBase<ArrayData<T, ContainerAllocator<T>, SizePolicy> >
{
public:
typedef T ValueType;
typedef ContainerAllocator<T> AllocatorType;
typedef SizePolicy SizePolicyType;
typedef Array<T, SizePolicy> SelfType;
typedef ArrayBase<ArrayData<T, ContainerAllocator<T>, SizePolicy> > BaseType;
Array() : BaseType() {}
Array(UPInt size) : BaseType(size) {}
Array(const SizePolicyType& p) : BaseType() { SetSizePolicy(p); }
Array(const SelfType& a) : BaseType(a) {}
const SelfType& operator=(const SelfType& a) { BaseType::operator=(a); return *this; }
};
// ***** ArrayPOD
//
// General purpose array for movable objects that DOES NOT require
// construction/destruction. Constructors and destructors are not called!
// Global heap is in use.
template<class T, class SizePolicy=ArrayDefaultPolicy>
class ArrayPOD : public ArrayBase<ArrayData<T, ContainerAllocator_POD<T>, SizePolicy> >
{
public:
typedef T ValueType;
typedef ContainerAllocator_POD<T> AllocatorType;
typedef SizePolicy SizePolicyType;
typedef ArrayPOD<T, SizePolicy> SelfType;
typedef ArrayBase<ArrayData<T, ContainerAllocator_POD<T>, SizePolicy> > BaseType;
ArrayPOD() : BaseType() {}
ArrayPOD(UPInt size) : BaseType(size) {}
ArrayPOD(const SizePolicyType& p) : BaseType() { SetSizePolicy(p); }
ArrayPOD(const SelfType& a) : BaseType(a) {}
const SelfType& operator=(const SelfType& a) { BaseType::operator=(a); return *this; }
};
// ***** ArrayCPP
//
// General purpose, fully C++ compliant array. Can be used with non-movable data.
// Global heap is in use.
template<class T, class SizePolicy=ArrayDefaultPolicy>
class ArrayCPP : public ArrayBase<ArrayData<T, ContainerAllocator_CPP<T>, SizePolicy> >
{
public:
typedef T ValueType;
typedef ContainerAllocator_CPP<T> AllocatorType;
typedef SizePolicy SizePolicyType;
typedef ArrayCPP<T, SizePolicy> SelfType;
typedef ArrayBase<ArrayData<T, ContainerAllocator_CPP<T>, SizePolicy> > BaseType;
ArrayCPP() : BaseType() {}
ArrayCPP(UPInt size) : BaseType(size) {}
ArrayCPP(const SizePolicyType& p) : BaseType() { SetSizePolicy(p); }
ArrayCPP(const SelfType& a) : BaseType(a) {}
const SelfType& operator=(const SelfType& a) { BaseType::operator=(a); return *this; }
};
// ***** ArrayCC
//
// A modification of the array that uses the given default value to
// construct the elements. The constructors and destructors are
// properly called, the objects must be movable.
template<class T, class SizePolicy=ArrayDefaultPolicy>
class ArrayCC : public ArrayBase<ArrayDataCC<T, ContainerAllocator<T>, SizePolicy> >
{
public:
typedef T ValueType;
typedef ContainerAllocator<T> AllocatorType;
typedef SizePolicy SizePolicyType;
typedef ArrayCC<T, SizePolicy> SelfType;
typedef ArrayBase<ArrayDataCC<T, ContainerAllocator<T>, SizePolicy> > BaseType;
ArrayCC(const ValueType& defval) : BaseType(defval) {}
ArrayCC(const ValueType& defval, UPInt size) : BaseType(defval, size) {}
ArrayCC(const ValueType& defval, const SizePolicyType& p) : BaseType(defval) { SetSizePolicy(p); }
ArrayCC(const SelfType& a) : BaseType(a) {}
const SelfType& operator=(const SelfType& a) { BaseType::operator=(a); return *this; }
};
} // OVR
#endif

View File

@ -0,0 +1,162 @@
/************************************************************************************
Filename : OVR_Atomic.cpp
Content : Contains atomic operations and inline fastest locking
functionality. Will contain #ifdefs for OS efficiency.
Have non-thread-safe implementation if not available.
Created : September 19, 2012
Notes :
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_Atomic.h"
#include "OVR_Allocator.h"
#ifdef OVR_ENABLE_THREADS
// Include Windows 8-Metro compatible Synchronization API
#if defined(OVR_OS_WIN32) && defined(NTDDI_WIN8) && (NTDDI_VERSION >= NTDDI_WIN8)
#include <synchapi.h>
#endif
namespace OVR {
// ***** Windows Lock implementation
#if defined(OVR_OS_WIN32)
// ***** Standard Win32 Lock implementation
// Constructors
Lock::Lock(unsigned spinCount)
{
#if defined(NTDDI_WIN8) && (NTDDI_VERSION >= NTDDI_WIN8)
// On Windows 8 we use InitializeCriticalSectionEx due to Metro-Compatibility
InitializeCriticalSectionEx(&cs, spinCount,
OVR_DEBUG_SELECT(NULL, CRITICAL_SECTION_NO_DEBUG_INFO));
#else
// Spin count init critical section function prototype for Window NT
typedef BOOL (WINAPI *Function_InitializeCriticalSectionAndSpinCount)
(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount);
// Try to load function dynamically so that we don't require NT
// On Windows NT we will use InitializeCriticalSectionAndSpinCount
static bool initTried = 0;
static Function_InitializeCriticalSectionAndSpinCount pInitFn = 0;
if (!initTried)
{
HMODULE hmodule = ::LoadLibrary(OVR_STR("kernel32.dll"));
pInitFn = (Function_InitializeCriticalSectionAndSpinCount)
::GetProcAddress(hmodule, "InitializeCriticalSectionAndSpinCount");
initTried = true;
}
// Initialize the critical section
if (pInitFn)
pInitFn(&cs, spinCount);
else
::InitializeCriticalSection(&cs);
#endif
}
Lock::~Lock()
{
DeleteCriticalSection(&cs);
}
#endif
//-------------------------------------------------------------------------------------
// ***** SharedLock
// This is a general purpose globally shared Lock implementation that should probably be
// moved to Kernel.
// May in theory busy spin-wait if we hit contention on first lock creation,
// but this shouldn't matter in practice since Lock* should be cached.
enum { LockInitMarker = 0xFFFFFFFF };
Lock* SharedLock::GetLockAddRef()
{
int oldUseCount;
do {
oldUseCount = UseCount;
if (oldUseCount == LockInitMarker)
continue;
if (oldUseCount == 0)
{
// Initialize marker
if (AtomicOps<int>::CompareAndSet_Sync(&UseCount, 0, LockInitMarker))
{
Construct<Lock>(Buffer);
do { }
while (!AtomicOps<int>::CompareAndSet_Sync(&UseCount, LockInitMarker, 1));
return toLock();
}
continue;
}
} while (!AtomicOps<int>::CompareAndSet_NoSync(&UseCount, oldUseCount, oldUseCount + 1));
return toLock();
}
void SharedLock::ReleaseLock(Lock* plock)
{
OVR_UNUSED(plock);
OVR_ASSERT(plock == toLock());
int oldUseCount;
do {
oldUseCount = UseCount;
OVR_ASSERT(oldUseCount != LockInitMarker);
if (oldUseCount == 1)
{
// Initialize marker
if (AtomicOps<int>::CompareAndSet_Sync(&UseCount, 1, LockInitMarker))
{
Destruct<Lock>(toLock());
do { }
while (!AtomicOps<int>::CompareAndSet_Sync(&UseCount, LockInitMarker, 0));
return;
}
continue;
}
} while (!AtomicOps<int>::CompareAndSet_NoSync(&UseCount, oldUseCount, oldUseCount - 1));
}
} // OVR
#endif // OVR_ENABLE_THREADS

View File

@ -0,0 +1,890 @@
/************************************************************************************
PublicHeader: OVR.h
Filename : OVR_Atomic.h
Content : Contains atomic operations and inline fastest locking
functionality. Will contain #ifdefs for OS efficiency.
Have non-thread-safe implementaion if not available.
Created : September 19, 2012
Notes :
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_Atomic_h
#define OVR_Atomic_h
#include "OVR_Types.h"
// Include System thread functionality.
#if defined(OVR_OS_WIN32)
#include <windows.h>
#else
#include <pthread.h>
#endif
namespace OVR {
// ****** Declared classes
// If there is NO thread support we implement AtomicOps and
// Lock objects as no-ops. The other classes are not defined.
template<class C> class AtomicOps;
template<class T> class AtomicInt;
template<class T> class AtomicPtr;
class Lock;
//-----------------------------------------------------------------------------------
// ***** AtomicOps
// Atomic operations are provided by the AtomicOps templates class,
// implemented through system-specific AtomicOpsRaw specializations.
// It provides several fundamental operations such as Exchange, ExchangeAdd
// CompareAndSet, and Store_Release. Each function includes several memory
// synchronization versions, important for multiprocessing CPUs with weak
// memory consistency. The following memory fencing strategies are supported:
//
// - NoSync. No memory synchronization is done for atomic op.
// - Release. All other memory writes are completed before atomic op
// writes its results.
// - Acquire. Further memory reads are forced to wait until atomic op
// executes, guaranteeing that the right values will be seen.
// - Sync. A combination of Release and Acquire.
// *** AtomicOpsRaw
// AtomicOpsRaw is a specialized template that provides atomic operations
// used by AtomicOps. This class has two fundamental qualities: (1) it
// defines a type T of correct size, and (2) provides operations that work
// atomically, such as Exchange_Sync and CompareAndSet_Release.
// AtomicOpsRawBase class contains shared constants/classes for AtomicOpsRaw.
// The primary thing is does is define sync class objects, whose destructor and
// constructor provide places to insert appropriate synchronization calls, on
// systems where such calls are necessary. So far, the breakdown is as follows:
//
// - X86 systems don't need custom syncs, since their exchange/atomic
// instructions are implicitly synchronized.
// - PowerPC requires lwsync/isync instructions that can use this mechanism.
// - If some other systems require a mechanism where syncing type is associated
// with a particular instruction, the default implementation (which implements
// all Sync, Acquire, and Release modes in terms of NoSync and fence) may not
// work. Ii that case it will need to be #ifdef-ed conditionally.
struct AtomicOpsRawBase
{
#if !defined(OVR_ENABLE_THREADS) || defined(OVR_CPU_X86) || defined(OVR_OS_WIN32) || defined(OVR_OS_IPHONE)
// Need to have empty constructor to avoid class 'unused' variable warning.
struct FullSync { inline FullSync() { } };
struct AcquireSync { inline AcquireSync() { } };
struct ReleaseSync { inline ReleaseSync() { } };
#elif defined(OVR_CPU_PPC64) || defined(OVR_CPU_PPC)
struct FullSync { inline FullSync() { asm volatile("sync\n"); } ~FullSync() { asm volatile("isync\n"); } };
struct AcquireSync { inline AcquireSync() { } ~AcquireSync() { asm volatile("isync\n"); } };
struct ReleaseSync { inline ReleaseSync() { asm volatile("sync\n"); } };
#elif defined(OVR_CPU_MIPS)
struct FullSync { inline FullSync() { asm volatile("sync\n"); } ~FullSync() { asm volatile("sync\n"); } };
struct AcquireSync { inline AcquireSync() { } ~AcquireSync() { asm volatile("sync\n"); } };
struct ReleaseSync { inline ReleaseSync() { asm volatile("sync\n"); } };
#elif defined(OVR_CPU_ARM)
struct FullSync { inline FullSync() { asm volatile("dmb\n"); } ~FullSync() { asm volatile("dmb\n"); } };
struct AcquireSync { inline AcquireSync() { } ~AcquireSync() { asm volatile("dmb\n"); } };
struct ReleaseSync { inline ReleaseSync() { asm volatile("dmb\n"); } };
#elif defined(OVR_CC_GNU) && (__GNUC__ >= 4)
// __sync functions are already full sync
struct FullSync { inline FullSync() { } };
struct AcquireSync { inline AcquireSync() { } };
struct ReleaseSync { inline ReleaseSync() { } };
#endif
};
// 4-Byte raw data atomic op implementation class.
struct AtomicOpsRaw_4ByteImpl : public AtomicOpsRawBase
{
#if !defined(OVR_ENABLE_THREADS)
// Provide a type for no-thread-support cases. Used by AtomicOpsRaw_DefImpl.
typedef UInt32 T;
// *** Thread - Safe Atomic Versions.
#elif defined(OVR_OS_WIN32)
// Use special defined for VC6, where volatile is not used and
// InterlockedCompareExchange is declared incorrectly.
typedef LONG T;
#if defined(OVR_CC_MSVC) && (OVR_CC_MSVC < 1300)
typedef T* InterlockTPtr;
typedef LPVOID ET;
typedef ET* InterlockETPtr;
#else
typedef volatile T* InterlockTPtr;
typedef T ET;
typedef InterlockTPtr InterlockETPtr;
#endif
inline static T Exchange_NoSync(volatile T* p, T val) { return InterlockedExchange((InterlockTPtr)p, val); }
inline static T ExchangeAdd_NoSync(volatile T* p, T val) { return InterlockedExchangeAdd((InterlockTPtr)p, val); }
inline static bool CompareAndSet_NoSync(volatile T* p, T c, T val) { return InterlockedCompareExchange((InterlockETPtr)p, (ET)val, (ET)c) == (ET)c; }
#elif defined(OVR_CPU_PPC64) || defined(OVR_CPU_PPC)
typedef UInt32 T;
static inline UInt32 Exchange_NoSync(volatile UInt32 *i, UInt32 j)
{
UInt32 ret;
asm volatile("1:\n\t"
"lwarx %[r],0,%[i]\n\t"
"stwcx. %[j],0,%[i]\n\t"
"bne- 1b\n"
: "+m" (*i), [r] "=&b" (ret) : [i] "b" (i), [j] "b" (j) : "cc", "memory");
return ret;
}
static inline UInt32 ExchangeAdd_NoSync(volatile UInt32 *i, UInt32 j)
{
UInt32 dummy, ret;
asm volatile("1:\n\t"
"lwarx %[r],0,%[i]\n\t"
"add %[o],%[r],%[j]\n\t"
"stwcx. %[o],0,%[i]\n\t"
"bne- 1b\n"
: "+m" (*i), [r] "=&b" (ret), [o] "=&r" (dummy) : [i] "b" (i), [j] "b" (j) : "cc", "memory");
return ret;
}
static inline bool CompareAndSet_NoSync(volatile UInt32 *i, UInt32 c, UInt32 value)
{
UInt32 ret;
asm volatile("1:\n\t"
"lwarx %[r],0,%[i]\n\t"
"cmpw 0,%[r],%[cmp]\n\t"
"mfcr %[r]\n\t"
"bne- 2f\n\t"
"stwcx. %[val],0,%[i]\n\t"
"bne- 1b\n\t"
"2:\n"
: "+m" (*i), [r] "=&b" (ret) : [i] "b" (i), [cmp] "b" (c), [val] "b" (value) : "cc", "memory");
return (ret & 0x20000000) ? 1 : 0;
}
#elif defined(OVR_CPU_MIPS)
typedef UInt32 T;
static inline UInt32 Exchange_NoSync(volatile UInt32 *i, UInt32 j)
{
UInt32 ret;
asm volatile("1:\n\t"
"ll %[r],0(%[i])\n\t"
"sc %[j],0(%[i])\n\t"
"beq %[j],$0,1b\n\t"
"nop \n"
: "+m" (*i), [r] "=&d" (ret) : [i] "d" (i), [j] "d" (j) : "cc", "memory");
return ret;
}
static inline UInt32 ExchangeAdd_NoSync(volatile UInt32 *i, UInt32 j)
{
UInt32 ret;
asm volatile("1:\n\t"
"ll %[r],0(%[i])\n\t"
"addu %[j],%[r],%[j]\n\t"
"sc %[j],0(%[i])\n\t"
"beq %[j],$0,1b\n\t"
"nop \n"
: "+m" (*i), [r] "=&d" (ret) : [i] "d" (i), [j] "d" (j) : "cc", "memory");
return ret;
}
static inline bool CompareAndSet_NoSync(volatile UInt32 *i, UInt32 c, UInt32 value)
{
UInt32 ret, dummy;
asm volatile("1:\n\t"
"move %[r],$0\n\t"
"ll %[o],0(%[i])\n\t"
"bne %[o],%[c],2f\n\t"
"move %[r],%[v]\n\t"
"sc %[r],0(%[i])\n\t"
"beq %[r],$0,1b\n\t"
"nop \n\t"
"2:\n"
: "+m" (*i),[r] "=&d" (ret), [o] "=&d" (dummy) : [i] "d" (i), [c] "d" (c), [v] "d" (value)
: "cc", "memory");
return ret;
}
#elif defined(OVR_CPU_ARM) && defined(OVR_CC_ARM)
typedef UInt32 T;
static inline UInt32 Exchange_NoSync(volatile UInt32 *i, UInt32 j)
{
for(;;)
{
T r = __ldrex(i);
if (__strex(j, i) == 0)
return r;
}
}
static inline UInt32 ExchangeAdd_NoSync(volatile UInt32 *i, UInt32 j)
{
for(;;)
{
T r = __ldrex(i);
if (__strex(r + j, i) == 0)
return r;
}
}
static inline bool CompareAndSet_NoSync(volatile UInt32 *i, UInt32 c, UInt32 value)
{
for(;;)
{
T r = __ldrex(i);
if (r != c)
return 0;
if (__strex(value, i) == 0)
return 1;
}
}
#elif defined(OVR_CPU_ARM)
typedef UInt32 T;
static inline UInt32 Exchange_NoSync(volatile UInt32 *i, UInt32 j)
{
UInt32 ret, dummy;
asm volatile("1:\n\t"
"ldrex %[r],[%[i]]\n\t"
"strex %[t],%[j],[%[i]]\n\t"
"cmp %[t],#0\n\t"
"bne 1b\n\t"
: "+m" (*i), [r] "=&r" (ret), [t] "=&r" (dummy) : [i] "r" (i), [j] "r" (j) : "cc", "memory");
return ret;
}
static inline UInt32 ExchangeAdd_NoSync(volatile UInt32 *i, UInt32 j)
{
UInt32 ret, dummy, test;
asm volatile("1:\n\t"
"ldrex %[r],[%[i]]\n\t"
"add %[o],%[r],%[j]\n\t"
"strex %[t],%[o],[%[i]]\n\t"
"cmp %[t],#0\n\t"
"bne 1b\n\t"
: "+m" (*i), [r] "=&r" (ret), [o] "=&r" (dummy), [t] "=&r" (test) : [i] "r" (i), [j] "r" (j) : "cc", "memory");
return ret;
}
static inline bool CompareAndSet_NoSync(volatile UInt32 *i, UInt32 c, UInt32 value)
{
UInt32 ret = 1, dummy, test;
asm volatile("1:\n\t"
"ldrex %[o],[%[i]]\n\t"
"cmp %[o],%[c]\n\t"
"bne 2f\n\t"
"strex %[r],%[v],[%[i]]\n\t"
"cmp %[r],#0\n\t"
"bne 1b\n\t"
"2:\n"
: "+m" (*i),[r] "=&r" (ret), [o] "=&r" (dummy), [t] "=&r" (test) : [i] "r" (i), [c] "r" (c), [v] "r" (value)
: "cc", "memory");
return !ret;
}
#elif defined(OVR_CPU_X86)
typedef UInt32 T;
static inline UInt32 Exchange_NoSync(volatile UInt32 *i, UInt32 j)
{
asm volatile("xchgl %1,%[i]\n"
: "+m" (*i), "=q" (j) : [i] "m" (*i), "1" (j) : "cc", "memory");
return j;
}
static inline UInt32 ExchangeAdd_NoSync(volatile UInt32 *i, UInt32 j)
{
asm volatile("lock; xaddl %1,%[i]\n"
: "+m" (*i), "+q" (j) : [i] "m" (*i) : "cc", "memory");
return j;
}
static inline bool CompareAndSet_NoSync(volatile UInt32 *i, UInt32 c, UInt32 value)
{
UInt32 ret;
asm volatile("lock; cmpxchgl %[v],%[i]\n"
: "+m" (*i), "=a" (ret) : [i] "m" (*i), "1" (c), [v] "q" (value) : "cc", "memory");
return (ret == c);
}
#elif defined(OVR_CC_GNU) && (__GNUC__ >= 4 && __GNUC_MINOR__ >= 1)
typedef UInt32 T;
static inline T Exchange_NoSync(volatile T *i, T j)
{
T v;
do {
v = *i;
} while (!__sync_bool_compare_and_swap(i, v, j));
return v;
}
static inline T ExchangeAdd_NoSync(volatile T *i, T j)
{
return __sync_fetch_and_add(i, j);
}
static inline bool CompareAndSet_NoSync(volatile T *i, T c, T value)
{
return __sync_bool_compare_and_swap(i, c, value);
}
#endif // OS
};
// 8-Byte raw data data atomic op implementation class.
// Currently implementation is provided only on systems with 64-bit pointers.
struct AtomicOpsRaw_8ByteImpl : public AtomicOpsRawBase
{
#if !defined(OVR_64BIT_POINTERS) || !defined(OVR_ENABLE_THREADS)
// Provide a type for no-thread-support cases. Used by AtomicOpsRaw_DefImpl.
typedef UInt64 T;
// *** Thread - Safe OS specific versions.
#elif defined(OVR_OS_WIN32)
// This is only for 64-bit systems.
typedef LONG64 T;
typedef volatile T* InterlockTPtr;
inline static T Exchange_NoSync(volatile T* p, T val) { return InterlockedExchange64((InterlockTPtr)p, val); }
inline static T ExchangeAdd_NoSync(volatile T* p, T val) { return InterlockedExchangeAdd64((InterlockTPtr)p, val); }
inline static bool CompareAndSet_NoSync(volatile T* p, T c, T val) { return InterlockedCompareExchange64((InterlockTPtr)p, val, c) == c; }
#elif defined(OVR_CPU_PPC64)
typedef UInt64 T;
static inline UInt64 Exchange_NoSync(volatile UInt64 *i, UInt64 j)
{
UInt64 dummy, ret;
asm volatile("1:\n\t"
"ldarx %[r],0,%[i]\n\t"
"mr %[o],%[j]\n\t"
"stdcx. %[o],0,%[i]\n\t"
"bne- 1b\n"
: "+m" (*i), [r] "=&b" (ret), [o] "=&r" (dummy) : [i] "b" (i), [j] "b" (j) : "cc");
return ret;
}
static inline UInt64 ExchangeAdd_NoSync(volatile UInt64 *i, UInt64 j)
{
UInt64 dummy, ret;
asm volatile("1:\n\t"
"ldarx %[r],0,%[i]\n\t"
"add %[o],%[r],%[j]\n\t"
"stdcx. %[o],0,%[i]\n\t"
"bne- 1b\n"
: "+m" (*i), [r] "=&b" (ret), [o] "=&r" (dummy) : [i] "b" (i), [j] "b" (j) : "cc");
return ret;
}
static inline bool CompareAndSet_NoSync(volatile UInt64 *i, UInt64 c, UInt64 value)
{
UInt64 ret, dummy;
asm volatile("1:\n\t"
"ldarx %[r],0,%[i]\n\t"
"cmpw 0,%[r],%[cmp]\n\t"
"mfcr %[r]\n\t"
"bne- 2f\n\t"
"stdcx. %[val],0,%[i]\n\t"
"bne- 1b\n\t"
"2:\n"
: "+m" (*i), [r] "=&b" (ret), [o] "=&r" (dummy) : [i] "b" (i), [cmp] "b" (c), [val] "b" (value) : "cc");
return (ret & 0x20000000) ? 1 : 0;
}
#elif defined(OVR_CC_GNU) && (__GNUC__ >= 4 && __GNUC_MINOR__ >= 1)
typedef UInt64 T;
static inline T Exchange_NoSync(volatile T *i, T j)
{
T v;
do {
v = *i;
} while (!__sync_bool_compare_and_swap(i, v, j));
return v;
}
static inline T ExchangeAdd_NoSync(volatile T *i, T j)
{
return __sync_fetch_and_add(i, j);
}
static inline bool CompareAndSet_NoSync(volatile T *i, T c, T value)
{
return __sync_bool_compare_and_swap(i, c, value);
}
#endif // OS
};
// Default implementation for AtomicOpsRaw; provides implementation of mem-fenced
// atomic operations where fencing is done with a sync object wrapped around a NoSync
// operation implemented in the base class. If such implementation is not possible
// on a given platform, #ifdefs can be used to disable it and then op functions can be
// implemented individually in the appropriate AtomicOpsRaw<size> class.
template<class O>
struct AtomicOpsRaw_DefImpl : public O
{
typedef typename O::T O_T;
typedef typename O::FullSync O_FullSync;
typedef typename O::AcquireSync O_AcquireSync;
typedef typename O::ReleaseSync O_ReleaseSync;
// If there is no thread support, provide the default implementation. In this case,
// the base class (0) must still provide the T declaration.
#ifndef OVR_ENABLE_THREADS
// Atomic exchange of val with argument. Returns old val.
inline static O_T Exchange_NoSync(volatile O_T* p, O_T val) { O_T old = *p; *p = val; return old; }
// Adds a new val to argument; returns its old val.
inline static O_T ExchangeAdd_NoSync(volatile O_T* p, O_T val) { O_T old = *p; *p += val; return old; }
// Compares the argument data with 'c' val.
// If succeeded, stores val int '*p' and returns true; otherwise returns false.
inline static bool CompareAndSet_NoSync(volatile O_T* p, O_T c, O_T val) { if (*p==c) { *p = val; return 1; } return 0; }
#endif
// If NoSync wrapped implementation may not be possible, it this block should be
// replaced with per-function implementation in O.
// "AtomicOpsRaw_DefImpl<O>::" prefix in calls below.
inline static O_T Exchange_Sync(volatile O_T* p, O_T val) { O_FullSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::Exchange_NoSync(p, val); }
inline static O_T Exchange_Release(volatile O_T* p, O_T val) { O_ReleaseSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::Exchange_NoSync(p, val); }
inline static O_T Exchange_Acquire(volatile O_T* p, O_T val) { O_AcquireSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::Exchange_NoSync(p, val); }
inline static O_T ExchangeAdd_Sync(volatile O_T* p, O_T val) { O_FullSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::ExchangeAdd_NoSync(p, val); }
inline static O_T ExchangeAdd_Release(volatile O_T* p, O_T val) { O_ReleaseSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::ExchangeAdd_NoSync(p, val); }
inline static O_T ExchangeAdd_Acquire(volatile O_T* p, O_T val) { O_AcquireSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::ExchangeAdd_NoSync(p, val); }
inline static bool CompareAndSet_Sync(volatile O_T* p, O_T c, O_T val) { O_FullSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::CompareAndSet_NoSync(p,c,val); }
inline static bool CompareAndSet_Release(volatile O_T* p, O_T c, O_T val) { O_ReleaseSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::CompareAndSet_NoSync(p,c,val); }
inline static bool CompareAndSet_Acquire(volatile O_T* p, O_T c, O_T val) { O_AcquireSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::CompareAndSet_NoSync(p,c,val); }
// Loads and stores with memory fence. These have only the relevant versions.
#ifdef OVR_CPU_X86
// On X86, Store_Release is implemented as exchange. Note that we can also
// consider 'sfence' in the future, although it is not as compatible with older CPUs.
inline static void Store_Release(volatile O_T* p, O_T val) { Exchange_Release(p, val); }
#else
inline static void Store_Release(volatile O_T* p, O_T val) { O_ReleaseSync sync; OVR_UNUSED(sync); *p = val; }
#endif
inline static O_T Load_Acquire(const volatile O_T* p) { O_AcquireSync sync; OVR_UNUSED(sync); return *p; }
};
template<int size>
struct AtomicOpsRaw : public AtomicOpsRawBase { };
template<>
struct AtomicOpsRaw<4> : public AtomicOpsRaw_DefImpl<AtomicOpsRaw_4ByteImpl>
{
// Ensure that assigned type size is correct.
AtomicOpsRaw()
{ OVR_COMPILER_ASSERT(sizeof(AtomicOpsRaw_DefImpl<AtomicOpsRaw_4ByteImpl>::T) == 4); }
};
template<>
struct AtomicOpsRaw<8> : public AtomicOpsRaw_DefImpl<AtomicOpsRaw_8ByteImpl>
{
AtomicOpsRaw()
{ OVR_COMPILER_ASSERT(sizeof(AtomicOpsRaw_DefImpl<AtomicOpsRaw_8ByteImpl>::T) == 8); }
};
// *** AtomicOps - implementation of atomic Ops for specified class
// Implements atomic ops on a class, provided that the object is either
// 4 or 8 bytes in size (depending on the AtomicOpsRaw specializations
// available). Relies on AtomicOpsRaw for much of implementation.
template<class C>
class AtomicOps
{
typedef AtomicOpsRaw<sizeof(C)> Ops;
typedef typename Ops::T T;
typedef volatile typename Ops::T* PT;
// We cast through unions to (1) avoid pointer size compiler warnings
// and (2) ensure that there are no problems with strict pointer aliasing.
union C2T_union { C c; T t; };
public:
// General purpose implementation for standard syncs.
inline static C Exchange_Sync(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::Exchange_Sync((PT)p, u.t); return u.c; }
inline static C Exchange_Release(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::Exchange_Release((PT)p, u.t); return u.c; }
inline static C Exchange_Acquire(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::Exchange_Acquire((PT)p, u.t); return u.c; }
inline static C Exchange_NoSync(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::Exchange_NoSync((PT)p, u.t); return u.c; }
inline static C ExchangeAdd_Sync(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::ExchangeAdd_Sync((PT)p, u.t); return u.c; }
inline static C ExchangeAdd_Release(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::ExchangeAdd_Release((PT)p, u.t); return u.c; }
inline static C ExchangeAdd_Acquire(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::ExchangeAdd_Acquire((PT)p, u.t); return u.c; }
inline static C ExchangeAdd_NoSync(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::ExchangeAdd_NoSync((PT)p, u.t); return u.c; }
inline static bool CompareAndSet_Sync(volatile C* p, C c, C val) { C2T_union u,cu; u.c = val; cu.c = c; return Ops::CompareAndSet_Sync((PT)p, cu.t, u.t); }
inline static bool CompareAndSet_Release(volatile C* p, C c, C val){ C2T_union u,cu; u.c = val; cu.c = c; return Ops::CompareAndSet_Release((PT)p, cu.t, u.t); }
inline static bool CompareAndSet_Relse(volatile C* p, C c, C val){ C2T_union u,cu; u.c = val; cu.c = c; return Ops::CompareAndSet_Acquire((PT)p, cu.t, u.t); }
inline static bool CompareAndSet_NoSync(volatile C* p, C c, C val) { C2T_union u,cu; u.c = val; cu.c = c; return Ops::CompareAndSet_NoSync((PT)p, cu.t, u.t); }
// Loads and stores with memory fence. These have only the relevant versions.
inline static void Store_Release(volatile C* p, C val) { C2T_union u; u.c = val; Ops::Store_Release((PT)p, u.t); }
inline static C Load_Acquire(const volatile C* p) { C2T_union u; u.t = Ops::Load_Acquire((PT)p); return u.c; }
};
// Atomic value base class - implements operations shared for integers and pointers.
template<class T>
class AtomicValueBase
{
protected:
typedef AtomicOps<T> Ops;
public:
volatile T Value;
inline AtomicValueBase() { }
explicit inline AtomicValueBase(T val) { Ops::Store_Release(&Value, val); }
// Most libraries (TBB and Joshua Scholar's) library do not do Load_Acquire
// here, since most algorithms do not require atomic loads. Needs some research.
inline operator T() const { return Value; }
// *** Standard Atomic inlines
inline T Exchange_Sync(T val) { return Ops::Exchange_Sync(&Value, val); }
inline T Exchange_Release(T val) { return Ops::Exchange_Release(&Value, val); }
inline T Exchange_Acquire(T val) { return Ops::Exchange_Acquire(&Value, val); }
inline T Exchange_NoSync(T val) { return Ops::Exchange_NoSync(&Value, val); }
inline bool CompareAndSet_Sync(T c, T val) { return Ops::CompareAndSet_Sync(&Value, c, val); }
inline bool CompareAndSet_Release(T c, T val) { return Ops::CompareAndSet_Release(&Value, c, val); }
inline bool CompareAndSet_Acquire(T c, T val) { return Ops::CompareAndSet_Relse(&Value, c, val); }
inline bool CompareAndSet_NoSync(T c, T val) { return Ops::CompareAndSet_NoSync(&Value, c, val); }
// Load & Store.
inline void Store_Release(T val) { Ops::Store_Release(&Value, val); }
inline T Load_Acquire() const { return Ops::Load_Acquire(&Value); }
};
// ***** AtomicPtr - Atomic pointer template
// This pointer class supports atomic assignments with release,
// increment / decrement operations, and conditional compare + set.
template<class T>
class AtomicPtr : public AtomicValueBase<T*>
{
typedef typename AtomicValueBase<T*>::Ops Ops;
public:
// Initialize pointer value to 0 by default; use Store_Release only with explicit constructor.
inline AtomicPtr() : AtomicValueBase<T*>() { this->Value = 0; }
explicit inline AtomicPtr(T* val) : AtomicValueBase<T*>(val) { }
// Pointer access.
inline T* operator -> () const { return this->Load_Acquire(); }
// It looks like it is convenient to have Load_Acquire characteristics
// for this, since that is convenient for algorithms such as linked
// list traversals that can be added to bu another thread.
inline operator T* () const { return this->Load_Acquire(); }
// *** Standard Atomic inlines (applicable to pointers)
// ExhangeAdd considers pointer size for pointers.
template<class I>
inline T* ExchangeAdd_Sync(I incr) { return Ops::ExchangeAdd_Sync(&this->Value, ((T*)0) + incr); }
template<class I>
inline T* ExchangeAdd_Release(I incr) { return Ops::ExchangeAdd_Release(&this->Value, ((T*)0) + incr); }
template<class I>
inline T* ExchangeAdd_Acquire(I incr) { return Ops::ExchangeAdd_Acquire(&this->Value, ((T*)0) + incr); }
template<class I>
inline T* ExchangeAdd_NoSync(I incr) { return Ops::ExchangeAdd_NoSync(&this->Value, ((T*)0) + incr); }
// *** Atomic Operators
inline T* operator = (T* val) { this->Store_Release(val); return val; }
template<class I>
inline T* operator += (I val) { return ExchangeAdd_Sync(val) + val; }
template<class I>
inline T* operator -= (I val) { return operator += (-val); }
inline T* operator ++ () { return ExchangeAdd_Sync(1) + 1; }
inline T* operator -- () { return ExchangeAdd_Sync(-1) - 1; }
inline T* operator ++ (int) { return ExchangeAdd_Sync(1); }
inline T* operator -- (int) { return ExchangeAdd_Sync(-1); }
};
// ***** AtomicInt - Atomic integer template
// Implements an atomic integer type; the exact type to use is provided
// as an argument. Supports atomic Acquire / Release semantics, atomic
// arithmetic operations, and atomic conditional compare + set.
template<class T>
class AtomicInt : public AtomicValueBase<T>
{
typedef typename AtomicValueBase<T>::Ops Ops;
public:
inline AtomicInt() : AtomicValueBase<T>() { }
explicit inline AtomicInt(T val) : AtomicValueBase<T>(val) { }
// *** Standard Atomic inlines (applicable to int)
inline T ExchangeAdd_Sync(T val) { return Ops::ExchangeAdd_Sync(&this->Value, val); }
inline T ExchangeAdd_Release(T val) { return Ops::ExchangeAdd_Release(&this->Value, val); }
inline T ExchangeAdd_Acquire(T val) { return Ops::ExchangeAdd_Acquire(&this->Value, val); }
inline T ExchangeAdd_NoSync(T val) { return Ops::ExchangeAdd_NoSync(&this->Value, val); }
// These increments could be more efficient because they don't return a value.
inline void Increment_Sync() { ExchangeAdd_Sync((T)1); }
inline void Increment_Release() { ExchangeAdd_Release((T)1); }
inline void Increment_Acquire() { ExchangeAdd_Acquire((T)1); }
inline void Increment_NoSync() { ExchangeAdd_NoSync((T)1); }
// *** Atomic Operators
inline T operator = (T val) { this->Store_Release(val); return val; }
inline T operator += (T val) { return ExchangeAdd_Sync(val) + val; }
inline T operator -= (T val) { return ExchangeAdd_Sync(0 - val) - val; }
inline T operator ++ () { return ExchangeAdd_Sync((T)1) + 1; }
inline T operator -- () { return ExchangeAdd_Sync(((T)0)-1) - 1; }
inline T operator ++ (int) { return ExchangeAdd_Sync((T)1); }
inline T operator -- (int) { return ExchangeAdd_Sync(((T)0)-1); }
// More complex atomic operations. Leave it to compiler whether to optimize them or not.
T operator &= (T arg)
{
T comp, newVal;
do {
comp = this->Value;
newVal = comp & arg;
} while(!this->CompareAndSet_Sync(comp, newVal));
return newVal;
}
T operator |= (T arg)
{
T comp, newVal;
do {
comp = this->Value;
newVal = comp | arg;
} while(!this->CompareAndSet_Sync(comp, newVal));
return newVal;
}
T operator ^= (T arg)
{
T comp, newVal;
do {
comp = this->Value;
newVal = comp ^ arg;
} while(!this->CompareAndSet_Sync(comp, newVal));
return newVal;
}
T operator *= (T arg)
{
T comp, newVal;
do {
comp = this->Value;
newVal = comp * arg;
} while(!this->CompareAndSet_Sync(comp, newVal));
return newVal;
}
T operator /= (T arg)
{
T comp, newVal;
do {
comp = this->Value;
newVal = comp / arg;
} while(!CompareAndSet_Sync(comp, newVal));
return newVal;
}
T operator >>= (unsigned bits)
{
T comp, newVal;
do {
comp = this->Value;
newVal = comp >> bits;
} while(!CompareAndSet_Sync(comp, newVal));
return newVal;
}
T operator <<= (unsigned bits)
{
T comp, newVal;
do {
comp = this->Value;
newVal = comp << bits;
} while(!this->CompareAndSet_Sync(comp, newVal));
return newVal;
}
};
//-----------------------------------------------------------------------------------
// ***** Lock
// Lock is a simplest and most efficient mutual-exclusion lock class.
// Unlike Mutex, it cannot be waited on.
class Lock
{
// NOTE: Locks are not allocatable and they themselves should not allocate
// memory by standard means. This is the case because StandardAllocator
// relies on this class.
// Make 'delete' private. Don't do this for 'new' since it can be redefined.
void operator delete(void*) {}
// *** Lock implementation for various platforms.
#if !defined(OVR_ENABLE_THREADS)
public:
// With no thread support, lock does nothing.
inline Lock() { }
inline Lock(unsigned) { }
inline ~Lock() { }
inline void DoLock() { }
inline void Unlock() { }
// Windows.
#elif defined(OVR_OS_WIN32)
CRITICAL_SECTION cs;
public:
Lock(unsigned spinCount = 0);
~Lock();
// Locking functions.
inline void DoLock() { ::EnterCriticalSection(&cs); }
inline void Unlock() { ::LeaveCriticalSection(&cs); }
#else
pthread_mutex_t mutex;
public:
static pthread_mutexattr_t RecursiveAttr;
static bool RecursiveAttrInit;
Lock (unsigned dummy = 0)
{
OVR_UNUSED(dummy);
if (!RecursiveAttrInit)
{
pthread_mutexattr_init(&RecursiveAttr);
pthread_mutexattr_settype(&RecursiveAttr, PTHREAD_MUTEX_RECURSIVE);
RecursiveAttrInit = 1;
}
pthread_mutex_init(&mutex,&RecursiveAttr);
}
~Lock () { pthread_mutex_destroy(&mutex); }
inline void DoLock() { pthread_mutex_lock(&mutex); }
inline void Unlock() { pthread_mutex_unlock(&mutex); }
#endif // OVR_ENABLE_THREDS
public:
// Locker class, used for automatic locking
class Locker
{
public:
Lock *pLock;
inline Locker(Lock *plock)
{ pLock = plock; pLock->DoLock(); }
inline ~Locker()
{ pLock->Unlock(); }
};
};
//-------------------------------------------------------------------------------------
// Globally shared Lock implementation used for MessageHandlers, etc.
class SharedLock
{
public:
SharedLock() : UseCount(0) {}
Lock* GetLockAddRef();
void ReleaseLock(Lock* plock);
private:
Lock* toLock() { return (Lock*)Buffer; }
// UseCount and max alignment.
volatile int UseCount;
UInt64 Buffer[(sizeof(Lock)+sizeof(UInt64)-1)/sizeof(UInt64)];
};
} // OVR
#endif

View File

@ -0,0 +1,66 @@
/************************************************************************************
PublicHeader: OVR.h
Filename : OVR_Color.h
Content : Contains color struct.
Created : February 7, 2013
Notes :
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_Color_h
#define OVR_Color_h
#include "OVR_Types.h"
namespace OVR {
struct Color
{
UByte R,G,B,A;
Color() {}
// Constructs color by channel. Alpha is set to 0xFF (fully visible)
// if not specified.
Color(unsigned char r,unsigned char g,unsigned char b, unsigned char a = 0xFF)
: R(r), G(g), B(b), A(a) { }
// 0xAARRGGBB - Common HTML color Hex layout
Color(unsigned c)
: R((unsigned char)(c>>16)), G((unsigned char)(c>>8)),
B((unsigned char)c), A((unsigned char)(c>>24)) { }
bool operator==(const Color& b) const
{
return R == b.R && G == b.G && B == b.B && A == b.A;
}
void GetRGBA(float *r, float *g, float *b, float* a) const
{
*r = R / 255.0f;
*g = G / 255.0f;
*b = B / 255.0f;
*a = A / 255.0f;
}
};
}
#endif

View File

@ -0,0 +1,267 @@
/************************************************************************************
PublicHeader: OVR.h
Filename : OVR_ContainerAllocator.h
Content : Template allocators and constructors for containers.
Created : September 19, 2012
Notes :
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_ContainerAllocator_h
#define OVR_ContainerAllocator_h
#include "OVR_Allocator.h"
#include <string.h>
namespace OVR {
//-----------------------------------------------------------------------------------
// ***** Container Allocator
// ContainerAllocator serves as a template argument for allocations done by
// containers, such as Array and Hash; replacing it could allow allocator
// substitution in containers.
class ContainerAllocatorBase
{
public:
static void* Alloc(UPInt size) { return OVR_ALLOC(size); }
static void* Realloc(void* p, UPInt newSize) { return OVR_REALLOC(p, newSize); }
static void Free(void *p) { OVR_FREE(p); }
};
//-----------------------------------------------------------------------------------
// ***** Constructors, Destructors, Copiers
// Plain Old Data - movable, no special constructors/destructor.
template<class T>
class ConstructorPOD
{
public:
static void Construct(void *) {}
static void Construct(void *p, const T& source)
{
*(T*)p = source;
}
// Same as above, but allows for a different type of constructor.
template <class S>
static void ConstructAlt(void *p, const S& source)
{
*(T*)p = source;
}
static void ConstructArray(void*, UPInt) {}
static void ConstructArray(void* p, UPInt count, const T& source)
{
UByte *pdata = (UByte*)p;
for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
*(T*)pdata = source;
}
static void ConstructArray(void* p, UPInt count, const T* psource)
{
memcpy(p, psource, sizeof(T) * count);
}
static void Destruct(T*) {}
static void DestructArray(T*, UPInt) {}
static void CopyArrayForward(T* dst, const T* src, UPInt count)
{
memmove(dst, src, count * sizeof(T));
}
static void CopyArrayBackward(T* dst, const T* src, UPInt count)
{
memmove(dst, src, count * sizeof(T));
}
static bool IsMovable() { return true; }
};
//-----------------------------------------------------------------------------------
// ***** ConstructorMov
//
// Correct C++ construction and destruction for movable objects
template<class T>
class ConstructorMov
{
public:
static void Construct(void* p)
{
OVR::Construct<T>(p);
}
static void Construct(void* p, const T& source)
{
OVR::Construct<T>(p, source);
}
// Same as above, but allows for a different type of constructor.
template <class S>
static void ConstructAlt(void* p, const S& source)
{
OVR::ConstructAlt<T,S>(p, source);
}
static void ConstructArray(void* p, UPInt count)
{
UByte* pdata = (UByte*)p;
for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
Construct(pdata);
}
static void ConstructArray(void* p, UPInt count, const T& source)
{
UByte* pdata = (UByte*)p;
for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
Construct(pdata, source);
}
static void ConstructArray(void* p, UPInt count, const T* psource)
{
UByte* pdata = (UByte*)p;
for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
Construct(pdata, *psource++);
}
static void Destruct(T* p)
{
p->~T();
OVR_UNUSED(p); // Suppress silly MSVC warning
}
static void DestructArray(T* p, UPInt count)
{
p += count - 1;
for (UPInt i=0; i<count; ++i, --p)
p->~T();
}
static void CopyArrayForward(T* dst, const T* src, UPInt count)
{
memmove(dst, src, count * sizeof(T));
}
static void CopyArrayBackward(T* dst, const T* src, UPInt count)
{
memmove(dst, src, count * sizeof(T));
}
static bool IsMovable() { return true; }
};
//-----------------------------------------------------------------------------------
// ***** ConstructorCPP
//
// Correct C++ construction and destruction for movable objects
template<class T>
class ConstructorCPP
{
public:
static void Construct(void* p)
{
OVR::Construct<T>(p);
}
static void Construct(void* p, const T& source)
{
OVR::Construct<T>(p, source);
}
// Same as above, but allows for a different type of constructor.
template <class S>
static void ConstructAlt(void* p, const S& source)
{
OVR::ConstructAlt<T,S>(p, source);
}
static void ConstructArray(void* p, UPInt count)
{
UByte* pdata = (UByte*)p;
for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
Construct(pdata);
}
static void ConstructArray(void* p, UPInt count, const T& source)
{
UByte* pdata = (UByte*)p;
for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
Construct(pdata, source);
}
static void ConstructArray(void* p, UPInt count, const T* psource)
{
UByte* pdata = (UByte*)p;
for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
Construct(pdata, *psource++);
}
static void Destruct(T* p)
{
p->~T();
OVR_UNUSED(p); // Suppress silly MSVC warning
}
static void DestructArray(T* p, UPInt count)
{
p += count - 1;
for (UPInt i=0; i<count; ++i, --p)
p->~T();
}
static void CopyArrayForward(T* dst, const T* src, UPInt count)
{
for(UPInt i = 0; i < count; ++i)
dst[i] = src[i];
}
static void CopyArrayBackward(T* dst, const T* src, UPInt count)
{
for(UPInt i = count; i; --i)
dst[i-1] = src[i-1];
}
static bool IsMovable() { return false; }
};
//-----------------------------------------------------------------------------------
// ***** Container Allocator with movement policy
//
// Simple wraps as specialized allocators
template<class T> struct ContainerAllocator_POD : ContainerAllocatorBase, ConstructorPOD<T> {};
template<class T> struct ContainerAllocator : ContainerAllocatorBase, ConstructorMov<T> {};
template<class T> struct ContainerAllocator_CPP : ContainerAllocatorBase, ConstructorCPP<T> {};
} // OVR
#endif

View File

@ -0,0 +1,296 @@
/************************************************************************************
Filename : OVR_Deque.h
Content : Deque container
Created : Nov. 15, 2013
Authors : Dov Katz
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_Deque_h
#define OVR_Deque_h
namespace OVR{
template <class Elem>
class Deque
{
public:
enum
{
DefaultCapacity = 500
};
Deque(int capacity = DefaultCapacity);
virtual ~Deque(void);
virtual void PushBack (const Elem &Item); // Adds Item to the end
virtual void PushFront (const Elem &Item); // Adds Item to the beginning
virtual Elem PopBack (void); // Removes Item from the end
virtual Elem PopFront (void); // Removes Item from the beginning
virtual const Elem& PeekBack (int count = 0) const; // Returns count-th Item from the end
virtual const Elem& PeekFront (int count = 0) const; // Returns count-th Item from the beginning
virtual inline UPInt GetSize (void) const; // Returns Number of Elements
virtual inline UPInt GetCapacity(void) const; // Returns the maximum possible number of elements
virtual void Clear (void); // Remove all elements
virtual inline bool IsEmpty () const;
virtual inline bool IsFull () const;
protected:
Elem *Data; // The actual Data array
const int Capacity; // Deque capacity
int Beginning; // Index of the first element
int End; // Index of the next after last element
// Instead of calculating the number of elements, using this variable
// is much more convenient.
int ElemCount;
private:
Deque& operator= (const Deque& q) { }; // forbidden
Deque(const Deque<Elem> &OtherDeque) { };
};
template <class Elem>
class InPlaceMutableDeque : public Deque<Elem>
{
public:
InPlaceMutableDeque( int capacity = Deque<Elem>::DefaultCapacity ) : Deque<Elem>( capacity ) {}
virtual ~InPlaceMutableDeque() {};
using Deque<Elem>::PeekBack;
using Deque<Elem>::PeekFront;
virtual Elem& PeekBack (int count = 0); // Returns count-th Item from the end
virtual Elem& PeekFront (int count = 0); // Returns count-th Item from the beginning
};
// Same as Deque, but allows to write more elements than maximum capacity
// Old elements are lost as they are overwritten with the new ones
template <class Elem>
class CircularBuffer : public InPlaceMutableDeque<Elem>
{
public:
CircularBuffer(int MaxSize = Deque<Elem>::DefaultCapacity) : InPlaceMutableDeque<Elem>(MaxSize) { };
// The following methods are inline as a workaround for a VS bug causing erroneous C4505 warnings
// See: http://stackoverflow.com/questions/3051992/compiler-warning-at-c-template-base-class
inline virtual void PushBack (const Elem &Item); // Adds Item to the end, overwriting the oldest element at the beginning if necessary
inline virtual void PushFront (const Elem &Item); // Adds Item to the beginning, overwriting the oldest element at the end if necessary
};
//----------------------------------------------------------------------------------
// Deque Constructor function
template <class Elem>
Deque<Elem>::Deque(int capacity) :
Capacity( capacity ), Beginning(0), End(0), ElemCount(0)
{
Data = (Elem*) OVR_ALLOC(Capacity * sizeof(Elem));
ConstructArray<Elem>(Data, Capacity);
}
// Deque Destructor function
template <class Elem>
Deque<Elem>::~Deque(void)
{
DestructArray<Elem>(Data, Capacity);
OVR_FREE(Data);
}
template <class Elem>
void Deque<Elem>::Clear()
{
Beginning = 0;
End = 0;
ElemCount = 0;
DestructArray<Elem>(Data, Capacity);
ConstructArray<Elem>(Data, Capacity);
}
// Push functions
template <class Elem>
void Deque<Elem>::PushBack(const Elem &Item)
{
// Error Check: Make sure we aren't
// exceeding our maximum storage space
OVR_ASSERT( ElemCount < Capacity );
Data[ End++ ] = Item;
++ElemCount;
// Check for wrap-around
if (End >= Capacity)
End -= Capacity;
}
template <class Elem>
void Deque<Elem>::PushFront(const Elem &Item)
{
// Error Check: Make sure we aren't
// exceeding our maximum storage space
OVR_ASSERT( ElemCount < Capacity );
Beginning--;
// Check for wrap-around
if (Beginning < 0)
Beginning += Capacity;
Data[ Beginning ] = Item;
++ElemCount;
}
// Pop functions
template <class Elem>
Elem Deque<Elem>::PopFront(void)
{
// Error Check: Make sure we aren't reading from an empty Deque
OVR_ASSERT( ElemCount > 0 );
Elem ReturnValue = Data[ Beginning ];
Destruct<Elem>(&Data[ Beginning ]);
Construct<Elem>(&Data[ Beginning ]);
++Beginning;
--ElemCount;
// Check for wrap-around
if (Beginning >= Capacity)
Beginning -= Capacity;
return ReturnValue;
}
template <class Elem>
Elem Deque<Elem>::PopBack(void)
{
// Error Check: Make sure we aren't reading from an empty Deque
OVR_ASSERT( ElemCount > 0 );
End--;
--ElemCount;
// Check for wrap-around
if (End < 0)
End += Capacity;
Elem ReturnValue = Data[ End ];
Destruct<Elem>(&Data[ End ]);
Construct<Elem>(&Data[ End ]);
return ReturnValue;
}
// Peek functions
template <class Elem>
const Elem& Deque<Elem>::PeekFront(int count) const
{
// Error Check: Make sure we aren't reading from an empty Deque
OVR_ASSERT( ElemCount > count );
int idx = Beginning + count;
if (idx >= Capacity)
idx -= Capacity;
return Data[ idx ];
}
template <class Elem>
const Elem& Deque<Elem>::PeekBack(int count) const
{
// Error Check: Make sure we aren't reading from an empty Deque
OVR_ASSERT( ElemCount > count );
int idx = End - count - 1;
if (idx < 0)
idx += Capacity;
return Data[ idx ];
}
// Mutable Peek functions
template <class Elem>
Elem& InPlaceMutableDeque<Elem>::PeekFront(int count)
{
// Error Check: Make sure we aren't reading from an empty Deque
OVR_ASSERT( Deque<Elem>::ElemCount > count );
int idx = Deque<Elem>::Beginning + count;
if (idx >= Deque<Elem>::Capacity)
idx -= Deque<Elem>::Capacity;
return Deque<Elem>::Data[ idx ];
}
template <class Elem>
Elem& InPlaceMutableDeque<Elem>::PeekBack(int count)
{
// Error Check: Make sure we aren't reading from an empty Deque
OVR_ASSERT( Deque<Elem>::ElemCount > count );
int idx = Deque<Elem>::End - count - 1;
if (idx < 0)
idx += Deque<Elem>::Capacity;
return Deque<Elem>::Data[ idx ];
}
template <class Elem>
inline UPInt Deque<Elem>::GetCapacity(void) const
{
return Deque<Elem>::Capacity;
}
template <class Elem>
inline UPInt Deque<Elem>::GetSize(void) const
{
return Deque<Elem>::ElemCount;
}
template <class Elem>
inline bool Deque<Elem>::IsEmpty(void) const
{
return Deque<Elem>::ElemCount==0;
}
template <class Elem>
inline bool Deque<Elem>::IsFull(void) const
{
return Deque<Elem>::ElemCount==Deque<Elem>::Capacity;
}
// ******* CircularBuffer<Elem> *******
// Push functions
template <class Elem>
void CircularBuffer<Elem>::PushBack(const Elem &Item)
{
if (this->IsFull())
this->PopFront();
Deque<Elem>::PushBack(Item);
}
template <class Elem>
void CircularBuffer<Elem>::PushFront(const Elem &Item)
{
if (this->IsFull())
this->PopBack();
Deque<Elem>::PushFront(Item);
}
};
#endif

View File

@ -0,0 +1,582 @@
/**************************************************************************
Filename : OVR_File.cpp
Content : File wrapper class implementation (Win32)
Created : April 5, 1999
Authors : Michael Antonov
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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.
**************************************************************************/
#define GFILE_CXX
// Standard C library (Captain Obvious guarantees!)
#include <stdio.h>
#include "OVR_File.h"
namespace OVR {
// Buffered file adds buffering to an existing file
// FILEBUFFER_SIZE defines the size of internal buffer, while
// FILEBUFFER_TOLERANCE controls the amount of data we'll effectively try to buffer
#define FILEBUFFER_SIZE (8192-8)
#define FILEBUFFER_TOLERANCE 4096
// ** Constructor/Destructor
// Hidden constructor
// Not supposed to be used
BufferedFile::BufferedFile() : DelegatedFile(0)
{
pBuffer = (UByte*)OVR_ALLOC(FILEBUFFER_SIZE);
BufferMode = NoBuffer;
FilePos = 0;
Pos = 0;
DataSize = 0;
}
// Takes another file as source
BufferedFile::BufferedFile(File *pfile) : DelegatedFile(pfile)
{
pBuffer = (UByte*)OVR_ALLOC(FILEBUFFER_SIZE);
BufferMode = NoBuffer;
FilePos = pfile->LTell();
Pos = 0;
DataSize = 0;
}
// Destructor
BufferedFile::~BufferedFile()
{
// Flush in case there's data
if (pFile)
FlushBuffer();
// Get rid of buffer
if (pBuffer)
OVR_FREE(pBuffer);
}
/*
bool BufferedFile::VCopy(const Object &source)
{
if (!DelegatedFile::VCopy(source))
return 0;
// Data members
BufferedFile *psource = (BufferedFile*)&source;
// Buffer & the mode it's in
pBuffer = psource->pBuffer;
BufferMode = psource->BufferMode;
Pos = psource->Pos;
DataSize = psource->DataSize;
return 1;
}
*/
// Initializes buffering to a certain mode
bool BufferedFile::SetBufferMode(BufferModeType mode)
{
if (!pBuffer)
return false;
if (mode == BufferMode)
return true;
FlushBuffer();
// Can't set write mode if we can't write
if ((mode==WriteBuffer) && (!pFile || !pFile->IsWritable()) )
return 0;
// And SetMode
BufferMode = mode;
Pos = 0;
DataSize = 0;
return 1;
}
// Flushes buffer
void BufferedFile::FlushBuffer()
{
switch(BufferMode)
{
case WriteBuffer:
// Write data in buffer
FilePos += pFile->Write(pBuffer,Pos);
Pos = 0;
break;
case ReadBuffer:
// Seek back & reset buffer data
if ((DataSize-Pos)>0)
FilePos = pFile->LSeek(-(int)(DataSize-Pos), Seek_Cur);
DataSize = 0;
Pos = 0;
break;
default:
// not handled!
break;
}
}
// Reloads data for ReadBuffer
void BufferedFile::LoadBuffer()
{
if (BufferMode == ReadBuffer)
{
// We should only reload once all of pre-loaded buffer is consumed.
OVR_ASSERT(Pos == DataSize);
// WARNING: Right now LoadBuffer() assumes the buffer's empty
int sz = pFile->Read(pBuffer,FILEBUFFER_SIZE);
DataSize = sz<0 ? 0 : (unsigned)sz;
Pos = 0;
FilePos += DataSize;
}
}
// ** Overridden functions
// We override all the functions that can possibly
// require buffer mode switch, flush, or extra calculations
// Tell() requires buffer adjustment
int BufferedFile::Tell()
{
if (BufferMode == ReadBuffer)
return int (FilePos - DataSize + Pos);
int pos = pFile->Tell();
// Adjust position based on buffer mode & data
if (pos!=-1)
{
OVR_ASSERT(BufferMode != ReadBuffer);
if (BufferMode == WriteBuffer)
pos += Pos;
}
return pos;
}
SInt64 BufferedFile::LTell()
{
if (BufferMode == ReadBuffer)
return FilePos - DataSize + Pos;
SInt64 pos = pFile->LTell();
if (pos!=-1)
{
OVR_ASSERT(BufferMode != ReadBuffer);
if (BufferMode == WriteBuffer)
pos += Pos;
}
return pos;
}
int BufferedFile::GetLength()
{
int len = pFile->GetLength();
// If writing through buffer, file length may actually be bigger
if ((len!=-1) && (BufferMode==WriteBuffer))
{
int currPos = pFile->Tell() + Pos;
if (currPos>len)
len = currPos;
}
return len;
}
SInt64 BufferedFile::LGetLength()
{
SInt64 len = pFile->LGetLength();
// If writing through buffer, file length may actually be bigger
if ((len!=-1) && (BufferMode==WriteBuffer))
{
SInt64 currPos = pFile->LTell() + Pos;
if (currPos>len)
len = currPos;
}
return len;
}
/*
bool BufferedFile::Stat(FileStats *pfs)
{
// Have to fix up length is stat
if (pFile->Stat(pfs))
{
if (BufferMode==WriteBuffer)
{
SInt64 currPos = pFile->LTell() + Pos;
if (currPos > pfs->Size)
{
pfs->Size = currPos;
// ??
pfs->Blocks = (pfs->Size+511) >> 9;
}
}
return 1;
}
return 0;
}
*/
int BufferedFile::Write(const UByte *psourceBuffer, int numBytes)
{
if ( (BufferMode==WriteBuffer) || SetBufferMode(WriteBuffer))
{
// If not data space in buffer, flush
if ((FILEBUFFER_SIZE-(int)Pos)<numBytes)
{
FlushBuffer();
// If bigger then tolerance, just write directly
if (numBytes>FILEBUFFER_TOLERANCE)
{
int sz = pFile->Write(psourceBuffer,numBytes);
if (sz > 0)
FilePos += sz;
return sz;
}
}
// Enough space in buffer.. so copy to it
memcpy(pBuffer+Pos, psourceBuffer, numBytes);
Pos += numBytes;
return numBytes;
}
int sz = pFile->Write(psourceBuffer,numBytes);
if (sz > 0)
FilePos += sz;
return sz;
}
int BufferedFile::Read(UByte *pdestBuffer, int numBytes)
{
if ( (BufferMode==ReadBuffer) || SetBufferMode(ReadBuffer))
{
// Data in buffer... copy it
if ((int)(DataSize-Pos) >= numBytes)
{
memcpy(pdestBuffer, pBuffer+Pos, numBytes);
Pos += numBytes;
return numBytes;
}
// Not enough data in buffer, copy buffer
int readBytes = DataSize-Pos;
memcpy(pdestBuffer, pBuffer+Pos, readBytes);
numBytes -= readBytes;
pdestBuffer += readBytes;
Pos = DataSize;
// Don't reload buffer if more then tolerance
// (No major advantage, and we don't want to write a loop)
if (numBytes>FILEBUFFER_TOLERANCE)
{
numBytes = pFile->Read(pdestBuffer,numBytes);
if (numBytes > 0)
{
FilePos += numBytes;
Pos = DataSize = 0;
}
return readBytes + ((numBytes==-1) ? 0 : numBytes);
}
// Reload the buffer
// WARNING: Right now LoadBuffer() assumes the buffer's empty
LoadBuffer();
if ((int)(DataSize-Pos) < numBytes)
numBytes = (int)DataSize-Pos;
memcpy(pdestBuffer, pBuffer+Pos, numBytes);
Pos += numBytes;
return numBytes + readBytes;
/*
// Alternative Read implementation. The one above is probably better
// due to FILEBUFFER_TOLERANCE.
int total = 0;
do {
int bufferBytes = (int)(DataSize-Pos);
int copyBytes = (bufferBytes > numBytes) ? numBytes : bufferBytes;
memcpy(pdestBuffer, pBuffer+Pos, copyBytes);
numBytes -= copyBytes;
pdestBuffer += copyBytes;
Pos += copyBytes;
total += copyBytes;
if (numBytes == 0)
break;
LoadBuffer();
} while (DataSize > 0);
return total;
*/
}
int sz = pFile->Read(pdestBuffer,numBytes);
if (sz > 0)
FilePos += sz;
return sz;
}
int BufferedFile::SkipBytes(int numBytes)
{
int skippedBytes = 0;
// Special case for skipping a little data in read buffer
if (BufferMode==ReadBuffer)
{
skippedBytes = (((int)DataSize-(int)Pos) >= numBytes) ? numBytes : (DataSize-Pos);
Pos += skippedBytes;
numBytes -= skippedBytes;
}
if (numBytes)
{
numBytes = pFile->SkipBytes(numBytes);
// Make sure we return the actual number skipped, or error
if (numBytes!=-1)
{
skippedBytes += numBytes;
FilePos += numBytes;
Pos = DataSize = 0;
}
else if (skippedBytes <= 0)
skippedBytes = -1;
}
return skippedBytes;
}
int BufferedFile::BytesAvailable()
{
int available = pFile->BytesAvailable();
// Adjust available size based on buffers
switch(BufferMode)
{
case ReadBuffer:
available += DataSize-Pos;
break;
case WriteBuffer:
available -= Pos;
if (available<0)
available= 0;
break;
default:
break;
}
return available;
}
bool BufferedFile::Flush()
{
FlushBuffer();
return pFile->Flush();
}
// Seeking could be optimized better..
int BufferedFile::Seek(int offset, int origin)
{
if (BufferMode == ReadBuffer)
{
if (origin == Seek_Cur)
{
// Seek can fall either before or after Pos in the buffer,
// but it must be within bounds.
if (((unsigned(offset) + Pos)) <= DataSize)
{
Pos += offset;
return int (FilePos - DataSize + Pos);
}
// Lightweight buffer "Flush". We do this to avoid an extra seek
// back operation which would take place if we called FlushBuffer directly.
origin = Seek_Set;
OVR_ASSERT(((FilePos - DataSize + Pos) + (UInt64)offset) < ~(UInt64)0);
offset = (int)(FilePos - DataSize + Pos) + offset;
Pos = DataSize = 0;
}
else if (origin == Seek_Set)
{
if (((unsigned)offset - (FilePos-DataSize)) <= DataSize)
{
OVR_ASSERT((FilePos-DataSize) < ~(UInt64)0);
Pos = (unsigned)offset - (unsigned)(FilePos-DataSize);
return offset;
}
Pos = DataSize = 0;
}
else
{
FlushBuffer();
}
}
else
{
FlushBuffer();
}
/*
// Old Seek Logic
if (origin == Seek_Cur && offset + Pos < DataSize)
{
//OVR_ASSERT((FilePos - DataSize) >= (FilePos - DataSize + Pos + offset));
Pos += offset;
OVR_ASSERT(int (Pos) >= 0);
return int (FilePos - DataSize + Pos);
}
else if (origin == Seek_Set && unsigned(offset) >= FilePos - DataSize && unsigned(offset) < FilePos)
{
Pos = unsigned(offset - FilePos + DataSize);
OVR_ASSERT(int (Pos) >= 0);
return int (FilePos - DataSize + Pos);
}
FlushBuffer();
*/
FilePos = pFile->Seek(offset,origin);
return int (FilePos);
}
SInt64 BufferedFile::LSeek(SInt64 offset, int origin)
{
if (BufferMode == ReadBuffer)
{
if (origin == Seek_Cur)
{
// Seek can fall either before or after Pos in the buffer,
// but it must be within bounds.
if (((unsigned(offset) + Pos)) <= DataSize)
{
Pos += (unsigned)offset;
return SInt64(FilePos - DataSize + Pos);
}
// Lightweight buffer "Flush". We do this to avoid an extra seek
// back operation which would take place if we called FlushBuffer directly.
origin = Seek_Set;
offset = (SInt64)(FilePos - DataSize + Pos) + offset;
Pos = DataSize = 0;
}
else if (origin == Seek_Set)
{
if (((UInt64)offset - (FilePos-DataSize)) <= DataSize)
{
Pos = (unsigned)((UInt64)offset - (FilePos-DataSize));
return offset;
}
Pos = DataSize = 0;
}
else
{
FlushBuffer();
}
}
else
{
FlushBuffer();
}
/*
OVR_ASSERT(BufferMode != NoBuffer);
if (origin == Seek_Cur && offset + Pos < DataSize)
{
Pos += int (offset);
return FilePos - DataSize + Pos;
}
else if (origin == Seek_Set && offset >= SInt64(FilePos - DataSize) && offset < SInt64(FilePos))
{
Pos = unsigned(offset - FilePos + DataSize);
return FilePos - DataSize + Pos;
}
FlushBuffer();
*/
FilePos = pFile->LSeek(offset,origin);
return FilePos;
}
int BufferedFile::CopyFromStream(File *pstream, int byteSize)
{
// We can't rely on overridden Write()
// because delegation doesn't override virtual pointers
// So, just re-implement
UByte buff[0x4000];
int count = 0;
int szRequest, szRead, szWritten;
while(byteSize)
{
szRequest = (byteSize > int(sizeof(buff))) ? int(sizeof(buff)) : byteSize;
szRead = pstream->Read(buff,szRequest);
szWritten = 0;
if (szRead > 0)
szWritten = Write(buff,szRead);
count +=szWritten;
byteSize-=szWritten;
if (szWritten < szRequest)
break;
}
return count;
}
// Closing files
bool BufferedFile::Close()
{
switch(BufferMode)
{
case WriteBuffer:
FlushBuffer();
break;
case ReadBuffer:
// No need to seek back on close
BufferMode = NoBuffer;
break;
default:
break;
}
return pFile->Close();
}
// ***** Global path helpers
// Find trailing short filename in a path.
const char* OVR_CDECL GetShortFilename(const char* purl)
{
UPInt len = OVR_strlen(purl);
for (UPInt i=len; i>0; i--)
if (purl[i]=='\\' || purl[i]=='/')
return purl+i+1;
return purl;
}
} // OVR

View File

@ -0,0 +1,529 @@
/************************************************************************************
PublicHeader: Kernel
Filename : OVR_File.h
Content : Header for all internal file management - functions and structures
to be inherited by OS specific subclasses.
Created : September 19, 2012
Notes :
Notes : errno may not be preserved across use of BaseFile member functions
: Directories cannot be deleted while files opened from them are in use
(For the GetFullName function)
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_File_h
#define OVR_File_h
#include "OVR_RefCount.h"
#include "OVR_Std.h"
#include "OVR_Alg.h"
#include <stdio.h>
#include "OVR_String.h"
namespace OVR {
// ***** Declared classes
class FileConstants;
class File;
class DelegatedFile;
class BufferedFile;
// ***** Flags for File & Directory accesses
class FileConstants
{
public:
// *** File open flags
enum OpenFlags
{
Open_Read = 1,
Open_Write = 2,
Open_ReadWrite = 3,
// Opens file and truncates it to zero length
// - file must have write permission
// - when used with Create, it opens an existing
// file and empties it or creates a new file
Open_Truncate = 4,
// Creates and opens new file
// - does not erase contents if file already
// exists unless combined with Truncate
Open_Create = 8,
// Returns an error value if the file already exists
Open_CreateOnly = 24,
// Open file with buffering
Open_Buffered = 32
};
// *** File Mode flags
enum Modes
{
Mode_Read = 0444,
Mode_Write = 0222,
Mode_Execute = 0111,
Mode_ReadWrite = 0666
};
// *** Seek operations
enum SeekOps
{
Seek_Set = 0,
Seek_Cur = 1,
Seek_End = 2
};
// *** Errors
enum Errors
{
Error_FileNotFound = 0x1001,
Error_Access = 0x1002,
Error_IOError = 0x1003,
Error_DiskFull = 0x1004
};
};
//-----------------------------------------------------------------------------------
// ***** File Class
// The pure virtual base random-access file
// This is a base class to all files
class File : public RefCountBase<File>, public FileConstants
{
public:
File() { }
// ** Location Information
// Returns a file name path relative to the 'reference' directory
// This is often a path that was used to create a file
// (this is not a global path, global path can be obtained with help of directory)
virtual const char* GetFilePath() = 0;
// ** File Information
// Return 1 if file's usable (open)
virtual bool IsValid() = 0;
// Return 1 if file's writable, otherwise 0
virtual bool IsWritable() = 0;
// Return position
virtual int Tell() = 0;
virtual SInt64 LTell() = 0;
// File size
virtual int GetLength() = 0;
virtual SInt64 LGetLength() = 0;
// Returns file stats
// 0 for failure
//virtual bool Stat(FileStats *pfs) = 0;
// Return errno-based error code
// Useful if any other function failed
virtual int GetErrorCode() = 0;
// ** Stream implementation & I/O
// Blocking write, will write in the given number of bytes to the stream
// Returns : -1 for error
// Otherwise number of bytes read
virtual int Write(const UByte *pbufer, int numBytes) = 0;
// Blocking read, will read in the given number of bytes or less from the stream
// Returns : -1 for error
// Otherwise number of bytes read,
// if 0 or < numBytes, no more bytes available; end of file or the other side of stream is closed
virtual int Read(UByte *pbufer, int numBytes) = 0;
// Skips (ignores) a given # of bytes
// Same return values as Read
virtual int SkipBytes(int numBytes) = 0;
// Returns the number of bytes available to read from a stream without blocking
// For a file, this should generally be number of bytes to the end
virtual int BytesAvailable() = 0;
// Causes any implementation's buffered data to be delivered to destination
// Return 0 for error
virtual bool Flush() = 0;
// Need to provide a more optimized implementation that doe snot necessarily involve a lot of seeking
inline bool IsEOF() { return !BytesAvailable(); }
// Seeking
// Returns new position, -1 for error
virtual int Seek(int offset, int origin=Seek_Set) = 0;
virtual SInt64 LSeek(SInt64 offset, int origin=Seek_Set) = 0;
// Seek simplification
int SeekToBegin() {return Seek(0); }
int SeekToEnd() {return Seek(0,Seek_End); }
int Skip(int numBytes) {return Seek(numBytes,Seek_Cur); }
// Appends other file data from a stream
// Return -1 for error, else # of bytes written
virtual int CopyFromStream(File *pstream, int byteSize) = 0;
// Closes the file
// After close, file cannot be accessed
virtual bool Close() = 0;
// ***** Inlines for convenient primitive type serialization
// Read/Write helpers
private:
UInt64 PRead64() { UInt64 v = 0; Read((UByte*)&v, 8); return v; }
UInt32 PRead32() { UInt32 v = 0; Read((UByte*)&v, 4); return v; }
UInt16 PRead16() { UInt16 v = 0; Read((UByte*)&v, 2); return v; }
UByte PRead8() { UByte v = 0; Read((UByte*)&v, 1); return v; }
void PWrite64(UInt64 v) { Write((UByte*)&v, 8); }
void PWrite32(UInt32 v) { Write((UByte*)&v, 4); }
void PWrite16(UInt16 v) { Write((UByte*)&v, 2); }
void PWrite8(UByte v) { Write((UByte*)&v, 1); }
public:
// Writing primitive types - Little Endian
inline void WriteUByte(UByte v) { PWrite8((UByte)Alg::ByteUtil::SystemToLE(v)); }
inline void WriteSByte(SByte v) { PWrite8((UByte)Alg::ByteUtil::SystemToLE(v)); }
inline void WriteUInt8(UByte v) { PWrite8((UByte)Alg::ByteUtil::SystemToLE(v)); }
inline void WriteSInt8(SByte v) { PWrite8((UByte)Alg::ByteUtil::SystemToLE(v)); }
inline void WriteUInt16(UInt16 v) { PWrite16((UInt16)Alg::ByteUtil::SystemToLE(v)); }
inline void WriteSInt16(SInt16 v) { PWrite16((UInt16)Alg::ByteUtil::SystemToLE(v)); }
inline void WriteUInt32(UInt32 v) { PWrite32((UInt32)Alg::ByteUtil::SystemToLE(v)); }
inline void WriteSInt32(SInt32 v) { PWrite32((UInt32)Alg::ByteUtil::SystemToLE(v)); }
inline void WriteUInt64(UInt64 v) { PWrite64((UInt64)Alg::ByteUtil::SystemToLE(v)); }
inline void WriteSInt64(SInt64 v) { PWrite64((UInt64)Alg::ByteUtil::SystemToLE(v)); }
inline void WriteFloat(float v) { v = Alg::ByteUtil::SystemToLE(v); Write((UByte*)&v, 4); }
inline void WriteDouble(double v) { v = Alg::ByteUtil::SystemToLE(v); Write((UByte*)&v, 8); }
// Writing primitive types - Big Endian
inline void WriteUByteBE(UByte v) { PWrite8((UByte)Alg::ByteUtil::SystemToBE(v)); }
inline void WriteSByteBE(SByte v) { PWrite8((UByte)Alg::ByteUtil::SystemToBE(v)); }
inline void WriteUInt8BE(UInt16 v) { PWrite8((UByte)Alg::ByteUtil::SystemToBE(v)); }
inline void WriteSInt8BE(SInt16 v) { PWrite8((UByte)Alg::ByteUtil::SystemToBE(v)); }
inline void WriteUInt16BE(UInt16 v) { PWrite16((UInt16)Alg::ByteUtil::SystemToBE(v)); }
inline void WriteSInt16BE(UInt16 v) { PWrite16((UInt16)Alg::ByteUtil::SystemToBE(v)); }
inline void WriteUInt32BE(UInt32 v) { PWrite32((UInt32)Alg::ByteUtil::SystemToBE(v)); }
inline void WriteSInt32BE(UInt32 v) { PWrite32((UInt32)Alg::ByteUtil::SystemToBE(v)); }
inline void WriteUInt64BE(UInt64 v) { PWrite64((UInt64)Alg::ByteUtil::SystemToBE(v)); }
inline void WriteSInt64BE(UInt64 v) { PWrite64((UInt64)Alg::ByteUtil::SystemToBE(v)); }
inline void WriteFloatBE(float v) { v = Alg::ByteUtil::SystemToBE(v); Write((UByte*)&v, 4); }
inline void WriteDoubleBE(double v) { v = Alg::ByteUtil::SystemToBE(v); Write((UByte*)&v, 8); }
// Reading primitive types - Little Endian
inline UByte ReadUByte() { return (UByte)Alg::ByteUtil::LEToSystem(PRead8()); }
inline SByte ReadSByte() { return (SByte)Alg::ByteUtil::LEToSystem(PRead8()); }
inline UByte ReadUInt8() { return (UByte)Alg::ByteUtil::LEToSystem(PRead8()); }
inline SByte ReadSInt8() { return (SByte)Alg::ByteUtil::LEToSystem(PRead8()); }
inline UInt16 ReadUInt16() { return (UInt16)Alg::ByteUtil::LEToSystem(PRead16()); }
inline SInt16 ReadSInt16() { return (SInt16)Alg::ByteUtil::LEToSystem(PRead16()); }
inline UInt32 ReadUInt32() { return (UInt32)Alg::ByteUtil::LEToSystem(PRead32()); }
inline SInt32 ReadSInt32() { return (SInt32)Alg::ByteUtil::LEToSystem(PRead32()); }
inline UInt64 ReadUInt64() { return (UInt64)Alg::ByteUtil::LEToSystem(PRead64()); }
inline SInt64 ReadSInt64() { return (SInt64)Alg::ByteUtil::LEToSystem(PRead64()); }
inline float ReadFloat() { float v = 0.0f; Read((UByte*)&v, 4); return Alg::ByteUtil::LEToSystem(v); }
inline double ReadDouble() { double v = 0.0; Read((UByte*)&v, 8); return Alg::ByteUtil::LEToSystem(v); }
// Reading primitive types - Big Endian
inline UByte ReadUByteBE() { return (UByte)Alg::ByteUtil::BEToSystem(PRead8()); }
inline SByte ReadSByteBE() { return (SByte)Alg::ByteUtil::BEToSystem(PRead8()); }
inline UByte ReadUInt8BE() { return (UByte)Alg::ByteUtil::BEToSystem(PRead8()); }
inline SByte ReadSInt8BE() { return (SByte)Alg::ByteUtil::BEToSystem(PRead8()); }
inline UInt16 ReadUInt16BE() { return (UInt16)Alg::ByteUtil::BEToSystem(PRead16()); }
inline SInt16 ReadSInt16BE() { return (SInt16)Alg::ByteUtil::BEToSystem(PRead16()); }
inline UInt32 ReadUInt32BE() { return (UInt32)Alg::ByteUtil::BEToSystem(PRead32()); }
inline SInt32 ReadSInt32BE() { return (SInt32)Alg::ByteUtil::BEToSystem(PRead32()); }
inline UInt64 ReadUInt64BE() { return (UInt64)Alg::ByteUtil::BEToSystem(PRead64()); }
inline SInt64 ReadSInt64BE() { return (SInt64)Alg::ByteUtil::BEToSystem(PRead64()); }
inline float ReadFloatBE() { float v = 0.0f; Read((UByte*)&v, 4); return Alg::ByteUtil::BEToSystem(v); }
inline double ReadDoubleBE() { double v = 0.0; Read((UByte*)&v, 8); return Alg::ByteUtil::BEToSystem(v); }
};
// *** Delegated File
class DelegatedFile : public File
{
protected:
// Delegating file pointer
Ptr<File> pFile;
// Hidden default constructor
DelegatedFile() : pFile(0) { }
DelegatedFile(const DelegatedFile &source) : File() { OVR_UNUSED(source); }
public:
// Constructors
DelegatedFile(File *pfile) : pFile(pfile) { }
// ** Location Information
virtual const char* GetFilePath() { return pFile->GetFilePath(); }
// ** File Information
virtual bool IsValid() { return pFile && pFile->IsValid(); }
virtual bool IsWritable() { return pFile->IsWritable(); }
// virtual bool IsRecoverable() { return pFile->IsRecoverable(); }
virtual int Tell() { return pFile->Tell(); }
virtual SInt64 LTell() { return pFile->LTell(); }
virtual int GetLength() { return pFile->GetLength(); }
virtual SInt64 LGetLength() { return pFile->LGetLength(); }
//virtual bool Stat(FileStats *pfs) { return pFile->Stat(pfs); }
virtual int GetErrorCode() { return pFile->GetErrorCode(); }
// ** Stream implementation & I/O
virtual int Write(const UByte *pbuffer, int numBytes) { return pFile->Write(pbuffer,numBytes); }
virtual int Read(UByte *pbuffer, int numBytes) { return pFile->Read(pbuffer,numBytes); }
virtual int SkipBytes(int numBytes) { return pFile->SkipBytes(numBytes); }
virtual int BytesAvailable() { return pFile->BytesAvailable(); }
virtual bool Flush() { return pFile->Flush(); }
// Seeking
virtual int Seek(int offset, int origin=Seek_Set) { return pFile->Seek(offset,origin); }
virtual SInt64 LSeek(SInt64 offset, int origin=Seek_Set) { return pFile->LSeek(offset,origin); }
virtual int CopyFromStream(File *pstream, int byteSize) { return pFile->CopyFromStream(pstream,byteSize); }
// Closing the file
virtual bool Close() { return pFile->Close(); }
};
//-----------------------------------------------------------------------------------
// ***** Buffered File
// This file class adds buffering to an existing file
// Buffered file never fails by itself; if there's not
// enough memory for buffer, no buffer's used
class BufferedFile : public DelegatedFile
{
protected:
enum BufferModeType
{
NoBuffer,
ReadBuffer,
WriteBuffer
};
// Buffer & the mode it's in
UByte* pBuffer;
BufferModeType BufferMode;
// Position in buffer
unsigned Pos;
// Data in buffer if reading
unsigned DataSize;
// Underlying file position
UInt64 FilePos;
// Initializes buffering to a certain mode
bool SetBufferMode(BufferModeType mode);
// Flushes buffer
// WriteBuffer - write data to disk, ReadBuffer - reset buffer & fix file position
void FlushBuffer();
// Loads data into ReadBuffer
// WARNING: Right now LoadBuffer() assumes the buffer's empty
void LoadBuffer();
// Hidden constructor
BufferedFile();
inline BufferedFile(const BufferedFile &source) : DelegatedFile() { OVR_UNUSED(source); }
public:
// Constructor
// - takes another file as source
BufferedFile(File *pfile);
~BufferedFile();
// ** Overridden functions
// We override all the functions that can possibly
// require buffer mode switch, flush, or extra calculations
virtual int Tell();
virtual SInt64 LTell();
virtual int GetLength();
virtual SInt64 LGetLength();
// virtual bool Stat(GFileStats *pfs);
virtual int Write(const UByte *pbufer, int numBytes);
virtual int Read(UByte *pbufer, int numBytes);
virtual int SkipBytes(int numBytes);
virtual int BytesAvailable();
virtual bool Flush();
virtual int Seek(int offset, int origin=Seek_Set);
virtual SInt64 LSeek(SInt64 offset, int origin=Seek_Set);
virtual int CopyFromStream(File *pstream, int byteSize);
virtual bool Close();
};
//-----------------------------------------------------------------------------------
// ***** Memory File
class MemoryFile : public File
{
public:
const char* GetFilePath() { return FilePath.ToCStr(); }
bool IsValid() { return Valid; }
bool IsWritable() { return false; }
bool Flush() { return true; }
int GetErrorCode() { return 0; }
int Tell() { return FileIndex; }
SInt64 LTell() { return (SInt64) FileIndex; }
int GetLength() { return FileSize; }
SInt64 LGetLength() { return (SInt64) FileSize; }
bool Close()
{
Valid = false;
return false;
}
int CopyFromStream(File *pstream, int byteSize)
{ OVR_UNUSED2(pstream, byteSize);
return 0;
}
int Write(const UByte *pbuffer, int numBytes)
{ OVR_UNUSED2(pbuffer, numBytes);
return 0;
}
int Read(UByte *pbufer, int numBytes)
{
if (FileIndex + numBytes > FileSize)
{
numBytes = FileSize - FileIndex;
}
if (numBytes > 0)
{
::memcpy (pbufer, &FileData [FileIndex], numBytes);
FileIndex += numBytes;
}
return numBytes;
}
int SkipBytes(int numBytes)
{
if (FileIndex + numBytes > FileSize)
{
numBytes = FileSize - FileIndex;
}
FileIndex += numBytes;
return numBytes;
}
int BytesAvailable()
{
return (FileSize - FileIndex);
}
int Seek(int offset, int origin = Seek_Set)
{
switch (origin)
{
case Seek_Set : FileIndex = offset; break;
case Seek_Cur : FileIndex += offset; break;
case Seek_End : FileIndex = FileSize - offset; break;
}
return FileIndex;
}
SInt64 LSeek(SInt64 offset, int origin = Seek_Set)
{
return (SInt64) Seek((int) offset, origin);
}
public:
MemoryFile (const String& fileName, const UByte *pBuffer, int buffSize)
: FilePath(fileName)
{
FileData = pBuffer;
FileSize = buffSize;
FileIndex = 0;
Valid = (!fileName.IsEmpty() && pBuffer && buffSize > 0) ? true : false;
}
// pfileName should be encoded as UTF-8 to support international file names.
MemoryFile (const char* pfileName, const UByte *pBuffer, int buffSize)
: FilePath(pfileName)
{
FileData = pBuffer;
FileSize = buffSize;
FileIndex = 0;
Valid = (pfileName && pBuffer && buffSize > 0) ? true : false;
}
private:
String FilePath;
const UByte *FileData;
int FileSize;
int FileIndex;
bool Valid;
};
// ***** Global path helpers
// Find trailing short filename in a path.
const char* OVR_CDECL GetShortFilename(const char* purl);
} // OVR
#endif

View File

@ -0,0 +1,595 @@
/**************************************************************************
Filename : OVR_FileFILE.cpp
Content : File wrapper class implementation (Win32)
Created : April 5, 1999
Authors : Michael Antonov
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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.
**************************************************************************/
#define GFILE_CXX
#include "OVR_Types.h"
#include "OVR_Log.h"
// Standard C library (Captain Obvious guarantees!)
#include <stdio.h>
#ifndef OVR_OS_WINCE
#include <sys/stat.h>
#endif
#include "OVR_SysFile.h"
#ifndef OVR_OS_WINCE
#include <errno.h>
#endif
namespace OVR {
// ***** File interface
// ***** FILEFile - C streams file
static int SFerror ()
{
if (errno == ENOENT)
return FileConstants::Error_FileNotFound;
else if (errno == EACCES || errno == EPERM)
return FileConstants::Error_Access;
else if (errno == ENOSPC)
return FileConstants::Error_DiskFull;
else
return FileConstants::Error_IOError;
};
#ifdef OVR_OS_WIN32
#include "windows.h"
// A simple helper class to disable/enable system error mode, if necessary
// Disabling happens conditionally only if a drive name is involved
class SysErrorModeDisabler
{
BOOL Disabled;
UINT OldMode;
public:
SysErrorModeDisabler(const char* pfileName)
{
if (pfileName && (pfileName[0]!=0) && pfileName[1]==':')
{
Disabled = 1;
OldMode = ::SetErrorMode(SEM_FAILCRITICALERRORS);
}
else
Disabled = 0;
}
~SysErrorModeDisabler()
{
if (Disabled) ::SetErrorMode(OldMode);
}
};
#else
class SysErrorModeDisabler
{
public:
SysErrorModeDisabler(const char* pfileName) { OVR_UNUSED(pfileName); }
};
#endif // OVR_OS_WIN32
// This macro enables verification of I/O results after seeks against a pre-loaded
// full file buffer copy. This is generally not necessary, but can been used to debug
// memory corruptions; we've seen this fail due to EAX2/DirectSound corrupting memory
// under FMOD with XP64 (32-bit) and Realtek HA Audio driver.
//#define GFILE_VERIFY_SEEK_ERRORS
// This is the simplest possible file implementation, it wraps around the descriptor
// This file is delegated to by SysFile.
class FILEFile : public File
{
protected:
// Allocated filename
String FileName;
// File handle & open mode
bool Opened;
FILE* fs;
int OpenFlags;
// Error code for last request
int ErrorCode;
int LastOp;
#ifdef OVR_FILE_VERIFY_SEEK_ERRORS
UByte* pFileTestBuffer;
unsigned FileTestLength;
unsigned TestPos; // File pointer position during tests.
#endif
public:
FILEFile()
{
Opened = 0; FileName = "";
#ifdef OVR_FILE_VERIFY_SEEK_ERRORS
pFileTestBuffer =0;
FileTestLength =0;
TestPos =0;
#endif
}
// Initialize file by opening it
FILEFile(const String& fileName, int flags, int Mode);
// The 'pfileName' should be encoded as UTF-8 to support international file names.
FILEFile(const char* pfileName, int flags, int Mode);
~FILEFile()
{
if (Opened)
Close();
}
virtual const char* GetFilePath();
// ** File Information
virtual bool IsValid();
virtual bool IsWritable();
// Return position / file size
virtual int Tell();
virtual SInt64 LTell();
virtual int GetLength();
virtual SInt64 LGetLength();
// virtual bool Stat(FileStats *pfs);
virtual int GetErrorCode();
// ** Stream implementation & I/O
virtual int Write(const UByte *pbuffer, int numBytes);
virtual int Read(UByte *pbuffer, int numBytes);
virtual int SkipBytes(int numBytes);
virtual int BytesAvailable();
virtual bool Flush();
virtual int Seek(int offset, int origin);
virtual SInt64 LSeek(SInt64 offset, int origin);
virtual int CopyFromStream(File *pStream, int byteSize);
virtual bool Close();
private:
void init();
};
// Initialize file by opening it
FILEFile::FILEFile(const String& fileName, int flags, int mode)
: FileName(fileName), OpenFlags(flags)
{
OVR_UNUSED(mode);
init();
}
// The 'pfileName' should be encoded as UTF-8 to support international file names.
FILEFile::FILEFile(const char* pfileName, int flags, int mode)
: FileName(pfileName), OpenFlags(flags)
{
OVR_UNUSED(mode);
init();
}
void FILEFile::init()
{
// Open mode for file's open
const char *omode = "rb";
if (OpenFlags & Open_Truncate)
{
if (OpenFlags & Open_Read)
omode = "w+b";
else
omode = "wb";
}
else if (OpenFlags & Open_Create)
{
if (OpenFlags & Open_Read)
omode = "a+b";
else
omode = "ab";
}
else if (OpenFlags & Open_Write)
omode = "r+b";
#ifdef OVR_OS_WIN32
SysErrorModeDisabler disabler(FileName.ToCStr());
#endif
#if defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400)
wchar_t womode[16];
wchar_t *pwFileName = (wchar_t*)OVR_ALLOC((UTF8Util::GetLength(FileName.ToCStr())+1) * sizeof(wchar_t));
UTF8Util::DecodeString(pwFileName, FileName.ToCStr());
OVR_ASSERT(strlen(omode) < sizeof(womode)/sizeof(womode[0]));
UTF8Util::DecodeString(womode, omode);
_wfopen_s(&fs, pwFileName, womode);
OVR_FREE(pwFileName);
#else
fs = fopen(FileName.ToCStr(), omode);
#endif
if (fs)
rewind (fs);
Opened = (fs != NULL);
// Set error code
if (!Opened)
ErrorCode = SFerror();
else
{
// If we are testing file seek correctness, pre-load the entire file so
// that we can do comparison tests later.
#ifdef OVR_FILE_VERIFY_SEEK_ERRORS
TestPos = 0;
fseek(fs, 0, SEEK_END);
FileTestLength = ftell(fs);
fseek(fs, 0, SEEK_SET);
pFileTestBuffer = (UByte*)OVR_ALLOC(FileTestLength);
if (pFileTestBuffer)
{
OVR_ASSERT(FileTestLength == (unsigned)Read(pFileTestBuffer, FileTestLength));
Seek(0, Seek_Set);
}
#endif
ErrorCode = 0;
}
LastOp = 0;
}
const char* FILEFile::GetFilePath()
{
return FileName.ToCStr();
}
// ** File Information
bool FILEFile::IsValid()
{
return Opened;
}
bool FILEFile::IsWritable()
{
return IsValid() && (OpenFlags&Open_Write);
}
/*
bool FILEFile::IsRecoverable()
{
return IsValid() && ((OpenFlags&OVR_FO_SAFETRUNC) == OVR_FO_SAFETRUNC);
}
*/
// Return position / file size
int FILEFile::Tell()
{
int pos = (int)ftell (fs);
if (pos < 0)
ErrorCode = SFerror();
return pos;
}
SInt64 FILEFile::LTell()
{
SInt64 pos = ftell(fs);
if (pos < 0)
ErrorCode = SFerror();
return pos;
}
int FILEFile::GetLength()
{
int pos = Tell();
if (pos >= 0)
{
Seek (0, Seek_End);
int size = Tell();
Seek (pos, Seek_Set);
return size;
}
return -1;
}
SInt64 FILEFile::LGetLength()
{
SInt64 pos = LTell();
if (pos >= 0)
{
LSeek (0, Seek_End);
SInt64 size = LTell();
LSeek (pos, Seek_Set);
return size;
}
return -1;
}
int FILEFile::GetErrorCode()
{
return ErrorCode;
}
// ** Stream implementation & I/O
int FILEFile::Write(const UByte *pbuffer, int numBytes)
{
if (LastOp && LastOp != Open_Write)
fflush(fs);
LastOp = Open_Write;
int written = (int) fwrite(pbuffer, 1, numBytes, fs);
if (written < numBytes)
ErrorCode = SFerror();
#ifdef OVR_FILE_VERIFY_SEEK_ERRORS
if (written > 0)
TestPos += written;
#endif
return written;
}
int FILEFile::Read(UByte *pbuffer, int numBytes)
{
if (LastOp && LastOp != Open_Read)
fflush(fs);
LastOp = Open_Read;
int read = (int) fread(pbuffer, 1, numBytes, fs);
if (read < numBytes)
ErrorCode = SFerror();
#ifdef OVR_FILE_VERIFY_SEEK_ERRORS
if (read > 0)
{
// Read-in data must match our pre-loaded buffer data!
UByte* pcompareBuffer = pFileTestBuffer + TestPos;
for (int i=0; i< read; i++)
{
OVR_ASSERT(pcompareBuffer[i] == pbuffer[i]);
}
//OVR_ASSERT(!memcmp(pFileTestBuffer + TestPos, pbuffer, read));
TestPos += read;
OVR_ASSERT(ftell(fs) == (int)TestPos);
}
#endif
return read;
}
// Seeks ahead to skip bytes
int FILEFile::SkipBytes(int numBytes)
{
SInt64 pos = LTell();
SInt64 newPos = LSeek(numBytes, Seek_Cur);
// Return -1 for major error
if ((pos==-1) || (newPos==-1))
{
return -1;
}
//ErrorCode = ((NewPos-Pos)<numBytes) ? errno : 0;
return int (newPos-(int)pos);
}
// Return # of bytes till EOF
int FILEFile::BytesAvailable()
{
SInt64 pos = LTell();
SInt64 endPos = LGetLength();
// Return -1 for major error
if ((pos==-1) || (endPos==-1))
{
ErrorCode = SFerror();
return 0;
}
else
ErrorCode = 0;
return int (endPos-(int)pos);
}
// Flush file contents
bool FILEFile::Flush()
{
return !fflush(fs);
}
int FILEFile::Seek(int offset, int origin)
{
int newOrigin = 0;
switch(origin)
{
case Seek_Set: newOrigin = SEEK_SET; break;
case Seek_Cur: newOrigin = SEEK_CUR; break;
case Seek_End: newOrigin = SEEK_END; break;
}
if (newOrigin == SEEK_SET && offset == Tell())
return Tell();
if (fseek (fs, offset, newOrigin))
{
#ifdef OVR_FILE_VERIFY_SEEK_ERRORS
OVR_ASSERT(0);
#endif
return -1;
}
#ifdef OVR_FILE_VERIFY_SEEK_ERRORS
// Track file position after seeks for read verification later.
switch(origin)
{
case Seek_Set: TestPos = offset; break;
case Seek_Cur: TestPos += offset; break;
case Seek_End: TestPos = FileTestLength + offset; break;
}
OVR_ASSERT((int)TestPos == Tell());
#endif
return (int)Tell();
}
SInt64 FILEFile::LSeek(SInt64 offset, int origin)
{
return Seek((int)offset,origin);
}
int FILEFile::CopyFromStream(File *pstream, int byteSize)
{
UByte buff[0x4000];
int count = 0;
int szRequest, szRead, szWritten;
while (byteSize)
{
szRequest = (byteSize > int(sizeof(buff))) ? int(sizeof(buff)) : byteSize;
szRead = pstream->Read(buff, szRequest);
szWritten = 0;
if (szRead > 0)
szWritten = Write(buff, szRead);
count += szWritten;
byteSize -= szWritten;
if (szWritten < szRequest)
break;
}
return count;
}
bool FILEFile::Close()
{
#ifdef OVR_FILE_VERIFY_SEEK_ERRORS
if (pFileTestBuffer)
{
OVR_FREE(pFileTestBuffer);
pFileTestBuffer = 0;
FileTestLength = 0;
}
#endif
bool closeRet = !fclose(fs);
if (!closeRet)
{
ErrorCode = SFerror();
return 0;
}
else
{
Opened = 0;
fs = 0;
ErrorCode = 0;
}
// Handle safe truncate
/*
if ((OpenFlags & OVR_FO_SAFETRUNC) == OVR_FO_SAFETRUNC)
{
// Delete original file (if it existed)
DWORD oldAttributes = FileUtilWin32::GetFileAttributes(FileName);
if (oldAttributes!=0xFFFFFFFF)
if (!FileUtilWin32::DeleteFile(FileName))
{
// Try to remove the readonly attribute
FileUtilWin32::SetFileAttributes(FileName, oldAttributes & (~FILE_ATTRIBUTE_READONLY) );
// And delete the file again
if (!FileUtilWin32::DeleteFile(FileName))
return 0;
}
// Rename temp file to real filename
if (!FileUtilWin32::MoveFile(TempName, FileName))
{
//ErrorCode = errno;
return 0;
}
}
*/
return 1;
}
/*
bool FILEFile::CloseCancel()
{
bool closeRet = (bool)::CloseHandle(fd);
if (!closeRet)
{
//ErrorCode = errno;
return 0;
}
else
{
Opened = 0;
fd = INVALID_HANDLE_VALUE;
ErrorCode = 0;
}
// Handle safe truncate (delete tmp file, leave original unchanged)
if ((OpenFlags&OVR_FO_SAFETRUNC) == OVR_FO_SAFETRUNC)
if (!FileUtilWin32::DeleteFile(TempName))
{
//ErrorCode = errno;
return 0;
}
return 1;
}
*/
Ptr<File> FileFILEOpen(const String& path, int flags, int mode)
{
Ptr<File> result = *new FILEFile(path, flags, mode);
return result;
}
// Helper function: obtain file information time.
bool SysFile::GetFileStat(FileStat* pfileStat, const String& path)
{
#if defined(OVR_OS_WIN32)
// 64-bit implementation on Windows.
struct __stat64 fileStat;
// Stat returns 0 for success.
wchar_t *pwpath = (wchar_t*)OVR_ALLOC((UTF8Util::GetLength(path.ToCStr())+1)*sizeof(wchar_t));
UTF8Util::DecodeString(pwpath, path.ToCStr());
int ret = _wstat64(pwpath, &fileStat);
OVR_FREE(pwpath);
if (ret) return false;
#else
struct stat fileStat;
// Stat returns 0 for success.
if (stat(path, &fileStat) != 0)
return false;
#endif
pfileStat->AccessTime = fileStat.st_atime;
pfileStat->ModifyTime = fileStat.st_mtime;
pfileStat->FileSize = fileStat.st_size;
return true;
}
} // Namespace OVR

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,251 @@
/************************************************************************************
PublicHeader: OVR.h
Filename : OVR_KeyCodes.h
Content : Common keyboard constants
Created : September 19, 2012
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_KeyCodes_h
#define OVR_KeyCodes_h
namespace OVR {
//-----------------------------------------------------------------------------------
// ***** KeyCode
// KeyCode enumeration defines platform-independent keyboard key constants.
// Note that Key_A through Key_Z are mapped to capital ascii constants.
enum KeyCode
{
// Key_None indicates that no key was specified.
Key_None = 0,
// A through Z and numbers 0 through 9.
Key_A = 65,
Key_B,
Key_C,
Key_D,
Key_E,
Key_F,
Key_G,
Key_H,
Key_I,
Key_J,
Key_K,
Key_L,
Key_M,
Key_N,
Key_O,
Key_P,
Key_Q,
Key_R,
Key_S,
Key_T,
Key_U,
Key_V,
Key_W,
Key_X,
Key_Y,
Key_Z,
Key_Num0 = 48,
Key_Num1,
Key_Num2,
Key_Num3,
Key_Num4,
Key_Num5,
Key_Num6,
Key_Num7,
Key_Num8,
Key_Num9,
// Numeric keypad.
Key_KP_0 = 0xa0,
Key_KP_1,
Key_KP_2,
Key_KP_3,
Key_KP_4,
Key_KP_5,
Key_KP_6,
Key_KP_7,
Key_KP_8,
Key_KP_9,
Key_KP_Multiply,
Key_KP_Add,
Key_KP_Enter,
Key_KP_Subtract,
Key_KP_Decimal,
Key_KP_Divide,
// Function keys.
Key_F1 = 0xb0,
Key_F2,
Key_F3,
Key_F4,
Key_F5,
Key_F6,
Key_F7,
Key_F8,
Key_F9,
Key_F10,
Key_F11,
Key_F12,
Key_F13,
Key_F14,
Key_F15,
// Other keys.
Key_Backspace = 8,
Key_Tab,
Key_Clear = 12,
Key_Return,
Key_Shift = 16,
Key_Control,
Key_Alt,
Key_Pause,
Key_CapsLock = 20, // Toggle
Key_Escape = 27,
Key_Space = 32,
Key_Quote = 39,
Key_PageUp = 0xc0,
Key_PageDown,
Key_End,
Key_Home,
Key_Left,
Key_Up,
Key_Right,
Key_Down,
Key_Insert,
Key_Delete,
Key_Help,
Key_Comma = 44,
Key_Minus,
Key_Slash = 47,
Key_Period,
Key_NumLock = 144, // Toggle
Key_ScrollLock = 145, // Toggle
Key_Semicolon = 59,
Key_Equal = 61,
Key_Backtick = 96, // ` and tilda~ when shifted (US keyboard)
Key_BracketLeft = 91,
Key_Backslash,
Key_BracketRight,
Key_OEM_AX = 0xE1, // 'AX' key on Japanese AX keyboard
Key_OEM_102 = 0xE2, // "<>" or "\|" on RT 102-key keyboard.
Key_ICO_HELP = 0xE3, // Help key on ICO
Key_ICO_00 = 0xE4, // 00 key on ICO
Key_Meta,
// Total number of keys.
Key_CodeCount
};
//-----------------------------------------------------------------------------------
class KeyModifiers
{
public:
enum
{
Key_ShiftPressed = 0x01,
Key_CtrlPressed = 0x02,
Key_AltPressed = 0x04,
Key_MetaPressed = 0x08,
Key_CapsToggled = 0x10,
Key_NumToggled = 0x20,
Key_ScrollToggled = 0x40,
Initialized_Bit = 0x80,
Initialized_Mask = 0xFF
};
unsigned char States;
KeyModifiers() : States(0) { }
KeyModifiers(unsigned char st) : States((unsigned char)(st | Initialized_Bit)) { }
void Reset() { States = 0; }
bool IsShiftPressed() const { return (States & Key_ShiftPressed) != 0; }
bool IsCtrlPressed() const { return (States & Key_CtrlPressed) != 0; }
bool IsAltPressed() const { return (States & Key_AltPressed) != 0; }
bool IsMetaPressed() const { return (States & Key_MetaPressed) != 0; }
bool IsCapsToggled() const { return (States & Key_CapsToggled) != 0; }
bool IsNumToggled() const { return (States & Key_NumToggled) != 0; }
bool IsScrollToggled() const{ return (States & Key_ScrollToggled) != 0; }
void SetShiftPressed(bool v = true) { (v) ? States |= Key_ShiftPressed : States &= ~Key_ShiftPressed; }
void SetCtrlPressed(bool v = true) { (v) ? States |= Key_CtrlPressed : States &= ~Key_CtrlPressed; }
void SetAltPressed(bool v = true) { (v) ? States |= Key_AltPressed : States &= ~Key_AltPressed; }
void SetMetaPressed(bool v = true) { (v) ? States |= Key_MetaPressed : States &= ~Key_MetaPressed; }
void SetCapsToggled(bool v = true) { (v) ? States |= Key_CapsToggled : States &= ~Key_CapsToggled; }
void SetNumToggled(bool v = true) { (v) ? States |= Key_NumToggled : States &= ~Key_NumToggled; }
void SetScrollToggled(bool v = true) { (v) ? States |= Key_ScrollToggled: States &= ~Key_ScrollToggled; }
bool IsInitialized() const { return (States & Initialized_Mask) != 0; }
};
//-----------------------------------------------------------------------------------
/*
enum PadKeyCode
{
Pad_None, // Indicates absence of key code.
Pad_Back,
Pad_Start,
Pad_A,
Pad_B,
Pad_X,
Pad_Y,
Pad_R1, // RightShoulder;
Pad_L1, // LeftShoulder;
Pad_R2, // RightTrigger;
Pad_L2, // LeftTrigger;
Pad_Up,
Pad_Down,
Pad_Right,
Pad_Left,
Pad_Plus,
Pad_Minus,
Pad_1,
Pad_2,
Pad_H,
Pad_C,
Pad_Z,
Pad_O,
Pad_T,
Pad_S,
Pad_Select,
Pad_Home,
Pad_RT, // RightThumb;
Pad_LT // LeftThumb;
};
*/
} // OVR
#endif

View File

@ -0,0 +1,336 @@
/************************************************************************************
PublicHeader: OVR
Filename : OVR_List.h
Content : Template implementation for doubly-connected linked List
Created : September 19, 2012
Notes :
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_List_h
#define OVR_List_h
#include "OVR_Types.h"
namespace OVR {
//-----------------------------------------------------------------------------------
// ***** ListNode
//
// Base class for the elements of the intrusive linked list.
// To store elements in the List do:
//
// struct MyData : ListNode<MyData>
// {
// . . .
// };
template<class T>
struct ListNode
{
union {
T* pPrev;
void* pVoidPrev;
};
union {
T* pNext;
void* pVoidNext;
};
void RemoveNode()
{
pPrev->pNext = pNext;
pNext->pPrev = pPrev;
}
// Removes us from the list and inserts pnew there instead.
void ReplaceNodeWith(T* pnew)
{
pPrev->pNext = pnew;
pNext->pPrev = pnew;
pnew->pPrev = pPrev;
pnew->pNext = pNext;
}
// Inserts the argument linked list node after us in the list.
void InsertNodeAfter(T* p)
{
p->pPrev = pNext->pPrev; // this
p->pNext = pNext;
pNext->pPrev = p;
pNext = p;
}
// Inserts the argument linked list node before us in the list.
void InsertNodeBefore(T* p)
{
p->pNext = pNext->pPrev; // this
p->pPrev = pPrev;
pPrev->pNext = p;
pPrev = p;
}
void Alloc_MoveTo(ListNode<T>* pdest)
{
pdest->pNext = pNext;
pdest->pPrev = pPrev;
pPrev->pNext = (T*)pdest;
pNext->pPrev = (T*)pdest;
}
};
//------------------------------------------------------------------------
// ***** List
//
// Doubly linked intrusive list.
// The data type must be derived from ListNode.
//
// Adding: PushFront(), PushBack().
// Removing: Remove() - the element must be in the list!
// Moving: BringToFront(), SendToBack() - the element must be in the list!
//
// Iterating:
// MyData* data = MyList.GetFirst();
// while (!MyList.IsNull(data))
// {
// . . .
// data = MyList.GetNext(data);
// }
//
// Removing:
// MyData* data = MyList.GetFirst();
// while (!MyList.IsNull(data))
// {
// MyData* next = MyList.GetNext(data);
// if (ToBeRemoved(data))
// MyList.Remove(data);
// data = next;
// }
//
// List<> represents a doubly-linked list of T, where each T must derive
// from ListNode<B>. B specifies the base class that was directly
// derived from ListNode, and is only necessary if there is an intermediate
// inheritance chain.
template<class T, class B = T> class List
{
public:
typedef T ValueType;
List()
{
Root.pNext = Root.pPrev = (ValueType*)&Root;
}
void Clear()
{
Root.pNext = Root.pPrev = (ValueType*)&Root;
}
const ValueType* GetFirst() const { return (const ValueType*)Root.pNext; }
const ValueType* GetLast () const { return (const ValueType*)Root.pPrev; }
ValueType* GetFirst() { return (ValueType*)Root.pNext; }
ValueType* GetLast () { return (ValueType*)Root.pPrev; }
// Determine if list is empty (i.e.) points to itself.
// Go through void* access to avoid issues with strict-aliasing optimizing out the
// access after RemoveNode(), etc.
bool IsEmpty() const { return Root.pVoidNext == (const T*)(const B*)&Root; }
bool IsFirst(const ValueType* p) const { return p == Root.pNext; }
bool IsLast (const ValueType* p) const { return p == Root.pPrev; }
bool IsNull (const ValueType* p) const { return p == (const T*)(const B*)&Root; }
inline static const ValueType* GetPrev(const ValueType* p) { return (const ValueType*)p->pPrev; }
inline static const ValueType* GetNext(const ValueType* p) { return (const ValueType*)p->pNext; }
inline static ValueType* GetPrev( ValueType* p) { return (ValueType*)p->pPrev; }
inline static ValueType* GetNext( ValueType* p) { return (ValueType*)p->pNext; }
void PushFront(ValueType* p)
{
p->pNext = Root.pNext;
p->pPrev = (ValueType*)&Root;
Root.pNext->pPrev = p;
Root.pNext = p;
}
void PushBack(ValueType* p)
{
p->pPrev = Root.pPrev;
p->pNext = (ValueType*)&Root;
Root.pPrev->pNext = p;
Root.pPrev = p;
}
static void Remove(ValueType* p)
{
p->pPrev->pNext = p->pNext;
p->pNext->pPrev = p->pPrev;
}
void BringToFront(ValueType* p)
{
Remove(p);
PushFront(p);
}
void SendToBack(ValueType* p)
{
Remove(p);
PushBack(p);
}
// Appends the contents of the argument list to the front of this list;
// items are removed from the argument list.
void PushListToFront(List<T>& src)
{
if (!src.IsEmpty())
{
ValueType* pfirst = src.GetFirst();
ValueType* plast = src.GetLast();
src.Clear();
plast->pNext = Root.pNext;
pfirst->pPrev = (ValueType*)&Root;
Root.pNext->pPrev = plast;
Root.pNext = pfirst;
}
}
void PushListToBack(List<T>& src)
{
if (!src.IsEmpty())
{
ValueType* pfirst = src.GetFirst();
ValueType* plast = src.GetLast();
src.Clear();
plast->pNext = (ValueType*)&Root;
pfirst->pPrev = Root.pPrev;
Root.pPrev->pNext = pfirst;
Root.pPrev = plast;
}
}
// Removes all source list items after (and including) the 'pfirst' node from the
// source list and adds them to out list.
void PushFollowingListItemsToFront(List<T>& src, ValueType *pfirst)
{
if (pfirst != &src.Root)
{
ValueType *plast = src.Root.pPrev;
// Remove list remainder from source.
pfirst->pPrev->pNext = (ValueType*)&src.Root;
src.Root.pPrev = pfirst->pPrev;
// Add the rest of the items to list.
plast->pNext = Root.pNext;
pfirst->pPrev = (ValueType*)&Root;
Root.pNext->pPrev = plast;
Root.pNext = pfirst;
}
}
// Removes all source list items up to but NOT including the 'pend' node from the
// source list and adds them to out list.
void PushPrecedingListItemsToFront(List<T>& src, ValueType *ptail)
{
if (src.GetFirst() != ptail)
{
ValueType *pfirst = src.Root.pNext;
ValueType *plast = ptail->pPrev;
// Remove list remainder from source.
ptail->pPrev = (ValueType*)&src.Root;
src.Root.pNext = ptail;
// Add the rest of the items to list.
plast->pNext = Root.pNext;
pfirst->pPrev = (ValueType*)&Root;
Root.pNext->pPrev = plast;
Root.pNext = pfirst;
}
}
// Removes a range of source list items starting at 'pfirst' and up to, but not including 'pend',
// and adds them to out list. Note that source items MUST already be in the list.
void PushListItemsToFront(ValueType *pfirst, ValueType *pend)
{
if (pfirst != pend)
{
ValueType *plast = pend->pPrev;
// Remove list remainder from source.
pfirst->pPrev->pNext = pend;
pend->pPrev = pfirst->pPrev;
// Add the rest of the items to list.
plast->pNext = Root.pNext;
pfirst->pPrev = (ValueType*)&Root;
Root.pNext->pPrev = plast;
Root.pNext = pfirst;
}
}
void Alloc_MoveTo(List<T>* pdest)
{
if (IsEmpty())
pdest->Clear();
else
{
pdest->Root.pNext = Root.pNext;
pdest->Root.pPrev = Root.pPrev;
Root.pNext->pPrev = (ValueType*)&pdest->Root;
Root.pPrev->pNext = (ValueType*)&pdest->Root;
}
}
private:
// Copying is prohibited
List(const List<T>&);
const List<T>& operator = (const List<T>&);
ListNode<B> Root;
};
//------------------------------------------------------------------------
// ***** FreeListElements
//
// Remove all elements in the list and free them in the allocator
template<class List, class Allocator>
void FreeListElements(List& list, Allocator& allocator)
{
typename List::ValueType* self = list.GetFirst();
while(!list.IsNull(self))
{
typename List::ValueType* next = list.GetNext(self);
allocator.Free(self);
self = next;
}
list.Clear();
}
} // OVR
#endif

View File

@ -0,0 +1,231 @@
/************************************************************************************
PublicHeader: OVR.h
Filename : OVR_Lockless.cpp
Content : Test logic for lock-less classes
Created : December 27, 2013
Authors : Michael Antonov
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_Lockless.h"
#ifdef OVR_LOCKLESS_TEST
#include "OVR_Threads.h"
#include "OVR_Timer.h"
#include "OVR_Log.h"
namespace OVR { namespace LocklessTest {
const int TestIterations = 10000000;
// Use volatile dummys to force compiler to do spinning.
volatile int Dummy1;
int Unused1[32];
volatile int Dummy2;
int Unused2[32];
volatile int Dummy3;
int Unused3[32];
// Data block out of 20 consecutive integers, should be internally consistent.
struct TestData
{
enum { ItemCount = 20 };
int Data[ItemCount];
void Set(int val)
{
for (int i=0; i<ItemCount; i++)
{
Data[i] = val*100 + i;
}
}
int ReadAndCheckConsistency(int prevValue) const
{
int val = Data[0];
for (int i=1; i<ItemCount; i++)
{
if (Data[i] != (val + i))
{
// Only complain once per same-value entry
if (prevValue != val / 100)
{
LogText("LocklessTest Fail - corruption at %d inside block %d\n",
i, val/100);
// OVR_ASSERT(Data[i] == val + i);
}
break;
}
}
return val / 100;
}
};
volatile bool FirstItemWritten = false;
LocklessUpdater<TestData> TestDataUpdater;
// Use this lock to verify that testing algorithm is otherwise correct...
Lock TestLock;
//-------------------------------------------------------------------------------------
// Consumer thread reads values from TestDataUpdater and
// ensures that each one is internally consistent.
class Consumer : public Thread
{
virtual int Run()
{
LogText("LocklessTest::Consumer::Run started.\n");
while (!FirstItemWritten)
{
// spin until producer wrote first value...
}
TestData d;
int oldValue = 0;
int newValue;
do
{
{
//Lock::Locker scope(&TestLock);
d = TestDataUpdater.GetState();
}
newValue = d.ReadAndCheckConsistency(oldValue);
// Values should increase or stay the same!
if (newValue < oldValue)
{
LogText("LocklessTest Fail - %d after %d; delta = %d\n",
newValue, oldValue, newValue - oldValue);
// OVR_ASSERT(0);
}
if (oldValue != newValue)
{
oldValue = newValue;
if (oldValue % (TestIterations/30) == 0)
{
LogText("LocklessTest::Consumer - %5.2f%% done\n",
100.0f * (float)oldValue/(float)TestIterations);
}
}
// Spin a while
for (int j = 0; j< 300; j++)
{
Dummy3 = j;
}
} while (oldValue < (TestIterations * 99 / 100));
LogText("LocklessTest::Consumer::Run exiting.\n");
return 0;
}
};
//-------------------------------------------------------------------------------------
class Producer : public Thread
{
virtual int Run()
{
LogText("LocklessTest::Producer::Run started.\n");
for (int testVal = 0; testVal < TestIterations; testVal++)
{
TestData d;
d.Set(testVal);
{
//Lock::Locker scope(&TestLock);
TestDataUpdater.SetState(d);
}
FirstItemWritten = true;
// Spin a bit
for(int j = 0; j < 1000; j++)
{
Dummy2 = j;
}
if (testVal % (TestIterations/30) == 0)
{
LogText("LocklessTest::Producer - %5.2f%% done\n",
100.0f * (float)testVal/(float)TestIterations);
}
}
LogText("LocklessTest::Producer::Run exiting.\n");
return 0;
}
};
} // namespace LocklessTest
void StartLocklessTest()
{
// These threads will release themselves once done
Ptr<LocklessTest::Producer> producerThread = *new LocklessTest::Producer;
Ptr<LocklessTest::Consumer> consumerThread = *new LocklessTest::Consumer;
producerThread->Start();
consumerThread->Start();
/*
while (!producerThread->IsFinished() && consumerThread->IsFinished())
{
Thread::MSleep(500);
} */
// TBD: Cleanup
}
} // namespace OVR
#endif // OVR_LOCKLESS_TEST

View File

@ -0,0 +1,107 @@
/************************************************************************************
PublicHeader: OVR.h
Filename : OVR_Lockless.h
Content : Lock-less classes for producer/consumer communication
Created : November 9, 2013
Authors : John Carmack
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_Lockless_h
#define OVR_Lockless_h
#include "OVR_Atomic.h"
// Define this to compile-in Lockless test logic
//#define OVR_LOCKLESS_TEST
namespace OVR {
// ***** LocklessUpdater
// For single producer cases where you only care about the most recent update, not
// necessarily getting every one that happens (vsync timing, SensorFusion updates).
//
// This is multiple consumer safe, but is currently only used with a single consumer.
template<class T>
class LocklessUpdater
{
public:
LocklessUpdater() : UpdateBegin( 0 ), UpdateEnd( 0 ) {}
T GetState() const
{
// Copy the state out, then retry with the alternate slot
// if we determine that our copy may have been partially
// stepped on by a new update.
T state;
int begin, end, final;
for(;;)
{
// We are adding 0, only using these as atomic memory barriers, so it
// is ok to cast off the const, allowing GetState() to remain const.
end = UpdateEnd.ExchangeAdd_Sync(0);
state = Slots[ end & 1 ];
begin = UpdateBegin.ExchangeAdd_Sync(0);
if ( begin == end ) {
break;
}
// The producer is potentially blocked while only having partially
// written the update, so copy out the other slot.
state = Slots[ (begin & 1) ^ 1 ];
final = UpdateBegin.ExchangeAdd_NoSync(0);
if ( final == begin ) {
break;
}
// The producer completed the last update and started a new one before
// we got it copied out, so try fetching the current buffer again.
}
return state;
}
void SetState( T state )
{
const int slot = UpdateBegin.ExchangeAdd_Sync(1) & 1;
// Write to (slot ^ 1) because ExchangeAdd returns 'previous' value before add.
Slots[slot ^ 1] = state;
UpdateEnd.ExchangeAdd_Sync(1);
}
mutable AtomicInt<int> UpdateBegin;
mutable AtomicInt<int> UpdateEnd;
T Slots[2];
};
#ifdef OVR_LOCKLESS_TEST
void StartLocklessTest();
#endif
} // namespace OVR
#endif // OVR_Lockless_h

View File

@ -0,0 +1,184 @@
/************************************************************************************
Filename : OVR_Log.cpp
Content : Logging support
Created : September 19, 2012
Notes :
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_Log.h"
#include "OVR_Std.h"
#include <stdarg.h>
#include <stdio.h>
#if defined(OVR_OS_WIN32)
#include <windows.h>
#elif defined(OVR_OS_ANDROID)
#include <android/log.h>
#endif
namespace OVR {
// Global Log pointer.
Log* volatile OVR_GlobalLog = 0;
//-----------------------------------------------------------------------------------
// ***** Log Implementation
Log::~Log()
{
// Clear out global log
if (this == OVR_GlobalLog)
{
// TBD: perhaps we should ASSERT if this happens before system shutdown?
OVR_GlobalLog = 0;
}
}
void Log::LogMessageVarg(LogMessageType messageType, const char* fmt, va_list argList)
{
if ((messageType & LoggingMask) == 0)
return;
#ifndef OVR_BUILD_DEBUG
if (IsDebugMessage(messageType))
return;
#endif
char buffer[MaxLogBufferMessageSize];
FormatLog(buffer, MaxLogBufferMessageSize, messageType, fmt, argList);
DefaultLogOutput(buffer, IsDebugMessage(messageType));
}
void OVR::Log::LogMessage(LogMessageType messageType, const char* pfmt, ...)
{
va_list argList;
va_start(argList, pfmt);
LogMessageVarg(messageType, pfmt, argList);
va_end(argList);
}
void Log::FormatLog(char* buffer, unsigned bufferSize, LogMessageType messageType,
const char* fmt, va_list argList)
{
bool addNewline = true;
switch(messageType)
{
case Log_Error: OVR_strcpy(buffer, bufferSize, "Error: "); break;
case Log_Debug: OVR_strcpy(buffer, bufferSize, "Debug: "); break;
case Log_Assert: OVR_strcpy(buffer, bufferSize, "Assert: "); break;
case Log_Text: buffer[0] = 0; addNewline = false; break;
case Log_DebugText: buffer[0] = 0; addNewline = false; break;
default:
buffer[0] = 0;
addNewline = false;
break;
}
UPInt prefixLength = OVR_strlen(buffer);
char *buffer2 = buffer + prefixLength;
OVR_vsprintf(buffer2, bufferSize - prefixLength, fmt, argList);
if (addNewline)
OVR_strcat(buffer, bufferSize, "\n");
}
void Log::DefaultLogOutput(const char* formattedText, bool debug)
{
#if defined(OVR_OS_WIN32)
// Under Win32, output regular messages to console if it exists; debug window otherwise.
static DWORD dummyMode;
static bool hasConsole = (GetStdHandle(STD_OUTPUT_HANDLE) != INVALID_HANDLE_VALUE) &&
(GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &dummyMode));
if (!hasConsole || debug)
{
::OutputDebugStringA(formattedText);
}
else
{
fputs(formattedText, stdout);
}
#elif defined(OVR_OS_ANDROID)
__android_log_write(ANDROID_LOG_INFO, "OVR", formattedText);
#else
fputs(formattedText, stdout);
#endif
// Just in case.
OVR_UNUSED2(formattedText, debug);
}
//static
void Log::SetGlobalLog(Log *log)
{
OVR_GlobalLog = log;
}
//static
Log* Log::GetGlobalLog()
{
// No global log by default?
// if (!OVR_GlobalLog)
// OVR_GlobalLog = GetDefaultLog();
return OVR_GlobalLog;
}
//static
Log* Log::GetDefaultLog()
{
// Create default log pointer statically so that it can be used
// even during startup.
static Log defaultLog;
return &defaultLog;
}
//-----------------------------------------------------------------------------------
// ***** Global Logging functions
#define OVR_LOG_FUNCTION_IMPL(Name) \
void Log##Name(const char* fmt, ...) \
{ \
if (OVR_GlobalLog) \
{ \
va_list argList; va_start(argList, fmt); \
OVR_GlobalLog->LogMessageVarg(Log_##Name, fmt, argList); \
va_end(argList); \
} \
}
OVR_LOG_FUNCTION_IMPL(Text)
OVR_LOG_FUNCTION_IMPL(Error)
#ifdef OVR_BUILD_DEBUG
OVR_LOG_FUNCTION_IMPL(DebugText)
OVR_LOG_FUNCTION_IMPL(Debug)
OVR_LOG_FUNCTION_IMPL(Assert)
#endif
} // OVR

View File

@ -0,0 +1,204 @@
/************************************************************************************
PublicHeader: OVR
Filename : OVR_Log.h
Content : Logging support
Created : September 19, 2012
Notes :
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_Log_h
#define OVR_Log_h
#include "OVR_Types.h"
#include <stdarg.h>
namespace OVR {
//-----------------------------------------------------------------------------------
// ***** Logging Constants
// LogMaskConstants defined bit mask constants that describe what log messages
// should be displayed.
enum LogMaskConstants
{
LogMask_Regular = 0x100,
LogMask_Debug = 0x200,
LogMask_None = 0,
LogMask_All = LogMask_Regular|LogMask_Debug
};
// LogMessageType describes the type of the log message, controls when it is
// displayed and what prefix/suffix is given to it. Messages are subdivided into
// regular and debug logging types. Debug logging is only generated in debug builds.
//
// Log_Text - General output text displayed without prefix or new-line.
// Used in OVR libraries for general log flow messages
// such as "Device Initialized".
//
// Log_Error - Error message output with "Error: %s\n", intended for
// application/sample-level use only, in cases where an expected
// operation failed. OVR libraries should not use this internally,
// reporting status codes instead.
//
// Log_DebugText - Message without prefix or new lines; output in Debug build only.
//
// Log_Debug - Debug-build only message, formatted with "Debug: %s\n".
// Intended to comment on incorrect API usage that doesn't lead
// to crashes but can be avoided with proper use.
// There is no Debug Error on purpose, since real errors should
// be handled by API user.
//
// Log_Assert - Debug-build only message, formatted with "Assert: %s\n".
// Intended for severe unrecoverable conditions in library
// source code. Generated though OVR_ASSERT_MSG(c, "Text").
enum LogMessageType
{
// General Logging
Log_Text = LogMask_Regular | 0,
Log_Error = LogMask_Regular | 1, // "Error: %s\n".
// Debug-only messages (not generated in release build)
Log_DebugText = LogMask_Debug | 0,
Log_Debug = LogMask_Debug | 1, // "Debug: %s\n".
Log_Assert = LogMask_Debug | 2, // "Assert: %s\n".
};
// LOG_VAARG_ATTRIBUTE macro, enforces printf-style fromatting for message types
#ifdef __GNUC__
# define OVR_LOG_VAARG_ATTRIBUTE(a,b) __attribute__((format (printf, a, b)))
#else
# define OVR_LOG_VAARG_ATTRIBUTE(a,b)
#endif
//-----------------------------------------------------------------------------------
// ***** Log
// Log defines a base class interface that can be implemented to catch both
// debug and runtime messages.
// Debug logging can be overridden by calling Log::SetGlobalLog.
class Log
{
friend class System;
public:
Log(unsigned logMask = LogMask_Debug) : LoggingMask(logMask) { }
virtual ~Log();
// Log formating buffer size used by default LogMessageVarg. Longer strings are truncated.
enum { MaxLogBufferMessageSize = 4096 };
unsigned GetLoggingMask() const { return LoggingMask; }
void SetLoggingMask(unsigned logMask) { LoggingMask = logMask; }
// This virtual function receives all the messages,
// developers should override this function in order to do custom logging
virtual void LogMessageVarg(LogMessageType messageType, const char* fmt, va_list argList);
// Call the logging function with specific message type, with no type filtering.
void LogMessage(LogMessageType messageType,
const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(3,4);
// Helper used by LogMessageVarg to format the log message, writing the resulting
// string into buffer. It formats text based on fmt and appends prefix/new line
// based on LogMessageType.
static void FormatLog(char* buffer, unsigned bufferSize, LogMessageType messageType,
const char* fmt, va_list argList);
// Default log output implementation used by by LogMessageVarg.
// Debug flag may be used to re-direct output on some platforms, but doesn't
// necessarily disable it in release builds; that is the job of the called.
static void DefaultLogOutput(const char* textBuffer, bool debug);
// Determines if the specified message type is for debugging only.
static bool IsDebugMessage(LogMessageType messageType)
{
return (messageType & LogMask_Debug) != 0;
}
// *** Global APIs
// Global Log registration APIs.
// - Global log is used for OVR_DEBUG messages. Set global log to null (0)
// to disable all logging.
static void SetGlobalLog(Log *log);
static Log* GetGlobalLog();
// Returns default log singleton instance.
static Log* GetDefaultLog();
// Applies logMask to the default log and returns a pointer to it.
// By default, only Debug logging is enabled, so to avoid SDK generating console
// messages in user app (those are always disabled in release build,
// even if the flag is set). This function is useful in System constructor.
static Log* ConfigureDefaultLog(unsigned logMask = LogMask_Debug)
{
Log* log = GetDefaultLog();
log->SetLoggingMask(logMask);
return log;
}
private:
// Logging mask described by LogMaskConstants.
unsigned LoggingMask;
};
//-----------------------------------------------------------------------------------
// ***** Global Logging Functions and Debug Macros
// These functions will output text to global log with semantics described by
// their LogMessageType.
void LogText(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2);
void LogError(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2);
#ifdef OVR_BUILD_DEBUG
// Debug build only logging.
void LogDebugText(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2);
void LogDebug(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2);
void LogAssert(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2);
// Macro to do debug logging, printf-style.
// An extra set of set of parenthesis must be used around arguments,
// as in: OVR_LOG_DEBUG(("Value %d", 2)).
#define OVR_DEBUG_LOG(args) do { OVR::LogDebug args; } while(0)
#define OVR_DEBUG_LOG_TEXT(args) do { OVR::LogDebugText args; } while(0)
#define OVR_ASSERT_LOG(c, args) do { if (!(c)) { OVR::LogAssert args; OVR_DEBUG_BREAK; } } while(0)
#else
// If not in debug build, macros do nothing.
#define OVR_DEBUG_LOG(args) ((void)0)
#define OVR_DEBUG_LOG_TEXT(args) ((void)0)
#define OVR_ASSERT_LOG(c, args) ((void)0)
#endif
} // OVR
#endif

View File

@ -0,0 +1,91 @@
/************************************************************************************
Filename : OVR_Math.h
Content : Implementation of 3D primitives such as vectors, matrices.
Created : September 4, 2012
Authors : Andrew Reisse, Michael Antonov, Anna Yershova
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_Math.h"
#include "OVR_Log.h"
#include <float.h>
namespace OVR {
//-------------------------------------------------------------------------------------
// ***** Math
// Single-precision Math constants class.
const float Math<float>::Pi = 3.1415926f;
const float Math<float>::TwoPi = 3.1415926f * 2;
const float Math<float>::PiOver2 = 3.1415926f / 2.0f;
const float Math<float>::PiOver4 = 3.1415926f / 4.0f;
const float Math<float>::E = 2.7182818f;
const float Math<float>::MaxValue = FLT_MAX;
const float Math<float>::MinPositiveValue = FLT_MIN;
const float Math<float>::RadToDegreeFactor = 360.0f / Math<float>::TwoPi;
const float Math<float>::DegreeToRadFactor = Math<float>::TwoPi / 360.0f;
const float Math<float>::Tolerance = 0.00001f;
const float Math<float>::SingularityRadius = 0.0000001f; // Use for Gimbal lock numerical problems
// Double-precision Math constants class.
const double Math<double>::Pi = 3.14159265358979;
const double Math<double>::TwoPi = 3.14159265358979 * 2;
const double Math<double>::PiOver2 = 3.14159265358979 / 2.0;
const double Math<double>::PiOver4 = 3.14159265358979 / 4.0;
const double Math<double>::E = 2.71828182845905;
const double Math<double>::MaxValue = DBL_MAX;
const double Math<double>::MinPositiveValue = DBL_MIN;
const double Math<double>::RadToDegreeFactor = 360.0 / Math<double>::TwoPi;
const double Math<double>::DegreeToRadFactor = Math<double>::TwoPi / 360.0;
const double Math<double>::Tolerance = 0.00001;
const double Math<double>::SingularityRadius = 0.000000000001; // Use for Gimbal lock numerical problems
//-------------------------------------------------------------------------------------
// ***** Matrix4
template<>
const Matrix4<float> Matrix4<float>::IdentityValue = Matrix4<float>(1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
template<>
const Matrix4<double> Matrix4<double>::IdentityValue = Matrix4<double>(1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0);
} // Namespace OVR

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,111 @@
/************************************************************************************
Filename : OVR_RefCount.cpp
Content : Reference counting implementation
Created : September 19, 2012
Notes :
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_RefCount.h"
#include "OVR_Atomic.h"
#include "OVR_Log.h"
namespace OVR {
#ifdef OVR_CC_ARM
void* ReturnArg0(void* p)
{
return p;
}
#endif
// ***** Reference Count Base implementation
RefCountImplCore::~RefCountImplCore()
{
// RefCount can be either 1 or 0 here.
// 0 if Release() was properly called.
// 1 if the object was declared on stack or as an aggregate.
OVR_ASSERT(RefCount <= 1);
}
#ifdef OVR_BUILD_DEBUG
void RefCountImplCore::reportInvalidDelete(void *pmem)
{
OVR_DEBUG_LOG(
("Invalid delete call on ref-counted object at %p. Please use Release()", pmem));
OVR_ASSERT(0);
}
#endif
RefCountNTSImplCore::~RefCountNTSImplCore()
{
// RefCount can be either 1 or 0 here.
// 0 if Release() was properly called.
// 1 if the object was declared on stack or as an aggregate.
OVR_ASSERT(RefCount <= 1);
}
#ifdef OVR_BUILD_DEBUG
void RefCountNTSImplCore::reportInvalidDelete(void *pmem)
{
OVR_DEBUG_LOG(
("Invalid delete call on ref-counted object at %p. Please use Release()", pmem));
OVR_ASSERT(0);
}
#endif
// *** Thread-Safe RefCountImpl
void RefCountImpl::AddRef()
{
AtomicOps<int>::ExchangeAdd_NoSync(&RefCount, 1);
}
void RefCountImpl::Release()
{
if ((AtomicOps<int>::ExchangeAdd_NoSync(&RefCount, -1) - 1) == 0)
delete this;
}
// *** Thread-Safe RefCountVImpl w/virtual AddRef/Release
void RefCountVImpl::AddRef()
{
AtomicOps<int>::ExchangeAdd_NoSync(&RefCount, 1);
}
void RefCountVImpl::Release()
{
if ((AtomicOps<int>::ExchangeAdd_NoSync(&RefCount, -1) - 1) == 0)
delete this;
}
// *** NON-Thread-Safe RefCountImpl
void RefCountNTSImpl::Release() const
{
RefCount--;
if (RefCount == 0)
delete this;
}
} // OVR

View File

@ -0,0 +1,564 @@
/************************************************************************************
PublicHeader: Kernel
Filename : OVR_RefCount.h
Content : Reference counting implementation headers
Created : September 19, 2012
Notes :
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_RefCount_h
#define OVR_RefCount_h
#include "OVR_Types.h"
#include "OVR_Allocator.h"
namespace OVR {
//-----------------------------------------------------------------------------------
// ***** Reference Counting
// There are three types of reference counting base classes:
//
// RefCountBase - Provides thread-safe reference counting (Default).
// RefCountBaseNTS - Non Thread Safe version of reference counting.
// ***** Declared classes
template<class C>
class RefCountBase;
template<class C>
class RefCountBaseNTS;
class RefCountImpl;
class RefCountNTSImpl;
//-----------------------------------------------------------------------------------
// ***** Implementation For Reference Counting
// RefCountImplCore holds RefCount value and defines a few utility
// functions shared by all implementations.
class RefCountImplCore
{
protected:
volatile int RefCount;
public:
// RefCountImpl constructor always initializes RefCount to 1 by default.
OVR_FORCE_INLINE RefCountImplCore() : RefCount(1) { }
// Need virtual destructor
// This: 1. Makes sure the right destructor's called.
// 2. Makes us have VTable, necessary if we are going to have format needed by InitNewMem()
virtual ~RefCountImplCore();
// Debug method only.
int GetRefCount() const { return RefCount; }
// This logic is used to detect invalid 'delete' calls of reference counted
// objects. Direct delete calls are not allowed on them unless they come in
// internally from Release.
#ifdef OVR_BUILD_DEBUG
static void OVR_CDECL reportInvalidDelete(void *pmem);
inline static void checkInvalidDelete(RefCountImplCore *pmem)
{
if (pmem->RefCount != 0)
reportInvalidDelete(pmem);
}
#else
inline static void checkInvalidDelete(RefCountImplCore *) { }
#endif
// Base class ref-count content should not be copied.
void operator = (const RefCountImplCore &) { }
};
class RefCountNTSImplCore
{
protected:
mutable int RefCount;
public:
// RefCountImpl constructor always initializes RefCount to 1 by default.
OVR_FORCE_INLINE RefCountNTSImplCore() : RefCount(1) { }
// Need virtual destructor
// This: 1. Makes sure the right destructor's called.
// 2. Makes us have VTable, necessary if we are going to have format needed by InitNewMem()
virtual ~RefCountNTSImplCore();
// Debug method only.
int GetRefCount() const { return RefCount; }
// This logic is used to detect invalid 'delete' calls of reference counted
// objects. Direct delete calls are not allowed on them unless they come in
// internally from Release.
#ifdef OVR_BUILD_DEBUG
static void OVR_CDECL reportInvalidDelete(void *pmem);
OVR_FORCE_INLINE static void checkInvalidDelete(RefCountNTSImplCore *pmem)
{
if (pmem->RefCount != 0)
reportInvalidDelete(pmem);
}
#else
OVR_FORCE_INLINE static void checkInvalidDelete(RefCountNTSImplCore *) { }
#endif
// Base class ref-count content should not be copied.
void operator = (const RefCountNTSImplCore &) { }
};
// RefCountImpl provides Thread-Safe implementation of reference counting, so
// it should be used by default in most places.
class RefCountImpl : public RefCountImplCore
{
public:
// Thread-Safe Ref-Count Implementation.
void AddRef();
void Release();
};
// RefCountVImpl provides Thread-Safe implementation of reference counting, plus,
// virtual AddRef and Release.
class RefCountVImpl : virtual public RefCountImplCore
{
public:
// Thread-Safe Ref-Count Implementation.
virtual void AddRef();
virtual void Release();
};
// RefCountImplNTS provides Non-Thread-Safe implementation of reference counting,
// which is slightly more efficient since it doesn't use atomics.
class RefCountNTSImpl : public RefCountNTSImplCore
{
public:
OVR_FORCE_INLINE void AddRef() const { RefCount++; }
void Release() const;
};
// RefCountBaseStatImpl<> is a common class that adds new/delete override with Stat tracking
// to the reference counting implementation. Base must be one of the RefCountImpl classes.
template<class Base>
class RefCountBaseStatImpl : public Base
{
public:
RefCountBaseStatImpl() { }
// *** Override New and Delete
// DOM-IGNORE-BEGIN
// Undef new temporarily if it is being redefined
#ifdef OVR_DEFINE_NEW
#undef new
#endif
#ifdef OVR_BUILD_DEBUG
// Custom check used to detect incorrect calls of 'delete' on ref-counted objects.
#define OVR_REFCOUNTALLOC_CHECK_DELETE(class_name, p) \
do {if (p) Base::checkInvalidDelete((class_name*)p); } while(0)
#else
#define OVR_REFCOUNTALLOC_CHECK_DELETE(class_name, p)
#endif
// Redefine all new & delete operators.
OVR_MEMORY_REDEFINE_NEW_IMPL(Base, OVR_REFCOUNTALLOC_CHECK_DELETE)
#undef OVR_REFCOUNTALLOC_CHECK_DELETE
#ifdef OVR_DEFINE_NEW
#define new OVR_DEFINE_NEW
#endif
// OVR_BUILD_DEFINE_NEW
// DOM-IGNORE-END
};
template<class Base>
class RefCountBaseStatVImpl : virtual public Base
{
public:
RefCountBaseStatVImpl() { }
// *** Override New and Delete
// DOM-IGNORE-BEGIN
// Undef new temporarily if it is being redefined
#ifdef OVR_DEFINE_NEW
#undef new
#endif
#define OVR_REFCOUNTALLOC_CHECK_DELETE(class_name, p)
// Redefine all new & delete operators.
OVR_MEMORY_REDEFINE_NEW_IMPL(Base, OVR_REFCOUNTALLOC_CHECK_DELETE)
#undef OVR_REFCOUNTALLOC_CHECK_DELETE
#ifdef OVR_DEFINE_NEW
#define new OVR_DEFINE_NEW
#endif
// OVR_BUILD_DEFINE_NEW
// DOM-IGNORE-END
};
//-----------------------------------------------------------------------------------
// *** End user RefCountBase<> classes
// RefCountBase is a base class for classes that require thread-safe reference
// counting; it also overrides the new and delete operators to use MemoryHeap.
//
// Reference counted objects start out with RefCount value of 1. Further lifetime
// management is done through the AddRef() and Release() methods, typically
// hidden by Ptr<>.
template<class C>
class RefCountBase : public RefCountBaseStatImpl<RefCountImpl>
{
public:
// Constructor.
OVR_FORCE_INLINE RefCountBase() : RefCountBaseStatImpl<RefCountImpl>() { }
};
// RefCountBaseV is the same as RefCountBase but with virtual AddRef/Release
template<class C>
class RefCountBaseV : virtual public RefCountBaseStatVImpl<RefCountVImpl>
{
public:
// Constructor.
OVR_FORCE_INLINE RefCountBaseV() : RefCountBaseStatVImpl<RefCountVImpl>() { }
};
// RefCountBaseNTS is a base class for classes that require Non-Thread-Safe reference
// counting; it also overrides the new and delete operators to use MemoryHeap.
// This class should only be used if all pointers to it are known to be assigned,
// destroyed and manipulated within one thread.
//
// Reference counted objects start out with RefCount value of 1. Further lifetime
// management is done through the AddRef() and Release() methods, typically
// hidden by Ptr<>.
template<class C>
class RefCountBaseNTS : public RefCountBaseStatImpl<RefCountNTSImpl>
{
public:
// Constructor.
OVR_FORCE_INLINE RefCountBaseNTS() : RefCountBaseStatImpl<RefCountNTSImpl>() { }
};
//-----------------------------------------------------------------------------------
// ***** Pickable template pointer
enum PickType { PickValue };
template <typename T>
class Pickable
{
public:
Pickable() : pV(NULL) {}
explicit Pickable(T* p) : pV(p) {}
Pickable(T* p, PickType) : pV(p)
{
OVR_ASSERT(pV);
if (pV)
pV->AddRef();
}
template <typename OT>
Pickable(const Pickable<OT>& other) : pV(other.GetPtr()) {}
public:
Pickable& operator =(const Pickable& other)
{
OVR_ASSERT(pV == NULL);
pV = other.pV;
// Extra check.
//other.pV = NULL;
return *this;
}
public:
T* GetPtr() const { return pV; }
T* operator->() const
{
return pV;
}
T& operator*() const
{
OVR_ASSERT(pV);
return *pV;
}
private:
T* pV;
};
template <typename T>
OVR_FORCE_INLINE
Pickable<T> MakePickable(T* p)
{
return Pickable<T>(p);
}
//-----------------------------------------------------------------------------------
// ***** Ref-Counted template pointer
// Automatically AddRefs and Releases interfaces
void* ReturnArg0(void* p);
template<class C>
class Ptr
{
#ifdef OVR_CC_ARM
static C* ReturnArg(void* p) { return (C*)ReturnArg0(p); }
#endif
protected:
C *pObject;
public:
// Constructors
OVR_FORCE_INLINE Ptr() : pObject(0)
{ }
#ifdef OVR_CC_ARM
OVR_FORCE_INLINE Ptr(C &robj) : pObject(ReturnArg(&robj))
#else
OVR_FORCE_INLINE Ptr(C &robj) : pObject(&robj)
#endif
{ }
OVR_FORCE_INLINE Ptr(Pickable<C> v) : pObject(v.GetPtr())
{
// No AddRef() on purpose.
}
OVR_FORCE_INLINE Ptr(Ptr<C>& other, PickType) : pObject(other.pObject)
{
other.pObject = NULL;
// No AddRef() on purpose.
}
OVR_FORCE_INLINE Ptr(C *pobj)
{
if (pobj) pobj->AddRef();
pObject = pobj;
}
OVR_FORCE_INLINE Ptr(const Ptr<C> &src)
{
if (src.pObject) src.pObject->AddRef();
pObject = src.pObject;
}
template<class R>
OVR_FORCE_INLINE Ptr(Ptr<R> &src)
{
if (src) src->AddRef();
pObject = src;
}
template<class R>
OVR_FORCE_INLINE Ptr(Pickable<R> v) : pObject(v.GetPtr())
{
// No AddRef() on purpose.
}
// Destructor
OVR_FORCE_INLINE ~Ptr()
{
if (pObject) pObject->Release();
}
// Compares
OVR_FORCE_INLINE bool operator == (const Ptr &other) const { return pObject == other.pObject; }
OVR_FORCE_INLINE bool operator != (const Ptr &other) const { return pObject != other.pObject; }
OVR_FORCE_INLINE bool operator == (C *pother) const { return pObject == pother; }
OVR_FORCE_INLINE bool operator != (C *pother) const { return pObject != pother; }
OVR_FORCE_INLINE bool operator < (const Ptr &other) const { return pObject < other.pObject; }
// Assignment
template<class R>
OVR_FORCE_INLINE const Ptr<C>& operator = (const Ptr<R> &src)
{
if (src) src->AddRef();
if (pObject) pObject->Release();
pObject = src;
return *this;
}
// Specialization
OVR_FORCE_INLINE const Ptr<C>& operator = (const Ptr<C> &src)
{
if (src) src->AddRef();
if (pObject) pObject->Release();
pObject = src;
return *this;
}
OVR_FORCE_INLINE const Ptr<C>& operator = (C *psrc)
{
if (psrc) psrc->AddRef();
if (pObject) pObject->Release();
pObject = psrc;
return *this;
}
OVR_FORCE_INLINE const Ptr<C>& operator = (C &src)
{
if (pObject) pObject->Release();
pObject = &src;
return *this;
}
OVR_FORCE_INLINE Ptr<C>& operator = (Pickable<C> src)
{
return Pick(src);
}
template<class R>
OVR_FORCE_INLINE Ptr<C>& operator = (Pickable<R> src)
{
return Pick(src);
}
// Set Assignment
template<class R>
OVR_FORCE_INLINE Ptr<C>& SetPtr(const Ptr<R> &src)
{
if (src) src->AddRef();
if (pObject) pObject->Release();
pObject = src;
return *this;
}
// Specialization
OVR_FORCE_INLINE Ptr<C>& SetPtr(const Ptr<C> &src)
{
if (src) src->AddRef();
if (pObject) pObject->Release();
pObject = src;
return *this;
}
OVR_FORCE_INLINE Ptr<C>& SetPtr(C *psrc)
{
if (psrc) psrc->AddRef();
if (pObject) pObject->Release();
pObject = psrc;
return *this;
}
OVR_FORCE_INLINE Ptr<C>& SetPtr(C &src)
{
if (pObject) pObject->Release();
pObject = &src;
return *this;
}
OVR_FORCE_INLINE Ptr<C>& SetPtr(Pickable<C> src)
{
return Pick(src);
}
// Nulls ref-counted pointer without decrement
OVR_FORCE_INLINE void NullWithoutRelease()
{
pObject = 0;
}
// Clears the pointer to the object
OVR_FORCE_INLINE void Clear()
{
if (pObject) pObject->Release();
pObject = 0;
}
// Obtain pointer reference directly, for D3D interfaces
OVR_FORCE_INLINE C*& GetRawRef() { return pObject; }
// Access Operators
OVR_FORCE_INLINE C* GetPtr() const { return pObject; }
OVR_FORCE_INLINE C& operator * () const { return *pObject; }
OVR_FORCE_INLINE C* operator -> () const { return pObject; }
// Conversion
OVR_FORCE_INLINE operator C* () const { return pObject; }
// Pickers.
// Pick a value.
OVR_FORCE_INLINE Ptr<C>& Pick(Ptr<C>& other)
{
if (&other != this)
{
if (pObject) pObject->Release();
pObject = other.pObject;
other.pObject = 0;
}
return *this;
}
OVR_FORCE_INLINE Ptr<C>& Pick(Pickable<C> v)
{
if (v.GetPtr() != pObject)
{
if (pObject) pObject->Release();
pObject = v.GetPtr();
}
return *this;
}
template<class R>
OVR_FORCE_INLINE Ptr<C>& Pick(Pickable<R> v)
{
if (v.GetPtr() != pObject)
{
if (pObject) pObject->Release();
pObject = v.GetPtr();
}
return *this;
}
OVR_FORCE_INLINE Ptr<C>& Pick(C* p)
{
if (p != pObject)
{
if (pObject) pObject->Release();
pObject = p;
}
return *this;
}
};
} // OVR
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,514 @@
/************************************************************************************
PublicHeader: OVR.h
Filename : OVR_Std.h
Content : Standard C function interface
Created : September 19, 2012
Notes :
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_Std_h
#define OVR_Std_h
#include "OVR_Types.h"
#include <stdarg.h> // for va_list args
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#if !defined(OVR_OS_WINCE) && defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400)
#define OVR_MSVC_SAFESTRING
#include <errno.h>
#endif
// Wide-char funcs
#include <wchar.h>
#include <wctype.h>
namespace OVR {
#if defined(OVR_OS_WIN32)
inline char* OVR_CDECL OVR_itoa(int val, char *dest, UPInt destsize, int radix)
{
#if defined(OVR_MSVC_SAFESTRING)
_itoa_s(val, dest, destsize, radix);
return dest;
#else
OVR_UNUSED(destsize);
return itoa(val, dest, radix);
#endif
}
#else // OVR_OS_WIN32
inline char* OVR_itoa(int val, char* dest, unsigned int len, int radix)
{
if (val == 0)
{
if (len > 1)
{
dest[0] = '0';
dest[1] = '\0';
}
return dest;
}
int cur = val;
unsigned int i = 0;
unsigned int sign = 0;
if (val < 0)
{
val = -val;
sign = 1;
}
while ((val != 0) && (i < (len - 1 - sign)))
{
cur = val % radix;
val /= radix;
if (radix == 16)
{
switch(cur)
{
case 10:
dest[i] = 'a';
break;
case 11:
dest[i] = 'b';
break;
case 12:
dest[i] = 'c';
break;
case 13:
dest[i] = 'd';
break;
case 14:
dest[i] = 'e';
break;
case 15:
dest[i] = 'f';
break;
default:
dest[i] = (char)('0' + cur);
break;
}
}
else
{
dest[i] = (char)('0' + cur);
}
++i;
}
if (sign)
{
dest[i++] = '-';
}
for (unsigned int j = 0; j < i / 2; ++j)
{
char tmp = dest[j];
dest[j] = dest[i - 1 - j];
dest[i - 1 - j] = tmp;
}
dest[i] = '\0';
return dest;
}
#endif
// String functions
inline UPInt OVR_CDECL OVR_strlen(const char* str)
{
return strlen(str);
}
inline char* OVR_CDECL OVR_strcpy(char* dest, UPInt destsize, const char* src)
{
#if defined(OVR_MSVC_SAFESTRING)
strcpy_s(dest, destsize, src);
return dest;
#else
OVR_UNUSED(destsize);
return strcpy(dest, src);
#endif
}
inline char* OVR_CDECL OVR_strncpy(char* dest, UPInt destsize, const char* src, UPInt count)
{
#if defined(OVR_MSVC_SAFESTRING)
strncpy_s(dest, destsize, src, count);
return dest;
#else
OVR_UNUSED(destsize);
return strncpy(dest, src, count);
#endif
}
inline char * OVR_CDECL OVR_strcat(char* dest, UPInt destsize, const char* src)
{
#if defined(OVR_MSVC_SAFESTRING)
strcat_s(dest, destsize, src);
return dest;
#else
OVR_UNUSED(destsize);
return strcat(dest, src);
#endif
}
inline int OVR_CDECL OVR_strcmp(const char* dest, const char* src)
{
return strcmp(dest, src);
}
inline const char* OVR_CDECL OVR_strchr(const char* str, char c)
{
return strchr(str, c);
}
inline char* OVR_CDECL OVR_strchr(char* str, char c)
{
return strchr(str, c);
}
inline const char* OVR_strrchr(const char* str, char c)
{
UPInt len = OVR_strlen(str);
for (UPInt i=len; i>0; i--)
if (str[i]==c)
return str+i;
return 0;
}
inline const UByte* OVR_CDECL OVR_memrchr(const UByte* str, UPInt size, UByte c)
{
for (SPInt i = (SPInt)size - 1; i >= 0; i--)
{
if (str[i] == c)
return str + i;
}
return 0;
}
inline char* OVR_CDECL OVR_strrchr(char* str, char c)
{
UPInt len = OVR_strlen(str);
for (UPInt i=len; i>0; i--)
if (str[i]==c)
return str+i;
return 0;
}
double OVR_CDECL OVR_strtod(const char* string, char** tailptr);
inline long OVR_CDECL OVR_strtol(const char* string, char** tailptr, int radix)
{
return strtol(string, tailptr, radix);
}
inline long OVR_CDECL OVR_strtoul(const char* string, char** tailptr, int radix)
{
return strtoul(string, tailptr, radix);
}
inline int OVR_CDECL OVR_strncmp(const char* ws1, const char* ws2, UPInt size)
{
return strncmp(ws1, ws2, size);
}
inline UInt64 OVR_CDECL OVR_strtouq(const char *nptr, char **endptr, int base)
{
#if defined(OVR_CC_MSVC) && !defined(OVR_OS_WINCE)
return _strtoui64(nptr, endptr, base);
#else
return strtoull(nptr, endptr, base);
#endif
}
inline SInt64 OVR_CDECL OVR_strtoq(const char *nptr, char **endptr, int base)
{
#if defined(OVR_CC_MSVC) && !defined(OVR_OS_WINCE)
return _strtoi64(nptr, endptr, base);
#else
return strtoll(nptr, endptr, base);
#endif
}
inline SInt64 OVR_CDECL OVR_atoq(const char* string)
{
#if defined(OVR_CC_MSVC) && !defined(OVR_OS_WINCE)
return _atoi64(string);
#else
return atoll(string);
#endif
}
inline UInt64 OVR_CDECL OVR_atouq(const char* string)
{
return OVR_strtouq(string, NULL, 10);
}
// Implemented in GStd.cpp in platform-specific manner.
int OVR_CDECL OVR_stricmp(const char* dest, const char* src);
int OVR_CDECL OVR_strnicmp(const char* dest, const char* src, UPInt count);
inline UPInt OVR_CDECL OVR_sprintf(char *dest, UPInt destsize, const char* format, ...)
{
va_list argList;
va_start(argList,format);
UPInt ret;
#if defined(OVR_CC_MSVC)
#if defined(OVR_MSVC_SAFESTRING)
ret = _vsnprintf_s(dest, destsize, _TRUNCATE, format, argList);
OVR_ASSERT(ret != -1);
#else
OVR_UNUSED(destsize);
ret = _vsnprintf(dest, destsize - 1, format, argList); // -1 for space for the null character
OVR_ASSERT(ret != -1);
dest[destsize-1] = 0;
#endif
#else
OVR_UNUSED(destsize);
ret = vsprintf(dest, format, argList);
OVR_ASSERT(ret < destsize);
#endif
va_end(argList);
return ret;
}
inline UPInt OVR_CDECL OVR_vsprintf(char *dest, UPInt destsize, const char * format, va_list argList)
{
UPInt ret;
#if defined(OVR_CC_MSVC)
#if defined(OVR_MSVC_SAFESTRING)
dest[0] = '\0';
int rv = vsnprintf_s(dest, destsize, _TRUNCATE, format, argList);
if (rv == -1)
{
dest[destsize - 1] = '\0';
ret = destsize - 1;
}
else
ret = (UPInt)rv;
#else
OVR_UNUSED(destsize);
int rv = _vsnprintf(dest, destsize - 1, format, argList);
OVR_ASSERT(rv != -1);
ret = (UPInt)rv;
dest[destsize-1] = 0;
#endif
#else
OVR_UNUSED(destsize);
ret = (UPInt)vsprintf(dest, format, argList);
OVR_ASSERT(ret < destsize);
#endif
return ret;
}
// Returns the number of characters in the formatted string.
inline UPInt OVR_CDECL OVR_vscprintf(const char * format, va_list argList)
{
UPInt ret;
#if defined(OVR_CC_MSVC)
ret = (UPInt) _vscprintf(format, argList);
#else
ret = (UPInt) vsnprintf(NULL, 0, format, argList);
#endif
return ret;
}
wchar_t* OVR_CDECL OVR_wcscpy(wchar_t* dest, UPInt destsize, const wchar_t* src);
wchar_t* OVR_CDECL OVR_wcsncpy(wchar_t* dest, UPInt destsize, const wchar_t* src, UPInt count);
wchar_t* OVR_CDECL OVR_wcscat(wchar_t* dest, UPInt destsize, const wchar_t* src);
UPInt OVR_CDECL OVR_wcslen(const wchar_t* str);
int OVR_CDECL OVR_wcscmp(const wchar_t* a, const wchar_t* b);
int OVR_CDECL OVR_wcsicmp(const wchar_t* a, const wchar_t* b);
inline int OVR_CDECL OVR_wcsicoll(const wchar_t* a, const wchar_t* b)
{
#if defined(OVR_OS_WIN32)
#if defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400)
return ::_wcsicoll(a, b);
#else
return ::wcsicoll(a, b);
#endif
#else
// not supported, use regular wcsicmp
return OVR_wcsicmp(a, b);
#endif
}
inline int OVR_CDECL OVR_wcscoll(const wchar_t* a, const wchar_t* b)
{
#if defined(OVR_OS_WIN32) || defined(OVR_OS_LINUX)
return wcscoll(a, b);
#else
// not supported, use regular wcscmp
return OVR_wcscmp(a, b);
#endif
}
#ifndef OVR_NO_WCTYPE
inline int OVR_CDECL UnicodeCharIs(const UInt16* table, wchar_t charCode)
{
unsigned offset = table[charCode >> 8];
if (offset == 0) return 0;
if (offset == 1) return 1;
return (table[offset + ((charCode >> 4) & 15)] & (1 << (charCode & 15))) != 0;
}
extern const UInt16 UnicodeAlnumBits[];
extern const UInt16 UnicodeAlphaBits[];
extern const UInt16 UnicodeDigitBits[];
extern const UInt16 UnicodeSpaceBits[];
extern const UInt16 UnicodeXDigitBits[];
// Uncomment if necessary
//extern const UInt16 UnicodeCntrlBits[];
//extern const UInt16 UnicodeGraphBits[];
//extern const UInt16 UnicodeLowerBits[];
//extern const UInt16 UnicodePrintBits[];
//extern const UInt16 UnicodePunctBits[];
//extern const UInt16 UnicodeUpperBits[];
inline int OVR_CDECL OVR_iswalnum (wchar_t charCode) { return UnicodeCharIs(UnicodeAlnumBits, charCode); }
inline int OVR_CDECL OVR_iswalpha (wchar_t charCode) { return UnicodeCharIs(UnicodeAlphaBits, charCode); }
inline int OVR_CDECL OVR_iswdigit (wchar_t charCode) { return UnicodeCharIs(UnicodeDigitBits, charCode); }
inline int OVR_CDECL OVR_iswspace (wchar_t charCode) { return UnicodeCharIs(UnicodeSpaceBits, charCode); }
inline int OVR_CDECL OVR_iswxdigit(wchar_t charCode) { return UnicodeCharIs(UnicodeXDigitBits, charCode); }
// Uncomment if necessary
//inline int OVR_CDECL OVR_iswcntrl (wchar_t charCode) { return UnicodeCharIs(UnicodeCntrlBits, charCode); }
//inline int OVR_CDECL OVR_iswgraph (wchar_t charCode) { return UnicodeCharIs(UnicodeGraphBits, charCode); }
//inline int OVR_CDECL OVR_iswlower (wchar_t charCode) { return UnicodeCharIs(UnicodeLowerBits, charCode); }
//inline int OVR_CDECL OVR_iswprint (wchar_t charCode) { return UnicodeCharIs(UnicodePrintBits, charCode); }
//inline int OVR_CDECL OVR_iswpunct (wchar_t charCode) { return UnicodeCharIs(UnicodePunctBits, charCode); }
//inline int OVR_CDECL OVR_iswupper (wchar_t charCode) { return UnicodeCharIs(UnicodeUpperBits, charCode); }
int OVR_CDECL OVR_towupper(wchar_t charCode);
int OVR_CDECL OVR_towlower(wchar_t charCode);
#else // OVR_NO_WCTYPE
inline int OVR_CDECL OVR_iswspace(wchar_t c)
{
return iswspace(c);
}
inline int OVR_CDECL OVR_iswdigit(wchar_t c)
{
return iswdigit(c);
}
inline int OVR_CDECL OVR_iswxdigit(wchar_t c)
{
return iswxdigit(c);
}
inline int OVR_CDECL OVR_iswalpha(wchar_t c)
{
return iswalpha(c);
}
inline int OVR_CDECL OVR_iswalnum(wchar_t c)
{
return iswalnum(c);
}
inline wchar_t OVR_CDECL OVR_towlower(wchar_t c)
{
return (wchar_t)towlower(c);
}
inline wchar_t OVR_towupper(wchar_t c)
{
return (wchar_t)towupper(c);
}
#endif // OVR_NO_WCTYPE
// ASCII versions of tolower and toupper. Don't use "char"
inline int OVR_CDECL OVR_tolower(int c)
{
return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c;
}
inline int OVR_CDECL OVR_toupper(int c)
{
return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c;
}
inline double OVR_CDECL OVR_wcstod(const wchar_t* string, wchar_t** tailptr)
{
#if defined(OVR_OS_OTHER)
OVR_UNUSED(tailptr);
char buffer[64];
char* tp = NULL;
UPInt max = OVR_wcslen(string);
if (max > 63) max = 63;
unsigned char c = 0;
for (UPInt i=0; i < max; i++)
{
c = (unsigned char)string[i];
buffer[i] = ((c) < 128 ? (char)c : '!');
}
buffer[max] = 0;
return OVR_strtod(buffer, &tp);
#else
return wcstod(string, tailptr);
#endif
}
inline long OVR_CDECL OVR_wcstol(const wchar_t* string, wchar_t** tailptr, int radix)
{
#if defined(OVR_OS_OTHER)
OVR_UNUSED(tailptr);
char buffer[64];
char* tp = NULL;
UPInt max = OVR_wcslen(string);
if (max > 63) max = 63;
unsigned char c = 0;
for (UPInt i=0; i < max; i++)
{
c = (unsigned char)string[i];
buffer[i] = ((c) < 128 ? (char)c : '!');
}
buffer[max] = 0;
return strtol(buffer, &tp, radix);
#else
return wcstol(string, tailptr, radix);
#endif
}
} // OVR
#endif // OVR_Std_h

View File

@ -0,0 +1,768 @@
/************************************************************************************
Filename : OVR_String.cpp
Content : String UTF8 string implementation with copy-on-write semantics
(thread-safe for assignment but not modification).
Created : September 19, 2012
Notes :
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_String.h"
#include <stdlib.h>
#include <ctype.h>
#ifdef OVR_OS_QNX
# include <strings.h>
#endif
namespace OVR {
#define String_LengthIsSize (UPInt(1) << String::Flag_LengthIsSizeShift)
String::DataDesc String::NullData = {String_LengthIsSize, 1, {0} };
String::String()
{
pData = &NullData;
pData->AddRef();
};
String::String(const char* pdata)
{
// Obtain length in bytes; it doesn't matter if _data is UTF8.
UPInt size = pdata ? OVR_strlen(pdata) : 0;
pData = AllocDataCopy1(size, 0, pdata, size);
};
String::String(const char* pdata1, const char* pdata2, const char* pdata3)
{
// Obtain length in bytes; it doesn't matter if _data is UTF8.
UPInt size1 = pdata1 ? OVR_strlen(pdata1) : 0;
UPInt size2 = pdata2 ? OVR_strlen(pdata2) : 0;
UPInt size3 = pdata3 ? OVR_strlen(pdata3) : 0;
DataDesc *pdataDesc = AllocDataCopy2(size1 + size2 + size3, 0,
pdata1, size1, pdata2, size2);
memcpy(pdataDesc->Data + size1 + size2, pdata3, size3);
pData = pdataDesc;
}
String::String(const char* pdata, UPInt size)
{
OVR_ASSERT((size == 0) || (pdata != 0));
pData = AllocDataCopy1(size, 0, pdata, size);
};
String::String(const InitStruct& src, UPInt size)
{
pData = AllocData(size, 0);
src.InitString(GetData()->Data, size);
}
String::String(const String& src)
{
pData = src.GetData();
pData->AddRef();
}
String::String(const StringBuffer& src)
{
pData = AllocDataCopy1(src.GetSize(), 0, src.ToCStr(), src.GetSize());
}
String::String(const wchar_t* data)
{
pData = &NullData;
pData->AddRef();
// Simplified logic for wchar_t constructor.
if (data)
*this = data;
}
String::DataDesc* String::AllocData(UPInt size, UPInt lengthIsSize)
{
String::DataDesc* pdesc;
if (size == 0)
{
pdesc = &NullData;
pdesc->AddRef();
return pdesc;
}
pdesc = (DataDesc*)OVR_ALLOC(sizeof(DataDesc)+ size);
pdesc->Data[size] = 0;
pdesc->RefCount = 1;
pdesc->Size = size | lengthIsSize;
return pdesc;
}
String::DataDesc* String::AllocDataCopy1(UPInt size, UPInt lengthIsSize,
const char* pdata, UPInt copySize)
{
String::DataDesc* pdesc = AllocData(size, lengthIsSize);
memcpy(pdesc->Data, pdata, copySize);
return pdesc;
}
String::DataDesc* String::AllocDataCopy2(UPInt size, UPInt lengthIsSize,
const char* pdata1, UPInt copySize1,
const char* pdata2, UPInt copySize2)
{
String::DataDesc* pdesc = AllocData(size, lengthIsSize);
memcpy(pdesc->Data, pdata1, copySize1);
memcpy(pdesc->Data + copySize1, pdata2, copySize2);
return pdesc;
}
UPInt String::GetLength() const
{
// Optimize length accesses for non-UTF8 character strings.
DataDesc* pdata = GetData();
UPInt length, size = pdata->GetSize();
if (pdata->LengthIsSize())
return size;
length = (UPInt)UTF8Util::GetLength(pdata->Data, (UPInt)size);
if (length == size)
pdata->Size |= String_LengthIsSize;
return length;
}
//static UInt32 String_CharSearch(const char* buf, )
UInt32 String::GetCharAt(UPInt index) const
{
SPInt i = (SPInt) index;
DataDesc* pdata = GetData();
const char* buf = pdata->Data;
UInt32 c;
if (pdata->LengthIsSize())
{
OVR_ASSERT(index < pdata->GetSize());
buf += i;
return UTF8Util::DecodeNextChar_Advance0(&buf);
}
c = UTF8Util::GetCharAt(index, buf, pdata->GetSize());
return c;
}
UInt32 String::GetFirstCharAt(UPInt index, const char** offset) const
{
DataDesc* pdata = GetData();
SPInt i = (SPInt) index;
const char* buf = pdata->Data;
const char* end = buf + pdata->GetSize();
UInt32 c;
do
{
c = UTF8Util::DecodeNextChar_Advance0(&buf);
i--;
if (buf >= end)
{
// We've hit the end of the string; don't go further.
OVR_ASSERT(i == 0);
return c;
}
} while (i >= 0);
*offset = buf;
return c;
}
UInt32 String::GetNextChar(const char** offset) const
{
return UTF8Util::DecodeNextChar(offset);
}
void String::AppendChar(UInt32 ch)
{
DataDesc* pdata = GetData();
UPInt size = pdata->GetSize();
char buff[8];
SPInt encodeSize = 0;
// Converts ch into UTF8 string and fills it into buff.
UTF8Util::EncodeChar(buff, &encodeSize, ch);
OVR_ASSERT(encodeSize >= 0);
SetData(AllocDataCopy2(size + (UPInt)encodeSize, 0,
pdata->Data, size, buff, (UPInt)encodeSize));
pdata->Release();
}
void String::AppendString(const wchar_t* pstr, SPInt len)
{
if (!pstr)
return;
DataDesc* pdata = GetData();
UPInt oldSize = pdata->GetSize();
UPInt encodeSize = (UPInt)UTF8Util::GetEncodeStringSize(pstr, len);
DataDesc* pnewData = AllocDataCopy1(oldSize + (UPInt)encodeSize, 0,
pdata->Data, oldSize);
UTF8Util::EncodeString(pnewData->Data + oldSize, pstr, len);
SetData(pnewData);
pdata->Release();
}
void String::AppendString(const char* putf8str, SPInt utf8StrSz)
{
if (!putf8str || !utf8StrSz)
return;
if (utf8StrSz == -1)
utf8StrSz = (SPInt)OVR_strlen(putf8str);
DataDesc* pdata = GetData();
UPInt oldSize = pdata->GetSize();
SetData(AllocDataCopy2(oldSize + (UPInt)utf8StrSz, 0,
pdata->Data, oldSize, putf8str, (UPInt)utf8StrSz));
pdata->Release();
}
void String::AssignString(const InitStruct& src, UPInt size)
{
DataDesc* poldData = GetData();
DataDesc* pnewData = AllocData(size, 0);
src.InitString(pnewData->Data, size);
SetData(pnewData);
poldData->Release();
}
void String::AssignString(const char* putf8str, UPInt size)
{
DataDesc* poldData = GetData();
SetData(AllocDataCopy1(size, 0, putf8str, size));
poldData->Release();
}
void String::operator = (const char* pstr)
{
AssignString(pstr, pstr ? OVR_strlen(pstr) : 0);
}
void String::operator = (const wchar_t* pwstr)
{
DataDesc* poldData = GetData();
UPInt size = pwstr ? (UPInt)UTF8Util::GetEncodeStringSize(pwstr) : 0;
DataDesc* pnewData = AllocData(size, 0);
UTF8Util::EncodeString(pnewData->Data, pwstr);
SetData(pnewData);
poldData->Release();
}
void String::operator = (const String& src)
{
DataDesc* psdata = src.GetData();
DataDesc* pdata = GetData();
SetData(psdata);
psdata->AddRef();
pdata->Release();
}
void String::operator = (const StringBuffer& src)
{
DataDesc* polddata = GetData();
SetData(AllocDataCopy1(src.GetSize(), 0, src.ToCStr(), src.GetSize()));
polddata->Release();
}
void String::operator += (const String& src)
{
DataDesc *pourData = GetData(),
*psrcData = src.GetData();
UPInt ourSize = pourData->GetSize(),
srcSize = psrcData->GetSize();
UPInt lflag = pourData->GetLengthFlag() & psrcData->GetLengthFlag();
SetData(AllocDataCopy2(ourSize + srcSize, lflag,
pourData->Data, ourSize, psrcData->Data, srcSize));
pourData->Release();
}
String String::operator + (const char* str) const
{
String tmp1(*this);
tmp1 += (str ? str : "");
return tmp1;
}
String String::operator + (const String& src) const
{
String tmp1(*this);
tmp1 += src;
return tmp1;
}
void String::Remove(UPInt posAt, SPInt removeLength)
{
DataDesc* pdata = GetData();
UPInt oldSize = pdata->GetSize();
// Length indicates the number of characters to remove.
UPInt length = GetLength();
// If index is past the string, nothing to remove.
if (posAt >= length)
return;
// Otherwise, cap removeLength to the length of the string.
if ((posAt + removeLength) > length)
removeLength = length - posAt;
// Get the byte position of the UTF8 char at position posAt.
SPInt bytePos = UTF8Util::GetByteIndex(posAt, pdata->Data, oldSize);
SPInt removeSize = UTF8Util::GetByteIndex(removeLength, pdata->Data + bytePos, oldSize-bytePos);
SetData(AllocDataCopy2(oldSize - removeSize, pdata->GetLengthFlag(),
pdata->Data, bytePos,
pData->Data + bytePos + removeSize, (oldSize - bytePos - removeSize)));
pdata->Release();
}
String String::Substring(UPInt start, UPInt end) const
{
UPInt length = GetLength();
if ((start >= length) || (start >= end))
return String();
DataDesc* pdata = GetData();
// If size matches, we know the exact index range.
if (pdata->LengthIsSize())
return String(pdata->Data + start, end - start);
// Get position of starting character.
SPInt byteStart = UTF8Util::GetByteIndex(start, pdata->Data, pdata->GetSize());
SPInt byteSize = UTF8Util::GetByteIndex(end - start, pdata->Data + byteStart, pdata->GetSize()-byteStart);
return String(pdata->Data + byteStart, (UPInt)byteSize);
}
void String::Clear()
{
NullData.AddRef();
GetData()->Release();
SetData(&NullData);
}
String String::ToUpper() const
{
UInt32 c;
const char* psource = GetData()->Data;
const char* pend = psource + GetData()->GetSize();
String str;
SPInt bufferOffset = 0;
char buffer[512];
while(psource < pend)
{
do {
c = UTF8Util::DecodeNextChar_Advance0(&psource);
UTF8Util::EncodeChar(buffer, &bufferOffset, OVR_towupper(wchar_t(c)));
} while ((psource < pend) && (bufferOffset < SPInt(sizeof(buffer)-8)));
// Append string a piece at a time.
str.AppendString(buffer, bufferOffset);
bufferOffset = 0;
}
return str;
}
String String::ToLower() const
{
UInt32 c;
const char* psource = GetData()->Data;
const char* pend = psource + GetData()->GetSize();
String str;
SPInt bufferOffset = 0;
char buffer[512];
while(psource < pend)
{
do {
c = UTF8Util::DecodeNextChar_Advance0(&psource);
UTF8Util::EncodeChar(buffer, &bufferOffset, OVR_towlower(wchar_t(c)));
} while ((psource < pend) && (bufferOffset < SPInt(sizeof(buffer)-8)));
// Append string a piece at a time.
str.AppendString(buffer, bufferOffset);
bufferOffset = 0;
}
return str;
}
String& String::Insert(const char* substr, UPInt posAt, SPInt strSize)
{
DataDesc* poldData = GetData();
UPInt oldSize = poldData->GetSize();
UPInt insertSize = (strSize < 0) ? OVR_strlen(substr) : (UPInt)strSize;
UPInt byteIndex = (poldData->LengthIsSize()) ?
posAt : (UPInt)UTF8Util::GetByteIndex(posAt, poldData->Data, oldSize);
OVR_ASSERT(byteIndex <= oldSize);
DataDesc* pnewData = AllocDataCopy2(oldSize + insertSize, 0,
poldData->Data, byteIndex, substr, insertSize);
memcpy(pnewData->Data + byteIndex + insertSize,
poldData->Data + byteIndex, oldSize - byteIndex);
SetData(pnewData);
poldData->Release();
return *this;
}
/*
String& String::Insert(const UInt32* substr, UPInt posAt, SPInt len)
{
for (SPInt i = 0; i < len; ++i)
{
UPInt charw = InsertCharAt(substr[i], posAt);
posAt += charw;
}
return *this;
}
*/
UPInt String::InsertCharAt(UInt32 c, UPInt posAt)
{
char buf[8];
SPInt index = 0;
UTF8Util::EncodeChar(buf, &index, c);
OVR_ASSERT(index >= 0);
buf[(UPInt)index] = 0;
Insert(buf, posAt, index);
return (UPInt)index;
}
int String::CompareNoCase(const char* a, const char* b)
{
return OVR_stricmp(a, b);
}
int String::CompareNoCase(const char* a, const char* b, SPInt len)
{
if (len)
{
SPInt f,l;
SPInt slen = len;
const char *s = b;
do {
f = (SPInt)OVR_tolower((int)(*(a++)));
l = (SPInt)OVR_tolower((int)(*(b++)));
} while (--len && f && (f == l) && *b != 0);
if (f == l && (len != 0 || *b != 0))
{
f = (SPInt)slen;
l = (SPInt)OVR_strlen(s);
return int(f - l);
}
return int(f - l);
}
else
return (0-(int)OVR_strlen(b));
}
// ***** Implement hash static functions
// Hash function
UPInt String::BernsteinHashFunction(const void* pdataIn, UPInt size, UPInt seed)
{
const UByte* pdata = (const UByte*) pdataIn;
UPInt h = seed;
while (size > 0)
{
size--;
h = ((h << 5) + h) ^ (unsigned) pdata[size];
}
return h;
}
// Hash function, case-insensitive
UPInt String::BernsteinHashFunctionCIS(const void* pdataIn, UPInt size, UPInt seed)
{
const UByte* pdata = (const UByte*) pdataIn;
UPInt h = seed;
while (size > 0)
{
size--;
h = ((h << 5) + h) ^ OVR_tolower(pdata[size]);
}
// Alternative: "sdbm" hash function, suggested at same web page above.
// h = 0;
// for bytes { h = (h << 16) + (h << 6) - hash + *p; }
return h;
}
// ***** String Buffer used for Building Strings
#define OVR_SBUFF_DEFAULT_GROW_SIZE 512
// Constructors / Destructor.
StringBuffer::StringBuffer()
: pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
{
}
StringBuffer::StringBuffer(UPInt growSize)
: pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
{
SetGrowSize(growSize);
}
StringBuffer::StringBuffer(const char* data)
: pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
{
AppendString(data);
}
StringBuffer::StringBuffer(const char* data, UPInt dataSize)
: pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
{
AppendString(data, dataSize);
}
StringBuffer::StringBuffer(const String& src)
: pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
{
AppendString(src.ToCStr(), src.GetSize());
}
StringBuffer::StringBuffer(const StringBuffer& src)
: pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
{
AppendString(src.ToCStr(), src.GetSize());
}
StringBuffer::StringBuffer(const wchar_t* data)
: pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
{
*this = data;
}
StringBuffer::~StringBuffer()
{
if (pData)
OVR_FREE(pData);
}
void StringBuffer::SetGrowSize(UPInt growSize)
{
if (growSize <= 16)
GrowSize = 16;
else
{
UByte bits = Alg::UpperBit(UInt32(growSize-1));
UPInt size = 1<<bits;
GrowSize = size == growSize ? growSize : size;
}
}
UPInt StringBuffer::GetLength() const
{
UPInt length, size = GetSize();
if (LengthIsSize)
return size;
length = (UPInt)UTF8Util::GetLength(pData, (UPInt)GetSize());
if (length == GetSize())
LengthIsSize = true;
return length;
}
void StringBuffer::Reserve(UPInt _size)
{
if (_size >= BufferSize) // >= because of trailing zero! (!AB)
{
BufferSize = (_size + 1 + GrowSize - 1)& ~(GrowSize-1);
if (!pData)
pData = (char*)OVR_ALLOC(BufferSize);
else
pData = (char*)OVR_REALLOC(pData, BufferSize);
}
}
void StringBuffer::Resize(UPInt _size)
{
Reserve(_size);
LengthIsSize = false;
Size = _size;
if (pData)
pData[Size] = 0;
}
void StringBuffer::Clear()
{
Resize(0);
/*
if (pData != pEmptyNullData)
{
OVR_FREE(pHeap, pData);
pData = pEmptyNullData;
Size = BufferSize = 0;
LengthIsSize = false;
}
*/
}
// Appends a character
void StringBuffer::AppendChar(UInt32 ch)
{
char buff[8];
UPInt origSize = GetSize();
// Converts ch into UTF8 string and fills it into buff. Also increments index according to the number of bytes
// in the UTF8 string.
SPInt srcSize = 0;
UTF8Util::EncodeChar(buff, &srcSize, ch);
OVR_ASSERT(srcSize >= 0);
UPInt size = origSize + srcSize;
Resize(size);
memcpy(pData + origSize, buff, srcSize);
}
// Append a string
void StringBuffer::AppendString(const wchar_t* pstr, SPInt len)
{
if (!pstr)
return;
SPInt srcSize = UTF8Util::GetEncodeStringSize(pstr, len);
UPInt origSize = GetSize();
UPInt size = srcSize + origSize;
Resize(size);
UTF8Util::EncodeString(pData + origSize, pstr, len);
}
void StringBuffer::AppendString(const char* putf8str, SPInt utf8StrSz)
{
if (!putf8str || !utf8StrSz)
return;
if (utf8StrSz == -1)
utf8StrSz = (SPInt)OVR_strlen(putf8str);
UPInt origSize = GetSize();
UPInt size = utf8StrSz + origSize;
Resize(size);
memcpy(pData + origSize, putf8str, utf8StrSz);
}
void StringBuffer::operator = (const char* pstr)
{
pstr = pstr ? pstr : "";
UPInt size = OVR_strlen(pstr);
Resize(size);
memcpy(pData, pstr, size);
}
void StringBuffer::operator = (const wchar_t* pstr)
{
pstr = pstr ? pstr : L"";
UPInt size = (UPInt)UTF8Util::GetEncodeStringSize(pstr);
Resize(size);
UTF8Util::EncodeString(pData, pstr);
}
void StringBuffer::operator = (const String& src)
{
Resize(src.GetSize());
memcpy(pData, src.ToCStr(), src.GetSize());
}
void StringBuffer::operator = (const StringBuffer& src)
{
Clear();
AppendString(src.ToCStr(), src.GetSize());
}
// Inserts substr at posAt
void StringBuffer::Insert(const char* substr, UPInt posAt, SPInt len)
{
UPInt oldSize = Size;
UPInt insertSize = (len < 0) ? OVR_strlen(substr) : (UPInt)len;
UPInt byteIndex = LengthIsSize ? posAt :
(UPInt)UTF8Util::GetByteIndex(posAt, pData, (SPInt)Size);
OVR_ASSERT(byteIndex <= oldSize);
Reserve(oldSize + insertSize);
memmove(pData + byteIndex + insertSize, pData + byteIndex, oldSize - byteIndex + 1);
memcpy (pData + byteIndex, substr, insertSize);
LengthIsSize = false;
Size = oldSize + insertSize;
pData[Size] = 0;
}
// Inserts character at posAt
UPInt StringBuffer::InsertCharAt(UInt32 c, UPInt posAt)
{
char buf[8];
SPInt len = 0;
UTF8Util::EncodeChar(buf, &len, c);
OVR_ASSERT(len >= 0);
buf[(UPInt)len] = 0;
Insert(buf, posAt, len);
return (UPInt)len;
}
} // OVR

View File

@ -0,0 +1,657 @@
/************************************************************************************
PublicHeader: OVR.h
Filename : OVR_String.h
Content : String UTF8 string implementation with copy-on-write semantics
(thread-safe for assignment but not modification).
Created : September 19, 2012
Notes :
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_String_h
#define OVR_String_h
#include "OVR_Types.h"
#include "OVR_Allocator.h"
#include "OVR_UTF8Util.h"
#include "OVR_Atomic.h"
#include "OVR_Std.h"
#include "OVR_Alg.h"
namespace OVR {
// ***** Classes
class String;
class StringBuffer;
//-----------------------------------------------------------------------------------
// ***** String Class
// String is UTF8 based string class with copy-on-write implementation
// for assignment.
class String
{
protected:
enum FlagConstants
{
//Flag_GetLength = 0x7FFFFFFF,
// This flag is set if GetLength() == GetSize() for a string.
// Avoid extra scanning is Substring and indexing logic.
Flag_LengthIsSizeShift = (sizeof(UPInt)*8 - 1)
};
// Internal structure to hold string data
struct DataDesc
{
// Number of bytes. Will be the same as the number of chars if the characters
// are ascii, may not be equal to number of chars in case string data is UTF8.
UPInt Size;
volatile SInt32 RefCount;
char Data[1];
void AddRef()
{
AtomicOps<SInt32>::ExchangeAdd_NoSync(&RefCount, 1);
}
// Decrement ref count. This needs to be thread-safe, since
// a different thread could have also decremented the ref count.
// For example, if u start off with a ref count = 2. Now if u
// decrement the ref count and check against 0 in different
// statements, a different thread can also decrement the ref count
// in between our decrement and checking against 0 and will find
// the ref count = 0 and delete the object. This will lead to a crash
// when context switches to our thread and we'll be trying to delete
// an already deleted object. Hence decrementing the ref count and
// checking against 0 needs to made an atomic operation.
void Release()
{
if ((AtomicOps<SInt32>::ExchangeAdd_NoSync(&RefCount, -1) - 1) == 0)
OVR_FREE(this);
}
static UPInt GetLengthFlagBit() { return UPInt(1) << Flag_LengthIsSizeShift; }
UPInt GetSize() const { return Size & ~GetLengthFlagBit() ; }
UPInt GetLengthFlag() const { return Size & GetLengthFlagBit(); }
bool LengthIsSize() const { return GetLengthFlag() != 0; }
};
// Heap type of the string is encoded in the lower bits.
enum HeapType
{
HT_Global = 0, // Heap is global.
HT_Local = 1, // SF::String_loc: Heap is determined based on string's address.
HT_Dynamic = 2, // SF::String_temp: Heap is stored as a part of the class.
HT_Mask = 3
};
union {
DataDesc* pData;
UPInt HeapTypeBits;
};
typedef union {
DataDesc* pData;
UPInt HeapTypeBits;
} DataDescUnion;
inline HeapType GetHeapType() const { return (HeapType) (HeapTypeBits & HT_Mask); }
inline DataDesc* GetData() const
{
DataDescUnion u;
u.pData = pData;
u.HeapTypeBits = (u.HeapTypeBits & ~(UPInt)HT_Mask);
return u.pData;
}
inline void SetData(DataDesc* pdesc)
{
HeapType ht = GetHeapType();
pData = pdesc;
OVR_ASSERT((HeapTypeBits & HT_Mask) == 0);
HeapTypeBits |= ht;
}
DataDesc* AllocData(UPInt size, UPInt lengthIsSize);
DataDesc* AllocDataCopy1(UPInt size, UPInt lengthIsSize,
const char* pdata, UPInt copySize);
DataDesc* AllocDataCopy2(UPInt size, UPInt lengthIsSize,
const char* pdata1, UPInt copySize1,
const char* pdata2, UPInt copySize2);
// Special constructor to avoid data initalization when used in derived class.
struct NoConstructor { };
String(const NoConstructor&) { }
public:
// For initializing string with dynamic buffer
struct InitStruct
{
virtual ~InitStruct() { }
virtual void InitString(char* pbuffer, UPInt size) const = 0;
};
// Constructors / Destructors.
String();
String(const char* data);
String(const char* data1, const char* pdata2, const char* pdata3 = 0);
String(const char* data, UPInt buflen);
String(const String& src);
String(const StringBuffer& src);
String(const InitStruct& src, UPInt size);
explicit String(const wchar_t* data);
// Destructor (Captain Obvious guarantees!)
~String()
{
GetData()->Release();
}
// Declaration of NullString
static DataDesc NullData;
// *** General Functions
void Clear();
// For casting to a pointer to char.
operator const char*() const { return GetData()->Data; }
// Pointer to raw buffer.
const char* ToCStr() const { return GetData()->Data; }
// Returns number of bytes
UPInt GetSize() const { return GetData()->GetSize() ; }
// Tells whether or not the string is empty
bool IsEmpty() const { return GetSize() == 0; }
// Returns number of characters
UPInt GetLength() const;
// Returns character at the specified index
UInt32 GetCharAt(UPInt index) const;
UInt32 GetFirstCharAt(UPInt index, const char** offset) const;
UInt32 GetNextChar(const char** offset) const;
// Appends a character
void AppendChar(UInt32 ch);
// Append a string
void AppendString(const wchar_t* pstr, SPInt len = -1);
void AppendString(const char* putf8str, SPInt utf8StrSz = -1);
// Assigned a string with dynamic data (copied through initializer).
void AssignString(const InitStruct& src, UPInt size);
// Assigns string with known size.
void AssignString(const char* putf8str, UPInt size);
// Resize the string to the new size
// void Resize(UPInt _size);
// Removes the character at posAt
void Remove(UPInt posAt, SPInt len = 1);
// Returns a String that's a substring of this.
// -start is the index of the first UTF8 character you want to include.
// -end is the index one past the last UTF8 character you want to include.
String Substring(UPInt start, UPInt end) const;
// Case-conversion
String ToUpper() const;
String ToLower() const;
// Inserts substr at posAt
String& Insert (const char* substr, UPInt posAt, SPInt len = -1);
// Inserts character at posAt
UPInt InsertCharAt(UInt32 c, UPInt posAt);
// Inserts substr at posAt, which is an index of a character (not byte).
// Of size is specified, it is in bytes.
// String& Insert(const UInt32* substr, UPInt posAt, SPInt size = -1);
// Get Byte index of the character at position = index
UPInt GetByteIndex(UPInt index) const { return (UPInt)UTF8Util::GetByteIndex(index, GetData()->Data); }
// Utility: case-insensitive string compare. stricmp() & strnicmp() are not
// ANSI or POSIX, do not seem to appear in Linux.
static int OVR_STDCALL CompareNoCase(const char* a, const char* b);
static int OVR_STDCALL CompareNoCase(const char* a, const char* b, SPInt len);
// Hash function, case-insensitive
static UPInt OVR_STDCALL BernsteinHashFunctionCIS(const void* pdataIn, UPInt size, UPInt seed = 5381);
// Hash function, case-sensitive
static UPInt OVR_STDCALL BernsteinHashFunction(const void* pdataIn, UPInt size, UPInt seed = 5381);
// ***** File path parsing helper functions.
// Implemented in OVR_String_FilePath.cpp.
// Absolute paths can star with:
// - protocols: 'file://', 'http://'
// - windows drive: 'c:\'
// - UNC share name: '\\share'
// - unix root '/'
static bool HasAbsolutePath(const char* path);
static bool HasExtension(const char* path);
static bool HasProtocol(const char* path);
bool HasAbsolutePath() const { return HasAbsolutePath(ToCStr()); }
bool HasExtension() const { return HasExtension(ToCStr()); }
bool HasProtocol() const { return HasProtocol(ToCStr()); }
String GetProtocol() const; // Returns protocol, if any, with trailing '://'.
String GetPath() const; // Returns path with trailing '/'.
String GetFilename() const; // Returns filename, including extension.
String GetExtension() const; // Returns extension with a dot.
void StripProtocol(); // Strips front protocol, if any, from the string.
void StripExtension(); // Strips off trailing extension.
// Operators
// Assignment
void operator = (const char* str);
void operator = (const wchar_t* str);
void operator = (const String& src);
void operator = (const StringBuffer& src);
// Addition
void operator += (const String& src);
void operator += (const char* psrc) { AppendString(psrc); }
void operator += (const wchar_t* psrc) { AppendString(psrc); }
void operator += (char ch) { AppendChar(ch); }
String operator + (const char* str) const;
String operator + (const String& src) const;
// Comparison
bool operator == (const String& str) const
{
return (OVR_strcmp(GetData()->Data, str.GetData()->Data)== 0);
}
bool operator != (const String& str) const
{
return !operator == (str);
}
bool operator == (const char* str) const
{
return OVR_strcmp(GetData()->Data, str) == 0;
}
bool operator != (const char* str) const
{
return !operator == (str);
}
bool operator < (const char* pstr) const
{
return OVR_strcmp(GetData()->Data, pstr) < 0;
}
bool operator < (const String& str) const
{
return *this < str.GetData()->Data;
}
bool operator > (const char* pstr) const
{
return OVR_strcmp(GetData()->Data, pstr) > 0;
}
bool operator > (const String& str) const
{
return *this > str.GetData()->Data;
}
int CompareNoCase(const char* pstr) const
{
return CompareNoCase(GetData()->Data, pstr);
}
int CompareNoCase(const String& str) const
{
return CompareNoCase(GetData()->Data, str.ToCStr());
}
// Accesses raw bytes
const char& operator [] (int index) const
{
OVR_ASSERT(index >= 0 && (UPInt)index < GetSize());
return GetData()->Data[index];
}
const char& operator [] (UPInt index) const
{
OVR_ASSERT(index < GetSize());
return GetData()->Data[index];
}
// Case insensitive keys are used to look up insensitive string in hash tables
// for SWF files with version before SWF 7.
struct NoCaseKey
{
const String* pStr;
NoCaseKey(const String &str) : pStr(&str){};
};
bool operator == (const NoCaseKey& strKey) const
{
return (CompareNoCase(ToCStr(), strKey.pStr->ToCStr()) == 0);
}
bool operator != (const NoCaseKey& strKey) const
{
return !(CompareNoCase(ToCStr(), strKey.pStr->ToCStr()) == 0);
}
// Hash functor used for strings.
struct HashFunctor
{
UPInt operator()(const String& data) const
{
UPInt size = data.GetSize();
return String::BernsteinHashFunction((const char*)data, size);
}
};
// Case-insensitive hash functor used for strings. Supports additional
// lookup based on NoCaseKey.
struct NoCaseHashFunctor
{
UPInt operator()(const String& data) const
{
UPInt size = data.GetSize();
return String::BernsteinHashFunctionCIS((const char*)data, size);
}
UPInt operator()(const NoCaseKey& data) const
{
UPInt size = data.pStr->GetSize();
return String::BernsteinHashFunctionCIS((const char*)data.pStr->ToCStr(), size);
}
};
};
//-----------------------------------------------------------------------------------
// ***** String Buffer used for Building Strings
class StringBuffer
{
char* pData;
UPInt Size;
UPInt BufferSize;
UPInt GrowSize;
mutable bool LengthIsSize;
public:
// Constructors / Destructor.
StringBuffer();
explicit StringBuffer(UPInt growSize);
StringBuffer(const char* data);
StringBuffer(const char* data, UPInt buflen);
StringBuffer(const String& src);
StringBuffer(const StringBuffer& src);
explicit StringBuffer(const wchar_t* data);
~StringBuffer();
// Modify grow size used for growing/shrinking the buffer.
UPInt GetGrowSize() const { return GrowSize; }
void SetGrowSize(UPInt growSize);
// *** General Functions
// Does not release memory, just sets Size to 0
void Clear();
// For casting to a pointer to char.
operator const char*() const { return (pData) ? pData : ""; }
// Pointer to raw buffer.
const char* ToCStr() const { return (pData) ? pData : ""; }
// Returns number of bytes.
UPInt GetSize() const { return Size ; }
// Tells whether or not the string is empty.
bool IsEmpty() const { return GetSize() == 0; }
// Returns number of characters
UPInt GetLength() const;
// Returns character at the specified index
UInt32 GetCharAt(UPInt index) const;
UInt32 GetFirstCharAt(UPInt index, const char** offset) const;
UInt32 GetNextChar(const char** offset) const;
// Resize the string to the new size
void Resize(UPInt _size);
void Reserve(UPInt _size);
// Appends a character
void AppendChar(UInt32 ch);
// Append a string
void AppendString(const wchar_t* pstr, SPInt len = -1);
void AppendString(const char* putf8str, SPInt utf8StrSz = -1);
void AppendFormat(const char* format, ...);
// Assigned a string with dynamic data (copied through initializer).
//void AssignString(const InitStruct& src, UPInt size);
// Inserts substr at posAt
void Insert (const char* substr, UPInt posAt, SPInt len = -1);
// Inserts character at posAt
UPInt InsertCharAt(UInt32 c, UPInt posAt);
// Assignment
void operator = (const char* str);
void operator = (const wchar_t* str);
void operator = (const String& src);
void operator = (const StringBuffer& src);
// Addition
void operator += (const String& src) { AppendString(src.ToCStr(),src.GetSize()); }
void operator += (const char* psrc) { AppendString(psrc); }
void operator += (const wchar_t* psrc) { AppendString(psrc); }
void operator += (char ch) { AppendChar(ch); }
//String operator + (const char* str) const ;
//String operator + (const String& src) const ;
// Accesses raw bytes
char& operator [] (int index)
{
OVR_ASSERT(((UPInt)index) < GetSize());
return pData[index];
}
char& operator [] (UPInt index)
{
OVR_ASSERT(index < GetSize());
return pData[index];
}
const char& operator [] (int index) const
{
OVR_ASSERT(((UPInt)index) < GetSize());
return pData[index];
}
const char& operator [] (UPInt index) const
{
OVR_ASSERT(index < GetSize());
return pData[index];
}
};
//
// Wrapper for string data. The data must have a guaranteed
// lifespan throughout the usage of the wrapper. Not intended for
// cached usage. Not thread safe.
//
class StringDataPtr
{
public:
StringDataPtr() : pStr(NULL), Size(0) {}
StringDataPtr(const StringDataPtr& p)
: pStr(p.pStr), Size(p.Size) {}
StringDataPtr(const char* pstr, UPInt sz)
: pStr(pstr), Size(sz) {}
StringDataPtr(const char* pstr)
: pStr(pstr), Size((pstr != NULL) ? OVR_strlen(pstr) : 0) {}
explicit StringDataPtr(const String& str)
: pStr(str.ToCStr()), Size(str.GetSize()) {}
template <typename T, int N>
StringDataPtr(const T (&v)[N])
: pStr(v), Size(N) {}
public:
const char* ToCStr() const { return pStr; }
UPInt GetSize() const { return Size; }
bool IsEmpty() const { return GetSize() == 0; }
// value is a prefix of this string
// Character's values are not compared.
bool IsPrefix(const StringDataPtr& value) const
{
return ToCStr() == value.ToCStr() && GetSize() >= value.GetSize();
}
// value is a suffix of this string
// Character's values are not compared.
bool IsSuffix(const StringDataPtr& value) const
{
return ToCStr() <= value.ToCStr() && (End()) == (value.End());
}
// Find first character.
// init_ind - initial index.
SPInt FindChar(char c, UPInt init_ind = 0) const
{
for (UPInt i = init_ind; i < GetSize(); ++i)
if (pStr[i] == c)
return static_cast<SPInt>(i);
return -1;
}
// Find last character.
// init_ind - initial index.
SPInt FindLastChar(char c, UPInt init_ind = ~0) const
{
if (init_ind == (UPInt)~0 || init_ind > GetSize())
init_ind = GetSize();
else
++init_ind;
for (UPInt i = init_ind; i > 0; --i)
if (pStr[i - 1] == c)
return static_cast<SPInt>(i - 1);
return -1;
}
// Create new object and trim size bytes from the left.
StringDataPtr GetTrimLeft(UPInt size) const
{
// Limit trim size to the size of the string.
size = Alg::PMin(GetSize(), size);
return StringDataPtr(ToCStr() + size, GetSize() - size);
}
// Create new object and trim size bytes from the right.
StringDataPtr GetTrimRight(UPInt size) const
{
// Limit trim to the size of the string.
size = Alg::PMin(GetSize(), size);
return StringDataPtr(ToCStr(), GetSize() - size);
}
// Create new object, which contains next token.
// Useful for parsing.
StringDataPtr GetNextToken(char separator = ':') const
{
UPInt cur_pos = 0;
const char* cur_str = ToCStr();
for (; cur_pos < GetSize() && cur_str[cur_pos]; ++cur_pos)
{
if (cur_str[cur_pos] == separator)
{
break;
}
}
return StringDataPtr(ToCStr(), cur_pos);
}
// Trim size bytes from the left.
StringDataPtr& TrimLeft(UPInt size)
{
// Limit trim size to the size of the string.
size = Alg::PMin(GetSize(), size);
pStr += size;
Size -= size;
return *this;
}
// Trim size bytes from the right.
StringDataPtr& TrimRight(UPInt size)
{
// Limit trim to the size of the string.
size = Alg::PMin(GetSize(), size);
Size -= size;
return *this;
}
const char* Begin() const { return ToCStr(); }
const char* End() const { return ToCStr() + GetSize(); }
// Hash functor used string data pointers
struct HashFunctor
{
UPInt operator()(const StringDataPtr& data) const
{
return String::BernsteinHashFunction(data.ToCStr(), data.GetSize());
}
};
bool operator== (const StringDataPtr& data) const
{
return (OVR_strncmp(pStr, data.pStr, data.Size) == 0);
}
protected:
const char* pStr;
UPInt Size;
};
} // OVR
#endif

View File

@ -0,0 +1,100 @@
/************************************************************************************
PublicHeader: None
Filename : OVR_StringHash.h
Content : String hash table used when optional case-insensitive
lookup is required.
Created : September 19, 2012
Notes :
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_StringHash_h
#define OVR_StringHash_h
#include "OVR_String.h"
#include "OVR_Hash.h"
namespace OVR {
//-----------------------------------------------------------------------------------
// *** StringHash
// This is a custom string hash table that supports case-insensitive
// searches through special functions such as GetCaseInsensitive, etc.
// This class is used for Flash labels, exports and other case-insensitive tables.
template<class U, class Allocator = ContainerAllocator<U> >
class StringHash : public Hash<String, U, String::NoCaseHashFunctor, Allocator>
{
public:
typedef U ValueType;
typedef StringHash<U, Allocator> SelfType;
typedef Hash<String, U, String::NoCaseHashFunctor, Allocator> BaseType;
public:
void operator = (const SelfType& src) { BaseType::operator = (src); }
bool GetCaseInsensitive(const String& key, U* pvalue) const
{
String::NoCaseKey ikey(key);
return BaseType::GetAlt(ikey, pvalue);
}
// Pointer-returning get variety.
const U* GetCaseInsensitive(const String& key) const
{
String::NoCaseKey ikey(key);
return BaseType::GetAlt(ikey);
}
U* GetCaseInsensitive(const String& key)
{
String::NoCaseKey ikey(key);
return BaseType::GetAlt(ikey);
}
typedef typename BaseType::Iterator base_iterator;
base_iterator FindCaseInsensitive(const String& key)
{
String::NoCaseKey ikey(key);
return BaseType::FindAlt(ikey);
}
// Set just uses a find and assigns value if found. The key is not modified;
// this behavior is identical to Flash string variable assignment.
void SetCaseInsensitive(const String& key, const U& value)
{
base_iterator it = FindCaseInsensitive(key);
if (it != BaseType::End())
{
it->Second = value;
}
else
{
BaseType::Add(key, value);
}
}
};
} // OVR
#endif

View File

@ -0,0 +1,53 @@
/************************************************************************************
Filename : OVR_String_FormatUtil.cpp
Content : String format functions.
Created : February 27, 2013
Notes :
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_String.h"
#include "OVR_Log.h"
namespace OVR {
void StringBuffer::AppendFormat(const char* format, ...)
{
va_list argList;
va_start(argList, format);
UPInt size = OVR_vscprintf(format, argList);
va_end(argList);
char* buffer = (char*) OVR_ALLOC(sizeof(char) * (size+1));
va_start(argList, format);
UPInt result = OVR_vsprintf(buffer, size+1, format, argList);
OVR_UNUSED1(result);
va_end(argList);
OVR_ASSERT_LOG(result == size, ("Error in OVR_vsprintf"));
AppendString(buffer);
OVR_FREE(buffer);
}
} // OVR

View File

@ -0,0 +1,211 @@
/************************************************************************************
Filename : OVR_String_PathUtil.cpp
Content : String filename/url helper function
Created : September 19, 2012
Notes :
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_String.h"
#include "OVR_UTF8Util.h"
namespace OVR {
//--------------------------------------------------------------------
// ***** Path-Scanner helper function
// Scans file path finding filename start and extension start, fills in their addess.
void ScanFilePath(const char* url, const char** pfilename, const char** pext)
{
const char* urlStart = url;
const char *filename = 0;
const char *lastDot = 0;
UInt32 charVal = UTF8Util::DecodeNextChar(&url);
while (charVal != 0)
{
if ((charVal == '/') || (charVal == '\\'))
{
filename = url;
lastDot = 0;
}
else if (charVal == '.')
{
lastDot = url - 1;
}
charVal = UTF8Util::DecodeNextChar(&url);
}
if (pfilename)
{
// It was a naked filename
if (urlStart && (*urlStart != '.') && *urlStart)
*pfilename = urlStart;
else
*pfilename = filename;
}
if (pext)
{
*pext = lastDot;
}
}
// Scans till the end of protocol. Returns first character past protocol,
// 0 if not found.
// - protocol: 'file://', 'http://'
const char* ScanPathProtocol(const char* url)
{
UInt32 charVal = UTF8Util::DecodeNextChar(&url);
UInt32 charVal2;
while (charVal != 0)
{
// Treat a colon followed by a slash as absolute.
if (charVal == ':')
{
charVal2 = UTF8Util::DecodeNextChar(&url);
charVal = UTF8Util::DecodeNextChar(&url);
if ((charVal == '/') && (charVal2 == '\\'))
return url;
}
charVal = UTF8Util::DecodeNextChar(&url);
}
return 0;
}
//--------------------------------------------------------------------
// ***** String Path API implementation
bool String::HasAbsolutePath(const char* url)
{
// Absolute paths can star with:
// - protocols: 'file://', 'http://'
// - windows drive: 'c:\'
// - UNC share name: '\\share'
// - unix root '/'
// On the other hand, relative paths are:
// - directory: 'directory/file'
// - this directory: './file'
// - parent directory: '../file'
//
// For now, we don't parse '.' or '..' out, but instead let it be concatenated
// to string and let the OS figure it out. This, however, is not good for file
// name matching in library/etc, so it should be improved.
if (!url || !*url)
return true; // Treat empty strings as absolute.
UInt32 charVal = UTF8Util::DecodeNextChar(&url);
// Fist character of '/' or '\\' means absolute url.
if ((charVal == '/') || (charVal == '\\'))
return true;
while (charVal != 0)
{
// Treat a colon followed by a slash as absolute.
if (charVal == ':')
{
charVal = UTF8Util::DecodeNextChar(&url);
// Protocol or windows drive. Absolute.
if ((charVal == '/') || (charVal == '\\'))
return true;
}
else if ((charVal == '/') || (charVal == '\\'))
{
// Not a first character (else 'if' above the loop would have caught it).
// Must be a relative url.
break;
}
charVal = UTF8Util::DecodeNextChar(&url);
}
// We get here for relative paths.
return false;
}
bool String::HasExtension(const char* path)
{
const char* ext = 0;
ScanFilePath(path, 0, &ext);
return ext != 0;
}
bool String::HasProtocol(const char* path)
{
return ScanPathProtocol(path) != 0;
}
String String::GetPath() const
{
const char* filename = 0;
ScanFilePath(ToCStr(), &filename, 0);
// Technically we can have extra logic somewhere for paths,
// such as enforcing protocol and '/' only based on flags,
// but we keep it simple for now.
return String(ToCStr(), filename ? (filename-ToCStr()) : GetSize());
}
String String::GetProtocol() const
{
const char* protocolEnd = ScanPathProtocol(ToCStr());
return String(ToCStr(), protocolEnd ? (protocolEnd-ToCStr()) : 0);
}
String String::GetFilename() const
{
const char* filename = 0;
ScanFilePath(ToCStr(), &filename, 0);
return String(filename);
}
String String::GetExtension() const
{
const char* ext = 0;
ScanFilePath(ToCStr(), 0, &ext);
return String(ext);
}
void String::StripExtension()
{
const char* ext = 0;
ScanFilePath(ToCStr(), 0, &ext);
if (ext)
{
*this = String(ToCStr(), ext-ToCStr());
}
}
void String::StripProtocol()
{
const char* protocol = ScanPathProtocol(ToCStr());
if (protocol)
AssignString(protocol, OVR_strlen(protocol));
}
} // OVR

View File

@ -0,0 +1,138 @@
/**************************************************************************
Filename : OVR_SysFile.cpp
Content : File wrapper class implementation (Win32)
Created : April 5, 1999
Authors : Michael Antonov
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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.
**************************************************************************/
#define GFILE_CXX
// Standard C library (Captain Obvious guarantees!)
#include <stdio.h>
#include "OVR_SysFile.h"
#include "OVR_Log.h"
namespace OVR {
// This is - a dummy file that fails on all calls.
class UnopenedFile : public File
{
public:
UnopenedFile() { }
~UnopenedFile() { }
virtual const char* GetFilePath() { return 0; }
// ** File Information
virtual bool IsValid() { return 0; }
virtual bool IsWritable() { return 0; }
// Return position / file size
virtual int Tell() { return 0; }
virtual SInt64 LTell() { return 0; }
virtual int GetLength() { return 0; }
virtual SInt64 LGetLength() { return 0; }
// virtual bool Stat(FileStats *pfs) { return 0; }
virtual int GetErrorCode() { return Error_FileNotFound; }
// ** Stream implementation & I/O
virtual int Write(const UByte *pbuffer, int numBytes) { return -1; OVR_UNUSED2(pbuffer, numBytes); }
virtual int Read(UByte *pbuffer, int numBytes) { return -1; OVR_UNUSED2(pbuffer, numBytes); }
virtual int SkipBytes(int numBytes) { return 0; OVR_UNUSED(numBytes); }
virtual int BytesAvailable() { return 0; }
virtual bool Flush() { return 0; }
virtual int Seek(int offset, int origin) { return -1; OVR_UNUSED2(offset, origin); }
virtual SInt64 LSeek(SInt64 offset, int origin) { return -1; OVR_UNUSED2(offset, origin); }
virtual int CopyFromStream(File *pstream, int byteSize) { return -1; OVR_UNUSED2(pstream, byteSize); }
virtual bool Close() { return 0; }
};
// ***** System File
// System file is created to access objects on file system directly
// This file can refer directly to path
// ** Constructor
SysFile::SysFile() : DelegatedFile(0)
{
pFile = *new UnopenedFile;
}
Ptr<File> FileFILEOpen(const String& path, int flags, int mode);
// Opens a file
SysFile::SysFile(const String& path, int flags, int mode) : DelegatedFile(0)
{
Open(path, flags, mode);
}
// ** Open & management
// Will fail if file's already open
bool SysFile::Open(const String& path, int flags, int mode)
{
pFile = FileFILEOpen(path, flags, mode);
if ((!pFile) || (!pFile->IsValid()))
{
pFile = *new UnopenedFile;
OVR_DEBUG_LOG(("Failed to open file: %s", path.ToCStr()));
return 0;
}
//pFile = *OVR_NEW DelegatedFile(pFile); // MA Testing
if (flags & Open_Buffered)
pFile = *new BufferedFile(pFile);
return 1;
}
// ** Overrides
int SysFile::GetErrorCode()
{
return pFile ? pFile->GetErrorCode() : Error_FileNotFound;
}
// Overrides to provide re-open support
bool SysFile::IsValid()
{
return pFile && pFile->IsValid();
}
bool SysFile::Close()
{
if (IsValid())
{
DelegatedFile::Close();
pFile = *new UnopenedFile;
return 1;
}
return 0;
}
} // OVR

View File

@ -0,0 +1,104 @@
/************************************************************************************
PublicHeader: Kernel
Filename : OVR_SysFile.h
Content : Header for all internal file management - functions and structures
to be inherited by OS specific subclasses.
Created : September 19, 2012
Notes :
Notes : errno may not be preserved across use of GBaseFile member functions
: Directories cannot be deleted while files opened from them are in use
(For the GetFullName function)
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_SysFile_h
#define OVR_SysFile_h
#include "OVR_File.h"
namespace OVR {
// ***** Declared classes
class SysFile;
//-----------------------------------------------------------------------------------
// *** File Statistics
// This class contents are similar to _stat, providing
// creation, modify and other information about the file.
struct FileStat
{
// No change or create time because they are not available on most systems
SInt64 ModifyTime;
SInt64 AccessTime;
SInt64 FileSize;
bool operator== (const FileStat& stat) const
{
return ( (ModifyTime == stat.ModifyTime) &&
(AccessTime == stat.AccessTime) &&
(FileSize == stat.FileSize) );
}
};
//-----------------------------------------------------------------------------------
// *** System File
// System file is created to access objects on file system directly
// This file can refer directly to path.
// System file can be open & closed several times; however, such use is not recommended
// This class is realy a wrapper around an implementation of File interface for a
// particular platform.
class SysFile : public DelegatedFile
{
protected:
SysFile(const SysFile &source) : DelegatedFile () { OVR_UNUSED(source); }
public:
// ** Constructor
SysFile();
// Opens a file
SysFile(const String& path, int flags = Open_Read|Open_Buffered, int mode = Mode_ReadWrite);
// ** Open & management
bool Open(const String& path, int flags = Open_Read|Open_Buffered, int mode = Mode_ReadWrite);
OVR_FORCE_INLINE bool Create(const String& path, int mode = Mode_ReadWrite)
{ return Open(path, Open_ReadWrite|Open_Create, mode); }
// Helper function: obtain file statistics information. In OVR, this is used to detect file changes.
// Return 0 if function failed, most likely because the file doesn't exist.
static bool OVR_CDECL GetFileStat(FileStat* pfileStats, const String& path);
// ** Overrides
// Overridden to provide re-open support
virtual int GetErrorCode();
virtual bool IsValid();
virtual bool Close();
};
} // Namespace OVR
#endif

View File

@ -0,0 +1,81 @@
/************************************************************************************
Filename : OVR_System.cpp
Content : General kernel initialization/cleanup, including that
of the memory allocator.
Created : September 19, 2012
Notes :
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_System.h"
#include "OVR_Threads.h"
#include "OVR_Timer.h"
namespace OVR {
// ***** OVR::System Implementation
// Initializes System core, installing allocator.
void System::Init(Log* log, Allocator *palloc)
{
if (!Allocator::GetInstance())
{
Log::SetGlobalLog(log);
Timer::initializeTimerSystem();
Allocator::setInstance(palloc);
}
else
{
OVR_DEBUG_LOG(("System::Init failed - duplicate call."));
}
}
void System::Destroy()
{
if (Allocator::GetInstance())
{
// Wait for all threads to finish; this must be done so that memory
// allocator and all destructors finalize correctly.
#ifdef OVR_ENABLE_THREADS
Thread::FinishAllThreads();
#endif
// Shutdown heap and destroy SysAlloc singleton, if any.
Allocator::GetInstance()->onSystemShutdown();
Allocator::setInstance(0);
Timer::shutdownTimerSystem();
Log::SetGlobalLog(Log::GetDefaultLog());
}
else
{
OVR_DEBUG_LOG(("System::Destroy failed - System not initialized."));
}
}
// Returns 'true' if system was properly initialized.
bool System::IsInitialized()
{
return Allocator::GetInstance() != 0;
}
} // OVR

View File

@ -0,0 +1,78 @@
/************************************************************************************
PublicHeader: OVR
Filename : OVR_System.h
Content : General kernel initialization/cleanup, including that
of the memory allocator.
Created : September 19, 2012
Notes :
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_System_h
#define OVR_System_h
#include "OVR_Allocator.h"
#include "OVR_Log.h"
namespace OVR {
// ***** System Core Initialization class
// System initialization must take place before any other OVR_Kernel objects are used;
// this is done my calling System::Init(). Among other things, this is necessary to
// initialize the memory allocator. Similarly, System::Destroy must be
// called before program exist for proper cleanup. Both of these tasks can be achieved by
// simply creating System object first, allowing its constructor/destructor do the work.
// TBD: Require additional System class for Oculus Rift API?
class System
{
public:
// System constructor expects allocator to be specified, if it is being substituted.
System(Log* log = Log::ConfigureDefaultLog(LogMask_Debug),
Allocator* palloc = DefaultAllocator::InitSystemSingleton())
{
Init(log, palloc);
}
~System()
{
Destroy();
}
// Returns 'true' if system was properly initialized.
static bool OVR_CDECL IsInitialized();
// Initializes System core. Users can override memory implementation by passing
// a different Allocator here.
static void OVR_CDECL Init(Log* log = Log::ConfigureDefaultLog(LogMask_Debug),
Allocator *palloc = DefaultAllocator::InitSystemSingleton());
// De-initializes System more, finalizing the threading system and destroying
// the global memory allocator.
static void OVR_CDECL Destroy();
};
} // OVR
#endif

View File

@ -0,0 +1,407 @@
/************************************************************************************
PublicHeader: None
Filename : OVR_Threads.h
Content : Contains thread-related (safe) functionality
Created : September 19, 2012
Notes :
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_Threads_h
#define OVR_Threads_h
#include "OVR_Types.h"
#include "OVR_Atomic.h"
#include "OVR_RefCount.h"
#include "OVR_Array.h"
// Defines the infinite wait delay timeout
#define OVR_WAIT_INFINITE 0xFFFFFFFF
// To be defined in the project configuration options
#ifdef OVR_ENABLE_THREADS
namespace OVR {
//-----------------------------------------------------------------------------------
// ****** Declared classes
// Declared with thread support only
class Mutex;
class WaitCondition;
class Event;
// Implementation forward declarations
class MutexImpl;
class WaitConditionImpl;
//-----------------------------------------------------------------------------------
// ***** Mutex
// Mutex class represents a system Mutex synchronization object that provides access
// serialization between different threads, allowing one thread mutually exclusive access
// to a resource. Mutex is more heavy-weight then Lock, but supports WaitCondition.
class Mutex
{
friend class WaitConditionImpl;
friend class MutexImpl;
MutexImpl *pImpl;
public:
// Constructor/destructor
Mutex(bool recursive = 1);
~Mutex();
// Locking functions
void DoLock();
bool TryLock();
void Unlock();
// Returns 1 if the mutes is currently locked by another thread
// Returns 0 if the mutex is not locked by another thread, and can therefore be acquired.
bool IsLockedByAnotherThread();
// Locker class; Used for automatic locking of a mutex withing scope
class Locker
{
public:
Mutex *pMutex;
Locker(Mutex *pmutex)
{ pMutex = pmutex; pMutex->DoLock(); }
~Locker()
{ pMutex->Unlock(); }
};
};
//-----------------------------------------------------------------------------------
// ***** WaitCondition
/*
WaitCondition is a synchronization primitive that can be used to implement what is known as a monitor.
Dependent threads wait on a wait condition by calling Wait(), and get woken up by other threads that
call Notify() or NotifyAll().
The unique feature of this class is that it provides an atomic way of first releasing a Mutex, and then
starting a wait on a wait condition. If both the mutex and the wait condition are associated with the same
resource, this ensures that any condition checked for while the mutex was locked does not change before
the wait on the condition is actually initiated.
*/
class WaitCondition
{
friend class WaitConditionImpl;
// Internal implementation structure
WaitConditionImpl *pImpl;
public:
// Constructor/destructor
WaitCondition();
~WaitCondition();
// Release mutex and wait for condition. The mutex is re-aquired after the wait.
// Delay is specified in milliseconds (1/1000 of a second).
bool Wait(Mutex *pmutex, unsigned delay = OVR_WAIT_INFINITE);
// Notify a condition, releasing at one object waiting
void Notify();
// Notify a condition, releasing all objects waiting
void NotifyAll();
};
//-----------------------------------------------------------------------------------
// ***** Event
// Event is a wait-able synchronization object similar to Windows event.
// Event can be waited on until it's signaled by another thread calling
// either SetEvent or PulseEvent.
class Event
{
// Event state, its mutex and the wait condition
volatile bool State;
volatile bool Temporary;
mutable Mutex StateMutex;
WaitCondition StateWaitCondition;
void updateState(bool newState, bool newTemp, bool mustNotify);
public:
Event(bool setInitially = 0) : State(setInitially), Temporary(false) { }
~Event() { }
// Wait on an event condition until it is set
// Delay is specified in milliseconds (1/1000 of a second).
bool Wait(unsigned delay = OVR_WAIT_INFINITE);
// Set an event, releasing objects waiting on it
void SetEvent()
{ updateState(true, false, true); }
// Reset an event, un-signaling it
void ResetEvent()
{ updateState(false, false, false); }
// Set and then reset an event once a waiter is released.
// If threads are already waiting, they will be notified and released
// If threads are not waiting, the event is set until the first thread comes in
void PulseEvent()
{ updateState(true, true, true); }
};
//-----------------------------------------------------------------------------------
// ***** Thread class
// ThreadId uniquely identifies a thread; returned by GetCurrentThreadId() and
// Thread::GetThreadId.
typedef void* ThreadId;
// *** Thread flags
// Indicates that the thread is has been started, i.e. Start method has been called, and threads
// OnExit() method has not yet been called/returned.
#define OVR_THREAD_STARTED 0x01
// This flag is set once the thread has ran, and finished.
#define OVR_THREAD_FINISHED 0x02
// This flag is set temporarily if this thread was started suspended. It is used internally.
#define OVR_THREAD_START_SUSPENDED 0x08
// This flag is used to ask a thread to exit. Message driven threads will usually check this flag
// and finish once it is set.
#define OVR_THREAD_EXIT 0x10
class Thread : public RefCountBase<Thread>
{ // NOTE: Waitable must be the first base since it implements RefCountImpl.
public:
// *** Callback functions, can be used instead of overriding Run
// Run function prototypes.
// Thread function and user handle passed to it, executed by the default
// Thread::Run implementation if not null.
typedef int (*ThreadFn)(Thread *pthread, void* h);
// Thread ThreadFunction1 is executed if not 0, otherwise ThreadFunction2 is tried
ThreadFn ThreadFunction;
// User handle passes to a thread
void* UserHandle;
// Thread state to start a thread with
enum ThreadState
{
NotRunning = 0,
Running = 1,
Suspended = 2
};
// Thread priority
enum ThreadPriority
{
CriticalPriority,
HighestPriority,
AboveNormalPriority,
NormalPriority,
BelowNormalPriority,
LowestPriority,
IdlePriority,
};
// Thread constructor parameters
struct CreateParams
{
CreateParams(ThreadFn func = 0, void* hand = 0, UPInt ssize = 128 * 1024,
int proc = -1, ThreadState state = NotRunning, ThreadPriority prior = NormalPriority)
: threadFunction(func), userHandle(hand), stackSize(ssize),
processor(proc), initialState(state), priority(prior) {}
ThreadFn threadFunction; // Thread function
void* userHandle; // User handle passes to a thread
UPInt stackSize; // Thread stack size
int processor; // Thread hardware processor
ThreadState initialState; //
ThreadPriority priority; // Thread priority
};
// *** Constructors
// A default constructor always creates a thread in NotRunning state, because
// the derived class has not yet been initialized. The derived class can call Start explicitly.
// "processor" parameter specifies which hardware processor this thread will be run on.
// -1 means OS decides this. Implemented only on Win32
Thread(UPInt stackSize = 128 * 1024, int processor = -1);
// Constructors that initialize the thread with a pointer to function.
// An option to start a thread is available, but it should not be used if classes are derived from Thread.
// "processor" parameter specifies which hardware processor this thread will be run on.
// -1 means OS decides this. Implemented only on Win32
Thread(ThreadFn threadFunction, void* userHandle = 0, UPInt stackSize = 128 * 1024,
int processor = -1, ThreadState initialState = NotRunning);
// Constructors that initialize the thread with a create parameters structure.
explicit Thread(const CreateParams& params);
// Destructor.
virtual ~Thread();
// Waits for all Threads to finish; should be called only from the root
// application thread. Once this function returns, we know that all other
// thread's references to Thread object have been released.
static void OVR_CDECL FinishAllThreads();
// *** Overridable Run function for thread processing
// - returning from this method will end the execution of the thread
// - return value is usually 0 for success
virtual int Run();
// Called after return/exit function
virtual void OnExit();
// *** Thread management
// Starts the thread if its not already running
// - internally sets up the threading and calls Run()
// - initial state can either be Running or Suspended, NotRunning will just fail and do nothing
// - returns the exit code
virtual bool Start(ThreadState initialState = Running);
// Quits with an exit code
virtual void Exit(int exitCode=0);
// Suspend the thread until resumed
// Returns 1 for success, 0 for failure.
bool Suspend();
// Resumes currently suspended thread
// Returns 1 for success, 0 for failure.
bool Resume();
// Static function to return a pointer to the current thread
//static Thread* GetThread();
// *** Thread status query functions
bool GetExitFlag() const;
void SetExitFlag(bool exitFlag);
// Determines whether the thread was running and is now finished
bool IsFinished() const;
// Determines if the thread is currently suspended
bool IsSuspended() const;
// Returns current thread state
ThreadState GetThreadState() const;
// Returns the number of available CPUs on the system
static int GetCPUCount();
// Returns the thread exit code. Exit code is initialized to 0,
// and set to the return value if Run function after the thread is finished.
inline int GetExitCode() const { return ExitCode; }
// Returns an OS handle
#if defined(OVR_OS_WIN32)
void* GetOSHandle() const { return ThreadHandle; }
#else
pthread_t GetOSHandle() const { return ThreadHandle; }
#endif
#if defined(OVR_OS_WIN32)
ThreadId GetThreadId() const { return IdValue; }
#else
ThreadId GetThreadId() const { return (ThreadId)GetOSHandle(); }
#endif
static int GetOSPriority(ThreadPriority);
// *** Sleep
// Sleep secs seconds
static bool Sleep(unsigned secs);
// Sleep msecs milliseconds
static bool MSleep(unsigned msecs);
// *** Debugging functionality
#if defined(OVR_OS_WIN32)
virtual void SetThreadName( const char* name );
#else
virtual void SetThreadName( const char* name ) { OVR_UNUSED(name); }
#endif
private:
#if defined(OVR_OS_WIN32)
friend unsigned WINAPI Thread_Win32StartFn(void *pthread);
#else
friend void *Thread_PthreadStartFn(void * phandle);
static int InitAttr;
static pthread_attr_t Attr;
#endif
protected:
// Thread state flags
AtomicInt<UInt32> ThreadFlags;
AtomicInt<SInt32> SuspendCount;
UPInt StackSize;
// Hardware processor which this thread is running on.
int Processor;
ThreadPriority Priority;
#if defined(OVR_OS_WIN32)
void* ThreadHandle;
volatile ThreadId IdValue;
// System-specific cleanup function called from destructor
void CleanupSystemThread();
#else
pthread_t ThreadHandle;
#endif
// Exit code of the thread, as returned by Run.
int ExitCode;
// Internal run function.
int PRun();
// Finishes the thread and releases internal reference to it.
void FinishAndRelease();
void Init(const CreateParams& params);
// Protected copy constructor
Thread(const Thread &source) : RefCountBase<Thread>() { OVR_UNUSED(source); }
};
// Returns the unique Id of a thread it is called on, intended for
// comparison purposes.
ThreadId GetCurrentThreadId();
} // OVR
#endif // OVR_ENABLE_THREADS
#endif // OVR_Threads_h

View File

@ -0,0 +1,787 @@
/************************************************************************************
Filename : OVR_ThreadsPthread.cpp
Content :
Created :
Notes :
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_Threads.h"
#include "OVR_Hash.h"
#ifdef OVR_ENABLE_THREADS
#include "OVR_Timer.h"
#include "OVR_Log.h"
#include <pthread.h>
#include <time.h>
#include <unistd.h>
#include <sys/time.h>
#include <errno.h>
namespace OVR {
// ***** Mutex implementation
// *** Internal Mutex implementation structure
class MutexImpl : public NewOverrideBase
{
// System mutex or semaphore
pthread_mutex_t SMutex;
bool Recursive;
unsigned LockCount;
pthread_t LockedBy;
friend class WaitConditionImpl;
public:
// Constructor/destructor
MutexImpl(Mutex* pmutex, bool recursive = 1);
~MutexImpl();
// Locking functions
void DoLock();
bool TryLock();
void Unlock(Mutex* pmutex);
// Returns 1 if the mutes is currently locked
bool IsLockedByAnotherThread(Mutex* pmutex);
bool IsSignaled() const;
};
pthread_mutexattr_t Lock::RecursiveAttr;
bool Lock::RecursiveAttrInit = 0;
// *** Constructor/destructor
MutexImpl::MutexImpl(Mutex* pmutex, bool recursive)
{
OVR_UNUSED(pmutex);
Recursive = recursive;
LockCount = 0;
if (Recursive)
{
if (!Lock::RecursiveAttrInit)
{
pthread_mutexattr_init(&Lock::RecursiveAttr);
pthread_mutexattr_settype(&Lock::RecursiveAttr, PTHREAD_MUTEX_RECURSIVE);
Lock::RecursiveAttrInit = 1;
}
pthread_mutex_init(&SMutex, &Lock::RecursiveAttr);
}
else
pthread_mutex_init(&SMutex, 0);
}
MutexImpl::~MutexImpl()
{
pthread_mutex_destroy(&SMutex);
}
// Lock and try lock
void MutexImpl::DoLock()
{
while (pthread_mutex_lock(&SMutex))
;
LockCount++;
LockedBy = pthread_self();
}
bool MutexImpl::TryLock()
{
if (!pthread_mutex_trylock(&SMutex))
{
LockCount++;
LockedBy = pthread_self();
return 1;
}
return 0;
}
void MutexImpl::Unlock(Mutex* pmutex)
{
OVR_UNUSED(pmutex);
OVR_ASSERT(pthread_self() == LockedBy && LockCount > 0);
unsigned lockCount;
LockCount--;
lockCount = LockCount;
pthread_mutex_unlock(&SMutex);
}
bool MutexImpl::IsLockedByAnotherThread(Mutex* pmutex)
{
OVR_UNUSED(pmutex);
// There could be multiple interpretations of IsLocked with respect to current thread
if (LockCount == 0)
return 0;
if (pthread_self() != LockedBy)
return 1;
return 0;
}
bool MutexImpl::IsSignaled() const
{
// An mutex is signaled if it is not locked ANYWHERE
// Note that this is different from IsLockedByAnotherThread function,
// that takes current thread into account
return LockCount == 0;
}
// *** Actual Mutex class implementation
Mutex::Mutex(bool recursive)
{
// NOTE: RefCount mode already thread-safe for all waitables.
pImpl = new MutexImpl(this, recursive);
}
Mutex::~Mutex()
{
delete pImpl;
}
// Lock and try lock
void Mutex::DoLock()
{
pImpl->DoLock();
}
bool Mutex::TryLock()
{
return pImpl->TryLock();
}
void Mutex::Unlock()
{
pImpl->Unlock(this);
}
bool Mutex::IsLockedByAnotherThread()
{
return pImpl->IsLockedByAnotherThread(this);
}
//-----------------------------------------------------------------------------------
// ***** Event
bool Event::Wait(unsigned delay)
{
Mutex::Locker lock(&StateMutex);
// Do the correct amount of waiting
if (delay == OVR_WAIT_INFINITE)
{
while(!State)
StateWaitCondition.Wait(&StateMutex);
}
else if (delay)
{
if (!State)
StateWaitCondition.Wait(&StateMutex, delay);
}
bool state = State;
// Take care of temporary 'pulsing' of a state
if (Temporary)
{
Temporary = false;
State = false;
}
return state;
}
void Event::updateState(bool newState, bool newTemp, bool mustNotify)
{
Mutex::Locker lock(&StateMutex);
State = newState;
Temporary = newTemp;
if (mustNotify)
StateWaitCondition.NotifyAll();
}
// ***** Wait Condition Implementation
// Internal implementation class
class WaitConditionImpl : public NewOverrideBase
{
pthread_mutex_t SMutex;
pthread_cond_t Condv;
public:
// Constructor/destructor
WaitConditionImpl();
~WaitConditionImpl();
// Release mutex and wait for condition. The mutex is re-aqured after the wait.
bool Wait(Mutex *pmutex, unsigned delay = OVR_WAIT_INFINITE);
// Notify a condition, releasing at one object waiting
void Notify();
// Notify a condition, releasing all objects waiting
void NotifyAll();
};
WaitConditionImpl::WaitConditionImpl()
{
pthread_mutex_init(&SMutex, 0);
pthread_cond_init(&Condv, 0);
}
WaitConditionImpl::~WaitConditionImpl()
{
pthread_mutex_destroy(&SMutex);
pthread_cond_destroy(&Condv);
}
bool WaitConditionImpl::Wait(Mutex *pmutex, unsigned delay)
{
bool result = 1;
unsigned lockCount = pmutex->pImpl->LockCount;
// Mutex must have been locked
if (lockCount == 0)
return 0;
pthread_mutex_lock(&SMutex);
// Finally, release a mutex or semaphore
if (pmutex->pImpl->Recursive)
{
// Release the recursive mutex N times
pmutex->pImpl->LockCount = 0;
for(unsigned i=0; i<lockCount; i++)
pthread_mutex_unlock(&pmutex->pImpl->SMutex);
}
else
{
pmutex->pImpl->LockCount = 0;
pthread_mutex_unlock(&pmutex->pImpl->SMutex);
}
// Note that there is a gap here between mutex.Unlock() and Wait().
// The other mutex protects this gap.
if (delay == OVR_WAIT_INFINITE)
pthread_cond_wait(&Condv,&SMutex);
else
{
timespec ts;
struct timeval tv;
gettimeofday(&tv, 0);
ts.tv_sec = tv.tv_sec + (delay / 1000);
ts.tv_nsec = (tv.tv_usec + (delay % 1000) * 1000) * 1000;
if (ts.tv_nsec > 999999999)
{
ts.tv_sec++;
ts.tv_nsec -= 1000000000;
}
int r = pthread_cond_timedwait(&Condv,&SMutex, &ts);
OVR_ASSERT(r == 0 || r == ETIMEDOUT);
if (r)
result = 0;
}
pthread_mutex_unlock(&SMutex);
// Re-aquire the mutex
for(unsigned i=0; i<lockCount; i++)
pmutex->DoLock();
// Return the result
return result;
}
// Notify a condition, releasing the least object in a queue
void WaitConditionImpl::Notify()
{
pthread_mutex_lock(&SMutex);
pthread_cond_signal(&Condv);
pthread_mutex_unlock(&SMutex);
}
// Notify a condition, releasing all objects waiting
void WaitConditionImpl::NotifyAll()
{
pthread_mutex_lock(&SMutex);
pthread_cond_broadcast(&Condv);
pthread_mutex_unlock(&SMutex);
}
// *** Actual implementation of WaitCondition
WaitCondition::WaitCondition()
{
pImpl = new WaitConditionImpl;
}
WaitCondition::~WaitCondition()
{
delete pImpl;
}
bool WaitCondition::Wait(Mutex *pmutex, unsigned delay)
{
return pImpl->Wait(pmutex, delay);
}
// Notification
void WaitCondition::Notify()
{
pImpl->Notify();
}
void WaitCondition::NotifyAll()
{
pImpl->NotifyAll();
}
// ***** Current thread
// Per-thread variable
/*
static __thread Thread* pCurrentThread = 0;
// Static function to return a pointer to the current thread
void Thread::InitCurrentThread(Thread *pthread)
{
pCurrentThread = pthread;
}
// Static function to return a pointer to the current thread
Thread* Thread::GetThread()
{
return pCurrentThread;
}
*/
// *** Thread constructors.
Thread::Thread(UPInt stackSize, int processor)
{
// NOTE: RefCount mode already thread-safe for all Waitable objects.
CreateParams params;
params.stackSize = stackSize;
params.processor = processor;
Init(params);
}
Thread::Thread(Thread::ThreadFn threadFunction, void* userHandle, UPInt stackSize,
int processor, Thread::ThreadState initialState)
{
CreateParams params(threadFunction, userHandle, stackSize, processor, initialState);
Init(params);
}
Thread::Thread(const CreateParams& params)
{
Init(params);
}
void Thread::Init(const CreateParams& params)
{
// Clear the variables
ThreadFlags = 0;
ThreadHandle = 0;
ExitCode = 0;
SuspendCount = 0;
StackSize = params.stackSize;
Processor = params.processor;
Priority = params.priority;
// Clear Function pointers
ThreadFunction = params.threadFunction;
UserHandle = params.userHandle;
if (params.initialState != NotRunning)
Start(params.initialState);
}
Thread::~Thread()
{
// Thread should not running while object is being destroyed,
// this would indicate ref-counting issue.
//OVR_ASSERT(IsRunning() == 0);
// Clean up thread.
ThreadHandle = 0;
}
// *** Overridable User functions.
// Default Run implementation
int Thread::Run()
{
// Call pointer to function, if available.
return (ThreadFunction) ? ThreadFunction(this, UserHandle) : 0;
}
void Thread::OnExit()
{
}
// Finishes the thread and releases internal reference to it.
void Thread::FinishAndRelease()
{
// Note: thread must be US.
ThreadFlags &= (UInt32)~(OVR_THREAD_STARTED);
ThreadFlags |= OVR_THREAD_FINISHED;
// Release our reference; this is equivalent to 'delete this'
// from the point of view of our thread.
Release();
}
// *** ThreadList - used to track all created threads
class ThreadList : public NewOverrideBase
{
//------------------------------------------------------------------------
struct ThreadHashOp
{
size_t operator()(const Thread* ptr)
{
return (((size_t)ptr) >> 6) ^ (size_t)ptr;
}
};
HashSet<Thread*, ThreadHashOp> ThreadSet;
Mutex ThreadMutex;
WaitCondition ThreadsEmpty;
// Track the root thread that created us.
pthread_t RootThreadId;
static ThreadList* volatile pRunningThreads;
void addThread(Thread *pthread)
{
Mutex::Locker lock(&ThreadMutex);
ThreadSet.Add(pthread);
}
void removeThread(Thread *pthread)
{
Mutex::Locker lock(&ThreadMutex);
ThreadSet.Remove(pthread);
if (ThreadSet.GetSize() == 0)
ThreadsEmpty.Notify();
}
void finishAllThreads()
{
// Only original root thread can call this.
OVR_ASSERT(pthread_self() == RootThreadId);
Mutex::Locker lock(&ThreadMutex);
while (ThreadSet.GetSize() != 0)
ThreadsEmpty.Wait(&ThreadMutex);
}
public:
ThreadList()
{
RootThreadId = pthread_self();
}
~ThreadList() { }
static void AddRunningThread(Thread *pthread)
{
// Non-atomic creation ok since only the root thread
if (!pRunningThreads)
{
pRunningThreads = new ThreadList;
OVR_ASSERT(pRunningThreads);
}
pRunningThreads->addThread(pthread);
}
// NOTE: 'pthread' might be a dead pointer when this is
// called so it should not be accessed; it is only used
// for removal.
static void RemoveRunningThread(Thread *pthread)
{
OVR_ASSERT(pRunningThreads);
pRunningThreads->removeThread(pthread);
}
static void FinishAllThreads()
{
// This is ok because only root thread can wait for other thread finish.
if (pRunningThreads)
{
pRunningThreads->finishAllThreads();
delete pRunningThreads;
pRunningThreads = 0;
}
}
};
// By default, we have no thread list.
ThreadList* volatile ThreadList::pRunningThreads = 0;
// FinishAllThreads - exposed publicly in Thread.
void Thread::FinishAllThreads()
{
ThreadList::FinishAllThreads();
}
// *** Run override
int Thread::PRun()
{
// Suspend us on start, if requested
if (ThreadFlags & OVR_THREAD_START_SUSPENDED)
{
Suspend();
ThreadFlags &= (UInt32)~OVR_THREAD_START_SUSPENDED;
}
// Call the virtual run function
ExitCode = Run();
return ExitCode;
}
// *** User overridables
bool Thread::GetExitFlag() const
{
return (ThreadFlags & OVR_THREAD_EXIT) != 0;
}
void Thread::SetExitFlag(bool exitFlag)
{
// The below is atomic since ThreadFlags is AtomicInt.
if (exitFlag)
ThreadFlags |= OVR_THREAD_EXIT;
else
ThreadFlags &= (UInt32) ~OVR_THREAD_EXIT;
}
// Determines whether the thread was running and is now finished
bool Thread::IsFinished() const
{
return (ThreadFlags & OVR_THREAD_FINISHED) != 0;
}
// Determines whether the thread is suspended
bool Thread::IsSuspended() const
{
return SuspendCount > 0;
}
// Returns current thread state
Thread::ThreadState Thread::GetThreadState() const
{
if (IsSuspended())
return Suspended;
if (ThreadFlags & OVR_THREAD_STARTED)
return Running;
return NotRunning;
}
/*
static const char* mapsched_policy(int policy)
{
switch(policy)
{
case SCHED_OTHER:
return "SCHED_OTHER";
case SCHED_RR:
return "SCHED_RR";
case SCHED_FIFO:
return "SCHED_FIFO";
}
return "UNKNOWN";
}
int policy;
sched_param sparam;
pthread_getschedparam(pthread_self(), &policy, &sparam);
int max_prior = sched_get_priority_max(policy);
int min_prior = sched_get_priority_min(policy);
printf(" !!!! policy: %s, priority: %d, max priority: %d, min priority: %d\n", mapsched_policy(policy), sparam.sched_priority, max_prior, min_prior);
#include <stdio.h>
*/
// ***** Thread management
// The actual first function called on thread start
void* Thread_PthreadStartFn(void* phandle)
{
Thread* pthread = (Thread*)phandle;
int result = pthread->PRun();
// Signal the thread as done and release it atomically.
pthread->FinishAndRelease();
// At this point Thread object might be dead; however we can still pass
// it to RemoveRunningThread since it is only used as a key there.
ThreadList::RemoveRunningThread(pthread);
return reinterpret_cast<void*>(result);
}
int Thread::InitAttr = 0;
pthread_attr_t Thread::Attr;
/* static */
int Thread::GetOSPriority(ThreadPriority p)
//static inline int MapToSystemPrority(Thread::ThreadPriority p)
{
OVR_UNUSED(p);
return -1;
}
bool Thread::Start(ThreadState initialState)
{
if (initialState == NotRunning)
return 0;
if (GetThreadState() != NotRunning)
{
OVR_DEBUG_LOG(("Thread::Start failed - thread %p already running", this));
return 0;
}
if (!InitAttr)
{
pthread_attr_init(&Attr);
pthread_attr_setdetachstate(&Attr, PTHREAD_CREATE_DETACHED);
pthread_attr_setstacksize(&Attr, 128 * 1024);
sched_param sparam;
sparam.sched_priority = Thread::GetOSPriority(NormalPriority);
pthread_attr_setschedparam(&Attr, &sparam);
InitAttr = 1;
}
ExitCode = 0;
SuspendCount = 0;
ThreadFlags = (initialState == Running) ? 0 : OVR_THREAD_START_SUSPENDED;
// AddRef to us until the thread is finished
AddRef();
ThreadList::AddRunningThread(this);
int result;
if (StackSize != 128 * 1024 || Priority != NormalPriority)
{
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_attr_setstacksize(&attr, StackSize);
sched_param sparam;
sparam.sched_priority = Thread::GetOSPriority(Priority);
pthread_attr_setschedparam(&attr, &sparam);
result = pthread_create(&ThreadHandle, &attr, Thread_PthreadStartFn, this);
pthread_attr_destroy(&attr);
}
else
result = pthread_create(&ThreadHandle, &Attr, Thread_PthreadStartFn, this);
if (result)
{
ThreadFlags = 0;
Release();
ThreadList::RemoveRunningThread(this);
return 0;
}
return 1;
}
// Suspend the thread until resumed
bool Thread::Suspend()
{
OVR_DEBUG_LOG(("Thread::Suspend - cannot suspend threads on this system"));
return 0;
}
// Resumes currently suspended thread
bool Thread::Resume()
{
return 0;
}
// Quits with an exit code
void Thread::Exit(int exitCode)
{
// Can only exist the current thread
// if (GetThread() != this)
// return;
// Call the virtual OnExit function
OnExit();
// Signal this thread object as done and release it's references.
FinishAndRelease();
ThreadList::RemoveRunningThread(this);
pthread_exit(reinterpret_cast<void*>(exitCode));
}
ThreadId GetCurrentThreadId()
{
return (void*)pthread_self();
}
// *** Sleep functions
/* static */
bool Thread::Sleep(unsigned secs)
{
sleep(secs);
return 1;
}
/* static */
bool Thread::MSleep(unsigned msecs)
{
usleep(msecs*1000);
return 1;
}
/* static */
int Thread::GetCPUCount()
{
return 1;
}
}
#endif // OVR_ENABLE_THREADS

View File

@ -0,0 +1,287 @@
/************************************************************************************
Filename : OVR_Timer.cpp
Content : Provides static functions for precise timing
Created : September 19, 2012
Notes :
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_Timer.h"
#include "OVR_Log.h"
#if defined (OVR_OS_WIN32)
#include <windows.h>
#elif defined(OVR_OS_ANDROID)
#include <time.h>
#include <android/log.h>
#else
#include <sys/time.h>
#endif
namespace OVR {
// For recorded data playback
bool Timer::useFakeSeconds = false;
double Timer::FakeSeconds = 0;
//------------------------------------------------------------------------
// *** Timer - Platform Independent functions
// Returns global high-resolution application timer in seconds.
double Timer::GetSeconds()
{
if(useFakeSeconds)
return FakeSeconds;
return double(Timer::GetTicksNanos()) * 0.000000001;
}
#ifndef OVR_OS_WIN32
// Unused on OSs other then Win32.
void Timer::initializeTimerSystem()
{
}
void Timer::shutdownTimerSystem()
{
}
#endif
//------------------------------------------------------------------------
// *** Android Specific Timer
#if defined(OVR_OS_ANDROID)
UInt64 Timer::GetTicksNanos()
{
if (useFakeSeconds)
return (UInt64) (FakeSeconds * NanosPerSecond);
// Choreographer vsync timestamp is based on.
struct timespec tp;
const int status = clock_gettime(CLOCK_MONOTONIC, &tp);
if (status != 0)
{
OVR_DEBUG_LOG(("clock_gettime status=%i", status ));
}
const UInt64 result = (UInt64)tp.tv_sec * (UInt64)(1000 * 1000 * 1000) + UInt64(tp.tv_nsec);
return result;
}
//------------------------------------------------------------------------
// *** Win32 Specific Timer
#elif defined (OVR_OS_WIN32)
// This helper class implements high-resolution wrapper that combines timeGetTime() output
// with QueryPerformanceCounter. timeGetTime() is lower precision but drives the high bits,
// as it's tied to the system clock.
struct PerformanceTimer
{
PerformanceTimer()
: OldMMTimeMs(0), MMTimeWrapCounter(0), PrefFrequency(0),
LastResultNanos(0), PerfMinusTicksDeltaNanos(0)
{ }
enum {
MMTimerResolutionNanos = 1000000
};
void Initialize();
void Shutdown();
UInt64 GetTimeNanos();
UINT64 getFrequency()
{
if (PrefFrequency == 0)
{
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
PrefFrequency = freq.QuadPart;
}
return PrefFrequency;
}
CRITICAL_SECTION TimeCS;
// timeGetTime() support with wrap.
UInt32 OldMMTimeMs;
UInt32 MMTimeWrapCounter;
// Cached performance frequency result.
UInt64 PrefFrequency;
// Computed as (perfCounterNanos - ticksCounterNanos) initially,
// and used to adjust timing.
UInt64 PerfMinusTicksDeltaNanos;
// Last returned value in nanoseconds, to ensure we don't back-step in time.
UInt64 LastResultNanos;
};
PerformanceTimer Win32_PerfTimer;
void PerformanceTimer::Initialize()
{
timeBeginPeriod(1);
InitializeCriticalSection(&TimeCS);
MMTimeWrapCounter = 0;
getFrequency();
}
void PerformanceTimer::Shutdown()
{
DeleteCriticalSection(&TimeCS);
timeEndPeriod(1);
}
UInt64 PerformanceTimer::GetTimeNanos()
{
UInt64 resultNanos;
LARGE_INTEGER li;
DWORD mmTimeMs;
// On Win32 QueryPerformanceFrequency is unreliable due to SMP and
// performance levels, so use this logic to detect wrapping and track
// high bits.
::EnterCriticalSection(&TimeCS);
// Get raw value and perf counter "At the same time".
mmTimeMs = timeGetTime();
QueryPerformanceCounter(&li);
if (OldMMTimeMs > mmTimeMs)
MMTimeWrapCounter++;
OldMMTimeMs = mmTimeMs;
// Normalize to nanoseconds.
UInt64 mmCounterNanos = ((UInt64(MMTimeWrapCounter) << 32) | mmTimeMs) * 1000000;
UInt64 frequency = getFrequency();
UInt64 perfCounterSeconds = UInt64(li.QuadPart) / frequency;
UInt64 perfRemainderNanos = ( (UInt64(li.QuadPart) - perfCounterSeconds * frequency) *
Timer::NanosPerSecond ) / frequency;
UInt64 perfCounterNanos = perfCounterSeconds * Timer::NanosPerSecond + perfRemainderNanos;
if (PerfMinusTicksDeltaNanos == 0)
PerfMinusTicksDeltaNanos = perfCounterNanos - mmCounterNanos;
// Compute result before snapping.
//
// On first call, this evaluates to:
// resultNanos = mmCounterNanos.
// Next call, assuming no wrap:
// resultNanos = prev_mmCounterNanos + (perfCounterNanos - prev_perfCounterNanos).
// After wrap, this would be:
// resultNanos = snapped(prev_mmCounterNanos +/- 1ms) + (perfCounterNanos - prev_perfCounterNanos).
//
resultNanos = perfCounterNanos - PerfMinusTicksDeltaNanos;
// Snap the range so that resultNanos never moves further apart then its target resolution.
// It's better to allow more slack on the high side as timeGetTime() may be updated at sporadically
// larger then 1 ms intervals even when 1 ms resolution is requested.
if (resultNanos > (mmCounterNanos + MMTimerResolutionNanos*2))
{
resultNanos = mmCounterNanos + MMTimerResolutionNanos*2;
if (resultNanos < LastResultNanos)
resultNanos = LastResultNanos;
PerfMinusTicksDeltaNanos = perfCounterNanos - resultNanos;
}
else if (resultNanos < (mmCounterNanos - MMTimerResolutionNanos))
{
resultNanos = mmCounterNanos - MMTimerResolutionNanos;
if (resultNanos < LastResultNanos)
resultNanos = LastResultNanos;
PerfMinusTicksDeltaNanos = perfCounterNanos - resultNanos;
}
LastResultNanos = resultNanos;
::LeaveCriticalSection(&TimeCS);
//Tom's addition, to keep precision
static UInt64 initial_time = 0;
if (!initial_time) initial_time = resultNanos;
resultNanos -= initial_time;
return resultNanos;
}
// Delegate to PerformanceTimer.
UInt64 Timer::GetTicksNanos()
{
if (useFakeSeconds)
return (UInt64) (FakeSeconds * NanosPerSecond);
return Win32_PerfTimer.GetTimeNanos();
}
void Timer::initializeTimerSystem()
{
Win32_PerfTimer.Initialize();
}
void Timer::shutdownTimerSystem()
{
Win32_PerfTimer.Shutdown();
}
#else // !OVR_OS_WIN32 && !OVR_OS_ANDROID
//------------------------------------------------------------------------
// *** Standard OS Timer
UInt64 Timer::GetTicksNanos()
{
if (useFakeSeconds)
return (UInt64) (FakeSeconds * NanosPerSecond);
// TODO: prefer rdtsc when available?
UInt64 result;
// Return microseconds.
struct timeval tv;
gettimeofday(&tv, 0);
result = (UInt64)tv.tv_sec * 1000000;
result += tv.tv_usec;
return result * 1000;
}
#endif // OS-specific
} // OVR

View File

@ -0,0 +1,88 @@
/************************************************************************************
PublicHeader: OVR
Filename : OVR_Timer.h
Content : Provides static functions for precise timing
Created : September 19, 2012
Notes :
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_Timer_h
#define OVR_Timer_h
#include "OVR_Types.h"
namespace OVR {
//-----------------------------------------------------------------------------------
// ***** Timer
// Timer class defines a family of static functions used for application
// timing and profiling.
class Timer
{
public:
enum {
MsPerSecond = 1000, // Milliseconds in one second.
NanosPerSecond = MsPerSecond * 1000 * 1000,
MksPerSecond = MsPerSecond * 1000
};
// ***** Timing APIs for Application
// These APIs should be used to guide animation and other program functions
// that require precision.
// Returns global high-resolution application timer in seconds.
static double OVR_STDCALL GetSeconds();
// Returns time in Nanoseconds, using highest possible system resolution.
static UInt64 OVR_STDCALL GetTicksNanos();
// Kept for compatibility.
// Returns ticks in milliseconds, as a 32-bit number. May wrap around every 49.2 days.
// Use either time difference of two values of GetTicks to avoid wrap-around.
static UInt32 OVR_STDCALL GetTicksMs()
{ return UInt32(GetTicksNanos() / 1000000); }
// for recorded data playback
static void SetFakeSeconds(double fakeSeconds)
{
FakeSeconds = fakeSeconds;
useFakeSeconds = true;
}
private:
friend class System;
// System called during program startup/shutdown.
static void initializeTimerSystem();
static void shutdownTimerSystem();
// for recorded data playback
static double FakeSeconds;
static bool useFakeSeconds;
};
} // OVR::Timer
#endif

View File

@ -0,0 +1,474 @@
/************************************************************************************
PublicHeader: OVR.h
Filename : OVR_Types.h
Content : Standard library defines and simple types
Created : September 19, 2012
Notes :
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_Types_H
#define OVR_Types_H
//-----------------------------------------------------------------------------------
// ****** Operating System
//
// Type definitions exist for the following operating systems: (OVR_OS_x)
//
// WIN32 - Win32 (Windows 95/98/ME and Windows NT/2000/XP)
// DARWIN - Darwin OS (Mac OS X)
// LINUX - Linux
// ANDROID - Android
// IPHONE - iPhone
#if (defined(__APPLE__) && (defined(__GNUC__) ||\
defined(__xlC__) || defined(__xlc__))) || defined(__MACOS__)
# if (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) || defined(__IPHONE_OS_VERSION_MIN_REQUIRED))
# define OVR_OS_IPHONE
# else
# define OVR_OS_DARWIN
# define OVR_OS_MAC
# endif
#elif (defined(WIN64) || defined(_WIN64) || defined(__WIN64__))
# define OVR_OS_WIN32
#elif (defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__))
# define OVR_OS_WIN32
#elif defined(__linux__) || defined(__linux)
# define OVR_OS_LINUX
#else
# define OVR_OS_OTHER
#endif
#if defined(ANDROID)
# define OVR_OS_ANDROID
#endif
//-----------------------------------------------------------------------------------
// ***** CPU Architecture
//
// The following CPUs are defined: (OVR_CPU_x)
//
// X86 - x86 (IA-32)
// X86_64 - x86_64 (amd64)
// PPC - PowerPC
// PPC64 - PowerPC64
// MIPS - MIPS
// OTHER - CPU for which no special support is present or needed
#if defined(__x86_64__) || defined(WIN64) || defined(_WIN64) || defined(__WIN64__)
# define OVR_CPU_X86_64
# define OVR_64BIT_POINTERS
#elif defined(__i386__) || defined(OVR_OS_WIN32)
# define OVR_CPU_X86
#elif defined(__powerpc64__)
# define OVR_CPU_PPC64
#elif defined(__ppc__)
# define OVR_CPU_PPC
#elif defined(__mips__) || defined(__MIPSEL__)
# define OVR_CPU_MIPS
#elif defined(__arm__)
# define OVR_CPU_ARM
#else
# define OVR_CPU_OTHER
#endif
//-----------------------------------------------------------------------------------
// ***** Co-Processor Architecture
//
// The following co-processors are defined: (OVR_CPU_x)
//
// SSE - Available on all modern x86 processors.
// Altivec - Available on all modern ppc processors.
// Neon - Available on some armv7+ processors.
#if defined(__SSE__) || defined(OVR_OS_WIN32)
# define OVR_CPU_SSE
#endif // __SSE__
#if defined( __ALTIVEC__ )
# define OVR_CPU_ALTIVEC
#endif // __ALTIVEC__
#if defined(__ARM_NEON__)
# define OVR_CPU_ARM_NEON
#endif // __ARM_NEON__
//-----------------------------------------------------------------------------------
// ***** Compiler
//
// The following compilers are defined: (OVR_CC_x)
//
// MSVC - Microsoft Visual C/C++
// INTEL - Intel C++ for Linux / Windows
// GNU - GNU C++
// ARM - ARM C/C++
#if defined(__INTEL_COMPILER)
// Intel 4.0 = 400
// Intel 5.0 = 500
// Intel 6.0 = 600
// Intel 8.0 = 800
// Intel 9.0 = 900
# define OVR_CC_INTEL __INTEL_COMPILER
#elif defined(_MSC_VER)
// MSVC 5.0 = 1100
// MSVC 6.0 = 1200
// MSVC 7.0 (VC2002) = 1300
// MSVC 7.1 (VC2003) = 1310
// MSVC 8.0 (VC2005) = 1400
// MSVC 9.0 (VC2008) = 1500
// MSVC 10.0 (VC2010) = 1600
// MSVC 11.0 (VC2012) = 1700
// MSVC 12.0 (VC2013) = 1800
# define OVR_CC_MSVC _MSC_VER
#elif defined(__GNUC__)
# define OVR_CC_GNU
#elif defined(__CC_ARM)
# define OVR_CC_ARM
#else
# error "Oculus does not support this Compiler"
#endif
//-----------------------------------------------------------------------------------
// ***** Compiler Warnings
// Disable MSVC warnings
#if defined(OVR_CC_MSVC)
# pragma warning(disable : 4127) // Inconsistent dll linkage
# pragma warning(disable : 4530) // Exception handling
# if (OVR_CC_MSVC<1300)
# pragma warning(disable : 4514) // Unreferenced inline function has been removed
# pragma warning(disable : 4710) // Function not inlined
# pragma warning(disable : 4714) // _force_inline not inlined
# pragma warning(disable : 4786) // Debug variable name longer than 255 chars
# endif // (OVR_CC_MSVC<1300)
#endif // (OVR_CC_MSVC)
// *** Linux Unicode - must come before Standard Includes
#ifdef OVR_OS_LINUX
// Use glibc unicode functions on linux.
# ifndef _GNU_SOURCE
# define _GNU_SOURCE
# endif
#endif
//-----------------------------------------------------------------------------------
// ***** Standard Includes
//
#include <stddef.h>
#include <limits.h>
#include <float.h>
// MSVC Based Memory Leak checking - for now
#if defined(OVR_CC_MSVC) && defined(OVR_BUILD_DEBUG)
# define _CRTDBG_MAP_ALLOC
# include <stdlib.h>
# include <crtdbg.h>
#if 0
// Uncomment this to help debug memory leaks under Visual Studio in OVR apps only.
// This shouldn't be defined in customer releases.
# ifndef OVR_DEFINE_NEW
# define OVR_DEFINE_NEW new(__FILE__, __LINE__)
# define new OVR_DEFINE_NEW
# endif
#endif
#endif
//-----------------------------------------------------------------------------------
// ***** Type definitions for Common Systems
namespace OVR {
typedef char Char;
// Pointer-sized integer
typedef size_t UPInt;
typedef ptrdiff_t SPInt;
#if defined(OVR_OS_WIN32)
typedef char SByte; // 8 bit Integer (Byte)
typedef unsigned char UByte;
typedef short SInt16; // 16 bit Integer (Word)
typedef unsigned short UInt16;
typedef long SInt32; // 32 bit Integer
typedef unsigned long UInt32;
typedef __int64 SInt64; // 64 bit Integer (QWord)
typedef unsigned __int64 UInt64;
#elif defined(OVR_OS_MAC) || defined(OVR_OS_IPHONE) || defined(OVR_CC_GNU)
typedef int SByte __attribute__((__mode__ (__QI__)));
typedef unsigned int UByte __attribute__((__mode__ (__QI__)));
typedef int SInt16 __attribute__((__mode__ (__HI__)));
typedef unsigned int UInt16 __attribute__((__mode__ (__HI__)));
typedef int SInt32 __attribute__((__mode__ (__SI__)));
typedef unsigned int UInt32 __attribute__((__mode__ (__SI__)));
typedef int SInt64 __attribute__((__mode__ (__DI__)));
typedef unsigned int UInt64 __attribute__((__mode__ (__DI__)));
#else
#include <sys/types.h>
typedef int8_t SByte;
typedef uint8_t UByte;
typedef int16_t SInt16;
typedef uint16_t UInt16;
typedef int32_t SInt32;
typedef uint32_t UInt32;
typedef int64_t SInt64;
typedef uint64_t UInt64;
#endif
// ***** BaseTypes Namespace
// BaseTypes namespace is explicitly declared to allow base types to be used
// by customers directly without other contents of OVR namespace.
//
// Its is expected that OVR samples will declare 'using namespace OVR::BaseTypes'
// to allow using these directly without polluting the target scope with other
// OVR declarations, such as Ptr<>, String or Mutex.
namespace BaseTypes
{
using OVR::UPInt;
using OVR::SPInt;
using OVR::UByte;
using OVR::SByte;
using OVR::UInt16;
using OVR::SInt16;
using OVR::UInt32;
using OVR::SInt32;
using OVR::UInt64;
using OVR::SInt64;
} // OVR::BaseTypes
} // OVR
//-----------------------------------------------------------------------------------
// ***** Macro Definitions
//
// We define the following:
//
// OVR_BYTE_ORDER - Defined to either OVR_LITTLE_ENDIAN or OVR_BIG_ENDIAN
// OVR_FORCE_INLINE - Forces inline expansion of function
// OVR_ASM - Assembly language prefix
// OVR_STR - Prefixes string with L"" if building unicode
//
// OVR_STDCALL - Use stdcall calling convention (Pascal arg order)
// OVR_CDECL - Use cdecl calling convention (C argument order)
// OVR_FASTCALL - Use fastcall calling convention (registers)
//
// Byte order constants, OVR_BYTE_ORDER is defined to be one of these.
#define OVR_LITTLE_ENDIAN 1
#define OVR_BIG_ENDIAN 2
// Force inline substitute - goes before function declaration
#if defined(OVR_CC_MSVC)
# define OVR_FORCE_INLINE __forceinline
#elif defined(OVR_CC_GNU)
# define OVR_FORCE_INLINE __attribute__((always_inline)) inline
#else
# define OVR_FORCE_INLINE inline
#endif // OVR_CC_MSVC
#if defined(OVR_OS_WIN32)
// ***** Win32
// Byte order
#define OVR_BYTE_ORDER OVR_LITTLE_ENDIAN
// Calling convention - goes after function return type but before function name
#ifdef __cplusplus_cli
# define OVR_FASTCALL __stdcall
#else
# define OVR_FASTCALL __fastcall
#endif
#define OVR_STDCALL __stdcall
#define OVR_CDECL __cdecl
// Assembly macros
#if defined(OVR_CC_MSVC)
# define OVR_ASM _asm
#else
# define OVR_ASM asm
#endif // (OVR_CC_MSVC)
#ifdef UNICODE
# define OVR_STR(str) L##str
#else
# define OVR_STR(str) str
#endif // UNICODE
#else
// **** Standard systems
#if (defined(BYTE_ORDER) && (BYTE_ORDER == BIG_ENDIAN))|| \
(defined(_BYTE_ORDER) && (_BYTE_ORDER == _BIG_ENDIAN))
# define OVR_BYTE_ORDER OVR_BIG_ENDIAN
#elif (defined(__ARMEB__) || defined(OVR_CPU_PPC) || defined(OVR_CPU_PPC64))
# define OVR_BYTE_ORDER OVR_BIG_ENDIAN
#else
# define OVR_BYTE_ORDER OVR_LITTLE_ENDIAN
#endif
// Assembly macros
#define OVR_ASM __asm__
#define OVR_ASM_PROC(procname) OVR_ASM
#define OVR_ASM_END OVR_ASM
// Calling convention - goes after function return type but before function name
#define OVR_FASTCALL
#define OVR_STDCALL
#define OVR_CDECL
#endif // defined(OVR_OS_WIN32)
//-----------------------------------------------------------------------------------
// ***** OVR_DEBUG_BREAK, OVR_ASSERT
//
// If not in debug build, macros do nothing
#ifndef OVR_BUILD_DEBUG
# define OVR_DEBUG_CODE(c) c
# define OVR_DEBUG_BREAK ((void)0)
# define OVR_ASSERT(p) ((void)0)
#else
// Microsoft Win32 specific debugging support
#if defined(OVR_OS_WIN32)
# ifdef OVR_CPU_X86
# if defined(__cplusplus_cli)
# define OVR_DEBUG_BREAK do { __debugbreak(); } while(0)
# elif defined(OVR_CC_GNU)
# define OVR_DEBUG_BREAK do { OVR_ASM("int $3\n\t"); } while(0)
# else
# define OVR_DEBUG_BREAK do { OVR_ASM int 3 } while (0)
# endif
# else
# define OVR_DEBUG_BREAK do { __debugbreak(); } while(0)
# endif
// Unix specific debugging support
#elif defined(OVR_CPU_X86) || defined(OVR_CPU_X86_64)
# define OVR_DEBUG_BREAK do { OVR_ASM("int $3\n\t"); } while(0)
#else
# define OVR_DEBUG_BREAK do { *((int *) 0) = 1; } while(0)
#endif
#define OVR_DEBUG_CODE(c)
// This will cause compiler breakpoint
#define OVR_ASSERT(p) do { if (!(p)) { OVR_DEBUG_BREAK; } } while(0)
#endif // OVR_BUILD_DEBUG
// Compile-time assert; produces compiler error if condition is false
#define OVR_COMPILER_ASSERT(x) { int zero = 0; switch(zero) {case 0: case x:;} }
//-----------------------------------------------------------------------------------
// ***** OVR_UNUSED - Unused Argument handling
// Macro to quiet compiler warnings about unused parameters/variables.
#if defined(OVR_CC_GNU)
# define OVR_UNUSED(a) do {__typeof__ (&a) __attribute__ ((unused)) __tmp = &a; } while(0)
#else
# define OVR_UNUSED(a) (a)
#endif
#define OVR_UNUSED1(a1) OVR_UNUSED(a1)
#define OVR_UNUSED2(a1,a2) OVR_UNUSED(a1); OVR_UNUSED(a2)
#define OVR_UNUSED3(a1,a2,a3) OVR_UNUSED2(a1,a2); OVR_UNUSED(a3)
#define OVR_UNUSED4(a1,a2,a3,a4) OVR_UNUSED3(a1,a2,a3); OVR_UNUSED(a4)
#define OVR_UNUSED5(a1,a2,a3,a4,a5) OVR_UNUSED4(a1,a2,a3,a4); OVR_UNUSED(a5)
#define OVR_UNUSED6(a1,a2,a3,a4,a5,a6) OVR_UNUSED4(a1,a2,a3,a4); OVR_UNUSED2(a5,a6)
#define OVR_UNUSED7(a1,a2,a3,a4,a5,a6,a7) OVR_UNUSED4(a1,a2,a3,a4); OVR_UNUSED3(a5,a6,a7)
#define OVR_UNUSED8(a1,a2,a3,a4,a5,a6,a7,a8) OVR_UNUSED4(a1,a2,a3,a4); OVR_UNUSED4(a5,a6,a7,a8)
#define OVR_UNUSED9(a1,a2,a3,a4,a5,a6,a7,a8,a9) OVR_UNUSED4(a1,a2,a3,a4); OVR_UNUSED5(a5,a6,a7,a8,a9)
//-----------------------------------------------------------------------------------
// ***** Configuration Macros
// SF Build type
#ifdef OVR_BUILD_DEBUG
# define OVR_BUILD_STRING "Debug"
#else
# define OVR_BUILD_STRING "Release"
#endif
//// Enables SF Debugging information
//# define OVR_BUILD_DEBUG
// OVR_DEBUG_STATEMENT injects a statement only in debug builds.
// OVR_DEBUG_SELECT injects first argument in debug builds, second argument otherwise.
#ifdef OVR_BUILD_DEBUG
#define OVR_DEBUG_STATEMENT(s) s
#define OVR_DEBUG_SELECT(d, nd) d
#else
#define OVR_DEBUG_STATEMENT(s)
#define OVR_DEBUG_SELECT(d, nd) nd
#endif
#define OVR_ENABLE_THREADS
//
// Prevents OVR from defining new within
// type macros, so developers can override
// new using the #define new new(...) trick
// - used with OVR_DEFINE_NEW macro
//# define OVR_BUILD_DEFINE_NEW
//
#endif // OVR_Types_h

View File

@ -0,0 +1,556 @@
/**************************************************************************
Filename : OVR_UTF8Util.cpp
Content : UTF8 Unicode character encoding/decoding support
Created : September 19, 2012
Notes :
Notes : Much useful info at "UTF-8 and Unicode FAQ"
http://www.cl.cam.ac.uk/~mgk25/unicode.html
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_UTF8Util.h"
namespace OVR { namespace UTF8Util {
SPInt OVR_STDCALL GetLength(const char* buf, SPInt buflen)
{
const char* p = buf;
SPInt length = 0;
if (buflen != -1)
{
while (p - buf < buflen)
{
// We should be able to have ASStrings with 0 in the middle.
UTF8Util::DecodeNextChar_Advance0(&p);
length++;
}
}
else
{
while (UTF8Util::DecodeNextChar_Advance0(&p))
length++;
}
return length;
}
UInt32 OVR_STDCALL GetCharAt(SPInt index, const char* putf8str, SPInt length)
{
const char* buf = putf8str;
UInt32 c = 0;
if (length != -1)
{
while (buf - putf8str < length)
{
c = UTF8Util::DecodeNextChar_Advance0(&buf);
if (index == 0)
return c;
index--;
}
return c;
}
do
{
c = UTF8Util::DecodeNextChar_Advance0(&buf);
index--;
if (c == 0)
{
// We've hit the end of the string; don't go further.
OVR_ASSERT(index == 0);
return c;
}
} while (index >= 0);
return c;
}
SPInt OVR_STDCALL GetByteIndex(SPInt index, const char *putf8str, SPInt length)
{
const char* buf = putf8str;
if (length != -1)
{
while ((buf - putf8str) < length && index > 0)
{
UTF8Util::DecodeNextChar_Advance0(&buf);
index--;
}
return buf-putf8str;
}
while (index > 0)
{
UInt32 c = UTF8Util::DecodeNextChar_Advance0(&buf);
index--;
if (c == 0)
return buf-putf8str;
};
return buf-putf8str;
}
int OVR_STDCALL GetEncodeCharSize(UInt32 ucs_character)
{
if (ucs_character <= 0x7F)
return 1;
else if (ucs_character <= 0x7FF)
return 2;
else if (ucs_character <= 0xFFFF)
return 3;
else if (ucs_character <= 0x1FFFFF)
return 4;
else if (ucs_character <= 0x3FFFFFF)
return 5;
else if (ucs_character <= 0x7FFFFFFF)
return 6;
else
return 0;
}
UInt32 OVR_STDCALL DecodeNextChar_Advance0(const char** putf8Buffer)
{
UInt32 uc;
char c;
// Security considerations:
//
// Changed, this is now only the case for DecodeNextChar:
// - If we hit a zero byte, we want to return 0 without stepping
// the buffer pointer past the 0. th
//
// If we hit an "overlong sequence"; i.e. a character encoded
// in a longer multibyte string than is necessary, then we
// need to discard the character. This is so attackers can't
// disguise dangerous characters or character sequences --
// there is only one valid encoding for each character.
//
// If we decode characters { 0xD800 .. 0xDFFF } or { 0xFFFE,
// 0xFFFF } then we ignore them; they are not valid in UTF-8.
// This isn't actually an invalid character; it's a valid char that
// looks like an inverted question mark.
#define INVALID_CHAR 0x0FFFD
#define FIRST_BYTE(mask, shift) \
uc = (c & (mask)) << (shift);
#define NEXT_BYTE(shift) \
c = **putf8Buffer; \
if (c == 0) return 0; /* end of buffer, do not advance */ \
if ((c & 0xC0) != 0x80) return INVALID_CHAR; /* standard check */ \
(*putf8Buffer)++; \
uc |= (c & 0x3F) << shift;
c = **putf8Buffer;
(*putf8Buffer)++;
if (c == 0)
return 0; // End of buffer.
if ((c & 0x80) == 0) return (UInt32) c; // Conventional 7-bit ASCII.
// Multi-byte sequences.
if ((c & 0xE0) == 0xC0)
{
// Two-byte sequence.
FIRST_BYTE(0x1F, 6);
NEXT_BYTE(0);
if (uc < 0x80) return INVALID_CHAR; // overlong
return uc;
}
else if ((c & 0xF0) == 0xE0)
{
// Three-byte sequence.
FIRST_BYTE(0x0F, 12);
NEXT_BYTE(6);
NEXT_BYTE(0);
if (uc < 0x800) return INVALID_CHAR; // overlong
// Not valid ISO 10646, but Flash requires these to work
// see AS3 test e15_5_3_2_3 for String.fromCharCode().charCodeAt(0)
// if (uc >= 0x0D800 && uc <= 0x0DFFF) return INVALID_CHAR;
// if (uc == 0x0FFFE || uc == 0x0FFFF) return INVALID_CHAR; // not valid ISO 10646
return uc;
}
else if ((c & 0xF8) == 0xF0)
{
// Four-byte sequence.
FIRST_BYTE(0x07, 18);
NEXT_BYTE(12);
NEXT_BYTE(6);
NEXT_BYTE(0);
if (uc < 0x010000) return INVALID_CHAR; // overlong
return uc;
}
else if ((c & 0xFC) == 0xF8)
{
// Five-byte sequence.
FIRST_BYTE(0x03, 24);
NEXT_BYTE(18);
NEXT_BYTE(12);
NEXT_BYTE(6);
NEXT_BYTE(0);
if (uc < 0x0200000) return INVALID_CHAR; // overlong
return uc;
}
else if ((c & 0xFE) == 0xFC)
{
// Six-byte sequence.
FIRST_BYTE(0x01, 30);
NEXT_BYTE(24);
NEXT_BYTE(18);
NEXT_BYTE(12);
NEXT_BYTE(6);
NEXT_BYTE(0);
if (uc < 0x04000000) return INVALID_CHAR; // overlong
return uc;
}
else
{
// Invalid.
return INVALID_CHAR;
}
}
void OVR_STDCALL EncodeChar(char* pbuffer, SPInt* pindex, UInt32 ucs_character)
{
if (ucs_character <= 0x7F)
{
// Plain single-byte ASCII.
pbuffer[(*pindex)++] = (char) ucs_character;
}
else if (ucs_character <= 0x7FF)
{
// Two bytes.
pbuffer[(*pindex)++] = 0xC0 | (char)(ucs_character >> 6);
pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 0) & 0x3F);
}
else if (ucs_character <= 0xFFFF)
{
// Three bytes.
pbuffer[(*pindex)++] = 0xE0 | (char)(ucs_character >> 12);
pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 6) & 0x3F);
pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 0) & 0x3F);
}
else if (ucs_character <= 0x1FFFFF)
{
// Four bytes.
pbuffer[(*pindex)++] = 0xF0 | (char)(ucs_character >> 18);
pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 12) & 0x3F);
pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 6) & 0x3F);
pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 0) & 0x3F);
}
else if (ucs_character <= 0x3FFFFFF)
{
// Five bytes.
pbuffer[(*pindex)++] = 0xF8 | (char)(ucs_character >> 24);
pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 18) & 0x3F);
pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 12) & 0x3F);
pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 6) & 0x3F);
pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 0) & 0x3F);
}
else if (ucs_character <= 0x7FFFFFFF)
{
// Six bytes.
pbuffer[(*pindex)++] = 0xFC | (char)(ucs_character >> 30);
pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 24) & 0x3F);
pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 18) & 0x3F);
pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 12) & 0x3F);
pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 6) & 0x3F);
pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 0) & 0x3F);
}
else
{
// Invalid char; don't encode anything.
}
}
SPInt OVR_STDCALL GetEncodeStringSize(const wchar_t* pchar, SPInt length)
{
SPInt len = 0;
if (length != -1)
for (int i = 0; i < length; i++)
{
len += GetEncodeCharSize(pchar[i]);
}
else
for (int i = 0;; i++)
{
if (pchar[i] == 0)
return len;
len += GetEncodeCharSize(pchar[i]);
}
return len;
}
void OVR_STDCALL EncodeString(char *pbuff, const wchar_t* pchar, SPInt length)
{
SPInt ofs = 0;
if (length != -1)
{
for (int i = 0; i < length; i++)
{
EncodeChar(pbuff, &ofs, pchar[i]);
}
}
else
{
for (int i = 0;; i++)
{
if (pchar[i] == 0)
break;
EncodeChar(pbuff, &ofs, pchar[i]);
}
}
pbuff[ofs] = 0;
}
UPInt OVR_STDCALL DecodeString(wchar_t *pbuff, const char* putf8str, SPInt bytesLen)
{
wchar_t *pbegin = pbuff;
if (bytesLen == -1)
{
while (1)
{
UInt32 ch = DecodeNextChar_Advance0(&putf8str);
if (ch == 0)
break;
else if (ch >= 0xFFFF)
ch = 0xFFFD;
*pbuff++ = wchar_t(ch);
}
}
else
{
const char* p = putf8str;
while ((p - putf8str) < bytesLen)
{
UInt32 ch = DecodeNextChar_Advance0(&p);
if (ch >= 0xFFFF)
ch = 0xFFFD;
*pbuff++ = wchar_t(ch);
}
}
*pbuff = 0;
return pbuff - pbegin;
}
#ifdef UTF8_UNIT_TEST
// Compile this test case with something like:
//
// gcc utf8.cpp -g -I.. -DUTF8_UNIT_TEST -lstdc++ -o utf8_test
//
// or
//
// cl utf8.cpp -Zi -Od -DUTF8_UNIT_TEST -I..
//
// If possible, try running the test program with the first arg
// pointing at the file:
//
// http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
//
// and examine the results by eye to make sure they are acceptable to
// you.
#include "base/utility.h"
#include <stdio.h>
bool check_equal(const char* utf8_in, const UInt32* ucs_in)
{
for (;;)
{
UInt32 next_ucs = *ucs_in++;
UInt32 next_ucs_from_utf8 = utf8::decode_next_unicode_character(&utf8_in);
if (next_ucs != next_ucs_from_utf8)
{
return false;
}
if (next_ucs == 0)
{
OVR_ASSERT(next_ucs_from_utf8 == 0);
break;
}
}
return true;
}
void log_ascii(const char* line)
{
for (;;)
{
unsigned char c = (unsigned char) *line++;
if (c == 0)
{
// End of line.
return;
}
else if (c != '\n'
&& (c < 32 || c > 127))
{
// Non-printable as plain ASCII.
printf("<0x%02X>", (int) c);
}
else
{
printf("%c", c);
}
}
}
void log_ucs(const UInt32* line)
{
for (;;)
{
UInt32 uc = *line++;
if (uc == 0)
{
// End of line.
return;
}
else if (uc != '\n'
&& (uc < 32 || uc > 127))
{
// Non-printable as plain ASCII.
printf("<U-%04X>", uc);
}
else
{
printf("%c", (char) uc);
}
}
}
// Simple canned test.
int main(int argc, const char* argv[])
{
{
const char* test8 = "Ignacio Castaño";
const UInt32 test32[] =
{
0x49, 0x67, 0x6E, 0x61, 0x63,
0x69, 0x6F, 0x20, 0x43, 0x61,
0x73, 0x74, 0x61, 0xF1, 0x6F,
0x00
};
OVR_ASSERT(check_equal(test8, test32));
}
// If user passed an arg, try reading the file as UTF-8 encoded text.
if (argc > 1)
{
const char* filename = argv[1];
FILE* fp = fopen(filename, "rb");
if (fp == NULL)
{
printf("Can't open file '%s'\n", filename);
return 1;
}
// Read lines from the file, encode/decode them, and highlight discrepancies.
const int LINE_SIZE = 200; // max line size
char line_buffer_utf8[LINE_SIZE];
char reencoded_utf8[6 * LINE_SIZE];
UInt32 line_buffer_ucs[LINE_SIZE];
int byte_counter = 0;
for (;;)
{
int c = fgetc(fp);
if (c == EOF)
{
// Done.
break;
}
line_buffer_utf8[byte_counter++] = c;
if (c == '\n' || byte_counter >= LINE_SIZE - 2)
{
// End of line. Process the line.
line_buffer_utf8[byte_counter++] = 0; // terminate.
// Decode into UCS.
const char* p = line_buffer_utf8;
UInt32* q = line_buffer_ucs;
for (;;)
{
UInt32 uc = UTF8Util::DecodeNextChar(&p);
*q++ = uc;
OVR_ASSERT(q < line_buffer_ucs + LINE_SIZE);
OVR_ASSERT(p < line_buffer_utf8 + LINE_SIZE);
if (uc == 0) break;
}
// Encode back into UTF-8.
q = line_buffer_ucs;
int index = 0;
for (;;)
{
UInt32 uc = *q++;
OVR_ASSERT(index < LINE_SIZE * 6 - 6);
int last_index = index;
UTF8Util::EncodeChar(reencoded_utf8, &index, uc);
OVR_ASSERT(index <= last_index + 6);
if (uc == 0) break;
}
// This can be useful for debugging.
#if 0
// Show the UCS and the re-encoded UTF-8.
log_ucs(line_buffer_ucs);
log_ascii(reencoded_utf8);
#endif // 0
OVR_ASSERT(check_equal(line_buffer_utf8, line_buffer_ucs));
OVR_ASSERT(check_equal(reencoded_utf8, line_buffer_ucs));
// Start next line.
byte_counter = 0;
}
}
fclose(fp);
}
return 0;
}
#endif // UTF8_UNIT_TEST
}} // namespace UTF8Util::OVR

View File

@ -0,0 +1,99 @@
/************************************************************************************
PublicHeader: OVR.h
Filename : OVR_UTF8Util.h
Content : UTF8 Unicode character encoding/decoding support
Created : September 19, 2012
Notes :
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_UTF8Util_h
#define OVR_UTF8Util_h
#include "OVR_Types.h"
namespace OVR { namespace UTF8Util {
//-----------------------------------------------------------------------------------
// *** UTF8 string length and indexing.
// Determines the length of UTF8 string in characters.
// If source length is specified (in bytes), null 0 character is counted properly.
SPInt OVR_STDCALL GetLength(const char* putf8str, SPInt length = -1);
// Gets a decoded UTF8 character at index; you can access up to the index returned
// by GetLength. 0 will be returned for out of bounds access.
UInt32 OVR_STDCALL GetCharAt(SPInt index, const char* putf8str, SPInt length = -1);
// Converts UTF8 character index into byte offset.
// -1 is returned if index was out of bounds.
SPInt OVR_STDCALL GetByteIndex(SPInt index, const char* putf8str, SPInt length = -1);
// *** 16-bit Unicode string Encoding/Decoding routines.
// Determines the number of bytes necessary to encode a string.
// Does not count the terminating 0 (null) character.
SPInt OVR_STDCALL GetEncodeStringSize(const wchar_t* pchar, SPInt length = -1);
// Encodes a unicode (UCS-2 only) string into a buffer. The size of buffer must be at
// least GetEncodeStringSize() + 1.
void OVR_STDCALL EncodeString(char *pbuff, const wchar_t* pchar, SPInt length = -1);
// Decode UTF8 into a wchar_t buffer. Must have GetLength()+1 characters available.
// Characters over 0xFFFF are replaced with 0xFFFD.
// Returns the length of resulting string (number of characters)
UPInt OVR_STDCALL DecodeString(wchar_t *pbuff, const char* putf8str, SPInt bytesLen = -1);
// *** Individual character Encoding/Decoding.
// Determined the number of bytes necessary to encode a UCS character.
int OVR_STDCALL GetEncodeCharSize(UInt32 ucsCharacter);
// Encodes the given UCS character into the given UTF-8 buffer.
// Writes the data starting at buffer[offset], and
// increments offset by the number of bytes written.
// May write up to 6 bytes, so make sure there's room in the buffer
void OVR_STDCALL EncodeChar(char* pbuffer, SPInt* poffset, UInt32 ucsCharacter);
// Return the next Unicode character in the UTF-8 encoded buffer.
// Invalid UTF-8 sequences produce a U+FFFD character as output.
// Advances *utf8_buffer past the character returned. Pointer advance
// occurs even if the terminating 0 character is hit, since that allows
// strings with middle '\0' characters to be supported.
UInt32 OVR_STDCALL DecodeNextChar_Advance0(const char** putf8Buffer);
// Safer version of DecodeNextChar, which doesn't advance pointer if
// null character is hit.
inline UInt32 DecodeNextChar(const char** putf8Buffer)
{
UInt32 ch = DecodeNextChar_Advance0(putf8Buffer);
if (ch == 0)
(*putf8Buffer)--;
return ch;
}
}} // OVR::UTF8Util
#endif

View File

@ -0,0 +1,925 @@
/************************************************************************************
Filename : OVR_CAPI.cpp
Content : Experimental simple C interface to the HMD - version 1.
Created : November 30, 2013
Authors : Michael Antonov
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_CAPI.h"
#include "Kernel/OVR_Timer.h"
#include "Kernel/OVR_Math.h"
#include "Kernel/OVR_System.h"
#include "OVR_Stereo.h"
#include "OVR_Profile.h"
#include "CAPI/CAPI_GlobalState.h"
#include "CAPI/CAPI_HMDState.h"
#include "CAPI/CAPI_FrameTimeManager.h"
using namespace OVR;
using namespace OVR::Util::Render;
//-------------------------------------------------------------------------------------
// Math
namespace OVR {
// ***** FovPort
// C-interop support: FovPort <-> ovrFovPort
FovPort::FovPort(const ovrFovPort &src)
: UpTan(src.UpTan), DownTan(src.DownTan), LeftTan(src.LeftTan), RightTan(src.RightTan)
{ }
FovPort::operator ovrFovPort () const
{
ovrFovPort result;
result.LeftTan = LeftTan;
result.RightTan = RightTan;
result.UpTan = UpTan;
result.DownTan = DownTan;
return result;
}
// Converts Fov Tan angle units to [-1,1] render target NDC space
Vector2f FovPort::TanAngleToRendertargetNDC(Vector2f const &tanEyeAngle)
{
ScaleAndOffset2D eyeToSourceNDC = CreateNDCScaleAndOffsetFromFov(*this);
return tanEyeAngle * eyeToSourceNDC.Scale + eyeToSourceNDC.Offset;
}
// ***** SensorState
SensorState::SensorState(const ovrSensorState& s)
{
Predicted = s.Predicted;
Recorded = s.Recorded;
Temperature = s.Temperature;
StatusFlags = s.StatusFlags;
}
SensorState::operator ovrSensorState() const
{
ovrSensorState result;
result.Predicted = Predicted;
result.Recorded = Recorded;
result.Temperature = Temperature;
result.StatusFlags = StatusFlags;
return result;
}
} // namespace OVR
//-------------------------------------------------------------------------------------
using namespace OVR::CAPI;
#ifdef __cplusplus
extern "C" {
#endif
// Used to generate projection from ovrEyeDesc::Fov
OVR_EXPORT ovrMatrix4f ovrMatrix4f_Projection(ovrFovPort fov, float znear, float zfar, ovrBool rightHanded)
{
return CreateProjection(rightHanded ? true : false, fov, znear, zfar);
}
OVR_EXPORT ovrMatrix4f ovrMatrix4f_OrthoSubProjection(ovrMatrix4f projection, ovrVector2f orthoScale,
float orthoDistance, float eyeViewAdjustX)
{
float orthoHorizontalOffset = eyeViewAdjustX / orthoDistance;
// Current projection maps real-world vector (x,y,1) to the RT.
// We want to find the projection that maps the range [-FovPixels/2,FovPixels/2] to
// the physical [-orthoHalfFov,orthoHalfFov]
// Note moving the offset from M[0][2]+M[1][2] to M[0][3]+M[1][3] - this means
// we don't have to feed in Z=1 all the time.
// The horizontal offset math is a little hinky because the destination is
// actually [-orthoHalfFov+orthoHorizontalOffset,orthoHalfFov+orthoHorizontalOffset]
// So we need to first map [-FovPixels/2,FovPixels/2] to
// [-orthoHalfFov+orthoHorizontalOffset,orthoHalfFov+orthoHorizontalOffset]:
// x1 = x0 * orthoHalfFov/(FovPixels/2) + orthoHorizontalOffset;
// = x0 * 2*orthoHalfFov/FovPixels + orthoHorizontalOffset;
// But then we need the sam mapping as the existing projection matrix, i.e.
// x2 = x1 * Projection.M[0][0] + Projection.M[0][2];
// = x0 * (2*orthoHalfFov/FovPixels + orthoHorizontalOffset) * Projection.M[0][0] + Projection.M[0][2];
// = x0 * Projection.M[0][0]*2*orthoHalfFov/FovPixels +
// orthoHorizontalOffset*Projection.M[0][0] + Projection.M[0][2];
// So in the new projection matrix we need to scale by Projection.M[0][0]*2*orthoHalfFov/FovPixels and
// offset by orthoHorizontalOffset*Projection.M[0][0] + Projection.M[0][2].
Matrix4f ortho;
ortho.M[0][0] = projection.M[0][0] * orthoScale.x;
ortho.M[0][1] = 0.0f;
ortho.M[0][2] = 0.0f;
ortho.M[0][3] = -projection.M[0][2] + ( orthoHorizontalOffset * projection.M[0][0] );
ortho.M[1][0] = 0.0f;
ortho.M[1][1] = -projection.M[1][1] * orthoScale.y; // Note sign flip (text rendering uses Y=down).
ortho.M[1][2] = 0.0f;
ortho.M[1][3] = -projection.M[1][2];
/*
if ( fabsf ( zNear - zFar ) < 0.001f )
{
ortho.M[2][0] = 0.0f;
ortho.M[2][1] = 0.0f;
ortho.M[2][2] = 0.0f;
ortho.M[2][3] = zFar;
}
else
{
ortho.M[2][0] = 0.0f;
ortho.M[2][1] = 0.0f;
ortho.M[2][2] = zFar / (zNear - zFar);
ortho.M[2][3] = (zFar * zNear) / (zNear - zFar);
}
*/
// MA: Undo effect of sign
ortho.M[2][0] = 0.0f;
ortho.M[2][1] = 0.0f;
//ortho.M[2][2] = projection.M[2][2] * projection.M[3][2] * -1.0f; // reverse right-handedness
ortho.M[2][2] = 0.0f;
ortho.M[2][3] = 0.0f;
//projection.M[2][3];
// No perspective correction for ortho.
ortho.M[3][0] = 0.0f;
ortho.M[3][1] = 0.0f;
ortho.M[3][2] = 0.0f;
ortho.M[3][3] = 1.0f;
return ortho;
}
OVR_EXPORT double ovr_GetTimeInSeconds()
{
return Timer::GetSeconds();
}
// Waits until the specified absolute time.
OVR_EXPORT double ovr_WaitTillTime(double absTime)
{
volatile int i;
double initialTime = ovr_GetTimeInSeconds();
double newTime = initialTime;
while(newTime < absTime)
{
for (int j = 0; j < 50; j++)
i = 0;
newTime = ovr_GetTimeInSeconds();
}
// How long we waited
return newTime - initialTime;
}
//-------------------------------------------------------------------------------------
// 1. Init/shutdown.
static ovrBool CAPI_SystemInitCalled = 0;
OVR_EXPORT ovrBool ovr_Initialize()
{
if (OVR::CAPI::GlobalState::pInstance)
return 1;
// We must set up the system for the plugin to work
if (!OVR::System::IsInitialized())
{
OVR::System::Init(OVR::Log::ConfigureDefaultLog(OVR::LogMask_All));
CAPI_SystemInitCalled = 1;
}
// Constructor detects devices
GlobalState::pInstance = new GlobalState;
return 1;
}
OVR_EXPORT void ovr_Shutdown()
{
if (!GlobalState::pInstance)
return;
delete GlobalState::pInstance;
GlobalState::pInstance = 0;
// We should clean up the system to be complete
if (CAPI_SystemInitCalled)
{
OVR::System::Destroy();
CAPI_SystemInitCalled = 0;
}
return;
}
// There is a thread safety issue with ovrHmd_Detect in that multiple calls from different
// threads can corrupt the global array state. This would lead to two problems:
// a) Create(index) enumerator may miss or overshoot items. Probably not a big deal
// as game logic can easily be written to only do Detect(s)/Creates in one place.
// The alternative would be to return list handle.
// b) TBD: Un-mutexed Detect access from two threads could lead to crash. We should
// probably check this.
//
OVR_EXPORT int ovrHmd_Detect()
{
if (!GlobalState::pInstance)
return 0;
return GlobalState::pInstance->EnumerateDevices();
}
// ovrHmd_Create us explicitly separated from StartSensor and Configure to allow creation of
// a relatively light-weight handle that would reference the device going forward and would
// survive future ovrHmd_Detect calls. That is once ovrHMD is returned, index is no longer
// necessary and can be changed by a ovrHmd_Detect call.
OVR_EXPORT ovrHmd ovrHmd_Create(int index)
{
if (!GlobalState::pInstance)
return 0;
Ptr<HMDDevice> device = *GlobalState::pInstance->CreateDevice(index);
if (!device)
return 0;
HMDState* hmds = new HMDState(device);
if (!hmds)
return 0;
return hmds;
}
OVR_EXPORT ovrHmd ovrHmd_CreateDebug(ovrHmdType type)
{
if (!GlobalState::pInstance)
return 0;
HMDState* hmds = new HMDState(type);
return hmds;
}
OVR_EXPORT void ovrHmd_Destroy(ovrHmd hmd)
{
if (!hmd)
return;
// TBD: Any extra shutdown?
HMDState* hmds = (HMDState*)hmd;
{ // Thread checker in its own scope, to avoid access after 'delete'.
// Essentially just checks that no other RenderAPI function is executing.
ThreadChecker::Scope checkScope(&hmds->RenderAPIThreadChecker, "ovrHmd_Destroy");
}
delete (HMDState*)hmd;
}
OVR_EXPORT const char* ovrHmd_GetLastError(ovrHmd hmd)
{
using namespace OVR;
if (!hmd)
{
if (!GlobalState::pInstance)
return "LibOVR not initialized.";
return GlobalState::pInstance->GetLastError();
}
HMDState* p = (HMDState*)hmd;
return p->GetLastError();
}
//-------------------------------------------------------------------------------------
// Returns capability bits that are enabled at this time; described by ovrHmdCapBits.
// Note that this value is different font ovrHmdDesc::Caps, which describes what
// capabilities are available.
OVR_EXPORT unsigned int ovrHmd_GetEnabledCaps(ovrHmd hmd)
{
HMDState* p = (HMDState*)hmd;
return p ? p->EnabledHmdCaps : 0;
}
// Modifies capability bits described by ovrHmdCapBits that can be modified,
// such as ovrHmd_LowPersistance.
OVR_EXPORT void ovrHmd_SetEnabledCaps(ovrHmd hmd, unsigned int capsBits)
{
HMDState* p = (HMDState*)hmd;
if (p)
p->SetEnabledHmdCaps(capsBits);
}
//-------------------------------------------------------------------------------------
// *** Sensor
// Sensor APIs are separated from Create & Configure for several reasons:
// - They need custom parameters that control allocation of heavy resources
// such as Vision tracking, which you don't want to create unless necessary.
// - A game may want to switch some sensor settings based on user input,
// or at lease enable/disable features such as Vision for debugging.
// - The same or syntactically similar sensor interface is likely to be used if we
// introduce controllers.
//
// - Sensor interface functions are all Thread-safe, unlike the frame/render API
// functions that have different rules (all frame access functions
// must be on render thread)
OVR_EXPORT ovrBool ovrHmd_StartSensor(ovrHmd hmd, unsigned int supportedCaps, unsigned int requiredCaps)
{
HMDState* p = (HMDState*)hmd;
// TBD: Decide if we null-check arguments.
return p->StartSensor(supportedCaps, requiredCaps);
}
OVR_EXPORT void ovrHmd_StopSensor(ovrHmd hmd)
{
HMDState* p = (HMDState*)hmd;
p->StopSensor();
}
OVR_EXPORT void ovrHmd_ResetSensor(ovrHmd hmd)
{
HMDState* p = (HMDState*)hmd;
p->ResetSensor();
}
OVR_EXPORT ovrSensorState ovrHmd_GetSensorState(ovrHmd hmd, double absTime)
{
HMDState* p = (HMDState*)hmd;
return p->PredictedSensorState(absTime);
}
// Returns information about a sensor. Only valid after SensorStart.
OVR_EXPORT ovrBool ovrHmd_GetSensorDesc(ovrHmd hmd, ovrSensorDesc* descOut)
{
HMDState* p = (HMDState*)hmd;
return p->GetSensorDesc(descOut) ? 1 : 0;
}
//-------------------------------------------------------------------------------------
// *** General Setup
OVR_EXPORT void ovrHmd_GetDesc(ovrHmd hmd, ovrHmdDesc* desc)
{
HMDState* hmds = (HMDState*)hmd;
*desc = hmds->RenderState.GetDesc();
desc->Handle = hmd;
}
// Per HMD -> calculateIdealPixelSize
OVR_EXPORT ovrSizei ovrHmd_GetFovTextureSize(ovrHmd hmd, ovrEyeType eye, ovrFovPort fov,
float pixelsPerDisplayPixel)
{
if (!hmd) return Sizei(0);
HMDState* hmds = (HMDState*)hmd;
return hmds->RenderState.GetFOVTextureSize(eye, fov, pixelsPerDisplayPixel);
}
//-------------------------------------------------------------------------------------
OVR_EXPORT
ovrBool ovrHmd_ConfigureRendering( ovrHmd hmd,
const ovrRenderAPIConfig* apiConfig,
unsigned int distortionCaps,
const ovrFovPort eyeFovIn[2],
ovrEyeRenderDesc eyeRenderDescOut[2] )
{
if (!hmd) return 0;
return ((HMDState*)hmd)->ConfigureRendering(eyeRenderDescOut, eyeFovIn,
apiConfig, distortionCaps);
}
// TBD: MA - Deprecated, need alternative
void ovrHmd_SetVsync(ovrHmd hmd, ovrBool vsync)
{
if (!hmd) return;
return ((HMDState*)hmd)->TimeManager.SetVsync(vsync? true : false);
}
OVR_EXPORT ovrFrameTiming ovrHmd_BeginFrame(ovrHmd hmd, unsigned int frameIndex)
{
HMDState* hmds = (HMDState*)hmd;
if (!hmds)
{
ovrFrameTiming f;
memset(&f, 0, sizeof(f));
return f;
}
// Check: Proper configure and threading state for the call.
hmds->checkRenderingConfigured("ovrHmd_BeginFrame");
OVR_ASSERT_LOG(hmds->BeginFrameCalled == false, ("ovrHmd_BeginFrame called multiple times."));
ThreadChecker::Scope checkScope(&hmds->RenderAPIThreadChecker, "ovrHmd_BeginFrame");
hmds->BeginFrameCalled = true;
hmds->BeginFrameThreadId = OVR::GetCurrentThreadId();
return ovrHmd_BeginFrameTiming(hmd, frameIndex);
}
// Renders textures to frame buffer
OVR_EXPORT void ovrHmd_EndFrame(ovrHmd hmd)
{
HMDState* hmds = (HMDState*)hmd;
if (!hmds) return;
// Debug state checks: Must be in BeginFrame, on the same thread.
hmds->checkBeginFrameScope("ovrHmd_EndFrame");
ThreadChecker::Scope checkScope(&hmds->RenderAPIThreadChecker, "ovrHmd_EndFrame");
// TBD: Move directly into renderer
bool dk2LatencyTest = (hmds->HMDInfo.HmdType == HmdType_DK2) &&
(hmds->EnabledHmdCaps & ovrHmdCap_LatencyTest);
if (dk2LatencyTest)
{
hmds->LatencyTest2DrawColor[0] = hmds->TimeManager.GetFrameLatencyTestDrawColor();
hmds->LatencyTest2DrawColor[1] = hmds->LatencyTest2DrawColor[0];
hmds->LatencyTest2DrawColor[2] = hmds->LatencyTest2DrawColor[0];
}
if (hmds->pRenderer)
{
hmds->pRenderer->SaveGraphicsState();
hmds->pRenderer->EndFrame(true,
hmds->LatencyTestActive ? hmds->LatencyTestDrawColor : NULL,
// MA: Use this color since we are running DK2 test all the time.
dk2LatencyTest ? hmds->LatencyTest2DrawColor : 0
//hmds->LatencyTest2Active ? hmds->LatencyTest2DrawColor : NULL
);
hmds->pRenderer->RestoreGraphicsState();
}
// Call after present
ovrHmd_EndFrameTiming(hmd);
if (dk2LatencyTest)
{
hmds->TimeManager.UpdateFrameLatencyTrackingAfterEndFrame(
hmds->LatencyTest2DrawColor[0], hmds->LatencyUtil2.GetLocklessState());
}
// Out of BeginFrame
hmds->BeginFrameThreadId = 0;
hmds->BeginFrameCalled = false;
}
OVR_EXPORT ovrPosef ovrHmd_BeginEyeRender(ovrHmd hmd, ovrEyeType eye)
{
HMDState* hmds = (HMDState*)hmd;
if (!hmds) return ovrPosef();
return hmds->BeginEyeRender(eye);
}
OVR_EXPORT void ovrHmd_EndEyeRender(ovrHmd hmd, ovrEyeType eye,
ovrPosef renderPose, ovrTexture* eyeTexture)
{
HMDState* hmds = (HMDState*)hmd;
if (!hmds) return;
hmds->EndEyeRender(eye, renderPose, eyeTexture);
}
//-------------------------------------------------------------------------------------
// ***** Frame Timing logic
OVR_EXPORT ovrFrameTiming ovrHmd_GetFrameTiming(ovrHmd hmd, unsigned int frameIndex)
{
ovrFrameTiming f;
memset(&f, 0, sizeof(f));
HMDState* hmds = (HMDState*)hmd;
if (hmds)
{
FrameTimeManager::Timing frameTiming = hmds->TimeManager.GetFrameTiming(frameIndex);
f.ThisFrameSeconds = frameTiming.ThisFrameTime;
f.NextFrameSeconds = frameTiming.NextFrameTime;
f.TimewarpPointSeconds = frameTiming.TimewarpPointTime;
f.ScanoutMidpointSeconds= frameTiming.MidpointTime;
f.EyeScanoutSeconds[0] = frameTiming.EyeRenderTimes[0];
f.EyeScanoutSeconds[1] = frameTiming.EyeRenderTimes[1];
// Compute DeltaSeconds.
f.DeltaSeconds = (hmds->LastGetFrameTimeSeconds == 0.0f) ? 0.0f :
(float) (f.ThisFrameSeconds - hmds->LastFrameTimeSeconds);
hmds->LastGetFrameTimeSeconds = f.ThisFrameSeconds;
if (f.DeltaSeconds > 1.0f)
f.DeltaSeconds = 1.0f;
}
return f;
}
OVR_EXPORT ovrFrameTiming ovrHmd_BeginFrameTiming(ovrHmd hmd, unsigned int frameIndex)
{
ovrFrameTiming f;
memset(&f, 0, sizeof(f));
HMDState* hmds = (HMDState*)hmd;
if (!hmds) return f;
// Check: Proper state for the call.
OVR_ASSERT_LOG(hmds->BeginFrameTimingCalled == false,
("ovrHmd_BeginFrameTiming called multiple times."));
hmds->BeginFrameTimingCalled = true;
double thisFrameTime = hmds->TimeManager.BeginFrame(frameIndex);
const FrameTimeManager::Timing &frameTiming = hmds->TimeManager.GetFrameTiming();
f.ThisFrameSeconds = thisFrameTime;
f.NextFrameSeconds = frameTiming.NextFrameTime;
f.TimewarpPointSeconds = frameTiming.TimewarpPointTime;
f.ScanoutMidpointSeconds= frameTiming.MidpointTime;
f.EyeScanoutSeconds[0] = frameTiming.EyeRenderTimes[0];
f.EyeScanoutSeconds[1] = frameTiming.EyeRenderTimes[1];
// Compute DeltaSeconds.
f.DeltaSeconds = (hmds->LastFrameTimeSeconds == 0.0f) ? 0.0f :
(float) (thisFrameTime - hmds->LastFrameTimeSeconds);
hmds->LastFrameTimeSeconds = thisFrameTime;
if (f.DeltaSeconds > 1.0f)
f.DeltaSeconds = 1.0f;
return f;
}
OVR_EXPORT void ovrHmd_EndFrameTiming(ovrHmd hmd)
{
HMDState* hmds = (HMDState*)hmd;
if (!hmds) return;
// Debug state checks: Must be in BeginFrameTiming, on the same thread.
hmds->checkBeginFrameTimingScope("ovrHmd_EndTiming");
// MA TBD: Correct chek or not?
// ThreadChecker::Scope checkScope(&hmds->RenderAPIThreadChecker, "ovrHmd_EndFrame");
hmds->TimeManager.EndFrame();
hmds->BeginFrameTimingCalled = false;
}
OVR_EXPORT void ovrHmd_ResetFrameTiming(ovrHmd hmd, unsigned int frameIndex)
{
HMDState* hmds = (HMDState*)hmd;
if (!hmds) return;
hmds->TimeManager.ResetFrameTiming(frameIndex,
false,
hmds->RenderingConfigured);
hmds->LastFrameTimeSeconds = 0.0;
hmds->LastGetFrameTimeSeconds = 0.0;
}
OVR_EXPORT ovrPosef ovrHmd_GetEyePose(ovrHmd hmd, ovrEyeType eye)
{
HMDState* hmds = (HMDState*)hmd;
if (!hmds) return ovrPosef();
hmds->checkBeginFrameTimingScope("ovrHmd_GetEyePose");
return hmds->TimeManager.GetEyePredictionPose(hmd, eye);
}
OVR_EXPORT void ovrHmd_GetEyeTimewarpMatrices(ovrHmd hmd, ovrEyeType eye,
ovrPosef renderPose, ovrMatrix4f twmOut[2])
{
HMDState* hmds = (HMDState*)hmd;
if (!hmd)
return;
// Debug checks: BeginFrame was called, on the same thread.
hmds->checkBeginFrameTimingScope("ovrHmd_GetTimewarpEyeMatrices");
hmds->TimeManager.GetTimewarpMatrices(hmd, eye, renderPose, twmOut);
/*
// MA: Took this out because new latency test approach just sames
// the sample times in FrameTimeManager.
// TODO: if no timewarp, then test latency in begin eye render
if (eye == 0)
{
hmds->ProcessLatencyTest2(hmds->LatencyTest2DrawColor, -1.0f);
}
*/
}
OVR_EXPORT ovrEyeRenderDesc ovrHmd_GetRenderDesc(ovrHmd hmd,
ovrEyeType eyeType, ovrFovPort fov)
{
ovrEyeRenderDesc erd;
HMDState* hmds = (HMDState*)hmd;
if (!hmds)
{
memset(&erd, 0, sizeof(erd));
return erd;
}
return hmds->RenderState.calcRenderDesc(eyeType, fov);
}
#define OVR_OFFSET_OF(s, field) ((size_t)&((s*)0)->field)
// Generate distortion mesh per eye.
// scaleAndOffsetOut - this will be needed for shader
OVR_EXPORT ovrBool ovrHmd_CreateDistortionMesh( ovrHmd hmd,
ovrEyeType eyeType, ovrFovPort fov,
unsigned int distortionCaps,
ovrDistortionMesh *meshData )
{
if (!meshData)
return 0;
HMDState* hmds = (HMDState*)hmd;
// Not used now, but Chromatic flag or others could possibly be checked for in the future.
OVR_UNUSED1(distortionCaps);
#if defined (OVR_OS_WIN32)
// TBD: We should probably be sharing some C API structures with C++ to avoid this mess...
OVR_COMPILER_ASSERT(sizeof(DistortionMeshVertexData) == sizeof(ovrDistortionVertex));
OVR_COMPILER_ASSERT(OVR_OFFSET_OF(DistortionMeshVertexData, ScreenPosNDC) == OVR_OFFSET_OF(ovrDistortionVertex, Pos));
OVR_COMPILER_ASSERT(OVR_OFFSET_OF(DistortionMeshVertexData, TimewarpLerp) == OVR_OFFSET_OF(ovrDistortionVertex, TimeWarpFactor));
OVR_COMPILER_ASSERT(OVR_OFFSET_OF(DistortionMeshVertexData, Shade) == OVR_OFFSET_OF(ovrDistortionVertex, VignetteFactor));
OVR_COMPILER_ASSERT(OVR_OFFSET_OF(DistortionMeshVertexData, TanEyeAnglesR) == OVR_OFFSET_OF(ovrDistortionVertex, TexR));
OVR_COMPILER_ASSERT(OVR_OFFSET_OF(DistortionMeshVertexData, TanEyeAnglesG) == OVR_OFFSET_OF(ovrDistortionVertex, TexG));
OVR_COMPILER_ASSERT(OVR_OFFSET_OF(DistortionMeshVertexData, TanEyeAnglesB) == OVR_OFFSET_OF(ovrDistortionVertex, TexB));
#endif
// *** Calculate a part of "StereoParams" needed for mesh generation
// Note that mesh distortion generation is invariant of RenderTarget UVs, allowing
// render target size and location to be changed after the fact dynamically.
// eyeToSourceUV is computed here for convenience, so that users don't need
// to call ovrHmd_GetRenderScaleAndOffset unless changing RT dynamically.
const HmdRenderInfo& hmdri = hmds->RenderState.RenderInfo;
StereoEye stereoEye = (eyeType == ovrEye_Left) ? StereoEye_Left : StereoEye_Right;
const DistortionRenderDesc& distortion = hmds->RenderState.Distortion[eyeType];
// Find the mapping from TanAngle space to target NDC space.
ScaleAndOffset2D eyeToSourceNDC = CreateNDCScaleAndOffsetFromFov(fov);
int triangleCount = 0;
int vertexCount = 0;
DistortionMeshCreate((DistortionMeshVertexData**)&meshData->pVertexData, (UInt16**)&meshData->pIndexData,
&vertexCount, &triangleCount,
(stereoEye == StereoEye_Right),
hmdri, distortion, eyeToSourceNDC);
if (meshData->pVertexData)
{
// Convert to index
meshData->IndexCount = triangleCount * 3;
meshData->VertexCount = vertexCount;
return 1;
}
return 0;
}
// Frees distortion mesh allocated by ovrHmd_GenerateDistortionMesh. meshData elements
// are set to null and 0s after the call.
OVR_EXPORT void ovrHmd_DestroyDistortionMesh(ovrDistortionMesh* meshData)
{
if (meshData->pVertexData)
DistortionMeshDestroy((DistortionMeshVertexData*)meshData->pVertexData,
meshData->pIndexData);
meshData->pVertexData = 0;
meshData->pIndexData = 0;
meshData->VertexCount = 0;
meshData->IndexCount = 0;
}
// Computes updated 'uvScaleOffsetOut' to be used with a distortion if render target size or
// viewport changes after the fact. This can be used to adjust render size every frame, if desired.
OVR_EXPORT void ovrHmd_GetRenderScaleAndOffset( ovrFovPort fov,
ovrSizei textureSize, ovrRecti renderViewport,
ovrVector2f uvScaleOffsetOut[2] )
{
// Find the mapping from TanAngle space to target NDC space.
ScaleAndOffset2D eyeToSourceNDC = CreateNDCScaleAndOffsetFromFov(fov);
// Find the mapping from TanAngle space to textureUV space.
ScaleAndOffset2D eyeToSourceUV = CreateUVScaleAndOffsetfromNDCScaleandOffset(
eyeToSourceNDC,
renderViewport, textureSize );
uvScaleOffsetOut[0] = eyeToSourceUV.Scale;
uvScaleOffsetOut[1] = eyeToSourceUV.Offset;
}
//-------------------------------------------------------------------------------------
// ***** Latency Test interface
OVR_EXPORT ovrBool ovrHmd_GetLatencyTestDrawColor(ovrHmd hmd, unsigned char rgbColorOut[3])
{
HMDState* p = (HMDState*)hmd;
rgbColorOut[0] = p->LatencyTestDrawColor[0];
rgbColorOut[1] = p->LatencyTestDrawColor[1];
rgbColorOut[2] = p->LatencyTestDrawColor[2];
return p->LatencyTestActive;
}
OVR_EXPORT const char* ovrHmd_GetLatencyTestResult(ovrHmd hmd)
{
HMDState* p = (HMDState*)hmd;
return p->LatencyUtil.GetResultsString();
}
OVR_EXPORT double ovrHmd_GetMeasuredLatencyTest2(ovrHmd hmd)
{
HMDState* p = (HMDState*)hmd;
// MA Test
float latencies[3];
p->TimeManager.GetLatencyTimings(latencies);
return latencies[2];
// return p->LatencyUtil2.GetMeasuredLatency();
}
// -----------------------------------------------------------------------------------
// ***** Property Access
OVR_EXPORT float ovrHmd_GetFloat(ovrHmd hmd, const char* propertyName, float defaultVal)
{
HMDState* hmds = (HMDState*)hmd;
if (hmds)
{
return hmds->getFloatValue(propertyName, defaultVal);
}
return defaultVal;
}
OVR_EXPORT ovrBool ovrHmd_SetFloat(ovrHmd hmd, const char* propertyName, float value)
{
HMDState* hmds = (HMDState*)hmd;
if (hmds)
{
return hmds->setFloatValue(propertyName, value);
}
return false;
}
OVR_EXPORT unsigned int ovrHmd_GetFloatArray(ovrHmd hmd, const char* propertyName,
float values[], unsigned int arraySize)
{
HMDState* hmds = (HMDState*)hmd;
if (hmds)
{
return hmds->getFloatArray(propertyName, values, arraySize);
}
return 0;
}
// Modify float[] property; false if property doesn't exist or is readonly.
OVR_EXPORT ovrBool ovrHmd_SetFloatArray(ovrHmd hmd, const char* propertyName,
float values[], unsigned int arraySize)
{
HMDState* hmds = (HMDState*)hmd;
if (hmds)
{
return hmds->setFloatArray(propertyName, values, arraySize);
}
return 0;
}
OVR_EXPORT const char* ovrHmd_GetString(ovrHmd hmd, const char* propertyName,
const char* defaultVal)
{
HMDState* hmds = (HMDState*)hmd;
if (hmds)
{
return hmds->getString(propertyName, defaultVal);
}
return defaultVal;
}
/* Not needed yet.
// Get array of strings, i.e. const char* [] property.
// Returns the number of elements filled in, 0 if property doesn't exist.
// Maximum of arraySize elements will be written.
// String memory is guaranteed to exist until next call to GetString or GetStringArray, or HMD is destroyed.
OVR_EXPORT
unsigned int ovrHmd_GetStringArray(ovrHmd hmd, const char* propertyName,
const char* values[], unsigned int arraySize)
{
HMDState* hmds = (HMDState*)hmd;
if (hmds && hmds->pHMD && arraySize)
{
Profile* p = hmds->pHMD->GetProfile();
hmds->LastGetStringValue[0] = 0;
if (p && p->GetValue(propertyName, hmds->LastGetStringValue, sizeof(hmds->LastGetStringValue)))
{
values[0] = hmds->LastGetStringValue;
return 1;
}
}
return 0;
}
*/
// Returns array size of a property, 0 if property doesn't exist.
// Can be used to check existence of a property.
OVR_EXPORT unsigned int ovrHmd_GetArraySize(ovrHmd hmd, const char* propertyName)
{
HMDState* hmds = (HMDState*)hmd;
if (hmds && hmds->pHMD)
{
// For now, just access the profile.
Profile* p = hmds->pHMD->GetProfile();
if (p)
return p->GetNumValues(propertyName);
}
return 0;
}
#ifdef __cplusplus
} // extern "C"
#endif
//-------------------------------------------------------------------------------------
// ****** Special access for VRConfig
// Return the sensor fusion object for the purposes of magnetometer calibration. The
// function is private and is only exposed through VRConfig header declarations
OVR::SensorFusion* ovrHmd_GetSensorFusion(ovrHmd hmd)
{
HMDState* p = (HMDState*)hmd;
return &p->SFusion;
}

View File

@ -0,0 +1,790 @@
/************************************************************************************
Filename : OVR_CAPI.h
Content : C Interface to Oculus sensors and rendering.
Created : November 23, 2013
Authors : Michael Antonov
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_CAPI_h
#define OVR_CAPI_h
#include <stdint.h>
typedef char ovrBool;
//-----------------------------------------------------------------------------------
// ***** OVR_EXPORT definition
#if !defined(OVR_EXPORT)
#if defined(WIN32)
#define OVR_EXPORT __declspec(dllexport)
#else
#define OVR_EXPORT
#endif
#endif
//-----------------------------------------------------------------------------------
// ***** Simple Math Structures
// 2D integer
typedef struct ovrVector2i_
{
int x, y;
} ovrVector2i;
typedef struct ovrSizei_
{
int w, h;
} ovrSizei;
typedef struct ovrRecti_
{
ovrVector2i Pos;
ovrSizei Size;
} ovrRecti;
// 3D
typedef struct ovrQuatf_
{
float x, y, z, w;
} ovrQuatf;
typedef struct ovrVector2f_
{
float x, y;
} ovrVector2f;
typedef struct ovrVector3f_
{
float x, y, z;
} ovrVector3f;
typedef struct ovrMatrix4f_
{
float M[4][4];
} ovrMatrix4f;
// Position and orientation together.
typedef struct ovrPosef_
{
ovrQuatf Orientation;
ovrVector3f Position;
} ovrPosef;
// Full pose (rigid body) configuration with first and second derivatives.
typedef struct ovrPoseStatef_
{
ovrPosef Pose;
ovrVector3f AngularVelocity;
ovrVector3f LinearVelocity;
ovrVector3f AngularAcceleration;
ovrVector3f LinearAcceleration;
double TimeInSeconds; // Absolute time of this state sample.
} ovrPoseStatef;
// Field Of View (FOV) in tangent of the angle units.
// As an example, for a standard 90 degree vertical FOV, we would
// have: { UpTan = tan(90 degrees / 2), DownTan = tan(90 degrees / 2) }.
typedef struct ovrFovPort_
{
float UpTan;
float DownTan;
float LeftTan;
float RightTan;
} ovrFovPort;
//-----------------------------------------------------------------------------------
// ***** HMD Types
// Enumerates all HMD types that we support.
typedef enum
{
ovrHmd_None = 0,
ovrHmd_DK1 = 3,
ovrHmd_DKHD = 4,
ovrHmd_CrystalCoveProto = 5,
ovrHmd_DK2 = 6,
ovrHmd_Other // Some HMD other then the one in the enumeration.
} ovrHmdType;
// HMD capability bits reported by device.
//
typedef enum
{
// Read-only flags.
ovrHmdCap_Present = 0x0001, // This HMD exists (as opposed to being unplugged).
ovrHmdCap_Available = 0x0002, // HMD and is sensor is available for use
// (if not owned by another app).
// These flags are intended for use with the new driver display mode.
/*
ovrHmdCap_ExtendDesktop = 0x0004, // Read only, means display driver is in compatibility mode.
ovrHmdCap_DisplayOff = 0x0040, // Turns off Oculus HMD screen and output.
ovrHmdCap_NoMirrorToWindow = 0x2000, // Disables mirrowing of HMD output to the window;
// may improve rendering performance slightly.
*/
// Modifiable flags (through ovrHmd_SetEnabledCaps).
ovrHmdCap_LowPersistence = 0x0080, // Supports low persistence mode.
ovrHmdCap_LatencyTest = 0x0100, // Supports pixel reading for continuous latency testing.
ovrHmdCap_DynamicPrediction = 0x0200, // Adjust prediction dynamically based on DK2 Latency.
// Support rendering without VSync for debugging
ovrHmdCap_NoVSync = 0x1000,
ovrHmdCap_NoRestore = 0x4000,
// These bits can be modified by ovrHmd_SetEnabledCaps.
ovrHmdCap_Writable_Mask = 0x1380
} ovrHmdCaps;
// Sensor capability bits reported by device.
// Used with ovrHmd_StartSensor.
typedef enum
{
ovrSensorCap_Orientation = 0x0010, // Supports orientation tracking (IMU).
ovrSensorCap_YawCorrection = 0x0020, // Supports yaw correction through magnetometer or other means.
ovrSensorCap_Position = 0x0040, // Supports positional tracking.
} ovrSensorCaps;
// Distortion capability bits reported by device.
// Used with ovrHmd_ConfigureRendering and ovrHmd_CreateDistortionMesh.
typedef enum
{
ovrDistortionCap_Chromatic = 0x01, // Supports chromatic aberration correction.
ovrDistortionCap_TimeWarp = 0x02, // Supports timewarp.
ovrDistortionCap_Vignette = 0x08 // Supports vignetting around the edges of the view.
} ovrDistortionCaps;
// Specifies which eye is being used for rendering.
// This type explicitly does not include a third "NoStereo" option, as such is
// not required for an HMD-centered API.
typedef enum
{
ovrEye_Left = 0,
ovrEye_Right = 1,
ovrEye_Count = 2
} ovrEyeType;
// Handle to HMD; returned by ovrHmd_Create.
typedef struct ovrHmdStruct* ovrHmd;
// This is a complete descriptor of the HMD.
typedef struct ovrHmdDesc_
{
ovrHmd Handle; // Handle of this HMD.
ovrHmdType Type;
// Name string describing the product: "Oculus Rift DK1", etc.
const char* ProductName;
const char* Manufacturer;
// Capability bits described by ovrHmdCaps.
unsigned int HmdCaps;
// Capability bits described by ovrSensorCaps.
unsigned int SensorCaps;
// Capability bits described by ovrDistortionCaps.
unsigned int DistortionCaps;
// Resolution of the entire HMD screen (for both eyes) in pixels.
ovrSizei Resolution;
// Where monitor window should be on screen or (0,0).
ovrVector2i WindowsPos;
// These define the recommended and maximum optical FOVs for the HMD.
ovrFovPort DefaultEyeFov[ovrEye_Count];
ovrFovPort MaxEyeFov[ovrEye_Count];
// Preferred eye rendering order for best performance.
// Can help reduce latency on sideways-scanned screens.
ovrEyeType EyeRenderOrder[ovrEye_Count];
// Display that HMD should present on.
// TBD: It may be good to remove this information relying on WidowPos instead.
// Ultimately, we may need to come up with a more convenient alternative,
// such as a API-specific functions that return adapter, ot something that will
// work with our monitor driver.
// Windows: "\\\\.\\DISPLAY3", etc. Can be used in EnumDisplaySettings/CreateDC.
const char* DisplayDeviceName;
// MacOS
int DisplayId;
} ovrHmdDesc;
// Describes the type of positional tracking being done.
/*
typedef enum
{
ovrPose_None,
ovrPose_HeadModel,
ovrPose_Positional
} ovrPoseType;
*/
// Bit flags describing the current status of sensor tracking.
typedef enum
{
ovrStatus_OrientationTracked = 0x0001, // Orientation is currently tracked (connected and in use).
ovrStatus_PositionTracked = 0x0002, // Position is currently tracked (FALSE if out of range).
ovrStatus_PositionConnected = 0x0020, // Position tracking HW is connected.
ovrStatus_HmdConnected = 0x0080 // HMD Display is available & connected.
} ovrStatusBits;
// State of the sensor at a given absolute time.
typedef struct ovrSensorState_
{
// Predicted pose configuration at requested absolute time.
// One can determine the time difference between predicted and actual
// readings by comparing ovrPoseState.TimeInSeconds.
ovrPoseStatef Predicted;
// Actual recorded pose configuration based on the sensor sample at a
// moment closest to the requested time.
ovrPoseStatef Recorded;
// Sensor temperature reading, in degrees Celsius, as sample time.
float Temperature;
// Sensor status described by ovrStatusBits.
unsigned int StatusFlags;
} ovrSensorState;
// For now.
// TBD: Decide if this becomes a part of HMDDesc
typedef struct ovrSensorDesc_
{
// HID Vendor and ProductId of the device.
short VendorId;
short ProductId;
// Sensor (and display) serial number.
char SerialNumber[24];
} ovrSensorDesc;
// Frame data reported by ovrHmd_BeginFrameTiming().
typedef struct ovrFrameTiming_
{
// The amount of time that has passed since the previous frame returned
// BeginFrameSeconds value, usable for movement scaling.
// This will be clamped to no more than 0.1 seconds to prevent
// excessive movement after pauses for loading or initialization.
float DeltaSeconds;
// It is generally expected that the following hold:
// ThisFrameSeconds < TimewarpPointSeconds < NextFrameSeconds <
// EyeScanoutSeconds[EyeOrder[0]] <= ScanoutMidpointSeconds <= EyeScanoutSeconds[EyeOrder[1]]
// Absolute time value of when rendering of this frame began or is expected to
// begin; generally equal to NextFrameSeconds of the previous frame. Can be used
// for animation timing.
double ThisFrameSeconds;
// Absolute point when IMU expects to be sampled for this frame.
double TimewarpPointSeconds;
// Absolute time when frame Present + GPU Flush will finish, and the next frame starts.
double NextFrameSeconds;
// Time when when half of the screen will be scanned out. Can be passes as a prediction
// value to ovrHmd_GetSensorState() go get general orientation.
double ScanoutMidpointSeconds;
// Timing points when each eye will be scanned out to display. Used for rendering each eye.
double EyeScanoutSeconds[2];
} ovrFrameTiming;
// Rendering information for each eye, computed by either ovrHmd_ConfigureRendering().
// or ovrHmd_GetRenderDesc() based on the specified Fov.
// Note that the rendering viewport is not included here as it can be
// specified separately and modified per frame though:
// (a) calling ovrHmd_GetRenderScaleAndOffset with game-rendered api,
// or (b) passing different values in ovrTexture in case of SDK-rendered distortion.
typedef struct ovrEyeRenderDesc_
{
ovrEyeType Eye;
ovrFovPort Fov;
ovrRecti DistortedViewport; // Distortion viewport
ovrVector2f PixelsPerTanAngleAtCenter; // How many display pixels will fit in tan(angle) = 1.
ovrVector3f ViewAdjust; // Translation to be applied to view matrix.
} ovrEyeRenderDesc;
//-----------------------------------------------------------------------------------
// ***** Platform-independent Rendering Configuration
// These types are used to hide platform-specific details when passing
// render device, OS and texture data to the APIs.
//
// The benefit of having these wrappers vs. platform-specific API functions is
// that they allow game glue code to be portable. A typical example is an
// engine that has multiple back ends, say GL and D3D. Portable code that calls
// these back ends may also use LibOVR. To do this, back ends can be modified
// to return portable types such as ovrTexture and ovrRenderAPIConfig.
typedef enum
{
ovrRenderAPI_None,
ovrRenderAPI_OpenGL,
ovrRenderAPI_Android_GLES, // May include extra native window pointers, etc.
ovrRenderAPI_D3D9,
ovrRenderAPI_D3D10,
ovrRenderAPI_D3D11,
ovrRenderAPI_Count
} ovrRenderAPIType;
// Platform-independent part of rendering API-configuration data.
// It is a part of ovrRenderAPIConfig, passed to ovrHmd_Configure.
typedef struct ovrRenderAPIConfigHeader_
{
ovrRenderAPIType API;
ovrSizei RTSize;
int Multisample;
} ovrRenderAPIConfigHeader;
typedef struct ovrRenderAPIConfig_
{
ovrRenderAPIConfigHeader Header;
uintptr_t PlatformData[8];
} ovrRenderAPIConfig;
// Platform-independent part of eye texture descriptor.
// It is a part of ovrTexture, passed to ovrHmd_EndFrame.
// - If RenderViewport is all zeros, will be used.
typedef struct ovrTextureHeader_
{
ovrRenderAPIType API;
ovrSizei TextureSize;
ovrRecti RenderViewport; // Pixel viewport in texture that holds eye image.
} ovrTextureHeader;
typedef struct ovrTexture_
{
ovrTextureHeader Header;
uintptr_t PlatformData[8];
} ovrTexture;
// -----------------------------------------------------------------------------------
// ***** API Interfaces
// Basic steps to use the API:
//
// Setup:
// 1. ovrInitialize();
// 2. ovrHMD hmd = ovrHmd_Create(0); ovrHmd_GetDesc(hmd, &hmdDesc);
// 3. Use hmdDesc and ovrHmd_GetFovTextureSize() to determine graphics configuration.
// 4. Call ovrHmd_StartSensor() to configure and initialize tracking.
// 5. Call ovrHmd_ConfigureRendering() to setup graphics for SDK rendering,
// which is the preferred approach.
// Please refer to "Game-Side Rendering" below if you prefer to do that instead.
// 5. Allocate textures as needed.
//
// Game Loop:
// 6. Call ovrHmd_BeginFrame() to get frame timing and orientation information.
// 7. Render each eye in between ovrHmd_BeginEyeRender and ovrHmd_EndEyeRender calls,
// providing the result texture to the API.
// 8. Call ovrHmd_EndFrame() to render distorted textures to the back buffer
// and present them on the Hmd.
//
// Shutdown:
// 9. ovrHmd_Destroy(hmd)
// 10. ovr_Shutdown()
//
#ifdef __cplusplus
extern "C" {
#endif
// Library init/shutdown, must be called around all other OVR code.
// No other functions calls are allowed before ovr_Initialize succeeds or after ovr_Shutdown.
OVR_EXPORT ovrBool ovr_Initialize();
OVR_EXPORT void ovr_Shutdown();
// Detects or re-detects HMDs and reports the total number detected.
// Users can get information about each HMD by calling ovrHmd_Create with an index.
OVR_EXPORT int ovrHmd_Detect();
// Creates a handle to an HMD and optionally fills in data about it.
// Index can [0 .. ovrHmd_Detect()-1]; index mappings can cange after each ovrHmd_Detect call.
// If not null, returned handle must be freed with ovrHmd_Destroy.
OVR_EXPORT ovrHmd ovrHmd_Create(int index);
OVR_EXPORT void ovrHmd_Destroy(ovrHmd hmd);
// Creates a "fake" HMD used for debugging only. This is not tied to specific hardware,
// but may be used to debug some of the related rendering.
OVR_EXPORT ovrHmd ovrHmd_CreateDebug(ovrHmdType type);
// Returns last error for HMD state. Returns null for no error.
// String is valid until next call or GetLastError or HMD is destroyed.
// Pass null hmd to get global error (for create, etc).
OVR_EXPORT const char* ovrHmd_GetLastError(ovrHmd hmd);
//-------------------------------------------------------------------------------------
// Returns capability bits that are enabled at this time; described by ovrHmdCaps.
// Note that this value is different font ovrHmdDesc::HmdCaps, which describes what
// capabilities are available.
OVR_EXPORT unsigned int ovrHmd_GetEnabledCaps(ovrHmd hmd);
// Modifies capability bits described by ovrHmdCaps that can be modified,
// such as ovrHmd_LowPersistance.
OVR_EXPORT void ovrHmd_SetEnabledCaps(ovrHmd hmd, unsigned int hmdCaps);
//-------------------------------------------------------------------------------------
// ***** Sensor Interface
// All sensor interface functions are thread-safe, allowing sensor state to be sampled
// from different threads.
// Starts sensor sampling, enabling specified capabilities, described by ovrSensorCaps.
// - supportedSensorCaps specifies support that is requested. The function will succeed
// even if these caps are not available (i.e. sensor or camera is unplugged). Support
// will automatically be enabled if such device is plugged in later. Software should
// check ovrSensorState.StatusFlags for real-time status.
// - requiredSensorCaps specify sensor capabilities required at the time of the call.
// If they are not available, the function will fail. Pass 0 if only specifying
// supportedSensorCaps.
OVR_EXPORT ovrBool ovrHmd_StartSensor(ovrHmd hmd, unsigned int supportedSensorCaps,
unsigned int requiredSensorCaps);
// Stops sensor sampling, shutting down internal resources.
OVR_EXPORT void ovrHmd_StopSensor(ovrHmd hmd);
// Resets sensor orientation.
OVR_EXPORT void ovrHmd_ResetSensor(ovrHmd hmd);
// Returns sensor state reading based on the specified absolute system time.
// Pass absTime value of 0.0 to request the most recent sensor reading; in this case
// both PredictedPose and SamplePose will have the same value.
// ovrHmd_GetEyePredictedSensorState relies on this internally.
// This may also be used for more refined timing of FrontBuffer rendering logic, etc.
OVR_EXPORT ovrSensorState ovrHmd_GetSensorState(ovrHmd hmd, double absTime);
// Returns information about a sensor.
// Only valid after StartSensor.
OVR_EXPORT ovrBool ovrHmd_GetSensorDesc(ovrHmd hmd, ovrSensorDesc* descOut);
//-------------------------------------------------------------------------------------
// ***** Graphics Setup
// Fills in description about HMD; this is the same as filled in by ovrHmd_Create.
OVR_EXPORT void ovrHmd_GetDesc(ovrHmd hmd, ovrHmdDesc* desc);
// Calculates texture size recommended for rendering one eye within HMD, given FOV cone.
// Higher FOV will generally require larger textures to maintain quality.
// - pixelsPerDisplayPixel specifies that number of render target pixels per display
// pixel at center of distortion; 1.0 is the default value. Lower values
// can improve performance.
OVR_EXPORT ovrSizei ovrHmd_GetFovTextureSize(ovrHmd hmd, ovrEyeType eye, ovrFovPort fov,
float pixelsPerDisplayPixel);
//-------------------------------------------------------------------------------------
// ***** Rendering API Thread Safety
// All of rendering APIs, inclusing Configure and frame functions are *NOT
// Thread Safe*. It is ok to use ConfigureRendering on one thread and handle
// frames on another thread, but explicit synchronization must be done since
// functions that depend on configured state are not reentrant.
//
// As an extra requirement, any of the following calls must be done on
// the render thread, which is the same thread that calls ovrHmd_BeginFrame
// or ovrHmd_BeginFrameTiming.
// - ovrHmd_EndFrame
// - ovrHmd_BeginEyeRender
// - ovrHmd_EndEyeRender
// - ovrHmd_GetFramePointTime
// - ovrHmd_GetEyePose
// - ovrHmd_GetEyeTimewarpMatrices
//-------------------------------------------------------------------------------------
// ***** SDK-Rendering Functions
// These functions support rendering of distortion by the SDK through direct
// access to the underlying rendering HW, such as D3D or GL.
// This is the recommended approach, as it allows for better support or future
// Oculus hardware and a range of low-level optimizations.
// Configures rendering; fills in computed render parameters.
// This function can be called multiple times to change rendering settings.
// The users pass in two eye view descriptors that are used to
// generate complete rendering information for each eye in eyeRenderDescOut[2].
//
// - apiConfig provides D3D/OpenGL specific parameters. Pass null
// to shutdown rendering and release all resources.
// - distortionCaps describe distortion settings that will be applied.
//
OVR_EXPORT ovrBool ovrHmd_ConfigureRendering( ovrHmd hmd,
const ovrRenderAPIConfig* apiConfig,
unsigned int distortionCaps,
const ovrFovPort eyeFovIn[2],
ovrEyeRenderDesc eyeRenderDescOut[2] );
// Begins a frame, returning timing and orientation information useful for simulation.
// This should be called in the beginning of game rendering loop (on render thread).
// This function relies on ovrHmd_BeginFrameTiming for some of its functionality.
// Pass 0 for frame index if not using GetFrameTiming.
OVR_EXPORT ovrFrameTiming ovrHmd_BeginFrame(ovrHmd hmd, unsigned int frameIndex);
// Ends frame, rendering textures to frame buffer. This may perform distortion and scaling
// internally, assuming is it not delegated to another thread.
// Must be called on the same thread as BeginFrame. Calls ovrHmd_BeginEndTiming internally.
// *** This Function will to Present/SwapBuffers and potentially wait for GPU Sync ***.
OVR_EXPORT void ovrHmd_EndFrame(ovrHmd hmd);
// Marks beginning of eye rendering. Must be called on the same thread as BeginFrame.
// This function uses ovrHmd_GetEyePose to predict sensor state that should be
// used rendering the specified eye.
// This combines current absolute time with prediction that is appropriate for this HMD.
// It is ok to call ovrHmd_BeginEyeRender() on both eyes before calling ovrHmd_EndEyeRender.
// If rendering one eye at a time, it is best to render eye specified by
// HmdDesc.EyeRenderOrder[0] first.
OVR_EXPORT ovrPosef ovrHmd_BeginEyeRender(ovrHmd hmd, ovrEyeType eye);
// Marks the end of eye rendering and submits the eye texture for display after it is ready.
// Rendering viewport within the texture can change per frame if necessary.
// Specified texture may be presented immediately or wait until ovrHmd_EndFrame based
// on the implementation. The API performs distortion and scaling internally.
// 'renderPose' will typically be the value returned from ovrHmd_BeginEyeRender, but can
// be different if a different pose was used for rendering.
OVR_EXPORT void ovrHmd_EndEyeRender(ovrHmd hmd, ovrEyeType eye,
ovrPosef renderPose, ovrTexture* eyeTexture);
//-------------------------------------------------------------------------------------
// ***** Game-Side Rendering Functions
// These functions provide distortion data and render timing support necessary to allow
// game rendering of distortion. Game-side rendering involves the following steps:
//
// 1. Setup ovrEyeDesc based on desired texture size and Fov.
// Call ovrHmd_GetRenderDesc to get the necessary rendering parameters for each eye.
//
// 2. Use ovrHmd_CreateDistortionMesh to generate distortion mesh.
//
// 3. Use ovrHmd_BeginFrameTiming, ovrHmd_GetEyePose and ovrHmd_BeginFrameTiming
// in the rendering loop to obtain timing and predicted view orientation for
// each eye.
// - If relying on timewarp, use ovr_WaitTillTime after rendering+flush, followed
// by ovrHmd_GetEyeTimewarpMatrices to obtain timewarp matrices used
// in distortion pixel shader to reduce latency.
//
// Computes distortion viewport, view adjust and other rendering for the specified
// eye. This can be used instead of ovrHmd_ConfigureRendering to help setup rendering on
// the game side.
OVR_EXPORT ovrEyeRenderDesc ovrHmd_GetRenderDesc(ovrHmd hmd,
ovrEyeType eyeType, ovrFovPort fov);
// Describes a vertex used for distortion; this is intended to be converted into
// the engine-specific format.
// Some fields may be unused based on ovrDistortionCaps selected. TexG and TexB, for example,
// are not used if chromatic correction is not requested.
typedef struct ovrDistortionVertex_
{
ovrVector2f Pos;
float TimeWarpFactor; // Lerp factor between time-warp matrices. Can be encoded in Pos.z.
float VignetteFactor; // Vignette fade factor. Can be encoded in Pos.w.
ovrVector2f TexR;
ovrVector2f TexG;
ovrVector2f TexB;
} ovrDistortionVertex;
// Describes a full set of distortion mesh data, filled in by ovrHmd_CreateDistortionMesh.
// Contents of this data structure, if not null, should be freed by ovrHmd_DestroyDistortionMesh.
typedef struct ovrDistortionMesh_
{
ovrDistortionVertex* pVertexData;
unsigned short* pIndexData;
unsigned int VertexCount;
unsigned int IndexCount;
} ovrDistortionMesh;
// Generate distortion mesh per eye.
// Distortion capabilities will depend on 'distortionCaps' flags; user should rely on
// appropriate shaders based on their settings.
// Distortion mesh data will be allocated and stored into the ovrDistortionMesh data structure,
// which should be explicitly freed with ovrHmd_DestroyDistortionMesh.
// Users should call ovrHmd_GetRenderScaleAndOffset to get uvScale and Offset values for rendering.
// The function shouldn't fail unless theres is a configuration or memory error, in which case
// ovrDistortionMesh values will be set to null.
OVR_EXPORT ovrBool ovrHmd_CreateDistortionMesh( ovrHmd hmd,
ovrEyeType eyeType, ovrFovPort fov,
unsigned int distortionCaps,
ovrDistortionMesh *meshData );
// Frees distortion mesh allocated by ovrHmd_GenerateDistortionMesh. meshData elements
// are set to null and zeroes after the call.
OVR_EXPORT void ovrHmd_DestroyDistortionMesh( ovrDistortionMesh* meshData );
// Computes updated 'uvScaleOffsetOut' to be used with a distortion if render target size or
// viewport changes after the fact. This can be used to adjust render size every frame, if desired.
OVR_EXPORT void ovrHmd_GetRenderScaleAndOffset( ovrFovPort fov,
ovrSizei textureSize, ovrRecti renderViewport,
ovrVector2f uvScaleOffsetOut[2] );
// Thread-safe timing function for the main thread. Caller should increment frameIndex
// with every frame and pass the index to RenderThread for processing.
OVR_EXPORT ovrFrameTiming ovrHmd_GetFrameTiming(ovrHmd hmd, unsigned int frameIndex);
// Called at the beginning of the frame on the Render Thread.
// Pass frameIndex == 0 if ovrHmd_GetFrameTiming isn't being used. Otherwise,
// pass the same frame index as was used for GetFrameTiming on the main thread.
OVR_EXPORT ovrFrameTiming ovrHmd_BeginFrameTiming(ovrHmd hmd, unsigned int frameIndex);
// Marks the end of game-rendered frame, tracking the necessary timing information. This
// function must be called immediately after Present/SwapBuffers + GPU sync. GPU sync is important
// before this call to reduce latency and ensure proper timing.
OVR_EXPORT void ovrHmd_EndFrameTiming(ovrHmd hmd);
// Initializes and resets frame time tracking. This is typically not necessary, but
// is helpful if game changes vsync state or video mode. vsync is assumed to be on if this
// isn't called. Resets internal frame index to the specified number.
OVR_EXPORT void ovrHmd_ResetFrameTiming(ovrHmd hmd, unsigned int frameIndex);
// Predicts and returns Pose that should be used rendering the specified eye.
// Must be called between ovrHmd_BeginFrameTiming & ovrHmd_EndFrameTiming.
OVR_EXPORT ovrPosef ovrHmd_GetEyePose(ovrHmd hmd, ovrEyeType eye);
// Computes timewarp matrices used by distortion mesh shader, these are used to adjust
// for orientation change since the last call to ovrHmd_GetEyePose for this eye.
// The ovrDistortionVertex::TimeWarpFactor is used to blend between the matrices,
// usually representing two different sides of the screen.
// Must be called on the same thread as ovrHmd_BeginFrameTiming.
OVR_EXPORT void ovrHmd_GetEyeTimewarpMatrices(ovrHmd hmd, ovrEyeType eye,
ovrPosef renderPose, ovrMatrix4f twmOut[2]);
//-------------------------------------------------------------------------------------
// ***** Stateless math setup functions
// Used to generate projection from ovrEyeDesc::Fov.
OVR_EXPORT ovrMatrix4f ovrMatrix4f_Projection( ovrFovPort fov,
float znear, float zfar, ovrBool rightHanded );
// Used for 2D rendering, Y is down
// orthoScale = 1.0f / pixelsPerTanAngleAtCenter
// orthoDistance = distance from camera, such as 0.8m
OVR_EXPORT ovrMatrix4f ovrMatrix4f_OrthoSubProjection(ovrMatrix4f projection, ovrVector2f orthoScale,
float orthoDistance, float eyeViewAdjustX);
// Returns global, absolute high-resolution time in seconds. This is the same
// value as used in sensor messages.
OVR_EXPORT double ovr_GetTimeInSeconds();
// Waits until the specified absolute time.
OVR_EXPORT double ovr_WaitTillTime(double absTime);
// -----------------------------------------------------------------------------------
// ***** Latency Test interface
// Does latency test processing and returns 'TRUE' if specified rgb color should
// be used to clear the screen.
OVR_EXPORT ovrBool ovrHmd_ProcessLatencyTest(ovrHmd hmd, unsigned char rgbColorOut[3]);
// Returns non-null string once with latency test result, when it is available.
// Buffer is valid until next call.
OVR_EXPORT const char* ovrHmd_GetLatencyTestResult(ovrHmd hmd);
// Returns latency for HMDs that support internal latency testing via the
// pixel-read back method (-1 for invalid or N/A)
OVR_EXPORT double ovrHmd_GetMeasuredLatencyTest2(ovrHmd hmd);
// -----------------------------------------------------------------------------------
// ***** Property Access
// NOTICE: This is experimental part of API that is likely to go away or change.
// These allow accessing different properties of the HMD and profile.
// Some of the properties may go away with profile/HMD versions, so software should
// use defaults and/or proper fallbacks.
//
// For now, access profile entries; this will change.
#if !defined(OVR_KEY_USER)
#define OVR_KEY_USER "User"
#define OVR_KEY_NAME "Name"
#define OVR_KEY_GENDER "Gender"
#define OVR_KEY_PLAYER_HEIGHT "PlayerHeight"
#define OVR_KEY_EYE_HEIGHT "EyeHeight"
#define OVR_KEY_IPD "IPD"
#define OVR_KEY_NECK_TO_EYE_HORIZONTAL "NeckEyeHori"
#define OVR_KEY_NECK_TO_EYE_VERTICAL "NeckEyeVert"
#define OVR_DEFAULT_GENDER "Male"
#define OVR_DEFAULT_PLAYER_HEIGHT 1.778f
#define OVR_DEFAULT_EYE_HEIGHT 1.675f
#define OVR_DEFAULT_IPD 0.064f
#define OVR_DEFAULT_NECK_TO_EYE_HORIZONTAL 0.12f
#define OVR_DEFAULT_NECK_TO_EYE_VERTICAL 0.12f
#endif
// Get float property. Returns first element if property is a float array.
// Returns defaultValue if property doesn't exist.
OVR_EXPORT float ovrHmd_GetFloat(ovrHmd hmd, const char* propertyName, float defaultVal);
// Modify float property; false if property doesn't exist or is readonly.
OVR_EXPORT ovrBool ovrHmd_SetFloat(ovrHmd hmd, const char* propertyName, float value);
// Get float[] property. Returns the number of elements filled in, 0 if property doesn't exist.
// Maximum of arraySize elements will be written.
OVR_EXPORT unsigned int ovrHmd_GetFloatArray(ovrHmd hmd, const char* propertyName,
float values[], unsigned int arraySize);
// Modify float[] property; false if property doesn't exist or is readonly.
OVR_EXPORT ovrBool ovrHmd_SetFloatArray(ovrHmd hmd, const char* propertyName,
float values[], unsigned int arraySize);
// Get string property. Returns first element if property is a string array.
// Returns defaultValue if property doesn't exist.
// String memory is guaranteed to exist until next call to GetString or GetStringArray, or HMD is destroyed.
OVR_EXPORT const char* ovrHmd_GetString(ovrHmd hmd, const char* propertyName,
const char* defaultVal);
// Returns array size of a property, 0 if property doesn't exist.
// Can be used to check existence of a property.
OVR_EXPORT unsigned int ovrHmd_GetArraySize(ovrHmd hmd, const char* propertyName);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // OVR_CAPI_h

View File

@ -0,0 +1,73 @@
/************************************************************************************
Filename : OVR_CAPI_GL.h
Content : GL specific structures used by the CAPI interface.
Created : November 7, 2013
Authors : Lee Cooper
Copyright : Copyright 2013 Oculus VR, Inc. 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
otherwise accompanies this software in either electronic or hard copy form.
************************************************************************************/
#ifndef OVR_CAPI_GL_h
#define OVR_CAPI_GL_h
#include "OVR_CAPI.h"
//-----------------------------------------------------------------------------------
// ***** GL Specific
#if defined(OVR_OS_WIN32)
#include <Windows.h>
#include <GL/gl.h>
#include <GL/glext.h>
#include <GL/wglext.h>
#elif defined(OVR_OS_MAC)
#include <OpenGL/gl3.h>
#include <OpenGL/gl3ext.h>
#include <OpenGL/OpenGL.h>
#else
#include <GL/gl.h>
#include <GL/glext.h>
#include <GL/glx.h>
#endif
// Used to configure slave GL rendering (i.e. for devices created externally).
typedef struct ovrGLConfigData_s
{
// General device settings.
ovrRenderAPIConfigHeader Header;
#if defined(OVR_OS_WIN32)
HWND Window;
#elif defined(OVR_OS_LINUX)
Display* Disp;
Window Win;
#endif
} ovrGLConfigData;
union ovrGLConfig
{
ovrRenderAPIConfig Config;
ovrGLConfigData OGL;
};
// Used to pass GL eye texture data to ovrHmd_EndFrame.
typedef struct ovrGLTextureData_s
{
// General device settings.
ovrTextureHeader Header;
GLuint TexId;
} ovrGLTextureData;
typedef union ovrGLTexture_s
{
ovrTexture Texture;
ovrGLTextureData OGL;
} ovrGLTexture;
#endif // OVR_CAPI_GL_h

View File

@ -0,0 +1,384 @@
/************************************************************************************
Filename : OVR_Common_HMDDevice.cpp
Content :
Created :
Authors :
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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.
*************************************************************************************/
// Should be #included from the relevant OVR_YourPlatformHere_HMDDevice.cpp
#include "Kernel/OVR_Alg.h"
//-------------------------------------------------------------------------------------
// ***** HMDDeviceCreateDesc
DeviceBase* HMDDeviceCreateDesc::NewDeviceInstance()
{
return new HMDDevice(this);
}
void HMDDeviceCreateDesc::SetScreenParameters(int x, int y,
int hres, int vres,
float hsize, float vsize,
float vCenterFromTopInMeters, float lensSeparationInMeters)
{
Desktop.X = x;
Desktop.Y = y;
ResolutionInPixels = Sizei(hres, vres);
ScreenSizeInMeters = Sizef(hsize, vsize);
VCenterFromTopInMeters = vCenterFromTopInMeters;
LensSeparationInMeters = lensSeparationInMeters;
Contents |= Contents_Screen;
}
void HMDDeviceCreateDesc::SetDistortion(const float* dks)
{
for (int i = 0; i < 4; i++)
DistortionK[i] = dks[i];
// TODO: add DistortionEqn
Contents |= Contents_Distortion;
}
HmdTypeEnum HMDDeviceCreateDesc::GetHmdType() const
{
// Determine the HMD model
// The closest thing we have to a dependable model indicator are the
// the screen characteristics. Additionally we can check the sensor
// (on attached devices) to further refine our guess
HmdTypeEnum hmdType = HmdType_Unknown;
if ( ResolutionInPixels.w == 1280 )
{
if ( ScreenSizeInMeters.w > 0.1497f && ScreenSizeInMeters.w < 0.1498f )
hmdType = HmdType_DK1;
else
hmdType = HmdType_DKProto;
}
else if ( ResolutionInPixels.w == 1920 )
{
// DKHD protoypes, all 1920x1080
if ( ScreenSizeInMeters.w > 0.1209f && ScreenSizeInMeters.w < 0.1210f )
{
// Screen size 0.12096 x 0.06804
hmdType = HmdType_DKHDProto;
}
else if ( ScreenSizeInMeters.w > 0.1257f && ScreenSizeInMeters.w < 0.1258f )
{
// Screen size 0.125 x 0.071
// Could be a HmdType_DKHDProto566Mi, HmdType_CrystalCoveProto, or DK2
// - most likely the latter.
hmdType = HmdType_DK2;
// If available, check the sensor to determine exactly which variant this is
if (pDevice)
{
Ptr<SensorDevice> sensor = *((HMDDevice*)pDevice)->GetSensor();
SensorInfo sinfo;
if (sensor && sensor->GetDeviceInfo(&sinfo))
{
if (sinfo.ProductId == 1)
{
hmdType = HmdType_DKHDProto566Mi;
}
else
{ // Crystal Cove uses 0.# firmware, DK2 uses 1.#
int firm_major = Alg::DecodeBCD((sinfo.Version >> 8) & 0x00ff);
int firm_minor = Alg::DecodeBCD(sinfo.Version & 0xff);
OVR_UNUSED(firm_minor);
if (firm_major == 0)
hmdType = HmdType_CrystalCoveProto;
else
hmdType = HmdType_DK2;
}
}
}
}
else if (ScreenSizeInMeters.w > 0.1295f && ScreenSizeInMeters.w < 0.1297f)
{
// Screen size 0.1296 x 0.0729
hmdType = HmdType_DKHD2Proto;
}
}
OVR_ASSERT( hmdType != HmdType_Unknown );
return hmdType;
}
bool HMDDeviceCreateDesc::GetDeviceInfo(DeviceInfo* info) const
{
if ((info->InfoClassType != Device_HMD) &&
(info->InfoClassType != Device_None))
return false;
HmdTypeEnum hmdType = GetHmdType();
char const* deviceName = "Oculus HMD";
switch (hmdType)
{
case HmdType_DKProto: deviceName = "Oculus Rift Prototype"; break;
case HmdType_DK1: deviceName = "Oculus Rift DK1"; break;
case HmdType_DKHDProto: deviceName = "Oculus Rift DKHD"; break;
case HmdType_DKHD2Proto: deviceName = "Oculus Rift DKHD2"; break;
case HmdType_DKHDProto566Mi: deviceName = "Oculus Rift DKHD 566 Mi"; break;
case HmdType_CrystalCoveProto: deviceName = "Oculus Rift Crystal Cove"; break;
case HmdType_DK2: deviceName = "Oculus Rift DK2"; break;
default: deviceName = "Oculus HMD"; break;
}
info->ProductName = deviceName;
info->Manufacturer = "Oculus VR";
info->Type = Device_HMD;
info->Version = 0;
// Display detection.
if (info->InfoClassType == Device_HMD)
{
HMDInfo* hmdInfo = static_cast<HMDInfo*>(info);
hmdInfo->HmdType = hmdType;
hmdInfo->DesktopX = Desktop.X;
hmdInfo->DesktopY = Desktop.Y;
hmdInfo->ResolutionInPixels = ResolutionInPixels;
hmdInfo->ScreenSizeInMeters = ScreenSizeInMeters; // Includes ScreenGapSizeInMeters
hmdInfo->ScreenGapSizeInMeters = 0.0f;
hmdInfo->CenterFromTopInMeters = VCenterFromTopInMeters;
hmdInfo->LensSeparationInMeters = LensSeparationInMeters;
// TODO: any other information we get from the hardware itself should be added to this list
switch ( hmdInfo->HmdType )
{
case HmdType_DKProto:
// WARNING - estimated.
hmdInfo->Shutter.Type = HmdShutter_RollingTopToBottom;
hmdInfo->Shutter.VsyncToNextVsync = ( 1.0f / 60.0f );
hmdInfo->Shutter.VsyncToFirstScanline = 0.000052f;
hmdInfo->Shutter.FirstScanlineToLastScanline = 0.016580f;
hmdInfo->Shutter.PixelSettleTime = 0.015f; // estimated.
hmdInfo->Shutter.PixelPersistence = hmdInfo->Shutter.VsyncToNextVsync; // Full persistence
break;
case HmdType_DK1:
// Data from specs.
hmdInfo->Shutter.Type = HmdShutter_RollingTopToBottom;
hmdInfo->Shutter.VsyncToNextVsync = ( 1.0f / 60.0f );
hmdInfo->Shutter.VsyncToFirstScanline = 0.00018226f;
hmdInfo->Shutter.FirstScanlineToLastScanline = 0.01620089f;
hmdInfo->Shutter.PixelSettleTime = 0.017f; // estimated.
hmdInfo->Shutter.PixelPersistence = hmdInfo->Shutter.VsyncToNextVsync; // Full persistence
break;
case HmdType_DKHDProto:
// Data from specs.
hmdInfo->Shutter.Type = HmdShutter_RollingRightToLeft;
hmdInfo->Shutter.VsyncToNextVsync = ( 1.0f / 60.0f );
hmdInfo->Shutter.VsyncToFirstScanline = 0.0000859f;
hmdInfo->Shutter.FirstScanlineToLastScanline = 0.0164948f;
hmdInfo->Shutter.PixelSettleTime = 0.012f; // estimated.
hmdInfo->Shutter.PixelPersistence = hmdInfo->Shutter.VsyncToNextVsync; // Full persistence
break;
case HmdType_DKHD2Proto:
// Data from specs.
hmdInfo->Shutter.Type = HmdShutter_RollingRightToLeft;
hmdInfo->Shutter.VsyncToNextVsync = ( 1.0f / 60.0f );
hmdInfo->Shutter.VsyncToFirstScanline = 0.000052f;
hmdInfo->Shutter.FirstScanlineToLastScanline = 0.016580f;
hmdInfo->Shutter.PixelSettleTime = 0.015f; // estimated.
hmdInfo->Shutter.PixelPersistence = hmdInfo->Shutter.VsyncToNextVsync; // Full persistence
break;
case HmdType_DKHDProto566Mi:
#if 0
// Low-persistence global shutter
hmdInfo->Shutter.Type = HmdShutter_Global;
hmdInfo->Shutter.VsyncToNextVsync = ( 1.0f / 76.0f );
hmdInfo->Shutter.VsyncToFirstScanline = 0.0000273f + 0.0131033f; // Global shutter - first visible scan line is actually the last!
hmdInfo->Shutter.FirstScanlineToLastScanline = 0.000f; // Global shutter - all visible at once.
hmdInfo->Shutter.PixelSettleTime = 0.0f; // <100us
hmdInfo->Shutter.PixelPersistence = 0.18f * hmdInfo->Shutter.VsyncToNextVsync; // Confgurable - currently set to 18% of total frame.
#else
// Low-persistence rolling shutter
hmdInfo->Shutter.Type = HmdShutter_RollingRightToLeft;
hmdInfo->Shutter.VsyncToNextVsync = ( 1.0f / 76.0f );
hmdInfo->Shutter.VsyncToFirstScanline = 0.0000273f;
hmdInfo->Shutter.FirstScanlineToLastScanline = 0.0131033f;
hmdInfo->Shutter.PixelSettleTime = 0.0f; // <100us
hmdInfo->Shutter.PixelPersistence = 0.18f * hmdInfo->Shutter.VsyncToNextVsync; // Confgurable - currently set to 18% of total frame.
#endif
break;
case HmdType_CrystalCoveProto:
// Low-persistence rolling shutter
hmdInfo->Shutter.Type = HmdShutter_RollingRightToLeft;
hmdInfo->Shutter.VsyncToNextVsync = ( 1.0f / 76.0f );
hmdInfo->Shutter.VsyncToFirstScanline = 0.0000273f;
hmdInfo->Shutter.FirstScanlineToLastScanline = 0.0131033f;
hmdInfo->Shutter.PixelSettleTime = 0.0f; // <100us
hmdInfo->Shutter.PixelPersistence = 0.18f * hmdInfo->Shutter.VsyncToNextVsync; // Confgurable - currently set to 18% of total frame.
break;
case HmdType_DK2:
// Low-persistence rolling shutter
hmdInfo->Shutter.Type = HmdShutter_RollingRightToLeft;
hmdInfo->Shutter.VsyncToNextVsync = ( 1.0f / 76.0f );
hmdInfo->Shutter.VsyncToFirstScanline = 0.0000273f;
hmdInfo->Shutter.FirstScanlineToLastScanline = 0.0131033f;
hmdInfo->Shutter.PixelSettleTime = 0.0f; // <100us
hmdInfo->Shutter.PixelPersistence = 0.18f * hmdInfo->Shutter.VsyncToNextVsync; // Confgurable - currently set to 18% of total frame.
break;
default: OVR_ASSERT ( false ); break;
}
OVR_strcpy(hmdInfo->DisplayDeviceName, sizeof(hmdInfo->DisplayDeviceName),
DisplayDeviceName.ToCStr());
#if defined(OVR_OS_WIN32)
// Nothing special for Win32.
#elif defined(OVR_OS_MAC)
hmdInfo->DisplayId = DisplayId;
#elif defined(OVR_OS_LINUX)
hmdInfo->DisplayId = DisplayId;
#elif defined(OVR_OS_ANDROID)
hmdInfo->DisplayId = DisplayId;
#else
#error Unknown platform
#endif
}
return true;
}
//-------------------------------------------------------------------------------------
// ***** HMDDevice
HMDDevice::HMDDevice(HMDDeviceCreateDesc* createDesc)
: OVR::DeviceImpl<OVR::HMDDevice>(createDesc, 0)
{
}
HMDDevice::~HMDDevice()
{
}
bool HMDDevice::Initialize(DeviceBase* parent)
{
pParent = parent;
return true;
}
void HMDDevice::Shutdown()
{
ProfileName.Clear();
pCachedProfile.Clear();
pParent.Clear();
}
Profile* HMDDevice::GetProfile()
{
// Loads and returns a cached profile based on this device and current user
if (pCachedProfile == NULL)
{
ProfileManager* mgr = GetManager()->GetProfileManager();
const char* profile_name = GetProfileName();
if (profile_name && profile_name[0])
pCachedProfile = *mgr->GetProfile(this, profile_name);
if (pCachedProfile == NULL)
pCachedProfile = *mgr->GetDefaultProfile(this);
}
return pCachedProfile.GetPtr();
}
const char* HMDDevice::GetProfileName()
{
if (ProfileName.IsEmpty())
{ // If the profile name has not been initialized then
// retrieve the stored default user for this specific device
ProfileManager* mgr = GetManager()->GetProfileManager();
const char* name = mgr->GetDefaultUser(this);
ProfileName = name;
}
return ProfileName.ToCStr();
}
bool HMDDevice::SetProfileName(const char* name)
{
if (ProfileName == name)
return true; // already set
// Flush the old profile
pCachedProfile.Clear();
if (!name)
{
ProfileName.Clear();
return false;
}
// Set the name and attempt to cache the profile
ProfileName = name;
if (GetProfile())
{
return true;
}
else
{
ProfileName.Clear();
return false;
}
}
OVR::SensorDevice* HMDDevice::GetSensor()
{
// Just return first sensor found since we have no way to match it yet.
// Create DK2 sensor if it exists otherwise create first DK1 sensor.
SensorDevice* sensor = NULL;
DeviceEnumerator<SensorDevice> enumerator = GetManager()->EnumerateDevices<SensorDevice>();
while(enumerator.GetType() != Device_None)
{
SensorInfo info;
enumerator.GetDeviceInfo(&info);
if (info.ProductId == Device_Tracker2_ProductId)
{
sensor = enumerator.CreateDevice();
break;
}
enumerator.Next();
}
if (sensor == NULL)
{
sensor = GetManager()->EnumerateDevices<SensorDevice>().CreateDevice();
}
if (sensor)
{
sensor->SetCoordinateFrame(SensorDevice::Coord_HMD);
}
return sensor;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,142 @@
/************************************************************************************
PublicHeader: OVR.h
Filename : OVR_DeviceConstants.h
Content : Device constants
Created : February 5, 2013
Authors : Lee Cooper
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_DeviceConstants_h
#define OVR_DeviceConstants_h
namespace OVR {
//-------------------------------------------------------------------------------------
// Different device types supported by OVR; this type is reported by DeviceBase::GetType.
//
enum DeviceType
{
Device_None = 0,
Device_Manager = 1,
Device_HMD = 2,
Device_Sensor = 3,
Device_LatencyTester = 4,
Device_BootLoader = 5,
Device_Camera = 6,
Device_Display = 7,
Device_All = 0xFF // Set for enumeration only, to enumerate all device types.
};
//-------------------------------------------------------------------------------------
// Different lens distortion types supported by devices.
//
enum DistortionEqnType
{
Distortion_No_Override = -1,
// These two are leagcy and deprecated.
Distortion_Poly4 = 0, // scale = (K0 + K1*r^2 + K2*r^4 + K3*r^6)
Distortion_RecipPoly4 = 1, // scale = 1/(K0 + K1*r^2 + K2*r^4 + K3*r^6)
// CatmullRom10 is the preferred distortion format.
Distortion_CatmullRom10 = 2, // scale = Catmull-Rom spline through points (1.0, K[1]...K[9])
Distortion_LAST // For ease of enumeration.
};
//-------------------------------------------------------------------------------------
// HMD types.
//
enum HmdTypeEnum
{
HmdType_None,
HmdType_DKProto, // First duct-tape model, never sold.
HmdType_DK1, // DevKit1 - on sale to developers.
HmdType_DKHDProto, // DKHD - shown at various shows, never sold.
HmdType_DKHD2Proto, // DKHD2, 5.85-inch panel, never sold.
HmdType_DKHDProto566Mi, // DKHD, 5.66-inch panel, never sold.
HmdType_CrystalCoveProto, // Crystal Cove, 5.66-inch panel, shown at shows but never sold.
HmdType_DK2,
// Reminder - this header file is public - codenames only!
HmdType_Unknown, // Used for unnamed HW lab experiments.
HmdType_LAST
};
//-------------------------------------------------------------------------------------
// HMD shutter types.
//
enum HmdShutterTypeEnum
{
HmdShutter_Global,
HmdShutter_RollingTopToBottom,
HmdShutter_RollingLeftToRight,
HmdShutter_RollingRightToLeft,
// TODO:
// color-sequential e.g. LCOS?
// alternate eyes?
// alternate columns?
// outside-in?
HmdShutter_LAST
};
//-------------------------------------------------------------------------------------
// For headsets that use eye cups
//
enum EyeCupType
{
// Public lenses
EyeCup_DK1A = 0,
EyeCup_DK1B = 1,
EyeCup_DK1C = 2,
EyeCup_DK2A = 3,
// Internal R&D codenames.
// Reminder - this header file is public - codenames only!
EyeCup_DKHD2A,
EyeCup_OrangeA,
EyeCup_RedA,
EyeCup_PinkA,
EyeCup_BlueA,
EyeCup_Delilah1A,
EyeCup_Delilah2A,
EyeCup_JamesA,
EyeCup_SunMandalaA,
EyeCup_LAST
};
} // namespace OVR
#endif

View File

@ -0,0 +1,185 @@
/************************************************************************************
Filename : OVR_DeviceHandle.cpp
Content : Implementation of device handle class
Created : February 5, 2013
Authors : Lee Cooper
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_DeviceHandle.h"
#include "OVR_DeviceImpl.h"
namespace OVR {
//-------------------------------------------------------------------------------------
// ***** DeviceHandle
DeviceHandle::DeviceHandle(DeviceCreateDesc* impl) : pImpl(impl)
{
if (pImpl)
pImpl->AddRef();
}
DeviceHandle::DeviceHandle(const DeviceHandle& src) : pImpl(src.pImpl)
{
if (pImpl)
pImpl->AddRef();
}
DeviceHandle::~DeviceHandle()
{
if (pImpl)
pImpl->Release();
}
void DeviceHandle::operator = (const DeviceHandle& src)
{
if (src.pImpl)
src.pImpl->AddRef();
if (pImpl)
pImpl->Release();
pImpl = src.pImpl;
}
DeviceBase* DeviceHandle::GetDevice_AddRef() const
{
if (pImpl && pImpl->pDevice)
{
pImpl->pDevice->AddRef();
return pImpl->pDevice;
}
return NULL;
}
// Returns true, if the handle contains the same device ptr
// as specified in the parameter.
bool DeviceHandle::IsDevice(DeviceBase* pdev) const
{
return (pdev && pImpl && pImpl->pDevice) ?
pImpl->pDevice == pdev : false;
}
DeviceType DeviceHandle::GetType() const
{
return pImpl ? pImpl->Type : Device_None;
}
bool DeviceHandle::GetDeviceInfo(DeviceInfo* info) const
{
return pImpl ? pImpl->GetDeviceInfo(info) : false;
}
bool DeviceHandle::IsAvailable() const
{
// This isn't "atomically safe", but the function only returns the
// recent state that may change.
return pImpl ? (pImpl->Enumerated && pImpl->pLock->pManager) : false;
}
bool DeviceHandle::IsCreated() const
{
return pImpl ? (pImpl->pDevice != 0) : false;
}
DeviceBase* DeviceHandle::CreateDevice()
{
if (!pImpl)
return 0;
DeviceBase* device = 0;
Ptr<DeviceManagerImpl> manager= 0;
// Since both manager and device pointers can only be destroyed during a lock,
// hold it while checking for availability.
// AddRef to manager so that it doesn't get released on us.
{
Lock::Locker deviceLockScope(pImpl->GetLock());
if (pImpl->pDevice)
{
pImpl->pDevice->AddRef();
return pImpl->pDevice;
}
manager = pImpl->GetManagerImpl();
}
if (manager)
{
if (manager->GetThreadId() != OVR::GetCurrentThreadId())
{
// Queue up a CreateDevice request. This fills in '&device' with AddRefed value,
// or keep it at null.
manager->GetThreadQueue()->PushCallAndWaitResult(
manager.GetPtr(), &DeviceManagerImpl::CreateDevice_MgrThread,
&device, pImpl, (DeviceBase*)0);
}
else
device = manager->CreateDevice_MgrThread(pImpl, (DeviceBase*)0);
}
return device;
}
void DeviceHandle::Clear()
{
if (pImpl)
{
pImpl->Release();
pImpl = 0;
}
}
bool DeviceHandle::enumerateNext(const DeviceEnumerationArgs& args)
{
if (GetType() == Device_None)
return false;
Ptr<DeviceManagerImpl> managerKeepAlive;
Lock::Locker lockScope(pImpl->GetLock());
DeviceCreateDesc* next = pImpl;
// If manager was destroyed, we get removed from the list.
if (!pImpl->pNext)
return false;
managerKeepAlive = next->GetManagerImpl();
OVR_ASSERT(managerKeepAlive);
do {
next = next->pNext;
if (managerKeepAlive->Devices.IsNull(next))
{
pImpl->Release();
pImpl = 0;
return false;
}
} while(!args.MatchRule(next->Type, next->Enumerated));
next->AddRef();
pImpl->Release();
pImpl = next;
return true;
}
} // namespace OVR

View File

@ -0,0 +1,108 @@
/************************************************************************************
PublicHeader: OVR.h
Filename : OVR_DeviceHandle.h
Content : Handle to a device that was enumerated
Created : February 5, 2013
Authors : Lee Cooper
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_DeviceHandle_h
#define OVR_DeviceHandle_h
#include "OVR_DeviceConstants.h"
namespace OVR {
class DeviceBase;
class DeviceInfo;
// Internal
class DeviceCreateDesc;
class DeviceEnumerationArgs;
//-------------------------------------------------------------------------------------
// ***** DeviceHandle
// DeviceHandle references a specific device that was enumerated; it can be assigned
// directly from DeviceEnumerator.
//
// Devices represented by DeviceHandle are not necessarily created or available.
// A device may become unavailable if, for example, it its unplugged. If the device
// is available, it can be created by calling CreateDevice.
//
class DeviceHandle
{
friend class DeviceManager;
friend class DeviceManagerImpl;
template<class B> friend class HIDDeviceImpl;
public:
DeviceHandle() : pImpl(0) { }
DeviceHandle(const DeviceHandle& src);
~DeviceHandle();
void operator = (const DeviceHandle& src);
bool operator == (const DeviceHandle& other) const { return pImpl == other.pImpl; }
bool operator != (const DeviceHandle& other) const { return pImpl != other.pImpl; }
// operator bool() returns true if Handle/Enumerator points to a valid device.
operator bool () const { return GetType() != Device_None; }
// Returns existing device, or NULL if !IsCreated. The returned ptr is
// addref-ed.
DeviceBase* GetDevice_AddRef() const;
DeviceType GetType() const;
bool GetDeviceInfo(DeviceInfo* info) const;
bool IsAvailable() const;
bool IsCreated() const;
// Returns true, if the handle contains the same device ptr
// as specified in the parameter.
bool IsDevice(DeviceBase*) const;
// Creates a device, or returns AddRefed pointer if one is already created.
// New devices start out with RefCount of 1.
DeviceBase* CreateDevice();
// Creates a device, or returns AddRefed pointer if one is already created.
// New devices start out with RefCount of 1. DeviceT is used to cast the
// DeviceBase* to a concreete type.
template <class DeviceT>
DeviceT* CreateDeviceTyped() const
{
return static_cast<DeviceT*>(DeviceHandle(*this).CreateDevice());
}
// Resets the device handle to uninitialized state.
void Clear();
protected:
explicit DeviceHandle(DeviceCreateDesc* impl);
bool enumerateNext(const DeviceEnumerationArgs& args);
DeviceCreateDesc* pImpl;
};
} // namespace OVR
#endif

View File

@ -0,0 +1,794 @@
/************************************************************************************
Filename : OVR_DeviceImpl.h
Content : Partial back-end independent implementation of Device interfaces
Created : October 10, 2012
Authors : Michael Antonov
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_DeviceImpl.h"
#include "Kernel/OVR_Atomic.h"
#include "Kernel/OVR_Log.h"
#include "Kernel/OVR_System.h"
#include "OVR_DeviceImpl.h"
#include "OVR_SensorImpl.h"
#include "OVR_Profile.h"
namespace OVR {
//-------------------------------------------------------------------------------------
// ***** MessageHandler
// Threading notes:
// The OnMessage() handler and SetMessageHandler are currently synchronized
// through a separately stored shared Lock object to avoid calling the handler
// from background thread while it's being removed.
static SharedLock MessageHandlerSharedLock;
class MessageHandlerImpl
{
public:
enum
{
MaxHandlerRefsCount = 4
};
MessageHandlerImpl()
: pLock(MessageHandlerSharedLock.GetLockAddRef()), HandlerRefsCount(0)
{
}
~MessageHandlerImpl()
{
MessageHandlerSharedLock.ReleaseLock(pLock);
pLock = 0;
}
static MessageHandlerImpl* FromHandler(MessageHandler* handler)
{ return (MessageHandlerImpl*)&handler->Internal; }
static const MessageHandlerImpl* FromHandler(const MessageHandler* handler)
{ return (const MessageHandlerImpl*)&handler->Internal; }
// This lock is held while calling a handler and when we are applied/
// removed from a device.
Lock* pLock;
// List of devices we are applied to.
int HandlerRefsCount;
MessageHandlerRef* pHandlerRefs[MaxHandlerRefsCount];
};
MessageHandlerRef::MessageHandlerRef(DeviceBase* device)
: pLock(MessageHandlerSharedLock.GetLockAddRef()), pDevice(device), HandlersCount(0)
{
}
MessageHandlerRef::~MessageHandlerRef()
{
{
Lock::Locker lockScope(pLock);
while (HandlersCount > 0)
removeHandler(0);
}
MessageHandlerSharedLock.ReleaseLock(pLock);
pLock = 0;
}
void MessageHandlerRef::Call(const Message& msg)
{
Lock::Locker lockScope(pLock);
for (int i = 0; i < HandlersCount; i++)
pHandlers[i]->OnMessage(msg);
}
void MessageHandlerRef::AddHandler(MessageHandler* handler)
{
OVR_ASSERT(!handler ||
MessageHandlerImpl::FromHandler(handler)->pLock == pLock);
Lock::Locker lockScope(pLock);
AddHandler_NTS(handler);
}
void MessageHandlerRef::AddHandler_NTS(MessageHandler* handler)
{
OVR_ASSERT(handler != NULL);
OVR_ASSERT(HandlersCount < MaxHandlersCount);
for (int i = 0; i < HandlersCount; i++)
if (pHandlers[i] == handler)
// handler already installed - do nothing
return;
pHandlers[HandlersCount] = handler;
HandlersCount++;
MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(handler);
OVR_ASSERT(handlerImpl->HandlerRefsCount < MessageHandlerImpl::MaxHandlerRefsCount);
handlerImpl->pHandlerRefs[handlerImpl->HandlerRefsCount] = this;
handlerImpl->HandlerRefsCount++;
// TBD: Call notifier on device?
}
bool MessageHandlerRef::RemoveHandler(MessageHandler* handler)
{
Lock::Locker lockScope(pLock);
for (int i = 0; i < HandlersCount; i++)
{
if (pHandlers[i] == handler)
return removeHandler(i);
}
return false;
}
bool MessageHandlerRef::removeHandler(int idx)
{
OVR_ASSERT(idx < HandlersCount);
MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(pHandlers[idx]);
for (int i = 0; i < handlerImpl->HandlerRefsCount; i++)
if (handlerImpl->pHandlerRefs[i] == this)
{
handlerImpl->pHandlerRefs[i] = handlerImpl->pHandlerRefs[handlerImpl->HandlerRefsCount - 1];
handlerImpl->HandlerRefsCount--;
pHandlers[idx] = pHandlers[HandlersCount - 1];
HandlersCount--;
return true;
}
// couldn't find a link in the opposite direction, assert in Debug
OVR_ASSERT(0);
pHandlers[idx] = pHandlers[HandlersCount - 1];
HandlersCount--;
return true;
}
MessageHandler::MessageHandler()
{
OVR_COMPILER_ASSERT(sizeof(Internal) > sizeof(MessageHandlerImpl));
Construct<MessageHandlerImpl>(Internal);
}
MessageHandler::~MessageHandler()
{
MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(this);
{
Lock::Locker lockedScope(handlerImpl->pLock);
OVR_ASSERT_LOG(handlerImpl->HandlerRefsCount == 0,
("~MessageHandler %p - Handler still active; call RemoveHandlerFromDevices", this));
}
Destruct<MessageHandlerImpl>(handlerImpl);
}
bool MessageHandler::IsHandlerInstalled() const
{
const MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(this);
Lock::Locker lockedScope(handlerImpl->pLock);
return handlerImpl->HandlerRefsCount > 0;
}
void MessageHandler::RemoveHandlerFromDevices()
{
MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(this);
Lock::Locker lockedScope(handlerImpl->pLock);
while (handlerImpl->HandlerRefsCount > 0)
{
MessageHandlerRef* use = handlerImpl->pHandlerRefs[0];
use->RemoveHandler(this);
}
}
Lock* MessageHandler::GetHandlerLock() const
{
const MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(this);
return handlerImpl->pLock;
}
//-------------------------------------------------------------------------------------
// ***** DeviceBase
// Delegate relevant implementation to DeviceRectord to avoid re-implementation in
// every derived Device.
void DeviceBase::AddRef()
{
getDeviceCommon()->DeviceAddRef();
}
void DeviceBase::Release()
{
getDeviceCommon()->DeviceRelease();
}
DeviceBase* DeviceBase::GetParent() const
{
return getDeviceCommon()->pParent.GetPtr();
}
DeviceManager* DeviceBase::GetManager() const
{
return getDeviceCommon()->pCreateDesc->GetManagerImpl();
}
void DeviceBase::AddMessageHandler(MessageHandler* handler)
{
getDeviceCommon()->HandlerRef.AddHandler(handler);
}
DeviceType DeviceBase::GetType() const
{
return getDeviceCommon()->pCreateDesc->Type;
}
bool DeviceBase::GetDeviceInfo(DeviceInfo* info) const
{
return getDeviceCommon()->pCreateDesc->GetDeviceInfo(info);
//info->Name[0] = 0;
//return false;
}
// Returns true if device is connected and usable
bool DeviceBase::IsConnected()
{
return getDeviceCommon()->ConnectedFlag;
}
// returns the MessageHandler's lock
Lock* DeviceBase::GetHandlerLock() const
{
return getDeviceCommon()->HandlerRef.GetLock();
}
// Derive DeviceManagerCreateDesc to provide abstract function implementation.
class DeviceManagerCreateDesc : public DeviceCreateDesc
{
public:
DeviceManagerCreateDesc(DeviceFactory* factory)
: DeviceCreateDesc(factory, Device_Manager) { }
// We don't need there on Manager since it isn't assigned to DeviceHandle.
virtual DeviceCreateDesc* Clone() const { return 0; }
virtual MatchResult MatchDevice(const DeviceCreateDesc&,
DeviceCreateDesc**) const { return Match_None; }
virtual DeviceBase* NewDeviceInstance() { return 0; }
virtual bool GetDeviceInfo(DeviceInfo*) const { return false; }
};
//-------------------------------------------------------------------------------------
// ***** DeviceManagerImpl
DeviceManagerImpl::DeviceManagerImpl()
: DeviceImpl<OVR::DeviceManager>(CreateManagerDesc(), 0)
//,DeviceCreateDescList(pCreateDesc ? pCreateDesc->pLock : 0)
{
if (pCreateDesc)
{
pCreateDesc->pLock->pManager = this;
}
}
DeviceManagerImpl::~DeviceManagerImpl()
{
// Shutdown must've been called.
OVR_ASSERT(!pCreateDesc->pDevice);
// Remove all factories
while(!Factories.IsEmpty())
{
DeviceFactory* factory = Factories.GetFirst();
factory->RemovedFromManager();
factory->RemoveNode();
}
}
DeviceCreateDesc* DeviceManagerImpl::CreateManagerDesc()
{
DeviceCreateDesc* managerDesc = new DeviceManagerCreateDesc(0);
if (managerDesc)
{
managerDesc->pLock = *new DeviceManagerLock;
}
return managerDesc;
}
bool DeviceManagerImpl::Initialize(DeviceBase* parent)
{
OVR_UNUSED(parent);
if (!pCreateDesc || !pCreateDesc->pLock)
return false;
pProfileManager = *ProfileManager::Create();
return true;
}
void DeviceManagerImpl::Shutdown()
{
// Remove all device descriptors from list while the lock is held.
// Some descriptors may survive longer due to handles.
while(!Devices.IsEmpty())
{
DeviceCreateDesc* devDesc = Devices.GetFirst();
OVR_ASSERT(!devDesc->pDevice); // Manager shouldn't be dying while Device exists.
devDesc->Enumerated = false;
devDesc->RemoveNode();
devDesc->pNext = devDesc->pPrev = 0;
if (devDesc->HandleCount == 0)
{
delete devDesc;
}
}
Devices.Clear();
// These must've been cleared by caller.
OVR_ASSERT(pCreateDesc->pDevice == 0);
OVR_ASSERT(pCreateDesc->pLock->pManager == 0);
pProfileManager.Clear();
}
// Callbacks for DeviceCreation/Release
DeviceBase* DeviceManagerImpl::CreateDevice_MgrThread(DeviceCreateDesc* createDesc, DeviceBase* parent)
{
// Calls to DeviceManagerImpl::CreateDevice are enqueued with wait while holding pManager,
// so 'this' must remain valid.
OVR_ASSERT(createDesc->pLock->pManager);
Lock::Locker devicesLock(GetLock());
// If device already exists, just AddRef to it.
if (createDesc->pDevice)
{
createDesc->pDevice->AddRef();
return createDesc->pDevice;
}
if (!parent)
parent = this;
DeviceBase* device = createDesc->NewDeviceInstance();
if (device)
{
if (device->getDeviceCommon()->Initialize(parent))
{
createDesc->pDevice = device;
}
else
{
// Don't go through Release() to avoid PushCall behaviour,
// as it is not needed here.
delete device;
device = 0;
}
}
return device;
}
Void DeviceManagerImpl::ReleaseDevice_MgrThread(DeviceBase* device)
{
// descKeepAlive will keep ManagerLock object alive as well,
// allowing us to exit gracefully.
Ptr<DeviceCreateDesc> descKeepAlive;
Lock::Locker devicesLock(GetLock());
DeviceCommon* devCommon = device->getDeviceCommon();
while(1)
{
UInt32 refCount = devCommon->RefCount;
if (refCount > 1)
{
if (devCommon->RefCount.CompareAndSet_NoSync(refCount, refCount-1))
{
// We decreented from initial count higher then 1;
// nothing else to do.
return 0;
}
}
else if (devCommon->RefCount.CompareAndSet_NoSync(1, 0))
{
// { 1 -> 0 } decrement succeded. Destroy this device.
break;
}
}
// At this point, may be releasing the device manager itself.
// This does not matter, however, since shutdown logic is the same
// in both cases. DeviceManager::Shutdown with begin shutdown process for
// the internal manager thread, which will eventually destroy itself.
// TBD: Clean thread shutdown.
descKeepAlive = devCommon->pCreateDesc;
descKeepAlive->pDevice = 0;
devCommon->Shutdown();
delete device;
return 0;
}
Void DeviceManagerImpl::EnumerateAllFactoryDevices()
{
// 1. Mark matching devices as NOT enumerated.
// 2. Call factory to enumerate all HW devices, adding any device that
// was not matched.
// 3. Remove non-matching devices.
Lock::Locker deviceLock(GetLock());
DeviceCreateDesc* devDesc, *nextdevDesc;
// 1.
for(devDesc = Devices.GetFirst();
!Devices.IsNull(devDesc); devDesc = devDesc->pNext)
{
//if (devDesc->pFactory == factory)
devDesc->Enumerated = false;
}
// 2.
DeviceFactory* factory = Factories.GetFirst();
while(!Factories.IsNull(factory))
{
EnumerateFactoryDevices(factory);
factory = factory->pNext;
}
// 3.
for(devDesc = Devices.GetFirst();
!Devices.IsNull(devDesc); devDesc = nextdevDesc)
{
// In case 'devDesc' gets removed.
nextdevDesc = devDesc->pNext;
// Note, device might be not enumerated since it is opened and
// in use! Do NOT notify 'device removed' in this case (!AB)
if (!devDesc->Enumerated)
{
// This deletes the devDesc for HandleCount == 0 due to Release in DeviceHandle.
CallOnDeviceRemoved(devDesc);
/*
if (devDesc->HandleCount == 0)
{
// Device must be dead if it ever existed, since it AddRefs to us.
// ~DeviceCreateDesc removes its node from list.
OVR_ASSERT(!devDesc->pDevice);
delete devDesc;
}
*/
}
}
return 0;
}
Ptr<DeviceCreateDesc> DeviceManagerImpl::AddDevice_NeedsLock(
const DeviceCreateDesc& createDesc)
{
// If found, mark as enumerated and we are done.
DeviceCreateDesc* descCandidate = 0;
for(DeviceCreateDesc* devDesc = Devices.GetFirst();
!Devices.IsNull(devDesc); devDesc = devDesc->pNext)
{
DeviceCreateDesc::MatchResult mr = devDesc->MatchDevice(createDesc, &descCandidate);
if (mr == DeviceCreateDesc::Match_Found)
{
devDesc->Enumerated = true;
if (!devDesc->pDevice)
CallOnDeviceAdded(devDesc);
return devDesc;
}
}
// Update candidate (this may involve writing fields to HMDDevice createDesc).
if (descCandidate)
{
bool newDevice = false;
if (descCandidate->UpdateMatchedCandidate(createDesc, &newDevice))
{
descCandidate->Enumerated = true;
if (!descCandidate->pDevice || newDevice)
CallOnDeviceAdded(descCandidate);
return descCandidate;
}
}
// If not found, add new device.
// - This stores a new descriptor with
// {pDevice = 0, HandleCount = 1, Enumerated = true}
DeviceCreateDesc* desc = createDesc.Clone();
desc->pLock = pCreateDesc->pLock;
Devices.PushBack(desc);
desc->Enumerated = true;
CallOnDeviceAdded(desc);
return desc;
}
Ptr<DeviceCreateDesc> DeviceManagerImpl::FindDevice(
const String& path,
DeviceType deviceType)
{
Lock::Locker deviceLock(GetLock());
DeviceCreateDesc* devDesc;
for (devDesc = Devices.GetFirst();
!Devices.IsNull(devDesc); devDesc = devDesc->pNext)
{
if ((deviceType == Device_None || deviceType == devDesc->Type) &&
devDesc->MatchDevice(path))
return devDesc;
}
return NULL;
}
Ptr<DeviceCreateDesc> DeviceManagerImpl::FindHIDDevice(const HIDDeviceDesc& hidDevDesc, bool created)
{
Lock::Locker deviceLock(GetLock());
DeviceCreateDesc* devDesc;
for (devDesc = Devices.GetFirst();
!Devices.IsNull(devDesc); devDesc = devDesc->pNext)
{
if (created)
{ // Search for matching device that is created
if (devDesc->MatchHIDDevice(hidDevDesc) && devDesc->pDevice)
return devDesc;
}
else
{ // Search for any matching device
if (devDesc->MatchHIDDevice(hidDevDesc))
return devDesc;
}
}
return NULL;
}
void DeviceManagerImpl::DetectHIDDevice(const HIDDeviceDesc& hidDevDesc)
{
Lock::Locker deviceLock(GetLock());
DeviceFactory* factory = Factories.GetFirst();
while(!Factories.IsNull(factory))
{
if (factory->DetectHIDDevice(this, hidDevDesc))
break;
factory = factory->pNext;
}
}
// Enumerates devices for a particular factory.
Void DeviceManagerImpl::EnumerateFactoryDevices(DeviceFactory* factory)
{
class FactoryEnumerateVisitor : public DeviceFactory::EnumerateVisitor
{
DeviceManagerImpl* pManager;
DeviceFactory* pFactory;
public:
FactoryEnumerateVisitor(DeviceManagerImpl* manager, DeviceFactory* factory)
: pManager(manager), pFactory(factory) { }
virtual void Visit(const DeviceCreateDesc& createDesc)
{
pManager->AddDevice_NeedsLock(createDesc);
}
};
FactoryEnumerateVisitor newDeviceVisitor(this, factory);
factory->EnumerateDevices(newDeviceVisitor);
return 0;
}
DeviceEnumerator<> DeviceManagerImpl::EnumerateDevicesEx(const DeviceEnumerationArgs& args)
{
Lock::Locker deviceLock(GetLock());
if (Devices.IsEmpty())
return DeviceEnumerator<>();
DeviceCreateDesc* firstDeviceDesc = Devices.GetFirst();
DeviceEnumerator<> e = enumeratorFromHandle(DeviceHandle(firstDeviceDesc), args);
if (!args.MatchRule(firstDeviceDesc->Type, firstDeviceDesc->Enumerated))
{
e.Next();
}
return e;
}
//-------------------------------------------------------------------------------------
// ***** DeviceCommon
void DeviceCommon::DeviceAddRef()
{
RefCount++;
}
void DeviceCommon::DeviceRelease()
{
while(1)
{
UInt32 refCount = RefCount;
OVR_ASSERT(refCount > 0);
if (refCount == 1)
{
DeviceManagerImpl* manager = pCreateDesc->GetManagerImpl();
ThreadCommandQueue* queue = manager->GetThreadQueue();
// Enqueue ReleaseDevice for {1 -> 0} transition with no wait.
// We pass our reference ownership into the queue to destroy.
// It's in theory possible for another thread to re-steal our device reference,
// but that is checked for atomically in DeviceManagerImpl::ReleaseDevice.
if (!queue->PushCall(manager, &DeviceManagerImpl::ReleaseDevice_MgrThread,
pCreateDesc->pDevice))
{
// PushCall shouldn't fail because background thread runs while manager is
// alive and we are holding Manager alive through pParent chain.
OVR_ASSERT(false);
}
// Warning! At his point everything, including manager, may be dead.
break;
}
else if (RefCount.CompareAndSet_NoSync(refCount, refCount-1))
{
break;
}
}
}
//-------------------------------------------------------------------------------------
// ***** DeviceCreateDesc
void DeviceCreateDesc::AddRef()
{
// Technically, HandleCount { 0 -> 1 } transition can only happen during Lock,
// but we leave this to caller to worry about (happens during enumeration).
HandleCount++;
}
void DeviceCreateDesc::Release()
{
while(1)
{
UInt32 handleCount = HandleCount;
// HandleCount must obviously be >= 1, since we are releasing it.
OVR_ASSERT(handleCount > 0);
// {1 -> 0} transition may cause us to be destroyed, so require a lock.
if (handleCount == 1)
{
Ptr<DeviceManagerLock> lockKeepAlive;
Lock::Locker deviceLockScope(GetLock());
if (!HandleCount.CompareAndSet_NoSync(handleCount, 0))
continue;
OVR_ASSERT(pDevice == 0);
// Destroy *this if the manager was destroyed already, or Enumerated
// is false (device no longer available).
if (!GetManagerImpl() || !Enumerated)
{
lockKeepAlive = pLock;
// Remove from manager list (only matters for !Enumerated).
if (pNext)
{
RemoveNode();
pNext = pPrev = 0;
}
delete this;
}
// Available DeviceCreateDesc may survive with { HandleCount == 0 },
// in case it might be enumerated again later.
break;
}
else if (HandleCount.CompareAndSet_NoSync(handleCount, handleCount-1))
{
break;
}
}
}
HMDDevice* HMDDevice::Disconnect(SensorDevice* psensor)
{
if (!psensor)
return NULL;
OVR::DeviceManager* manager = GetManager();
if (manager)
{
//DeviceManagerImpl* mgrImpl = static_cast<DeviceManagerImpl*>(manager);
Ptr<DeviceCreateDesc> desc = getDeviceCommon()->pCreateDesc;
if (desc)
{
class Visitor : public DeviceFactory::EnumerateVisitor
{
Ptr<DeviceCreateDesc> Desc;
public:
Visitor(DeviceCreateDesc* desc) : Desc(desc) {}
virtual void Visit(const DeviceCreateDesc& createDesc)
{
Lock::Locker lock(Desc->GetLock());
Desc->UpdateMatchedCandidate(createDesc);
}
} visitor(desc);
//SensorDeviceImpl* sImpl = static_cast<SensorDeviceImpl*>(psensor);
SensorDisplayInfoImpl displayInfo;
if (psensor->GetFeatureReport(displayInfo.Buffer, SensorDisplayInfoImpl::PacketSize))
{
displayInfo.Unpack();
// If we got display info, try to match / create HMDDevice as well
// so that sensor settings give preference.
if (displayInfo.DistortionType & SensorDisplayInfoImpl::Mask_BaseFmt)
{
SensorDeviceImpl::EnumerateHMDFromSensorDisplayInfo(displayInfo, visitor);
}
}
}
}
return this;
}
bool HMDDevice::IsDisconnected() const
{
OVR::HMDInfo info;
GetDeviceInfo(&info);
// if strlen(info.DisplayDeviceName) == 0 then
// this HMD is 'fake' (created using sensor).
return (strlen(info.DisplayDeviceName) == 0);
}
} // namespace OVR

View File

@ -0,0 +1,428 @@
/************************************************************************************
Filename : OVR_DeviceImpl.h
Content : Partial back-end independent implementation of Device interfaces
Created : October 10, 2012
Authors : Michael Antonov
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_DeviceImpl_h
#define OVR_DeviceImpl_h
#include "OVR_Device.h"
#include "Kernel/OVR_Atomic.h"
#include "Kernel/OVR_Log.h"
#include "Kernel/OVR_System.h"
#include "Kernel/OVR_Threads.h"
#include "OVR_ThreadCommandQueue.h"
#include "OVR_HIDDevice.h"
namespace OVR {
class DeviceManagerImpl;
class DeviceFactory;
enum
{
Oculus_VendorId = 0x2833,
Device_Tracker_ProductId = 0x0001,
Device_Tracker2_ProductId = 0x0021,
Device_KTracker_ProductId = 0x0010,
};
// Wrapper for MessageHandler that includes synchronization logic.
class MessageHandlerRef
{
enum
{
MaxHandlersCount = 4
};
public:
MessageHandlerRef(DeviceBase* device);
~MessageHandlerRef();
bool HasHandlers() const { return HandlersCount > 0; };
void AddHandler(MessageHandler* handler);
// returns false if the handler is not found
bool RemoveHandler(MessageHandler* handler);
// Not-thread-safe version
void AddHandler_NTS(MessageHandler* handler);
void Call(const Message& msg);
Lock* GetLock() const { return pLock; }
DeviceBase* GetDevice() const { return pDevice; }
private:
Lock* pLock; // Cached global handler lock.
DeviceBase* pDevice;
int HandlersCount;
MessageHandler* pHandlers[MaxHandlersCount];
bool removeHandler(int idx);
};
//-------------------------------------------------------------------------------------
// DeviceManagerLock is a synchronization lock used by DeviceManager for Devices
// and is allocated separately for potentially longer lifetime.
//
// DeviceManagerLock is used for all of the following:
// - Adding/removing devices
// - Reporting manager lifetime (pManager != 0) for DeviceHandles
// - Protecting device creation/shutdown.
class DeviceManagerLock : public RefCountBase<DeviceManagerLock>
{
public:
Lock CreateLock;
DeviceManagerImpl* pManager;
DeviceManagerLock() : pManager(0) { }
};
// DeviceCreateDesc provides all of the information needed to create any device, a derived
// instance of this class is created by DeviceFactory during enumeration.
// - DeviceCreateDesc may or may not be a part of DeviceManager::Devices list (check pNext != 0).
// - Referenced and kept alive by DeviceHandle.
class DeviceCreateDesc : public ListNode<DeviceCreateDesc>, public NewOverrideBase
{
void operator = (const DeviceCreateDesc&) { } // Assign not supported; suppress MSVC warning.
public:
DeviceCreateDesc(DeviceFactory* factory, DeviceType type)
: pFactory(factory), Type(type), pLock(0), HandleCount(0), pDevice(0), Enumerated(true)
{
pNext = pPrev = 0;
}
virtual ~DeviceCreateDesc()
{
OVR_ASSERT(!pDevice);
if (pNext)
RemoveNode();
}
DeviceManagerImpl* GetManagerImpl() const { return pLock->pManager; }
Lock* GetLock() const { return &pLock->CreateLock; }
// DeviceCreateDesc reference counting is tied to Devices list management,
// see comments for HandleCount.
void AddRef();
void Release();
// *** Device creation/matching Interface
// Cloning copies us to an allocated object when new device is enumerated.
virtual DeviceCreateDesc* Clone() const = 0;
// Creates a new device instance without Initializing it; the
// later is done my Initialize()/Shutdown() methods of the device itself.
virtual DeviceBase* NewDeviceInstance() = 0;
// Override to return device-specific info.
virtual bool GetDeviceInfo(DeviceInfo* info) const = 0;
enum MatchResult
{
Match_None,
Match_Found,
Match_Candidate
};
// Override to return Match_Found if descriptor matches our device.
// Match_Candidate can be returned, with pcandicate update, if this may be a match
// but more searching is necessary. If this is the case UpdateMatchedCandidate will be called.
virtual MatchResult MatchDevice(const DeviceCreateDesc& other,
DeviceCreateDesc** pcandidate) const = 0;
// Called for matched candidate after all potential matches are iterated.
// Used to update HMDevice creation arguments from Sensor.
// Optional return param 'newDeviceFlag' will be set to true if the
// 'desc' refers to a new device; false, otherwise.
// Return 'false' to create new object, 'true' if done with this argument.
virtual bool UpdateMatchedCandidate(
const DeviceCreateDesc& desc, bool* newDeviceFlag = NULL)
{ OVR_UNUSED2(desc, newDeviceFlag); return false; }
// Matches HID device to the descriptor.
virtual bool MatchHIDDevice(const HIDDeviceDesc&) const { return false; }
// Matches device by path.
virtual bool MatchDevice(const String& /*path*/) { return false; }
//protected:
DeviceFactory* const pFactory;
const DeviceType Type;
// List in which this descriptor lives. pList->CreateLock required if added/removed.
Ptr<DeviceManagerLock> pLock;
// Strong references to us: Incremented by Device, DeviceHandles & Enumerators.
// May be 0 if device not created and there are no handles.
// Following transitions require pList->CreateLock:
// {1 -> 0}: May delete & remove handle if no longer available.
// {0 -> 1}: Device creation is only possible if manager is still alive.
AtomicInt<UInt32> HandleCount;
// If not null, points to our created device instance. Modified during lock only.
DeviceBase* pDevice;
// True if device is marked as available during enumeration.
bool Enumerated;
};
// Common data present in the implementation of every DeviceBase.
// Injected by DeviceImpl.
class DeviceCommon
{
public:
AtomicInt<UInt32> RefCount;
Ptr<DeviceCreateDesc> pCreateDesc;
Ptr<DeviceBase> pParent;
volatile bool ConnectedFlag;
MessageHandlerRef HandlerRef;
DeviceCommon(DeviceCreateDesc* createDesc, DeviceBase* device, DeviceBase* parent)
: RefCount(1), pCreateDesc(createDesc), pParent(parent),
ConnectedFlag(true), HandlerRef(device)
{
}
virtual ~DeviceCommon() {}
// Device reference counting delegates to Manager thread to actually kill devices.
void DeviceAddRef();
void DeviceRelease();
Lock* GetLock() const { return pCreateDesc->GetLock(); }
virtual bool Initialize(DeviceBase* parent) = 0;
virtual void Shutdown() = 0;
};
//-------------------------------------------------------------------------------------
// DeviceImpl address DeviceRecord implementation to a device base class B.
// B must be derived form DeviceBase.
template<class B>
class DeviceImpl : public B, public DeviceCommon
{
public:
DeviceImpl(DeviceCreateDesc* createDesc, DeviceBase* parent)
: DeviceCommon(createDesc, getThis(), parent)
{
}
// Convenience method to avoid manager access typecasts.
DeviceManagerImpl* GetManagerImpl() const { return pCreateDesc->pLock->pManager; }
// Inline to avoid warnings.
DeviceImpl* getThis() { return this; }
// Common implementation delegate to avoid virtual inheritance and dynamic casts.
virtual DeviceCommon* getDeviceCommon() const { return (DeviceCommon*)this; }
/*
virtual void AddRef() { pCreateDesc->DeviceAddRef(); }
virtual void Release() { pCreateDesc->DeviceRelease(); }
virtual DeviceBase* GetParent() const { return pParent.GetPtr(); }
virtual DeviceManager* GetManager() const { return pCreateDesc->pLock->pManager;}
virtual void SetMessageHandler(MessageHandler* handler) { HanderRef.SetHandler(handler); }
virtual MessageHandler* GetMessageHandler() const { return HanderRef.GetHandler(); }
virtual DeviceType GetType() const { return pCreateDesc->Type; }
virtual DeviceType GetType() const { return pCreateDesc->Type; }
*/
};
//-------------------------------------------------------------------------------------
// ***** DeviceFactory
// DeviceFactory is maintained in DeviceManager for each separately-enumerable
// device type; factories allow separation of unrelated enumeration code.
class DeviceFactory : public ListNode<DeviceFactory>, public NewOverrideBase
{
public:
DeviceFactory() : pManager(0)
{
pNext = pPrev = 0;
}
virtual ~DeviceFactory() { }
DeviceManagerImpl* GetManagerImpl() { return pManager; }
// Notifiers called when we are added to/removed from a device.
virtual bool AddedToManager(DeviceManagerImpl* manager)
{
OVR_ASSERT(pManager == 0);
pManager = manager;
return true;
}
virtual void RemovedFromManager()
{
pManager = 0;
}
// *** Device Enumeration/Creation Support
// Passed to EnumerateDevices to be informed of every device detected.
class EnumerateVisitor
{
public:
virtual void Visit(const DeviceCreateDesc& createDesc) = 0;
};
// Enumerates factory devices by notifying EnumerateVisitor about every
// device that is present.
virtual void EnumerateDevices(EnumerateVisitor& visitor) = 0;
// Matches vendorId/productId pair with the factory; returns 'true'
// if the factory can handle the device.
virtual bool MatchVendorProduct(UInt16 vendorId, UInt16 productId) const
{
OVR_UNUSED2(vendorId, productId);
return false;
}
// Detects the HID device and adds the DeviceCreateDesc into Devices list, if
// the device belongs to this factory. Returns 'false', if not.
virtual bool DetectHIDDevice(DeviceManager* pdevMgr, const HIDDeviceDesc& desc)
{
OVR_UNUSED2(pdevMgr, desc);
return false;
}
protected:
DeviceManagerImpl* pManager;
};
//-------------------------------------------------------------------------------------
// ***** DeviceManagerImpl
// DeviceManagerImpl is a partial default DeviceManager implementation that
// maintains a list of devices and supports their enumeration.
class DeviceManagerImpl : public DeviceImpl<OVR::DeviceManager>, public ThreadCommandQueue
{
public:
DeviceManagerImpl();
~DeviceManagerImpl();
// Constructor helper function to create Descriptor and manager lock during initialization.
static DeviceCreateDesc* CreateManagerDesc();
// DeviceManagerImpl provides partial implementation of Initialize/Shutdown that must
// be called by the platform-specific derived class.
virtual bool Initialize(DeviceBase* parent);
virtual void Shutdown();
// Every DeviceManager has an associated profile manager, which is used to store
// user settings that may affect device behavior.
virtual ProfileManager* GetProfileManager() const { return pProfileManager.GetPtr(); }
// Override to return ThreadCommandQueue implementation used to post commands
// to the background device manager thread (that must be created by Initialize).
virtual ThreadCommandQueue* GetThreadQueue() = 0;
// Returns the thread id of the DeviceManager.
virtual ThreadId GetThreadId() const = 0;
virtual DeviceEnumerator<> EnumerateDevicesEx(const DeviceEnumerationArgs& args);
//
void AddFactory(DeviceFactory* factory)
{
// This lock is only needed if we call AddFactory after manager thread creation.
Lock::Locker scopeLock(GetLock());
Factories.PushBack(factory);
factory->AddedToManager(this);
}
void CallOnDeviceAdded(DeviceCreateDesc* desc)
{
HandlerRef.Call(MessageDeviceStatus(Message_DeviceAdded, this, DeviceHandle(desc)));
}
void CallOnDeviceRemoved(DeviceCreateDesc* desc)
{
HandlerRef.Call(MessageDeviceStatus(Message_DeviceRemoved, this, DeviceHandle(desc)));
}
// Helper to access Common data for a device.
static DeviceCommon* GetDeviceCommon(DeviceBase* device)
{
return device->getDeviceCommon();
}
// Background-thread callbacks for DeviceCreation/Release. These
DeviceBase* CreateDevice_MgrThread(DeviceCreateDesc* createDesc, DeviceBase* parent = 0);
Void ReleaseDevice_MgrThread(DeviceBase* device);
// Calls EnumerateDevices() on all factories
virtual Void EnumerateAllFactoryDevices();
// Enumerates devices for a particular factory.
virtual Void EnumerateFactoryDevices(DeviceFactory* factory);
virtual HIDDeviceManager* GetHIDDeviceManager() const
{
return HidDeviceManager;
}
// Adds device (DeviceCreateDesc*) into Devices. Returns NULL,
// if unsuccessful or device is already in the list.
virtual Ptr<DeviceCreateDesc> AddDevice_NeedsLock(const DeviceCreateDesc& createDesc);
// Finds a device descriptor by path and optional type.
Ptr<DeviceCreateDesc> FindDevice(const String& path, DeviceType = Device_None);
// Finds HID device by HIDDeviceDesc.
Ptr<DeviceCreateDesc> FindHIDDevice(const HIDDeviceDesc&, bool created);
void DetectHIDDevice(const HIDDeviceDesc&);
// Manager Lock-protected list of devices.
List<DeviceCreateDesc> Devices;
// Factories used to detect and manage devices.
List<DeviceFactory> Factories;
protected:
Ptr<HIDDeviceManager> HidDeviceManager;
Ptr<ProfileManager> pProfileManager;
};
} // namespace OVR
#endif

View File

@ -0,0 +1,273 @@
/************************************************************************************
PublicHeader: OVR.h
Filename : OVR_DeviceMessages.h
Content : Definition of messages generated by devices
Created : February 5, 2013
Authors : Lee Cooper
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_DeviceMessages_h
#define OVR_DeviceMessages_h
#include "OVR_DeviceConstants.h"
#include "OVR_DeviceHandle.h"
#include "Kernel/OVR_Math.h"
#include "Kernel/OVR_Array.h"
#include "Kernel/OVR_Color.h"
#include "Kernel/OVR_String.h"
namespace OVR {
class DeviceBase;
class DeviceHandle;
class String;
#define OVR_MESSAGETYPE(devName, msgIndex) ((Device_##devName << 8) | msgIndex)
// MessageType identifies the structure of the Message class; based on the message,
// casting can be used to obtain the exact value.
enum MessageType
{
// Used for unassigned message types.
Message_None = 0,
// Device Manager Messages
Message_DeviceAdded = OVR_MESSAGETYPE(Manager, 0), // A new device is detected by manager.
Message_DeviceRemoved = OVR_MESSAGETYPE(Manager, 1), // Existing device has been plugged/unplugged.
// Sensor Messages
Message_BodyFrame = OVR_MESSAGETYPE(Sensor, 0), // Emitted by sensor at regular intervals.
Message_ExposureFrame = OVR_MESSAGETYPE(Sensor, 1),
Message_PixelRead = OVR_MESSAGETYPE(Sensor, 2),
// Latency Tester Messages
Message_LatencyTestSamples = OVR_MESSAGETYPE(LatencyTester, 0),
Message_LatencyTestColorDetected = OVR_MESSAGETYPE(LatencyTester, 1),
Message_LatencyTestStarted = OVR_MESSAGETYPE(LatencyTester, 2),
Message_LatencyTestButton = OVR_MESSAGETYPE(LatencyTester, 3),
Message_CameraFrame = OVR_MESSAGETYPE(Camera, 0),
Message_CameraAdded = OVR_MESSAGETYPE(Camera, 1),
};
//-------------------------------------------------------------------------------------
// Base class for all messages.
class Message
{
public:
Message(MessageType type = Message_None,
DeviceBase* pdev = 0) : Type(type), pDevice(pdev)
{ }
MessageType Type; // What kind of message this is.
DeviceBase* pDevice; // Device that emitted the message.
};
// Sensor BodyFrame notification.
// Sensor uses Right-Handed coordinate system to return results, with the following
// axis definitions:
// - Y Up positive
// - X Right Positive
// - Z Back Positive
// Rotations a counter-clockwise (CCW) while looking in the negative direction
// of the axis. This means they are interpreted as follows:
// - Roll is rotation around Z, counter-clockwise (tilting left) in XY plane.
// - Yaw is rotation around Y, positive for turning left.
// - Pitch is rotation around X, positive for pitching up.
//-------------------------------------------------------------------------------------
// ***** Sensor
class MessageBodyFrame : public Message
{
public:
MessageBodyFrame(DeviceBase* dev)
: Message(Message_BodyFrame, dev), Temperature(0.0f), TimeDelta(0.0f)
{
}
Vector3f Acceleration; // Acceleration in m/s^2.
Vector3f RotationRate; // Angular velocity in rad/s.
Vector3f MagneticField; // Magnetic field strength in Gauss.
float Temperature; // Temperature reading on sensor surface, in degrees Celsius.
float TimeDelta; // Time passed since last Body Frame, in seconds.
// The absolute time from the host computers perspective that the message should be
// interpreted as. This is based on incoming timestamp and processed by a filter
// that syncs the clocks while attempting to keep the distance between messages
// device clock matching.
//
// Integration should use TimeDelta, but prediction into the future should derive
// the delta time from PredictToSeconds - AbsoluteTimeSeconds.
//
// This value will generally be <= the return from a call to ovr_GetTimeInSeconds(),
// but could be greater by under 1 ms due to system time update interrupt delays.
//
double AbsoluteTimeSeconds;
};
// Sent when we receive a device status changes (e.g.:
// Message_DeviceAdded, Message_DeviceRemoved).
class MessageDeviceStatus : public Message
{
public:
MessageDeviceStatus(MessageType type, DeviceBase* dev, const DeviceHandle &hdev)
: Message(type, dev), Handle(hdev) { }
DeviceHandle Handle;
};
class MessageExposureFrame : public Message
{
public:
MessageExposureFrame(DeviceBase* dev)
: Message(Message_ExposureFrame, dev),
CameraPattern(0), CameraFrameCount(0), CameraTimeSeconds(0) { }
UByte CameraPattern;
UInt32 CameraFrameCount;
double CameraTimeSeconds;
};
class MessagePixelRead : public Message
{
public:
MessagePixelRead(DeviceBase* dev)
: Message(Message_PixelRead, dev),
PixelReadValue(0), SensorTimeSeconds(0), FrameTimeSeconds(0) { }
UByte PixelReadValue;
UInt32 RawSensorTime;
UInt32 RawFrameTime;
double SensorTimeSeconds;
double FrameTimeSeconds;
};
//-------------------------------------------------------------------------------------
// ***** Latency Tester
// Sent when we receive Latency Tester samples.
class MessageLatencyTestSamples : public Message
{
public:
MessageLatencyTestSamples(DeviceBase* dev)
: Message(Message_LatencyTestSamples, dev)
{
}
Array<Color> Samples;
};
// Sent when a Latency Tester 'color detected' event occurs.
class MessageLatencyTestColorDetected : public Message
{
public:
MessageLatencyTestColorDetected(DeviceBase* dev)
: Message(Message_LatencyTestColorDetected, dev)
{
}
UInt16 Elapsed;
Color DetectedValue;
Color TargetValue;
};
// Sent when a Latency Tester 'change color' event occurs.
class MessageLatencyTestStarted : public Message
{
public:
MessageLatencyTestStarted(DeviceBase* dev)
: Message(Message_LatencyTestStarted, dev)
{
}
Color TargetValue;
};
// Sent when a Latency Tester 'button' event occurs.
class MessageLatencyTestButton : public Message
{
public:
MessageLatencyTestButton(DeviceBase* dev)
: Message(Message_LatencyTestButton, dev)
{
}
};
//-------------------------------------------------------------------------------------
// ***** Camera
// Sent by camera, frame.
class MessageCameraFrame : public Message
{
public:
MessageCameraFrame(DeviceBase* dev)
: Message(Message_CameraFrame, dev), CameraHandle(NULL), pFrameData(NULL)
{
LostFrames = 0;
}
void SetInfo(UInt32 frameNumber, double timeSeconds, UInt32 width, UInt32 height, UInt32 format)
{
FrameNumber = frameNumber;
ArrivalTimeSeconds = timeSeconds;
Width = width;
Height = height;
Format = format;
}
void SetData(const UByte* pdata, UInt32 sizeInBytes)
{
pFrameData = pdata;
FrameSizeInBytes = sizeInBytes;
}
UInt32 FrameNumber; // an index of the frame
double ArrivalTimeSeconds; // frame time in seconds, as recorded by the host computer
const UByte* pFrameData; // a ptr to frame data.
UInt32 FrameSizeInBytes; // size of the data in the pFrameData.
UInt32 Width, Height; // width & height in pixels.
UInt32 Format; // format of pixel, see CameraDevice::PixelFormat enum
UInt32 LostFrames; // number of lost frames before this frame
String DeviceIdentifier; // identifies the device sensing the message
UInt32* CameraHandle; // Identifies the camera object associated with this frame
};
// Sent when a new camera is connected
class MessageCameraAdded : public Message
{
public:
MessageCameraAdded(DeviceBase* dev)
: Message(Message_CameraAdded, dev) { }
MessageCameraAdded(UInt32* cam)
: Message(Message_CameraAdded, NULL), CameraHandle(cam) { }
UInt32* CameraHandle; // Identifies the camera object associated with this frame
};
} // namespace OVR
#endif

View File

@ -0,0 +1,154 @@
/************************************************************************************
Filename : OVR_HIDDevice.h
Content : Cross platform HID device interface.
Created : February 22, 2013
Authors : Lee Cooper
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_HIDDevice_h
#define OVR_HIDDevice_h
#include "OVR_HIDDeviceBase.h"
#include "Kernel/OVR_RefCount.h"
#include "Kernel/OVR_String.h"
#include "Kernel/OVR_Timer.h"
namespace OVR {
class HIDDevice;
class DeviceManager;
// HIDDeviceDesc contains interesting attributes of a HID device, including a Path
// that can be used to create it.
struct HIDDeviceDesc
{
UInt16 VendorId;
UInt16 ProductId;
UInt16 VersionNumber;
UInt16 Usage;
UInt16 UsagePage;
String Path; // Platform specific.
String Manufacturer;
String Product;
String SerialNumber;
};
// HIDEnumerateVisitor exposes a Visit interface called for every detected device
// by HIDDeviceManager::Enumerate.
class HIDEnumerateVisitor
{
public:
// Should return true if we are interested in supporting
// this HID VendorId and ProductId pair.
virtual bool MatchVendorProduct(UInt16 vendorId, UInt16 productId)
{ OVR_UNUSED2(vendorId, productId); return true; }
// Override to get notified about available device. Will only be called for
// devices that matched MatchVendorProduct.
virtual void Visit(HIDDevice&, const HIDDeviceDesc&) { }
};
//-------------------------------------------------------------------------------------
// ***** HIDDeviceManager
// Internal manager for enumerating and opening HID devices.
// If an OVR::DeviceManager is created then an OVR::HIDDeviceManager will automatically be created and can be accessed from the
// DeviceManager by calling 'GetHIDDeviceManager()'. When using HIDDeviceManager in standalone mode, the client must call
// 'Create' below.
class HIDDeviceManager : public RefCountBase<HIDDeviceManager>
{
public:
// Creates a new HIDDeviceManager. Only one instance of HIDDeviceManager should be created at a time.
static HIDDeviceManager* Create(Ptr<OVR::DeviceManager>& deviceManager);
// Enumerate HID devices using a HIDEnumerateVisitor derived visitor class.
virtual bool Enumerate(HIDEnumerateVisitor* enumVisitor) = 0;
// Open a HID device with the specified path.
virtual HIDDevice* Open(const String& path) = 0;
protected:
HIDDeviceManager()
{ }
};
//-------------------------------------------------------------------------------------
// ***** HIDDevice
// HID device object. This is designed to be operated in synchronous
// and asynchronous modes. With no handler set, input messages will be
// stored and can be retrieved by calling 'Read' or 'ReadBlocking'.
class HIDDevice : public RefCountBase<HIDDevice>, public HIDDeviceBase
{
public:
HIDDevice()
: Handler(NULL)
{
}
virtual ~HIDDevice() {}
virtual bool SetFeatureReport(UByte* data, UInt32 length) = 0;
virtual bool GetFeatureReport(UByte* data, UInt32 length) = 0;
// Not yet implemented.
/*
virtual bool Write(UByte* data, UInt32 length) = 0;
virtual bool Read(UByte* pData, UInt32 length, UInt32 timeoutMilliS) = 0;
virtual bool ReadBlocking(UByte* pData, UInt32 length) = 0;
*/
class HIDHandler
{
public:
virtual void OnInputReport(UByte* pData, UInt32 length)
{ OVR_UNUSED2(pData, length); }
virtual double OnTicks(double tickSeconds)
{ OVR_UNUSED1(tickSeconds); return 1000.0 ; }
enum HIDDeviceMessageType
{
HIDDeviceMessage_DeviceAdded = 0,
HIDDeviceMessage_DeviceRemoved = 1
};
virtual void OnDeviceMessage(HIDDeviceMessageType messageType)
{ OVR_UNUSED1(messageType); }
};
void SetHandler(HIDHandler* handler)
{ Handler = handler; }
protected:
HIDHandler* Handler;
};
} // namespace OVR
#endif

View File

@ -0,0 +1,51 @@
/************************************************************************************
PublicHeader: OVR.h
Filename : OVR_HIDDeviceBase.h
Content : Definition of HID device interface.
Created : March 11, 2013
Authors : Lee Cooper
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_HIDDeviceBase_h
#define OVR_HIDDeviceBase_h
#include "Kernel/OVR_Types.h"
namespace OVR {
//-------------------------------------------------------------------------------------
// ***** HIDDeviceBase
// Base interface for HID devices.
class HIDDeviceBase
{
public:
virtual ~HIDDeviceBase() { }
virtual bool SetFeatureReport(UByte* data, UInt32 length) = 0;
virtual bool GetFeatureReport(UByte* data, UInt32 length) = 0;
};
} // namespace OVR
#endif

View File

@ -0,0 +1,201 @@
/************************************************************************************
Filename : OVR_HIDDeviceImpl.h
Content : Implementation of HIDDevice.
Created : March 7, 2013
Authors : Lee Cooper
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_HIDDeviceImpl_h
#define OVR_HIDDeviceImpl_h
//#include "OVR_Device.h"
#include "OVR_DeviceImpl.h"
namespace OVR {
//-------------------------------------------------------------------------------------
class HIDDeviceCreateDesc : public DeviceCreateDesc
{
public:
HIDDeviceCreateDesc(DeviceFactory* factory, DeviceType type, const HIDDeviceDesc& hidDesc)
: DeviceCreateDesc(factory, type), HIDDesc(hidDesc) { }
HIDDeviceCreateDesc(const HIDDeviceCreateDesc& other)
: DeviceCreateDesc(other.pFactory, other.Type), HIDDesc(other.HIDDesc) { }
virtual bool MatchDevice(const String& path)
{
// should it be case insensitive?
return HIDDesc.Path.CompareNoCase(path) == 0;
}
HIDDeviceDesc HIDDesc;
};
//-------------------------------------------------------------------------------------
template<class B>
class HIDDeviceImpl : public DeviceImpl<B>, public HIDDevice::HIDHandler
{
public:
HIDDeviceImpl(HIDDeviceCreateDesc* createDesc, DeviceBase* parent)
: DeviceImpl<B>(createDesc, parent)
{
}
// HIDDevice::Handler interface.
virtual void OnDeviceMessage(HIDDeviceMessageType messageType)
{
MessageType handlerMessageType;
switch (messageType) {
case HIDDeviceMessage_DeviceAdded:
handlerMessageType = Message_DeviceAdded;
DeviceImpl<B>::ConnectedFlag = true;
break;
case HIDDeviceMessage_DeviceRemoved:
handlerMessageType = Message_DeviceRemoved;
DeviceImpl<B>::ConnectedFlag = false;
break;
default: OVR_ASSERT(0); return;
}
// Do device notification.
MessageDeviceStatus status(handlerMessageType, this, OVR::DeviceHandle(this->pCreateDesc));
this->HandlerRef.Call(status);
// Do device manager notification.
DeviceManagerImpl* manager = this->GetManagerImpl();
switch (handlerMessageType) {
case Message_DeviceAdded:
manager->CallOnDeviceAdded(this->pCreateDesc);
break;
case Message_DeviceRemoved:
manager->CallOnDeviceRemoved(this->pCreateDesc);
break;
default:;
}
}
virtual bool Initialize(DeviceBase* parent)
{
// Open HID device.
HIDDeviceDesc& hidDesc = *getHIDDesc();
HIDDeviceManager* pManager = GetHIDDeviceManager();
HIDDevice* device = pManager->Open(hidDesc.Path);
if (!device)
{
return false;
}
InternalDevice = *device;
InternalDevice->SetHandler(this);
// AddRef() to parent, forcing chain to stay alive.
DeviceImpl<B>::pParent = parent;
return true;
}
virtual void Shutdown()
{
InternalDevice->SetHandler(NULL);
DeviceImpl<B>::pParent.Clear();
}
DeviceManager* GetDeviceManager()
{
return DeviceImpl<B>::pCreateDesc->GetManagerImpl();
}
HIDDeviceManager* GetHIDDeviceManager()
{
return DeviceImpl<B>::pCreateDesc->GetManagerImpl()->GetHIDDeviceManager();
}
bool SetFeatureReport(UByte* data, UInt32 length)
{
// Push call with wait.
bool result = false;
ThreadCommandQueue* pQueue = this->GetManagerImpl()->GetThreadQueue();
if (!pQueue->PushCallAndWaitResult(this, &HIDDeviceImpl::setFeatureReport, &result, data, length))
return false;
return result;
}
bool setFeatureReport(UByte* data, UInt32 length)
{
return InternalDevice->SetFeatureReport(data, length);
}
bool GetFeatureReport(UByte* data, UInt32 length)
{
bool result = false;
ThreadCommandQueue* pQueue = this->GetManagerImpl()->GetThreadQueue();
if (!pQueue->PushCallAndWaitResult(this, &HIDDeviceImpl::getFeatureReport, &result, data, length))
return false;
return result;
}
bool getFeatureReport(UByte* data, UInt32 length)
{
return InternalDevice->GetFeatureReport(data, length);
}
UByte GetDeviceInterfaceVersion()
{
UInt16 versionNumber = getHIDDesc()->VersionNumber;
// Our interface and hardware versions are represented as two BCD digits each.
// Interface version is in the last two digits.
UByte interfaceVersion = (UByte) ((versionNumber & 0x000F) >> 0) * 1 +
((versionNumber & 0x00F0) >> 4) * 10;
return interfaceVersion;
}
protected:
HIDDevice* GetInternalDevice() const
{
return InternalDevice;
}
HIDDeviceDesc* getHIDDesc() const
{ return &getCreateDesc()->HIDDesc; }
HIDDeviceCreateDesc* getCreateDesc() const
{ return (HIDDeviceCreateDesc*) &(*DeviceImpl<B>::pCreateDesc); }
private:
Ptr<HIDDevice> InternalDevice;
};
} // namespace OVR
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,164 @@
/************************************************************************************
PublicHeader: None
Filename : OVR_JSON.h
Content : JSON format reader and writer
Created : April 9, 2013
Author : Brant Lewis
Notes :
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_JSON_H
#define OVR_JSON_H
#include "Kernel/OVR_RefCount.h"
#include "Kernel/OVR_String.h"
#include "Kernel/OVR_List.h"
namespace OVR {
// JSONItemType describes the type of JSON item, specifying the type of
// data that can be obtained from it.
enum JSONItemType
{
JSON_None = 0,
JSON_Null = 1,
JSON_Bool = 2,
JSON_Number = 3,
JSON_String = 4,
JSON_Array = 5,
JSON_Object = 6
};
//-----------------------------------------------------------------------------
// ***** JSON
// JSON object represents a JSON node that can be either a root of the JSON tree
// or a child item. Every node has a type that describes what is is.
// New JSON trees are typically loaded JSON::Load or created with JSON::Parse.
class JSON : public RefCountBase<JSON>, public ListNode<JSON>
{
protected:
List<JSON> Children;
public:
JSONItemType Type; // Type of this JSON node.
String Name; // Name part of the {Name, Value} pair in a parent object.
String Value;
double dValue;
public:
~JSON();
// *** Creation of NEW JSON objects
static JSON* CreateObject() { return new JSON(JSON_Object);}
static JSON* CreateNull() { return new JSON(JSON_Null); }
static JSON* CreateArray() { return new JSON(JSON_Array); }
static JSON* CreateBool(bool b) { return createHelper(JSON_Bool, b ? 1.0 : 0.0); }
static JSON* CreateNumber(double num) { return createHelper(JSON_Number, num); }
static JSON* CreateString(const char *s) { return createHelper(JSON_String, 0.0, s); }
// Creates a new JSON object from parsing string.
// Returns null pointer and fills in *perror in case of parse error.
static JSON* Parse(const char* buff, const char** perror = 0);
// This version works for buffers that are not null terminated strings.
static JSON* ParseBuffer(const char *buff, int len, const char** perror = 0);
// Loads and parses a JSON object from a file.
// Returns 0 and assigns perror with error message on fail.
static JSON* Load(const char* path, const char** perror = 0);
// Saves a JSON object to a file.
bool Save(const char* path);
// *** Object Member Access
// These provide access to child items of the list.
bool HasItems() const { return Children.IsEmpty(); }
// Returns first/last child item, or null if child list is empty
JSON* GetFirstItem() { return (!Children.IsEmpty()) ? Children.GetFirst() : 0; }
JSON* GetLastItem() { return (!Children.IsEmpty()) ? Children.GetLast() : 0; }
// Counts the number of items in the object; these methods are inefficient.
unsigned GetItemCount() const;
JSON* GetItemByIndex(unsigned i);
JSON* GetItemByName(const char* name);
// Accessors by name
double GetNumberByName(const char *name, double defValue = 0.0);
int GetIntByName(const char *name, int defValue = 0);
bool GetBoolByName(const char *name, bool defValue = false);
String GetStringByName(const char *name, const String &defValue = "");
// Returns next item in a list of children; 0 if no more items exist.
JSON* GetNextItem(JSON* item) { return Children.IsNull(item->pNext) ? 0 : item->pNext; }
JSON* GetPrevItem(JSON* item) { return Children.IsNull(item->pPrev) ? 0 : item->pPrev; }
// Child item access functions
void AddItem(const char *string, JSON* item);
void AddNullItem(const char* name) { AddItem(name, CreateNull()); }
void AddBoolItem(const char* name, bool b) { AddItem(name, CreateBool(b)); }
void AddNumberItem(const char* name, double n) { AddItem(name, CreateNumber(n)); }
void AddStringItem(const char* name, const char* s) { AddItem(name, CreateString(s)); }
// void ReplaceItem(unsigned index, JSON* new_item);
// void DeleteItem(unsigned index);
void RemoveLast();
// *** Array Element Access
// Add new elements to the end of array.
void AddArrayElement(JSON *item);
void InsertArrayElement(int index, JSON* item);
void AddArrayNumber(double n) { AddArrayElement(CreateNumber(n)); }
void AddArrayString(const char* s) { AddArrayElement(CreateString(s)); }
// Accessed array elements; currently inefficient.
int GetArraySize();
double GetArrayNumber(int index);
const char* GetArrayString(int index);
JSON* Copy(); // Create a copy of this object
protected:
JSON(JSONItemType itemType = JSON_Object);
static JSON* createHelper(JSONItemType itemType, double dval, const char* strVal = 0);
// JSON Parsing helper functions.
const char* parseValue(const char *buff, const char** perror);
const char* parseNumber(const char *num);
const char* parseArray(const char* value, const char** perror);
const char* parseObject(const char* value, const char** perror);
const char* parseString(const char* str, const char** perror);
char* PrintValue(int depth, bool fmt);
char* PrintObject(int depth, bool fmt);
char* PrintArray(int depth, bool fmt);
};
}
#endif

View File

@ -0,0 +1,773 @@
/************************************************************************************
Filename : OVR_LatencyTestImpl.cpp
Content : Oculus Latency Tester device implementation.
Created : March 7, 2013
Authors : Lee Cooper
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_LatencyTestImpl.h"
#include "Kernel/OVR_Alg.h"
namespace OVR {
using namespace Alg;
//-------------------------------------------------------------------------------------
// ***** Oculus Latency Tester specific packet data structures
enum {
LatencyTester_VendorId = Oculus_VendorId,
LatencyTester_ProductId = 0x0101,
};
static void UnpackSamples(const UByte* buffer, UByte* r, UByte* g, UByte* b)
{
*r = buffer[0];
*g = buffer[1];
*b = buffer[2];
}
// Messages we handle.
enum LatencyTestMessageType
{
LatencyTestMessage_None = 0,
LatencyTestMessage_Samples = 1,
LatencyTestMessage_ColorDetected = 2,
LatencyTestMessage_TestStarted = 3,
LatencyTestMessage_Button = 4,
LatencyTestMessage_Unknown = 0x100,
LatencyTestMessage_SizeError = 0x101,
};
struct LatencyTestSample
{
UByte Value[3];
};
struct LatencyTestSamples
{
UByte SampleCount;
UInt16 Timestamp;
LatencyTestSample Samples[20];
LatencyTestMessageType Decode(const UByte* buffer, int size)
{
if (size < 64)
{
return LatencyTestMessage_SizeError;
}
SampleCount = buffer[1];
Timestamp = DecodeUInt16(buffer + 2);
for (UByte i = 0; i < SampleCount; i++)
{
UnpackSamples(buffer + 4 + (3 * i), &Samples[i].Value[0], &Samples[i].Value[1], &Samples[i].Value[2]);
}
return LatencyTestMessage_Samples;
}
};
struct LatencyTestSamplesMessage
{
LatencyTestMessageType Type;
LatencyTestSamples Samples;
};
bool DecodeLatencyTestSamplesMessage(LatencyTestSamplesMessage* message, UByte* buffer, int size)
{
memset(message, 0, sizeof(LatencyTestSamplesMessage));
if (size < 64)
{
message->Type = LatencyTestMessage_SizeError;
return false;
}
switch (buffer[0])
{
case LatencyTestMessage_Samples:
message->Type = message->Samples.Decode(buffer, size);
break;
default:
message->Type = LatencyTestMessage_Unknown;
break;
}
return (message->Type < LatencyTestMessage_Unknown) && (message->Type != LatencyTestMessage_None);
}
struct LatencyTestColorDetected
{
UInt16 CommandID;
UInt16 Timestamp;
UInt16 Elapsed;
UByte TriggerValue[3];
UByte TargetValue[3];
LatencyTestMessageType Decode(const UByte* buffer, int size)
{
if (size < 13)
return LatencyTestMessage_SizeError;
CommandID = DecodeUInt16(buffer + 1);
Timestamp = DecodeUInt16(buffer + 3);
Elapsed = DecodeUInt16(buffer + 5);
memcpy(TriggerValue, buffer + 7, 3);
memcpy(TargetValue, buffer + 10, 3);
return LatencyTestMessage_ColorDetected;
}
};
struct LatencyTestColorDetectedMessage
{
LatencyTestMessageType Type;
LatencyTestColorDetected ColorDetected;
};
bool DecodeLatencyTestColorDetectedMessage(LatencyTestColorDetectedMessage* message, UByte* buffer, int size)
{
memset(message, 0, sizeof(LatencyTestColorDetectedMessage));
if (size < 13)
{
message->Type = LatencyTestMessage_SizeError;
return false;
}
switch (buffer[0])
{
case LatencyTestMessage_ColorDetected:
message->Type = message->ColorDetected.Decode(buffer, size);
break;
default:
message->Type = LatencyTestMessage_Unknown;
break;
}
return (message->Type < LatencyTestMessage_Unknown) && (message->Type != LatencyTestMessage_None);
}
struct LatencyTestStarted
{
UInt16 CommandID;
UInt16 Timestamp;
UByte TargetValue[3];
LatencyTestMessageType Decode(const UByte* buffer, int size)
{
if (size < 8)
return LatencyTestMessage_SizeError;
CommandID = DecodeUInt16(buffer + 1);
Timestamp = DecodeUInt16(buffer + 3);
memcpy(TargetValue, buffer + 5, 3);
return LatencyTestMessage_TestStarted;
}
};
struct LatencyTestStartedMessage
{
LatencyTestMessageType Type;
LatencyTestStarted TestStarted;
};
bool DecodeLatencyTestStartedMessage(LatencyTestStartedMessage* message, UByte* buffer, int size)
{
memset(message, 0, sizeof(LatencyTestStartedMessage));
if (size < 8)
{
message->Type = LatencyTestMessage_SizeError;
return false;
}
switch (buffer[0])
{
case LatencyTestMessage_TestStarted:
message->Type = message->TestStarted.Decode(buffer, size);
break;
default:
message->Type = LatencyTestMessage_Unknown;
break;
}
return (message->Type < LatencyTestMessage_Unknown) && (message->Type != LatencyTestMessage_None);
}
struct LatencyTestButton
{
UInt16 CommandID;
UInt16 Timestamp;
LatencyTestMessageType Decode(const UByte* buffer, int size)
{
if (size < 5)
return LatencyTestMessage_SizeError;
CommandID = DecodeUInt16(buffer + 1);
Timestamp = DecodeUInt16(buffer + 3);
return LatencyTestMessage_Button;
}
};
struct LatencyTestButtonMessage
{
LatencyTestMessageType Type;
LatencyTestButton Button;
};
bool DecodeLatencyTestButtonMessage(LatencyTestButtonMessage* message, UByte* buffer, int size)
{
memset(message, 0, sizeof(LatencyTestButtonMessage));
if (size < 5)
{
message->Type = LatencyTestMessage_SizeError;
return false;
}
switch (buffer[0])
{
case LatencyTestMessage_Button:
message->Type = message->Button.Decode(buffer, size);
break;
default:
message->Type = LatencyTestMessage_Unknown;
break;
}
return (message->Type < LatencyTestMessage_Unknown) && (message->Type != LatencyTestMessage_None);
}
struct LatencyTestConfigurationImpl
{
enum { PacketSize = 5 };
UByte Buffer[PacketSize];
OVR::LatencyTestConfiguration Configuration;
LatencyTestConfigurationImpl(const OVR::LatencyTestConfiguration& configuration)
: Configuration(configuration)
{
Pack();
}
void Pack()
{
Buffer[0] = 5;
Buffer[1] = UByte(Configuration.SendSamples);
Buffer[2] = Configuration.Threshold.R;
Buffer[3] = Configuration.Threshold.G;
Buffer[4] = Configuration.Threshold.B;
}
void Unpack()
{
Configuration.SendSamples = Buffer[1] != 0 ? true : false;
Configuration.Threshold.R = Buffer[2];
Configuration.Threshold.G = Buffer[3];
Configuration.Threshold.B = Buffer[4];
}
};
struct LatencyTestCalibrateImpl
{
enum { PacketSize = 4 };
UByte Buffer[PacketSize];
Color CalibrationColor;
LatencyTestCalibrateImpl(const Color& calibrationColor)
: CalibrationColor(calibrationColor)
{
Pack();
}
void Pack()
{
Buffer[0] = 7;
Buffer[1] = CalibrationColor.R;
Buffer[2] = CalibrationColor.G;
Buffer[3] = CalibrationColor.B;
}
void Unpack()
{
CalibrationColor.R = Buffer[1];
CalibrationColor.G = Buffer[2];
CalibrationColor.B = Buffer[3];
}
};
struct LatencyTestStartTestImpl
{
enum { PacketSize = 6 };
UByte Buffer[PacketSize];
Color TargetColor;
LatencyTestStartTestImpl(const Color& targetColor)
: TargetColor(targetColor)
{
Pack();
}
void Pack()
{
UInt16 commandID = 1;
Buffer[0] = 8;
EncodeUInt16(Buffer+1, commandID);
Buffer[3] = TargetColor.R;
Buffer[4] = TargetColor.G;
Buffer[5] = TargetColor.B;
}
void Unpack()
{
// UInt16 commandID = DecodeUInt16(Buffer+1);
TargetColor.R = Buffer[3];
TargetColor.G = Buffer[4];
TargetColor.B = Buffer[5];
}
};
struct LatencyTestDisplayImpl
{
enum { PacketSize = 6 };
UByte Buffer[PacketSize];
OVR::LatencyTestDisplay Display;
LatencyTestDisplayImpl(const OVR::LatencyTestDisplay& display)
: Display(display)
{
Pack();
}
void Pack()
{
Buffer[0] = 9;
Buffer[1] = Display.Mode;
EncodeUInt32(Buffer+2, Display.Value);
}
void Unpack()
{
Display.Mode = Buffer[1];
Display.Value = DecodeUInt32(Buffer+2);
}
};
//-------------------------------------------------------------------------------------
// ***** LatencyTestDeviceFactory
LatencyTestDeviceFactory &LatencyTestDeviceFactory::GetInstance()
{
static LatencyTestDeviceFactory instance;
return instance;
}
void LatencyTestDeviceFactory::EnumerateDevices(EnumerateVisitor& visitor)
{
class LatencyTestEnumerator : public HIDEnumerateVisitor
{
// Assign not supported; suppress MSVC warning.
void operator = (const LatencyTestEnumerator&) { }
DeviceFactory* pFactory;
EnumerateVisitor& ExternalVisitor;
public:
LatencyTestEnumerator(DeviceFactory* factory, EnumerateVisitor& externalVisitor)
: pFactory(factory), ExternalVisitor(externalVisitor) { }
virtual bool MatchVendorProduct(UInt16 vendorId, UInt16 productId)
{
return pFactory->MatchVendorProduct(vendorId, productId);
}
virtual void Visit(HIDDevice& device, const HIDDeviceDesc& desc)
{
OVR_UNUSED(device);
LatencyTestDeviceCreateDesc createDesc(pFactory, desc);
ExternalVisitor.Visit(createDesc);
}
};
LatencyTestEnumerator latencyTestEnumerator(this, visitor);
GetManagerImpl()->GetHIDDeviceManager()->Enumerate(&latencyTestEnumerator);
}
bool LatencyTestDeviceFactory::MatchVendorProduct(UInt16 vendorId, UInt16 productId) const
{
return ((vendorId == LatencyTester_VendorId) && (productId == LatencyTester_ProductId));
}
bool LatencyTestDeviceFactory::DetectHIDDevice(DeviceManager* pdevMgr,
const HIDDeviceDesc& desc)
{
if (MatchVendorProduct(desc.VendorId, desc.ProductId))
{
LatencyTestDeviceCreateDesc createDesc(this, desc);
return pdevMgr->AddDevice_NeedsLock(createDesc).GetPtr() != NULL;
}
return false;
}
//-------------------------------------------------------------------------------------
// ***** LatencyTestDeviceCreateDesc
DeviceBase* LatencyTestDeviceCreateDesc::NewDeviceInstance()
{
return new LatencyTestDeviceImpl(this);
}
bool LatencyTestDeviceCreateDesc::GetDeviceInfo(DeviceInfo* info) const
{
if ((info->InfoClassType != Device_LatencyTester) &&
(info->InfoClassType != Device_None))
return false;
info->Type = Device_LatencyTester;
info->ProductName = HIDDesc.Product;
info->Manufacturer = HIDDesc.Manufacturer;
info->Version = HIDDesc.VersionNumber;
if (info->InfoClassType == Device_LatencyTester)
{
SensorInfo* sinfo = (SensorInfo*)info;
sinfo->VendorId = HIDDesc.VendorId;
sinfo->ProductId = HIDDesc.ProductId;
sinfo->SerialNumber = HIDDesc.SerialNumber;
}
return true;
}
//-------------------------------------------------------------------------------------
// ***** LatencyTestDevice
LatencyTestDeviceImpl::LatencyTestDeviceImpl(LatencyTestDeviceCreateDesc* createDesc)
: OVR::HIDDeviceImpl<OVR::LatencyTestDevice>(createDesc, 0)
{
}
LatencyTestDeviceImpl::~LatencyTestDeviceImpl()
{
// Check that Shutdown() was called.
OVR_ASSERT(!pCreateDesc->pDevice);
}
// Internal creation APIs.
bool LatencyTestDeviceImpl::Initialize(DeviceBase* parent)
{
if (HIDDeviceImpl<OVR::LatencyTestDevice>::Initialize(parent))
{
LogText("OVR::LatencyTestDevice initialized.\n");
return true;
}
return false;
}
void LatencyTestDeviceImpl::Shutdown()
{
HIDDeviceImpl<OVR::LatencyTestDevice>::Shutdown();
LogText("OVR::LatencyTestDevice - Closed '%s'\n", getHIDDesc()->Path.ToCStr());
}
void LatencyTestDeviceImpl::OnInputReport(UByte* pData, UInt32 length)
{
bool processed = false;
if (!processed)
{
LatencyTestSamplesMessage message;
if (DecodeLatencyTestSamplesMessage(&message, pData, length))
{
processed = true;
onLatencyTestSamplesMessage(&message);
}
}
if (!processed)
{
LatencyTestColorDetectedMessage message;
if (DecodeLatencyTestColorDetectedMessage(&message, pData, length))
{
processed = true;
onLatencyTestColorDetectedMessage(&message);
}
}
if (!processed)
{
LatencyTestStartedMessage message;
if (DecodeLatencyTestStartedMessage(&message, pData, length))
{
processed = true;
onLatencyTestStartedMessage(&message);
}
}
if (!processed)
{
LatencyTestButtonMessage message;
if (DecodeLatencyTestButtonMessage(&message, pData, length))
{
processed = true;
onLatencyTestButtonMessage(&message);
}
}
}
bool LatencyTestDeviceImpl::SetConfiguration(const OVR::LatencyTestConfiguration& configuration, bool waitFlag)
{
bool result = false;
ThreadCommandQueue* queue = GetManagerImpl()->GetThreadQueue();
if (GetManagerImpl()->GetThreadId() != OVR::GetCurrentThreadId())
{
if (!waitFlag)
{
return queue->PushCall(this, &LatencyTestDeviceImpl::setConfiguration, configuration);
}
if (!queue->PushCallAndWaitResult( this,
&LatencyTestDeviceImpl::setConfiguration,
&result,
configuration))
{
return false;
}
}
else
return setConfiguration(configuration);
return result;
}
bool LatencyTestDeviceImpl::setConfiguration(const OVR::LatencyTestConfiguration& configuration)
{
LatencyTestConfigurationImpl ltc(configuration);
return GetInternalDevice()->SetFeatureReport(ltc.Buffer, LatencyTestConfigurationImpl::PacketSize);
}
bool LatencyTestDeviceImpl::GetConfiguration(OVR::LatencyTestConfiguration* configuration)
{
bool result = false;
ThreadCommandQueue* pQueue = this->GetManagerImpl()->GetThreadQueue();
if (!pQueue->PushCallAndWaitResult(this, &LatencyTestDeviceImpl::getConfiguration, &result, configuration))
return false;
return result;
}
bool LatencyTestDeviceImpl::getConfiguration(OVR::LatencyTestConfiguration* configuration)
{
LatencyTestConfigurationImpl ltc(*configuration);
if (GetInternalDevice()->GetFeatureReport(ltc.Buffer, LatencyTestConfigurationImpl::PacketSize))
{
ltc.Unpack();
*configuration = ltc.Configuration;
return true;
}
return false;
}
bool LatencyTestDeviceImpl::SetCalibrate(const Color& calibrationColor, bool waitFlag)
{
bool result = false;
ThreadCommandQueue* queue = GetManagerImpl()->GetThreadQueue();
if (!waitFlag)
{
return queue->PushCall(this, &LatencyTestDeviceImpl::setCalibrate, calibrationColor);
}
if (!queue->PushCallAndWaitResult( this,
&LatencyTestDeviceImpl::setCalibrate,
&result,
calibrationColor))
{
return false;
}
return result;
}
bool LatencyTestDeviceImpl::setCalibrate(const Color& calibrationColor)
{
LatencyTestCalibrateImpl ltc(calibrationColor);
return GetInternalDevice()->SetFeatureReport(ltc.Buffer, LatencyTestCalibrateImpl::PacketSize);
}
bool LatencyTestDeviceImpl::SetStartTest(const Color& targetColor, bool waitFlag)
{
bool result = false;
ThreadCommandQueue* queue = GetManagerImpl()->GetThreadQueue();
if (!waitFlag)
{
return queue->PushCall(this, &LatencyTestDeviceImpl::setStartTest, targetColor);
}
if (!queue->PushCallAndWaitResult( this,
&LatencyTestDeviceImpl::setStartTest,
&result,
targetColor))
{
return false;
}
return result;
}
bool LatencyTestDeviceImpl::setStartTest(const Color& targetColor)
{
LatencyTestStartTestImpl ltst(targetColor);
return GetInternalDevice()->SetFeatureReport(ltst.Buffer, LatencyTestStartTestImpl::PacketSize);
}
bool LatencyTestDeviceImpl::SetDisplay(const OVR::LatencyTestDisplay& display, bool waitFlag)
{
bool result = false;
ThreadCommandQueue * queue = GetManagerImpl()->GetThreadQueue();
if (!waitFlag)
{
return queue->PushCall(this, &LatencyTestDeviceImpl::setDisplay, display);
}
if (!queue->PushCallAndWaitResult( this,
&LatencyTestDeviceImpl::setDisplay,
&result,
display))
{
return false;
}
return result;
}
bool LatencyTestDeviceImpl::setDisplay(const OVR::LatencyTestDisplay& display)
{
LatencyTestDisplayImpl ltd(display);
return GetInternalDevice()->SetFeatureReport(ltd.Buffer, LatencyTestDisplayImpl::PacketSize);
}
void LatencyTestDeviceImpl::onLatencyTestSamplesMessage(LatencyTestSamplesMessage* message)
{
if (message->Type != LatencyTestMessage_Samples)
return;
LatencyTestSamples& s = message->Samples;
// Call OnMessage() within a lock to avoid conflicts with handlers.
Lock::Locker scopeLock(HandlerRef.GetLock());
if (HandlerRef.HasHandlers())
{
MessageLatencyTestSamples samples(this);
for (UByte i = 0; i < s.SampleCount; i++)
{
samples.Samples.PushBack(Color(s.Samples[i].Value[0], s.Samples[i].Value[1], s.Samples[i].Value[2]));
}
HandlerRef.Call(samples);
}
}
void LatencyTestDeviceImpl::onLatencyTestColorDetectedMessage(LatencyTestColorDetectedMessage* message)
{
if (message->Type != LatencyTestMessage_ColorDetected)
return;
LatencyTestColorDetected& s = message->ColorDetected;
// Call OnMessage() within a lock to avoid conflicts with handlers.
Lock::Locker scopeLock(HandlerRef.GetLock());
if (HandlerRef.HasHandlers())
{
MessageLatencyTestColorDetected detected(this);
detected.Elapsed = s.Elapsed;
detected.DetectedValue = Color(s.TriggerValue[0], s.TriggerValue[1], s.TriggerValue[2]);
detected.TargetValue = Color(s.TargetValue[0], s.TargetValue[1], s.TargetValue[2]);
HandlerRef.Call(detected);
}
}
void LatencyTestDeviceImpl::onLatencyTestStartedMessage(LatencyTestStartedMessage* message)
{
if (message->Type != LatencyTestMessage_TestStarted)
return;
LatencyTestStarted& ts = message->TestStarted;
// Call OnMessage() within a lock to avoid conflicts with handlers.
Lock::Locker scopeLock(HandlerRef.GetLock());
if (HandlerRef.HasHandlers())
{
MessageLatencyTestStarted started(this);
started.TargetValue = Color(ts.TargetValue[0], ts.TargetValue[1], ts.TargetValue[2]);
HandlerRef.Call(started);
}
}
void LatencyTestDeviceImpl::onLatencyTestButtonMessage(LatencyTestButtonMessage* message)
{
if (message->Type != LatencyTestMessage_Button)
return;
// LatencyTestButton& s = message->Button;
// Call OnMessage() within a lock to avoid conflicts with handlers.
Lock::Locker scopeLock(HandlerRef.GetLock());
if (HandlerRef.HasHandlers())
{
MessageLatencyTestButton button(this);
HandlerRef.Call(button);
}
}
} // namespace OVR

View File

@ -0,0 +1,144 @@
/************************************************************************************
Filename : OVR_LatencyTestImpl.h
Content : Latency Tester specific implementation.
Created : March 7, 2013
Authors : Lee Cooper
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_LatencyTestImpl_h
#define OVR_LatencyTestImpl_h
#include "OVR_HIDDeviceImpl.h"
namespace OVR {
struct LatencyTestSamplesMessage;
struct LatencyTestButtonMessage;
struct LatencyTestStartedMessage;
struct LatencyTestColorDetectedMessage;
//-------------------------------------------------------------------------------------
// LatencyTestDeviceFactory enumerates Oculus Latency Tester devices.
class LatencyTestDeviceFactory : public DeviceFactory
{
public:
static LatencyTestDeviceFactory &GetInstance();
// Enumerates devices, creating and destroying relevant objects in manager.
virtual void EnumerateDevices(EnumerateVisitor& visitor);
virtual bool MatchVendorProduct(UInt16 vendorId, UInt16 productId) const;
virtual bool DetectHIDDevice(DeviceManager* pdevMgr, const HIDDeviceDesc& desc);
protected:
DeviceManager* getManager() const { return (DeviceManager*) pManager; }
};
// Describes a single a Oculus Latency Tester device and supports creating its instance.
class LatencyTestDeviceCreateDesc : public HIDDeviceCreateDesc
{
public:
LatencyTestDeviceCreateDesc(DeviceFactory* factory, const HIDDeviceDesc& hidDesc)
: HIDDeviceCreateDesc(factory, Device_LatencyTester, hidDesc) { }
virtual DeviceCreateDesc* Clone() const
{
return new LatencyTestDeviceCreateDesc(*this);
}
virtual DeviceBase* NewDeviceInstance();
virtual MatchResult MatchDevice(const DeviceCreateDesc& other,
DeviceCreateDesc**) const
{
if ((other.Type == Device_LatencyTester) && (pFactory == other.pFactory))
{
const LatencyTestDeviceCreateDesc& s2 = (const LatencyTestDeviceCreateDesc&) other;
if (MatchHIDDevice(s2.HIDDesc))
return Match_Found;
}
return Match_None;
}
virtual bool MatchHIDDevice(const HIDDeviceDesc& hidDesc) const
{
// should paths comparison be case insensitive?
return ((HIDDesc.Path.CompareNoCase(hidDesc.Path) == 0) &&
(HIDDesc.SerialNumber == hidDesc.SerialNumber));
}
virtual bool GetDeviceInfo(DeviceInfo* info) const;
};
//-------------------------------------------------------------------------------------
// ***** OVR::LatencyTestDeviceImpl
// Oculus Latency Tester interface.
class LatencyTestDeviceImpl : public HIDDeviceImpl<OVR::LatencyTestDevice>
{
public:
LatencyTestDeviceImpl(LatencyTestDeviceCreateDesc* createDesc);
~LatencyTestDeviceImpl();
// DeviceCommon interface.
virtual bool Initialize(DeviceBase* parent);
virtual void Shutdown();
// DeviceManagerThread::Notifier interface.
virtual void OnInputReport(UByte* pData, UInt32 length);
// LatencyTesterDevice interface
virtual bool SetConfiguration(const OVR::LatencyTestConfiguration& configuration, bool waitFlag = false);
virtual bool GetConfiguration(OVR::LatencyTestConfiguration* configuration);
virtual bool SetCalibrate(const Color& calibrationColor, bool waitFlag = false);
virtual bool SetStartTest(const Color& targetColor, bool waitFlag = false);
virtual bool SetDisplay(const LatencyTestDisplay& display, bool waitFlag = false);
protected:
bool openDevice(const char** errorFormatString);
void closeDevice();
void closeDeviceOnIOError();
bool initializeRead();
bool processReadResult();
bool setConfiguration(const OVR::LatencyTestConfiguration& configuration);
bool getConfiguration(OVR::LatencyTestConfiguration* configuration);
bool setCalibrate(const Color& calibrationColor);
bool setStartTest(const Color& targetColor);
bool setDisplay(const OVR::LatencyTestDisplay& display);
// Called for decoded messages
void onLatencyTestSamplesMessage(LatencyTestSamplesMessage* message);
void onLatencyTestButtonMessage(LatencyTestButtonMessage* message);
void onLatencyTestStartedMessage(LatencyTestStartedMessage* message);
void onLatencyTestColorDetectedMessage(LatencyTestColorDetectedMessage* message);
};
} // namespace OVR
#endif // OVR_LatencyTestImpl_h

View File

@ -0,0 +1,331 @@
/************************************************************************************
Filename : OVR_Linux_DeviceManager.h
Content : Linux implementation of DeviceManager.
Created :
Authors :
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_DeviceManager.h"
// Sensor & HMD Factories
#include "OVR_LatencyTestImpl.h"
#include "OVR_SensorImpl.h"
#include "OVR_Linux_HIDDevice.h"
#include "OVR_Linux_HMDDevice.h"
#include "Kernel/OVR_Timer.h"
#include "Kernel/OVR_Std.h"
#include "Kernel/OVR_Log.h"
namespace OVR { namespace Linux {
//-------------------------------------------------------------------------------------
// **** Linux::DeviceManager
DeviceManager::DeviceManager()
{
}
DeviceManager::~DeviceManager()
{
}
bool DeviceManager::Initialize(DeviceBase*)
{
if (!DeviceManagerImpl::Initialize(0))
return false;
pThread = *new DeviceManagerThread();
if (!pThread || !pThread->Start())
return false;
// Wait for the thread to be fully up and running.
pThread->StartupEvent.Wait();
// Do this now that we know the thread's run loop.
HidDeviceManager = *HIDDeviceManager::CreateInternal(this);
pCreateDesc->pDevice = this;
LogText("OVR::DeviceManager - initialized.\n");
return true;
}
void DeviceManager::Shutdown()
{
LogText("OVR::DeviceManager - shutting down.\n");
// Set Manager shutdown marker variable; this prevents
// any existing DeviceHandle objects from accessing device.
pCreateDesc->pLock->pManager = 0;
// Push for thread shutdown *WITH NO WAIT*.
// This will have the following effect:
// - Exit command will get enqueued, which will be executed later on the thread itself.
// - Beyond this point, this DeviceManager object may be deleted by our caller.
// - Other commands, such as CreateDevice, may execute before ExitCommand, but they will
// fail gracefully due to pLock->pManager == 0. Future commands can't be enqued
// after pManager is null.
// - Once ExitCommand executes, ThreadCommand::Run loop will exit and release the last
// reference to the thread object.
pThread->PushExitCommand(false);
pThread.Clear();
DeviceManagerImpl::Shutdown();
}
ThreadCommandQueue* DeviceManager::GetThreadQueue()
{
return pThread;
}
ThreadId DeviceManager::GetThreadId() const
{
return pThread->GetThreadId();
}
bool DeviceManager::GetDeviceInfo(DeviceInfo* info) const
{
if ((info->InfoClassType != Device_Manager) &&
(info->InfoClassType != Device_None))
return false;
info->Type = Device_Manager;
info->Version = 0;
info->ProductName = "DeviceManager";
info->Manufacturer = "Oculus VR, Inc.";
return true;
}
DeviceEnumerator<> DeviceManager::EnumerateDevicesEx(const DeviceEnumerationArgs& args)
{
// TBD: Can this be avoided in the future, once proper device notification is in place?
pThread->PushCall((DeviceManagerImpl*)this,
&DeviceManager::EnumerateAllFactoryDevices, true);
return DeviceManagerImpl::EnumerateDevicesEx(args);
}
//-------------------------------------------------------------------------------------
// ***** DeviceManager Thread
DeviceManagerThread::DeviceManagerThread()
: Thread(ThreadStackSize)
{
int result = pipe(CommandFd);
OVR_ASSERT(!result);
OVR_UNUSED(result);
AddSelectFd(NULL, CommandFd[0]);
}
DeviceManagerThread::~DeviceManagerThread()
{
if (CommandFd[0])
{
RemoveSelectFd(NULL, CommandFd[0]);
close(CommandFd[0]);
close(CommandFd[1]);
}
}
bool DeviceManagerThread::AddSelectFd(Notifier* notify, int fd)
{
struct pollfd pfd;
pfd.fd = fd;
pfd.events = POLLIN|POLLHUP|POLLERR;
pfd.revents = 0;
FdNotifiers.PushBack(notify);
PollFds.PushBack(pfd);
OVR_ASSERT(FdNotifiers.GetSize() == PollFds.GetSize());
return true;
}
bool DeviceManagerThread::RemoveSelectFd(Notifier* notify, int fd)
{
// [0] is reserved for thread commands with notify of null, but we still
// can use this function to remove it.
for (UPInt i = 0; i < FdNotifiers.GetSize(); i++)
{
if ((FdNotifiers[i] == notify) && (PollFds[i].fd == fd))
{
FdNotifiers.RemoveAt(i);
PollFds.RemoveAt(i);
return true;
}
}
return false;
}
int DeviceManagerThread::Run()
{
ThreadCommand::PopBuffer command;
SetThreadName("OVR::DeviceManagerThread");
LogText("OVR::DeviceManagerThread - running (ThreadId=%p).\n", GetThreadId());
// Signal to the parent thread that initialization has finished.
StartupEvent.SetEvent();
while(!IsExiting())
{
// PopCommand will reset event on empty queue.
if (PopCommand(&command))
{
command.Execute();
}
else
{
bool commands = 0;
do
{
int waitMs = -1;
// If devices have time-dependent logic registered, get the longest wait
// allowed based on current ticks.
if (!TicksNotifiers.IsEmpty())
{
double timeSeconds = Timer::GetSeconds();
unsigned waitAllowed;
for (UPInt j = 0; j < TicksNotifiers.GetSize(); j++)
{
waitAllowed = (unsigned)(TicksNotifiers[j]->OnTicks(timeSeconds) * Timer::MsPerSecond);
if (waitAllowed < (unsigned)waitMs)
waitMs = waitAllowed;
}
}
// wait until there is data available on one of the devices or the timeout expires
int n = poll(&PollFds[0], PollFds.GetSize(), waitMs);
if (n > 0)
{
// Iterate backwards through the list so the ordering will not be
// affected if the called object gets removed during the callback
// Also, the HID data streams are located toward the back of the list
// and servicing them first will allow a disconnect to be handled
// and cleaned directly at the device first instead of the general HID monitor
for (int i=PollFds.GetSize()-1; i>=0; i--)
{
if (PollFds[i].revents & POLLERR)
{
OVR_DEBUG_LOG(("poll: error on [%d]: %d", i, PollFds[i].fd));
}
else if (PollFds[i].revents & POLLIN)
{
if (FdNotifiers[i])
FdNotifiers[i]->OnEvent(i, PollFds[i].fd);
else if (i == 0) // command
{
char dummy[128];
read(PollFds[i].fd, dummy, 128);
commands = 1;
}
}
if (PollFds[i].revents & POLLHUP)
PollFds[i].events = 0;
if (PollFds[i].revents != 0)
{
n--;
if (n == 0)
break;
}
}
}
} while (PollFds.GetSize() > 0 && !commands);
}
}
LogText("OVR::DeviceManagerThread - exiting (ThreadId=%p).\n", GetThreadId());
return 0;
}
bool DeviceManagerThread::AddTicksNotifier(Notifier* notify)
{
TicksNotifiers.PushBack(notify);
return true;
}
bool DeviceManagerThread::RemoveTicksNotifier(Notifier* notify)
{
for (UPInt i = 0; i < TicksNotifiers.GetSize(); i++)
{
if (TicksNotifiers[i] == notify)
{
TicksNotifiers.RemoveAt(i);
return true;
}
}
return false;
}
} // namespace Linux
//-------------------------------------------------------------------------------------
// ***** Creation
// Creates a new DeviceManager and initializes OVR.
DeviceManager* DeviceManager::Create()
{
if (!System::IsInitialized())
{
// Use custom message, since Log is not yet installed.
OVR_DEBUG_STATEMENT(Log::GetDefaultLog()->
LogMessage(Log_Debug, "DeviceManager::Create failed - OVR::System not initialized"); );
return 0;
}
Ptr<Linux::DeviceManager> manager = *new Linux::DeviceManager;
if (manager)
{
if (manager->Initialize(0))
{
manager->AddFactory(&LatencyTestDeviceFactory::GetInstance());
manager->AddFactory(&SensorDeviceFactory::GetInstance());
manager->AddFactory(&Linux::HMDDeviceFactory::GetInstance());
manager->AddRef();
}
else
{
manager.Clear();
}
}
return manager.GetPtr();
}
} // namespace OVR

View File

@ -0,0 +1,122 @@
/************************************************************************************
Filename : OVR_Linux_DeviceManager.h
Content : Linux-specific DeviceManager header.
Created :
Authors :
Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.1 (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
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_DeviceManager_h
#define OVR_Linux_DeviceManager_h
#include "OVR_DeviceImpl.h"
#include <unistd.h>
#include <sys/poll.h>
namespace OVR { namespace Linux {
class DeviceManagerThread;
//-------------------------------------------------------------------------------------
// ***** Linux DeviceManager
class DeviceManager : public DeviceManagerImpl
{
public:
DeviceManager();
~DeviceManager();
// Initialize/Shutdowncreate and shutdown manger thread.
virtual bool Initialize(DeviceBase* parent);
virtual void Shutdown();
virtual ThreadCommandQueue* GetThreadQueue();
virtual ThreadId GetThreadId() const;
virtual DeviceEnumerator<> EnumerateDevicesEx(const DeviceEnumerationArgs& args);
virtual bool GetDeviceInfo(DeviceInfo* info) const;
Ptr<DeviceManagerThread> pThread;
};
//-------------------------------------------------------------------------------------
// ***** Device Manager Background Thread
class DeviceManagerThread : public Thread, public ThreadCommandQueue
{
friend class DeviceManager;
enum { ThreadStackSize = 64 * 1024 };
public:
DeviceManagerThread();
~DeviceManagerThread();
virtual int Run();
// ThreadCommandQueue notifications for CommandEvent handling.
virtual void OnPushNonEmpty_Locked() { write(CommandFd[1], this, 1); }
virtual void OnPopEmpty_Locked() { }
class Notifier
{
public:
// Called when I/O is received
virtual void OnEvent(int i, int fd) = 0;
// Called when timing ticks are updated.
// Returns the largest number of seconds this function can
// wait till next call.
virtual double OnTicks(double tickSeconds)
{
OVR_UNUSED1(tickSeconds);
return 1000.0;
}
};
// Add I/O notifier
bool AddSelectFd(Notifier* notify, int fd);
bool RemoveSelectFd(Notifier* notify, int fd);
// Add notifier that will be called at regular intervals.
bool AddTicksNotifier(Notifier* notify);
bool RemoveTicksNotifier(Notifier* notify);
private:
bool threadInitialized() { return CommandFd[0] != 0; }
// pipe used to signal commands
int CommandFd[2];
Array<struct pollfd> PollFds;
Array<Notifier*> FdNotifiers;
Event StartupEvent;
// Ticks notifiers - used for time-dependent events such as keep-alive.
Array<Notifier*> TicksNotifiers;
};
}} // namespace Linux::OVR
#endif // OVR_Linux_DeviceManager_h

Some files were not shown because too many files have changed in this diff Show More