mirror of
https://github.com/mii443/rust-openvr.git
synced 2025-12-05 20:28:19 +00:00
added linux makefile
This commit is contained in:
11
configure
vendored
11
configure
vendored
@@ -329,17 +329,16 @@ def set_source_dir(modules, source_dir):
|
|||||||
_base = os.path.abspath(os.path.dirname(__file__))
|
_base = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
|
||||||
modules = [Bin("oculus-info", ["oculus-vr"]),
|
modules = [Bin("oculus-info", ["oculus-vr"]),
|
||||||
|
Lib("oculus-vr", ["libovr.a", "cgmath"]),
|
||||||
Lib("cgmath")]
|
Lib("cgmath")]
|
||||||
|
|
||||||
if platform.system() == "Linux":
|
if platform.system() == "Linux":
|
||||||
modules += [Lib("oculus-vr", ["libOVR_C.so", "cgmath"]),
|
modules += [LibMakefile("libovr.a",
|
||||||
LibCMake("libOVR_C.so",
|
"modules/oculus_sdk_linux/",
|
||||||
"modules/OculusSDK/",
|
["modules/oculus_sdk_linux/LibOVR/Lib/Linux/Release/x86_64/libovr.a"])]
|
||||||
"modules/OculusSDK/output/libOVR_C.so")]
|
|
||||||
|
|
||||||
elif platform.system() == "Darwin":
|
elif platform.system() == "Darwin":
|
||||||
modules += [Lib("oculus-vr", ["libovr.a", "cgmath"]),
|
modules += [LibXcodebuild("libovr.a",
|
||||||
LibXcodebuild("libovr.a",
|
|
||||||
"modules/oculus_sdk_mac/LibOVR/Projects/Mac/Xcode/LibOVR.xcodeproj",
|
"modules/oculus_sdk_mac/LibOVR/Projects/Mac/Xcode/LibOVR.xcodeproj",
|
||||||
["modules/oculus_sdk_mac/LibOVR/Lib/MacOS/Release/libovr.a"])]
|
["modules/oculus_sdk_mac/LibOVR/Lib/MacOS/Release/libovr.a"])]
|
||||||
|
|
||||||
|
|||||||
446
modules/oculus_sdk_linux/3rdParty/EDID/edid.cpp
vendored
Normal file
446
modules/oculus_sdk_linux/3rdParty/EDID/edid.cpp
vendored
Normal 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;
|
||||||
|
}
|
||||||
174
modules/oculus_sdk_linux/3rdParty/EDID/edid.h
vendored
Normal file
174
modules/oculus_sdk_linux/3rdParty/EDID/edid.h
vendored
Normal 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);
|
||||||
2101
modules/oculus_sdk_linux/3rdParty/TinyXml/tinyxml2.cpp
vendored
Normal file
2101
modules/oculus_sdk_linux/3rdParty/TinyXml/tinyxml2.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1911
modules/oculus_sdk_linux/3rdParty/TinyXml/tinyxml2.h
vendored
Normal file
1911
modules/oculus_sdk_linux/3rdParty/TinyXml/tinyxml2.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
19
modules/oculus_sdk_linux/Firmware/readme.txt
Normal file
19
modules/oculus_sdk_linux/Firmware/readme.txt
Normal 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.
|
||||||
|
|
||||||
264
modules/oculus_sdk_linux/LICENSE.txt
Normal file
264
modules/oculus_sdk_linux/LICENSE.txt
Normal 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 arbitrator’s judgment
|
||||||
|
or decision or any dispute with respect to the arbitration process or procedure
|
||||||
|
or Oculus VR’s exercise of its equitable rights or remedies.
|
||||||
2
modules/oculus_sdk_linux/LibOVR/90-oculus.rules
Normal file
2
modules/oculus_sdk_linux/LibOVR/90-oculus.rules
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Oculus HID Sensor naming and permissioning
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2833", MODE="0666"
|
||||||
47
modules/oculus_sdk_linux/LibOVR/Include/OVR.h
Normal file
47
modules/oculus_sdk_linux/LibOVR/Include/OVR.h
Normal 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
|
||||||
|
|
||||||
33
modules/oculus_sdk_linux/LibOVR/Include/OVRVersion.h
Normal file
33
modules/oculus_sdk_linux/LibOVR/Include/OVRVersion.h
Normal 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
|
||||||
BIN
modules/oculus_sdk_linux/LibOVR/Lib/Linux/Debug/i386/libovr.a
Normal file
BIN
modules/oculus_sdk_linux/LibOVR/Lib/Linux/Debug/i386/libovr.a
Normal file
Binary file not shown.
@@ -0,0 +1,2 @@
|
|||||||
|
This document exits to ensure that the required directory structure gets created correctly.
|
||||||
|
|
||||||
BIN
modules/oculus_sdk_linux/LibOVR/Lib/Linux/Debug/x86_64/libovr.a
Normal file
BIN
modules/oculus_sdk_linux/LibOVR/Lib/Linux/Debug/x86_64/libovr.a
Normal file
Binary file not shown.
@@ -0,0 +1,2 @@
|
|||||||
|
This document exits to ensure that the required directory structure gets created correctly.
|
||||||
|
|
||||||
BIN
modules/oculus_sdk_linux/LibOVR/Lib/Linux/Release/i386/libovr.a
Normal file
BIN
modules/oculus_sdk_linux/LibOVR/Lib/Linux/Release/i386/libovr.a
Normal file
Binary file not shown.
@@ -0,0 +1,2 @@
|
|||||||
|
This document exits to ensure that the required directory structure gets created correctly.
|
||||||
|
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
This document exits to ensure that the required directory structure gets created correctly.
|
||||||
|
|
||||||
278
modules/oculus_sdk_linux/LibOVR/Makefile
Normal file
278
modules/oculus_sdk_linux/LibOVR/Makefile
Normal 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)
|
||||||
|
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
This document exits to ensure that the required directory structure gets created correctly.
|
||||||
|
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
This document exits to ensure that the required directory structure gets created correctly.
|
||||||
|
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
This document exits to ensure that the required directory structure gets created correctly.
|
||||||
|
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
This document exits to ensure that the required directory structure gets created correctly.
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|
||||||
264
modules/oculus_sdk_linux/LibOVR/Src/CAPI/CAPI_FrameTimeManager.h
Normal file
264
modules/oculus_sdk_linux/LibOVR/Src/CAPI/CAPI_FrameTimeManager.h
Normal 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
|
||||||
|
|
||||||
|
|
||||||
142
modules/oculus_sdk_linux/LibOVR/Src/CAPI/CAPI_GlobalState.cpp
Normal file
142
modules/oculus_sdk_linux/LibOVR/Src/CAPI/CAPI_GlobalState.cpp
Normal 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
|
||||||
84
modules/oculus_sdk_linux/LibOVR/Src/CAPI/CAPI_GlobalState.h
Normal file
84
modules/oculus_sdk_linux/LibOVR/Src/CAPI/CAPI_GlobalState.h
Normal 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
|
||||||
|
|
||||||
|
|
||||||
143
modules/oculus_sdk_linux/LibOVR/Src/CAPI/CAPI_HMDRenderState.cpp
Normal file
143
modules/oculus_sdk_linux/LibOVR/Src/CAPI/CAPI_HMDRenderState.cpp
Normal 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
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|
||||||
804
modules/oculus_sdk_linux/LibOVR/Src/CAPI/CAPI_HMDState.cpp
Normal file
804
modules/oculus_sdk_linux/LibOVR/Src/CAPI/CAPI_HMDState.cpp
Normal 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
|
||||||
|
|
||||||
347
modules/oculus_sdk_linux/LibOVR/Src/CAPI/CAPI_HMDState.h
Normal file
347
modules/oculus_sdk_linux/LibOVR/Src/CAPI/CAPI_HMDState.h
Normal 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
|
||||||
|
|
||||||
|
|
||||||
@@ -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, ¤tSwapInterval);
|
||||||
|
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, ¤tSwapInterval);
|
||||||
|
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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
530
modules/oculus_sdk_linux/LibOVR/Src/CAPI/GL/CAPI_GL_Util.cpp
Normal file
530
modules/oculus_sdk_linux/LibOVR/Src/CAPI/GL/CAPI_GL_Util.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}}}
|
||||||
537
modules/oculus_sdk_linux/LibOVR/Src/CAPI/GL/CAPI_GL_Util.h
Normal file
537
modules/oculus_sdk_linux/LibOVR/Src/CAPI/GL/CAPI_GL_Util.h
Normal 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
|
||||||
57
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Alg.cpp
Normal file
57
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Alg.cpp
Normal 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
|
||||||
1060
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Alg.h
Normal file
1060
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Alg.h
Normal file
File diff suppressed because it is too large
Load Diff
95
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Allocator.cpp
Normal file
95
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Allocator.cpp
Normal 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
|
||||||
347
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Allocator.h
Normal file
347
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Allocator.h
Normal 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
|
||||||
833
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Array.h
Normal file
833
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Array.h
Normal 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
|
||||||
162
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Atomic.cpp
Normal file
162
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Atomic.cpp
Normal 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
|
||||||
890
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Atomic.h
Normal file
890
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Atomic.h
Normal 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
|
||||||
66
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Color.h
Normal file
66
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Color.h
Normal 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
|
||||||
@@ -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
|
||||||
296
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Deque.h
Normal file
296
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Deque.h
Normal 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
|
||||||
582
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_File.cpp
Normal file
582
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_File.cpp
Normal 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
|
||||||
|
|
||||||
529
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_File.h
Normal file
529
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_File.h
Normal 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
|
||||||
595
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_FileFILE.cpp
Normal file
595
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_FileFILE.cpp
Normal 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
|
||||||
1302
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Hash.h
Normal file
1302
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Hash.h
Normal file
File diff suppressed because it is too large
Load Diff
251
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_KeyCodes.h
Normal file
251
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_KeyCodes.h
Normal 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
|
||||||
336
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_List.h
Normal file
336
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_List.h
Normal 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
|
||||||
231
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Lockless.cpp
Normal file
231
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Lockless.cpp
Normal 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
|
||||||
107
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Lockless.h
Normal file
107
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Lockless.h
Normal 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
|
||||||
|
|
||||||
184
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Log.cpp
Normal file
184
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Log.cpp
Normal 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
|
||||||
204
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Log.h
Normal file
204
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Log.h
Normal 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
|
||||||
91
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Math.cpp
Normal file
91
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Math.cpp
Normal 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
|
||||||
2526
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Math.h
Normal file
2526
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Math.h
Normal file
File diff suppressed because it is too large
Load Diff
111
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_RefCount.cpp
Normal file
111
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_RefCount.cpp
Normal 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
|
||||||
564
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_RefCount.h
Normal file
564
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_RefCount.h
Normal 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
|
||||||
1036
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Std.cpp
Normal file
1036
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Std.cpp
Normal file
File diff suppressed because it is too large
Load Diff
514
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Std.h
Normal file
514
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Std.h
Normal 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
|
||||||
768
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_String.cpp
Normal file
768
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_String.cpp
Normal 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
|
||||||
657
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_String.h
Normal file
657
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_String.h
Normal 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
|
||||||
100
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_StringHash.h
Normal file
100
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_StringHash.h
Normal 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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
138
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_SysFile.cpp
Normal file
138
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_SysFile.cpp
Normal 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
|
||||||
104
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_SysFile.h
Normal file
104
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_SysFile.h
Normal 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
|
||||||
81
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_System.cpp
Normal file
81
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_System.cpp
Normal 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
|
||||||
|
|
||||||
78
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_System.h
Normal file
78
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_System.h
Normal 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
|
||||||
407
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Threads.h
Normal file
407
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Threads.h
Normal 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
|
||||||
@@ -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
|
||||||
287
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Timer.cpp
Normal file
287
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Timer.cpp
Normal 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
|
||||||
|
|
||||||
88
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Timer.h
Normal file
88
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Timer.h
Normal 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
|
||||||
474
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Types.h
Normal file
474
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_Types.h
Normal 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
|
||||||
556
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_UTF8Util.cpp
Normal file
556
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_UTF8Util.cpp
Normal 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
|
||||||
|
|
||||||
99
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_UTF8Util.h
Normal file
99
modules/oculus_sdk_linux/LibOVR/Src/Kernel/OVR_UTF8Util.h
Normal 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
|
||||||
925
modules/oculus_sdk_linux/LibOVR/Src/OVR_CAPI.cpp
Normal file
925
modules/oculus_sdk_linux/LibOVR/Src/OVR_CAPI.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
790
modules/oculus_sdk_linux/LibOVR/Src/OVR_CAPI.h
Normal file
790
modules/oculus_sdk_linux/LibOVR/Src/OVR_CAPI.h
Normal 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
|
||||||
73
modules/oculus_sdk_linux/LibOVR/Src/OVR_CAPI_GL.h
Normal file
73
modules/oculus_sdk_linux/LibOVR/Src/OVR_CAPI_GL.h
Normal 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
|
||||||
384
modules/oculus_sdk_linux/LibOVR/Src/OVR_Common_HMDDevice.cpp
Normal file
384
modules/oculus_sdk_linux/LibOVR/Src/OVR_Common_HMDDevice.cpp
Normal 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;
|
||||||
|
}
|
||||||
1135
modules/oculus_sdk_linux/LibOVR/Src/OVR_Device.h
Normal file
1135
modules/oculus_sdk_linux/LibOVR/Src/OVR_Device.h
Normal file
File diff suppressed because it is too large
Load Diff
142
modules/oculus_sdk_linux/LibOVR/Src/OVR_DeviceConstants.h
Normal file
142
modules/oculus_sdk_linux/LibOVR/Src/OVR_DeviceConstants.h
Normal 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
|
||||||
185
modules/oculus_sdk_linux/LibOVR/Src/OVR_DeviceHandle.cpp
Normal file
185
modules/oculus_sdk_linux/LibOVR/Src/OVR_DeviceHandle.cpp
Normal 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
|
||||||
|
|
||||||
108
modules/oculus_sdk_linux/LibOVR/Src/OVR_DeviceHandle.h
Normal file
108
modules/oculus_sdk_linux/LibOVR/Src/OVR_DeviceHandle.h
Normal 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
|
||||||
794
modules/oculus_sdk_linux/LibOVR/Src/OVR_DeviceImpl.cpp
Normal file
794
modules/oculus_sdk_linux/LibOVR/Src/OVR_DeviceImpl.cpp
Normal 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
|
||||||
|
|
||||||
428
modules/oculus_sdk_linux/LibOVR/Src/OVR_DeviceImpl.h
Normal file
428
modules/oculus_sdk_linux/LibOVR/Src/OVR_DeviceImpl.h
Normal 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
|
||||||
273
modules/oculus_sdk_linux/LibOVR/Src/OVR_DeviceMessages.h
Normal file
273
modules/oculus_sdk_linux/LibOVR/Src/OVR_DeviceMessages.h
Normal 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
|
||||||
154
modules/oculus_sdk_linux/LibOVR/Src/OVR_HIDDevice.h
Normal file
154
modules/oculus_sdk_linux/LibOVR/Src/OVR_HIDDevice.h
Normal 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
|
||||||
51
modules/oculus_sdk_linux/LibOVR/Src/OVR_HIDDeviceBase.h
Normal file
51
modules/oculus_sdk_linux/LibOVR/Src/OVR_HIDDeviceBase.h
Normal 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
|
||||||
201
modules/oculus_sdk_linux/LibOVR/Src/OVR_HIDDeviceImpl.h
Normal file
201
modules/oculus_sdk_linux/LibOVR/Src/OVR_HIDDeviceImpl.h
Normal 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
|
||||||
1185
modules/oculus_sdk_linux/LibOVR/Src/OVR_JSON.cpp
Normal file
1185
modules/oculus_sdk_linux/LibOVR/Src/OVR_JSON.cpp
Normal file
File diff suppressed because it is too large
Load Diff
164
modules/oculus_sdk_linux/LibOVR/Src/OVR_JSON.h
Normal file
164
modules/oculus_sdk_linux/LibOVR/Src/OVR_JSON.h
Normal 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
|
||||||
773
modules/oculus_sdk_linux/LibOVR/Src/OVR_LatencyTestImpl.cpp
Normal file
773
modules/oculus_sdk_linux/LibOVR/Src/OVR_LatencyTestImpl.cpp
Normal 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
|
||||||
144
modules/oculus_sdk_linux/LibOVR/Src/OVR_LatencyTestImpl.h
Normal file
144
modules/oculus_sdk_linux/LibOVR/Src/OVR_LatencyTestImpl.h
Normal 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
|
||||||
331
modules/oculus_sdk_linux/LibOVR/Src/OVR_Linux_DeviceManager.cpp
Normal file
331
modules/oculus_sdk_linux/LibOVR/Src/OVR_Linux_DeviceManager.cpp
Normal 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
|
||||||
|
|
||||||
122
modules/oculus_sdk_linux/LibOVR/Src/OVR_Linux_DeviceManager.h
Normal file
122
modules/oculus_sdk_linux/LibOVR/Src/OVR_Linux_DeviceManager.h
Normal 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
Reference in New Issue
Block a user