Add files

This commit is contained in:
2025-01-29 10:55:49 +01:00
commit 98fba39c36
1017 changed files with 403715 additions and 0 deletions

View File

@ -0,0 +1,245 @@
Oculus Software Development Kit License Agreement
Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
The text of this may be found at: https://developer.oculus.com/licenses/sdk-3.5/
In order to obtain and use the Oculus Software Development Kit for mobile or for PC, You must first agree to
the terms of this License. If you agree to the terms of this License, you may use the Oculus Software
Development Kit. If you do not agree to the terms of this License, then you may not use the Oculus Software
Development Kit.
OCULUS SDK LICENSE
1. Subject to the terms and conditions of this License Agreement (the "License"), Facebook Technologies, LLC
formerly known as Oculus VR, LLC ("Oculus") hereby grants to you a worldwide, non-exclusive, no-charge,
royalty-free, sublicenseable copyright license to use, reproduce and redistribute (subject to restrictions
below) the software contained in this Oculus Software Development Kit for PC and/or mobile ("Oculus SDK"),
including, but not limited to, the samples, headers, LibOVR and VRLib headers, LibOVR and VRLib source and,
subject to your compliance with Section 3, the headers, libraries and APIs to enable the Platform Services.
This License is subject to the following terms and conditions:
1.1 This license grants you the non-exclusive license and right to use (i) the Oculus SDK to make engines,
tools, applications, content, games and demos (collectively and generally referred to as "Developer Content")
for use on the Oculus approved hardware and software products ("Oculus Approved Products") and which may
incorporate the Oculus SDK in whole or in part in binary or object code; and (ii) the headers, libraries, APIs
and other tools made available by Oculus to enable the use of Platform Services with your Developer Content.
1.2 For the sake of clarification, when you use the Oculus SDK 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 or any third parties; provided, however, Oculus retains all rights to
the Oculus SDK and the headers, libraries and APIs to the Platform Services and other tools made available by
Oculus, including those that may be incorporated into your Developer Content.
1.3 You agree that as a condition of this License you will design and distribute your Developer Content to
ensure that your Developer Content and any software required to use your Developer Content does not, and you
will not, alter or interfere with the normal operation, behavior or functionality of the Oculus hardware or
software or Oculus Approved Products, including:(i) the behavior of the "Oculus button" and "XBox button"
implemented by the Oculus system software; (ii) any on-screen messages or information; (iii) the behavior of
the proximity sensor in the Oculus hardware implemented by the Oculus system software; (iv) Oculus hardware or
software security features; (v) end user's settings; or (vi) the Oculus Flash Screen Warnings. You also agree
not to commit any act intended to interfere with the normal operation of the Oculus hardware or software or
Oculus Approved Products, or provide software to Oculus users or developers that would induce breach of any
Oculus agreements or that contains malware, viruses, hacks, bots, Trojan horses, or other malicious code.
1.4 You may not use the Oculus SDK for any purpose not expressly permitted by this License. You may not
(except as and only to the extent any following restriction is prohibited by applicable law): (a) decompile;
(b) reverse engineer; (c) disassemble; (d) attempt to derive the source code of the Oculus SDK or any part of
the Oculus SDK, or any other software or firmware provided to you by Oculus
REDISTRIBUTION
2. Subject to the terms and conditions of this License, your license to redistribute and sublicense the Oculus
SDK is also expressly made subject to the following conditions:
2.1 You may sublicense and redistribute the source, binary, or object code of the Oculus SDK in whole 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 the Oculus SDK in its entirety. The Oculus SDK
(including, but not limited to LibOVR and VRLib), and any Developer Content that includes any portion of the
Oculus SDK, may only be used with Oculus Approved Products and may not be used, licensed, or sublicensed to
interface with software or hardware or other commercial headsets, mobile tablets or phones that are not
authorized and approved by Oculus;
2.2 You must include with all such redistributed or sublicensed Oculus SDK code the following copyright
notice: "Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved."
2.3 You must give any other recipients of the Oculus SDK a copy of this License as such recipients, licensees
or sublicensees may only use the Oculus SDK subject to the terms of this License and such recipient's,
licensee's or sublicensee's agreement to and acceptance of this License with Oculus; and
2.4 The Oculus SDK includes a "LICENSE" text file (the "License Notice"), and any Oculus SDK distribution that
you distribute must include a copy of this License with the License Notice.
OCULUS PLATFORM SERVICES
3. Oculus makes the headers, libraries and APIs, software, and other tools made available by Oculus to enable
Platform Services in connection with your Developer Content. You agree not to use any API, code or other
tools, instruction or service provided by Oculus to enable or use a Platform Service other than in compliance
with these terms. For more information go to https://developer.oculus.com.
<EFBFBD> "Oculus Platform Framework" means the suite of Oculus platform services, including but not limited to the
Oculus file distribution and update system (enabling distribution and updates of Developer Content by Oculus,
including through generated activation Keys), entitlement system, and account authentication, which list may
be changed from time to time in Oculus' sole discretion.
<EFBFBD> "Application Services" means services provided by Oculus associated with the Platform, including but not
limited to in-app purchasing, multiplayer matchmaking, friends, leader boards, achievements, rooms, voice over
IP and cloud saves, which list may be changed from time to time in Oculus' sole discretion.
<EFBFBD> "Platform" means the Oculus virtual reality platform, including but not limited to the user experience, user
interface, store, and social features, usable on Oculus approved hardware or any third-party device or
operating system, including but not limited to iOS, Android, Windows, OS X, Linux, and Windows Mobile.
<EFBFBD> "Platform Services" means the Oculus Platform Framework and the Application Services.
3.1 Oculus Platform Services. Oculus makes certain Platform Services available to you to include and enable in
your Developer Content. Developer Content that enables or includes any Platform Service must implement the
Oculus Platform Framework with that Developer Content. Once your Developer Content has been authorized for use
of the Platform Services, you are not required to update your Developer Content to include new Platform
Services Oculus may make available as part of the Oculus Platform Framework.
3.2 Limited Authorization. You hereby grant Oculus the limited authorization reasonably necessary for Oculus's
exercise of its rights and performance of its obligations under this Section 3. You agree that Oculus may use
its contractors and affiliates for the purposes of exercising its rights and licenses set forth in this
Section 3.
3.3. Internal Use. You agree that Oculus may grant its employees and internal contractors the right to use,
perform and display the Developer Content you provide to Oculus for testing, evaluation and approval purposes,
which shall be on a royalty-free basis.
3.4 Key Provision and Redemption. If you request that Oculus generate activation keys for your Developer
Content on the Platform ("Keys") and Oculus agrees, you hereby grant Oculus (i) the right to generate Keys for
you and (ii) a license to make available, reproduce, distribute, perform, and display the Developer Content to
end users who have submitted a Key to Oculus. Oculus agrees to authenticate and make Developer Content
available to any end user supplying a valid Key (unless the Developer Content has been removed or withdrawn).
3.5 Platform Services Requirements. You will not make any use of any API, software, code or other item or
information supplied by Oculus in connection with the Platform Services other than to enhance the
functionality of your Developer Content. In particular, you must not (nor enable others to): (i) defame,
abuse, harass, stalk, or threaten others, or to promote or facilitate any prohibited or illegal activities;
(ii) enable any functionality in your Developer Content that would generate excessive traffic over the Oculus
network or servers that would negatively impact other users' experience, or otherwise interfere with or
restrict the operation of the Platform Services, or Oculus's servers or networks providing the Platform
Services; or (iii) remove, obscure, or alter any Oculus license terms, policies or terms of service or any
links to or notices thereto. You may not sublicense any software, firmware or other item or information
supplied by Oculus in connection with the Platform Service for use by a third party, unless expressly
authorized by Oculus to do so. You agree not to use (or encourage the use of) the Platform Services for
mission critical, life saving or ultra-hazardous activities. Oculus may suspend operation of or remove any
Developer Content that does not comply with the restrictions in this License.
You will not use the Oculus Avatar associated with the Oculus ID of any end user in your Developer Content
without the express permission of that end user unless, (i) that end user is actively engaged with your
Developer Content or (ii) that end user remains part of an active session of your Developer Content with whom
other end users are interacting, whether or not that end user is then online.
GENERAL PROVISIONS
4. Additional Materials
4.1 Oculus may include in this Oculus SDK additional content (e.g., samples) for demonstration, references or
other specific purposes. Such content will be clearly marked in the Oculus SDK and is subject to any included
terms and conditions.
4.2 Your use of third-party materials included in the Oculus SDK may be subject to other terms and conditions
typically found in separate third-party license agreements or "READ ME" files included with such third-party
materials. To the extent such other terms and conditions conflict with the terms and conditions of this
License, the former will control with respect to the applicable third-party materials.
5. THE OCULUS SDK AND ANY COMPONENT THEREOF, THE OCULUS HEADERS, LIBRARIES AND APIS, AND THE PLATFORM SERVICES
FROM OCULUS AND ITS CONTRIBUTORS ARE PROVIDED "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 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 OCULUS SDK, THE OCULUS HEADERS, LIBRARIES AND APIS OR THE PLATFORM
SERVICES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOME JURISDICTIONS DO NOT PERMIT THE EXCLUSION OR
LIMITATION OF IMPLIED WARRANTIES, SO YOU MAY HAVE ADDITIONAL RIGHTS.
6. This License does not grant permission to use the trade names, trademarks, service marks, or product names
of Oculus, except as required for reasonable and customary use in describing the origin of the Oculus SDK, and
reproducing the content of the License Notice file. Oculus reserves all rights not expressly granted to you
under this License. Neither the name of Facebook Technologies, LLC, Oculus VR, LLC, Oculus, nor the names of
Oculus<EFBFBD>s contributors, licensors, employees, or contractors, may be used to endorse or promote products
developed using the Oculus SDK without specific prior written permission of Oculus.
7. You are responsible for ensuring that your use of the Oculus SDK and your Developer Content, including
enabled Platform Services, complies with all applicable laws (including privacy laws) wherever your Developer
Content is made available. You acknowledge and agree that you are solely responsible for any health and safety
issues arising from your Developer Content. You will not collect end users' content or information, or
otherwise access any Oculus site, using automated means (such as harvesting bots, robots, spiders, or
scrapers) without Oculus' prior permission.
8. Your acceptance of the terms and conditions of this License in and of itself and for all Developer Content
created as of March 28, 2016, may be evidenced by any of the following: your usage of the Oculus SDK, or
acceptance of the license agreement. As this License is updated for future releases of the Oculus SDK, you
agree to abide by and meet all requirements of future updates of this License for those future Oculus SDK
releases, with acceptance evidenced by usage of the Oculus SDK or any element thereof and the future updates
of this License will apply for that future Developer Content that may be developed for or with that future
Oculus 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 Oculus SDK or License).
9. Oculus reserves the right to terminate this License and all your rights hereunder immediately in the event
you materially breach this License.
10. Furthermore, Oculus also reserves the right to cancel or terminate this License for any of the following
reasons:
a. Intellectual property infringement by you with Developer Content created by you that is used with or by
the Oculus SDK, or any of the Platform Services;
b. Developer Content (including enabling Platform Services) that violates applicable law;
c. Health and safety issues associated with your Developer Content;
d. Failure to comply with or use properly the Oculus Flash Screen Warnings;
e. Use of the Oculus SDK with a commercial product other than an Oculus Approved Product;
f. Failure to provide required notices as set forth above; and
g. Failure to observe the restrictions in Section 3.5.
11. You agree to fully indemnify Oculus from any and all losses, costs, damages and expenses (including
reasonable attorney's fees) arising out of your Developer Content or any matter set forth in Sections 6, 7 and
10(a) through (g).
12. Oculus may discontinue or change functionality of the Platform Services at any time, and your continued
use of the Platform Services or use of any modified or additional Platform Services is conditioned upon your
adherence to the terms of this License, as modified by Oculus from time to time.
13. 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.
14. You may not assign any rights or obligations under this License without the advance written consent of
Oculus, which may be withheld in its sole discretion. Oculus may assign its rights or obligations under this
License in its sole discretion.
15. 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.
16. 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.
17. You will comply, and will not cause Oculus to not comply (by for example, providing Developer Content to
Oculus under this Agreement for which required export clearances have not been obtained), with all applicable
export control laws of the United States and any other applicable governmental authority, including without
limitation, the U.S. Export Administration Regulations. You agree that this License and the Oculus SDK and
accompanying documentation are Oculus's confidential information (and is not publicly available), and you will
not use it, disclose it or make it available to others except in accordance with the terms of this License.
18. This License shall be governed by the laws of the State of California, without giving effect to conflict
of laws provisions or principles thereof. The parties agree that, except as provided below, all disputes
relating to this License shall be resolved by binding non-appearance-based arbitration before a single neutral
arbitrator in San Francisco, California. The arbitration will be conducted in the English language by a single
arbitrator who is an attorney-at-law with at least fifteen (15) years<72> experience in consumer and technology
transactions and who is also a member of the JAMS roster of arbitrators. If You and Oculus cannot agree on a
mutually acceptable arbitrator within thirty (30) days after the arbitration is initiated, then JAMS will pick
a neutral arbitrator who meets such qualifications. 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. The parties undertake to keep confidential all awards in their
arbitration, together with all materials in the proceedings created for the purpose of the arbitration and all
other documents produced by another party in the proceedings not otherwise in the public domain, save and to
the extent that disclosure may be required of a party by legal duty, to protect or pursue a legal right or to
enforce or challenge an award in legal proceedings before a court or other judicial authority. You and Oculus
agree the following may be submitted to a court of competent jurisdiction located within San Francisco,
California and further agree to submit to the personal jurisdiction of the courts located within San
Francisco, California in connection with (a) any entrance of an arbitrator's judgment or decision, (b) any
dispute with respect to the arbitration process or procedure, (c) Oculus<75> exercise of any of its equitable
rights or remedies or (d) any claims regarding the ownership, validity, enforceability and/or infringement of
any intellectual property rights.

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

View File

@ -0,0 +1,283 @@
/********************************************************************************/ /**
\file OVR_CAPI_Util.h
\brief This header provides LibOVR utility function declarations
\copyright Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
*************************************************************************************/
#ifndef OVR_CAPI_Util_h
#define OVR_CAPI_Util_h
#include "OVR_CAPI.h"
#ifdef __cplusplus
extern "C" {
#endif
/// Enumerates modifications to the projection matrix based on the application's needs.
///
/// \see ovrMatrix4f_Projection
///
typedef enum ovrProjectionModifier_ {
/// Use for generating a default projection matrix that is:
/// * Right-handed.
/// * Near depth values stored in the depth buffer are smaller than far depth values.
/// * Both near and far are explicitly defined.
/// * With a clipping range that is (0 to w).
ovrProjection_None = 0x00,
/// Enable if using left-handed transformations in your application.
ovrProjection_LeftHanded = 0x01,
/// After the projection transform is applied, far values stored in the depth buffer will be less
/// than closer depth values.
/// NOTE: Enable only if the application is using a floating-point depth buffer for proper
/// precision.
ovrProjection_FarLessThanNear = 0x02,
/// When this flag is used, the zfar value pushed into ovrMatrix4f_Projection() will be ignored
/// NOTE: Enable only if ovrProjection_FarLessThanNear is also enabled where the far clipping
/// plane will be pushed to infinity.
ovrProjection_FarClipAtInfinity = 0x04,
/// Enable if the application is rendering with OpenGL and expects a projection matrix with a
/// clipping range of (-w to w).
/// Ignore this flag if your application already handles the conversion from D3D range (0 to w) to
/// OpenGL.
ovrProjection_ClipRangeOpenGL = 0x08,
} ovrProjectionModifier;
/// Return values for ovr_Detect.
///
/// \see ovr_Detect
///
typedef struct OVR_ALIGNAS(8) ovrDetectResult_ {
/// Is ovrFalse when the Oculus Service is not running.
/// This means that the Oculus Service is either uninstalled or stopped.
/// IsOculusHMDConnected will be ovrFalse in this case.
/// Is ovrTrue when the Oculus Service is running.
/// This means that the Oculus Service is installed and running.
/// IsOculusHMDConnected will reflect the state of the HMD.
ovrBool IsOculusServiceRunning;
/// Is ovrFalse when an Oculus HMD is not detected.
/// If the Oculus Service is not running, this will be ovrFalse.
/// Is ovrTrue when an Oculus HMD is detected.
/// This implies that the Oculus Service is also installed and running.
ovrBool IsOculusHMDConnected;
OVR_UNUSED_STRUCT_PAD(pad0, 6) ///< \internal struct padding
} ovrDetectResult;
OVR_STATIC_ASSERT(sizeof(ovrDetectResult) == 8, "ovrDetectResult size mismatch");
/// Modes used to generate Touch Haptics from audio PCM buffer.
///
typedef enum ovrHapticsGenMode_ {
/// Point sample original signal at Haptics frequency
ovrHapticsGenMode_PointSample,
ovrHapticsGenMode_Count
} ovrHapticsGenMode;
/// Store audio PCM data (as 32b float samples) for an audio channel.
/// Note: needs to be released with ovr_ReleaseAudioChannelData to avoid memory leak.
///
typedef struct ovrAudioChannelData_ {
/// Samples stored as floats [-1.0f, 1.0f].
const float* Samples;
/// Number of samples
int SamplesCount;
/// Frequency (e.g. 44100)
int Frequency;
} ovrAudioChannelData;
/// Store a full Haptics clip, which can be used as data source for multiple ovrHapticsBuffers.
///
typedef struct ovrHapticsClip_ {
/// Samples stored in opaque format
const void* Samples;
/// Number of samples
int SamplesCount;
} ovrHapticsClip;
/// Detects Oculus Runtime and Device Status
///
/// Checks for Oculus Runtime and Oculus HMD device status without loading the LibOVRRT
/// shared library. This may be called before ovr_Initialize() to help decide whether or
/// not to initialize LibOVR.
///
/// \param[in] timeoutMilliseconds Specifies a timeout to wait for HMD to be attached or 0 to poll.
///
/// \return Returns an ovrDetectResult object indicating the result of detection.
///
/// \see ovrDetectResult
///
OVR_PUBLIC_FUNCTION(ovrDetectResult) ovr_Detect(int timeoutMilliseconds);
// On the Windows platform,
#ifdef _WIN32
/// This is the Windows Named Event name that is used to check for HMD connected state.
#define OVR_HMD_CONNECTED_EVENT_NAME L"OculusHMDConnected"
#endif // _WIN32
/// Used to generate projection from ovrEyeDesc::Fov.
///
/// \param[in] fov Specifies the ovrFovPort to use.
/// \param[in] znear Distance to near Z limit.
/// \param[in] zfar Distance to far Z limit.
/// \param[in] projectionModFlags A combination of the ovrProjectionModifier flags.
///
/// \return Returns the calculated projection matrix.
///
/// \see ovrProjectionModifier
///
OVR_PUBLIC_FUNCTION(ovrMatrix4f)
ovrMatrix4f_Projection(ovrFovPort fov, float znear, float zfar, unsigned int projectionModFlags);
/// Extracts the required data from the result of ovrMatrix4f_Projection.
///
/// \param[in] projection Specifies the project matrix from which to
/// extract ovrTimewarpProjectionDesc.
/// \param[in] projectionModFlags A combination of the ovrProjectionModifier flags.
/// \return Returns the extracted ovrTimewarpProjectionDesc.
/// \see ovrTimewarpProjectionDesc
///
OVR_PUBLIC_FUNCTION(ovrTimewarpProjectionDesc)
ovrTimewarpProjectionDesc_FromProjection(ovrMatrix4f projection, unsigned int projectionModFlags);
/// Generates an orthographic sub-projection.
///
/// Used for 2D rendering, Y is down.
///
/// \param[in] projection The perspective matrix that the orthographic matrix is derived from.
/// \param[in] orthoScale Equal to 1.0f / pixelsPerTanAngleAtCenter.
/// \param[in] orthoDistance Equal to the distance from the camera in meters, such as 0.8m.
/// \param[in] HmdToEyeOffsetX Specifies the offset of the eye from the center.
///
/// \return Returns the calculated projection matrix.
///
OVR_PUBLIC_FUNCTION(ovrMatrix4f)
ovrMatrix4f_OrthoSubProjection(
ovrMatrix4f projection,
ovrVector2f orthoScale,
float orthoDistance,
float HmdToEyeOffsetX);
/// Computes offset eye poses based on headPose returned by ovrTrackingState.
///
/// \param[in] headPose Indicates the HMD position and orientation to use for the calculation.
/// \param[in] hmdToEyePose Can be ovrEyeRenderDesc.HmdToEyePose returned from
/// ovr_GetRenderDesc. For monoscopic rendering, use a position vector that is average
/// of the two position vectors for each eyes.
/// \param[out] outEyePoses If outEyePoses are used for rendering, they should be passed to
/// ovr_SubmitFrame in ovrLayerEyeFov::RenderPose or ovrLayerEyeFovDepth::RenderPose.
///
#undef ovr_CalcEyePoses
OVR_PUBLIC_FUNCTION(void)
ovr_CalcEyePoses(ovrPosef headPose, const ovrVector3f hmdToEyeOffset[2], ovrPosef outEyePoses[2]);
OVR_PRIVATE_FUNCTION(void)
ovr_CalcEyePoses2(ovrPosef headPose, const ovrPosef HmdToEyePose[2], ovrPosef outEyePoses[2]);
#define ovr_CalcEyePoses ovr_CalcEyePoses2
/// Returns the predicted head pose in outHmdTrackingState and offset eye poses in outEyePoses.
///
/// This is a thread-safe function where caller should increment frameIndex with every frame
/// and pass that index where applicable to functions called on the rendering thread.
/// Assuming outEyePoses are used for rendering, it should be passed as a part of ovrLayerEyeFov.
/// The caller does not need to worry about applying HmdToEyePose to the returned outEyePoses
/// variables.
///
/// \param[in] hmd Specifies an ovrSession previously returned by ovr_Create.
/// \param[in] frameIndex Specifies the targeted frame index, or 0 to refer to one frame after
/// the last time ovr_SubmitFrame was called.
/// \param[in] latencyMarker Specifies that this call is the point in time where
/// the "App-to-Mid-Photon" latency timer starts from. If a given ovrLayer
/// provides "SensorSampleTimestamp", that will override the value stored here.
/// \param[in] hmdToEyePose Can be ovrEyeRenderDesc.HmdToEyePose returned from
/// ovr_GetRenderDesc. For monoscopic rendering, use a position vector that is average
/// of the two position vectors for each eyes.
/// \param[out] outEyePoses The predicted eye poses.
/// \param[out] outSensorSampleTime The time when this function was called. May be NULL, in which
/// case it is ignored.
///
#undef ovr_GetEyePoses
OVR_PUBLIC_FUNCTION(void)
ovr_GetEyePoses(
ovrSession session,
long long frameIndex,
ovrBool latencyMarker,
const ovrVector3f hmdToEyeOffset[2],
ovrPosef outEyePoses[2],
double* outSensorSampleTime);
OVR_PRIVATE_FUNCTION(void)
ovr_GetEyePoses2(
ovrSession session,
long long frameIndex,
ovrBool latencyMarker,
const ovrPosef HmdToEyePose[2],
ovrPosef outEyePoses[2],
double* outSensorSampleTime);
#define ovr_GetEyePoses ovr_GetEyePoses2
/// Tracking poses provided by the SDK come in a right-handed coordinate system. If an application
/// is passing in ovrProjection_LeftHanded into ovrMatrix4f_Projection, then it should also use
/// this function to flip the HMD tracking poses to be left-handed.
///
/// While this utility function is intended to convert a left-handed ovrPosef into a right-handed
/// coordinate system, it will also work for converting right-handed to left-handed since the
/// flip operation is the same for both cases.
///
/// \param[in] inPose that is right-handed
/// \param[out] outPose that is requested to be left-handed (can be the same pointer to inPose)
///
OVR_PUBLIC_FUNCTION(void) ovrPosef_FlipHandedness(const ovrPosef* inPose, ovrPosef* outPose);
/// Reads an audio channel from Wav (Waveform Audio File) data.
/// Input must be a byte buffer representing a valid Wav file. Audio samples from the specified
/// channel are read,
/// converted to float [-1.0f, 1.0f] and returned through ovrAudioChannelData.
///
/// Supported formats: PCM 8b, 16b, 32b and IEEE float (little-endian only).
///
/// \param[out] outAudioChannel output audio channel data.
/// \param[in] inputData a binary buffer representing a valid Wav file data.
/// \param[in] dataSizeInBytes size of the buffer in bytes.
/// \param[in] stereoChannelToUse audio channel index to extract (0 for mono).
///
OVR_PUBLIC_FUNCTION(ovrResult)
ovr_ReadWavFromBuffer(
ovrAudioChannelData* outAudioChannel,
const void* inputData,
int dataSizeInBytes,
int stereoChannelToUse);
/// Generates playable Touch Haptics data from an audio channel.
///
/// \param[out] outHapticsClip generated Haptics clip.
/// \param[in] audioChannel input audio channel data.
/// \param[in] genMode mode used to convert and audio channel data to Haptics data.
///
OVR_PUBLIC_FUNCTION(ovrResult)
ovr_GenHapticsFromAudioData(
ovrHapticsClip* outHapticsClip,
const ovrAudioChannelData* audioChannel,
ovrHapticsGenMode genMode);
/// Releases memory allocated for ovrAudioChannelData. Must be called to avoid memory leak.
/// \param[in] audioChannel pointer to an audio channel
///
OVR_PUBLIC_FUNCTION(void) ovr_ReleaseAudioChannelData(ovrAudioChannelData* audioChannel);
/// Releases memory allocated for ovrHapticsClip. Must be called to avoid memory leak.
/// \param[in] hapticsClip pointer to a haptics clip
///
OVR_PUBLIC_FUNCTION(void) ovr_ReleaseHapticsClip(ovrHapticsClip* hapticsClip);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif // Header include guard

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,73 @@
/************************************************************************************
Filename : OVR_StereoProjection.h
Content : Stereo projection functions
Created : November 30, 2013
Authors : Tom Fosyth
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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_StereoProjection_h
#define OVR_StereoProjection_h
#include "Extras/OVR_Math.h"
namespace OVR {
//-----------------------------------------------------------------------------------
// ***** Stereo Enumerations
// StereoEye specifies which eye we are rendering for; it is used to
// retrieve StereoEyeParams.
enum StereoEye { StereoEye_Left, StereoEye_Right, StereoEye_Center };
//-----------------------------------------------------------------------------------
// ***** Propjection functions
Matrix4f CreateProjection(
bool rightHanded,
bool isOpenGL,
FovPort fov,
StereoEye eye,
float zNear = 0.01f,
float zFar = 10000.0f,
bool flipZ = false,
bool farAtInfinity = false);
Matrix4f CreateOrthoSubProjection(
bool rightHanded,
StereoEye eyeType,
float tanHalfFovX,
float tanHalfFovY,
float unitsX,
float unitsY,
float distanceFromCamera,
float interpupillaryDistance,
Matrix4f const& projection,
float zNear = 0.0f,
float zFar = 0.0f,
bool flipZ = false,
bool farAtInfinity = false);
ScaleAndOffset2D CreateNDCScaleAndOffsetFromFov(FovPort fov);
} // namespace OVR
#endif // OVR_StereoProjection_h

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,85 @@
/********************************************************************************/ /**
\file OVR_CAPI_Audio.h
\brief CAPI audio functions.
\copyright Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
************************************************************************************/
#ifndef OVR_CAPI_Audio_h
#define OVR_CAPI_Audio_h
#ifdef _WIN32
// Prevents <Windows.h> from defining min() and max() macro symbols.
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#include "OVR_CAPI.h"
#define OVR_AUDIO_MAX_DEVICE_STR_SIZE 128
#if !defined(OVR_EXPORTING_CAPI)
/// Gets the ID of the preferred VR audio output device.
///
/// \param[out] deviceOutId The ID of the user's preferred VR audio device to use,
/// which will be valid upon a successful return value, else it will be WAVE_MAPPER.
///
/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
/// ovr_GetLastErrorInfo to get more information.
///
OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetAudioDeviceOutWaveId(UINT* deviceOutId);
/// Gets the ID of the preferred VR audio input device.
///
/// \param[out] deviceInId The ID of the user's preferred VR audio device to use,
/// which will be valid upon a successful return value, else it will be WAVE_MAPPER.
///
/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
/// ovr_GetLastErrorInfo to get more information.
///
OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetAudioDeviceInWaveId(UINT* deviceInId);
/// Gets the GUID of the preferred VR audio device as a string.
///
/// \param[out] deviceOutStrBuffer A buffer where the GUID string for the device will copied to.
///
/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
/// ovr_GetLastErrorInfo to get more information.
///
OVR_PUBLIC_FUNCTION(ovrResult)
ovr_GetAudioDeviceOutGuidStr(WCHAR deviceOutStrBuffer[OVR_AUDIO_MAX_DEVICE_STR_SIZE]);
/// Gets the GUID of the preferred VR audio device.
///
/// \param[out] deviceOutGuid The GUID of the user's preferred VR audio device to use,
/// which will be valid upon a successful return value, else it will be NULL.
///
/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
/// ovr_GetLastErrorInfo to get more information.
///
OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetAudioDeviceOutGuid(GUID* deviceOutGuid);
/// Gets the GUID of the preferred VR microphone device as a string.
///
/// \param[out] deviceInStrBuffer A buffer where the GUID string for the device will copied to.
///
/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
/// ovr_GetLastErrorInfo to get more information.
///
OVR_PUBLIC_FUNCTION(ovrResult)
ovr_GetAudioDeviceInGuidStr(WCHAR deviceInStrBuffer[OVR_AUDIO_MAX_DEVICE_STR_SIZE]);
/// Gets the GUID of the preferred VR microphone device.
///
/// \param[out] deviceInGuid The GUID of the user's preferred VR audio device to use,
/// which will be valid upon a successful return value, else it will be NULL.
///
/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
/// ovr_GetLastErrorInfo to get more information.
///
OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetAudioDeviceInGuid(GUID* deviceInGuid);
#endif // !defined(OVR_EXPORTING_CAPI)
#endif // OVR_OS_MS
#endif // OVR_CAPI_Audio_h

View File

@ -0,0 +1,203 @@
/********************************************************************************/ /**
\file OVR_CAPI_D3D.h
\brief D3D specific structures used by the CAPI interface.
\copyright Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
************************************************************************************/
#ifndef OVR_CAPI_D3D_h
#define OVR_CAPI_D3D_h
#include "OVR_CAPI.h"
#include "OVR_Version.h"
#if defined(_WIN32)
#include <Unknwn.h>
#include <guiddef.h>
#if !defined(OVR_EXPORTING_CAPI)
//-----------------------------------------------------------------------------------
// ***** Direct3D Specific
/// Create Texture Swap Chain suitable for use with Direct3D 11 and 12.
///
/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
/// \param[in] d3dPtr Specifies the application's D3D11Device to create resources with
/// or the D3D12CommandQueue which must be the same one the application renders
/// to the eye textures with.
/// \param[in] desc Specifies requested texture properties. See notes for more info
/// about texture format.
/// \param[in] bindFlags Specifies what ovrTextureBindFlags the application requires
/// for this texture chain.
/// \param[out] out_TextureSwapChain Returns the created ovrTextureSwapChain, which will
/// be valid upon a successful return value, else it will be NULL.
/// This texture chain must be eventually destroyed via ovr_DestroyTextureSwapChain
/// before destroying the session with ovr_Destroy.
///
/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
/// ovr_GetLastErrorInfo to get more information.
///
/// \note The texture format provided in \a desc should be thought of as the format the
/// distortion-compositor will use for the ShaderResourceView when reading the contents of
/// the texture. To that end, it is highly recommended that the application requests texture
// swapchain formats that are in sRGB-space (e.g. OVR_FORMAT_R8G8B8A8_UNORM_SRGB)
/// as the compositor does sRGB-correct rendering. As such, the compositor relies on the
/// GPU's hardware sampler to do the sRGB-to-linear conversion. If the application still
/// prefers to render to a linear format (e.g. OVR_FORMAT_R8G8B8A8_UNORM) while handling the
/// linear-to-gamma conversion via HLSL code, then the application must still request the
/// corresponding sRGB format and also use the \a ovrTextureMisc_DX_Typeless flag in the
/// ovrTextureSwapChainDesc's Flag field. This will allow the application to create
/// a RenderTargetView that is the desired linear format while the compositor continues to
/// treat it as sRGB. Failure to do so will cause the compositor to apply unexpected gamma
/// conversions leading to gamma-curve artifacts. The \a ovrTextureMisc_DX_Typeless
/// flag for depth buffer formats (e.g. OVR_FORMAT_D32_FLOAT) is ignored as they are always
/// converted to be typeless.
///
/// \see ovr_GetTextureSwapChainLength
/// \see ovr_GetTextureSwapChainCurrentIndex
/// \see ovr_GetTextureSwapChainDesc
/// \see ovr_GetTextureSwapChainBufferDX
/// \see ovr_DestroyTextureSwapChain
///
OVR_PUBLIC_FUNCTION(ovrResult)
ovr_CreateTextureSwapChainDX(
ovrSession session,
IUnknown* d3dPtr,
const ovrTextureSwapChainDesc* desc,
ovrTextureSwapChain* out_TextureSwapChain);
/// Get a specific buffer within the chain as any compatible COM interface (similar to
/// QueryInterface)
///
/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
/// \param[in] chain Specifies an ovrTextureSwapChain previously returned
/// by ovr_CreateTextureSwapChainDX
/// \param[in] index Specifies the index within the chain to retrieve.
/// Must be between 0 and length (see ovr_GetTextureSwapChainLength),
/// or may pass -1 to get the buffer at the CurrentIndex location. (Saving a call to
/// GetTextureSwapChainCurrentIndex)
/// \param[in] iid Specifies the interface ID of the interface pointer to query the buffer for.
/// \param[out] out_Buffer Returns the COM interface pointer retrieved.
///
/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
/// ovr_GetLastErrorInfo to get more information.
///
/// <b>Example code</b>
/// \code{.cpp}
/// ovr_GetTextureSwapChainBufferDX(s, d3d11Chain, 0, IID_ID3D11Texture2D, &d3d11Texture);
/// ovr_GetTextureSwapChainBufferDX(s, d3d11Chain, 1, IID_PPV_ARGS(&dxgiResource));
/// ovr_GetTextureSwapChainBufferDX(s, d3d12Chain, 0, IID_ID3D12Resource, &d3d12Texture);
/// \endcode
///
OVR_PUBLIC_FUNCTION(ovrResult)
ovr_GetTextureSwapChainBufferDX(
ovrSession session,
ovrTextureSwapChain chain,
int index,
IID iid,
void** out_Buffer);
/// Create Mirror Texture which is auto-refreshed to mirror Rift contents produced by this
/// application.
///
/// A second call to ovr_CreateMirrorTextureWithOptionsDX for a given ovrSession before destroying
/// the first one is not supported and will result in an error return.
///
/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
/// \param[in] d3dPtr Specifies the application's D3D11Device to create resources with
/// or the D3D12CommandQueue which must be the same one the application renders to
/// the textures with.
/// \param[in] desc Specifies requested texture properties.
/// See notes for more info about texture format.
/// \param[out] out_MirrorTexture Returns the created ovrMirrorTexture, which will be valid upon a
/// successful return value, else it will be NULL.
/// This texture must be eventually destroyed via ovr_DestroyMirrorTexture before
/// destroying the session with ovr_Destroy.
///
/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
/// ovr_GetLastErrorInfo to get more information.
///
/// \note The texture format provided in \a desc should be thought of as the format the compositor
/// will use for the RenderTargetView when writing into mirror texture. To that end, it is
/// highly recommended that the application requests a mirror texture format that is
/// in sRGB-space (e.g. OVR_FORMAT_R8G8B8A8_UNORM_SRGB) as the compositor does sRGB-correct
/// rendering. If however the application wants to still read the mirror texture as a linear
/// format (e.g. OVR_FORMAT_R8G8B8A8_UNORM) and handle the sRGB-to-linear conversion in
/// HLSL code, then it is recommended the application still requests an sRGB format and also
/// use the \a ovrTextureMisc_DX_Typeless flag in the ovrMirrorTextureDesc's Flags field.
/// This will allow the application to bind a ShaderResourceView that is a linear format
/// while the compositor continues to treat is as sRGB. Failure to do so will cause the
/// compositor to apply unexpected gamma conversions leading to gamma-curve artifacts.
///
///
/// <b>Example code</b>
/// \code{.cpp}
/// ovrMirrorTexture mirrorTexture = nullptr;
/// ovrMirrorTextureDesc mirrorDesc = {};
/// mirrorDesc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB;
/// mirrorDesc.Width = mirrorWindowWidth;
/// mirrorDesc.Height = mirrorWindowHeight;
/// ovrResult result = ovr_CreateMirrorTextureWithOptionsDX(session, d3d11Device,
/// &mirrorDesc, &mirrorTexture);
/// [...]
/// // Destroy the texture when done with it.
/// ovr_DestroyMirrorTexture(session, mirrorTexture);
/// mirrorTexture = nullptr;
/// \endcode
///
/// \see ovr_GetMirrorTextureBufferDX
/// \see ovr_DestroyMirrorTexture
///
OVR_PUBLIC_FUNCTION(ovrResult)
ovr_CreateMirrorTextureWithOptionsDX(
ovrSession session,
IUnknown* d3dPtr,
const ovrMirrorTextureDesc* desc,
ovrMirrorTexture* out_MirrorTexture);
/// Deprecated. Use ovr_CreateMirrorTextureWithOptionsDX instead
///
/// Same as ovr_CreateMirrorTextureWithOptionsDX except doesn't use ovrMirrorOptions flags as part
/// of ovrMirrorTextureDesc's MirrorOptions field, and defaults to ovrMirrorOption_PostDistortion
///
/// \see ovrMirrorOptions, ovr_CreateMirrorTextureWithOptionsDX
///
OVR_PUBLIC_FUNCTION(ovrResult)
ovr_CreateMirrorTextureDX(
ovrSession session,
IUnknown* d3dPtr,
const ovrMirrorTextureDesc* desc,
ovrMirrorTexture* out_MirrorTexture);
/// Get a the underlying buffer as any compatible COM interface (similar to QueryInterface)
///
/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
/// \param[in] mirrorTexture Specifies an ovrMirrorTexture previously returned
/// by ovr_CreateMirrorTextureWithOptionsDX
/// \param[in] iid Specifies the interface ID of the interface pointer to query the buffer for.
/// \param[out] out_Buffer Returns the COM interface pointer retrieved.
///
/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
/// ovr_GetLastErrorInfo to get more information.
///
/// <b>Example code</b>
/// \code{.cpp}
/// ID3D11Texture2D* d3d11Texture = nullptr;
/// ovr_GetMirrorTextureBufferDX(session, mirrorTexture, IID_PPV_ARGS(&d3d11Texture));
/// d3d11DeviceContext->CopyResource(d3d11TextureBackBuffer, d3d11Texture);
/// d3d11Texture->Release();
/// dxgiSwapChain->Present(0, 0);
/// \endcode
///
OVR_PUBLIC_FUNCTION(ovrResult)
ovr_GetMirrorTextureBufferDX(
ovrSession session,
ovrMirrorTexture mirrorTexture,
IID iid,
void** out_Buffer);
#endif // !defined(OVR_EXPORTING_CAPI)
#endif // _WIN32
#endif // OVR_CAPI_D3D_h

View File

@ -0,0 +1,137 @@
/********************************************************************************/ /**
\file OVR_CAPI_GL.h
\brief OpenGL-specific structures used by the CAPI interface.
\copyright Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
************************************************************************************/
#ifndef OVR_CAPI_GL_h
#define OVR_CAPI_GL_h
#include "OVR_CAPI.h"
#if !defined(OVR_EXPORTING_CAPI)
/// Creates a TextureSwapChain suitable for use with OpenGL.
///
/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
/// \param[in] desc Specifies the requested texture properties.
/// See notes for more info about texture format.
/// \param[out] out_TextureSwapChain Returns the created ovrTextureSwapChain,
/// which will be valid upon a successful return value, else it will be NULL.
/// This texture swap chain must be eventually destroyed via
// ovr_DestroyTextureSwapChain before destroying the session with ovr_Destroy.
///
/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
/// ovr_GetLastErrorInfo to get more information.
///
/// \note The \a format provided should be thought of as the format the distortion compositor will
/// use when reading the contents of the texture. To that end, it is highly recommended
/// that the application requests texture swap chain formats that are in sRGB-space
/// (e.g. OVR_FORMAT_R8G8B8A8_UNORM_SRGB) as the distortion compositor does sRGB-correct
/// rendering. Furthermore, the app should then make sure "glEnable(GL_FRAMEBUFFER_SRGB);"
/// is called before rendering into these textures. Even though it is not recommended,
/// if the application would like to treat the texture as a linear format and do
/// linear-to-gamma conversion in GLSL, then the application can avoid
/// calling "glEnable(GL_FRAMEBUFFER_SRGB);", but should still pass in an sRGB variant for
/// the \a format. Failure to do so will cause the distortion compositor to apply incorrect
/// gamma conversions leading to gamma-curve artifacts.
///
/// \see ovr_GetTextureSwapChainLength
/// \see ovr_GetTextureSwapChainCurrentIndex
/// \see ovr_GetTextureSwapChainDesc
/// \see ovr_GetTextureSwapChainBufferGL
/// \see ovr_DestroyTextureSwapChain
///
OVR_PUBLIC_FUNCTION(ovrResult)
ovr_CreateTextureSwapChainGL(
ovrSession session,
const ovrTextureSwapChainDesc* desc,
ovrTextureSwapChain* out_TextureSwapChain);
/// Get a specific buffer within the chain as a GL texture name
///
/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
/// \param[in] chain Specifies an ovrTextureSwapChain previously returned
/// by ovr_CreateTextureSwapChainGL
/// \param[in] index Specifies the index within the chain to retrieve.
/// Must be between 0 and length (see ovr_GetTextureSwapChainLength)
/// or may pass -1 to get the buffer at the CurrentIndex location.
/// (Saving a call to GetTextureSwapChainCurrentIndex)
/// \param[out] out_TexId Returns the GL texture object name associated with
/// the specific index requested
///
/// \return Returns an ovrResult indicating success or failure.
/// In the case of failure, use ovr_GetLastErrorInfo to get more information.
///
OVR_PUBLIC_FUNCTION(ovrResult)
ovr_GetTextureSwapChainBufferGL(
ovrSession session,
ovrTextureSwapChain chain,
int index,
unsigned int* out_TexId);
/// Creates a Mirror Texture which is auto-refreshed to mirror Rift contents produced by this
/// application.
///
/// A second call to ovr_CreateMirrorTextureWithOptionsGL for a given ovrSession before destroying
/// the first one is not supported and will result in an error return.
///
/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
/// \param[in] desc Specifies the requested mirror texture description.
/// \param[out] out_MirrorTexture Specifies the created ovrMirrorTexture, which will be
/// valid upon a successful return value, else it will be NULL.
/// This texture must be eventually destroyed via ovr_DestroyMirrorTexture before
/// destroying the session with ovr_Destroy.
///
/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
/// ovr_GetLastErrorInfo to get more information.
///
/// \note The \a format provided should be thought of as the format the distortion compositor will
/// use when writing into the mirror texture. It is highly recommended that mirror textures
// are requested as sRGB formats because the distortion compositor does sRGB-correct
/// rendering. If the application requests a non-sRGB format (e.g. R8G8B8A8_UNORM) as the
/// mirror texture, then the application might have to apply a manual linear-to-gamma
/// conversion when reading from the mirror texture. Failure to do so can result in
// incorrect gamma conversions leading to gamma-curve artifacts and color banding.
///
/// \see ovr_GetMirrorTextureBufferGL
/// \see ovr_DestroyMirrorTexture
///
OVR_PUBLIC_FUNCTION(ovrResult)
ovr_CreateMirrorTextureWithOptionsGL(
ovrSession session,
const ovrMirrorTextureDesc* desc,
ovrMirrorTexture* out_MirrorTexture);
/// Deprecated. Use ovr_CreateMirrorTextureWithOptionsGL instead
///
/// Same as ovr_CreateMirrorTextureWithOptionsGL except doesn't use ovrMirrorOptions flags as part
/// of ovrMirrorTextureDesc's MirrorOptions field, and defaults to ovrMirrorOption_PostDistortion
///
/// \see ovrMirrorOptions, ovr_CreateMirrorTextureWithOptionsGL
///
OVR_PUBLIC_FUNCTION(ovrResult)
ovr_CreateMirrorTextureGL(
ovrSession session,
const ovrMirrorTextureDesc* desc,
ovrMirrorTexture* out_MirrorTexture);
/// Get a the underlying buffer as a GL texture name
///
/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
/// \param[in] mirrorTexture Specifies an ovrMirrorTexture previously returned
// by ovr_CreateMirrorTextureWithOptionsGL
/// \param[out] out_TexId Specifies the GL texture object name associated with the mirror texture
///
/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
/// ovr_GetLastErrorInfo to get more information.
///
OVR_PUBLIC_FUNCTION(ovrResult)
ovr_GetMirrorTextureBufferGL(
ovrSession session,
ovrMirrorTexture mirrorTexture,
unsigned int* out_TexId);
#endif // !defined(OVR_EXPORTING_CAPI)
#endif // OVR_CAPI_GL_h

View File

@ -0,0 +1,49 @@
/********************************************************************************/ /**
\file OVR_CAPI.h
\brief Keys for CAPI property function calls
\copyright Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
************************************************************************************/
#ifndef OVR_CAPI_Keys_h
#define OVR_CAPI_Keys_h
#include "OVR_Version.h"
#define OVR_KEY_USER "User" // string
#define OVR_KEY_NAME "Name" // string
#define OVR_KEY_GENDER "Gender" // string "Male", "Female", or "Unknown"
#define OVR_DEFAULT_GENDER "Unknown"
#define OVR_KEY_PLAYER_HEIGHT "PlayerHeight" // float meters
#define OVR_DEFAULT_PLAYER_HEIGHT 1.778f
#define OVR_KEY_EYE_HEIGHT "EyeHeight" // float meters
#define OVR_DEFAULT_EYE_HEIGHT 1.675f
#define OVR_KEY_NECK_TO_EYE_DISTANCE "NeckEyeDistance" // float[2] meters
#define OVR_DEFAULT_NECK_TO_EYE_HORIZONTAL 0.0805f
#define OVR_DEFAULT_NECK_TO_EYE_VERTICAL 0.075f
#define OVR_KEY_EYE_TO_NOSE_DISTANCE "EyeToNoseDist" // float[2] meters
#define OVR_PERF_HUD_MODE "PerfHudMode" // int, allowed values are defined in enum ovrPerfHudMode
#define OVR_LAYER_HUD_MODE "LayerHudMode" // int, allowed values are defined in enum ovrLayerHudMode
#define OVR_LAYER_HUD_CURRENT_LAYER "LayerHudCurrentLayer" // int, The layer to show
#define OVR_LAYER_HUD_SHOW_ALL_LAYERS "LayerHudShowAll" // bool, Hide other layers when hud enabled
#define OVR_DEBUG_HUD_STEREO_MODE "DebugHudStereoMode" // int, see enum ovrDebugHudStereoMode
#define OVR_DEBUG_HUD_STEREO_GUIDE_INFO_ENABLE "DebugHudStereoGuideInfoEnable" // bool
#define OVR_DEBUG_HUD_STEREO_GUIDE_SIZE "DebugHudStereoGuideSize2f" // float[2]
#define OVR_DEBUG_HUD_STEREO_GUIDE_POSITION "DebugHudStereoGuidePosition3f" // float[3]
#define OVR_DEBUG_HUD_STEREO_GUIDE_YAWPITCHROLL "DebugHudStereoGuideYawPitchRoll3f" // float[3]
#define OVR_DEBUG_HUD_STEREO_GUIDE_COLOR "DebugHudStereoGuideColor4f" // float[4]
#endif // OVR_CAPI_Keys_h

View File

@ -0,0 +1,285 @@
/********************************************************************************/ /**
\file OVR_CAPI_Vk.h
\brief Vulkan specific structures used by the CAPI interface.
\copyright Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
************************************************************************************/
#ifndef OVR_CAPI_Vk_h
#define OVR_CAPI_Vk_h
#include "OVR_CAPI.h"
#include "OVR_Version.h"
#if !defined(OVR_EXPORTING_CAPI)
//-----------------------------------------------------------------------------------
// ***** Vulkan Specific
/// Get a list of Vulkan vkInstance extensions required for VR.
///
/// Returns a list of strings delimited by a single space identifying Vulkan extensions that must
/// be enabled in order for the VR runtime to support Vulkan-based applications. The returned
/// list reflects the current runtime version and the GPU the VR system is currently connected to.
///
/// \param[in] luid Specifies the luid for the relevant GPU, which is returned from ovr_Create.
/// \param[in] extensionNames is a character buffer which will receive a list of extension name
/// strings, separated by a single space char between each extension.
/// \param[in] inoutExtensionNamesSize indicates on input the capacity of extensionNames in chars.
/// On output it returns the number of characters written to extensionNames,
/// including the terminating 0 char. In the case of this function returning
/// ovrError_InsufficientArraySize, the required inoutExtensionNamesSize is returned.
///
/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
/// ovr_GetLastErrorInfo to get more information. Returns ovrError_InsufficientArraySize in
/// the case that inoutExtensionNameSize didn't have enough space, in which case
/// inoutExtensionNameSize will return the required inoutExtensionNamesSize.
///
/// <b>Example code</b>
/// \code{.cpp}
/// char extensionNames[4096];
/// uint32_t extensionNamesSize = sizeof(extensionNames);
/// ovr_GetInstanceExtensionsVk(luid, extensionsnames, &extensionNamesSize);
///
/// uint32_t extensionCount = 0;
/// const char* extensionNamePtrs[256];
/// for(const char* p = extensionNames; *p; ++p) {
/// if((p == extensionNames) || (p[-1] == ' ')) {
/// extensionNamePtrs[extensionCount++] = p;
/// if (p[-1] == ' ')
/// p[-1] = '\0';
/// }
/// }
///
/// VkInstanceCreateInfo info = { ... };
/// info.enabledExtensionCount = extensionCount;
/// info.ppEnabledExtensionNames = extensionNamePtrs;
/// [...]
/// \endcode
///
OVR_PUBLIC_FUNCTION(ovrResult)
ovr_GetInstanceExtensionsVk(
ovrGraphicsLuid luid,
char* extensionNames,
uint32_t* inoutExtensionNamesSize);
/// Get a list of Vulkan vkDevice extensions required for VR.
///
/// Returns a list of strings delimited by a single space identifying Vulkan extensions that must
/// be enabled in order for the VR runtime to support Vulkan-based applications. The returned
/// list reflects the current runtime version and the GPU the VR system is currently connected to.
///
/// \param[in] luid Specifies the luid for the relevant GPU, which is returned from ovr_Create.
/// \param[in] extensionNames is a character buffer which will receive a list of extension name
/// strings, separated by a single space char between each extension.
/// \param[in] inoutExtensionNamesSize indicates on input the capacity of extensionNames in chars.
/// On output it returns the number of characters written to extensionNames,
/// including the terminating 0 char. In the case of this function returning
/// ovrError_InsufficientArraySize, the required inoutExtensionNamesSize is returned.
///
/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
/// ovr_GetLastErrorInfo to get more information. Returns ovrError_InsufficientArraySize in
/// the case that inoutExtensionNameSize didn't have enough space, in which case
/// inoutExtensionNameSize will return the required inoutExtensionNamesSize.
///
OVR_PUBLIC_FUNCTION(ovrResult)
ovr_GetDeviceExtensionsVk(
ovrGraphicsLuid luid,
char* extensionNames,
uint32_t* inoutExtensionNamesSize);
/// Find VkPhysicalDevice matching ovrGraphicsLuid
///
/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
/// \param[in] luid Specifies the luid returned from ovr_Create.
/// \param[in] instance Specifies a VkInstance to search for matching luids in.
/// \param[out] out_physicalDevice Returns the VkPhysicalDevice matching the instance and luid.
///
/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
/// ovr_GetLastErrorInfo to get more information.
///
/// \note This function enumerates the current physical devices and returns the one matching the
/// luid. It must be called at least once prior to any ovr_CreateTextureSwapChainVk or
/// ovr_CreateMirrorTextureWithOptionsVk calls, and the instance must remain valid for the lifetime
/// of the returned objects. It is assumed the VkDevice created by the application will be for the
/// returned physical device.
///
OVR_PUBLIC_FUNCTION(ovrResult)
ovr_GetSessionPhysicalDeviceVk(
ovrSession session,
ovrGraphicsLuid luid,
VkInstance instance,
VkPhysicalDevice* out_physicalDevice);
/// Select VkQueue to block on till rendering is complete
///
/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
/// \param[in] queue Specifies a VkQueue to add a VkFence operation to and wait on.
///
/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
/// ovr_GetLastErrorInfo to get more information.
///
/// \note The queue may be changed at any time but only the value at the time ovr_SubmitFrame
/// is called will be used. ovr_SetSynchronizationQueueVk must be called with a valid VkQueue
/// created on the same VkDevice the texture sets were created on prior to the first call to
/// ovr_SubmitFrame. An internally created VkFence object will be signalled by the completion
/// of operations on queue and waited on to synchronize the VR compositor.
///
OVR_PUBLIC_FUNCTION(ovrResult) ovr_SetSynchronizationQueueVk(ovrSession session, VkQueue queue);
// Backwards compatibility for the original typoed version
#define ovr_SetSynchonizationQueueVk ovr_SetSynchronizationQueueVk
// Define OVR_PREVIEW_DEPRECATION to generate warnings for upcoming API deprecations
#if defined(OVR_PREVIEW_DEPRECATION)
#pragma deprecated("ovr_SetSynchonizationQueueVk")
#endif
/// Create Texture Swap Chain suitable for use with Vulkan
///
/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
/// \param[in] device Specifies the application's VkDevice to create resources with.
/// \param[in] desc Specifies requested texture properties. See notes for more info
/// about texture format.
/// \param[out] out_TextureSwapChain Returns the created ovrTextureSwapChain, which will be valid
/// upon a successful return value, else it will be NULL.
/// This texture chain must be eventually destroyed via ovr_DestroyTextureSwapChain
/// before destroying the session with ovr_Destroy.
///
/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
/// ovr_GetLastErrorInfo to get more information.
///
/// \note The texture format provided in \a desc should be thought of as the format the
/// distortion-compositor will use for the ShaderResourceView when reading the contents
/// of the texture. To that end, it is highly recommended that the application
/// requests texture swapchain formats that are in sRGB-space
/// (e.g. OVR_FORMAT_R8G8B8A8_UNORM_SRGB) as the compositor does sRGB-correct rendering.
/// As such, the compositor relies on the GPU's hardware sampler to do the sRGB-to-linear
/// conversion. If the application still prefers to render to a linear format (e.g.
/// OVR_FORMAT_R8G8B8A8_UNORM) while handling the linear-to-gamma conversion via
/// SPIRV code, then the application must still request the corresponding sRGB format and
/// also use the \a ovrTextureMisc_DX_Typeless flag in the ovrTextureSwapChainDesc's
/// Flag field. This will allow the application to create a RenderTargetView that is the
/// desired linear format while the compositor continues to treat it as sRGB. Failure to
/// do so will cause the compositor to apply unexpected gamma conversions leading to
/// gamma-curve artifacts. The \a ovrTextureMisc_DX_Typeless flag for depth buffer formats
/// (e.g. OVR_FORMAT_D32_FLOAT) is ignored as they are always
/// converted to be typeless.
///
/// \see ovr_GetTextureSwapChainLength
/// \see ovr_GetTextureSwapChainCurrentIndex
/// \see ovr_GetTextureSwapChainDesc
/// \see ovr_GetTextureSwapChainBufferVk
/// \see ovr_DestroyTextureSwapChain
///
OVR_PUBLIC_FUNCTION(ovrResult)
ovr_CreateTextureSwapChainVk(
ovrSession session,
VkDevice device,
const ovrTextureSwapChainDesc* desc,
ovrTextureSwapChain* out_TextureSwapChain);
/// Get a specific VkImage within the chain
///
/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
/// \param[in] chain Specifies an ovrTextureSwapChain previously returned by
/// ovr_CreateTextureSwapChainVk
/// \param[in] index Specifies the index within the chain to retrieve.
/// Must be between 0 and length (see ovr_GetTextureSwapChainLength),
/// or may pass -1 to get the buffer at the CurrentIndex location (saving a
/// call to GetTextureSwapChainCurrentIndex).
/// \param[out] out_Image Returns the VkImage retrieved.
///
/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
/// ovr_GetLastErrorInfo to get more information.
///
OVR_PUBLIC_FUNCTION(ovrResult)
ovr_GetTextureSwapChainBufferVk(
ovrSession session,
ovrTextureSwapChain chain,
int index,
VkImage* out_Image);
/// Create Mirror Texture which is auto-refreshed to mirror Rift contents produced by this
/// application.
///
/// A second call to ovr_CreateMirrorTextureWithOptionsVk for a given ovrSession before destroying
/// the first one is not supported and will result in an error return.
///
/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
/// \param[in] device Specifies the VkDevice to create resources with.
/// \param[in] desc Specifies requested texture properties. See notes for more info
/// about texture format.
/// \param[out] out_MirrorTexture Returns the created ovrMirrorTexture, which will be
/// valid upon a successful return value, else it will be NULL.
/// This texture must be eventually destroyed via ovr_DestroyMirrorTexture before
/// destroying the session with ovr_Destroy.
///
/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
/// ovr_GetLastErrorInfo to get more information.
///
/// \note The texture format provided in \a desc should be thought of as the format the
/// compositor will use for the VkImageView when writing into mirror texture. To that end,
/// it is highly recommended that the application requests a mirror texture format that is
/// in sRGB-space (e.g. OVR_FORMAT_R8G8B8A8_UNORM_SRGB) as the compositor does sRGB-correct
/// rendering. If however the application wants to still read the mirror texture as a
/// linear format (e.g. OVR_FORMAT_R8G8B8A8_UNORM) and handle the sRGB-to-linear conversion
/// in SPIRV code, then it is recommended the application still requests an sRGB format and
/// also use the \a ovrTextureMisc_DX_Typeless flag in the ovrMirrorTextureDesc's
/// Flags field. This will allow the application to bind a ShaderResourceView that is a
/// linear format while the compositor continues to treat is as sRGB. Failure to do so will
/// cause the compositor to apply unexpected gamma conversions leading to
/// gamma-curve artifacts.
///
/// <b>Example code</b>
/// \code{.cpp}
/// ovrMirrorTexture mirrorTexture = nullptr;
/// ovrMirrorTextureDesc mirrorDesc = {};
/// mirrorDesc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB;
/// mirrorDesc.Width = mirrorWindowWidth;
/// mirrorDesc.Height = mirrorWindowHeight;
/// ovrResult result = ovr_CreateMirrorTextureWithOptionsVk(session, vkDevice, &mirrorDesc,
/// &mirrorTexture);
/// [...]
/// // Destroy the texture when done with it.
/// ovr_DestroyMirrorTexture(session, mirrorTexture);
/// mirrorTexture = nullptr;
/// \endcode
///
/// \see ovr_GetMirrorTextureBufferVk
/// \see ovr_DestroyMirrorTexture
///
OVR_PUBLIC_FUNCTION(ovrResult)
ovr_CreateMirrorTextureWithOptionsVk(
ovrSession session,
VkDevice device,
const ovrMirrorTextureDesc* desc,
ovrMirrorTexture* out_MirrorTexture);
/// Get a the underlying mirror VkImage
///
/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
/// \param[in] mirrorTexture Specifies an ovrMirrorTexture previously returned by
/// ovr_CreateMirrorTextureWithOptionsVk
/// \param[out] out_Image Returns the VkImage pointer retrieved.
///
/// \return Returns an ovrResult indicating success or failure. In the case of failure, use
/// ovr_GetLastErrorInfo to get more information.
///
/// <b>Example code</b>
/// \code{.cpp}
/// VkImage mirrorImage = VK_NULL_HANDLE;
/// ovr_GetMirrorTextureBufferVk(session, mirrorTexture, &mirrorImage);
/// ...
/// vkCmdBlitImage(commandBuffer, mirrorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
/// presentImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region, VK_FILTER_LINEAR);
/// ...
/// vkQueuePresentKHR(queue, &presentInfo);
/// \endcode
///
OVR_PUBLIC_FUNCTION(ovrResult)
ovr_GetMirrorTextureBufferVk(
ovrSession session,
ovrMirrorTexture mirrorTexture,
VkImage* out_Image);
#endif // !defined(OVR_EXPORTING_CAPI)
#endif // OVR_CAPI_Vk_h

View File

@ -0,0 +1,324 @@
/********************************************************************************/ /**
\file OVR_ErrorCode.h
\brief This header provides LibOVR error code declarations.
\copyright Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
*************************************************************************************/
#ifndef OVR_ErrorCode_h
#define OVR_ErrorCode_h
#include "OVR_Version.h"
#include <stdint.h>
#ifndef OVR_RESULT_DEFINED
#define OVR_RESULT_DEFINED ///< Allows ovrResult to be independently defined.
/// API call results are represented at the highest level by a single ovrResult.
typedef int32_t ovrResult;
#endif
/// \brief Indicates if an ovrResult indicates success.
///
/// Some functions return additional successful values other than ovrSucces and
/// require usage of this macro to indicate successs.
///
#if !defined(OVR_SUCCESS)
#define OVR_SUCCESS(result) (result >= 0)
#endif
/// \brief Indicates if an ovrResult indicates an unqualified success.
///
/// This is useful for indicating that the code intentionally wants to
/// check for result == ovrSuccess as opposed to OVR_SUCCESS(), which
/// checks for result >= ovrSuccess.
///
#if !defined(OVR_UNQUALIFIED_SUCCESS)
#define OVR_UNQUALIFIED_SUCCESS(result) (result == ovrSuccess)
#endif
/// \brief Indicates if an ovrResult indicates failure.
///
#if !defined(OVR_FAILURE)
#define OVR_FAILURE(result) (!OVR_SUCCESS(result))
#endif
// Success is a value greater or equal to 0, while all error types are negative values.
#ifndef OVR_SUCCESS_DEFINED
#define OVR_SUCCESS_DEFINED ///< Allows ovrResult to be independently defined.
typedef enum ovrSuccessType_ {
/// This is a general success result. Use OVR_SUCCESS to test for success.
ovrSuccess = 0,
} ovrSuccessType;
#endif
// Public success types
// Success is a value greater or equal to 0, while all error types are negative values.
typedef enum ovrSuccessTypes_ {
/// Returned from a call to SubmitFrame. The call succeeded, but what the app
/// rendered will not be visible on the HMD. Ideally the app should continue
/// calling SubmitFrame, but not do any rendering. When the result becomes
/// ovrSuccess, rendering should continue as usual.
ovrSuccess_NotVisible = 1000,
/// Boundary is invalid due to sensor change or was not setup.
ovrSuccess_BoundaryInvalid = 1001,
/// Device is not available for the requested operation.
ovrSuccess_DeviceUnavailable = 1002,
} ovrSuccessTypes;
// Public error types
typedef enum ovrErrorType_ {
/******************/
/* General errors */
/******************/
/// Failure to allocate memory.
ovrError_MemoryAllocationFailure = -1000,
/// Invalid ovrSession parameter provided.
ovrError_InvalidSession = -1002,
/// The operation timed out.
ovrError_Timeout = -1003,
/// The system or component has not been initialized.
ovrError_NotInitialized = -1004,
/// Invalid parameter provided. See error info or log for details.
ovrError_InvalidParameter = -1005,
/// Generic service error. See error info or log for details.
ovrError_ServiceError = -1006,
/// The given HMD doesn't exist.
ovrError_NoHmd = -1007,
/// Function call is not supported on this hardware/software
ovrError_Unsupported = -1009,
/// Specified device type isn't available.
ovrError_DeviceUnavailable = -1010,
/// The headset was in an invalid orientation for the requested
/// operation (e.g. vertically oriented during ovr_RecenterPose).
ovrError_InvalidHeadsetOrientation = -1011,
/// The client failed to call ovr_Destroy on an active session before calling ovr_Shutdown.
/// Or the client crashed.
ovrError_ClientSkippedDestroy = -1012,
/// The client failed to call ovr_Shutdown or the client crashed.
ovrError_ClientSkippedShutdown = -1013,
///< The service watchdog discovered a deadlock.
ovrError_ServiceDeadlockDetected = -1014,
///< Function call is invalid for object's current state
ovrError_InvalidOperation = -1015,
///< Increase size of output array
ovrError_InsufficientArraySize = -1016,
/// There is not any external camera information stored by ovrServer.
ovrError_NoExternalCameraInfo = -1017,
/// Tracking is lost when ovr_GetDevicePoses() is called.
ovrError_LostTracking = -1018,
/// There was a problem initializing the external camera for capture
ovrError_ExternalCameraInitializedFailed = -1019,
/// There was a problem capturing external camera frames
ovrError_ExternalCameraCaptureFailed = -1020,
/// The external camera friendly name list and the external camera name list
/// are not the fixed size(OVR_MAX_EXTERNAL_CAMERA_NAME_BUFFER_SIZE).
ovrError_ExternalCameraNameListsBufferSize = -1021,
/// The external camera friendly name list is not the same size as
/// the external camera name list.
ovrError_ExternalCameraNameListsMistmatch = -1022,
/// The external camera property has not been sent to OVRServer
/// when the user tries to open the camera.
ovrError_ExternalCameraNotCalibrated = -1023,
/// The external camera name is larger than OVR_EXTERNAL_CAMERA_NAME_SIZE-1
ovrError_ExternalCameraNameWrongSize = -1024,
/// The caller doesn't have permissions for the requested action.
ovrError_AccessDenied = -1025,
/*************************************************/
/* Audio error range, reserved for Audio errors. */
/*************************************************/
/// Failure to find the specified audio device.
ovrError_AudioDeviceNotFound = -2001,
/// Generic COM error.
ovrError_AudioComError = -2002,
/**************************/
/* Initialization errors. */
/**************************/
/// Generic initialization error.
ovrError_Initialize = -3000,
/// Couldn't load LibOVRRT.
ovrError_LibLoad = -3001,
/// LibOVRRT version incompatibility.
ovrError_LibVersion = -3002,
/// Couldn't connect to the OVR Service.
ovrError_ServiceConnection = -3003,
/// OVR Service version incompatibility.
ovrError_ServiceVersion = -3004,
/// The operating system version is incompatible.
ovrError_IncompatibleOS = -3005,
/// Unable to initialize the HMD display.
ovrError_DisplayInit = -3006,
/// Unable to start the server. Is it already running?
ovrError_ServerStart = -3007,
/// Attempting to re-initialize with a different version.
ovrError_Reinitialization = -3008,
/// Chosen rendering adapters between client and service do not match
ovrError_MismatchedAdapters = -3009,
/// Calling application has leaked resources
ovrError_LeakingResources = -3010,
/// Client version too old to connect to service
ovrError_ClientVersion = -3011,
/// The operating system is out of date.
ovrError_OutOfDateOS = -3012,
/// The graphics driver is out of date.
ovrError_OutOfDateGfxDriver = -3013,
/// The graphics hardware is not supported
ovrError_IncompatibleGPU = -3014,
/// No valid VR display system found.
ovrError_NoValidVRDisplaySystem = -3015,
/// Feature or API is obsolete and no longer supported.
ovrError_Obsolete = -3016,
/// No supported VR display system found, but disabled or driverless adapter found.
ovrError_DisabledOrDefaultAdapter = -3017,
/// The system is using hybrid graphics (Optimus, etc...), which is not support.
ovrError_HybridGraphicsNotSupported = -3018,
/// Initialization of the DisplayManager failed.
ovrError_DisplayManagerInit = -3019,
/// Failed to get the interface for an attached tracker
ovrError_TrackerDriverInit = -3020,
/// LibOVRRT signature check failure.
ovrError_LibSignCheck = -3021,
/// LibOVRRT path failure.
ovrError_LibPath = -3022,
/// LibOVRRT symbol resolution failure.
ovrError_LibSymbols = -3023,
/// Failed to connect to the service because remote connections to the service are not allowed.
ovrError_RemoteSession = -3024,
/// Vulkan initialization error.
ovrError_InitializeVulkan = -3025,
/// The graphics driver is black-listed.
ovrError_BlacklistedGfxDriver = -3026,
/********************/
/* Rendering errors */
/********************/
/// In the event of a system-wide graphics reset or cable unplug this is returned to the app.
ovrError_DisplayLost = -6000,
/// ovr_CommitTextureSwapChain was called too many times on a texture swapchain without
/// calling submit to use the chain.
ovrError_TextureSwapChainFull = -6001,
/// The ovrTextureSwapChain is in an incomplete or inconsistent state.
/// Ensure ovr_CommitTextureSwapChain was called at least once first.
ovrError_TextureSwapChainInvalid = -6002,
/// Graphics device has been reset (TDR, etc...)
ovrError_GraphicsDeviceReset = -6003,
/// HMD removed from the display adapter
ovrError_DisplayRemoved = -6004,
/// Content protection is not available for the display.
ovrError_ContentProtectionNotAvailable = -6005,
/// Application declared itself as an invisible type and is not allowed to submit frames.
ovrError_ApplicationInvisible = -6006,
/// The given request is disallowed under the current conditions.
ovrError_Disallowed = -6007,
/// Display portion of HMD is plugged into an incompatible port (ex: IGP)
ovrError_DisplayPluggedIncorrectly = -6008,
/// Returned in the event a virtual display system reaches a display limit
ovrError_DisplayLimitReached = -6009,
/****************/
/* Fatal errors */
/****************/
///< A runtime exception occurred. The application is required to shutdown LibOVR and
/// re-initialize it before this error state will be cleared.
ovrError_RuntimeException = -7000,
/**********************/
/* Calibration errors */
/**********************/
/// Result of a missing calibration block
ovrError_NoCalibration = -9000,
/// Result of an old calibration block
ovrError_OldVersion = -9001,
/// Result of a bad calibration block due to lengths
ovrError_MisformattedBlock = -9002,
/****************/
/* Other errors */
/****************/
} ovrErrorType;
/// Provides information about the last error.
/// \see ovr_GetLastErrorInfo
typedef struct ovrErrorInfo_ {
/// The result from the last API call that generated an error ovrResult.
ovrResult Result;
/// A UTF8-encoded null-terminated English string describing the problem.
/// The format of this string is subject to change in future versions.
char ErrorString[512];
} ovrErrorInfo;
#endif /* OVR_ErrorCode_h */

View File

@ -0,0 +1,60 @@
/*************************************************************************************
\file OVR_Version.h
\brief This header provides LibOVR version identification.
\copyright Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
*************************************************************************************/
#ifndef OVR_Version_h
#define OVR_Version_h
/// Conventional string-ification macro.
#if !defined(OVR_STRINGIZE)
#define OVR_STRINGIZEIMPL(x) #x
#define OVR_STRINGIZE(x) OVR_STRINGIZEIMPL(x)
#endif
// Master version numbers
#define OVR_PRODUCT_VERSION 1 // Product version doesn't participate in semantic versioning.
#define OVR_MAJOR_VERSION 1 // If you change these values then you need to also make sure to change
// LibOVR/Projects/Windows/LibOVR.props in parallel.
#define OVR_MINOR_VERSION 43 //
#define OVR_PATCH_VERSION 0
#define OVR_BUILD_NUMBER 0
// This is the ((product * 100) + major) version of the service that the DLL is compatible with.
// When we backport changes to old versions of the DLL we update the old DLLs
// to move this version number up to the latest version.
// The DLL is responsible for checking that the service is the version it supports
// and returning an appropriate error message if it has not been made compatible.
#define OVR_DLL_COMPATIBLE_VERSION 101
// This is the minor version representing the minimum version an application can query with this
// SDK. Calls ovr_Initialize will fail if the application requests a version that is less than this.
#define OVR_MIN_REQUESTABLE_MINOR_VERSION 17
#define OVR_FEATURE_VERSION 0
/// "Major.Minor.Patch"
#if !defined(OVR_VERSION_STRING)
#define OVR_VERSION_STRING OVR_STRINGIZE(OVR_MAJOR_VERSION.OVR_MINOR_VERSION.OVR_PATCH_VERSION)
#endif
/// "Major.Minor.Patch.Build"
#if !defined(OVR_DETAILED_VERSION_STRING)
#define OVR_DETAILED_VERSION_STRING \
OVR_STRINGIZE(OVR_MAJOR_VERSION.OVR_MINOR_VERSION.OVR_PATCH_VERSION.OVR_BUILD_NUMBER)
#endif
/// \brief file description for version info
/// This appears in the user-visible file properties. It is intended to convey publicly
/// available additional information such as feature builds.
#if !defined(OVR_FILE_DESCRIPTION_STRING)
#if defined(_DEBUG)
#define OVR_FILE_DESCRIPTION_STRING "dev build debug"
#else
#define OVR_FILE_DESCRIPTION_STRING "dev build"
#endif
#endif
#endif // OVR_Version_h

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,169 @@
/********************************************************************************/ /**
\file OVR_CAPI_Prototypes.h
\brief Internal CAPI prototype listing macros
\copyright Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
************************************************************************************/
#ifndef OVR_CAPI_Prototypes_h
#define OVR_CAPI_Prototypes_h
#include "OVR_CAPI.h"
//
// OVR_LIST_*_APIS - apply passed in macros to a list of API entrypoints
//
// The _ macro argument is applied for all current API versions
// The X macro argument is applied for back-compat API versions
//
// The tuple passed to either macro is (ReturnType, FunctionName, OptionalVersion, ParameterList)
//
struct ovrViewportStencilDesc_;
typedef struct ovrViewportStencilDesc_ ovrViewportStencilDesc;
// clang-format off
#define OVR_LIST_PUBLIC_APIS(_,X) \
X(ovrBool, ovr_InitializeRenderingShimVersion, , (int requestedMinorVersion)) \
_(ovrResult, ovr_Initialize, , (const ovrInitParams* params)) \
_(void, ovr_Shutdown, , (void)) \
_(const char*, ovr_GetVersionString, , (void)) \
_(void, ovr_GetLastErrorInfo, , (ovrErrorInfo* errorInfo)) \
_(ovrHmdDesc, ovr_GetHmdDesc, , (ovrSession session)) \
_(unsigned int, ovr_GetTrackerCount, , (ovrSession session)) \
_(ovrTrackerDesc, ovr_GetTrackerDesc, , (ovrSession session, unsigned int trackerDescIndex)) \
_(ovrResult, ovr_Create, , (ovrSession* pSession, ovrGraphicsLuid* pLuid)) \
_(void, ovr_Destroy, , (ovrSession session)) \
_(ovrResult, ovr_GetSessionStatus, , (ovrSession session, ovrSessionStatus* sessionStatus)) \
_(ovrResult, ovr_IsExtensionSupported, , (ovrSession session, ovrExtensions extension, ovrBool* outExtensionSupported)) \
_(ovrResult, ovr_EnableExtension, , (ovrSession session, ovrExtensions extension)) \
_(ovrResult, ovr_SetTrackingOriginType, , (ovrSession session, ovrTrackingOrigin origin)) \
_(ovrTrackingOrigin, ovr_GetTrackingOriginType, , (ovrSession session)) \
_(ovrResult, ovr_RecenterTrackingOrigin, , (ovrSession session)) \
_(ovrResult, ovr_SpecifyTrackingOrigin, , (ovrSession session, ovrPosef originPose)) \
_(void, ovr_ClearShouldRecenterFlag, , (ovrSession session)) \
_(ovrTrackingState, ovr_GetTrackingState, , (ovrSession session, double absTime, ovrBool latencyMarker)) \
_(ovrResult, ovr_GetDevicePoses, , (ovrSession session, ovrTrackedDeviceType* deviceTypes, int deviceCount, double absTime, ovrPoseStatef* outDevicePoses)) \
_(ovrTrackerPose, ovr_GetTrackerPose, , (ovrSession session, unsigned int index)) \
_(ovrResult, ovr_GetInputState, , (ovrSession session, ovrControllerType controllerType, ovrInputState*)) \
_(unsigned int, ovr_GetConnectedControllerTypes, , (ovrSession session)) \
_(ovrSizei, ovr_GetFovTextureSize, , (ovrSession session, ovrEyeType eye, ovrFovPort fov, float pixelsPerDisplayPixel)) \
X(ovrResult, ovr_GetViewportStencil, , (ovrSession session, const ovrViewportStencilDesc* viewportStencilDesc, ovrFovStencilMeshBuffer* meshBuffer)) \
_(ovrResult, ovr_GetFovStencil, , (ovrSession session, const ovrFovStencilDesc* fovStencilDesc, ovrFovStencilMeshBuffer* meshBuffer)) \
_(ovrResult, ovr_WaitToBeginFrame, , (ovrSession session, long long frameIndex)) \
_(ovrResult, ovr_BeginFrame, , (ovrSession session, long long frameIndex)) \
_(ovrResult, ovr_EndFrame, , (ovrSession session, long long frameIndex, const ovrViewScaleDesc* viewScaleDesc, ovrLayerHeader const * const * layerPtrList, unsigned int layerCount)) \
X(ovrResult, ovr_SubmitFrame, , (ovrSession session, long long frameIndex, const ovrViewScaleDescPre117* viewScaleDesc, ovrLayerHeader const * const * layerPtrList, unsigned int layerCount)) \
_(ovrResult, ovr_SubmitFrame, 2, (ovrSession session, long long frameIndex, const ovrViewScaleDesc* viewScaleDesc, ovrLayerHeader const * const * layerPtrList, unsigned int layerCount)) \
X(ovrEyeRenderDescPre117, ovr_GetRenderDesc, , (ovrSession session, ovrEyeType eyeType, ovrFovPort fov)) \
_(ovrEyeRenderDesc, ovr_GetRenderDesc, 2, (ovrSession session, ovrEyeType eyeType, ovrFovPort fov)) \
_(double, ovr_GetPredictedDisplayTime, , (ovrSession session, long long frameIndex)) \
_(double, ovr_GetTimeInSeconds, , (void)) \
_(ovrBool, ovr_GetBool, , (ovrSession session, const char* propertyName, ovrBool defaultVal)) \
_(ovrBool, ovr_SetBool, , (ovrSession session, const char* propertyName, ovrBool value)) \
_(int, ovr_GetInt, , (ovrSession session, const char* propertyName, int defaultVal)) \
_(ovrBool, ovr_SetInt, , (ovrSession session, const char* propertyName, int value)) \
_(float, ovr_GetFloat, , (ovrSession session, const char* propertyName, float defaultVal)) \
_(ovrBool, ovr_SetFloat, , (ovrSession session, const char* propertyName, float value)) \
_(unsigned int, ovr_GetFloatArray, , (ovrSession session, const char* propertyName, float values[], unsigned int arraySize)) \
_(ovrBool, ovr_SetFloatArray, , (ovrSession session, const char* propertyName, const float values[], unsigned int arraySize)) \
_(const char*, ovr_GetString, , (ovrSession session, const char* propertyName, const char* defaultVal)) \
_(ovrBool, ovr_SetString, , (ovrSession session, const char* propertyName, const char* value)) \
_(int, ovr_TraceMessage, , (int level, const char* message)) \
_(ovrResult, ovr_IdentifyClient, , (const char* identity)) \
_(ovrResult, ovr_CreateTextureSwapChainGL, , (ovrSession session, const ovrTextureSwapChainDesc* desc, ovrTextureSwapChain* outTextureChain)) \
_(ovrResult, ovr_CreateMirrorTextureGL, , (ovrSession session, const ovrMirrorTextureDesc* desc, ovrMirrorTexture* outMirrorTexture)) \
_(ovrResult, ovr_CreateMirrorTextureWithOptionsGL, , (ovrSession session, const ovrMirrorTextureDesc* desc, ovrMirrorTexture* outMirrorTexture)) \
_(ovrResult, ovr_GetTextureSwapChainBufferGL, , (ovrSession session, ovrTextureSwapChain chain, int index, unsigned int* texId)) \
_(ovrResult, ovr_GetMirrorTextureBufferGL, , (ovrSession session, ovrMirrorTexture mirror, unsigned int* texId)) \
_(ovrResult, ovr_GetTextureSwapChainLength, , (ovrSession session, ovrTextureSwapChain chain, int* length)) \
_(ovrResult, ovr_GetTextureSwapChainCurrentIndex, , (ovrSession session, ovrTextureSwapChain chain, int* currentIndex)) \
_(ovrResult, ovr_GetTextureSwapChainDesc, , (ovrSession session, ovrTextureSwapChain chain, ovrTextureSwapChainDesc* desc)) \
_(ovrResult, ovr_CommitTextureSwapChain, , (ovrSession session, ovrTextureSwapChain chain)) \
_(void, ovr_DestroyTextureSwapChain, , (ovrSession session, ovrTextureSwapChain chain)) \
_(void, ovr_DestroyMirrorTexture, , (ovrSession session, ovrMirrorTexture texture)) \
X(ovrResult, ovr_SetQueueAheadFraction, , (ovrSession session, float queueAheadFraction)) \
_(ovrResult, ovr_Lookup, , (const char* name, void** data)) \
_(ovrTouchHapticsDesc, ovr_GetTouchHapticsDesc, , (ovrSession session, ovrControllerType controllerType)) \
_(ovrResult, ovr_SetControllerVibration, , (ovrSession session, ovrControllerType controllerType, float frequency, float amplitude)) \
_(ovrResult, ovr_SubmitControllerVibration, , (ovrSession session, ovrControllerType controllerType, const ovrHapticsBuffer* buffer)) \
_(ovrResult, ovr_GetControllerVibrationState, , (ovrSession session, ovrControllerType controllerType, ovrHapticsPlaybackState* outState)) \
_(ovrResult, ovr_TestBoundary, , (ovrSession session, ovrTrackedDeviceType deviceBitmask, ovrBoundaryType singleBoundaryType, ovrBoundaryTestResult* outTestResult)) \
_(ovrResult, ovr_TestBoundaryPoint, , (ovrSession session, const ovrVector3f* point, ovrBoundaryType singleBoundaryType, ovrBoundaryTestResult* outTestResult)) \
_(ovrResult, ovr_SetBoundaryLookAndFeel, , (ovrSession session, const ovrBoundaryLookAndFeel* lookAndFeel)) \
_(ovrResult, ovr_ResetBoundaryLookAndFeel, , (ovrSession session)) \
_(ovrResult, ovr_GetBoundaryGeometry, , (ovrSession session, ovrBoundaryType singleBoundaryType, ovrVector3f* outFloorPoints, int* outFloorPointsCount)) \
_(ovrResult, ovr_GetBoundaryDimensions, , (ovrSession session, ovrBoundaryType singleBoundaryType, ovrVector3f* outDimension)) \
_(ovrResult, ovr_GetBoundaryVisible, , (ovrSession session, ovrBool* outIsVisible)) \
_(ovrResult, ovr_RequestBoundaryVisible, , (ovrSession session, ovrBool visible)) \
_(ovrResult, ovr_GetPerfStats, , (ovrSession session, ovrPerfStats* outPerfStats)) \
_(ovrResult, ovr_ResetPerfStats, , (ovrSession session))\
_(ovrResult, ovr_GetExternalCameras, , (ovrSession session, ovrExternalCamera* outCameras, unsigned int* outCameraCount))\
_(ovrResult, ovr_SetExternalCameraProperties, , (ovrSession session, const char* name, const ovrCameraIntrinsics* const intrinsics, const ovrCameraExtrinsics* const extrinsics ))
#if defined (_WIN32)
#define OVR_LIST_WIN32_APIS(_,X) \
_(ovrResult, ovr_CreateTextureSwapChainDX, , (ovrSession session, IUnknown* d3dPtr, const ovrTextureSwapChainDesc* desc, ovrTextureSwapChain* outTextureChain)) \
_(ovrResult, ovr_CreateMirrorTextureDX, , (ovrSession session, IUnknown* d3dPtr, const ovrMirrorTextureDesc* desc, ovrMirrorTexture* outMirrorTexture)) \
_(ovrResult, ovr_CreateMirrorTextureWithOptionsDX, , (ovrSession session, IUnknown* d3dPtr, const ovrMirrorTextureDesc* desc, ovrMirrorTexture* outMirrorTexture)) \
_(ovrResult, ovr_GetTextureSwapChainBufferDX, , (ovrSession session, ovrTextureSwapChain chain, int index, IID iid, void** ppObject)) \
_(ovrResult, ovr_GetMirrorTextureBufferDX, , (ovrSession session, ovrMirrorTexture mirror, IID iid, void** ppObject)) \
_(ovrResult, ovr_GetAudioDeviceOutWaveId, , (UINT* deviceOutId)) \
_(ovrResult, ovr_GetAudioDeviceInWaveId, , (UINT* deviceInId)) \
_(ovrResult, ovr_GetAudioDeviceOutGuidStr, , (WCHAR* deviceOutStrBuffer)) \
_(ovrResult, ovr_GetAudioDeviceOutGuid, , (GUID* deviceOutGuid)) \
_(ovrResult, ovr_GetAudioDeviceInGuidStr, , (WCHAR* deviceInStrBuffer)) \
_(ovrResult, ovr_GetAudioDeviceInGuid, , (GUID* deviceInGuid)) \
_(ovrResult, ovr_GetInstanceExtensionsVk, , (ovrGraphicsLuid luid, char* extensionNames, uint32_t* inoutExtensionNamesSize)) \
_(ovrResult, ovr_GetDeviceExtensionsVk, , (ovrGraphicsLuid luid, char* extensionNames, uint32_t* inoutExtensionNamesSize)) \
_(ovrResult, ovr_GetSessionPhysicalDeviceVk, , (ovrSession session, ovrGraphicsLuid luid, VkInstance instance, VkPhysicalDevice* out_physicalDevice)) \
X(ovrResult, ovr_SetSynchonizationQueueVk, , (ovrSession session, VkQueue queue)) \
_(ovrResult, ovr_SetSynchronizationQueueVk, , (ovrSession session, VkQueue queue)) \
_(ovrResult, ovr_CreateTextureSwapChainVk, , (ovrSession session, VkDevice device, const ovrTextureSwapChainDesc* desc, ovrTextureSwapChain* out_TextureSwapChain)) \
_(ovrResult, ovr_GetTextureSwapChainBufferVk, , (ovrSession session, ovrTextureSwapChain chain, int index, VkImage* out_Image)) \
_(ovrResult, ovr_CreateMirrorTextureWithOptionsVk, , (ovrSession session, VkDevice device, const ovrMirrorTextureDesc* desc, ovrMirrorTexture* out_MirrorTexture)) \
_(ovrResult, ovr_GetMirrorTextureBufferVk, , (ovrSession session, ovrMirrorTexture mirrorTexture, VkImage* out_Image))
#else
#define OVR_LIST_WIN32_APIS(_,X)
#endif
#define OVR_LIST_INTERNAL_APIS(_,X)
// We need to forward declare the ovrSensorData type here, as it won't be in a public OVR_CAPI.h header.
struct ovrSensorData_;
typedef struct ovrSensorData_ ovrSensorData;
// Hybrid Apps API forward declaration which won't be in a public OVR_CAPI.h header for now.
// --------------------------------------------------------------------------
struct ovrDesktopWindowDesc_;
typedef struct ovrDesktopWindowDesc_ ovrDesktopWindowDesc;
struct ovrKeyboardDesc_;
typedef struct ovrKeyboardDesc_ ovrKeyboardDesc;
enum ovrHybridInputFocusType_ ;
typedef enum ovrHybridInputFocusType_ ovrHybridInputFocusType;
struct ovrHybridInputFocusState_;
typedef struct ovrHybridInputFocusState_ ovrHybridInputFocusState;
typedef uint32_t ovrDesktopWindowHandle;
// --------------------------------------------------------------------------
#define OVR_LIST_PRIVATE_APIS(_,X)
// clang-format on
//
// OVR_LIST_APIS - master list of all API entrypoints
//
#define OVR_LIST_APIS(_, X) \
OVR_LIST_PUBLIC_APIS(_, X) \
OVR_LIST_WIN32_APIS(_, X) \
OVR_LIST_INTERNAL_APIS(_, X) \
OVR_LIST_PRIVATE_APIS(_, X)
#endif // OVR_CAPI_Prototypes_h

View File

@ -0,0 +1,437 @@
/************************************************************************************
PublicHeader: OVR_CAPI_Util.c
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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 <Extras/OVR_CAPI_Util.h>
#include <Extras/OVR_StereoProjection.h>
#include <limits.h>
#if !defined(_WIN32)
#include <assert.h>
#endif
#if defined(_MSC_VER) && _MSC_VER < 1800 // MSVC < 2013
#define round(dbl) \
(dbl) >= 0.0 ? (int)((dbl) + 0.5) \
: (((dbl) - (double)(int)(dbl)) <= -0.5 ? (int)(dbl) : (int)((dbl)-0.5))
#endif
#if defined(_MSC_VER)
#include <emmintrin.h>
#pragma intrinsic(_mm_pause)
#endif
#if defined(_WIN32)
#include <windows.h>
#endif
#if defined(OVR_DLL_BUILD) && defined(OVR_OPENXR_SUPPORT_ENABLED)
// This forces transitive export of the symbols marked for export in OVR_OpenXR_Impl.cpp:
__pragma(comment(linker, "/INCLUDE:" OVR_ON32("_") "exported_openxr_version"))
#endif // defined(OVR_DLL_BUILD) && defined(OVR_OPENXR_SUPPORT_ENABLED)
template <typename T>
T ovrMax(T a, T b) {
return a > b ? a : b;
}
template <typename T>
T ovrMin(T a, T b) {
return a < b ? a : b;
}
// Used to generate projection from ovrEyeDesc::Fov
OVR_PUBLIC_FUNCTION(ovrMatrix4f)
ovrMatrix4f_Projection(ovrFovPort fov, float znear, float zfar, unsigned int projectionModFlags) {
bool leftHanded = (projectionModFlags & ovrProjection_LeftHanded) > 0;
bool flipZ = (projectionModFlags & ovrProjection_FarLessThanNear) > 0;
bool farAtInfinity = (projectionModFlags & ovrProjection_FarClipAtInfinity) > 0;
bool isOpenGL = (projectionModFlags & ovrProjection_ClipRangeOpenGL) > 0;
// TODO: Pass in correct eye to CreateProjection if we want to support canted displays from CAPI
return OVR::CreateProjection(
leftHanded, isOpenGL, fov, OVR::StereoEye_Center, znear, zfar, flipZ, farAtInfinity);
}
OVR_PUBLIC_FUNCTION(ovrTimewarpProjectionDesc)
ovrTimewarpProjectionDesc_FromProjection(ovrMatrix4f Projection, unsigned int projectionModFlags) {
ovrTimewarpProjectionDesc res;
res.Projection22 = Projection.M[2][2];
res.Projection23 = Projection.M[2][3];
res.Projection32 = Projection.M[3][2];
if ((res.Projection32 != 1.0f) && (res.Projection32 != -1.0f)) {
// This is a very strange projection matrix, and probably won't work.
// If you need it to work, please contact Oculus and let us know your usage scenario.
}
if ((projectionModFlags & ovrProjection_ClipRangeOpenGL) != 0) {
// Internally we use the D3D range of [0,+w] not the OGL one of [-w,+w], so we need to convert
// one to the other.
// Note that the values in the depth buffer, and the actual linear depth we want is the same for
// both APIs,
// the difference is purely in the values inside the projection matrix.
// D3D does this:
// depthBuffer = ( ProjD3D.M[2][2] * linearDepth + ProjD3D.M[2][3] ) / ( linearDepth
// * ProjD3D.M[3][2] );
// OGL does this:
// depthBuffer = 0.5 + 0.5 * ( ProjOGL.M[2][2] * linearDepth + ProjOGL.M[2][3] ) / ( linearDepth
// * ProjOGL.M[3][2] );
// Therefore:
// ProjD3D.M[2][2] = 0.5 * ( ProjOGL.M[2][2] + ProjOGL.M[3][2] );
// ProjD3D.M[2][3] = 0.5 * ProjOGL.M[2][3];
// ProjD3D.M[3][2] = ProjOGL.M[3][2];
res.Projection22 = 0.5f * (Projection.M[2][2] + Projection.M[3][2]);
res.Projection23 = 0.5f * Projection.M[2][3];
res.Projection32 = Projection.M[3][2];
}
return res;
}
OVR_PUBLIC_FUNCTION(ovrMatrix4f)
ovrMatrix4f_OrthoSubProjection(
ovrMatrix4f projection,
ovrVector2f orthoScale,
float orthoDistance,
float hmdToEyeOffsetX) {
ovrMatrix4f ortho;
// Negative sign is correct!
// If the eye is offset to the left, then the ortho view needs to be offset to the right relative
// to the camera.
float orthoHorizontalOffset = -hmdToEyeOffsetX / 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 same 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].
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];
ortho.M[2][0] = 0.0f;
ortho.M[2][1] = 0.0f;
ortho.M[2][2] = 0.0f;
ortho.M[2][3] = 0.0f;
/* 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;
}
#undef ovr_CalcEyePoses
OVR_PUBLIC_FUNCTION(void)
ovr_CalcEyePoses(ovrPosef headPose, const ovrVector3f hmdToEyeOffset[2], ovrPosef outEyePoses[2]) {
if (!hmdToEyeOffset || !outEyePoses) {
return;
}
using OVR::Posef;
using OVR::Vector3f;
// Currently hmdToEyeOffset is only a 3D vector
outEyePoses[0] =
Posef(headPose.Orientation, ((Posef)headPose).Apply((Vector3f)hmdToEyeOffset[0]));
outEyePoses[1] =
Posef(headPose.Orientation, ((Posef)headPose).Apply((Vector3f)hmdToEyeOffset[1]));
}
OVR_PRIVATE_FUNCTION(void)
ovr_CalcEyePoses2(ovrPosef headPose, const ovrPosef hmdToEyePose[2], ovrPosef outEyePoses[2]) {
if (!hmdToEyePose || !outEyePoses) {
return;
}
using OVR::Posef;
using OVR::Vector3f;
outEyePoses[0] = (Posef)headPose * (Posef)hmdToEyePose[0];
outEyePoses[1] = (Posef)headPose * (Posef)hmdToEyePose[1];
}
#undef ovr_GetEyePoses
OVR_PUBLIC_FUNCTION(void)
ovr_GetEyePoses(
ovrSession session,
long long frameIndex,
ovrBool latencyMarker,
const ovrVector3f hmdToEyeOffset[2],
ovrPosef outEyePoses[2],
double* outSensorSampleTime) {
double frameTime = ovr_GetPredictedDisplayTime(session, frameIndex);
ovrTrackingState trackingState = ovr_GetTrackingState(session, frameTime, latencyMarker);
ovr_CalcEyePoses(trackingState.HeadPose.ThePose, hmdToEyeOffset, outEyePoses);
if (outSensorSampleTime != nullptr) {
*outSensorSampleTime = ovr_GetTimeInSeconds();
}
}
OVR_PRIVATE_FUNCTION(void)
ovr_GetEyePoses2(
ovrSession session,
long long frameIndex,
ovrBool latencyMarker,
const ovrPosef hmdToEyePose[2],
ovrPosef outEyePoses[2],
double* outSensorSampleTime) {
double frameTime = ovr_GetPredictedDisplayTime(session, frameIndex);
ovrTrackingState trackingState = ovr_GetTrackingState(session, frameTime, latencyMarker);
ovr_CalcEyePoses2(trackingState.HeadPose.ThePose, hmdToEyePose, outEyePoses);
if (outSensorSampleTime != nullptr) {
*outSensorSampleTime = ovr_GetTimeInSeconds();
}
}
OVR_PUBLIC_FUNCTION(ovrDetectResult) ovr_Detect(int timeoutMilliseconds) {
// Initially we assume everything is not running.
ovrDetectResult result;
result.IsOculusHMDConnected = ovrFalse;
result.IsOculusServiceRunning = ovrFalse;
#if defined(_WIN32)
// Attempt to open the named event.
HANDLE hServiceEvent = ::OpenEventW(SYNCHRONIZE, FALSE, OVR_HMD_CONNECTED_EVENT_NAME);
// If event exists,
if (hServiceEvent != nullptr) {
// This indicates that the Oculus Runtime is installed and running.
result.IsOculusServiceRunning = ovrTrue;
// Poll for event state.
DWORD objectResult = ::WaitForSingleObject(hServiceEvent, timeoutMilliseconds);
// If the event is signaled,
if (objectResult == WAIT_OBJECT_0) {
// This indicates that the Oculus HMD is connected.
result.IsOculusHMDConnected = ovrTrue;
}
::CloseHandle(hServiceEvent);
}
#else
(void)timeoutMilliseconds;
fprintf(stderr, __FILE__ "::[%s] Not implemented. Assuming single-process.\n", __func__);
result.IsOculusServiceRunning = ovrTrue;
result.IsOculusHMDConnected = ovrTrue;
#endif // OSX_UNIMPLEMENTED
return result;
}
OVR_PUBLIC_FUNCTION(void) ovrPosef_FlipHandedness(const ovrPosef* inPose, ovrPosef* outPose) {
outPose->Orientation.x = -inPose->Orientation.x;
outPose->Orientation.y = inPose->Orientation.y;
outPose->Orientation.z = inPose->Orientation.z;
outPose->Orientation.w = -inPose->Orientation.w;
outPose->Position.x = -inPose->Position.x;
outPose->Position.y = inPose->Position.y;
outPose->Position.z = inPose->Position.z;
}
static float wavPcmBytesToFloat(const void* data, int32_t sizeInBits, bool swapBytes) {
// TODO Support big endian
(void)swapBytes;
// There's not a strong standard to convert 8/16/32b PCM to float.
// For 16b: MSDN says range is [-32760, 32760], Pyton Scipy uses [-32767, 32767] and Audacity
// outputs the full range [-32768, 32767].
// We use the same range on both sides and clamp to [-1, 1].
float result = 0.0f;
if (sizeInBits == 8)
// uint8_t is a special case, unsigned where 128 is zero
result = (*((uint8_t*)data) / (float)UCHAR_MAX) * 2.0f - 1.0f;
else if (sizeInBits == 16)
result = *((int16_t*)data) / (float)SHRT_MAX;
// else if (sizeInBits == 24) {
// int value = data[0] | data[1] << 8 | data[2] << 16; // Need consider 2's complement
// return value / 8388607.0f;
//}
else if (sizeInBits == 32)
result = *((int32_t*)data) / (float)INT_MAX;
return ovrMax(-1.0f, result);
}
OVR_PUBLIC_FUNCTION(ovrResult)
ovr_GenHapticsFromAudioData(
ovrHapticsClip* outHapticsClip,
const ovrAudioChannelData* audioChannel,
ovrHapticsGenMode genMode) {
if (!outHapticsClip || !audioChannel || genMode != ovrHapticsGenMode_PointSample)
return ovrError_InvalidParameter;
// Validate audio channel
if (audioChannel->Frequency <= 0 || audioChannel->SamplesCount <= 0 ||
audioChannel->Samples == nullptr)
return ovrError_InvalidParameter;
const int32_t kHapticsFrequency = 320;
const int32_t kHapticsMaxAmplitude = 255;
float samplesPerStep = audioChannel->Frequency / (float)kHapticsFrequency;
int32_t hapticsSampleCount = (int32_t)ceil(audioChannel->SamplesCount / samplesPerStep);
uint8_t* hapticsSamples = new uint8_t[hapticsSampleCount];
for (int32_t i = 0; i < hapticsSampleCount; ++i) {
float sample = audioChannel->Samples[(int32_t)(i * samplesPerStep)];
uint8_t hapticSample =
(uint8_t)ovrMin(UCHAR_MAX, (int)round(fabs(sample) * kHapticsMaxAmplitude));
hapticsSamples[i] = hapticSample;
}
outHapticsClip->Samples = hapticsSamples;
outHapticsClip->SamplesCount = hapticsSampleCount;
return ovrSuccess;
}
OVR_PUBLIC_FUNCTION(ovrResult)
ovr_ReadWavFromBuffer(
ovrAudioChannelData* outAudioChannel,
const void* inputData,
int dataSizeInBytes,
int stereoChannelToUse) {
// We don't support any format other than PCM and IEEE Float
enum WavFormats {
kWavFormatUnknown = 0x0000,
kWavFormatLPCM = 0x0001,
kWavFormatFloatIEEE = 0x0003,
kWavFormatExtensible = 0xFFFE
};
struct WavHeader {
char RiffId[4]; // "RIFF" = little-endian, "RIFX" = big-endian
int32_t Size; // 4 + (8 + FmtChunkSize) + (8 + DataChunkSize)
char WavId[4]; // Must be "WAVE"
char FmtChunckId[4]; // Must be "fmt "
uint32_t FmtChunkSize; // Remaining size of this chunk (16B)
uint16_t Format; // WavFormats: PCM or Float supported
uint16_t Channels; // 1 = Mono, 2 = Stereo
uint32_t SampleRate; // e.g. 44100
uint32_t BytesPerSec; // SampleRate * BytesPerBlock
uint16_t BytesPerBlock; // (NumChannels * BitsPerSample/8)
uint16_t BitsPerSample; // 8, 16, 32
char DataChunckId[4]; // Must be "data"
uint32_t DataChunkSize; // Remaining size of this chunk
};
const int32_t kMinWavFileSize = sizeof(WavHeader) + 1;
if (!outAudioChannel || !inputData || dataSizeInBytes < kMinWavFileSize)
return ovrError_InvalidParameter;
WavHeader* header = (WavHeader*)inputData;
uint8_t* data = (uint8_t*)inputData + sizeof(WavHeader);
// Validate
const char* wavId = header->RiffId;
// TODO We need to support RIFX when supporting big endian formats
// bool isValidWav = (wavId[0] == 'R' && wavId[1] == 'I' && wavId[2] == 'F' && (wavId[3] == 'F' ||
// wavId[3] == 'X')) &&
bool isValidWav = (wavId[0] == 'R' && wavId[1] == 'I' && wavId[2] == 'F' && wavId[3] == 'F') &&
memcmp(header->WavId, "WAVE", 4) == 0;
bool hasValidChunks =
memcmp(header->FmtChunckId, "fmt ", 4) == 0 && memcmp(header->DataChunckId, "data ", 4) == 0;
if (!isValidWav || !hasValidChunks) {
return ovrError_InvalidOperation;
}
// We only support PCM
bool isSupported = (header->Format == kWavFormatLPCM || header->Format == kWavFormatFloatIEEE) &&
(header->Channels == 1 || header->Channels == 2) &&
(header->BitsPerSample == 8 || header->BitsPerSample == 16 || header->BitsPerSample == 32);
if (!isSupported) {
return ovrError_Unsupported;
}
// Channel selection
bool useSecondChannel = (header->Channels == 2 && stereoChannelToUse == 1);
int32_t channelOffset = (useSecondChannel) ? header->BytesPerBlock / 2 : 0;
// TODO Support big-endian
int32_t blockCount = header->DataChunkSize / header->BytesPerBlock;
float* samples = new float[blockCount];
for (int32_t i = 0; i < blockCount; i++) {
int32_t dataIndex = i * header->BytesPerBlock;
uint8_t* dataPtr = &data[dataIndex + channelOffset];
float sample = (header->Format == kWavFormatLPCM)
? wavPcmBytesToFloat(dataPtr, header->BitsPerSample, false)
: *(float*)dataPtr;
samples[i] = sample;
}
// Output
outAudioChannel->Samples = samples;
outAudioChannel->SamplesCount = blockCount;
outAudioChannel->Frequency = header->SampleRate;
return ovrSuccess;
}
OVR_PUBLIC_FUNCTION(void) ovr_ReleaseAudioChannelData(ovrAudioChannelData* audioChannel) {
if (audioChannel != nullptr && audioChannel->Samples != nullptr) {
delete[] audioChannel->Samples;
memset(audioChannel, 0, sizeof(ovrAudioChannelData));
}
}
OVR_PUBLIC_FUNCTION(void) ovr_ReleaseHapticsClip(ovrHapticsClip* hapticsClip) {
if (hapticsClip != nullptr && hapticsClip->Samples != nullptr) {
delete[](uint8_t*) hapticsClip->Samples;
memset(hapticsClip, 0, sizeof(ovrHapticsClip));
}
}

View File

@ -0,0 +1,218 @@
/************************************************************************************
Filename : OVR_StereoProjection.cpp
Content : Stereo rendering functions
Created : November 30, 2013
Authors : Tom Fosyth
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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 <Extras/OVR_StereoProjection.h>
namespace OVR {
ScaleAndOffset2D CreateNDCScaleAndOffsetFromFov(FovPort tanHalfFov) {
float projXScale = 2.0f / (tanHalfFov.LeftTan + tanHalfFov.RightTan);
float projXOffset = (tanHalfFov.LeftTan - tanHalfFov.RightTan) * projXScale * 0.5f;
float projYScale = 2.0f / (tanHalfFov.UpTan + tanHalfFov.DownTan);
float projYOffset = (tanHalfFov.UpTan - tanHalfFov.DownTan) * projYScale * 0.5f;
ScaleAndOffset2D result;
result.Scale = Vector2f(projXScale, projYScale);
result.Offset = Vector2f(projXOffset, projYOffset);
// Hey - why is that Y.Offset negated?
// It's because a projection matrix transforms from world coords with Y=up,
// whereas this is from NDC which is Y=down.
return result;
}
Matrix4f CreateProjection(
bool leftHanded,
bool isOpenGL,
FovPort tanHalfFov,
StereoEye /*eye*/,
float zNear /*= 0.01f*/,
float zFar /*= 10000.0f*/,
bool flipZ /*= false*/,
bool farAtInfinity /*= false*/) {
if (!flipZ && farAtInfinity) {
// OVR_ASSERT_M(false, "Cannot push Far Clip to Infinity when Z-order is not flipped");
// Assertion disabled because this code no longer has access to LibOVRKernel assertion
// functionality.
farAtInfinity = false;
}
// A projection matrix is very like a scaling from NDC, so we can start with that.
ScaleAndOffset2D scaleAndOffset = CreateNDCScaleAndOffsetFromFov(tanHalfFov);
float handednessScale = leftHanded ? 1.0f : -1.0f;
Matrix4f projection;
// Produces X result, mapping clip edges to [-w,+w]
projection.M[0][0] = scaleAndOffset.Scale.x;
projection.M[0][1] = 0.0f;
projection.M[0][2] = handednessScale * scaleAndOffset.Offset.x;
projection.M[0][3] = 0.0f;
// Produces Y result, mapping clip edges to [-w,+w]
// Hey - why is that YOffset negated?
// It's because a projection matrix transforms from world coords with Y=up,
// whereas this is derived from an NDC scaling, which is Y=down.
projection.M[1][0] = 0.0f;
projection.M[1][1] = scaleAndOffset.Scale.y;
projection.M[1][2] = handednessScale * -scaleAndOffset.Offset.y;
projection.M[1][3] = 0.0f;
// Produces Z-buffer result - app needs to fill this in with whatever Z range it wants.
// We'll just use some defaults for now.
projection.M[2][0] = 0.0f;
projection.M[2][1] = 0.0f;
if (farAtInfinity) {
if (isOpenGL) {
// It's not clear this makes sense for OpenGL - you don't get the same precision benefits you
// do in D3D.
projection.M[2][2] = -handednessScale;
projection.M[2][3] = 2.0f * zNear;
} else {
projection.M[2][2] = 0.0f;
projection.M[2][3] = zNear;
}
} else {
if (isOpenGL) {
// Clip range is [-w,+w], so 0 is at the middle of the range.
projection.M[2][2] =
-handednessScale * (flipZ ? -1.0f : 1.0f) * (zNear + zFar) / (zNear - zFar);
projection.M[2][3] = 2.0f * ((flipZ ? -zFar : zFar) * zNear) / (zNear - zFar);
} else {
// Clip range is [0,+w], so 0 is at the start of the range.
projection.M[2][2] = -handednessScale * (flipZ ? -zNear : zFar) / (zNear - zFar);
projection.M[2][3] = ((flipZ ? -zFar : zFar) * zNear) / (zNear - zFar);
}
}
// Produces W result (= Z in)
projection.M[3][0] = 0.0f;
projection.M[3][1] = 0.0f;
projection.M[3][2] = handednessScale;
projection.M[3][3] = 0.0f;
return projection;
}
Matrix4f CreateOrthoSubProjection(
bool /*rightHanded*/,
StereoEye eyeType,
float tanHalfFovX,
float tanHalfFovY,
float unitsX,
float unitsY,
float distanceFromCamera,
float interpupillaryDistance,
Matrix4f const& projection,
float zNear /*= 0.0f*/,
float zFar /*= 0.0f*/,
bool flipZ /*= false*/,
bool farAtInfinity /*= false*/) {
if (!flipZ && farAtInfinity) {
// OVR_ASSERT_M(false, "Cannot push Far Clip to Infinity when Z-order is not flipped");
// Assertion disabled because this code no longer has access to LibOVRKernel assertion
// functionality.
farAtInfinity = false;
}
float orthoHorizontalOffset = interpupillaryDistance * 0.5f / distanceFromCamera;
switch (eyeType) {
case StereoEye_Left:
break;
case StereoEye_Right:
orthoHorizontalOffset = -orthoHorizontalOffset;
break;
case StereoEye_Center:
orthoHorizontalOffset = 0.0f;
break;
default:
break;
}
// 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].
float orthoScaleX = 2.0f * tanHalfFovX / unitsX;
float orthoScaleY = 2.0f * tanHalfFovY / unitsY;
Matrix4f ortho;
ortho.M[0][0] = projection.M[0][0] * orthoScaleX;
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] * orthoScaleY; // Note sign flip (text rendering uses Y=down).
ortho.M[1][2] = 0.0f;
ortho.M[1][3] = -projection.M[1][2];
const float zDiff = zNear - zFar;
if (fabsf(zDiff) < 0.001f) {
ortho.M[2][0] = 0.0f;
ortho.M[2][1] = 0.0f;
ortho.M[2][2] = 0.0f;
ortho.M[2][3] = flipZ ? zNear : zFar;
} else {
ortho.M[2][0] = 0.0f;
ortho.M[2][1] = 0.0f;
if (farAtInfinity) {
ortho.M[2][2] = 0.0f;
ortho.M[2][3] = zNear;
} else if (zDiff != 0.0f) {
ortho.M[2][2] = (flipZ ? zNear : zFar) / zDiff;
ortho.M[2][3] = ((flipZ ? -zFar : zFar) * zNear) / zDiff;
}
}
// 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;
}
} // namespace OVR

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,53 @@
/************************************************************************************
Filename : OVR_Alg.cpp
Content : Static lookup tables for Alg functions
Created : September 19, 2012
Notes :
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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 uint8_t 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 uint8_t 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};
} // namespace Alg
} // namespace OVR

View File

@ -0,0 +1,854 @@
/************************************************************************************
Filename : OVR_Array.h
Content : Template implementation for Array
Created : September 19, 2012
Notes :
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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) {}
size_t GetMinCapacity() const {
return 0;
}
size_t GetGranularity() const {
return 4;
}
bool NeverShrinking() const {
return 1;
}
size_t GetCapacity() const {
return Capacity;
}
void SetCapacity(size_t capacity) {
Capacity = capacity;
}
private:
size_t 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) {}
size_t GetMinCapacity() const {
return MinCapacity;
}
size_t GetGranularity() const {
return Granularity;
}
bool NeverShrinking() const {
return NeverShrink;
}
size_t GetCapacity() const {
return Capacity;
}
void SetCapacity(size_t capacity) {
Capacity = capacity;
}
private:
size_t 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() {
if (Data) {
Allocator::DestructArray(Data, Size);
Allocator::Free(Data);
}
}
size_t GetCapacity() const {
return Policy.GetCapacity();
}
void ClearAndRelease() {
if (Data) {
Allocator::DestructArray(Data, Size);
Allocator::Free(Data);
Data = 0;
}
Size = 0;
Policy.SetCapacity(0);
}
void Reserve(size_t 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 {
size_t 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);
size_t 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(size_t newSize) {
size_t 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;
size_t 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(size_t size) : BaseType() {
Resize(size);
}
ArrayData(const SelfType& a) : BaseType(a.Policy) {
Append(a.Data, a.Size);
}
void Resize(size_t newSize) {
size_t 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);
OVR_ASSERT(this->Data != NULL);
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[], size_t count) {
if (count) {
size_t 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, size_t size) : BaseType(), DefaultValue(defval) {
Resize(size);
}
ArrayDataCC(const SelfType& a) : BaseType(a.Policy), DefaultValue(a.DefaultValue) {
Append(a.Data, a.Size);
}
void Resize(size_t newSize) {
size_t 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[], size_t count) {
if (count) {
size_t 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(size_t size) : Data(size) {}
ArrayBase(const SelfType& a) : Data(a.Data) {}
ArrayBase(const ValueType& defval) : Data(defval) {}
ArrayBase(const ValueType& defval, size_t 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();
}
size_t GetSize() const {
return Data.Size;
}
int GetSizeI() const {
return (int)Data.Size;
}
bool IsEmpty() const {
return Data.Size == 0;
}
size_t GetCapacity() const {
return Data.GetCapacity();
}
size_t GetNumBytes() const {
return Data.GetCapacity() * sizeof(ValueType);
}
void ClearAndRelease() {
Data.ClearAndRelease();
}
void Clear() {
Data.Resize(0);
}
void Resize(size_t newSize) {
Data.Resize(newSize);
}
// Reserve can only increase the capacity
void Reserve(size_t newCapacity) {
if (newCapacity > Data.GetCapacity())
Data.Reserve(newCapacity);
}
// Basic access.
ValueType& At(size_t index) {
OVR_ASSERT(
(Data.Data) &&
(index < Data.Size)); // Asserting that Data.Data is valid helps static analysis tools.
return Data.Data[index];
}
const ValueType& At(size_t index) const {
OVR_ASSERT((Data.Data) && (index < Data.Size));
return Data.Data[index];
}
ValueType ValueAt(size_t index) const {
OVR_ASSERT((Data.Data) && (index < Data.Size));
return Data.Data[index];
}
// Basic access.
ValueType& operator[](size_t index) {
OVR_ASSERT((Data.Data) && (index < Data.Size));
return Data.Data[index];
}
const ValueType& operator[](size_t index) const {
OVR_ASSERT((Data.Data) && (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(size_t count = 1) {
OVR_ASSERT(Data.Size >= count);
Data.Resize(Data.Size - count);
}
ValueType& PushDefault() {
Data.PushBack(ValueType());
return Back();
}
ValueType Pop() {
OVR_ASSERT((Data.Data) && (Data.Size > 0));
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());
OVR_ASSERT((Data.Data != NULL) || (Data.Size == 0));
for (size_t i = 0; i < Data.Size; i++) {
*(Data.Data + i) = a[i];
}
return *this;
}
// Removing multiple elements from the array.
void RemoveMultipleAt(size_t index, size_t 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(size_t index) {
OVR_ASSERT((Data.Data) && (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(size_t index) {
OVR_ASSERT((Data.Data) && (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 size_t 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(size_t 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(size_t index, size_t 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 (size_t 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[], size_t count) {
Data.Append(other, count);
}
class Iterator {
SelfType* pArray;
intptr_t CurIndex;
public:
Iterator() : pArray(0), CurIndex(-1) {}
Iterator(SelfType* parr, intptr_t 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 < (intptr_t)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);
}
intptr_t 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);
}
intptr_t GetIndex() const {
return CurIndex;
}
};
Iterator Begin() {
return Iterator(this);
}
Iterator End() {
return Iterator(this, (intptr_t)GetSize());
}
Iterator Last() {
return Iterator(this, (intptr_t)GetSize() - 1);
}
class ConstIterator {
const SelfType* pArray;
intptr_t CurIndex;
public:
ConstIterator() : pArray(0), CurIndex(-1) {}
ConstIterator(const SelfType* parr, intptr_t 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);
}
intptr_t 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();
}
intptr_t GetIndex() const {
return CurIndex;
}
};
ConstIterator Begin() const {
return ConstIterator(this);
}
ConstIterator End() const {
return ConstIterator(this, (intptr_t)GetSize());
}
ConstIterator Last() const {
return ConstIterator(this, (intptr_t)GetSize() - 1);
}
// C++11 ranged-based for loop support.
Iterator begin() {
return Begin();
}
Iterator end() {
return End();
}
ConstIterator begin() const {
return Begin();
}
ConstIterator end() const {
return End();
}
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() {}
explicit Array(size_t 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() {}
explicit ArrayPOD(size_t 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() {}
explicit ArrayCPP(size_t 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, size_t 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;
}
};
} // namespace OVR
#endif

View File

@ -0,0 +1,134 @@
/************************************************************************************
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 (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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_MS) && defined(NTDDI_WIN8) && (NTDDI_VERSION >= NTDDI_WIN8)
#include <synchapi.h>
#endif
namespace OVR {
// ***** Windows Lock implementation
#if defined(OVR_OS_MS)
// ***** 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, (DWORD)spinCount, OVR_DEBUG_SELECT(NULL, CRITICAL_SECTION_NO_DEBUG_INFO));
#else
::InitializeCriticalSectionAndSpinCount(
&cs, (DWORD)spinCount); // This is available with WindowsXP+.
#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, oldUseCount_tmp;
do {
oldUseCount = UseCount;
if (oldUseCount == (int)LockInitMarker)
continue;
if (oldUseCount == 0) {
// Initialize marker
int tmp_zero = 0;
int tmp_LockInitMarker = LockInitMarker;
if (UseCount.compare_exchange_strong(tmp_zero, LockInitMarker)) {
Construct<Lock>(Buffer);
do {
} while (UseCount.compare_exchange_weak(tmp_LockInitMarker, 1));
return toLock();
}
continue;
}
oldUseCount_tmp = oldUseCount;
} while (
!UseCount.compare_exchange_weak(oldUseCount_tmp, oldUseCount + 1, std::memory_order_relaxed));
return toLock();
}
void SharedLock::ReleaseLock(Lock* plock) {
OVR_UNUSED(plock);
OVR_ASSERT(plock == toLock());
int oldUseCount, oldUseCount_tmp;
do {
oldUseCount = UseCount;
OVR_ASSERT(oldUseCount != (int)LockInitMarker);
if (oldUseCount == 1) {
// Initialize marker
int tmp_one = 1;
int tmp_LockInitMarker = LockInitMarker;
if (UseCount.compare_exchange_strong(tmp_one, LockInitMarker)) {
Destruct<Lock>(toLock());
do {
} while (!UseCount.compare_exchange_weak(tmp_LockInitMarker, 0));
return;
}
continue;
}
oldUseCount_tmp = oldUseCount;
} while (
!UseCount.compare_exchange_weak(oldUseCount_tmp, oldUseCount - 1, std::memory_order_relaxed));
}
} // namespace OVR
#endif // OVR_ENABLE_THREADS

View File

@ -0,0 +1,216 @@
/************************************************************************************
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 (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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 <atomic>
// Include System thread functionality.
#if defined(OVR_OS_MS) && !defined(OVR_OS_MS_MOBILE)
#include "OVR_Win32_IncludeWindows.h"
#else
#include <pthread.h>
#endif
namespace OVR {
//-----------------------------------------------------------------------------------
// ***** Lock
// Lock is a simplest and most efficient mutual-exclusion lock class.
// Unlike Mutex, it cannot be waited on.
class Lock {
#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_MS)
CRITICAL_SECTION cs;
public:
Lock(unsigned spinCount = 10000); // Mutexes with non-zero spin counts usually result in better
// performance.
~Lock();
// Locking functions.
inline void DoLock() {
::EnterCriticalSection(&cs);
}
inline void Unlock() {
::LeaveCriticalSection(&cs);
}
inline bool TryLock() {
return (::TryEnterCriticalSection(&cs) == TRUE);
}
#else
pthread_mutex_t mutex;
public:
static pthread_mutexattr_t RecursiveAttr;
static bool RecursiveAttrInit;
Lock(unsigned spinCount = 0) // To do: Support spin count, probably via a custom lock
// implementation.
{
OVR_UNUSED(spinCount);
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);
}
inline bool TryLock() {
return (pthread_mutex_trylock(&mutex) == 0);
}
#endif // OVR_ENABLE_THREDS
public:
// Locker class, used for automatic locking
class Locker {
Lock* pLock;
public:
Locker(Lock* plock) {
pLock = plock;
if (plock)
pLock->DoLock();
}
~Locker() {
Release();
}
void Release() {
if (pLock)
pLock->Unlock();
pLock = nullptr;
}
};
// Unlocker class, used for automatic unlocking
class Unlocker {
// OVR_NON_COPYABLE(Unlocker);
Lock* mLock;
public:
Unlocker(Lock* lock) : mLock(lock) {}
~Unlocker() {
Release();
}
void Release() {
if (mLock)
mLock->Unlock();
mLock = nullptr;
}
};
};
//-------------------------------------------------------------------------------------
// 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.
std::atomic<int> UseCount;
uint64_t Buffer[(sizeof(Lock) + sizeof(uint64_t) - 1) / sizeof(uint64_t)];
};
//-------------------------------------------------------------------------------------
// Thin locking wrapper around data
template <class T>
class LockedData {
public:
LockedData(Lock& lock) : TheLock(lock) {}
LockedData& operator=(const LockedData& /*rhs*/) {
OVR_ASSERT(false);
return *this;
}
T Get() {
Lock::Locker locker(&TheLock);
return Instance;
}
void Set(const T& value) {
Lock::Locker locker(&TheLock);
Instance = value;
}
// Returns true if the value has changed.
// Returns false if the value has not changed.
bool GetIfChanged(T& value) {
Lock::Locker locker(&TheLock);
if (value != Instance) {
value = Instance;
return true;
}
return false;
}
protected:
T Instance;
Lock& TheLock;
};
} // namespace OVR
#endif

View File

@ -0,0 +1,42 @@
/************************************************************************************
PublicHeader: Kernel
Filename : OVR_Callbacks.cpp
Content : Callback library
Created : Nov 17, 2014
Author : Chris Taylor
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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_Callbacks.h"
namespace OVR {
// Global emitter lock
//
// Add/remove operations on callbacks happen infrequently, and are already fairly
// serialized in order of construction by design. Therefore contention for this
// lock between call()/shutdown() is the main concern and is also rare.
Lock* CallbackEmitterBase::GetEmitterLock() {
static Lock lock;
return &lock;
}
} // namespace OVR

View File

@ -0,0 +1,282 @@
/************************************************************************************
PublicHeader: Kernel
Filename : OVR_Callbacks.h
Content : Callback library
Created : June 20, 2014
Author : Chris Taylor
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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_Callbacks_h
#define OVR_Callbacks_h
#include "OVR_CallbacksInternal.h"
#include "OVR_String.h" // For CallbackHash
#include "OVR_Hash.h" // For CallbackHash
namespace OVR {
//-----------------------------------------------------------------------------
// CallbackEmitter
//
// Emitter of callbacks.
// Thread-safety: All public members may be safely called concurrently.
template <class DelegateT>
class CallbackEmitter : public NewOverrideBase {
public:
CallbackEmitter();
~CallbackEmitter();
// Add a listener.
bool AddListener(CallbackListener<DelegateT>* listener);
// Get the current number of listeners. Note that this can change as other threads
// add listeners to the emitter.
int GetListenerCount() const;
bool HasListeners() const {
return Emitter->HasListeners();
}
void Call() {
Emitter->Call();
}
template <class Param1>
void Call(Param1* p1) {
Emitter->Call(p1);
}
template <class Param1>
void Call(Param1& p1) {
Emitter->Call(p1);
}
template <class Param1, class Param2>
void Call(Param1* p1, Param2* p2) {
Emitter->Call(p1, p2);
}
template <class Param1, class Param2>
void Call(Param1& p1, Param2& p2) {
Emitter->Call(p1, p2);
}
template <class Param1, class Param2, class Param3>
void Call(Param1* p1, Param2* p2, Param3* p3) {
Emitter->Call(p1, p2, p3);
}
template <class Param1, class Param2, class Param3>
void Call(Param1& p1, Param2& p2, Param3& p3) {
Emitter->Call(p1, p2, p3);
}
// Remove all listeners and prevent further listeners from being added.
void Shutdown();
protected:
Ptr<FloatingCallbackEmitter<DelegateT>> Emitter;
};
//-----------------------------------------------------------------------------
// CallbackListener
//
// Listener for callbacks.
// Thread-safety: Operations on a listener are not thread-safe.
// The listener may only listen to *one emitter* at a time.
template <class DelegateT>
class CallbackListener : public NewOverrideBase {
friend class CallbackEmitter<DelegateT>;
public:
CallbackListener();
~CallbackListener();
// Stop listening to callbacks.
// And set a new handler for callbacks.
void SetHandler(DelegateT handler);
// Is listening to an emitter at this instant?
// If the Emitter has shutdown, then this may inaccurately return true.
bool IsListening() const;
// Stops listening to callbacks.
void Cancel();
protected:
/// Internal data:
// Reference to the associated listener.
Ptr<FloatingCallbackListener<DelegateT>> FloatingListener;
// Reference to the associated emitter.
Ptr<FloatingCallbackEmitter<DelegateT>> FloatingEmitter;
DelegateT Handler;
};
//-----------------------------------------------------------------------------
// Template Implementation: CallbackEmitter
template <class DelegateT>
CallbackEmitter<DelegateT>::CallbackEmitter() {
Emitter = *new FloatingCallbackEmitter<DelegateT>;
}
template <class DelegateT>
CallbackEmitter<DelegateT>::~CallbackEmitter() {
Emitter->Shutdown();
// Emitter goes out of scope here.
}
template <class DelegateT>
bool CallbackEmitter<DelegateT>::AddListener(CallbackListener<DelegateT>* listener) {
// The listener object can only be attached to one emitter at a time.
// The caller should explicitly Cancel() a listener before listening
// to a new emitter, even if it is the same emitter.
OVR_ASSERT(!listener->FloatingEmitter && !listener->FloatingListener);
if (listener->FloatingEmitter || listener->FloatingListener) {
// Cancel any previous listening
listener->Cancel();
}
// Set the floating listener and emitter
listener->FloatingListener = *new FloatingCallbackListener<DelegateT>(listener->Handler);
listener->FloatingEmitter = Emitter.GetPtr();
// The remaining input checks are performed inside.
return Emitter->AddListener(listener->FloatingListener);
}
template <class DelegateT>
int CallbackEmitter<DelegateT>::GetListenerCount() const {
return Emitter->Listeners.GetSizeI();
}
template <class DelegateT>
void CallbackEmitter<DelegateT>::Shutdown() {
Emitter->Shutdown();
}
//-----------------------------------------------------------------------------
// Template Implementation: CallbackListener
template <class DelegateT>
CallbackListener<DelegateT>::CallbackListener() {
// Listener is null until a handler is set.
}
template <class DelegateT>
CallbackListener<DelegateT>::~CallbackListener() {
Cancel();
}
template <class DelegateT>
void CallbackListener<DelegateT>::Cancel() {
if (FloatingListener) {
FloatingListener->EnterCancelState();
}
if (FloatingEmitter) {
if (FloatingListener) {
FloatingEmitter->OnListenerCancel(FloatingListener);
}
}
// FloatingEmitter goes out of scope here.
FloatingEmitter = nullptr;
// FloatingListener goes out of scope here.
FloatingListener = nullptr;
}
template <class DelegateT>
void CallbackListener<DelegateT>::SetHandler(DelegateT handler) {
Cancel();
Handler = handler;
}
template <class DelegateT>
bool CallbackListener<DelegateT>::IsListening() const {
if (!FloatingListener.GetPtr()) {
return false;
}
return FloatingListener->IsValid();
}
//-----------------------------------------------------------------------------
// CallbackHash
//
// A hash containing CallbackEmitters
template <class DelegateT>
class CallbackHash : public NewOverrideBase {
typedef Hash<String, CallbackEmitter<DelegateT>*, String::HashFunctor> HashTable;
public:
~CallbackHash() {
Clear();
}
void Clear() {
for (auto ii = Table.Begin(); ii != Table.End(); ++ii) {
delete ii->Second;
}
Table.Clear();
}
CallbackEmitter<DelegateT>* GetKey(String key) {
CallbackEmitter<DelegateT>** emitter = Table.Get(key);
if (emitter) {
return *emitter;
}
return nullptr;
}
void AddListener(String key, CallbackListener<DelegateT>* listener) {
CallbackEmitter<DelegateT>** pEmitter = Table.Get(key);
CallbackEmitter<DelegateT>* emitter = nullptr;
if (!pEmitter) {
emitter = new CallbackEmitter<DelegateT>;
Table.Add(key, emitter);
} else {
emitter = *pEmitter;
}
emitter->AddListener(listener);
}
void RemoveKey(String key) {
CallbackEmitter<DelegateT>** emitter = Table.Get(key);
if (emitter) {
delete *emitter;
Table.Remove(key);
}
}
protected:
HashTable Table; // Hash table
};
} // namespace OVR
#endif // OVR_Callbacks_h

View File

@ -0,0 +1,338 @@
/************************************************************************************
PublicHeader: Kernel
Filename : OVR_CallbacksInternal.h
Content : Callback library
Created : Nov 11, 2014
Author : Chris Taylor
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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_CallbacksInternal_h
#define OVR_CallbacksInternal_h
#include "OVR_Atomic.h"
#include "OVR_RefCount.h"
#include "OVR_Delegates.h"
#include "OVR_Array.h"
#if !defined(OVR_CC_MSVC) || (OVR_CC_VERSION > 1600) // Newer than VS2010
#include <atomic>
#endif
namespace OVR {
template <class DelegateT>
class FloatingCallbackEmitter; // Floating emitter object
template <class DelegateT>
class CallbackEmitter;
template <class DelegateT>
class FloatingCallbackListener; // Floating listener object
template <class DelegateT>
class CallbackListener;
//-----------------------------------------------------------------------------
// FloatingCallbackEmitter
//
// The Call() function is not thread-safe.
// TBD: Should we add a thread-safe Call() option to constructor?
class CallbackEmitterBase {
protected:
static Lock* GetEmitterLock();
};
template <class DelegateT>
class FloatingCallbackEmitter : public CallbackEmitterBase,
public RefCountBase<FloatingCallbackEmitter<DelegateT>> {
friend class CallbackEmitter<DelegateT>;
FloatingCallbackEmitter()
: IsShutdown(false),
#if !defined(OVR_CC_MSVC) || (OVR_CC_VERSION > 1600) // Newer than VS2010
ListenersExist(false),
#endif
DirtyListenersCache(0) {
}
public:
typedef Array<Ptr<FloatingCallbackListener<DelegateT>>> ListenerPtrArray;
~FloatingCallbackEmitter() {
OVR_ASSERT(Listeners.GetSizeI() == 0);
// ListenersCache will be emptied here.
}
bool AddListener(FloatingCallbackListener<DelegateT>* listener);
bool HasListeners() const {
#if !defined(OVR_CC_MSVC) || (OVR_CC_VERSION > 1600) // Newer than VS2010
return ListenersExist.load(std::memory_order_relaxed);
#else
// This code still has a data race
return (Listeners.GetSizeI() > 0);
#endif
}
void Shutdown();
// Called from the listener object as it is transitioning to canceled state.
// The listener's mutex is not held during this call.
void OnListenerCancel(FloatingCallbackListener<DelegateT>* listener);
public:
void Call();
template <class Param1>
void Call(Param1* p1);
template <class Param1>
void Call(Param1& p1);
template <class Param1, class Param2>
void Call(Param1* p1, Param2* p2);
template <class Param1, class Param2>
void Call(Param1& p1, Param2& p2);
template <class Param1, class Param2, class Param3>
void Call(Param1* p1, Param2* p2, Param3* p3);
template <class Param1, class Param2, class Param3>
void Call(Param1& p1, Param2& p2, Param3& p3);
protected:
// Is the emitter shut down? This prevents more listeners from being added during shutdown.
bool IsShutdown;
// Array of added listeners.
ListenerPtrArray Listeners;
#if !defined(OVR_CC_MSVC) || (OVR_CC_VERSION > 1600) // Newer than VS2010
std::atomic<bool> ListenersExist;
#endif
// Is the cache dirty? This avoids locking and memory allocation in steady state.
std::atomic<uint32_t> DirtyListenersCache = {0};
// Cache of listeners used by the Call() function.
ListenerPtrArray ListenersCacheForCalls;
// Update the ListenersCache array in response to an insertion or removal.
// This is how AddListener() insertions get rolled into the listeners array.
// This is how RemoveListener() removals get purged from the cache.
void updateListenersCache() {
if (DirtyListenersCache != 0) {
Lock::Locker locker(GetEmitterLock());
// TBD: Should memory allocation be further reduced here?
ListenersCacheForCalls = Listeners;
DirtyListenersCache = 0;
}
}
// Without holding a lock, find and remove the given listener from the array of listeners.
void noLockFindAndRemoveListener(FloatingCallbackListener<DelegateT>* listener) {
const int count = Listeners.GetSizeI();
for (int i = 0; i < count; ++i) {
if (Listeners[i] == listener) {
Listeners.RemoveAt(i);
// After removing it from the array, set the dirty flag.
// Note: Because the flag is atomic, a portable memory fence is implied.
DirtyListenersCache = 1;
break;
}
}
#if !defined(OVR_CC_MSVC) || (OVR_CC_VERSION > 1600) // Newer than VS2010
if (Listeners.GetSizeI() < 1) {
ListenersExist.store(false, std::memory_order_relaxed);
}
#endif
}
};
//-----------------------------------------------------------------------------
// FloatingCallbackListener
//
// Internal implementation class for the CallbackListener.
// This can only be associated with one CallbackListener object for its lifetime.
template <class DelegateT>
class FloatingCallbackListener : public RefCountBase<FloatingCallbackListener<DelegateT>> {
public:
FloatingCallbackListener(DelegateT handler);
~FloatingCallbackListener();
void EnterCancelState();
bool IsValid() const {
return Handler.IsValid();
}
// TBD: Should these be binned to reduce the lock count?
// Boost does not do that. And I am worried about deadlocks when misused.
mutable Lock ListenerLock;
// Handler function
DelegateT Handler;
};
//-----------------------------------------------------------------------------
// Template Implementation: FloatingCallbackEmitter
template <class DelegateT>
bool FloatingCallbackEmitter<DelegateT>::AddListener(
FloatingCallbackListener<DelegateT>* listener) {
Lock::Locker locker(GetEmitterLock());
if (IsShutdown) {
return false;
}
// Add the listener to our list
Listeners.PushBack(listener);
// After adding it to the array, set the dirty flag.
// Note: Because the flag is atomic, a portable memory fence is implied.
DirtyListenersCache = 1;
#if !defined(OVR_CC_MSVC) || (OVR_CC_VERSION > 1600) // Newer than VS2010
ListenersExist.store(true, std::memory_order_relaxed);
#endif
return true;
}
// Called from the listener object as it is transitioning to canceled state.
// The listener's mutex is not held during this call.
template <class DelegateT>
void FloatingCallbackEmitter<DelegateT>::OnListenerCancel(
FloatingCallbackListener<DelegateT>* listener) {
Lock::Locker locker(GetEmitterLock());
// If not shut down,
// Note that if it is shut down then there will be no listeners in the array.
if (!IsShutdown) {
// Remove it.
noLockFindAndRemoveListener(listener);
}
}
template <class DelegateT>
void FloatingCallbackEmitter<DelegateT>::Shutdown() {
Lock::Locker locker(GetEmitterLock());
IsShutdown = true;
Listeners.ClearAndRelease();
// Note: Because the flag is atomic, a portable memory fence is implied.
DirtyListenersCache = 1;
#if !defined(OVR_CC_MSVC) || (OVR_CC_VERSION > 1600) // Newer than VS2010
ListenersExist.store(false, std::memory_order_relaxed);
#endif
}
//-----------------------------------------------------------------------------
// Call function
//
// (1) Update the cache of listener references, if it has changed.
// (2) For each listener,
// (a) Hold ListenerLock.
// (b) If listener handler is valid, call the handler.
#define OVR_EMITTER_CALL_BODY(params) \
updateListenersCache(); \
if (IsShutdown) \
return; /* Pure optimization. It is fine if this races. */ \
const int count = ListenersCacheForCalls.GetSizeI(); \
for (int i = 0; i < count; ++i) { \
Lock::Locker locker(&ListenersCacheForCalls[i]->ListenerLock); \
if (ListenersCacheForCalls[i]->Handler.IsValid()) { \
ListenersCacheForCalls[i]->Handler params; /* Using a macro for this line. */ \
} \
}
template <class DelegateT>
void FloatingCallbackEmitter<DelegateT>::Call() {
OVR_EMITTER_CALL_BODY(())
}
template <class DelegateT>
template <class Param1>
void FloatingCallbackEmitter<DelegateT>::Call(Param1* p1) {
OVR_EMITTER_CALL_BODY((p1))
}
template <class DelegateT>
template <class Param1>
void FloatingCallbackEmitter<DelegateT>::Call(Param1& p1) {
OVR_EMITTER_CALL_BODY((p1))
}
template <class DelegateT>
template <class Param1, class Param2>
void FloatingCallbackEmitter<DelegateT>::Call(Param1* p1, Param2* p2) {
OVR_EMITTER_CALL_BODY((p1, p2))
}
template <class DelegateT>
template <class Param1, class Param2>
void FloatingCallbackEmitter<DelegateT>::Call(Param1& p1, Param2& p2) {
OVR_EMITTER_CALL_BODY((p1, p2))
}
template <class DelegateT>
template <class Param1, class Param2, class Param3>
void FloatingCallbackEmitter<DelegateT>::Call(Param1* p1, Param2* p2, Param3* p3) {
OVR_EMITTER_CALL_BODY((p1, p2, p3))
}
template <class DelegateT>
template <class Param1, class Param2, class Param3>
void FloatingCallbackEmitter<DelegateT>::Call(Param1& p1, Param2& p2, Param3& p3) {
OVR_EMITTER_CALL_BODY((p1, p2, p3))
}
#undef OVR_EMITTER_CALL_BODY
//-----------------------------------------------------------------------------
// Template Implementation: FloatingCallbackListener
template <class DelegateT>
FloatingCallbackListener<DelegateT>::FloatingCallbackListener(DelegateT handler)
: Handler(handler) {
OVR_ASSERT(Handler.IsValid());
}
template <class DelegateT>
FloatingCallbackListener<DelegateT>::~FloatingCallbackListener() {
OVR_ASSERT(!Handler.IsValid());
}
template <class DelegateT>
void FloatingCallbackListener<DelegateT>::EnterCancelState() {
ListenerLock.DoLock();
Handler.Invalidate();
ListenerLock.Unlock();
}
} // namespace OVR
#endif // OVR_CallbacksInternal_h

View File

@ -0,0 +1,68 @@
/************************************************************************************
Filename : OVR_Color.h
Content : Contains color struct.
Created : February 7, 2013
Notes :
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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 {
uint8_t R, G, B, A;
Color() {
#if defined(OVR_BUILD_DEBUG)
R = G = B = A = 0;
#endif
}
// 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;
}
};
} // namespace OVR
#endif

View File

@ -0,0 +1,244 @@
/************************************************************************************
Filename : OVR_ContainerAllocator.h
Content : Template allocators and constructors for containers.
Created : September 19, 2012
Notes :
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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(size_t size) {
return OVR_ALLOC(size);
}
static void* Realloc(void* p, size_t 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*, size_t) {}
static void ConstructArray(void* p, size_t count, const T& source) {
uint8_t* pdata = (uint8_t*)p;
for (size_t i = 0; i < count; ++i, pdata += sizeof(T))
*(T*)pdata = source;
}
static void ConstructArray(void* p, size_t count, const T* psource) {
memcpy(p, psource, sizeof(T) * count);
}
static void Destruct(T*) {}
static void DestructArray(T*, size_t) {}
static void CopyArrayForward(T* dst, const T* src, size_t count) {
memmove(dst, src, count * sizeof(T));
}
static void CopyArrayBackward(T* dst, const T* src, size_t 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, size_t count) {
uint8_t* pdata = (uint8_t*)p;
for (size_t i = 0; i < count; ++i, pdata += sizeof(T))
Construct(pdata);
}
static void ConstructArray(void* p, size_t count, const T& source) {
uint8_t* pdata = (uint8_t*)p;
for (size_t i = 0; i < count; ++i, pdata += sizeof(T))
Construct(pdata, source);
}
static void ConstructArray(void* p, size_t count, const T* psource) {
uint8_t* pdata = (uint8_t*)p;
for (size_t 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, size_t count) {
for (size_t i = 0; i < count; ++i, ++p)
p->~T();
}
static void CopyArrayForward(T* dst, const T* src, size_t count) {
memmove(dst, src, count * sizeof(T));
}
static void CopyArrayBackward(T* dst, const T* src, size_t 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, size_t count) {
uint8_t* pdata = (uint8_t*)p;
for (size_t i = 0; i < count; ++i, pdata += sizeof(T))
Construct(pdata);
}
static void ConstructArray(void* p, size_t count, const T& source) {
uint8_t* pdata = (uint8_t*)p;
for (size_t i = 0; i < count; ++i, pdata += sizeof(T))
Construct(pdata, source);
}
static void ConstructArray(void* p, size_t count, const T* psource) {
uint8_t* pdata = (uint8_t*)p;
for (size_t 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, size_t count) {
for (size_t i = 0; i < count; ++i, ++p)
p->~T();
}
static void CopyArrayForward(T* dst, const T* src, size_t count) {
for (size_t i = 0; i < count; ++i)
dst[i] = src[i];
}
static void CopyArrayBackward(T* dst, const T* src, size_t count) {
for (size_t 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> {};
} // namespace OVR
#endif

View File

@ -0,0 +1,87 @@
/************************************************************************************
Filename : OVR_DLLHelper.h
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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.
************************************************************************************/
#pragma once
#ifdef _WIN32
#include <Windows.h>
#include <type_traits>
namespace OVR {
///////////////////////////////////////////////////////////////////////////////////////////////////
// Example usage
//
// Write one of these for each of the modules (DLLs) you want to use functions from.
// The following class can be safely declared at global scope.
// class Kernel32API {
// public:
// decltype(GetModuleFileNameA)* getModuleFileNameA = dllHelper.Load("GetModuleFileNameA");
//
// protected:
// DllHelper dllHelper{"Kernel32.dll"};
// };
//
// Use the class declared above:
// void main() {
// Kernel32API kernel32Api;
//
// if(kernel32Api.getModuleFileNameA)
// kernel32Api.getModuleFileNameA(NULL, path, sizeof(path));
// }
///////////////////////////////////////////////////////////////////////////////////////////////////
// DllHelper instances can be declared at global scope in most cases.
class DllHelper {
public:
// Example moduleFileName: "kernel32.dll"
explicit DllHelper(const char* moduleFileName) : moduleHandle(::LoadLibraryA(moduleFileName)) {}
~DllHelper() {
::FreeLibrary(moduleHandle);
}
class ProcPtr {
public:
explicit ProcPtr(FARPROC ptr) : procPtr(ptr) {}
template <typename T, typename = std::enable_if_t<std::is_function_v<T>>>
operator T*() const {
return reinterpret_cast<T*>(procPtr);
}
private:
FARPROC procPtr;
};
// Example proc name: "GetModuleFileName"
ProcPtr Load(const char* procName) const {
return ProcPtr(GetProcAddress(moduleHandle, procName));
}
protected:
HMODULE moduleHandle;
};
} // namespace OVR
#endif // _WIN32

View File

@ -0,0 +1,817 @@
/************************************************************************************
Filename : OVR_DebugHelp.h
Content : Platform-independent exception handling interface
Created : October 6, 2014
Copyright : Copyright 2014 Oculus VR, LLC. 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 OVR_DebugHelp_h
#define OVR_DebugHelp_h
#include "OVR_Types.h"
#include "OVR_String.h"
#include "OVR_Threads.h"
#include "OVR_Atomic.h"
#include "OVR_Nullptr.h"
#include "OVR_System.h"
#include <stdio.h>
#include <time.h>
#if defined(OVR_OS_WIN32) || defined(OVR_OS_WIN64)
#include "OVR_Win32_IncludeWindows.h"
#elif defined(OVR_OS_APPLE)
#include <pthread.h>
#include <mach/thread_status.h>
#include <mach/mach_types.h>
extern "C" void* MachHandlerThreadFunctionStatic(void*);
extern "C" int catch_mach_exception_raise_state_identity_OVR(
mach_port_t,
mach_port_t,
mach_port_t,
exception_type_t,
mach_exception_data_type_t*,
mach_msg_type_number_t,
int*,
thread_state_t,
mach_msg_type_number_t,
thread_state_t,
mach_msg_type_number_t*);
#elif defined(OVR_OS_LINUX)
#include <pthread.h>
#endif
OVR_DISABLE_MSVC_WARNING(4351) // new behavior: elements of array will be default initialized
namespace OVR {
// Thread identifiers
// typedef void* ThreadHandle; // Already defined by OVR Threads. Same as Windows thread
// handle, Unix pthread_t.
// typedef void* ThreadId; // Already defined by OVR Threads. Used by Windows as DWORD
// thread id, by Unix as pthread_t.
typedef uintptr_t ThreadSysId; // System thread identifier. Used by Windows the same as ThreadId
// (DWORD), thread_act_t on Mac/BSD, lwp id on Linux.
// Thread constants
// To do: Move to OVR Threads
#define OVR_THREADHANDLE_INVALID ((ThreadHandle*)nullptr)
#define OVR_THREADID_INVALID ((ThreadId*)nullptr)
#define OVR_THREADSYSID_INVALID ((uintptr_t)0)
OVR::ThreadSysId ConvertThreadHandleToThreadSysId(OVR::ThreadHandle threadHandle);
OVR::ThreadHandle ConvertThreadSysIdToThreadHandle(
OVR::ThreadSysId threadSysId); // The returned handle must be freed with FreeThreadHandle.
void FreeThreadHandle(OVR::ThreadHandle threadHandle); // Frees the handle returned by
// ConvertThreadSysIdToThreadHandle.
OVR::ThreadSysId GetCurrentThreadSysId();
void GetOSVersionName(char* versionName, size_t versionNameCapacity);
// CPUContext
#if defined(OVR_OS_MS)
typedef CONTEXT CPUContext;
#elif defined(OVR_OS_MAC)
struct CPUContext {
x86_thread_state_t threadState; // This works for both x86 and x64.
x86_float_state_t floatState;
x86_debug_state_t debugState;
x86_avx_state_t avxState;
x86_exception_state exceptionState;
CPUContext() {
memset(this, 0, sizeof(CPUContext));
}
};
#elif defined(OVR_OS_LINUX)
typedef int CPUContext; // To do.
#endif
// Force OVRIsDebuggerPresent to return false
void ForceDebuggerNotPresent();
// Allow debugger check to proceded as normal
void ClearDebuggerNotPresent();
// Tells if the current process appears to be running under a debugger. Does not attempt to
// detect the case of stealth debuggers (malware-related for example).
bool OVRIsDebuggerPresent();
// Exits the process with the given exit code.
#if !defined(OVR_NORETURN)
#if defined(OVR_CC_MSVC)
#define OVR_NORETURN __declspec(noreturn)
#else
#define OVR_NORETURN __attribute__((noreturn))
#endif
#endif
OVR_NORETURN void ExitProcess(intptr_t processReturnValue);
// Returns the instruction pointer of the caller for the position right after the call.
OVR_NO_INLINE void* GetInstructionAddress();
// Returns the instruction pointer of the call to the caller of this function.
// This is a macro defined as with the following C declaration:
// void* GetInstructionAddress();
#ifndef OVRGetReturnAddress
#if defined(_MSC_VER)
#define OVRGetReturnAddress() _ReturnAddress()
#else // GCC, clang
#define OVRGetReturnAddress() __builtin_return_address(0)
#endif
#endif
// Returns the stack base and limit addresses for the given thread, or for the current thread if the
// threadHandle is default.
// The stack limit is a value less than the stack base on most platforms, as stacks usually grow
// downward.
// Some platforms (e.g. Microsoft) have dynamically resizing stacks, in which case the stack limit
// reflects the current limit.
void GetThreadStackBounds(
void*& pStackBase,
void*& pStackLimit,
ThreadHandle threadHandle = OVR_THREADHANDLE_INVALID);
enum MemoryAccess { kMANone = 0x00, kMARead = 0x01, kMAWrite = 0x02, kMAExecute = 0x04 };
// Returns MemoryAccess flags. Returns kMAUnknown for unknown access.
int GetMemoryAccess(const void* p);
/// Used by KillCdeclFunction and RestoreCdeclFunction
///
struct SavedFunction {
void* Function;
uint8_t Size;
uint8_t Data[15];
void* FunctionImplementation; // Points to the original function, if possible to use it.
SavedFunction() : Function(nullptr), Size(0), FunctionImplementation(nullptr) {}
SavedFunction(int) {} // Intentionally uninitialized
};
/// Overwrites the implementation of a statically linked function with an implementation
/// that unilaterally returns the given int32_t value. Works regardless of the arguments
/// passed to that function by the caller. This version is specific to cdecl functions
/// as opposed to Microsoft stdcall functions. Requires the ability to use VirtualProtect
/// to change the code memory to be writable. Returns true if the operation was successful.
///
/// Since this function overwrites the memory of the existing function implementation,
/// it reequires the function to have at least enough bytes for this. If functionReturnValue
/// is zero then pFunction must be at least three bytes in size. If functionReturnValue is
/// non-zero then pFunction must be at least six bytes in size.
///
/// Example usage:
/// int __cdecl _CrtIsValidHeapPointer(const void* heapPtr);
///
/// void main(int, char*[]){
/// KillCdeclFunction(_CrtIsValidHeapPointer, TRUE); // Make _CrtIsValidHeapPointer always
/// return true.
/// }
///
bool KillCdeclFunction(
void* pFunction,
int32_t functionReturnValue,
SavedFunction* pSavedFunction = nullptr);
/// This version is for functions that return void. It causes them to immediately return.
///
/// Example usage:
/// void __cdecl _CrtCheckMemory();
///
/// void main(int, char*[]){
/// KillCdeclFunction(_CrtCheckMemory);
/// }
///
bool KillCdeclFunction(void* pFunction, SavedFunction* pSavedFunction = nullptr);
/// RedirectCdeclFunction
///
/// Upon success, pSavedFunction is modified to contain a saved copy of the modified bytes.
/// Upon failure, pSavedFunction is not modified.
/// RestoreCdeclFunction can be used to restore the bytes saved by pSavedFunction.
///
/// Example usage:
/// void* MyMalloc(size_t n)
/// { ... }
/// RedirectCdeclFunction(malloc, MyMalloc);
///
bool RedirectCdeclFunction(
void* pFunction,
const void* pDestFunction,
OVR::SavedFunction* pSavedFunction = nullptr);
/// Restores a function which was previously killed by KillCdeclFunction.
///
/// Example usage:
/// void main(int, char*[]){
/// SavedFunction savedFunction
/// KillCdeclFunction(_CrtCheckMemory, &savedFunction);
/// [...]
/// RestoreCdeclFunction(&savedFunction);
/// }
///
bool RestoreCdeclFunction(SavedFunction* pSavedFunction);
/// Smart class which temporarily kills a function and restores it upon scope completion.
///
/// Example usage:
/// void main(int, char*[]){
/// TempCdeclFunctionKill tempKill(_CrtIsValidHeapPointer, TRUE);
/// [...]
/// }
///
struct TempCdeclFunctionKill {
TempCdeclFunctionKill(void* pFunction, int32_t functionReturnValue)
: Success(false), FunctionPtr(nullptr), SavedFunctionData() {
Success = KillCdeclFunction(pFunction, functionReturnValue, &SavedFunctionData);
}
TempCdeclFunctionKill(void* pFunction)
: Success(false), FunctionPtr(nullptr), SavedFunctionData() {
Success = KillCdeclFunction(pFunction, &SavedFunctionData);
}
~TempCdeclFunctionKill() {
if (Success)
RestoreCdeclFunction(&SavedFunctionData);
}
bool Success;
void* FunctionPtr;
SavedFunction SavedFunctionData;
};
/// Class which implements copying the executable bytes of a function to a newly allocated page.
/// This is useful for when doing some kinds of function interception and overriding at runtime.
///
/// Example usage:
/// void main(int, char*[]){
/// CopiedFunction strlenCopy(strlen);
/// size_t n = strlen("test"); // Will execute through the newly allocated version of strlen.
/// }
///
class CopiedFunction {
public:
CopiedFunction(const void* pFunction = nullptr, size_t size = 0);
~CopiedFunction();
const void* Copy(const void* pFunction, size_t size);
void Free();
const void* GetFunction() const {
return Function;
}
protected:
const void* GetRealFunctionLocation(const void* pFunction);
void* Function;
};
// OVR_MAX_PATH
// Max file path length (for most uses).
// To do: move this to OVR_File.
#if !defined(OVR_MAX_PATH)
#if defined( \
OVR_OS_MS) // http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx
#define OVR_MAX_PATH \
260 // Windows can use paths longer than this in some cases (network paths, UNC paths).
#else
#define OVR_MAX_PATH 1024 // This isn't a strict limit on all Unix-based platforms.
#endif
#endif
// ModuleHandle
#if defined(OVR_OS_MS)
typedef void* ModuleHandle; // from LoadLibrary()
#elif defined(OVR_OS_APPLE) || defined(OVR_OS_UNIX)
typedef void* ModuleHandle; // from dlopen()
#endif
#define OVR_MODULEHANDLE_INVALID ((ModuleHandle*)nullptr)
// Module info constants
static const ModuleHandle kMIHandleInvalid = OVR_MODULEHANDLE_INVALID;
static const uint64_t kMIAddressInvalid = 0xffffffffffffffffull;
static const uint64_t kMISizeInvalid = 0xffffffffffffffffull;
static const int32_t kMILineNumberInvalid = -1;
static const int32_t kMIFunctionOffsetInvalid = -1;
static const uint64_t kMIBaseAddressInvalid = 0xffffffffffffffffull;
static const uint64_t kMIBaseAddressUnspecified = 0xffffffffffffffffull;
struct ModuleInfo {
ModuleHandle handle;
uint64_t baseAddress; // The actual runtime base address of the module. May be different from
// the base address specified in the debug symbol file, because the module may be placed at a
// different address on startup.
uint64_t size;
char filePath[OVR_MAX_PATH]; // UTF8 encoded
char name[32]; // UTF8 encoded
char type[8]; // Unix-specific. e.g. __TEXT
char permissions[8]; // Unix specific. e.g. "drwxr-xr-x"
ModuleInfo()
: handle(kMIHandleInvalid), baseAddress(kMIBaseAddressInvalid), size(0), filePath(), name() {}
};
// Refers to symbol info for an instruction address.
// Info includes function name, source code file/line, and source code itself.
struct SymbolInfo {
uint64_t address;
uint64_t size;
const ModuleInfo* pModuleInfo;
char filePath[OVR_MAX_PATH];
int32_t fileLineNumber;
char function[384]; // This is a fixed size because we need to use it during application
// exceptions.
int32_t functionOffset;
char sourceCode[1024]; // This is a string representing the code itself and not a file path to the
// code.
SymbolInfo()
: address(kMIAddressInvalid),
size(kMISizeInvalid),
pModuleInfo(nullptr),
filePath(),
fileLineNumber(kMILineNumberInvalid),
function(),
functionOffset(kMIFunctionOffsetInvalid),
sourceCode() {}
};
// Implements support for reading thread lists, module lists, backtraces, and backtrace symbols.
class SymbolLookup {
public:
SymbolLookup();
~SymbolLookup() = default;
// Every successful call to Initialize must be eventually matched by a call to Shutdown.
// Shutdown should be called if and only if Initialize returns true.
static bool Initialize();
static bool IsInitialized();
static void Shutdown();
void AddSourceCodeDirectory(const char* pDirectory);
// Should be disabled when within an exception handler.
void EnableMemoryAllocation(bool enabled);
// Refresh our view of the symbols and modules present within the current process.
bool Refresh();
// Retrieves the backtrace (call stack) of the given thread. There may be some per-platform
// restrictions on this.
// Returns the number written, which will be <= addressArrayCapacity.
// This may not work on some platforms unless stack frames are enabled.
// For Microsoft platforms the platformThreadContext is CONTEXT*.
// For Apple platforms the platformThreadContext is x86_thread_state_t* or arm_thread_state_t*.
// If threadSysIdHelp is non-zero, it may be used by the implementation to help produce a better
// backtrace.
static size_t GetBacktrace(
void* addressArray[],
size_t addressArrayCapacity,
size_t skipCount = 0,
void* platformThreadContext = nullptr,
OVR::ThreadSysId threadSysIdHelp = OVR_THREADSYSID_INVALID);
// Retrieves the backtrace for the given ThreadHandle.
// Returns the number written, which will be <= addressArrayCapacity.
static size_t GetBacktraceFromThreadHandle(
void* addressArray[],
size_t addressArrayCapacity,
size_t skipCount = 0,
OVR::ThreadHandle threadHandle = OVR_THREADHANDLE_INVALID);
// Retrieves the backtrace for the given ThreadSysId.
// Returns the number written, which will be <= addressArrayCapacity.
static size_t GetBacktraceFromThreadSysId(
void* addressArray[],
size_t addressArrayCapacity,
size_t skipCount = 0,
OVR::ThreadSysId threadSysId = OVR_THREADSYSID_INVALID);
enum ModuleSort { ModuleSortNone = 0, ModuleSortByAddress, ModuleSortByName };
// Gets a list of the modules (e.g. DLLs) present in the current process.
// Writes as many ModuleInfos as possible to pModuleInfoArray.
// Returns the required count of ModuleInfos, which will be > moduleInfoArrayCapacity if the
// capacity needs to be larger.
static size_t GetModuleInfoArray(
ModuleInfo* pModuleInfoArray,
size_t moduleInfoArrayCapacity,
ModuleSort moduleSort = ModuleSortNone);
// Retrieves a list of the current threads. Unless the process is paused the list is volatile.
// Returns the required capacity, which may be larger than threadArrayCapacity.
// Either array can be NULL to specify that it's not written to.
// For Windows the caller needs to CloseHandle the returned ThreadHandles. This can be done by
// calling DoneThreadList.
static size_t GetThreadList(
ThreadHandle* threadHandleArray,
ThreadSysId* threadSysIdArray,
size_t threadArrayCapacity);
// Frees any references to thread handles or ids returned by GetThreadList;
static void DoneThreadList(
ThreadHandle* threadHandleArray,
ThreadSysId* threadSysIdArray,
size_t threadArrayCount);
// Writes a given thread's callstack with symbols to the given output.
// It may not be safe to call this from an exception handler, as sOutput allocates memory.
bool ReportThreadCallstack(
OVR::String& sOutput,
size_t skipCount = 0,
ThreadSysId threadSysId = OVR_THREADSYSID_INVALID);
// Writes all thread's callstacks with symbols to the given output.
// It may not be safe to call this from an exception handler, as sOutput allocates memory.
bool ReportThreadCallstacks(OVR::String& sOutput, size_t skipCount = 0);
// Writes all loaded modules to the given output string.
// It may not be safe to call this from an exception handler, as sOutput allocates memory.
bool ReportModuleInformation(OVR::String& sOutput);
// Retrieves symbol info for the given address.
bool LookupSymbol(uint64_t address, SymbolInfo& symbolInfo);
bool LookupSymbols(uint64_t* addressArray, SymbolInfo* pSymbolInfoArray, size_t arraySize);
// The returned ModuleInfo points to an internal structure. This function assumes that the
// internal cached ModuleInfo array is valid. If modules are dynamically added or removed
// during runtime then the array may be partially out of date.
// May return NULL if there was no found module for the address.
const ModuleInfo* GetModuleInfoForAddress(uint64_t address);
const ModuleInfo& GetModuleInfoForCurrentModule();
protected:
bool RefreshModuleList();
protected:
// True by default. If true then we allow allocating memory (and as a
// result provide less information). This is useful for when in an
// exception handler.
bool AllowMemoryAllocation;
bool ModuleListUpdated;
// Cached list of modules we use. This is a fixed size because
// we need to use it during application exceptions.
ModuleInfo ModuleInfoArray[256];
size_t ModuleInfoArraySize;
// The ModuleInfo for the current module, which is often needed and so we make a member for it.
ModuleInfo currentModuleInfo;
};
// ExceptionInfo
// We need to be careful to avoid data types that can allocate memory while we are
// handling an exception, as the memory system may be corrupted at that point in time.
struct ExceptionInfo {
tm time; // GM time.
time_t timeVal; // GM time_t (seconds since 1970).
void* backtrace[64];
size_t backtraceCount;
ThreadHandle threadHandle; //
ThreadSysId threadSysId; //
char threadName[32]; // Cannot be an allocating String object.
void* pExceptionInstructionAddress;
void* pExceptionMemoryAddress;
CPUContext cpuContext;
char exceptionDescription[1024]; // Cannot be an allocating String object.
SymbolInfo symbolInfo; // SymbolInfo for the exception location.
#if defined(OVR_OS_MS)
EXCEPTION_RECORD exceptionRecord; // This is a Windows SDK struct.
#elif defined(OVR_OS_APPLE)
uint64_t exceptionType; // e.g. EXC_BAD_INSTRUCTION, EXC_BAD_ACCESS, etc.
uint32_t cpuExceptionId; // The x86/x64 CPU trap id.
uint32_t cpuExceptionIdError; // The x86/x64 CPU trap id extra info.
int64_t machExceptionData[4]; // Kernel exception code info.
int machExceptionDataCount; // Count of valid entries.
#endif
ExceptionInfo();
};
// Implments support for asynchronous exception handling and basic exception report generation.
// If you are implementing exception handling for a commercial application and want auto-uploading
// functionality you may want to consider using something like Google Breakpad. This exception
// handler
// is for in-application debug/diagnostic services, though it can write a report that has similar
// information to Breakpad or OS-provided reports such as Apple .crash files.
//
// Example usage:
// ExceptionHandler exceptionHandler;
//
// int main(int, char**)
// {
// exceptionHandler.Enable(true);
// exceptionHandler.SetExceptionListener(pSomeListener, 0); // Optional listener hook.
// }
//
class ExceptionHandler {
public:
ExceptionHandler();
~ExceptionHandler();
// Enables or disables handling by installing or uninstalling an exception handler.
// If you merely want to temporarily pause handling then it may be better to cause PauseHandling,
// as that's a lighter weight solution.
bool Enable(bool enable);
// Pauses handling. Exceptions will be caught but immediately passed on to the next handler
// without taking any action. Pauses are additive and calls to Pause(true) must be eventually
// matched to Pause(false). This function can be called from multiple threads simultaneously.
// Returns the new pause count.
int PauseHandling(bool pause);
// Some report info can be considered private information of the user, such as the current process
// list,
// computer name, IP address or other identifying info, etc. We should not report this information
// for
// external users unless they agree to this.
void EnableReportPrivacy(bool enable);
struct ExceptionListener {
virtual ~ExceptionListener() {}
virtual int HandleException(
uintptr_t userValue,
ExceptionHandler* pExceptionHandler,
ExceptionInfo* pExceptionInfo,
const char* reportFilePath) = 0;
};
void SetExceptionListener(ExceptionListener* pExceptionListener, uintptr_t userValue);
// What we do after handling the exception.
enum ExceptionResponse {
kERContinue, // Continue execution. Will result in the exception being re-generated unless the
// application has fixed the cause. Similar to Windows
// EXCEPTION_CONTINUE_EXECUTION.
kERHandle, // Causes the OS to handle the exception as it normally would. Similar to Windows
// EXCEPTION_EXECUTE_HANDLER.
kERTerminate, // Exit the application.
kERThrow, // Re-throw the exception. Other handlers may catch it. Similar to Windows
// EXCEPTION_CONTINUE_SEARCH.
kERDefault // Usually set to kERTerminate.
};
void SetExceptionResponse(ExceptionResponse er) {
exceptionResponse = er;
}
// Allws you to add an arbitrary description of the current application, which will be added to
// exception reports.
void SetAppDescription(const char* appDescription);
// Specifies how much info the minidump has, but also how large it gets.
enum MinidumpInfoLevel {
kMILNone, // Don't generate a .mdmp file.
kMILSmall, // Will result in a .mdmp file that's about 10-30 KiB
kMILMedium, // Will result in a .mdmp file that's about 5-15 MiB
kMILLarge // Will result in a .mdmp file that's about 50-150 MiB.
};
void SetMinidumpInfoLevel(MinidumpInfoLevel level) {
minidumpInfoLevel = level;
}
MinidumpInfoLevel GetMinidumpInfoLevel() const {
return minidumpInfoLevel;
}
// If the report path has a "%s" in its name, then assume the path is a sprintf format and write
// it
// with the %s specified as a date/time string.
// The report path can be "default" to signify that you want to use the default user location.
// Passing NULL for exceptionReportPath or exceptionMinidumpPath causes those files to not be
// written.
// By default both the exceptionReportPath and exceptionMinidumpPath are NULL.
// Example usage:
// handler.SetExceptionPaths("/Users/Current/Exceptions/Exception %s.txt");
void SetExceptionPaths(
const char* exceptionReportPath,
const char* exceptionMinidumpPath = nullptr);
// Calls SetExceptionPaths in the appropriate convention for each operating system
// Windows: %AppData%\Organization\Application
// Mac: ~/Library/Logs/DiagnosticReports/Organization/Application"
// Linux: ~/Library/Organization/Application
// exceptionFormat and minidumpFormat define the file names in the format above
// with the %s specified as a date/time string.
void SetPathsFromNames(
const char* organizationName,
const char* ApplicationName,
const char* exceptionFormat = "Exception Report (%s).txt",
const char* minidumpFormat = "Exception Minidump (%s).mdmp");
// Allows you to specify base directories for code paths, which can be used to associate exception
// addresses to lines
// of code as opposed to just file names and line numbers, or function names plus binary offsets.
void SetCodeBaseDirectoryPaths(
const char* codeBaseDirectoryPathArray[],
size_t codeBaseDirectoryPathCount);
// Writes lines into the current report.
void WriteReportLine(const char* pLine);
void WriteReportLineF(const char* format, ...);
// Retrieves a directory path which ends with a path separator.
// Returns the required strlen of the path.
// Guarantees the presence of the directory upon returning true.
static size_t GetCrashDumpDirectory(char* directoryPath, size_t directoryPathCapacity);
// Retrieves a directory path for a specific organization and application.
// Returns the required strlen of the path.
// Guarantees the presence of the directory upon returning true.
static void GetCrashDumpDirectoryFromNames(
char* path,
const char* organizationName,
const char* ApplicationName);
// Given an exception report at a given file path, returns a string suitable for displaying in a
// message
// box or similar user interface during the handling of an exception. The returned string must be
// passed
// to FreeMessageBoxText when complete.
static const char* GetExceptionUIText(const char* exceptionReportPath);
static void FreeExceptionUIText(const char* messageBoxText);
// Writes a deadlock report similar to an exception report. Since there is no allocation risk, an
// exception handler is created for this log.
static void ReportDeadlock(
const char* threadName,
const char* organizationName = nullptr,
const char* applicationName = nullptr);
protected:
// Write one log line to log file, console, syslog, and debug output.
// If LogFile is null, it will not write to the log file.
// The buffer must be null-terminated.
void writeLogLine(const char* buffer, int length);
void WriteExceptionDescription();
void WriteReport(const char* reportType);
void WriteThreadCallstack(
ThreadHandle threadHandle,
ThreadSysId threadSysId,
const char* additionalInfo);
void WriteMiniDump();
protected:
// Runtime constants
bool enabled;
std::atomic<int> pauseCount = {0}; // 0 means unpaused. 1+ means paused.
bool reportPrivacyEnabled; // Defaults to true.
ExceptionResponse exceptionResponse; // Defaults to kERHandle
ExceptionListener* exceptionListener;
uintptr_t exceptionListenerUserValue;
String appDescription;
String codeBasePathArray[6]; // 6 is arbitrary.
char reportFilePath[OVR_MAX_PATH]; // May be an encoded path, in that it has "%s" in it or is
// named "default". See reporFiletPathActual for the runtime
// actual report path.
MinidumpInfoLevel minidumpInfoLevel;
char miniDumpFilePath[OVR_MAX_PATH];
FILE* LogFile; // Can/should we use OVR Files for this?
char scratchBuffer[4096];
// Runtime variables
bool exceptionOccurred;
std::atomic<uint32_t> handlingBusy = {0};
char reportFilePathActual[OVR_MAX_PATH];
char minidumpFilePathActual[OVR_MAX_PATH];
int terminateReturnValue;
ExceptionInfo exceptionInfo;
SymbolLookup symbolLookup;
#if defined(OVR_OS_MS)
void* vectoredHandle;
LPTOP_LEVEL_EXCEPTION_FILTER previousFilter;
LPEXCEPTION_POINTERS pExceptionPointers;
friend LONG WINAPI Win32ExceptionFilter(LPEXCEPTION_POINTERS pExceptionPointers);
LONG ExceptionFilter(LPEXCEPTION_POINTERS pExceptionPointers);
// handles exception in a new thread, used for stack overflow
static unsigned WINAPI ExceptionHandlerThreadExec(void* callingHandler);
#elif defined(OVR_OS_APPLE)
struct SavedExceptionPorts {
SavedExceptionPorts() : count(0) {
memset(this, 0, sizeof(SavedExceptionPorts));
}
mach_msg_type_number_t count;
exception_mask_t masks[6];
exception_handler_t ports[6];
exception_behavior_t behaviors[6];
thread_state_flavor_t flavors[6];
};
friend void* ::MachHandlerThreadFunctionStatic(void*);
friend int ::catch_mach_exception_raise_state_identity_OVR(
mach_port_t,
mach_port_t,
mach_port_t,
exception_type_t,
mach_exception_data_type_t*,
mach_msg_type_number_t,
int*,
thread_state_t,
mach_msg_type_number_t,
thread_state_t,
mach_msg_type_number_t*);
bool InitMachExceptionHandler();
void ShutdownMachExceptionHandler();
void* MachHandlerThreadFunction();
kern_return_t HandleMachException(
mach_port_t port,
mach_port_t thread,
mach_port_t task,
exception_type_t exceptionType,
mach_exception_data_type_t* pExceptionDetail,
mach_msg_type_number_t exceptionDetailCount,
int* pFlavor,
thread_state_t pOldState,
mach_msg_type_number_t oldStateCount,
thread_state_t pNewState,
mach_msg_type_number_t* pNewStateCount);
kern_return_t ForwardMachException(
mach_port_t thread,
mach_port_t task,
exception_type_t exceptionType,
mach_exception_data_t pExceptionDetail,
mach_msg_type_number_t exceptionDetailCount);
bool machHandlerInitialized;
mach_port_t machExceptionPort;
SavedExceptionPorts machExceptionPortsSaved;
volatile bool machThreadShouldContinue;
volatile bool machThreadExecuting;
pthread_t machThread;
#elif defined(OVR_OS_LINUX)
// To do.
#endif
};
// Identifies basic exception types for the CreateException function.
enum CreateExceptionType {
kCETAccessViolation, // Read or write to inaccessable memory.
kCETAlignment, // Misaligned read or write.
kCETDivideByZero, // Integer divide by zero.
kCETFPU, // Floating point / VPU exception.
kCETIllegalInstruction, // Illegal opcode.
kCETStackCorruption, // Stack frame was corrupted.
kCETStackOverflow, // Stack ran out of space, often due to infinite recursion.
kCETTrap // System/OS trap (system call).
};
// Creates an exception of the given type, primarily for testing.
void CreateException(CreateExceptionType exceptionType);
//-----------------------------------------------------------------------------
// GUI Exception Listener
//
// When this exception handler is called, it will verify that the application
// is not being debugged at that instant. If not, then it will present a GUI
// to the user containing error information.
// Initially the exception listener is not silenced.
class GUIExceptionListener : public ExceptionHandler::ExceptionListener {
public:
GUIExceptionListener();
virtual int HandleException(
uintptr_t userValue,
ExceptionHandler* pExceptionHandler,
ExceptionInfo* pExceptionInfo,
const char* reportFilePath) OVR_OVERRIDE;
protected:
ExceptionHandler Handler;
};
} // namespace OVR
OVR_RESTORE_MSVC_WARNING()
#endif // OVR_DebugHelp_h

View File

@ -0,0 +1,468 @@
/************************************************************************************
Filename : OVR_Delegates.h
Content : C++ Delegates
Created : June 15, 2014
Authors : Chris Taylor
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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.
************************************************************************************/
/*
Based on The Impossibly Fast C++ Delegates by Sergey Ryazanov from
http://www.codeproject.com/KB/cpp/ImpossiblyFastCppDelegate.aspx (2005)
*/
/*
Usage:
Declare a delegate with a void (int) signature, also known as a
function that returns void and has one parameter that is an int:
typedef Delegate1<void, int> MyDelegate;
MyDelegate d;
Point the delegate to a member function:
d.SetMember<A, &A::TestFunctionA>(&a);
d = MyDelegate::FromMember<A, &A::TestFunctionA>(&a);
Point the delegate to a const member function:
d.SetConstMember<C, &C::TestFunctionA>(&c);
d = MyDelegate::FromConstMember<C, &C::TestFunctionA>(&c);
Point the delegate to a free function:
d.SetFree<&FreeFunctionX>();
d = MyDelegate::FromFree<&FreeFunctionX>();
Invoke the function via the delegate (works for all 3 cases):
d(1000);
By default the delegates are uninitialized.
To clear an array of delegates quickly just zero the memory.
This implementation is nicer than FastDelegates in my opinion
because it is simple and easy to read. It is a little slower
for virtual functions, but the size of the delegate is small,
and it will only get better as compilers improve.
*/
#ifndef OVR_Delegates_h
#define OVR_Delegates_h
#include "OVR_Types.h"
namespace OVR {
template <class ret_type>
class Delegate0 {
typedef ret_type (*StubPointer)(void*);
typedef Delegate0<ret_type> this_type;
void* _object;
StubPointer _stub;
inline Delegate0(void* object, StubPointer stub) {
_object = object;
_stub = stub;
}
// Stubs
template <ret_type (*F)()>
static inline ret_type FreeStub(void* /*object*/) {
return (F)();
}
template <class T, ret_type (T::*F)()>
static inline ret_type MemberStub(void* object) {
T* p = static_cast<T*>(object);
return (p->*F)();
}
template <class T, ret_type (T::*F)() const>
static inline ret_type ConstMemberStub(void* object) {
T* p = static_cast<T*>(object);
return (p->*F)();
}
public:
inline Delegate0() : _object(0), _stub(0) {}
// Function invocation
inline ret_type operator()() const {
return (*_stub)(_object);
}
// Use stub pointer as a validity flag and equality checker
inline bool operator==(const this_type& rhs) const {
return _object == rhs._object && _stub == rhs._stub;
}
inline bool operator!=(const this_type& rhs) const {
return _object != rhs._object || _stub != rhs._stub;
}
inline bool IsValid() const {
return _stub != 0;
}
inline bool operator!() const {
return _stub == 0;
}
inline void Invalidate() {
_stub = 0;
}
// Delegate creation from a function
template <ret_type (*F)()>
static inline this_type FromFree() {
return this_type(0, &FreeStub<F>);
}
template <class T, ret_type (T::*F)()>
static inline this_type FromMember(T* object) {
return this_type(object, &MemberStub<T, F>);
}
template <class T, ret_type (T::*F)() const>
static inline this_type FromConstMember(T const* object) {
return this_type(const_cast<T*>(object), &ConstMemberStub<T, F>);
}
// In-place assignment to a different function
template <ret_type (*F)()>
inline void SetFree() {
*this = FromFree<F>();
}
template <class T, ret_type (T::*F)()>
inline void SetMember(T* object) {
*this = FromMember<T, F>(object);
}
template <class T, ret_type (T::*F)() const>
inline void SetConstMember(T const* object) {
*this = FromConstMember<T, F>(object);
}
};
template <class ret_type, class arg1_type>
class Delegate1 {
typedef ret_type (*StubPointer)(void*, arg1_type);
typedef Delegate1<ret_type, arg1_type> this_type;
void* _object;
StubPointer _stub;
inline Delegate1(void* object, StubPointer stub) {
_object = object;
_stub = stub;
}
// Stubs
template <ret_type (*F)(arg1_type)>
static inline ret_type FreeStub(void* /*object*/, arg1_type a1) {
return (F)(a1);
}
template <class T, ret_type (T::*F)(arg1_type)>
static inline ret_type MemberStub(void* object, arg1_type a1) {
T* p = static_cast<T*>(object);
return (p->*F)(a1);
}
template <class T, ret_type (T::*F)(arg1_type) const>
static inline ret_type ConstMemberStub(void* object, arg1_type a1) {
T* p = static_cast<T*>(object);
return (p->*F)(a1);
}
public:
inline Delegate1() : _object(0), _stub(0) {}
// Function invocation
inline ret_type operator()(arg1_type a1) const {
return (*_stub)(_object, a1);
}
// Use stub pointer as a validity flag and equality checker
inline bool operator==(const this_type& rhs) const {
return _object == rhs._object && _stub == rhs._stub;
}
inline bool operator!=(const this_type& rhs) const {
return _object != rhs._object || _stub != rhs._stub;
}
inline bool IsValid() const {
return _stub != 0;
}
inline bool operator!() const {
return _stub == 0;
}
inline void Invalidate() {
_stub = 0;
}
// Delegate creation from a function
template <ret_type (*F)(arg1_type)>
static inline this_type FromFree() {
return this_type(0, &FreeStub<F>);
}
template <class T, ret_type (T::*F)(arg1_type)>
static inline this_type FromMember(T* object) {
return this_type(object, &MemberStub<T, F>);
}
template <class T, ret_type (T::*F)(arg1_type) const>
static inline this_type FromConstMember(T const* object) {
return this_type(const_cast<T*>(object), &ConstMemberStub<T, F>);
}
// In-place assignment to a different function
template <ret_type (*F)(arg1_type)>
inline void SetFree() {
*this = FromFree<F>();
}
template <class T, ret_type (T::*F)(arg1_type)>
inline void SetMember(T* object) {
*this = FromMember<T, F>(object);
}
template <class T, ret_type (T::*F)(arg1_type) const>
inline void SetConstMember(T const* object) {
*this = FromConstMember<T, F>(object);
}
};
template <class ret_type, class arg1_type, class arg2_type>
class Delegate2 {
typedef ret_type (*StubPointer)(void*, arg1_type, arg2_type);
typedef Delegate2<ret_type, arg1_type, arg2_type> this_type;
void* _object;
StubPointer _stub;
inline Delegate2(void* object, StubPointer stub) {
_object = object;
_stub = stub;
}
// Stubs
template <ret_type (*F)(arg1_type, arg2_type)>
static inline ret_type FreeStub(void* /*object*/, arg1_type a1, arg2_type a2) {
return (F)(a1, a2);
}
template <class T, ret_type (T::*F)(arg1_type, arg2_type)>
static inline ret_type MemberStub(void* object, arg1_type a1, arg2_type a2) {
T* p = static_cast<T*>(object);
return (p->*F)(a1, a2);
}
template <class T, ret_type (T::*F)(arg1_type, arg2_type) const>
static inline ret_type ConstMemberStub(void* object, arg1_type a1, arg2_type a2) {
T* p = static_cast<T*>(object);
return (p->*F)(a1, a2);
}
public:
inline Delegate2() : _object(0), _stub(0) {}
// Function invocation
inline ret_type operator()(arg1_type a1, arg2_type a2) const {
return (*_stub)(_object, a1, a2);
}
// Use stub pointer as a validity flag and equality checker
inline bool operator==(const this_type& rhs) const {
return _object == rhs._object && _stub == rhs._stub;
}
inline bool operator!=(const this_type& rhs) const {
return _object != rhs._object || _stub != rhs._stub;
}
inline bool IsValid() const {
return _stub != 0;
}
inline bool operator!() const {
return _stub == 0;
}
inline void Invalidate() {
_stub = 0;
}
// Delegate creation from a function
template <ret_type (*F)(arg1_type, arg2_type)>
static inline this_type FromFree() {
return this_type(0, &FreeStub<F>);
}
template <class T, ret_type (T::*F)(arg1_type, arg2_type)>
static inline this_type FromMember(T* object) {
return this_type(object, &MemberStub<T, F>);
}
template <class T, ret_type (T::*F)(arg1_type, arg2_type) const>
static inline this_type FromConstMember(T const* object) {
return this_type(const_cast<T*>(object), &ConstMemberStub<T, F>);
}
// In-place assignment to a different function
template <ret_type (*F)(arg1_type, arg2_type)>
inline void SetFree() {
*this = FromFree<F>();
}
template <class T, ret_type (T::*F)(arg1_type, arg2_type)>
inline void SetMember(T* object) {
*this = FromMember<T, F>(object);
}
template <class T, ret_type (T::*F)(arg1_type, arg2_type) const>
inline void SetConstMember(T const* object) {
*this = FromConstMember<T, F>(object);
}
};
template <class ret_type, class arg1_type, class arg2_type, class arg3_type>
class Delegate3 {
typedef ret_type (*StubPointer)(void*, arg1_type, arg2_type, arg3_type);
typedef Delegate3<ret_type, arg1_type, arg2_type, arg3_type> this_type;
void* _object;
StubPointer _stub;
inline Delegate3(void* object, StubPointer stub) {
_object = object;
_stub = stub;
}
// Stubs
template <ret_type (*F)(arg1_type, arg2_type, arg3_type)>
static inline ret_type FreeStub(void* /*object*/, arg1_type a1, arg2_type a2, arg3_type a3) {
return (F)(a1, a2, a3);
}
template <class T, ret_type (T::*F)(arg1_type, arg2_type, arg3_type)>
static inline ret_type MemberStub(void* object, arg1_type a1, arg2_type a2, arg3_type a3) {
T* p = static_cast<T*>(object);
return (p->*F)(a1, a2, a3);
}
template <class T, ret_type (T::*F)(arg1_type, arg2_type, arg3_type) const>
static inline ret_type ConstMemberStub(void* object, arg1_type a1, arg2_type a2, arg3_type a3) {
T* p = static_cast<T*>(object);
return (p->*F)(a1, a2, a3);
}
public:
inline Delegate3() : _object(0), _stub(0) {}
// Function invocation
inline ret_type operator()(arg1_type a1, arg2_type a2, arg3_type a3) const {
return (*_stub)(_object, a1, a2, a3);
}
// Use stub pointer as a validity flag and equality checker
inline bool operator==(const this_type& rhs) const {
return _object == rhs._object && _stub == rhs._stub;
}
inline bool operator!=(const this_type& rhs) const {
return _object != rhs._object || _stub != rhs._stub;
}
inline bool IsValid() const {
return _stub != 0;
}
inline bool operator!() const {
return _stub == 0;
}
inline void Invalidate() {
_stub = 0;
}
// Delegate creation from a function
template <ret_type (*F)(arg1_type, arg2_type, arg3_type)>
static inline this_type FromFree() {
return this_type(0, &FreeStub<F>);
}
template <class T, ret_type (T::*F)(arg1_type, arg2_type, arg3_type)>
static inline this_type FromMember(T* object) {
return this_type(object, &MemberStub<T, F>);
}
template <class T, ret_type (T::*F)(arg1_type, arg2_type, arg3_type) const>
static inline this_type FromConstMember(T const* object) {
return this_type(const_cast<T*>(object), &ConstMemberStub<T, F>);
}
// In-place assignment to a different function
template <ret_type (*F)(arg1_type, arg2_type, arg3_type)>
inline void SetFree() {
*this = FromFree<F>();
}
template <class T, ret_type (T::*F)(arg1_type, arg2_type, arg3_type)>
inline void SetMember(T* object) {
*this = FromMember<T, F>(object);
}
template <class T, ret_type (T::*F)(arg1_type, arg2_type, arg3_type) const>
inline void SetConstMember(T const* object) {
*this = FromConstMember<T, F>(object);
}
};
// Add more here if needed, but keep in mind that a short, simple interface
// is rewarded by making the delegates faster...
} // namespace OVR
#endif // OVR_Delegates_h

View File

@ -0,0 +1,287 @@
/************************************************************************************
Filename : OVR_Deque.h
Content : Deque container
Created : Nov. 15, 2013
Authors : Dov Katz
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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.
*************************************************************************************/
#pragma once
#include "OVR_ContainerAllocator.h"
namespace OVR {
template <class Elem, class Allocator = ContainerAllocator<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 size_t GetSize(void) const; // Returns Number of Elements
OVR_FORCE_INLINE int GetSizeI(void) const {
return (int)GetSize();
}
virtual inline size_t 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:
OVR_NON_COPYABLE(Deque);
};
template <class Elem, class Allocator = ContainerAllocator<Elem>>
class InPlaceMutableDeque : public Deque<Elem, Allocator> {
typedef Deque<Elem, Allocator> BaseType;
public:
InPlaceMutableDeque(int capacity = BaseType::DefaultCapacity) : BaseType(capacity) {}
virtual ~InPlaceMutableDeque(){};
using BaseType::PeekBack;
using BaseType::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 Allocator = ContainerAllocator<Elem>>
class CircularBuffer : public InPlaceMutableDeque<Elem, Allocator> {
typedef InPlaceMutableDeque<Elem, Allocator> BaseType;
public:
CircularBuffer(int MaxSize = BaseType::DefaultCapacity) : BaseType(MaxSize){};
virtual ~CircularBuffer() {}
// 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, class Allocator>
Deque<Elem, Allocator>::Deque(int capacity)
: Capacity(capacity), Beginning(0), End(0), ElemCount(0) {
Data = (Elem*)Allocator::Alloc(Capacity * sizeof(Elem));
}
// Deque Destructor function
template <class Elem, class Allocator>
Deque<Elem, Allocator>::~Deque(void) {
Clear();
Allocator::Free(Data);
}
template <class Elem, class Allocator>
void Deque<Elem, Allocator>::Clear() {
if (!IsEmpty()) {
if (Beginning < End) {
// no wrap-around
Allocator::DestructArray(Data + Beginning, End - Beginning);
} else {
// wrap-around
Allocator::DestructArray(Data + Beginning, Capacity - Beginning);
Allocator::DestructArray(Data, End);
}
}
Beginning = 0;
End = 0;
ElemCount = 0;
}
// Push functions
template <class Elem, class Allocator>
void Deque<Elem, Allocator>::PushBack(const Elem& Item) {
// Error Check: Make sure we aren't
// exceeding our maximum storage space
OVR_ASSERT(ElemCount < Capacity);
Allocator::Construct(Data + End, Item);
++End;
++ElemCount;
// Check for wrap-around
if (End >= Capacity)
End -= Capacity;
}
template <class Elem, class Allocator>
void Deque<Elem, Allocator>::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;
Allocator::Construct(Data + Beginning, Item);
++ElemCount;
}
// Pop functions
template <class Elem, class Allocator>
Elem Deque<Elem, Allocator>::PopFront(void) {
// Error Check: Make sure we aren't reading from an empty Deque
OVR_ASSERT(ElemCount > 0);
Elem ReturnValue = Data[Beginning];
Allocator::Destruct(Data + Beginning);
++Beginning;
--ElemCount;
// Check for wrap-around
if (Beginning >= Capacity)
Beginning -= Capacity;
return ReturnValue;
}
template <class Elem, class Allocator>
Elem Deque<Elem, Allocator>::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];
Allocator::Destruct(Data + End);
return ReturnValue;
}
// Peek functions
template <class Elem, class Allocator>
const Elem& Deque<Elem, Allocator>::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, class Allocator>
const Elem& Deque<Elem, Allocator>::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, class Allocator>
Elem& InPlaceMutableDeque<Elem, Allocator>::PeekFront(int count) {
// Error Check: Make sure we aren't reading from an empty Deque
OVR_ASSERT(BaseType::ElemCount > count);
int idx = BaseType::Beginning + count;
if (idx >= BaseType::Capacity)
idx -= BaseType::Capacity;
return BaseType::Data[idx];
}
template <class Elem, class Allocator>
Elem& InPlaceMutableDeque<Elem, Allocator>::PeekBack(int count) {
// Error Check: Make sure we aren't reading from an empty Deque
OVR_ASSERT(BaseType::ElemCount > count);
int idx = BaseType::End - count - 1;
if (idx < 0)
idx += BaseType::Capacity;
return BaseType::Data[idx];
}
template <class Elem, class Allocator>
inline size_t Deque<Elem, Allocator>::GetCapacity(void) const {
return Capacity;
}
template <class Elem, class Allocator>
inline size_t Deque<Elem, Allocator>::GetSize(void) const {
return ElemCount;
}
template <class Elem, class Allocator>
inline bool Deque<Elem, Allocator>::IsEmpty(void) const {
return ElemCount == 0;
}
template <class Elem, class Allocator>
inline bool Deque<Elem, Allocator>::IsFull(void) const {
return ElemCount == Capacity;
}
// ******* CircularBuffer<Elem> *******
// Push functions
template <class Elem, class Allocator>
void CircularBuffer<Elem, Allocator>::PushBack(const Elem& Item) {
if (this->IsFull())
this->PopFront();
BaseType::PushBack(Item);
}
template <class Elem, class Allocator>
void CircularBuffer<Elem, Allocator>::PushFront(const Elem& Item) {
if (this->IsFull())
this->PopBack();
BaseType::PushFront(Item);
}
} // namespace OVR

View File

@ -0,0 +1,878 @@
/************************************************************************************
PublicHeader: None
Filename : OVR_Error.cpp
Content : Structs and functions for handling OVRErrorInfos
Created : February 15, 2015
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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_Error.h"
#include "OVR_Types.h"
#include "OVR_Std.h"
#include "OVR_String.h"
#include "OVR_Timer.h"
#include "OVR_DebugHelp.h"
#include "OVR_Atomic.h"
#include "OVR_UTF8Util.h"
#include "OVR_Threads.h"
#include "OVR_Win32_IncludeWindows.h"
#include "Logging/Logging_Library.h"
OVR_DISABLE_ALL_MSVC_WARNINGS()
OVR_DISABLE_MSVC_WARNING(4265)
#if defined(OVR_OS_WIN32)
#include <winerror.h>
#include <dxgitype.h>
#endif
#include <utility>
#include <algorithm>
#include <chrono>
#include <ctime>
#include <stdarg.h>
#include <cstdio>
#include <mutex>
#include <unordered_map>
OVR_RESTORE_MSVC_WARNING()
OVR_RESTORE_ALL_MSVC_WARNINGS()
OVR_DEFINE_SINGLETON(OVR::LastErrorTLS);
OVR_DISABLE_MSVC_WARNING(4996) // 'localtime': This function or variable may be unsafe.
static ovrlog::Channel Logger("Kernel:Error");
// -----------------------------------------------------------------------------
// ***** OVR_ERROR_ENABLE_BACKTRACES
//
// If defined then we record backtraces in Errors.
//
#if !defined(OVR_ERROR_ENABLE_BACKTRACES)
#if defined(OVR_BUILD_DEBUG)
#define OVR_ERROR_ENABLE_BACKTRACES 1
#endif
#endif
namespace OVR {
//-----------------------------------------------------------------------------
// LastErrorTLS
static SymbolLookup Symbols;
LastErrorTLS::LastErrorTLS() {
Symbols.Initialize();
// Must be at end of function
PushDestroyCallbacks();
}
LastErrorTLS::~LastErrorTLS() {
Symbols.Shutdown();
}
void LastErrorTLS::OnSystemDestroy() {
delete this;
}
// This is an accessor which auto-allocates and initializes the return value if needed.
OVRError& LastErrorTLS::LastError() {
Lock::Locker autoLock(&TheLock);
ThreadId threadId = GetCurrentThreadId();
auto i = TLSDictionary.Find(threadId);
if (i == TLSDictionary.End()) {
TLSDictionary.Add(threadId, OVRError::Success());
i = TLSDictionary.Find(threadId);
}
return (*i).Second;
}
// ****** OVRFormatDateTime
//
// Prints a date/time like so:
// Y-M-d H:M:S [ms:us:ns]
// Example output:
// 2016-12-25 8:15:01 [392:445:23]
//
// SysClockTime is of type std::chrono::time_point<std::chrono::system_clock>.
//
// To consider: Move SysClockTime and OVRFormatDateTime to OVRKernel.
//
static void OVRFormatDateTime(SysClockTime sysClockTime, OVR::String& dateTimeString) {
// Get the basic Date and HMS time.
char buffer[128];
struct tm tmResult;
const time_t cTime = std::chrono::system_clock::to_time_t(sysClockTime);
#if defined(_MSC_VER)
localtime_s(&tmResult, &cTime);
#else
localtime_r(&cTime, &tmResult);
#endif
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &tmResult);
// Append milli:micro:nano time.
std::chrono::system_clock::duration timeSinceEpoch = sysClockTime.time_since_epoch();
std::chrono::seconds s = std::chrono::duration_cast<std::chrono::seconds>(timeSinceEpoch);
timeSinceEpoch -= s;
std::chrono::milliseconds ms =
std::chrono::duration_cast<std::chrono::milliseconds>(timeSinceEpoch);
timeSinceEpoch -= ms;
std::chrono::microseconds us =
std::chrono::duration_cast<std::chrono::microseconds>(timeSinceEpoch);
timeSinceEpoch -= us;
std::chrono::nanoseconds ns =
std::chrono::duration_cast<std::chrono::nanoseconds>(timeSinceEpoch);
char buffer2[384];
sprintf(buffer2, "%s [%d:%d:%d]", buffer, (int)ms.count(), (int)us.count(), (int)ns.count());
dateTimeString = buffer2;
}
static void OVRRemoveTrailingNewlines(String& s) {
while (!s.IsEmpty() && ((s.Back() == '\n') || (s.Back() == '\r')))
s.PopBack();
}
OVR_SELECTANY const int64_t OVRError::kLogLineUnset;
OVRError::OVRError() {
Reset();
}
OVRError::OVRError(ovrResult code) : OVRError() {
Code = code;
}
OVRError::OVRError(ovrResult code, const char* pFormat, ...) : OVRError(code) {
va_list argList;
va_start(argList, pFormat);
StringBuffer strbuff;
strbuff.AppendFormatV(pFormat, argList);
SetDescription(strbuff.ToCStr());
va_end(argList);
}
OVRError::OVRError(const OVRError& ovrError) {
operator=(ovrError);
}
OVRError::OVRError(OVRError&& ovrError) {
operator=(std::move(ovrError));
}
OVRError::~OVRError() {
// Empty
}
OVRError& OVRError::operator=(const OVRError& ovrError) {
ErrorString = ovrError.ErrorString;
Code = ovrError.Code;
SysCodeType = ovrError.SysCodeType;
SysCode = ovrError.SysCode;
strcpy(SysCodeStr, ovrError.SysCodeStr);
Description = ovrError.Description;
Context = ovrError.Context;
OVRTime = ovrError.OVRTime;
ClockTime = ovrError.ClockTime;
LogLine = ovrError.LogLine;
SourceFilePath = ovrError.SourceFilePath;
SourceFileLine = ovrError.SourceFileLine;
Backtrace = ovrError.Backtrace;
AlreadyLogged = ovrError.AlreadyLogged;
return *this;
}
OVRError& OVRError::operator=(OVRError&& ovrError) {
ErrorString = ovrError.ErrorString;
Code = ovrError.Code;
SysCodeType = ovrError.SysCodeType;
SysCode = ovrError.SysCode;
strcpy(SysCodeStr, ovrError.SysCodeStr);
Description = std::move(ovrError.Description);
Context = std::move(ovrError.Context);
OVRTime = ovrError.OVRTime;
ClockTime = ovrError.ClockTime;
LogLine = ovrError.LogLine;
SourceFilePath = std::move(ovrError.SourceFilePath);
SourceFileLine = ovrError.SourceFileLine;
Backtrace = std::move(ovrError.Backtrace);
AlreadyLogged = ovrError.AlreadyLogged;
return *this;
}
void OVRError::SetCurrentValues() {
OVRTime = Timer::GetSeconds(); // It would be better if we called ovr_GetTimeInSeconds, but that
// doesn't have a constant header to use.
ClockTime = std::chrono::system_clock::now();
#if defined(OVR_ERROR_ENABLE_BACKTRACES)
if (Symbols.IsInitialized()) {
void* addressArray[32];
size_t n = Symbols.GetBacktrace(
addressArray, OVR_ARRAY_COUNT(addressArray), 2, nullptr, OVR_THREADSYSID_INVALID);
Backtrace.Clear();
Backtrace.Append(addressArray, n);
}
#endif
}
void OVRError::Reset() {
ErrorString.Clear();
Code = ovrSuccess;
SysCodeType = ovrSysErrorCodeType::None;
SysCode = ovrSysErrorCodeSuccess;
SysCodeStr[0] = '\0';
Description.Clear();
Context.Clear();
OVRTime = 0;
ClockTime = SysClockTime();
LogLine = kLogLineUnset;
SourceFilePath.Clear();
SourceFileLine = 0;
Backtrace.ClearAndRelease();
AlreadyLogged = false;
}
String OVRError::GetErrorString() const {
if (ErrorString.GetSize() == 0) { // If not already cached...
ErrorString.AppendString("OVR Error:\n");
// Code
OVR::String errorCodeString;
GetErrorCodeString(Code, false, errorCodeString);
ErrorString.AppendFormat(" Code: %d -- %s\n", Code, errorCodeString.ToCStr());
// SysCode
if (SysCode != ovrSysErrorCodeSuccess) {
if (SysCodeStr[0]) { // If the sys error was previously set to a custom value...
ErrorString.AppendFormat(
" System error: %d (%x) -- %s\n", (int)SysCode, (int)SysCode, SysCodeStr);
} else { // Else just build it with the system error code.
OVR::String sysErrorString;
GetSysErrorCodeString(SysCodeType, SysCode, false, sysErrorString);
OVRRemoveTrailingNewlines(sysErrorString);
ErrorString.AppendFormat(
" System error: %d (%x) -- %s\n", (int)SysCode, (int)SysCode, sysErrorString.ToCStr());
}
}
// Description
if (Description.GetLength()) {
ErrorString.AppendFormat(" Description: %s\n", Description.ToCStr());
}
// OVRTime
ErrorString.AppendFormat(" OVRTime: %f\n", OVRTime);
// SysClockTime
OVR::String sysClockTimeString;
OVRFormatDateTime(ClockTime, sysClockTimeString);
ErrorString.AppendFormat(" Time: %s\n", sysClockTimeString.ToCStr());
// Context
if (Context.GetLength())
ErrorString.AppendFormat(" Context: %s\n", Context.ToCStr());
// If LogLine is set,
if (LogLine != kLogLineUnset)
ErrorString.AppendFormat(" LogLine: %lld\n", LogLine);
// FILE/LINE
if (SourceFilePath.GetLength())
ErrorString.AppendFormat(" File/Line: %s:%d\n", SourceFilePath.ToCStr(), SourceFileLine);
// Backtrace
if (Backtrace.GetSize()) {
// We can trace symbols in a debug build here or we can trace just addresses. See other code
// for examples of how to trace symbols.
ErrorString.AppendFormat(" Backtrace: ");
for (size_t i = 0, iEnd = Backtrace.GetSize(); i != iEnd; ++i)
ErrorString.AppendFormat(" %p", Backtrace[i]);
ErrorString.AppendChar('\n');
}
}
return OVR::String(ErrorString.ToCStr(), ErrorString.GetSize());
}
void OVRError::SetCode(ovrResult code) {
Code = code;
}
ovrResult OVRError::GetCode() const {
return Code;
}
void OVRError::SetSysCode(
ovrSysErrorCodeType sysCodeType,
ovrSysErrorCode sysCode,
const char* sysCodeString) {
SysCodeType = sysCodeType;
SysCode = sysCode;
if (sysCodeString)
OVR_strlcpy(SysCodeStr, sysCodeString, sizeof(SysCodeStr));
}
ovrSysErrorCodeType OVRError::GetSysCodeType() const {
return SysCodeType;
}
ovrSysErrorCode OVRError::GetSysCode() const {
return SysCode;
}
void OVRError::SetDescription(const char* pDescription) {
if (pDescription) {
Description = pDescription;
OVRRemoveTrailingNewlines(Description); // Users sometimes send text with trailing newlines,
// which have no purpose in the error report.
} else
Description.Clear();
}
String OVRError::GetDescription() const {
return Description;
}
void OVRError::SetContext(const char* pContext) {
if (pContext) {
Context = pContext;
OVRRemoveTrailingNewlines(Context);
} else
Context.Clear();
}
String OVRError::GetContext() const {
return Context;
}
void OVRError::SetOVRTime(double ovrTime) {
OVRTime = ovrTime;
}
double OVRError::GetOVRTime() const {
return OVRTime;
}
void OVRError::SetSysClockTime(const SysClockTime& clockTime) {
ClockTime = clockTime;
}
SysClockTime OVRError::GetSysClockTime() const {
return ClockTime;
}
void OVRError::SetLogLine(int64_t logLine) {
LogLine = logLine;
}
int64_t OVRError::GetLogLine() const {
return LogLine;
}
void OVRError::SetSource(const char* pSourceFilePath, int sourceFileLine) {
if (pSourceFilePath)
SourceFilePath = pSourceFilePath;
else
SourceFilePath.Clear();
SourceFileLine = sourceFileLine;
}
std::pair<OVR::String, int> OVRError::GetSource() const {
return std::make_pair(SourceFilePath, SourceFileLine);
}
OVRError::AddressArray OVRError::GetBacktrace() const {
return Backtrace;
}
void LogError(OVRError& ovrError) {
// If not already logged,
if (!ovrError.IsAlreadyLogged()) {
Logger.LogError(ovrError.GetErrorString());
ovrError.SetAlreadyLogged();
}
}
void SetError(OVRError& ovrError) {
// Record that the current thread's last error is this error. If we wanted to support
// chaining of errors such that multiple OVRErrors could be concurrent in a thread
// (e.g. one that occurred deep in the call chain and a higher level version of it higher
// in the call chain), we could handle that here.
LastErrorTLS::GetInstance()->LastError() = ovrError;
}
static OVRErrorCallback ErrorCallback;
void SetErrorCallback(OVRErrorCallback callback) {
ErrorCallback = callback;
}
OVRError MakeError(
ovrResult errorCode,
ovrSysErrorCodeType sysCodeType,
ovrSysErrorCode sysCode,
const char* sysCodeString, // Optional pre-generated sys error code string.
const char* pSourceFile,
int sourceLine,
bool logError,
bool assertError,
const char* pContext,
const char* pDescriptionFormat,
...) {
OVRError ovrError(errorCode);
ovrError.SetCurrentValues(); // Sets the current time, etc.
ovrError.SetSysCode(sysCodeType, sysCode, sysCodeString);
va_list argList;
va_start(argList, pDescriptionFormat);
StringBuffer strbuff;
strbuff.AppendFormatV(pDescriptionFormat, argList);
va_end(argList);
ovrError.SetDescription(strbuff.ToCStr());
ovrError.SetContext(pContext);
ovrError.SetSource(pSourceFile, sourceLine);
// Set the TLS last error.
LastErrorTLS::GetInstance()->LastError() = ovrError;
int silencerOptions = ovrlog::ErrorSilencer::GetSilenceOptions();
if (silencerOptions & ovrlog::ErrorSilencer::CompletelySilenceLogs)
logError = false;
if (silencerOptions & ovrlog::ErrorSilencer::PreventErrorAsserts)
assertError = false;
if (logError)
Logger.LogError(ovrError.GetErrorString().ToCStr());
if (assertError) {
// Assert in debug mode to alert unit tester/developer of the error as it occurs.
OVR_FAIL_M(ovrError.GetErrorString().ToCStr());
}
// ErrorCallback should be called after LastErrorTLS is set.
// ErrorCallback could choose to save LastErrorTLS if desired.
if (ErrorCallback) {
const bool quiet = !logError && !assertError;
ErrorCallback(ovrError, quiet);
}
return ovrError;
}
typedef std::unordered_map<ovrResult, const char*> ResultNameMap;
static ResultNameMap& GetResultNameMap() {
static ResultNameMap resultNameMap;
return resultNameMap;
}
const char* GetErrorCodeName(ovrResult errorCode) {
if (errorCode == ovrSuccess) {
return "ovrSuccess"; // Speed up a common case
}
const ResultNameMap& resultNameMap = GetResultNameMap();
ResultNameMap::const_iterator it = resultNameMap.find(errorCode);
if (it == resultNameMap.end()) {
OVR_FAIL_M("Unknown result code. It should have been registered");
return "UnknownResultCode";
}
return it->second;
}
void OVRError::RegisterResultCodeName(ovrResult number, const char* name) {
ResultNameMap& resultNameMap = GetResultNameMap();
if (resultNameMap.find(number) != resultNameMap.end()) {
OVR_FAIL_M("Duplicate result code registered");
return;
}
resultNameMap[number] = name;
}
bool GetErrorCodeString(ovrResult resultIn, bool prefixErrorCode, OVR::String& sResult) {
char codeBuffer[256];
const char* errorCodeName = GetErrorCodeName(resultIn);
if (prefixErrorCode) {
snprintf(
codeBuffer,
OVR_ARRAY_COUNT(codeBuffer),
"0x%llx (%lld) %s",
(uint64_t)resultIn,
(int64_t)resultIn,
errorCodeName);
} else {
snprintf(codeBuffer, OVR_ARRAY_COUNT(codeBuffer), "%s", errorCodeName);
}
sResult = codeBuffer;
return true;
}
#if defined(OVR_OS_WIN32)
static const wchar_t* OVR_DXGetErrorStringW(HRESULT dwDXGIErrorCode) {
switch (dwDXGIErrorCode) {
case DXGI_ERROR_DEVICE_HUNG:
return L"DXGI_ERROR_DEVICE_HUNG"; // The application's device failed due to badly formed
// commands sent by the application. This is an design-time
// issue that should be investigated and fixed.
case DXGI_ERROR_DEVICE_REMOVED:
return L"DXGI_ERROR_DEVICE_REMOVED"; // The video card has been physically removed from the
// system, or a driver upgrade for the video card has
// occurred. The application should destroy and recreate
// the device. For help debugging the problem, call
// ID3D10Device::GetDeviceRemovedReason.
case DXGI_ERROR_DEVICE_RESET:
return L"DXGI_ERROR_DEVICE_RESET"; // The device failed due to a badly formed command. This is
// a run-time issue; The application should destroy and
// recreate the device.
case DXGI_ERROR_DRIVER_INTERNAL_ERROR:
return L"DXGI_ERROR_DRIVER_INTERNAL_ERROR"; // The driver encountered a problem and was put
// into the device removed state.
case DXGI_ERROR_FRAME_STATISTICS_DISJOINT:
return L"DXGI_ERROR_FRAME_STATISTICS_DISJOINT"; // An event (for example, a power cycle)
// interrupted the gathering of presentation
// statistics.
case DXGI_ERROR_GRAPHICS_VIDPN_SOURCE_IN_USE:
return L"DXGI_ERROR_GRAPHICS_VIDPN_SOURCE_IN_USE"; // The application attempted to acquire
// exclusive ownership of an output, but
// failed because some other application
// (or device within the application)
// already acquired ownership.
case DXGI_ERROR_INVALID_CALL:
return L"DXGI_ERROR_INVALID_CALL"; // The application provided invalid parameter data; this
// must be debugged and fixed before the application is
// released.
case DXGI_ERROR_MORE_DATA:
return L"DXGI_ERROR_MORE_DATA"; // The buffer supplied by the application is not big enough to
// hold the requested data.
case DXGI_ERROR_NONEXCLUSIVE:
return L"DXGI_ERROR_NONEXCLUSIVE"; // A global counter resource is in use, and the Direct3D
// device can't currently use the counter resource.
case DXGI_ERROR_NOT_CURRENTLY_AVAILABLE:
return L"DXGI_ERROR_NOT_CURRENTLY_AVAILABLE"; // The resource or request is not currently
// available, but it might become available
// later.
case DXGI_ERROR_NOT_FOUND:
return L"DXGI_ERROR_NOT_FOUND"; // When calling IDXGIObject::GetPrivateData, the GUID passed
// in is not recognized as one previously passed to
// IDXGIObject::SetPrivateData or
// IDXGIObject::SetPrivateDataInterface. When calling
// IDXGIFactory::EnumAdapters or IDXGIAdapter::EnumOutputs,
// the enumerated ordinal is out of range.
case DXGI_ERROR_REMOTE_CLIENT_DISCONNECTED:
return L"DXGI_ERROR_REMOTE_CLIENT_DISCONNECTED"; // Reserved
case DXGI_ERROR_REMOTE_OUTOFMEMORY:
return L"DXGI_ERROR_REMOTE_OUTOFMEMORY"; // Reserved
case DXGI_ERROR_WAS_STILL_DRAWING:
return L"DXGI_ERROR_WAS_STILL_DRAWING"; // The GPU was busy at the moment when a call was made
// to perform an operation, and did not execute or
// schedule the operation.
case DXGI_ERROR_UNSUPPORTED:
return L"DXGI_ERROR_UNSUPPORTED"; // The requested functionality is not supported by the
// device or the driver.
case DXGI_ERROR_ACCESS_LOST:
return L"DXGI_ERROR_ACCESS_LOST"; // The desktop duplication interface is invalid. The desktop
// duplication interface typically becomes invalid when a
// different type of image is displayed on the desktop.
case DXGI_ERROR_WAIT_TIMEOUT:
return L"DXGI_ERROR_WAIT_TIMEOUT"; // The time-out interval elapsed before the next desktop
// frame was available.
case DXGI_ERROR_SESSION_DISCONNECTED:
return L"DXGI_ERROR_SESSION_DISCONNECTED"; // The Remote Desktop Services session is currently
// disconnected.
case DXGI_ERROR_RESTRICT_TO_OUTPUT_STALE:
return L"DXGI_ERROR_RESTRICT_TO_OUTPUT_STALE"; // The DXGI output (monitor) to which the swap
// chain content was restricted is now
// disconnected or changed.
case DXGI_ERROR_CANNOT_PROTECT_CONTENT:
return L"DXGI_ERROR_CANNOT_PROTECT_CONTENT"; // DXGI can't provide content protection on the
// swap chain. This error is typically caused by
// an older driver, or when you use a swap chain
// that is incompatible with content protection.
case DXGI_ERROR_ACCESS_DENIED:
return L"DXGI_ERROR_ACCESS_DENIED"; // You tried to use a resource to which you did not have
// the required access privileges. This error is most
// typically caused when you write to a shared resource
// with read-only access.
case DXGI_ERROR_NAME_ALREADY_EXISTS:
return L"DXGI_ERROR_NAME_ALREADY_EXISTS"; // The supplied name of a resource in a call to
// IDXGIResource1::CreateSharedHandle is already
// associated with some other resource.
case DXGI_ERROR_SDK_COMPONENT_MISSING:
return L"DXGI_ERROR_SDK_COMPONENT_MISSING"; // The operation depends on an SDK component that
// is missing or mismatched.
}
return nullptr;
}
#endif
bool GetSysErrorCodeString(
ovrSysErrorCodeType sysErrorCodeType,
ovrSysErrorCode sysErrorCode,
bool prefixErrorCode,
OVR::String& sResult) {
char errorBuffer[1024];
errorBuffer[0] = '\0';
if (prefixErrorCode) {
char prefixBuffer[64];
snprintf(
prefixBuffer,
OVR_ARRAY_COUNT(prefixBuffer),
"0x%llx (%lld): ",
(uint64_t)sysErrorCode,
(int64_t)sysErrorCode);
sResult = prefixBuffer;
} else {
sResult.Clear();
}
if (sysErrorCodeType == ovrSysErrorCodeType::Vulkan) {
// We have a problem here in that we can't #include <vulkan.h> because this source is
// distributed as part of a public SDK, and we don't want to create that dependency.
// However, vulkan.h errors are stable, so we can repeat them here.
char buffer[32];
itoa(sysErrorCode, buffer, 10);
const char* vkResultStr = buffer; // Default to the numerical value.
switch (static_cast<int32_t>(sysErrorCode)) {
case 0:
vkResultStr = "VK_SUCESS";
break;
case 1:
vkResultStr = "VK_NOT_READY";
break;
case 2:
vkResultStr = "VK_TIMEOUT";
break;
case 3:
vkResultStr = "VK_EVENT_SET";
break;
case 4:
vkResultStr = "VK_EVENT_RESET";
break;
case 5:
vkResultStr = "VK_INCOMPLETE";
break;
case -1:
vkResultStr = "VK_ERROR_OUT_OF_HOST_MEMORY";
break;
case -2:
vkResultStr = "VK_ERROR_OUT_OF_DEVICE_MEMORY";
break;
case -3:
vkResultStr = "VK_ERROR_INITIALIZATION_FAILED";
break;
case -4:
vkResultStr = "VK_ERROR_DEVICE_LOST";
break;
case -5:
vkResultStr = "VK_ERROR_MEMORY_MAP_FAILED";
break;
case -6:
vkResultStr = "VK_ERROR_LAYER_NOT_PRESENT";
break;
case -7:
vkResultStr = "VK_ERROR_EXTENSION_NOT_PRESENT";
break;
case -8:
vkResultStr = "VK_ERROR_FEATURE_NOT_PRESENT";
break;
case -9:
vkResultStr = "VK_ERROR_INCOMPATIBLE_DRIVER";
break;
case -10:
vkResultStr = "VK_ERROR_TOO_MANY_OBJECTS";
break;
case -11:
vkResultStr = "VK_ERROR_FORMAT_NOT_SUPPORTED";
break;
case -12:
vkResultStr = "VK_ERROR_FRAGMENTED_POOL";
break;
case -1000000000:
vkResultStr = "VK_ERROR_SURFACE_LOST_KHR";
break;
case -1000000001:
vkResultStr = "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR";
break;
case 1000001003:
vkResultStr = "VK_SUBOPTIMAL_KHR";
break;
case -1000001004:
vkResultStr = "VK_ERROR_OUT_OF_DATE_KHR";
break;
case -1000003001:
vkResultStr = "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR";
break;
case -1000011001:
vkResultStr = "VK_ERROR_VALIDATION_FAILED_EXT";
break;
case -1000012000:
vkResultStr = "VK_ERROR_INVALID_SHADER_NV";
break;
case -1000069000:
vkResultStr = "VK_ERROR_OUT_OF_POOL_MEMORY_KHR";
break;
case -1000072003:
vkResultStr = "VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR";
break;
case -1000174001:
vkResultStr = "VK_ERROR_NOT_PERMITTED_EXT";
break;
default:
// Use the numerical default above.
break;
}
OVR::OVR_strlcat(errorBuffer, vkResultStr, sizeof(errorBuffer));
} else if (sysErrorCodeType == ovrSysErrorCodeType::OpenGL) {
char buffer[32];
itoa(sysErrorCode, buffer, 10);
const char* glResultStr = buffer; // Default to the numerical value.
switch (sysErrorCode) {
case 0:
glResultStr = "GL_NO_ERROR";
break;
case 0x0500:
glResultStr = "GL_INVALID_ENUM";
break;
case 0x0501:
glResultStr = "GL_INVALID_VALUE";
break;
case 0x0502:
glResultStr = "GL_INVALID_OPERATION";
break;
case 0x0503:
glResultStr = "GL_STACK_OVERFLOW";
break;
case 0x0504:
glResultStr = "GL_STACK_UNDERFLOW";
break;
case 0x0505:
glResultStr = "GL_OUT_OF_MEMORY";
break;
default:
// Use the numerical default above.
break;
}
OVR::OVR_strlcat(errorBuffer, glResultStr, sizeof(errorBuffer));
} else if (sysErrorCodeType == ovrSysErrorCodeType::OS) {
#if defined(OVR_OS_WIN32)
// Note: It may be useful to use FORMAT_MESSAGE_FROM_HMODULE here to get a module-specific error
// string if our source of errors ends up including more than just system-native errors. For
// example, a third party module with custom errors defined in it.
WCHAR errorBufferW[1024];
DWORD errorBufferWCapacity = OVR_ARRAY_COUNT(errorBufferW);
DWORD length = FormatMessageW(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr,
(DWORD)sysErrorCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
errorBufferW,
errorBufferWCapacity,
nullptr);
if (!length) // If failed...
{
if (HRESULT_FACILITY(sysErrorCode) == _FACDXGI) // If it is a DXGI error...
{
// This situation occurs on Windows 7. You can't use FORMAT_MESSAGE_FROM_HMODULE to solve it
// either. We can only use DXGetErrorString or manually handle it.
const wchar_t* pStr = OVR_DXGetErrorStringW(sysErrorCode);
if (pStr) {
wcscpy_s(errorBufferW, OVR_ARRAY_COUNT(errorBufferW), pStr);
length = (DWORD)wcslen(errorBufferW);
}
}
}
if (length) // If errorBufferW contains what we are looking for...
{
// Need to convert WCHAR errorBuffer to UTF8 char sResult;
const auto requiredUTF8Length =
OVR::UTF8Util::Strlcpy(errorBuffer, OVR_ARRAY_COUNT(errorBuffer), errorBufferW);
if (requiredUTF8Length >=
OVR_ARRAY_COUNT(errorBuffer)) // Zero out if too big (XXX truncate instead?)
errorBuffer[0] = '\0';
// Else fall through
} // Else fall through
#else
#if (((_POSIX_C_SOURCE >= 200112L) || (_XOPEN_SOURCE >= 600)) && !_GNU_SOURCE) || \
defined(__APPLE__) || defined(__BSD__)
const int result = strerror_r((int)sysErrorCode, errorBuffer, OVR_ARRAY_COUNT(errorBuffer));
if (result != 0) // If failed... [result is 0 upon success; result will be EINVAL if the code is
// not recognized; ERANGE if buffer didn't have enough capacity.]
errorBuffer[0] = '\0'; // re-null-terminate, in case strerror_r left it in an invalid state.
#else
const char* result = strerror_r((int)sysErrorCode, errorBuffer, OVR_ARRAY_COUNT(errorBuffer));
if (result ==
nullptr) // Implementations in practice seem to always return a pointer, though the
// behavior isn't formally standardized.
errorBuffer[0] = '\0'; // re-null-terminate, in case strerror_r left it in an invalid state.
#endif
#endif
}
// Fall through functionality of simply printing the value as an integer.
if (errorBuffer[0]) // If errorBuffer was successfully written above...
{
sResult += errorBuffer;
return true;
}
sResult += "(unknown)"; // This is not localized. Question: Is there a way to get the error
// formatting functions above to print this themselves in a localized way?
return false;
}
} // namespace OVR

View File

@ -0,0 +1,802 @@
/************************************************************************************
Filename : OVR_Error.h
Content : Structs and functions for handling OVRErrors
Created : February 15, 2015
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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.
************************************************************************************/
#pragma once
#include "Kernel/OVR_Log.h"
#include "Kernel/OVR_String.h"
#include "Kernel/OVR_Array.h"
#include "Kernel/OVR_System.h"
#include "Kernel/OVR_Threads.h"
#include "Kernel/OVR_Hash.h"
#include <chrono>
#include <utility>
#include <functional>
OVR_DISABLE_MSVC_WARNING(4351) // new behavior: elements of array will be default initialized
#ifndef OVR_RESULT_DEFINED
#define OVR_RESULT_DEFINED ///< Allows ovrResult to be independently defined.
/// API call results are represented at the highest level by a single ovrResult.
typedef int32_t ovrResult;
#endif
/// \brief Indicates if an ovrResult indicates success.
///
/// Some functions return additional successful values other than ovrSucces and
/// require usage of this macro to indicate successs.
///
#if !defined(OVR_SUCCESS)
#define OVR_SUCCESS(result) (result >= 0)
#endif
/// \brief Indicates if an ovrResult indicates an unqualified success.
///
/// This is useful for indicating that the code intentionally wants to
/// check for result == ovrSuccess as opposed to OVR_SUCCESS(), which
/// checks for result >= ovrSuccess.
///
#if !defined(OVR_UNQUALIFIED_SUCCESS)
#define OVR_UNQUALIFIED_SUCCESS(result) (result == ovrSuccess)
#endif
/// \brief Indicates if an ovrResult indicates failure.
///
#if !defined(OVR_FAILURE)
#define OVR_FAILURE(result) (!OVR_SUCCESS(result))
#endif
// Success is a value greater or equal to 0, while all error types are negative values.
#ifndef OVR_SUCCESS_DEFINED
#define OVR_SUCCESS_DEFINED ///< Allows ovrResult to be independently defined.
typedef enum ovrSuccessType_ {
/// This is a general success result. Use OVR_SUCCESS to test for success.
ovrSuccess = 0,
} ovrSuccessType;
#endif
/// -----------------------------------------------------------------------------
/// ***** OVR_FILE / OVR_LINE
///
#if !defined(OVR_FILE)
#if defined(OVR_BUILD_DEBUG)
#define OVR_FILE __FILE__
#define OVR_LINE __LINE__
#else
#define OVR_FILE nullptr
#define OVR_LINE 0
#endif
#endif
// LOG_VAARG_ATTRIBUTE macro, enforces printf-style formatting 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
namespace OVR {
/// -----------------------------------------------------------------------------
/// ***** OVR_MAKE_ERROR, OVR_MAKE_ERROR_F, OVR_MAKE_SYS_ERROR, OVR_MAKE_SYS_ERROR_F
///
/// Declaration:
/// OVRError OVR_MAKE_ERROR(ovrResult r, const char* description);
/// OVRError OVR_MAKE_ERROR_F(ovrResult r, const char* format, ...);
///
/// OVRError OVR_MAKE_SYS_ERROR(ovrResult r, ovrSysErrorCode sysCode, const char* description);
/// OVRError OVR_MAKE_SYS_ERROR_F(ovrResult r, ovrSysErrorCode sysCode, const char* format, ...);
///
/// Example usage:
/// OVRError InitGraphics()
/// {
/// if(!GraphicsCardPresent())
/// {
/// return OVR_MAKE_ERROR(ovrError_GraphicsInit, "Failed to init graphics; graphics
/// support absent.");
/// }
///
/// HRESULT hr = pDevice->CreateTexture2D(&dsDesc, nullptr, &Texture);
/// if(FAILED(hr))
/// {
/// return OVR_MAKE_SYS_ERROR_F(ovrError_GraphicsInit, hr, "Failed to create texture of
/// size %u x %u", dsDesc.Width, dsDesc.Height);
/// }
/// or:
/// OVR_HR_CHECK_RET_ERROR(ovrError_GraphicsInit, hr, "Failed to create texture of size
/// %u x %u", dsDesc.Width, dsDesc.Height);
///
/// return ovrSuccess; // Converts to an OVRError instance that has no error.
/// }
///
#define OVR_MAKE_ERROR(errorCode, pDescription) \
OVR::MakeError( \
(errorCode), \
OVR::ovrSysErrorCodeType::None, \
OVR::ovrSysErrorCodeSuccess, \
nullptr, \
OVR_FILE, \
OVR_LINE, \
true, \
true, \
nullptr, \
"%s", \
(pDescription))
// Note: The format string is the first part of the .../__VA_ARGS__ as per the C99-C++11 Standards.
#define OVR_MAKE_ERROR_F(errorCode, ...) \
OVR::MakeError( \
(errorCode), \
OVR::ovrSysErrorCodeType::None, \
OVR::ovrSysErrorCodeSuccess, \
nullptr, \
OVR_FILE, \
OVR_LINE, \
true, \
true, \
nullptr, \
__VA_ARGS__)
#define OVR_MAKE_SYS_ERROR(errorCode, sysErrorCode, pDescription) \
OVR::MakeError( \
(errorCode), \
OVR::ovrSysErrorCodeType::OS, \
(sysErrorCode), \
nullptr, \
OVR_FILE, \
OVR_LINE, \
true, \
true, \
nullptr, \
"%s", \
(pDescription))
// Note: The format string is the first part of the .../__VA_ARGS__ as per the C99-C++11 Standards.
#define OVR_MAKE_SYS_ERROR_F(errorCode, sysErrorCode, ...) \
OVR::MakeError( \
(errorCode), \
OVR::ovrSysErrorCodeType::OS, \
(sysErrorCode), \
nullptr, \
OVR_FILE, \
OVR_LINE, \
true, \
true, \
nullptr, \
__VA_ARGS__)
#define OVR_MAKE_VULKAN_ERROR(errorCode, sysErrorCode, pDescription) \
OVR::MakeError( \
(errorCode), \
OVR::ovrSysErrorCodeType::Vulkan, \
(sysErrorCode), \
nullptr, \
OVR_FILE, \
OVR_LINE, \
true, \
true, \
nullptr, \
"%s", \
(pDescription))
// Note: The format string is the first part of the .../__VA_ARGS__ as per the C99-C++11 Standards.
#define OVR_MAKE_VULKAN_ERROR_F(errorCode, sysErrorCode, ...) \
OVR::MakeError( \
(errorCode), \
OVR::ovrSysErrorCodeType::Vulkan, \
(sysErrorCode), \
nullptr, \
OVR_FILE, \
OVR_LINE, \
true, \
true, \
nullptr, \
__VA_ARGS__)
#define OVR_MAKE_OPENGL_ERROR(errorCode, sysErrorCode, pDescription) \
OVR::MakeError( \
(errorCode), \
OVR::ovrSysErrorCodeType::OpenGL, \
(sysErrorCode), \
nullptr, \
OVR_FILE, \
OVR_LINE, \
true, \
true, \
nullptr, \
"%s", \
(pDescription))
// Note: The format string is the first part of the .../__VA_ARGS__ as per the C99-C++11 Standards.
#define OVR_MAKE_OPENGL_ERROR_F(errorCode, sysErrorCode, ...) \
OVR::MakeError( \
(errorCode), \
OVR::ovrSysErrorCodeType::OpenGL, \
(sysErrorCode), \
nullptr, \
OVR_FILE, \
OVR_LINE, \
true, \
true, \
nullptr, \
__VA_ARGS__)
// Consider using OVR_MAKE_QUIET_ERROR() instead of OVR_MAKE_ERROR() where the error
// should not automatically log/assert. If the error is normal (HMD unplugged) or
// repetitive then please use OVR_MAKE_QUIET_ERROR().
#define OVR_MAKE_QUIET_ERROR(errorCode, pDescription) \
OVR::MakeError( \
(errorCode), \
OVR::ovrSysErrorCodeType::None, \
OVR::ovrSysErrorCodeSuccess, \
nullptr, \
OVR_FILE, \
OVR_LINE, \
false, \
false, \
nullptr, \
"%s", \
(pDescription))
// Note: The format string is the first part of the .../__VA_ARGS__ as per the C99-C++11 Standards.
#define OVR_MAKE_QUIET_ERROR_F(errorCode, ...) \
OVR::MakeError( \
(errorCode), \
OVR::ovrSysErrorCodeType::None, \
OVR::ovrSysErrorCodeSuccess, \
nullptr, \
OVR_FILE, \
OVR_LINE, \
false, \
false, \
nullptr, \
__VA_ARGS__)
#define OVR_MAKE_QUIET_SYS_ERROR(errorCode, sysErrorCode, pDescription) \
OVR::MakeError( \
(errorCode), \
OVR::ovrSysErrorCodeType::OS, \
(sysErrorCode), \
nullptr, \
OVR_FILE, \
OVR_LINE, \
false, \
false, \
nullptr, \
"%s", \
(pDescription))
// Note: The format string is the first part of the .../__VA_ARGS__ as per the C99-C++11 Standards.
#define OVR_MAKE_QUIET_SYS_ERROR_F(errorCode, sysErrorCode, ...) \
OVR::MakeError( \
(errorCode), \
ovrSysErrorCodeType::OS, \
(sysErrorCode), \
nullptr, \
OVR_FILE, \
OVR_LINE, \
false, \
false, \
nullptr, \
__VA_ARGS__)
// Consider using OVR_MAKE_NOASSERT_ERROR() instead of OVR_MAKE_ERROR() where the error
// should not automatically log/assert. If the error is normal (HMD unplugged) or
// repetitive then please use OVR_MAKE_NOASSERT_ERROR().
#define OVR_MAKE_NOASSERT_ERROR(errorCode, pDescription) \
OVR::MakeError( \
(errorCode), \
OVR::ovrSysErrorCodeType::None, \
OVR::ovrSysErrorCodeSuccess, \
nullptr, \
OVR_FILE, \
OVR_LINE, \
true, \
false, \
nullptr, \
"%s", \
(pDescription))
// Note: The format string is the first part of the .../__VA_ARGS__ as per the C99-C++11 Standards.
#define OVR_MAKE_NOASSERT_ERROR_F(errorCode, ...) \
OVR::MakeError( \
(errorCode), \
OVR::ovrSysErrorCodeType::None, \
OVR::ovrSysErrorCodeSuccess, \
nullptr, \
OVR_FILE, \
OVR_LINE, \
true, \
false, \
nullptr, \
__VA_ARGS__)
#define OVR_MAKE_NOASSERT_SYS_ERROR(errorCode, sysErrorCode, pDescription) \
OVR::MakeError( \
(errorCode), \
OVR::ovrSysErrorCodeType::OS, \
(sysErrorCode), \
nullptr, \
OVR_FILE, \
OVR_LINE, \
true, \
false, \
nullptr, \
"%s", \
(pDescription))
// Note: The format string is the first part of the .../__VA_ARGS__ as per the C99-C++11 Standards.
#define OVR_MAKE_NOASSERT_SYS_ERROR_F(errorCode, sysErrorCode, ...) \
OVR::MakeError( \
(errorCode), \
OVR::ovrSysErrorCodeType::OS, \
(sysErrorCode), \
nullptr, \
OVR_FILE, \
OVR_LINE, \
true, \
false, \
nullptr, \
__VA_ARGS__)
// Set the TLS last error:
#define OVR_SET_ERROR(ovrError) OVR::SetError(ovrError)
// Log the error if it has not already been logged:
#define OVR_LOG_ERROR(ovrError) OVR::LogError(ovrError)
// Check an HRESULT error code and assert/log on failure:
#define OVR_HR_CHECK_RET_ERROR(errorCode, sysErrorCode, pDescription) \
if (FAILED(sysErrorCode)) { \
return OVR_MAKE_SYS_ERROR_F((errorCode), (sysErrorCode), "%s", (pDescription)); \
}
// Note: The format string is the first part of the .../__VA_ARGS__ as per the C99-C++11 Standards.
#define OVR_HR_CHECK_RET_ERROR_F(errorCode, sysErrorCode, ...) \
if (FAILED(sysErrorCode)) { \
return OVR_MAKE_SYS_ERROR_F((errorCode), (sysErrorCode), __VA_ARGS__); \
}
/// -----------------------------------------------------------------------------
/// ***** ovrSysErrorCodeType
///
enum class ovrSysErrorCodeType {
None,
OS, /// Windows: HRESULT or DWORD system error code from GetLastError.
ALVR, /// AMD LiquidVR error
NVAPI, /// NVidia API error
NVENC, /// NVidia video encode API error
Vulkan, /// Vulkan graphics API
OpenGL /// OpenGL graphics API
};
/// -----------------------------------------------------------------------------
/// ***** ovrSysErrorCode
///
/// Identifies a platform- or API-specific error identifier.
/// The error space is identified by ovrSysErrorCodeType.
///
typedef uint32_t ovrSysErrorCode;
/// -----------------------------------------------------------------------------
/// ***** ovrSysErrorCodeSuccess
///
/// Identifies a ovrSysErrorCode that's success.
///
const ovrSysErrorCode ovrSysErrorCodeSuccess = 0;
/// -----------------------------------------------------------------------------
/// ***** ovrSysErrorCodeNone
///
/// Identifies a ovrSysErrorCode that's un-set.
///
const ovrSysErrorCode ovrSysErrorCodeNone = 0;
// SysClockTime is a C++11 equivalent to C time_t.
typedef std::chrono::time_point<std::chrono::system_clock> SysClockTime;
/// -----------------------------------------------------------------------------
/// ***** OVRError
///
/// Represents an error and relevant information about it.
/// While you can create error instances directly via this class, it's better if
/// you create them via the OVR_MAKE_ERROR family of macros, or at least via the
/// MakeError function.
///
/// Relevant design analogues:
/// https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSError_Class/
/// https://msdn.microsoft.com/en-us/library/windows/desktop/ms723041%28v=vs.85%29.aspx
///
class OVRError {
private:
// Cannot convert boolean to OVRError - It must be done explicitly.
OVRError(bool) {
OVR_ASSERT(false);
}
OVRError(bool, const char*, ...) {
OVR_ASSERT(false);
}
public:
OVRError();
OVRError(ovrResult code); // Intentionally not explicit.
OVRError(ovrResult code, const char* pFormat, ...);
OVRError(const OVRError& OVRError);
OVRError(OVRError&& OVRError);
virtual ~OVRError();
// Construct a success code. Use Succeeded() to check for success.
static OVRError Success() {
return OVRError();
}
OVRError& operator=(const OVRError& OVRError);
OVRError& operator=(OVRError&& OVRError);
// Use this to check if result is a success code
bool Succeeded() const {
return Code >= ovrSuccess;
}
bool Failed() const {
return !Succeeded();
}
// Sets the OVRTime, ClockTime, Backtrace to current values.
void SetCurrentValues(); // To do: Come up with a more appropiate name.
// Clears all members to a newly default-constructed state.
void Reset();
// Get the full error string for this error. May include newlines.
String GetErrorString() const;
// Property accessors
void SetCode(ovrResult code);
ovrResult GetCode() const;
// Example usage:
// ovrResult SomeFunction() {
// OVRError err = SomeOtherFunction();
// return err;
// }
operator ovrResult() const {
return Code;
}
void SetSysCode(
ovrSysErrorCodeType sysCodeType,
ovrSysErrorCode sysCode,
const char* sysCodeString = nullptr);
ovrSysErrorCodeType GetSysCodeType() const;
ovrSysErrorCode GetSysCode() const;
void SetDescription(const char* pDescription);
String GetDescription() const;
void SetContext(const char* pContext);
String GetContext() const;
void SetOVRTime(double ovrTime);
double GetOVRTime() const;
void SetSysClockTime(const SysClockTime& clockTime);
SysClockTime GetSysClockTime() const;
static const int64_t kLogLineUnset = -1;
void SetLogLine(int64_t logLine);
int64_t GetLogLine() const;
bool IsAlreadyLogged() const {
return AlreadyLogged;
}
void SetAlreadyLogged() {
AlreadyLogged = true;
}
void ResetAlreadyLogged() {
AlreadyLogged = false;
}
void SetSource(const char* pSourceFilePath, int sourceFileLine);
std::pair<String, int> GetSource() const;
typedef OVR::Array<void*> AddressArray;
AddressArray GetBacktrace() const;
static void RegisterResultCodeName(ovrResult number, const char* name);
protected:
mutable StringBuffer ErrorString; /// Complete error string describing the variables below.
ovrResult Code; /// The main ovrResult, which is a high level error id.
ovrSysErrorCodeType SysCodeType;
ovrSysErrorCode SysCode; /// ovrSysErrorCodeSuccess means no system error code.
char SysCodeStr[64]; /// String describing just the sys code error.
String Description; /// Unlocalized error description string.
String Context; /// Context string. For example, for a file open failure this is the file path.
double OVRTime; /// Time when the error was generated. Same format as OVR time.
SysClockTime ClockTime; /// Wall clock time.
int64_t LogLine; /// Log line of the error. -1 if not set (not logged).
String SourceFilePath; /// The __FILE__ where the error was first encountered.
int SourceFileLine; /// The __LINE__ where the error was first encountered.
AddressArray Backtrace; /// Backtrace at point of error. May be empty in publicly released builds.
bool AlreadyLogged; /// Error has already been logged to avoid double-printing it.
};
/// -----------------------------------------------------------------------------
/// ***** SetError
///
/// This function sets the error as the last error via the TLS last error class.
///
void SetError(OVRError& ovrError);
/// -----------------------------------------------------------------------------
/// ***** LogError
///
/// Utility function for logging an error based on the Log subsystem.
///
void LogError(OVRError& ovrError);
/// -----------------------------------------------------------------------------
/// ***** MakeError
///
/// Utility function for making an error, logging it, and setting it as the last error for the
/// current thread. It's preferred to instead use the OVR_MAKE_ERROR macro functions, as they handle
/// file/line functionality cleanly between debug and release. The "quiet" parameter will prevent it
/// from automatically logging/asserting.
///
OVRError MakeError(
ovrResult errorCode,
ovrSysErrorCodeType sysCodeType,
ovrSysErrorCode sysCode,
const char* sysCodeString, // Optional pre-generated sys error code string.
const char* pSourceFile,
int sourceLine,
bool logError,
bool assertError,
const char* pContext,
const char* pDescriptionFormat,
...) OVR_LOG_VAARG_ATTRIBUTE(8, 9);
// -----------------------------------------------------------------------------
// ***** LastErrorTLS
//
// We don't use C++11 thread-local storage nor C-style __thread/__declsped(thread)
// to manager thread-local storage, as neither of these provide a means for us
// to control the lifetime of the data. Rather it can be controlled only
// passively by the thread's lifetime. Similarly we don't use pthread_getspecific
// pthread_setspecific (and Windows equivalents) because they too don't let us
// control the lifetime of the data. Our solution is to have a map of threads
// to thread-specific data, and we can clear the entire map on ovrShutdown as-needed.
// this scheme is not as fast as the aforementioned schemes but it doesn't need to
// be fast for our use.
//
// We use pointers below instead of concrete objects because we want to have their
// lifetimes entirely controlled by ovr_Initialize/ovr_Shutdown.
class LastErrorTLS : public NewOverrideBase, public SystemSingletonBase<LastErrorTLS> {
OVR_DECLARE_SINGLETON(LastErrorTLS);
public:
OVRError& LastError();
protected:
// Protect hash from multiple thread access.
Lock TheLock;
// Map thread-id to OVRError objects.
typedef Hash<ThreadId, OVRError> TLSHash;
TLSHash TLSDictionary;
};
/// -----------------------------------------------------------------------------
/// ***** GetErrorCodeName
///
/// Utility function which converts an ovrResult error code to a string which matches
/// errorCode's ovrResult enumeration identifier.
///
const char* GetErrorCodeName(ovrResult errorCode);
/// -----------------------------------------------------------------------------
/// ***** GetErrorCodeString
///
/// Utility function which converts an ovrResult error code to a readable string version.
///
bool GetErrorCodeString(ovrResult errorCode, bool prefixErrorCode, OVR::String& sResult);
/// -----------------------------------------------------------------------------
/// ***** GetSysErrorCodeString
///
/// Utility function which converts a system error to a string. Similar to the Windows FormatMessage
/// function and the Unix strerror_r function.
/// If prefixErrorCode is true then the string is prefixed with "<code>: "
/// Returns true if the sysErrorCode was a known valid code and a string was produced from it.
/// Else the returned string will be empty. The returned string may have tabs or newlines.
/// Users of OVR_MAKE_SYS_ERROR and MakeError don't need to call this function, as it's done
/// automatically internally.
///
bool GetSysErrorCodeString(
ovrSysErrorCodeType sysErrorCodeType,
ovrSysErrorCode sysErrorCode,
bool prefixErrorCode,
OVR::String& sResult);
//-------------------------------------------------------------------------------------
// C++ Exception state
// CPPExceptionInfo contains information about a possible exception state for the current library.
// We cannot safely use the OVRError system for this, as it could fail when we are in an exceptional
// state. It would be a non-trivial effort to make the OVRError system work in a way that doesn't
// allocate memory, for various reasons.
struct CPPExceptionInfo {
CPPExceptionInfo() OVR_NOEXCEPT : ExceptionOccurred(false), Description() {}
void Reset() OVR_NOEXCEPT {
ExceptionOccurred = false;
Description[0] = '\0';
}
void FromStdException(const std::exception& e) OVR_NOEXCEPT {
ExceptionOccurred = true;
OVR_strlcpy(Description, e.what(), sizeof(Description));
}
void FromString(const char* str) OVR_NOEXCEPT {
ExceptionOccurred = true;
OVR_strlcpy(Description, str, sizeof(Description));
}
// If this get set to true then it should never be set back to false
// except by an unloading of the module (i.e. DLL) itself.
bool ExceptionOccurred;
// Describes the exception in a way that makes no external calls
// nor allocates any memory.
char Description[256];
};
extern OVR::CPPExceptionInfo gCPPExceptionInfo;
// Helper macros to make repetitive exception handling tasks non-redundant.
//
// Example usage:
// OVR_PUBLIC_FUNCTION(void) ovr_DoSomething(ovrSession session)
// {
// OVR_CAPI_TRY_VOID
// {
// HMDState* hmds = GetHMDStateFromOvrHmd(session);
// if (hmds)
// hmds->DoSomething();
// }
// OVR_CAPI_CATCH
// }
//
// OVR_PUBLIC_FUNCTION(int) ovr_DoSomething(ovrSession session)
// {
// int result = 0;
//
// OVR_CAPI_TRY_VALUE(result)
// {
// HMDState* hmds = GetHMDStateFromOvrHmd(session);
// if (hmds)
// result = hmds->DoSomething;
// }
// OVR_CAPI_CATCH
//
// return result;
// }
//
// OVR_PUBLIC_FUNCTION(ovrResult) ovr_DoSomething(ovrSession session)
// {
// OVR_CAPI_TRY_OVRRESULT
// {
// HMDState* pState = GetHMDStateFromOvrHmd(session);
// if (!pState)
// {
// OVR_MAKE_ERROR(ovrError_InvalidSession, L"Invalid session.");
// return ovrError_InvalidSession;
// }
// return hmds->DoSomething();
// }
// OVR_CAPI_CATCH
//
// return ovrError_CPPException;
// }
#if defined(OVR_BUILD_DEBUG)
#define OVR_CAPI_TRY_VOID \
do { \
} while (false);
#define OVR_CAPI_TRY_VALUE(exceptionStateReturnValue) \
do { \
} while (false);
#define OVR_CAPI_TRY_OVRRESULT \
do { \
} while (false);
#define OVR_CAPI_CATCH \
do { \
} while (false);
#else // OVR_BUILD_DEBUG
#define OVR_CAPI_TRY_VOID \
if (OVR::gCPPExceptionInfo.ExceptionOccurred) \
return; \
try
#define OVR_CAPI_TRY_VALUE(exceptionStateReturnValue) \
if (OVR::gCPPExceptionInfo.ExceptionOccurred) \
return exceptionStateReturnValue; \
try
#define OVR_CAPI_TRY_OVRRESULT \
if (OVR::gCPPExceptionInfo.ExceptionOccurred) \
return ovrError_RuntimeException; \
try
#define OVR_CAPI_CATCH \
catch (const std::exception& e) { \
OVR::gCPPExceptionInfo.FromStdException(e); \
} \
catch (...) { \
OVR::gCPPExceptionInfo.FromString("Non-standard C++ exception occurred."); \
}
#endif // OVR_BUILD_DEBUG
/// -----------------------------------------------------------------------------
/// ***** OVRErrorCallback
///
/// Identifies a callback error handler.
/// Callbacks were added instead of integrating logic directly in OVRError
/// to make application specific logic easier
///
typedef std::function<void(const OVRError& err, bool quiet)> OVRErrorCallback;
/// -----------------------------------------------------------------------------
/// ***** SetErrorCallback
///
/// Sets callback to be issued whenever an error is encountered.
///
void SetErrorCallback(OVRErrorCallback callback);
} // namespace OVR
#ifndef MICRO_OVR
namespace ovrlog {
template <>
LOGGING_INLINE void LogStringize(LogStringBuffer& buffer, const OVR::OVRError& first) {
buffer.Stream << first.GetErrorString().ToCStr();
}
} // namespace ovrlog
#endif

View File

@ -0,0 +1,521 @@
/**************************************************************************
Filename : OVR_File.cpp
Content : File wrapper class implementation (Win32)
Created : April 5, 1999
Authors : Michael Antonov
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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 = (uint8_t*)OVR_ALLOC(FILEBUFFER_SIZE);
BufferMode = NoBuffer;
FilePos = 0;
Pos = 0;
DataSize = 0;
}
// Takes another file as source
BufferedFile::BufferedFile(File* pfile) : DelegatedFile(pfile) {
pBuffer = (uint8_t*)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;
}
int64_t BufferedFile::LTell() {
if (BufferMode == ReadBuffer)
return FilePos - DataSize + Pos;
int64_t 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;
}
int64_t BufferedFile::LGetLength() {
int64_t len = pFile->LGetLength();
// If writing through buffer, file length may actually be bigger
if ((len != -1) && (BufferMode == WriteBuffer)) {
int64_t 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)
{
int64_t 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 uint8_t* 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(uint8_t* 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_t)offset) < ~(uint64_t)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_t)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);
}
int64_t BufferedFile::LSeek(int64_t 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 int64_t(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 = (int64_t)(FilePos - DataSize + Pos) + offset;
Pos = DataSize = 0;
} else if (origin == Seek_Set) {
if (((uint64_t)offset - (FilePos - DataSize)) <= DataSize) {
Pos = (unsigned)((uint64_t)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 >= int64_t(FilePos - DataSize) && offset <
int64_t(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
uint8_t* buff = new uint8_t[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;
}
delete[] buff;
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) {
size_t len = OVR_strlen(purl);
for (size_t i = len; i > 0; i--)
if (purl[i] == '\\' || purl[i] == '/')
return purl + i + 1;
return purl;
}
} // namespace OVR

View File

@ -0,0 +1,695 @@
/************************************************************************************
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 (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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 {
//-----------------------------------------------------------------------------------
// ***** OVR_MAX_PATH
//
// Max file path length (for most uses).
// To do: move this to OVR_File.
//
#if !defined(OVR_MAX_PATH)
#if defined( \
_WIN32) // http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx
#define OVR_MAX_PATH \
MAX_PATH // Windows can use paths longer than MAX_PATH in some cases (network paths, UNC paths).
#else
#define OVR_MAX_PATH 1024 // This isn't a strict limit on all Unix-based platforms.
#endif
#endif
// ***** 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 int64_t LTell() = 0;
// File size
virtual int GetLength() = 0;
virtual int64_t 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 uint8_t* 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(uint8_t* 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 int64_t LSeek(int64_t 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_t PRead64() {
uint64_t v = 0;
Read((uint8_t*)&v, 8);
return v;
}
uint32_t PRead32() {
uint32_t v = 0;
Read((uint8_t*)&v, 4);
return v;
}
uint16_t PRead16() {
uint16_t v = 0;
Read((uint8_t*)&v, 2);
return v;
}
uint8_t PRead8() {
uint8_t v = 0;
Read((uint8_t*)&v, 1);
return v;
}
void PWrite64(uint64_t v) {
Write((uint8_t*)&v, 8);
}
void PWrite32(uint32_t v) {
Write((uint8_t*)&v, 4);
}
void PWrite16(uint16_t v) {
Write((uint8_t*)&v, 2);
}
void PWrite8(uint8_t v) {
Write((uint8_t*)&v, 1);
}
public:
// Writing primitive types - Little Endian
inline void WriteUByte(uint8_t v) {
PWrite8((uint8_t)Alg::ByteUtil::SystemToLE(v));
}
inline void WriteSByte(int8_t v) {
PWrite8((uint8_t)Alg::ByteUtil::SystemToLE(v));
}
inline void WriteUInt8(uint8_t v) {
PWrite8((uint8_t)Alg::ByteUtil::SystemToLE(v));
}
inline void WriteSInt8(int8_t v) {
PWrite8((uint8_t)Alg::ByteUtil::SystemToLE(v));
}
inline void WriteUInt16(uint16_t v) {
PWrite16((uint16_t)Alg::ByteUtil::SystemToLE(v));
}
inline void WriteSInt16(int16_t v) {
PWrite16((uint16_t)Alg::ByteUtil::SystemToLE(v));
}
inline void WriteUInt32(uint32_t v) {
PWrite32((uint32_t)Alg::ByteUtil::SystemToLE(v));
}
inline void WriteSInt32(int32_t v) {
PWrite32((uint32_t)Alg::ByteUtil::SystemToLE(v));
}
inline void WriteUInt64(uint64_t v) {
PWrite64((uint64_t)Alg::ByteUtil::SystemToLE(v));
}
inline void WriteSInt64(int64_t v) {
PWrite64((uint64_t)Alg::ByteUtil::SystemToLE(v));
}
inline void WriteFloat(float v) {
v = Alg::ByteUtil::SystemToLE(v);
Write((uint8_t*)&v, 4);
}
inline void WriteDouble(double v) {
v = Alg::ByteUtil::SystemToLE(v);
Write((uint8_t*)&v, 8);
}
// Writing primitive types - Big Endian
inline void WriteUByteBE(uint8_t v) {
PWrite8((uint8_t)Alg::ByteUtil::SystemToBE(v));
}
inline void WriteSByteBE(int8_t v) {
PWrite8((uint8_t)Alg::ByteUtil::SystemToBE(v));
}
inline void WriteUInt8BE(uint16_t v) {
PWrite8((uint8_t)Alg::ByteUtil::SystemToBE(v));
}
inline void WriteSInt8BE(int16_t v) {
PWrite8((uint8_t)Alg::ByteUtil::SystemToBE(v));
}
inline void WriteUInt16BE(uint16_t v) {
PWrite16((uint16_t)Alg::ByteUtil::SystemToBE(v));
}
inline void WriteSInt16BE(uint16_t v) {
PWrite16((uint16_t)Alg::ByteUtil::SystemToBE(v));
}
inline void WriteUInt32BE(uint32_t v) {
PWrite32((uint32_t)Alg::ByteUtil::SystemToBE(v));
}
inline void WriteSInt32BE(uint32_t v) {
PWrite32((uint32_t)Alg::ByteUtil::SystemToBE(v));
}
inline void WriteUInt64BE(uint64_t v) {
PWrite64((uint64_t)Alg::ByteUtil::SystemToBE(v));
}
inline void WriteSInt64BE(uint64_t v) {
PWrite64((uint64_t)Alg::ByteUtil::SystemToBE(v));
}
inline void WriteFloatBE(float v) {
v = Alg::ByteUtil::SystemToBE(v);
Write((uint8_t*)&v, 4);
}
inline void WriteDoubleBE(double v) {
v = Alg::ByteUtil::SystemToBE(v);
Write((uint8_t*)&v, 8);
}
// Reading primitive types - Little Endian
inline uint8_t ReadUByte() {
return (uint8_t)Alg::ByteUtil::LEToSystem(PRead8());
}
inline int8_t ReadSByte() {
return (int8_t)Alg::ByteUtil::LEToSystem(PRead8());
}
inline uint8_t ReadUInt8() {
return (uint8_t)Alg::ByteUtil::LEToSystem(PRead8());
}
inline int8_t ReadSInt8() {
return (int8_t)Alg::ByteUtil::LEToSystem(PRead8());
}
inline uint16_t ReadUInt16() {
return (uint16_t)Alg::ByteUtil::LEToSystem(PRead16());
}
inline int16_t ReadSInt16() {
return (int16_t)Alg::ByteUtil::LEToSystem(PRead16());
}
inline uint32_t ReadUInt32() {
return (uint32_t)Alg::ByteUtil::LEToSystem(PRead32());
}
inline int32_t ReadSInt32() {
return (int32_t)Alg::ByteUtil::LEToSystem(PRead32());
}
inline uint64_t ReadUInt64() {
return (uint64_t)Alg::ByteUtil::LEToSystem(PRead64());
}
inline int64_t ReadSInt64() {
return (int64_t)Alg::ByteUtil::LEToSystem(PRead64());
}
inline float ReadFloat() {
float v = 0.0f;
Read((uint8_t*)&v, 4);
return Alg::ByteUtil::LEToSystem(v);
}
inline double ReadDouble() {
double v = 0.0;
Read((uint8_t*)&v, 8);
return Alg::ByteUtil::LEToSystem(v);
}
// Reading primitive types - Big Endian
inline uint8_t ReadUByteBE() {
return (uint8_t)Alg::ByteUtil::BEToSystem(PRead8());
}
inline int8_t ReadSByteBE() {
return (int8_t)Alg::ByteUtil::BEToSystem(PRead8());
}
inline uint8_t ReadUInt8BE() {
return (uint8_t)Alg::ByteUtil::BEToSystem(PRead8());
}
inline int8_t ReadSInt8BE() {
return (int8_t)Alg::ByteUtil::BEToSystem(PRead8());
}
inline uint16_t ReadUInt16BE() {
return (uint16_t)Alg::ByteUtil::BEToSystem(PRead16());
}
inline int16_t ReadSInt16BE() {
return (int16_t)Alg::ByteUtil::BEToSystem(PRead16());
}
inline uint32_t ReadUInt32BE() {
return (uint32_t)Alg::ByteUtil::BEToSystem(PRead32());
}
inline int32_t ReadSInt32BE() {
return (int32_t)Alg::ByteUtil::BEToSystem(PRead32());
}
inline uint64_t ReadUInt64BE() {
return (uint64_t)Alg::ByteUtil::BEToSystem(PRead64());
}
inline int64_t ReadSInt64BE() {
return (int64_t)Alg::ByteUtil::BEToSystem(PRead64());
}
inline float ReadFloatBE() {
float v = 0.0f;
Read((uint8_t*)&v, 4);
return Alg::ByteUtil::BEToSystem(v);
}
inline double ReadDoubleBE() {
double v = 0.0;
Read((uint8_t*)&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 int64_t LTell() {
return pFile->LTell();
}
virtual int GetLength() {
return pFile->GetLength();
}
virtual int64_t 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 uint8_t* pbuffer, int numBytes) {
return pFile->Write(pbuffer, numBytes);
}
virtual int Read(uint8_t* 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 int64_t LSeek(int64_t 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
uint8_t* pBuffer;
BufferModeType BufferMode;
// Position in buffer
unsigned Pos;
// Data in buffer if reading
unsigned DataSize;
// Underlying file position
uint64_t 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();
BufferedFile(const BufferedFile&)
: DelegatedFile(), pBuffer(NULL), BufferMode(NoBuffer), Pos(0), DataSize(0), FilePos(0) {}
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 int64_t LTell();
virtual int GetLength();
virtual int64_t LGetLength();
// virtual bool Stat(GFileStats *pfs);
virtual int Write(const uint8_t* pbufer, int numBytes);
virtual int Read(uint8_t* pbufer, int numBytes);
virtual int SkipBytes(int numBytes);
virtual int BytesAvailable();
virtual bool Flush();
virtual int Seek(int offset, int origin = Seek_Set);
virtual int64_t LSeek(int64_t 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;
}
int64_t LTell() {
return (int64_t)FileIndex;
}
int GetLength() {
return FileSize;
}
int64_t LGetLength() {
return (int64_t)FileSize;
}
bool Close() {
Valid = false;
return false;
}
int CopyFromStream(File* pstream, int byteSize) {
OVR_UNUSED2(pstream, byteSize);
return 0;
}
int Write(const uint8_t* pbuffer, int numBytes) {
OVR_UNUSED2(pbuffer, numBytes);
return 0;
}
int Read(uint8_t* 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;
}
int64_t LSeek(int64_t offset, int origin = Seek_Set) {
return (int64_t)Seek((int)offset, origin);
}
public:
MemoryFile(const String& fileName, const uint8_t* 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 uint8_t* pBuffer, int buffSize) : FilePath(pfileName) {
FileData = pBuffer;
FileSize = buffSize;
FileIndex = 0;
Valid = (pfileName && pBuffer && buffSize > 0) ? true : false;
}
private:
String FilePath;
const uint8_t* 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);
} // namespace OVR
#endif

View File

@ -0,0 +1,576 @@
/**************************************************************************
Filename : OVR_FileFILE.cpp
Content : File wrapper class implementation (Win32)
Created : April 5, 1999
Authors : Michael Antonov
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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;
};
#if defined(OVR_CC_MSVC)
#include "share.h"
#endif
#if defined(OVR_OS_WIN32)
#include "OVR_Win32_IncludeWindows.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 = TRUE;
OldMode = ::SetErrorMode(SEM_FAILCRITICALERRORS);
} else {
Disabled = 0;
OldMode = 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
uint8_t* pFileTestBuffer;
unsigned FileTestLength;
unsigned TestPos; // File pointer position during tests.
#endif
public:
FILEFile()
: FileName(),
Opened(false),
fs(NULL),
OpenFlags(0),
ErrorCode(0),
LastOp(0)
#ifdef OVR_FILE_VERIFY_SEEK_ERRORS
,
pFileTestBuffer(NULL),
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 int64_t LTell();
virtual int GetLength();
virtual int64_t LGetLength();
// virtual bool Stat(FileStats *pfs);
virtual int GetErrorCode();
// ** Stream implementation & I/O
virtual int Write(const uint8_t* pbuffer, int numBytes);
virtual int Read(uint8_t* pbuffer, int numBytes);
virtual int SkipBytes(int numBytes);
virtual int BytesAvailable();
virtual bool Flush();
virtual int Seek(int offset, int origin);
virtual int64_t LSeek(int64_t 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";
#if defined(OVR_OS_MS)
SysErrorModeDisabler disabler(FileName.ToCStr());
#endif
#if defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400)
wchar_t womode[16];
auto fileNameLength = (size_t)UTF8Util::GetLength(FileName.ToCStr()) + 1;
wchar_t* pwFileName = (wchar_t*)OVR_ALLOC(fileNameLength * sizeof(pwFileName[0]));
auto requiredUTF8Length = OVR::UTF8Util::Strlcpy(pwFileName, fileNameLength, FileName.ToCStr());
if (requiredUTF8Length < fileNameLength) {
requiredUTF8Length = OVR::UTF8Util::Strlcpy(womode, OVR_ARRAY_COUNT(womode), omode);
OVR_ASSERT(requiredUTF8Length < OVR_ARRAY_COUNT(womode));
fs = _wfsopen(
pwFileName, womode, _SH_DENYWR); // Allow others to read the file when we are writing it.
}
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 = (uint8_t*)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;
}
int64_t FILEFile::LTell() {
int64_t 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;
}
int64_t FILEFile::LGetLength() {
int64_t pos = LTell();
if (pos >= 0) {
LSeek(0, Seek_End);
int64_t size = LTell();
LSeek(pos, Seek_Set);
return size;
}
return -1;
}
int FILEFile::GetErrorCode() {
return ErrorCode;
}
// ** Stream implementation & I/O
int FILEFile::Write(const uint8_t* 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(uint8_t* 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!
uint8_t* 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) {
int64_t pos = LTell();
int64_t 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() {
int64_t pos = LTell();
int64_t 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();
}
int64_t FILEFile::LSeek(int64_t offset, int origin) {
return Seek((int)offset, origin);
}
int FILEFile::CopyFromStream(File* pstream, int byteSize) {
uint8_t* buff = new uint8_t[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;
}
delete[] buff;
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_MS)
// 64-bit implementation on Windows.
struct __stat64 fileStat {};
auto pathLength = (size_t)UTF8Util::GetLength(path.ToCStr()) + 1;
wchar_t* pwPath = (wchar_t*)OVR_ALLOC(pathLength * sizeof(pwPath[0]));
auto requiredUTF8Length = OVR::UTF8Util::Strlcpy(pwPath, pathLength, path.ToCStr());
int ret = -1; // Stat returns 0 for success.
if (requiredUTF8Length < pathLength)
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

View File

@ -0,0 +1,228 @@
/************************************************************************************
PublicHeader: None
Filename : OVR_JSON.h
Content : JSON format reader and writer
Created : April 9, 2013
Author : Brant Lewis
Notes :
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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 "OVR_RefCount.h"
#include "OVR_String.h"
#include "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);
static JSON* CreateNumber(double num);
static JSON* CreateInt(int num);
static JSON* CreateString(const char* 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);
// Return the String representation of a JSON object.
String Stringify(bool fmt);
// *** 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 = "");
template <typename T>
int GetArrayByName(const char* name, T values[], int count, T defaultValue = T(0)) {
// Zero values in case one or more elements not present in JSON
for (int i = 0; i < count; i++)
values[i] = defaultValue;
JSON* array = GetItemByName(name);
if (!array || array->Type != JSON_Array)
return 0;
int i = 0;
for (JSON* child = array->Children.GetFirst(); !array->Children.IsNull(child);
child = array->Children.GetNext(child)) {
if (i >= count)
break;
values[i++] = (T)child->dValue;
}
OVR_ASSERT(i <= count);
return i;
}
// Returns next item in a list of children; 0 if no more items exist.
JSON* GetNextItem(JSON* item) {
return Children.IsLast(item) ? nullptr : item->GetNext();
}
JSON* GetPrevItem(JSON* item) {
return Children.IsFirst(item) ? nullptr : item->GetPrev();
}
// 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 AddIntItem(const char* name, int n) {
AddItem(name, CreateInt(n));
}
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 AddArrayInt(int n) {
AddArrayElement(CreateInt(n));
}
void AddArrayString(const char* s) {
AddArrayElement(CreateString(s));
}
template <typename T>
void AddNumberArray(const char* name, const T array[], int arraySize) {
JSON* node = JSON::CreateArray();
AddItem(name, node);
for (int i = 0; i < arraySize; i++)
node->AddArrayNumber((double)array[i]);
}
// Accessed array elements; currently inefficient.
int GetArraySize();
double GetArrayNumber(int index);
const char* GetArrayString(int index);
JSON* Copy(); // Create a copy of this object
// Return text value of JSON. Use OVR_FREE when done with return value
char* PrintValue(bool fmt);
protected:
JSON(JSONItemType itemType = JSON_Object);
// 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);
};
} // namespace OVR
#endif // OVR_JSON_h

View File

@ -0,0 +1,281 @@
/************************************************************************************
Filename : OVR_KeyCodes.h
Content : Common keyboard constants
Created : September 19, 2012
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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,
// Synthetic mouse wheel state
Key_MouseWheelAwayFromUser, // "forwards" or "up"
Key_MouseWheelTowardUser, // "backwards" or "down"
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;
};
*/
} // namespace OVR
#endif

View File

@ -0,0 +1,389 @@
/************************************************************************************
PublicHeader: OVR
Filename : OVR_List.h
Content : Template implementation for doubly-connected linked List
Created : September 19, 2012
Notes :
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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:
//
// class MyData : ListNode<MyData>
// {
// . . .
// };
template <class T>
class ListNode {
private:
ListNode<T>* pPrev;
ListNode<T>* pNext;
template <class X, class B>
friend class List;
#ifdef OVR_BUILD_DEBUG
bool marker; // Is this a marker node (rather than an actual data node)?
#endif
public:
#ifdef OVR_BUILD_DEBUG
T* GetPrev() const {
if (pPrev && !pPrev->marker) {
return (T*)(pPrev);
} else {
OVR_FAIL_M("Unstable call to ListNode<>::GetPrev() without first checking List<>IsFirst()");
return nullptr;
}
}
T* GetNext() const {
if (pNext && !pNext->marker) {
return (T*)(pNext);
} else {
OVR_FAIL_M("Unstable call to ListNode<>::GetNext() without first checking List<>IsLast()");
return nullptr;
}
}
#else
T* GetPrev() const {
return (T*)(pPrev);
}
T* GetNext() const {
return (T*)(pNext);
}
#endif
ListNode() {
#ifdef OVR_BUILD_DEBUG
marker = false; // Most nodes are data nodes, so that is the default.
#endif
pPrev = nullptr;
pNext = nullptr;
}
bool IsInList() {
return (pNext != nullptr);
}
void RemoveNode() {
pPrev->pNext = pNext;
pNext->pPrev = pPrev;
pPrev = nullptr;
pNext = nullptr;
}
// 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;
pPrev = nullptr;
pNext = nullptr;
}
// 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 = pdest;
pNext->pPrev = pdest;
pPrev = nullptr;
pNext = nullptr;
}
};
//------------------------------------------------------------------------
// ***** 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 = &Root;
#ifdef OVR_BUILD_DEBUG
Root.marker = true; // This is a marker node.
#endif
}
void Clear() {
Root.pNext = Root.pPrev = &Root;
}
size_t GetSize() const {
size_t n = 0;
for (const ListNode<B>* pNode = Root.pNext; pNode != &Root; pNode = pNode->pNext)
++n;
return n;
}
const ValueType* GetFirst() const {
return IsEmpty() ? nullptr : (const ValueType*)Root.pNext;
}
const ValueType* GetLast() const {
return IsEmpty() ? nullptr : (const ValueType*)Root.pPrev;
}
ValueType* GetFirst() {
return IsEmpty() ? nullptr : (ValueType*)Root.pNext;
}
ValueType* GetLast() {
return IsEmpty() ? nullptr : (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.pNext == &Root;
}
bool IsFirst(const ValueType* p) const {
return p == Root.pNext;
}
bool IsLast(const ValueType* p) const {
return p == Root.pPrev;
}
bool IsNull(const ListNode<B>* p) const {
return p == nullptr || p == &Root;
}
inline const ValueType* GetPrev(const ValueType* p) const {
return IsNull(p->pPrev) ? nullptr : (const ValueType*)p->pPrev;
}
inline const ValueType* GetNext(const ValueType* p) const {
return IsNull(p->pNext) ? nullptr : (const ValueType*)p->pNext;
}
inline ValueType* GetPrev(ValueType* p) {
return IsNull(p->pPrev) ? nullptr : (ValueType*)p->pPrev;
}
inline ValueType* GetNext(ValueType* p) {
return IsNull(p->pNext) ? nullptr : (ValueType*)p->pNext;
}
void PushFront(ValueType* p) {
p->pNext = Root.pNext;
p->pPrev = &Root;
Root.pNext->pPrev = p;
Root.pNext = p;
}
void PushBack(ValueType* p) {
p->pPrev = Root.pPrev;
p->pNext = &Root;
Root.pPrev->pNext = p;
Root.pPrev = p;
}
static void Remove(ValueType* p) {
p->pPrev->pNext = p->pNext;
p->pNext->pPrev = p->pPrev;
p->pPrev = nullptr;
p->pNext = nullptr;
}
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 = &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 = &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 = &src.Root;
src.Root.pPrev = pfirst->pPrev;
// Add the rest of the items to list.
plast->pNext = Root.pNext;
pfirst->pPrev = &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 = &src.Root;
src.Root.pNext = ptail;
// Add the rest of the items to list.
plast->pNext = Root.pNext;
pfirst->pPrev = &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 = &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 = &pdest->Root;
Root.pPrev->pNext = &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();
}
} // namespace OVR
#endif

View File

@ -0,0 +1,202 @@
/************************************************************************************
Filename : OVR_Lockless.h
Content : Lock-less classes for producer/consumer communication
Created : November 9, 2013
Authors : John Carmack
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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 <cstring>
using std::memcpy;
#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.
//
// The SlotType can be the same as T, but should probably be a larger fixed size.
// This allows for forward compatibility when the updater is shared between processes.
template <class T, class SlotType = T>
class LocklessUpdater {
public:
LocklessUpdater() {
OVR_COMPILER_ASSERT(sizeof(T) <= sizeof(SlotType));
}
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.load(std::memory_order_acquire);
state = Slots[end & 1];
begin = UpdateBegin.load(std::memory_order_acquire);
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.load(std::memory_order_acquire);
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(const T& state) {
const int slot = UpdateBegin.fetch_add(1) & 1;
// Write to (slot ^ 1) because ExchangeAdd returns 'previous' value before add.
Slots[slot ^ 1] = state;
UpdateEnd.fetch_add(1);
}
std::atomic<int> UpdateBegin = {0};
std::atomic<int> UpdateEnd = {0};
SlotType Slots[2];
};
#pragma pack(push, 8)
// Padded out version stored in the updater slots
// Designed to be a larger fixed size to allow the data to grow in the future
// without breaking older compiled code.
OVR_DISABLE_MSVC_WARNING(4351)
template <class Payload, int PaddingSize>
struct LocklessPadding {
uint8_t buffer[PaddingSize];
LocklessPadding() : buffer() {}
LocklessPadding& operator=(const Payload& rhs) {
// if this fires off, then increase PaddingSize
// IMPORTANT: this WILL break backwards compatibility
static_assert(sizeof(buffer) >= sizeof(Payload), "PaddingSize is too small");
memcpy(buffer, &rhs, sizeof(Payload));
return *this;
}
operator Payload() const {
Payload result;
memcpy(&result, buffer, sizeof(Payload));
return result;
}
};
OVR_RESTORE_MSVC_WARNING()
#pragma pack(pop)
// FIXME: Move this somewhere else
// ***** LocklessBuffer
// FIXME: update these comments
// For single producer cases where you only care about the most recent update, not
// necessarily getting every one that happens (vsync timing, SensorFusion updates, external camera
// frames).
//
// The writer writes an incrementing generation # for each write start, and write end
// The reader reads the last written generation number, saves it, does its operations, then
// reads the latest value of the last written generation number. If they match, there was no
// collision, and the work is done. If not, the reader has to loop until it gets a matching
// Last written generation number
//
// This is to update & read a dynamically sized object in shared memory.
// Initial use case is for frame buffers for cameras, which are an unknown size until runtime
#pragma pack(push, 1)
class LocklessBuffer {
public:
LocklessBuffer() {
;
}
void Initialize(unsigned bufferSize) {
BufferSize = bufferSize;
LastWrittenGeneration = 0;
}
char* StartWrite(unsigned offset) {
++LastWrittenGeneration;
return GetDataForWrite(offset);
}
unsigned GetBufferSize() const {
return BufferSize;
}
int EndWrite() {
return ++LastWrittenGeneration;
}
int GetLastWrittenGeneration() const {
return LastWrittenGeneration;
}
const char* GetDataForRead(unsigned offset = 0) const {
return &(Data[offset]);
}
char* GetDataForWrite(unsigned offset = 0) {
return &(Data[offset]);
}
bool DidReadCollide(int lastReadGeneration) const {
return lastReadGeneration != LastWrittenGeneration;
}
private:
unsigned BufferSize = 0;
std::atomic<int> LastWrittenGeneration;
// Data starts here...
char Data[1];
};
#pragma pack(pop)
} // namespace OVR
#endif // OVR_Lockless_h

View File

@ -0,0 +1,144 @@
/************************************************************************************
Filename : OVR_Log.cpp
Content : Logging support
Created : September 19, 2012
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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_Allocator.h"
#include "OVR_String.h"
#include "OVR_DebugHelp.h"
#include "Util/Util_SystemGUI.h"
#include <fstream>
namespace OVR {
ovrlog::Channel DefaultChannel("Kernel:Default");
static OVRAssertionHandler sOVRAssertionHandler = OVR::DefaultAssertionHandler;
static intptr_t sOVRAssertionHandlerUserParameter = 0;
OVRAssertionHandler GetAssertionHandler(intptr_t* userParameter) {
if (userParameter)
*userParameter = sOVRAssertionHandlerUserParameter;
return sOVRAssertionHandler;
}
void SetAssertionHandler(OVRAssertionHandler assertionHandler, intptr_t userParameter) {
sOVRAssertionHandler = assertionHandler;
sOVRAssertionHandlerUserParameter = userParameter;
}
intptr_t
DefaultAssertionHandler(intptr_t /*userParameter*/, const char* title, const char* message) {
if (OVRIsDebuggerPresent()) {
OVR_DEBUG_BREAK;
} else {
OVR_UNUSED(title);
OVR_UNUSED(message);
#if defined(OVR_BUILD_DEBUG)
if (Allocator::GetInstance()) // The code below currently depends on having a valid Allocator.
{
// Print a stack trace of all threads.
OVR::String s;
OVR::String threadListOutput;
static OVR::SymbolLookup symbolLookup;
s = "Failure: ";
s += message;
if (symbolLookup.Initialize() &&
symbolLookup.ReportThreadCallstack(threadListOutput, 4)) // This '4' is there to skip our
// internal handling and retrieve
// starting at the assertion
// location (our caller) only.
{
// threadListOutput has newlines that are merely \n, whereas Windows MessageBox wants \r\n
// newlines. So we insert \r in front of all \n.
for (size_t i = 0, iEnd = threadListOutput.GetSize(); i < iEnd; i++) {
if (threadListOutput[i] == '\n') {
threadListOutput.Insert("\r", i, 1);
++i;
++iEnd;
}
}
s += "\r\n\r\n";
s += threadListOutput;
}
OVR::Util::DisplayMessageBox(title, s.ToCStr());
} else {
// See above.
OVR::Util::DisplayMessageBox(title, message);
}
#else
OVR::Util::DisplayMessageBox(title, message);
#endif
}
return 0;
}
// This currently has no multi-thread safety.
intptr_t AssertHandlerDiskFile(intptr_t userParameter, const char* title, const char* message) {
// We don't have a means to keep state, so we need to have a little state machine here to
// help us direct how this works.
static std::ofstream file;
static std::string filePath;
const char* userFilePath = (userParameter ? reinterpret_cast<const char*>(userParameter) : "");
// See if we need to change the file state.
if (filePath != userFilePath) { // If a file change is occurring...
file.close(); // Possibly close any existing open file. OK if the file wasn't open.
filePath = userFilePath;
if (!filePath.empty()) // If there is a file to open...
file.open(filePath.c_str(), std::ios::out | std::ios::trunc); // If this fails, we won't know.
}
// Write the message if there is a file to write to.
if (file.is_open()) {
file.write("Assertion failure\n", strlen("Assertion failure\n"));
file.write(title, strlen(title));
file.write("\n", 1);
file.write(message, strlen(message));
file.write("\n\n", 1);
}
return 0;
}
bool IsAutomationRunning() {
#if defined(OVR_OS_WIN32)
// We use the OS GetEnvironmentVariable function as opposed to getenv, as that
// is process-wide as opposed to being tied to the current C runtime library.
return GetEnvironmentVariableW(L"OvrAutomationRunning", NULL, 0) > 0;
#else
return getenv("OvrAutomationRunning") != nullptr;
#endif
}
} // namespace OVR

View File

@ -0,0 +1,199 @@
/************************************************************************************
Filename : OVR_Log.h
Content : Logging support
Created : September 19, 2012
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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
#ifdef MICRO_OVR
namespace OVR {
template <typename... Args>
void LogText(Args&&...) {}
template <typename... Args>
void LogError(Args&&...) {}
template <typename... Args>
void LogDebug(Args&&...) {}
} // namespace OVR
#define OVR_DEBUG_LOG(args) \
do { \
} while (0);
#define OVR_DEBUG_LOG_TEXT(args) \
do { \
} while (0);
#define OVR_ASSERT_LOG(c, args) \
do { \
} while (0)
namespace ovrlog {
struct Channel {
template <typename... Args>
Channel(Args&&...) {}
template <typename... Args>
void LogTrace(Args&&...) {}
template <typename... Args>
void LogWarningF(Args&&...) {}
};
} // namespace ovrlog
#else
#include "OVR_Types.h"
#include "OVR_Std.h"
#include "OVR_String.h"
#include "Logging/Logging_Library.h"
#if defined(__clang__)
#pragma clang diagnostic ignored "-Wformat-nonliteral"
#pragma clang diagnostic ignored \
"-Wformat-security" // Otherwise the printf usage below generates a warning.
#endif
namespace OVR {
//-----------------------------------------------------------------------------------
// Terrible Legacy Log Wrapper
//
// Try not to use this deprecated code.
#define OVR_SYSLOG_NAME L"OculusVR"
typedef int LogMessageType;
extern ovrlog::Channel DefaultChannel;
template <typename... Args>
inline void LogText(Args&&... args) {
if (DefaultChannel.Active(ovrlog::Level::Info)) {
char buffer[512];
#pragma warning(push)
#pragma warning(disable : 4840)
int written = snprintf(buffer, sizeof(buffer), args...);
#pragma warning(pop)
if (written <= 0 || written >= (int)sizeof(buffer)) {
OVR_ASSERT(false); // This call should be converted to the new log system.
return;
}
// Fix up the newlines
if (buffer[written - 1] == '\n') {
buffer[written - 1] = '\0';
}
DefaultChannel.LogInfo(buffer);
}
}
template <typename... Args>
inline void LogError(Args&&... args) {
if (DefaultChannel.Active(ovrlog::Level::Error)) {
char buffer[512];
#pragma warning(push)
#pragma warning(disable : 4840)
int written = snprintf(buffer, sizeof(buffer), args...);
#pragma warning(pop)
if (written <= 0 || written >= (int)sizeof(buffer)) {
OVR_ASSERT(false); // This call should be converted to the new log system.
return;
}
// Fix up the newlines
if (buffer[written - 1] == '\n') {
buffer[written - 1] = '\0';
}
DefaultChannel.LogError(buffer);
}
}
template <typename... Args>
inline void LogDebug(Args&&... args) {
if (DefaultChannel.Active(ovrlog::Level::Debug)) {
char buffer[512];
int written = snprintf(buffer, sizeof(buffer), args...);
if (written <= 0 || written >= (int)sizeof(buffer)) {
OVR_ASSERT(false); // This call should be converted to the new log system.
return;
}
// Fix up the newlines
if (buffer[written - 1] == '\n') {
buffer[written - 1] = '\0';
}
DefaultChannel.LogDebug(buffer);
}
}
// This acts as a replacement for the assertion dialog box, primarily for the purpose of assisting
// in testing and automation. Instead of presenting a dialong box, this will write assertions to
// a disk file. userParameter is a pointer to a file path to use, or 0 to drop assertion failures.
// This handler creates the file if not found, and initially clears the file if found.
// Calling SetAssertionHandler to set a file with a path, then later calling SetAssertionHandler
// with another path or 0 causes the closing of the initial file.
//
// Example usage:
// SetAssertionHandler(AssertHandlerDiskFile, (intptr_t)"C:\\SomeDir\SomeFile.txt");
// SetAssertionHandler(AssertHandlerDiskFile, 0); // Write assertions to nowhere.
//
intptr_t AssertHandlerDiskFile(intptr_t userParameter, const char* title, const char* message);
#define OVR_DEBUG_LOG(args) \
do { \
OVR::LogDebug args; \
} while (0);
#define OVR_DEBUG_LOG_TEXT(args) \
do { \
OVR::LogDebug args; \
} while (0);
#define OVR_ERROR_LOG(args) \
do { \
OVR::LogError args; \
} while (0);
// Conditional logging & asserting. It asserts/logs when the condition 'c' is NOT true.
#define OVR_ASSERT_LOG(c, args) \
do { \
if (!(c)) { \
OVR::LogError args; \
OVR_DEBUG_BREAK; \
} \
} while (0)
} // namespace OVR
namespace ovrlog {
template <>
LOGGING_INLINE void LogStringize(LogStringBuffer& buffer, const OVR::String& first) {
buffer.Stream << first.ToCStr();
}
} // namespace ovrlog
#endif // MICRO_OVR
#endif // OVR_Log_h

View File

@ -0,0 +1,206 @@
/************************************************************************************
Filename : OVR_NewOverride.inl
Content : New override for LibOVR Allocator
Created : April 7, 2015
Authors : Paul Pedriana, Chris Taylor
Copyright : Copyright 2015-2016 Oculus VR, LLC All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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_NewOverride_inl
#define OVR_NewOverride_inl
#include "OVR_Allocator.h"
#include <new>
#if defined(_MSC_VER)
#pragma warning(push, 0)
#include <malloc.h>
#include <crtdbg.h>
#include <math.h> // Work around VS header bug by #including math.h then intrin.h.
#if (_MSC_VER >= 1500)
#include <intrin.h>
#endif
#pragma warning(pop)
#if (_MSC_VER >= 1600) // VS2010+
#pragma warning(disable : 4986) // 'operator delete[]': exception specification does not match previous declaration.
#endif
#endif
#if defined(_MSC_VER)
#if (_MSC_VER <= 1900)
#define OVR_THROW_SPEC_NEW(X) __pragma(warning(push)) __pragma(warning(disable: 4290 4987)) _THROW(,X) __pragma(warning(pop))
#define OVR_THROW_SPEC_NEW_NONE() _THROW(,)
#define OVR_THROW_SPEC_DELETE_NONE() _THROW(,)
#else
#define OVR_THROW_SPEC_NEW(x) __pragma(warning(push)) __pragma(warning(disable: 4290 4987)) noexcept(false) __pragma(warning(pop))
#define OVR_THROW_SPEC_NEW_NONE() noexcept
#define OVR_THROW_SPEC_DELETE_NONE() noexcept
#endif
#else
#define OVR_THROW_SPEC_NEW(x) throw(x)
#define OVR_THROW_SPEC_NEW_NONE() throw()
#define OVR_THROW_SPEC_DELETE_NONE() throw()
#endif
// Add common decorators here as neeeded.
#define OVR_NEW_OVERRIDE_INLINE
OVR_NEW_OVERRIDE_INLINE void* operator new(size_t size) OVR_THROW_SPEC_NEW(std::bad_alloc)
{
void* p = OVR_ALLOC(size);
#if !defined(OVR_CPP_NO_EXCEPTIONS)
if(!p)
throw std::bad_alloc();
#endif
return p;
}
OVR_NEW_OVERRIDE_INLINE void* operator new[](size_t size) OVR_THROW_SPEC_NEW(std::bad_alloc)
{
void* p = OVR_ALLOC(size);
#if !defined(OVR_CPP_NO_EXCEPTIONS)
if(!p)
throw std::bad_alloc();
#endif
return p;
}
OVR_NEW_OVERRIDE_INLINE void* operator new(size_t size, std::nothrow_t&) OVR_THROW_SPEC_NEW_NONE()
{
return OVR_ALLOC(size);
}
OVR_NEW_OVERRIDE_INLINE void* operator new[](size_t size, std::nothrow_t&) OVR_THROW_SPEC_NEW_NONE()
{
return OVR_ALLOC(size);
}
OVR_NEW_OVERRIDE_INLINE void* operator new(size_t size, const std::nothrow_t&) OVR_THROW_SPEC_NEW_NONE()
{
return OVR_ALLOC(size);
}
OVR_NEW_OVERRIDE_INLINE void* operator new[](size_t size, const std::nothrow_t&) OVR_THROW_SPEC_NEW_NONE()
{
return OVR_ALLOC(size);
}
OVR_NEW_OVERRIDE_INLINE void operator delete(void* p) OVR_THROW_SPEC_DELETE_NONE()
{
OVR_FREE(p);
}
OVR_NEW_OVERRIDE_INLINE void operator delete[](void* p) OVR_THROW_SPEC_DELETE_NONE()
{
OVR_FREE(p);
}
OVR_NEW_OVERRIDE_INLINE void operator delete(void* p, std::nothrow_t&) OVR_THROW_SPEC_DELETE_NONE()
{
OVR_FREE(p);
}
OVR_NEW_OVERRIDE_INLINE void operator delete[](void* p, std::nothrow_t&) OVR_THROW_SPEC_DELETE_NONE()
{
OVR_FREE(p);
}
OVR_NEW_OVERRIDE_INLINE void operator delete(void* p, const std::nothrow_t&) OVR_THROW_SPEC_DELETE_NONE()
{
OVR_FREE(p);
}
OVR_NEW_OVERRIDE_INLINE void operator delete[](void* p, const std::nothrow_t&) OVR_THROW_SPEC_DELETE_NONE()
{
OVR_FREE(p);
}
// The following new/delete overrides are required under VC++ because it defines the following operator new versions of its own.
#if defined(_MSC_VER)
OVR_NEW_OVERRIDE_INLINE void* operator new(size_t n, const char* /*fileName*/, int /*line*/)
{
return ::operator new(n);
}
OVR_NEW_OVERRIDE_INLINE void* operator new[](size_t n, const char* /*fileName*/, int /*line*/)
{
return ::operator new[](n);
}
OVR_NEW_OVERRIDE_INLINE void operator delete(void* p, const char* /*fileName*/, int /*line*/)
{
::operator delete(p);
}
OVR_NEW_OVERRIDE_INLINE void operator delete[](void* p, const char* /*fileName*/, int /*line*/)
{
::operator delete[](p);
}
OVR_NEW_OVERRIDE_INLINE void* operator new(size_t n, int /*debug*/, const char* /*fileName*/, int /*line*/)
{
return ::operator new (n);
}
OVR_NEW_OVERRIDE_INLINE void* operator new[](size_t n, int /*debug*/, const char* /*fileName*/, int /*line*/)
{
return ::operator new[](n);
}
OVR_NEW_OVERRIDE_INLINE void __CRTDECL
operator delete(void* p, int /*debug*/, const char* /*fileName*/, int /*line*/)
OVR_THROW_SPEC_DELETE_NONE() {
::operator delete(p);
}
OVR_NEW_OVERRIDE_INLINE void __CRTDECL
operator delete[](void* p, int /*debug*/, const char* /*fileName*/, int /*line*/)
OVR_THROW_SPEC_DELETE_NONE() {
::operator delete[](p);
}
#endif
#endif // OVR_NewOverride_inl

View File

@ -0,0 +1,159 @@
/************************************************************************************
Filename : OVR_Nullptr.h
Content : Implements C++11 nullptr for the case that the compiler doesn't.
Created : June 19, 2014
Notes :
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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_Nullptr_h
#define OVR_Nullptr_h
#pragma once
#include "OVR_Types.h"
//-----------------------------------------------------------------------------------
// ***** OVR_HAVE_std_nullptr_t
//
// Identifies if <cstddef.h> includes std::nullptr_t.
//
#if !defined(OVR_HAVE_std_nullptr_t) && defined(OVR_CPP11_ENABLED)
#if defined(OVR_STDLIB_LIBCPP)
#define OVR_HAVE_std_nullptr_t 1
#elif defined(OVR_STDLIB_LIBSTDCPP)
#if (__GLIBCXX__ >= 20110325) && (__GLIBCXX__ != 20110428) && (__GLIBCXX__ != 20120702)
#define OVR_HAVE_std_nullptr_t 1
#endif
#elif defined(_MSC_VER) && (_MSC_VER >= 1600) // VS2010+
#define OVR_HAVE_std_nullptr_t 1
#elif defined(__clang__)
#define OVR_HAVE_std_nullptr_t 1
#elif defined(OVR_CPP_GNUC) && (OVR_CC_VERSION >= 406) // GCC 4.6+
#define OVR_HAVE_std_nullptr_t 1
#endif
#endif
//-----------------------------------------------------------------------------------
// ***** nullptr / std::nullptr_t
//
// Declares and defines nullptr and related types.
//
#if defined(OVR_CPP_NO_NULLPTR)
namespace std {
class nullptr_t {
public:
template <typename T>
operator T*() const {
return 0;
}
template <typename C, typename T>
operator T C::*() const {
return 0;
}
#if OVR_CPP_NO_EXPLICIT_CONVERSION_OPERATORS
typedef void* (nullptr_t::*bool_)()
const; // 4.12,p1. We can't portably use operator bool(){ return false; } because bool
operator bool_() const // is convertable to int which breaks other required functionality.
{
return false;
}
#else
operator bool() const {
return false;
}
#endif
private:
void operator&() const; // 5.2.10,p9
};
inline nullptr_t nullptr_get() {
nullptr_t n = {};
return n;
}
#if !defined(nullptr)
#define nullptr nullptr_get()
#endif
} // namespace std
// 5.9,p2 p4
// 13.6, p13
template <typename T>
inline bool operator==(T* pT, const std::nullptr_t) {
return pT == 0;
}
template <typename T>
inline bool operator==(const std::nullptr_t, T* pT) {
return pT == 0;
}
template <typename T, typename U>
inline bool operator==(const std::nullptr_t, T U::*pU) {
return pU == 0;
}
template <typename T, typename U>
inline bool operator==(T U::*pTU, const std::nullptr_t) {
return pTU == 0;
}
inline bool operator==(const std::nullptr_t, const std::nullptr_t) {
return true;
}
inline bool operator!=(const std::nullptr_t, const std::nullptr_t) {
return false;
}
inline bool operator<(const std::nullptr_t, const std::nullptr_t) {
return false;
}
inline bool operator<=(const std::nullptr_t, const std::nullptr_t) {
return true;
}
inline bool operator>(const std::nullptr_t, const std::nullptr_t) {
return false;
}
inline bool operator>=(const std::nullptr_t, const std::nullptr_t) {
return true;
}
using std::nullptr_get;
using std::nullptr_t;
// Some compilers natively support C++11 nullptr but the standard library being used
// doesn't declare std::nullptr_t, in which case we provide one ourselves.
#elif !defined(OVR_HAVE_std_nullptr_t) && !defined(OVR_CPP_NO_DECLTYPE)
namespace std {
typedef decltype(nullptr) nullptr_t;
}
#endif
#endif

View File

@ -0,0 +1,91 @@
/************************************************************************************
Filename : OVR_RefCount.cpp
Content : Reference counting implementation
Created : September 19, 2012
Notes :
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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 {
// ***** 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() {
RefCount.fetch_add(1, std::memory_order_relaxed);
}
void RefCountImpl::Release() {
if (RefCount.fetch_add(-1, std::memory_order_relaxed) - 1 == 0)
delete this;
}
// *** Thread-Safe RefCountVImpl w/virtual AddRef/Release
void RefCountVImpl::AddRef() {
RefCount.fetch_add(1, std::memory_order_relaxed);
}
void RefCountVImpl::Release() {
if (RefCount.fetch_add(-1, std::memory_order_relaxed) - 1 == 0)
delete this;
}
// *** NON-Thread-Safe RefCountImpl
void RefCountNTSImpl::Release() const {
RefCount--;
if (RefCount == 0)
delete this;
}
} // namespace OVR

View File

@ -0,0 +1,495 @@
/************************************************************************************
PublicHeader: Kernel
Filename : OVR_RefCount.h
Content : Reference counting implementation headers
Created : September 19, 2012
Notes :
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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:
std::atomic<int> RefCount = {1};
public:
// RefCountImpl constructor always initializes RefCount to 1 by default.
OVR_FORCE_INLINE RefCountImplCore() {}
// 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>() {}
};
//-----------------------------------------------------------------------------------
// ***** Ref-Counted template pointer
//
// Automatically AddRefs and Releases interfaces
//
// Note: Some of the member functions take C& as opposed to C* arguments:
// Ptr(C&)
// const Ptr<C>& operator= (C&)
// Ptr<C>& SetPtr(C&)
// These functions do not AddRef the assigned C& value, unlike the C* assignment
// functions. Thus the purpose of these functions is for the Ptr instance to
// assume ownership of a C reference count. Example usage:
// Ptr<Widget> w = *new Widget; // Calls the Ptr(C&) constructor. Note that the Widget
// constructor sets initial refcount to 1.
//
template <class C>
class Ptr {
protected:
C* pObject;
public:
// Constructors
OVR_FORCE_INLINE Ptr() : pObject(0) {}
// This constructor adopts the object's existing reference count rather than increment it.
OVR_FORCE_INLINE Ptr(C& robj) : pObject(&robj) {}
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;
}
// 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) {
// By design we don't check for src == pObject, as we don't expect that to be the case the large
// majority of the time.
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;
}
// This operator adopts the object's existing reference count rather than increment it.
OVR_FORCE_INLINE const Ptr<C>& operator=(C& src) {
if (pObject)
pObject->Release();
pObject = &src;
return *this;
}
// 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;
}
// This function adopts the object's existing reference count rather than increment it.
OVR_FORCE_INLINE Ptr<C>& SetPtr(C& src) {
if (pObject)
pObject->Release();
pObject = &src;
return *this;
}
// 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;
}
};
// LockedPtr
//
// Helper class to simplify thread-safety of the TrackingManager.
// It wraps the Ptr<> object it contains in a Lock.
template <class T>
class LockedPtr {
public:
LockedPtr(Lock* lock = nullptr) : TheLock(lock) {}
void Set(T* value) {
OVR_ASSERT(TheLock);
TheLock->DoLock();
Ptr<T> oldPtr = ThePtr; // Keep a reference to the old ptr
ThePtr = value; // Change/decrement the old ptr (cannot die here due to oldPtr)
TheLock->Unlock();
// Release the old Ptr reference here, outside of the lock
// so that the object will not die while TheLock is held.
}
template <class S>
void Get(Ptr<S>& outputPtr) const {
OVR_ASSERT(TheLock);
TheLock->DoLock();
Ptr<T> retval = ThePtr;
TheLock->Unlock();
outputPtr = retval;
}
protected:
mutable Lock* TheLock;
Ptr<T> ThePtr;
};
} // namespace OVR
#endif

View File

@ -0,0 +1,687 @@
/************************************************************************************
Filename : OVR_SharedMemory.cpp
Content : Inter-process shared memory subsystem
Created : June 1, 2014
Notes :
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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_SharedMemory.h"
#include "OVR_Atomic.h"
#include "OVR_Log.h"
#include "OVR_String.h"
#include "OVR_Array.h"
#if defined(OVR_OS_WIN32)
#include <Sddl.h> // ConvertStringSecurityDescriptorToSecurityDescriptor
#endif // OVR_OS_WIN32
#if defined(OVR_OS_LINUX) || defined(OVR_OS_MAC)
#include <sys/mman.h> // shm_open(), mmap()
#include <errno.h> // error results for mmap
#include <sys/stat.h> // mode constants
#include <fcntl.h> // O_ constants
#include <unistd.h> // close()
#endif // OVR_OS_LINUX
OVR_DEFINE_SINGLETON(OVR::SharedMemoryFactory);
namespace OVR {
static ovrlog::Channel Logger("SharedMemory");
//-----------------------------------------------------------------------------
// SharedMemoryInternalBase
class SharedMemoryInternalBase : public NewOverrideBase {
public:
SharedMemoryInternalBase() {}
virtual ~SharedMemoryInternalBase() {}
virtual void* GetFileView() = 0;
};
//-----------------------------------------------------------------------------
// FakeMemoryBlock
class FakeMemoryBlock : public RefCountBase<FakeMemoryBlock> {
String Name;
std::unique_ptr<char[]> Data;
int SizeBytes;
int References;
public:
FakeMemoryBlock(const String& name, int size)
: Name(name), Data(new char[size]), SizeBytes(size), References(1) {}
bool IsNamed(const String& name) {
return Name.CompareNoCase(name) == 0;
}
void* GetData() {
return Data.get();
}
int GetSizeI() {
return SizeBytes;
}
void IncrementReferences() {
++References;
}
bool DecrementReferences() {
return --References <= 0;
}
};
class FakeMemoryInternal : public SharedMemoryInternalBase {
public:
void* FileView;
Ptr<FakeMemoryBlock> Block;
FakeMemoryInternal(FakeMemoryBlock* block);
~FakeMemoryInternal();
virtual void* GetFileView() override {
return FileView;
}
};
//-----------------------------------------------------------------------------
// FakeMemoryManager
class FakeMemoryManager : public NewOverrideBase, public SystemSingletonBase<FakeMemoryManager> {
OVR_DECLARE_SINGLETON(FakeMemoryManager);
Lock FakeLock;
Array<Ptr<FakeMemoryBlock>> FakeArray;
public:
FakeMemoryInternal* Open(const char* name, int bytes, bool openOnly) {
Lock::Locker locker(&FakeLock);
const int count = FakeArray.GetSizeI();
for (int ii = 0; ii < count; ++ii) {
if (FakeArray[ii]->IsNamed(name)) {
FakeArray[ii]->IncrementReferences();
return new FakeMemoryInternal(FakeArray[ii]);
}
}
if (openOnly) {
return NULL;
}
Ptr<FakeMemoryBlock> data = *new FakeMemoryBlock(name, bytes);
FakeArray.PushBack(data);
return new FakeMemoryInternal(data);
}
void Free(FakeMemoryBlock* block) {
Lock::Locker locker(&FakeLock);
const int count = FakeArray.GetSizeI();
for (int ii = 0; ii < count; ++ii) {
if (FakeArray[ii].GetPtr() == block) {
// If the reference count hit zero,
if (FakeArray[ii]->DecrementReferences()) {
// Toast
FakeArray.RemoveAtUnordered(ii);
}
break;
}
}
}
};
FakeMemoryManager::FakeMemoryManager() {
// Must be at end of function
PushDestroyCallbacks();
}
FakeMemoryManager::~FakeMemoryManager() {
// If this assertion trips it is because we have not cleanly released shared memory resources.
OVR_ASSERT(FakeArray.GetSizeI() == 0);
}
void FakeMemoryManager::OnSystemDestroy() {
delete this;
}
FakeMemoryInternal::FakeMemoryInternal(FakeMemoryBlock* block) : Block(block) {
FileView = Block->GetData();
}
FakeMemoryInternal::~FakeMemoryInternal() {
FakeMemoryManager::GetInstance()->Free(Block);
Block.Clear();
}
} // namespace OVR
OVR_DEFINE_SINGLETON(FakeMemoryManager);
namespace OVR {
static SharedMemoryInternalBase* CreateFakeSharedMemory(
const SharedMemory::OpenParameters& params) {
return FakeMemoryManager::GetInstance()->Open(
params.globalName, params.minSizeBytes, params.openMode == SharedMemory::OpenMode_OpenOnly);
}
//// Windows version
#if defined(OVR_OS_WIN32)
#pragma comment(lib, "advapi32.lib")
// Hidden implementation class for OS-specific behavior
class SharedMemoryInternal : public SharedMemoryInternalBase {
public:
HANDLE FileMapping;
void* FileView;
SharedMemoryInternal(HANDLE fileMapping, void* fileView)
: FileMapping(fileMapping), FileView(fileView) {}
~SharedMemoryInternal() {
// If file view is set,
if (FileView) {
UnmapViewOfFile(FileView);
FileView = NULL;
}
// If file mapping is set,
if (FileMapping != NULL) {
CloseHandle(FileMapping);
FileMapping = NULL;
}
}
virtual void* GetFileView() override {
return FileView;
}
};
static SharedMemoryInternal*
DoFileMap(HANDLE hFileMapping, const char* fileName, bool openReadOnly, int minSize) {
// Interpret the access mode as a map desired access code
DWORD mapDesiredAccess = openReadOnly ? FILE_MAP_READ : FILE_MAP_WRITE;
// Map view of the file to this process
void* pFileView = MapViewOfFile(hFileMapping, mapDesiredAccess, 0, 0, minSize);
// If mapping could not be created,
if (!pFileView) {
CloseHandle(hFileMapping);
Logger.LogDebugF(
"FAILURE: Unable to map view of file for %s error code = %d", fileName, GetLastError());
OVR_UNUSED(fileName);
return NULL;
}
// Create internal representation
SharedMemoryInternal* pimple = new SharedMemoryInternal(hFileMapping, pFileView);
// If memory allocation fails,
if (!pimple) {
UnmapViewOfFile(pFileView);
CloseHandle(hFileMapping);
Logger.LogDebugF("FAILURE: Out of memory");
return NULL;
}
return pimple;
}
static SharedMemoryInternal*
AttemptOpenSharedMemory(const char* fileName, int minSize, bool openReadOnly) {
// Interpret the access mode as a map desired access code
DWORD mapDesiredAccess = openReadOnly ? FILE_MAP_READ : FILE_MAP_WRITE;
// Open file mapping
std::wstring wFileName = UTF8StringToUCSString(fileName);
HANDLE hFileMapping = OpenFileMappingW(mapDesiredAccess, TRUE, wFileName.c_str());
// If file was mapped unsuccessfully,
if (NULL == hFileMapping) {
Logger.LogTraceF(
"WARNING: Unable to open file mapping for %s error code = %d (not necessarily bad)",
fileName,
GetLastError());
return NULL;
}
// Map the file
return DoFileMap(hFileMapping, fileName, openReadOnly, minSize);
}
static SharedMemoryInternal* AttemptCreateSharedMemory(
const char* fileName,
int minSize,
bool openReadOnly,
bool allowRemoteWrite) {
// Prepare a SECURITY_ATTRIBUTES object
SECURITY_ATTRIBUTES security;
ZeroMemory(&security, sizeof(security));
security.nLength = sizeof(security);
// Security descriptor by DACL strings:
// ACE strings grant Allow(A), Object/Contains Inheritance (OICI) of:
// + Grant All (GA) to System (SY)
// + Grant All (GA) to Built-in Administrators (BA)
// + Grant Read-Only (GR) or Read-Write (GWGR) to Interactive Users (IU) - ie. games
static const wchar_t* DACLString_ReadOnly =
L"D:P(A;OICI;GA;;;SY)(A;OICI;GA;;;BA)(A;OICI;GR;;;IU)"
L"(A;OICI;GR;;;S-1-15-3-191680118-1275207936-1426169489-1705429854)";
static const wchar_t* DACLString_ReadWrite =
L"D:P(A;OICI;GA;;;SY)(A;OICI;GA;;;BA)(A;OICI;GWGR;;;IU)"
L"(A;OICI;GWGR;;;S-1-15-3-191680118-1275207936-1426169489-1705429854)";
// HACK: https://our.intern.facebook.com/intern/tasks/?t=10698852
// The extra SIDs above give access to our named pipe to UWP apps
// Select the remote process access mode
const wchar_t* remoteAccessString = allowRemoteWrite ? DACLString_ReadWrite : DACLString_ReadOnly;
// Attempt to convert access string to security attributes
// Note: This will allocate the security descriptor with LocalAlloc() and must be freed later
BOOL bConvertOkay = ConvertStringSecurityDescriptorToSecurityDescriptorW(
remoteAccessString, SDDL_REVISION_1, &security.lpSecurityDescriptor, NULL);
// If conversion fails,
if (!bConvertOkay) {
Logger.LogDebugF("FAILURE: Unable to convert access string, error code = %d", GetLastError());
return NULL;
}
// Interpret the access mode as a page protection code
int pageProtectCode = openReadOnly ? PAGE_READONLY : PAGE_READWRITE;
std::wstring wFileName = UTF8StringToUCSString(fileName);
// Attempt to create a file mapping
HANDLE hFileMapping = CreateFileMappingW(
INVALID_HANDLE_VALUE, // From page file
&security, // Security attributes
pageProtectCode, // Read-only?
0, // High word for size = 0
minSize, // Low word for size
wFileName.c_str()); // Name of global shared memory file
// Free the security descriptor buffer
LocalFree(security.lpSecurityDescriptor);
// If mapping could not be created,
if (NULL == hFileMapping) {
Logger.LogDebugF(
"FAILURE: Unable to create file mapping for %s error code = %d", fileName, GetLastError());
return NULL;
}
#ifndef OVR_ALLOW_CREATE_FILE_MAPPING_IF_EXISTS
// If the file mapping already exists,
if (GetLastError() == ERROR_ALREADY_EXISTS) {
CloseHandle(hFileMapping);
Logger.LogDebugF("FAILURE: File mapping at %s already exists", fileName);
return NULL;
}
#endif
// Map the file
return DoFileMap(hFileMapping, fileName, openReadOnly, minSize);
}
static SharedMemoryInternal* CreateSharedMemory(const SharedMemory::OpenParameters& params) {
SharedMemoryInternal* retval = NULL;
// Construct the file mapping name in a Windows-specific way
OVR::String fileMappingName = params.globalName;
const char* fileName = fileMappingName.ToCStr();
// Is being opened read-only?
const bool openReadOnly = (params.accessMode == SharedMemory::AccessMode_ReadOnly);
// Try up to 3 times to reduce low-probability failures:
static const int ATTEMPTS_MAX = 3;
for (int attempts = 0; attempts < ATTEMPTS_MAX; ++attempts) {
// If opening should be attempted first,
if (params.openMode != SharedMemory::OpenMode_CreateOnly) {
// Attempt to open a shared memory map
retval = AttemptOpenSharedMemory(fileName, params.minSizeBytes, openReadOnly);
// If successful,
if (retval) {
// Done!
break;
}
}
// If creating the shared memory is also acceptable,
if (params.openMode != SharedMemory::OpenMode_OpenOnly) {
// Interpret create mode
const bool allowRemoteWrite = (params.remoteMode == SharedMemory::RemoteMode_ReadWrite);
// Attempt to create a shared memory map
retval =
AttemptCreateSharedMemory(fileName, params.minSizeBytes, openReadOnly, allowRemoteWrite);
// If successful,
if (retval) {
// Done!
break;
}
}
} // Re-attempt create/open
// Note: On Windows the initial contents of the region are guaranteed to be zero.
return retval;
}
#endif // OVR_OS_WIN32
#if (defined(OVR_OS_LINUX) || defined(OVR_OS_MAC))
// Hidden implementation class for OS-specific behavior
class SharedMemoryInternal : public SharedMemoryInternalBase {
public:
int FileMapping;
void* FileView;
int FileSize;
SharedMemoryInternal(int fileMapping, void* fileView, int fileSize)
: FileMapping(fileMapping), FileView(fileView), FileSize(fileSize) {}
virtual ~SharedMemoryInternal() {
// If file view is set,
if (FileView) {
munmap(FileView, FileSize);
FileView = MAP_FAILED;
}
// If file mapping is set,
if (FileMapping >= 0) {
close(FileMapping);
FileMapping = -1;
}
}
virtual void* GetFileView() override {
return FileView;
}
};
static SharedMemoryInternal*
DoFileMap(int hFileMapping, const char* fileName, bool openReadOnly, int minSize) {
// Calculate the required flags based on read/write mode
int prot = openReadOnly ? PROT_READ : (PROT_READ | PROT_WRITE);
// Map the file view
void* pFileView = mmap(NULL, minSize, prot, MAP_SHARED, hFileMapping, 0);
if (pFileView == MAP_FAILED) {
close(hFileMapping);
Logger.LogDebugF("FAILURE: Unable to map view of file for %s error code = %d", fileName, errno);
OVR_UNUSED(fileName);
return NULL;
}
// Create internal representation
SharedMemoryInternal* pimple = new SharedMemoryInternal(hFileMapping, pFileView, minSize);
// If memory allocation fails,
if (!pimple) {
munmap(pFileView, minSize);
close(hFileMapping);
Logger.LogDebugF("FAILURE: Out of memory");
return NULL;
}
return pimple;
}
static SharedMemoryInternal*
AttemptOpenSharedMemory(const char* fileName, int minSize, bool openReadOnly) {
// Calculate permissions and flags based on read/write mode
int flags = openReadOnly ? O_RDONLY : O_RDWR;
int perms = openReadOnly ? S_IRUSR : (S_IRUSR | S_IWUSR);
// Attempt to open the shared memory file
int hFileMapping = shm_open(fileName, flags, perms);
// If file was not opened successfully,
if (hFileMapping < 0) {
Logger.LogDebugF(
"WARNING: Unable to open file mapping for %s error code = %d (not necessarily bad)",
fileName,
errno);
return NULL;
}
// Map the file
return DoFileMap(hFileMapping, fileName, openReadOnly, minSize);
}
static SharedMemoryInternal* AttemptCreateSharedMemory(
const char* fileName,
int minSize,
bool openReadOnly,
bool allowRemoteWrite) {
// Create mode
// Note: Cannot create the shared memory file read-only because then ftruncate() will fail.
int flags = O_CREAT | O_RDWR;
#ifndef OVR_ALLOW_CREATE_FILE_MAPPING_IF_EXISTS
// Require exclusive access when creating (seems like a good idea without trying it yet..)
if (shm_unlink(fileName) < 0) {
Logger.LogDebugF(
"WARNING: Unable to unlink shared memory file %s error code = %d", fileName, errno);
}
flags |= O_EXCL;
#endif
// Set own read/write permissions
int perms = openReadOnly ? S_IRUSR : (S_IRUSR | S_IWUSR);
// Allow other users to read/write the shared memory file
perms |= allowRemoteWrite ? (S_IWGRP | S_IWOTH | S_IRGRP | S_IROTH) : (S_IRGRP | S_IROTH);
// Attempt to open the shared memory file
int hFileMapping = shm_open(fileName, flags, perms);
// If file was not opened successfully,
if (hFileMapping < 0) {
Logger.LogDebugF(
"FAILURE: Unable to create file mapping for %s error code = %d", fileName, errno);
return NULL;
}
int truncRes = ftruncate(hFileMapping, minSize);
// If file was not opened successfully,
if (truncRes < 0) {
close(hFileMapping);
Logger.LogDebugF(
"FAILURE: Unable to truncate file for %s to %d error code = %d", fileName, minSize, errno);
return NULL;
}
// Map the file
return DoFileMap(hFileMapping, fileName, openReadOnly, minSize);
}
static SharedMemoryInternal* CreateSharedMemory(const SharedMemory::OpenParameters& params) {
SharedMemoryInternal* retval = NULL;
// Construct the file mapping name in a Linux-specific way
OVR::String fileMappingName = "/";
fileMappingName += params.globalName;
const char* fileName = fileMappingName.ToCStr();
// Is being opened read-only?
const bool openReadOnly = (params.accessMode == SharedMemory::AccessMode_ReadOnly);
// Try up to 3 times to reduce low-probability failures:
static const int ATTEMPTS_MAX = 3;
for (int attempts = 0; attempts < ATTEMPTS_MAX; ++attempts) {
// If opening should be attempted first,
if (params.openMode != SharedMemory::OpenMode_CreateOnly) {
// Attempt to open a shared memory map
retval = AttemptOpenSharedMemory(fileName, params.minSizeBytes, openReadOnly);
// If successful,
if (retval) {
// Done!
break;
}
}
// If creating the shared memory is also acceptable,
if (params.openMode != SharedMemory::OpenMode_OpenOnly) {
// Interpret create mode
const bool allowRemoteWrite = (params.remoteMode == SharedMemory::RemoteMode_ReadWrite);
// Attempt to create a shared memory map
retval =
AttemptCreateSharedMemory(fileName, params.minSizeBytes, openReadOnly, allowRemoteWrite);
// If successful,
if (retval) {
// Done!
break;
}
}
} // Re-attempt create/open
// Note: On Windows the initial contents of the region are guaranteed to be zero.
return retval;
}
#endif // OVR_OS_LINUX
//-----------------------------------------------------------------------------
// SharedMemory
static bool FakingSharedMemory = false;
void SharedMemory::SetFakeSharedMemory(bool enabled) {
FakingSharedMemory = enabled;
}
bool SharedMemory::IsFakingSharedMemory() {
return FakingSharedMemory;
}
SharedMemory::SharedMemory(
int size,
void* data,
const String& name,
SharedMemoryInternalBase* pInternal)
: Size(size), Data(data), Name(name), Internal(pInternal) {}
SharedMemory::~SharedMemory() {
// Call close when it goes out of scope
Close();
delete Internal;
}
void SharedMemory::Close() {
if (Internal) {
delete Internal;
Internal = NULL;
}
}
//-----------------------------------------------------------------------------
// SharedMemoryFactory
Ptr<SharedMemory> SharedMemoryFactory::Open(const SharedMemory::OpenParameters& params) {
Ptr<SharedMemory> retval;
// Return if no name specified or invalid size requested
// 0 is a valid option, it means 'map the whole region'
// In this case, the client must know the valid size of the region
if (!params.globalName || (params.minSizeBytes < 0)) {
Logger.LogDebug("FAILURE: Invalid parameters to Create()");
return NULL;
}
#ifdef OVR_BUILD_DEBUG
if (Logger.GetMinimumOutputLevel() <= ovrlog::Level::Trace) {
const char* OpType = "{Unknown}";
switch (params.openMode) {
case SharedMemory::OpenMode_CreateOnly:
OpType = "Creating";
break;
case SharedMemory::OpenMode_CreateOrOpen:
OpType = "Creating/Opening";
break;
case SharedMemory::OpenMode_OpenOnly:
OpType = "Opening";
break;
default:
OVR_ASSERT(false);
break;
}
Logger.LogTraceF(
"%s shared memory region: %s > %d bytes", OpType, params.globalName, params.minSizeBytes);
}
#endif
// Attempt to create a shared memory region from the parameters
SharedMemoryInternalBase* pInternal;
if (SharedMemory::IsFakingSharedMemory()) {
pInternal = CreateFakeSharedMemory(params);
} else {
pInternal = CreateSharedMemory(params);
}
if (pInternal) {
// Create the wrapper object
retval = *new SharedMemory(
params.minSizeBytes, pInternal->GetFileView(), params.globalName, pInternal);
}
return retval;
}
SharedMemoryFactory::SharedMemoryFactory() {
Logger.LogDebug("Creating factory");
FakeMemoryManager::GetInstance(); // Make sure the fake memory manager is destroyed at the right
// time
// Must be at end of function
PushDestroyCallbacks();
}
SharedMemoryFactory::~SharedMemoryFactory() {
Logger.LogDebug("Destroying factory");
}
void SharedMemoryFactory::OnSystemDestroy() {
delete this;
}
} // namespace OVR

View File

@ -0,0 +1,229 @@
/************************************************************************************
PublicHeader: OVR
Filename : OVR_SharedMemory.h
Content : Inter-process shared memory subsystem
Created : June 1, 2014
Notes :
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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_SharedMemory_h
#define OVR_SharedMemory_h
#include "OVR_Types.h"
#include "OVR_RefCount.h"
#include "OVR_Allocator.h"
#include "OVR_System.h"
#include "OVR_String.h"
namespace OVR {
class SharedMemoryInternalBase; // Opaque
// SharedMemory
// Note: Safe when used between 32-bit and 64-bit processes
class SharedMemory : public RefCountBase<SharedMemory> {
friend class SharedMemoryFactory;
OVR_NON_COPYABLE(SharedMemory);
public:
// Only constructed by the SharedMemory Factory
SharedMemory(int size, void* data, const String& name, SharedMemoryInternalBase* pInternal);
// Call close when it goes out of scope
~SharedMemory();
// Modes for opening a new shared memory region
enum OpenMode {
// Note: On Windows, Create* requires Administrator priviledges or running as a Service.
OpenMode_CreateOnly, // Must not already exist
OpenMode_OpenOnly, // Must already exist
OpenMode_CreateOrOpen // May exist or not
};
// Local access restrictions
enum AccessMode {
AccessMode_ReadOnly, // Acquire read-only access
AccessMode_ReadWrite, // Acquire read or write access
};
// Remote access restrictions
enum RemoteMode {
RemoteMode_ReadOnly, // Other processes will need to open in read-only mode
RemoteMode_ReadWrite // Other processes can open in read-write mode
};
// Modes for opening a new shared memory region
struct OpenParameters {
OpenParameters()
: globalName(NULL),
minSizeBytes(0),
openMode(SharedMemory::OpenMode_CreateOrOpen),
remoteMode(SharedMemory::RemoteMode_ReadWrite),
accessMode(SharedMemory::AccessMode_ReadWrite) {}
// Creation parameters
const char* globalName; // Name of the shared memory region
int minSizeBytes; // Minimum number of bytes to request
SharedMemory::OpenMode openMode; // Creating the file or opening the file?
SharedMemory::RemoteMode remoteMode; // When creating, what access should other processes get?
SharedMemory::AccessMode
accessMode; // When opening/creating, what access should this process get?
};
public:
// Returns the size of the shared memory region
int GetSizeI() const {
return Size;
}
// Returns the process-local pointer to the shared memory region
// Note: This may be different on different processes
void* GetData() const {
return Data;
}
// Returns the name of the shared memory region
String GetName() {
return Name;
}
protected:
int Size; // How many shared bytes are shared at the pointer address?
void* Data; // Pointer to the shared memory region.
String Name; // Name that can be used to access this region
// Hidden implementation class for OS-specific behavior
SharedMemoryInternalBase* Internal;
// Close and cleanup the shared memory region
// Note: This is called on destruction
void Close();
public:
static void SetFakeSharedMemory(bool enabled);
static bool IsFakingSharedMemory();
};
// SharedMemoryFactory
class SharedMemoryFactory : public NewOverrideBase,
public SystemSingletonBase<SharedMemoryFactory> {
OVR_DECLARE_SINGLETON(SharedMemoryFactory);
public:
// Construct a SharedMemory object.
// Note: The new object is reference-counted so it should be stored with Ptr<>. Initial reference
// count is 1.
Ptr<SharedMemory> Open(const SharedMemory::OpenParameters&);
};
// A shared object
// Its constructor will be called when creating a writer
// Its destructor will not be called
template <class SharedType>
class ISharedObject : public RefCountBase<ISharedObject<SharedType>> {
public:
static const int RegionSize = (int)sizeof(SharedType);
protected:
Ptr<SharedMemory> pSharedMemory;
bool Open(const char* name, bool readOnly) {
// Configure open parameters based on read-only mode
SharedMemory::OpenParameters params;
// FIXME: This is a hack. We currently need to allow clients to open this for read-write even
// though they only need read-only access. This is because in the first 0.4 release the
// LocklessUpdater class technically writes to it (increments by 0) to read from the space.
// This was quickly corrected in 0.4.1 and we are waiting for the right time to disallow write
// access when everyone upgrades to 0.4.1+.
// params.remoteMode = SharedMemory::RemoteMode_ReadOnly;
params.remoteMode = SharedMemory::RemoteMode_ReadWrite;
params.globalName = name;
params.accessMode =
readOnly ? SharedMemory::AccessMode_ReadOnly : SharedMemory::AccessMode_ReadWrite;
params.minSizeBytes = RegionSize;
params.openMode =
readOnly ? SharedMemory::OpenMode_OpenOnly : SharedMemory::OpenMode_CreateOrOpen;
// Attempt to open the shared memory file
pSharedMemory = SharedMemoryFactory::GetInstance()->Open(params);
// If it was not able to be opened,
if (pSharedMemory && pSharedMemory->GetSizeI() >= RegionSize && pSharedMemory->GetData()) {
// If writing,
if (!readOnly) {
// Construct the object also
Construct<SharedType>(pSharedMemory->GetData());
}
return true;
}
return false;
}
SharedType* Get() const {
if (!pSharedMemory) {
return NULL;
}
void* data = pSharedMemory->GetData();
if (!data) {
return NULL;
}
return reinterpret_cast<SharedType*>(data);
}
public:
String GetName() const {
return pSharedMemory ? pSharedMemory->GetName() : "";
}
};
// Writer specialized shared object: Ctor will be called on Open()
template <class SharedType>
class SharedObjectWriter : public ISharedObject<SharedType> {
public:
OVR_FORCE_INLINE bool Open(const char* name) {
return ISharedObject<SharedType>::Open(name, false);
}
OVR_FORCE_INLINE SharedType* Get() {
return ISharedObject<SharedType>::Get();
}
};
// Reader specialized shared object: Ctor will not be called
template <class SharedType>
class SharedObjectReader : public ISharedObject<SharedType> {
public:
OVR_FORCE_INLINE bool Open(const char* name) {
return ISharedObject<SharedType>::Open(name, true);
}
OVR_FORCE_INLINE const SharedType* Get() const {
return ISharedObject<SharedType>::Get();
}
};
} // namespace OVR
#endif // OVR_SharedMemory_h

View File

@ -0,0 +1,523 @@
/************************************************************************************
Filename : OVR_Std.h
Content : Standard C function interface
Created : September 19, 2012
Notes :
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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_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 {
// Has the same behavior as itoa aside from also having a dest size argument.
// Return value: Pointer to the resulting null-terminated string, same as parameter str.
#if defined(OVR_OS_MS)
inline char* OVR_CDECL OVR_itoa(int val, char* dest, size_t 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_MS
inline char* OVR_itoa(int val, char* dest, size_t len, int radix) {
if (val == 0) {
if (len > 1) {
dest[0] = '0';
dest[1] = '\0';
} else if (len > 0)
dest[0] = '\0';
return dest;
}
// FIXME: Fix the following code to avoid memory write overruns when len is in sufficient.
int cur = val;
size_t i = 0;
size_t 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 (size_t 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 size_t OVR_CDECL OVR_strlen(const char* str) {
return strlen(str);
}
inline size_t OVR_CDECL OVR_strlen(const wchar_t* str) {
return wcslen(str);
}
inline char* OVR_CDECL OVR_strcpy(char* dest, size_t destsize, const char* src) {
#if defined(OVR_MSVC_SAFESTRING)
// Using strncpy_s() instead of strcpy_s() since strcpy_s will invoke the
// invalid parameter exception handler (now in google breakpad) and will
// cause the server to crash, and even if it returns the data may not be
// copied truncated. The intent of all users surveyed has been to truncate
// so we specify strncpy_s with the truncate option instead.
strncpy_s(dest, destsize, src, _TRUNCATE);
return dest;
#else
// FIXME: This should be a safer implementation
OVR_UNUSED(destsize);
return strcpy(dest, src);
#endif
}
inline wchar_t* OVR_CDECL OVR_strcpy(wchar_t* dest, size_t destsize, const wchar_t* src) {
#if defined(OVR_MSVC_SAFESTRING)
wcscpy_s(dest, destsize, src);
return dest;
#else
// FIXME: This should be a safer implementation
OVR_UNUSED(destsize);
return wcscpy(dest, src);
#endif
}
// Acts the same as the strlcpy function.
// Copies src to dest, 0-terminating even if it involves truncating the write.
// Returns the required strlen of dest (which is one less than the required size of dest).
// strlcpy is a safer alternative to strcpy and strncpy and provides size information.
// However, it still may result in an incomplete copy.
//
// Example usage:
// char buffer[256];
// if(OVR_strlcpy(buffer, "hello world", sizeof(buffer)) < sizeof(buffer))
// { there was enough space }
// else
// { need a larger buffer }
//
size_t OVR_CDECL OVR_strlcpy(char* dest, const char* src, size_t destsize);
size_t OVR_CDECL OVR_strlcpy(wchar_t* dest, const wchar_t* src, size_t destsize);
// Acts the same as the strlcat function.
// Appends src to dest, 0-terminating even if it involves an incomplete write.
// Doesn't 0-terminate in the case that destsize is 0.
// Returns the required strlen of dest (which is one less than the required size of dest).
// The terminating 0 char of dest is overwritten by the first
// character of src, and a new 0 char is appended to dest. The required capacity
// of the destination is (strlen(src) + strlen(dest) + 1).
// strlcat is a safer alternative to strcat and provides size information.
// However, it still may result in an incomplete copy.
//
// Example usage:
// char buffer[256] = "hello ";
// if(OVR_strlcat(buffer, "world", sizeof(buffer)) < sizeof(buffer))
// { there was enough space }
// else
// { need a larger buffer }
//
size_t OVR_CDECL OVR_strlcat(char* dest, const char* src, size_t destsize);
size_t OVR_CDECL OVR_strlcat(wchar_t* dest, const wchar_t* src, size_t destsize);
inline char* OVR_CDECL OVR_strncpy(char* dest, size_t destsize, const char* src, size_t count) {
#if defined(OVR_MSVC_SAFESTRING)
strncpy_s(dest, destsize, src, count);
return dest;
#else
// FIXME: This should be a safer implementation
OVR_UNUSED(destsize);
return strncpy(dest, src, count);
#endif
}
inline char* OVR_CDECL OVR_strcat(char* dest, size_t destsize, const char* src) {
#if defined(OVR_MSVC_SAFESTRING)
strcat_s(dest, destsize, src);
return dest;
#else
// FIXME: This should be a safer implementation
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);
}
const char* OVR_CDECL OVR_strrchr(const char* pString, int c);
inline char* OVR_CDECL OVR_strrchr(char* pString, int c) {
return (char*)OVR_strrchr((const char*)pString, c);
}
// Supports ASCII strings only, by calling tolower on each element.
char* OVR_CDECL OVR_stristr(const char* s1, const char* s2);
// Converts each element via towlower.
wchar_t* OVR_CDECL OVR_stristr(const wchar_t* s1, const wchar_t* s2);
inline const uint8_t* OVR_CDECL OVR_memrchr(const uint8_t* str, size_t size, uint8_t c) {
for (intptr_t i = (intptr_t)size - 1; 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 unsigned 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, size_t size) {
return strncmp(ws1, ws2, size);
}
inline uint64_t OVR_CDECL OVR_strtouq(const char* nptr, char** endptr, int base) {
#if defined(OVR_CC_MSVC)
return _strtoui64(nptr, endptr, base);
#else
return strtoull(nptr, endptr, base);
#endif
}
inline int64_t OVR_CDECL OVR_strtoq(const char* nptr, char** endptr, int base) {
#if defined(OVR_CC_MSVC)
return _strtoi64(nptr, endptr, base);
#else
return strtoll(nptr, endptr, base);
#endif
}
inline int64_t OVR_CDECL OVR_atoq(const char* string) {
#if defined(OVR_CC_MSVC)
return _atoi64(string);
#else
return atoll(string);
#endif
}
inline uint64_t OVR_CDECL OVR_atouq(const char* string) {
return OVR_strtouq(string, NULL, 10);
}
// Implemented in OVR_Std.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, size_t count);
// This is like vsprintf but with a destination buffer size argument. However, the behavior is
// different
// from vsnprintf in that the return value semantics are like vsprintf (which returns -1 on capacity
// overflow) and
// not like vsnprintf (which returns intended strlen on capacity overflow).
// Return value:
// On success, the total number of characters written is returned.
// On failure, a negative number is returned.
inline size_t OVR_CDECL
OVR_vsprintf(char* dest, size_t destsize, const char* format, va_list argList) {
size_t 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 = (size_t)rv;
#else
OVR_UNUSED(destsize);
int rv = _vsnprintf(dest, destsize - 1, format, argList);
OVR_ASSERT(rv != -1);
ret = (size_t)rv;
dest[destsize - 1] = 0;
#endif
#else
// FIXME: This should be a safer implementation
OVR_UNUSED(destsize);
ret = (size_t)vsprintf(dest, format, argList);
OVR_ASSERT(ret < destsize);
#endif
return ret;
}
// Returns the strlen of the resulting formatted string, or a negative value if the format is
// invalid.
// Note: If you are planning on printing a string then it's more efficient to just use vsnprintf and
// look at the return value and handle the uncommon case that there wasn't enough space.
inline int OVR_CDECL OVR_vscprintf(const char* format, va_list argList) {
int ret;
#if defined(OVR_CC_MSVC)
ret = _vscprintf(format, argList);
#else
ret = vsnprintf(NULL, 0, format, argList);
#endif
return ret;
}
wchar_t* OVR_CDECL OVR_wcscpy(wchar_t* dest, size_t destsize, const wchar_t* src);
wchar_t* OVR_CDECL OVR_wcsncpy(wchar_t* dest, size_t destsize, const wchar_t* src, size_t count);
wchar_t* OVR_CDECL OVR_wcscat(wchar_t* dest, size_t destsize, const wchar_t* src);
size_t 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_MS)
#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_MS) || 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_t* 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_t UnicodeAlnumBits[];
extern const uint16_t UnicodeAlphaBits[];
extern const uint16_t UnicodeDigitBits[];
extern const uint16_t UnicodeSpaceBits[];
extern const uint16_t UnicodeXDigitBits[];
// Uncomment if necessary
// extern const uint16_t UnicodeCntrlBits[];
// extern const uint16_t UnicodeGraphBits[];
// extern const uint16_t UnicodeLowerBits[];
// extern const uint16_t UnicodePrintBits[];
// extern const uint16_t UnicodePunctBits[];
// extern const uint16_t 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;
size_t max = OVR_wcslen(string);
if (max > 63)
max = 63;
unsigned char c = 0;
for (size_t 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;
size_t max = OVR_wcslen(string);
if (max > 63)
max = 63;
unsigned char c = 0;
for (size_t 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
}
} // namespace OVR
#endif // OVR_Std_h

View File

@ -0,0 +1,370 @@
/************************************************************************************
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 (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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>
#include <atomic>
namespace OVR {
// Return the byte size of the UTF-8 string corresponding to pchar (not including null termination)
static size_t GetEncodeStringSize(const wchar_t* pchar, size_t length = StringIsNullTerminated) {
size_t len = 0;
if (length == StringIsNullTerminated) {
for (size_t i = 0; pchar[i] != 0; ++i) {
len += UTF8Util::GetEncodeCharSize(pchar[i]);
}
} else {
for (size_t i = 0; i < length; ++i) {
len += UTF8Util::GetEncodeCharSize(pchar[i]);
}
}
return len;
}
static size_t StringStrlcpy(
char* pDestUTF8,
size_t destCharCountNotIncludingNull,
const wchar_t* pSrcUCS,
size_t sourceLength = StringIsNullTerminated) {
// String Data[] buffers always have one extra character for null-termination
return UTF8Util::Strlcpy(pDestUTF8, destCharCountNotIncludingNull + 1, pSrcUCS, sourceLength);
}
static size_t StringStrlcpy(
wchar_t* pDestUCS,
size_t destCharCountNotIncludingNull,
const char* pSrcUTF8,
size_t sourceLength = StringIsNullTerminated) {
// String Data[] buffers always have one extra character for null-termination
return UTF8Util::Strlcpy(pDestUCS, destCharCountNotIncludingNull + 1, pSrcUTF8, sourceLength);
}
// ***** 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(size_t 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, size_t 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(size_t growSize) {
if (growSize <= 16)
GrowSize = 16;
else {
uint8_t bits = Alg::UpperBit(uint32_t(growSize - 1));
size_t size = (size_t)1 << bits;
GrowSize = size == growSize ? growSize : size;
}
}
size_t StringBuffer::GetLength() const {
size_t length, size = GetSize();
if (LengthIsSize)
return size;
length = (size_t)UTF8Util::GetLength(pData, (size_t)GetSize());
if (length == GetSize())
LengthIsSize = true;
return length;
}
void StringBuffer::Reserve(size_t _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(size_t _size) {
Reserve(_size);
LengthIsSize = false;
Size = _size;
if (pData)
pData[Size] = 0;
}
void StringBuffer::Clear() {
Resize(0);
}
// Appends a character
void StringBuffer::AppendChar(uint32_t ch) {
char buff[8];
size_t 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.
intptr_t srcSize = 0;
UTF8Util::EncodeChar(buff, &srcSize, ch);
OVR_ASSERT(srcSize >= 0);
size_t size = origSize + srcSize;
Resize(size);
OVR_ASSERT(pData != NULL);
memcpy(pData + origSize, buff, srcSize);
}
// Append a string
void StringBuffer::AppendString(const wchar_t* pstr, size_t len) {
if (!pstr || !len)
return;
size_t srcSize = GetEncodeStringSize(pstr, len);
size_t origSize = GetSize();
size_t size = srcSize + origSize;
Resize(size);
OVR_ASSERT(pData != NULL);
StringStrlcpy(pData + origSize, srcSize, pstr, len);
}
void StringBuffer::AppendString(const char* putf8str, size_t utf8StrSz) {
if (!putf8str || !utf8StrSz)
return;
if (utf8StrSz == StringIsNullTerminated)
utf8StrSz = OVR_strlen(putf8str);
size_t origSize = GetSize();
size_t size = utf8StrSz + origSize;
Resize(size);
OVR_ASSERT(pData != NULL);
memcpy(pData + origSize, putf8str, utf8StrSz);
}
// If pstr is NULL then the StringBuffer is cleared.
void StringBuffer::operator=(const char* pstr) {
pstr = pstr ? pstr : "";
size_t size = OVR_strlen(pstr);
Resize(size);
OVR_ASSERT((pData != NULL) || (size == 0));
memcpy(pData, pstr, size);
}
// If pstr is NULL then the StringBuffer is cleared.
void StringBuffer::operator=(const wchar_t* pstr) {
pstr = pstr ? pstr : L"";
size_t size = GetEncodeStringSize(pstr);
Resize(size);
OVR_ASSERT((pData != NULL) || (size == 0));
StringStrlcpy(pData, size, pstr);
}
void StringBuffer::operator=(const String& src) {
const size_t size = src.GetSize();
Resize(size);
OVR_ASSERT((pData != NULL) || (size == 0));
memcpy(pData, src.ToCStr(), size);
}
void StringBuffer::operator=(const StringBuffer& src) {
Clear();
AppendString(src.ToCStr(), src.GetSize());
}
// Inserts substr at posAt
void StringBuffer::Insert(const char* substr, size_t posAt, size_t len) {
size_t oldSize = Size;
size_t insertSize = (len == StringIsNullTerminated) ? OVR_strlen(substr) : len;
size_t byteIndex =
LengthIsSize ? posAt : (size_t)UTF8Util::GetByteIndex(posAt, pData, (intptr_t)Size);
OVR_ASSERT(byteIndex <= oldSize);
Reserve(oldSize + insertSize);
OVR_ASSERT(pData != NULL); // pData is unilaterally written to below.
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
size_t StringBuffer::InsertCharAt(uint32_t c, size_t posAt) {
char buf[8];
intptr_t len = 0;
UTF8Util::EncodeChar(buf, &len, c);
OVR_ASSERT(len >= 0);
buf[(size_t)len] = 0;
Insert(buf, posAt, len);
return (size_t)len;
}
std::string StringVsprintf(const char* format, va_list args) {
char buffer[512]; // We first try writing into this buffer. If it's not enough then use a string.
va_list tmp_args;
va_copy(tmp_args, args);
const int requiredStrlen = vsnprintf(buffer, sizeof(buffer), format, tmp_args);
va_end(tmp_args);
if (requiredStrlen <
static_cast<int>(sizeof(buffer))) { // If the entire result fits into the buffer.
return std::string(buffer, requiredStrlen);
}
std::string result(requiredStrlen, '\0');
std::vsnprintf(&result[0], result.size(), format, args);
return result;
}
std::string& AppendSprintf(std::string& s, const char* format, ...) {
va_list args;
va_start(args, format);
s += StringVsprintf(format, args);
va_end(args);
return s;
}
std::wstring UTF8StringToUCSString(const char* pUTF8, size_t length) {
if (length == StringIsNullTerminated)
length = OVR_strlen(pUTF8);
std::wstring returnValue(length, wchar_t(0)); // We'll possibly trim this value below.
// Note that Strlcpy doesn't handle UTF8 encoding errors.
size_t decodedLength = StringStrlcpy(&returnValue[0], length, pUTF8, length);
OVR_ASSERT(decodedLength <= length);
returnValue.resize(decodedLength);
return returnValue;
}
std::wstring UTF8StringToUCSString(const std::string& sUTF8) {
return UTF8StringToUCSString(sUTF8.data(), sUTF8.size());
}
std::wstring OVRStringToUCSString(const String& sOVRUTF8) {
return UTF8StringToUCSString(sOVRUTF8.ToCStr(), sOVRUTF8.GetSize());
}
std::string UCSStringToUTF8String(const wchar_t* pUCS, size_t length) {
if (length == StringIsNullTerminated)
length = wcslen(pUCS);
std::string sUTF8;
size_t size = GetEncodeStringSize(pUCS, length);
sUTF8.resize(size);
StringStrlcpy(&sUTF8[0], size, pUCS, length);
return sUTF8;
}
std::string UCSStringToUTF8String(const std::wstring& sUCS) {
return UCSStringToUTF8String(sUCS.data(), sUCS.size());
}
String UCSStringToOVRString(const wchar_t* pUCS, size_t length) {
if (length == StringIsNullTerminated)
length = wcslen(pUCS);
// We use a std::string intermediate because String doesn't support resize or assignment without
// preallocated data.
const std::string sUTF8 = UCSStringToUTF8String(pUCS, length);
const String sOVRUTF8(sUTF8.data(), sUTF8.size());
return sOVRUTF8;
}
String UCSStringToOVRString(const std::wstring& sUCS) {
return UCSStringToOVRString(sUCS.data(), sUCS.length());
}
} // namespace OVR

View File

@ -0,0 +1,597 @@
/************************************************************************************
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 (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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"
#include <string>
#include <stdarg.h>
namespace OVR {
class String;
class StringBuffer;
// Special/default null-terminated length argument
const size_t StringIsNullTerminated = size_t(-1);
//-----------------------------------------------------------------------------------
// ***** String Class
// String is UTF8 based string class with copy-on-write implementation
// for assignment.
class String : public std::string {
public:
typedef std::string inherited;
// Constructors / Destructors.
String() {}
String(const char* data) {
if (data)
inherited::assign(data);
}
String(const char* data1, const char* pdata2, const char* pdata3 = nullptr) {
if (data1)
inherited::append(data1);
if (pdata2)
inherited::append(pdata2);
if (pdata3)
inherited::append(pdata3);
}
String(const char* data, size_t buflen) {
if (data)
inherited::assign(data, buflen);
}
String(const String& src) {
inherited::assign(src.data(), src.length());
}
String(const std::string& src) {
inherited::assign(src.data(), src.length());
}
explicit String(const wchar_t* data) {
if (data)
String::operator=(data); // Need to do UCS2->UTF8 conversion
}
void Clear() {
inherited::clear();
}
operator const char*() const {
return inherited::c_str();
}
const char* ToCStr() const {
return inherited::c_str();
}
// Byte length.
size_t GetSize() const {
return inherited::size();
}
bool IsEmpty() const {
return inherited::empty();
}
// Returns number of Unicode codepoints (not byte length).
size_t GetLength() const {
return (size_t)UTF8Util::GetLength(inherited::data(), inherited::size());
}
// Return Unicode codepoint count.
int GetLengthI() const {
return (int)UTF8Util::GetLength(inherited::data(), inherited::size());
}
// Return Unicode codepoint at the specified codepoint index.
uint32_t GetCharAt(size_t index) const {
return UTF8Util::GetCharAt(index, inherited::data(), inherited::size());
}
// Get first Unicode codepoint.
uint32_t Front() const {
return UTF8Util::GetCharAt(0, inherited::data(), inherited::size());
}
// Get last Unicode codepoint.
uint32_t Back() const {
OVR_ASSERT(!inherited::empty());
return GetCharAt(GetSize() - 1);
}
// Append a Unicode codepoint.
void AppendChar(uint32_t ch) {
char buff[8]; // Max possible UTF8 sequence is 6 bytes.
intptr_t encodeSize = 0;
UTF8Util::EncodeChar(buff, &encodeSize, ch);
inherited::append(buff, encodeSize);
}
// Append Unicode codepoints
void AppendString(const wchar_t* pstr, size_t len = StringIsNullTerminated) {
if (pstr) {
if (len == StringIsNullTerminated)
len = wcslen(pstr);
while (len-- > 0)
AppendChar(*pstr++);
}
}
// Append UTF8 stirng of a given byte size.
void AppendString(const char* putf8str, size_t utf8StrSz = StringIsNullTerminated) {
if (putf8str) {
if (utf8StrSz == StringIsNullTerminated)
inherited::append(putf8str);
else
inherited::append(putf8str, utf8StrSz);
}
}
// Assigns string with known byte size.
void AssignString(const char* putf8str, size_t size) {
if (putf8str || (size == 0))
inherited::assign(putf8str, size);
}
// Remove 'removeLength' Unicode codepoints starting at the 'posAt' Unicode codepoint.
void Remove(size_t posAt, size_t removeLength = 1) {
size_t length = GetLength(); // Unicode size.
if (posAt < length) {
size_t oldSize = inherited::size(); // Byte size.
if ((posAt + removeLength) > length)
removeLength = (length - posAt);
intptr_t bytePos = UTF8Util::GetByteIndex(posAt, inherited::data(), oldSize);
intptr_t removeSize =
UTF8Util::GetByteIndex(removeLength, inherited::data() + bytePos, oldSize - bytePos);
inherited::erase(bytePos, removeSize);
}
}
// Removes the last Unicode codepoint.
void PopBack() {
if (!inherited::empty())
Remove(GetLength() - 1, 1);
}
// Returns a String that's a substring of this.
// start is the index of the first Unicode codepoint you want to include.
// end is the index one past the last Unicode codepoint you want to include.
String Substring(size_t start, size_t end) const {
size_t length = GetLength();
if ((start >= length) || (start >= end))
return String();
if (end > length)
end = length;
// Get position of starting character and size
intptr_t byteStart = UTF8Util::GetByteIndex(start, inherited::data(), inherited::size());
intptr_t byteSize = UTF8Util::GetByteIndex(
end - start, inherited::data() + byteStart, inherited::size() - byteStart);
return String(inherited::data() + byteStart, (size_t)byteSize);
}
// Insert a UTF8 string at the Unicode codepoint posAt.
String& Insert(const char* substr, size_t posAt, size_t strSize = StringIsNullTerminated) {
if (substr) {
if (strSize == StringIsNullTerminated)
strSize = strlen(substr);
size_t byteIndex = UTF8Util::GetByteIndex(posAt, inherited::c_str(), inherited::size());
if (byteIndex > inherited::size())
byteIndex = inherited::size();
inherited::insert(byteIndex, substr, strSize);
}
return *this;
}
// UTF8 compare
static int CompareNoCase(const char* a, const char* b) {
return OVR_stricmp(a, b);
}
// UTF8 compare
static int CompareNoCase(const char* a, const char* b, size_t byteSize) {
return OVR_strnicmp(a, b, byteSize);
}
// Hash function, case-insensitive
static size_t BernsteinHashFunctionCIS(const void* pdataIn, size_t size, size_t seed = 5381) {
const uint8_t* pdata = (const uint8_t*)pdataIn;
size_t h = seed;
while (size > 0) {
size--;
h = ((h << 5) + h) ^ OVR_tolower(pdata[size]);
}
return h;
}
// Hash function, case-sensitive
static size_t BernsteinHashFunction(const void* pdataIn, size_t size, size_t seed = 5381) {
const uint8_t* pdata = (const uint8_t*)pdataIn;
size_t h = seed;
while (size > 0) {
size--;
h = ((h << 5) + h) ^ (unsigned)pdata[size];
}
return h;
}
// 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(inherited::c_str());
}
bool HasExtension() const {
return HasExtension(inherited::c_str());
}
bool HasProtocol() const {
return HasProtocol(inherited::c_str());
}
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.
void operator=(const char* str) {
if (str)
inherited::assign(str);
else
inherited::clear();
}
void operator=(const wchar_t* str) {
inherited::clear();
while (str && *str)
AppendChar(*str++);
}
void operator=(const String& src) {
inherited::assign(src.data(), src.size());
}
void operator+=(const String& src) {
inherited::append(src.data(), src.size());
}
void operator+=(const char* psrc) {
if (psrc)
inherited::append(psrc);
}
void operator+=(const wchar_t* psrc) {
if (psrc)
AppendString(psrc);
}
// Append a Unicode codepoint.
// Note that this function seems amiss by taking char as an argument instead of uint32_t or
// wchar_t.
void operator+=(char ch) {
AppendChar(ch);
}
String operator+(const char* str) const {
String temp(*this);
if (str)
temp += str;
return temp;
}
String operator+(const String& src) const {
String temp(*this);
temp += src;
return temp;
}
bool operator==(const String& str) const {
return (OVR_strcmp(inherited::c_str(), str.c_str()) == 0);
}
bool operator!=(const String& str) const {
return !operator==(str);
}
bool operator==(const char* str) const {
return OVR_strcmp(inherited::c_str(), (str ? str : "")) == 0;
}
bool operator!=(const char* str) const {
return !operator==(str);
}
bool operator<(const char* pstr) const {
return OVR_strcmp(inherited::c_str(), (pstr ? pstr : "")) < 0;
}
bool operator<(const String& str) const {
return *this < str.c_str();
}
bool operator>(const char* pstr) const {
return OVR_strcmp(inherited::c_str(), (pstr ? pstr : "")) > 0;
}
bool operator>(const String& str) const {
return *this > str.c_str();
}
int CompareNoCase(const char* pstr) const {
return CompareNoCase(inherited::c_str(), (pstr ? pstr : ""));
}
int CompareNoCase(const String& str) const {
return CompareNoCase(inherited::c_str(), str.c_str());
}
int CompareNoCaseStartsWith(const String& str) const {
// Problem: the original version of this used GetLength, which seems like a bug because
// CompareNoCase takes a byte length. Need to look back in the OVR_String.h history to see if
// the bug has always been there.
return CompareNoCase(inherited::c_str(), str.c_str(), str.size());
}
// Accesses raw bytes
const char& operator[](int index) const {
OVR_ASSERT(index >= 0 && (size_t)index < inherited::size());
return inherited::operator[](index);
}
const char& operator[](size_t index) const {
OVR_ASSERT(index < inherited::size());
return inherited::operator[](index);
}
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 {
size_t operator()(const String& str) const {
return String::BernsteinHashFunction(str.data(), str.size());
}
};
// Case-insensitive hash functor used for strings. Supports additional
// lookup based on NoCaseKey.
struct NoCaseHashFunctor {
size_t operator()(const String& str) const {
return String::BernsteinHashFunctionCIS(str.data(), str.size());
}
size_t operator()(const NoCaseKey& key) const {
return String::BernsteinHashFunctionCIS(key.pStr->c_str(), key.pStr->size());
}
};
};
//-----------------------------------------------------------------------------------
// ***** String Buffer used for Building Strings
class StringBuffer {
char* pData;
size_t Size;
size_t BufferSize;
size_t GrowSize;
mutable bool LengthIsSize;
public:
// Constructors / Destructor.
StringBuffer();
explicit StringBuffer(size_t growSize);
StringBuffer(const char* data);
StringBuffer(const char* data, size_t 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.
size_t GetGrowSize() const {
return GrowSize;
}
void SetGrowSize(size_t 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.
size_t GetSize() const {
return Size;
}
// Tells whether or not the string is empty.
bool IsEmpty() const {
return GetSize() == 0;
}
// Returns number of characters
size_t GetLength() const;
// Returns character at the specified index
uint32_t GetCharAt(size_t index) const;
uint32_t GetFirstCharAt(size_t index, const char** offset) const;
uint32_t GetNextChar(const char** offset) const;
uint32_t Front() const {
return GetCharAt(0);
}
uint32_t Back() const {
return GetCharAt(GetSize() - 1);
}
// Resize the string to the new size
void Resize(size_t _size);
void Reserve(size_t _size);
// Appends a character
void AppendChar(uint32_t ch);
// Append a string
void AppendString(const wchar_t* pstr, size_t len = StringIsNullTerminated);
void AppendString(const char* putf8str, size_t utf8StrSz = StringIsNullTerminated);
void AppendFormatV(const char* format, va_list argList);
void AppendFormat(const char* format, ...);
// Assigned a string with dynamic data (copied through initializer).
// void AssignString(const InitStruct& src, size_t size);
// Inserts substr at posAt
void Insert(const char* substr, size_t posAt, size_t len = StringIsNullTerminated);
// Inserts character at posAt
size_t InsertCharAt(uint32_t c, size_t 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[](size_t index) {
OVR_ASSERT(index < GetSize());
return pData[index];
}
const char& operator[](size_t index) const {
OVR_ASSERT(index < GetSize());
return pData[index];
}
};
// Returns a std::string that was initialized via printf-style formatting.
// The behavior is undefined if the specified format or arguments are invalid.
// Example usage:
// std::string s = StringVsprintf("Hello %s", "world");
std::string StringVsprintf(const char* format, va_list args);
// Returns a std::string that was appended to via printf-style formatting.
// The behavior is undefined if the specified format or arguments are invalid.
// Example usage:
// AppendSprintf(s, "appended %s", "hello world");
std::string& AppendSprintf(std::string& s, const char* format, ...);
// Convert a UTF8 String object to a wchar_t UCS (Unicode) std::basic_string object.
// The C++11 Standard Library has similar functionality, but it's not supported by earlier
// versions of Visual Studio. To consider: Add support for this when available.
// length is the strlen of pUTF8. If not specified then it is calculated automatically.
// Returns an empty string in the case that the UTF8 is malformed.
std::wstring UTF8StringToUCSString(const char* pUTF8, size_t length = StringIsNullTerminated);
std::wstring UTF8StringToUCSString(const std::string& sUTF8);
std::wstring OVRStringToUCSString(const String& sOVRUTF8);
// Convert a wchar_t UCS (Unicode) std::basic_string object to a UTF8 std::basic_string object.
// The C++11 Standard Library has similar functionality, but it's not supported by earlier
// versions of Visual Studio. To consider: Add support for this when available.
// length is the strlen of pUCS. If not specified then it is calculated automatically.
// Returns an empty string in the case that the UTF8 is malformed.
std::string UCSStringToUTF8String(const wchar_t* pUCS, size_t length = StringIsNullTerminated);
std::string UCSStringToUTF8String(const std::wstring& sUCS);
String UCSStringToOVRString(const wchar_t* pUCS, size_t length = StringIsNullTerminated);
String UCSStringToOVRString(const std::wstring& sUCS);
} // namespace OVR
#endif

View File

@ -0,0 +1,91 @@
/************************************************************************************
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 (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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);
}
}
};
} // namespace OVR
#endif

View File

@ -0,0 +1,78 @@
/************************************************************************************
Filename : OVR_String_FormatUtil.cpp
Content : String format functions.
Created : February 27, 2013
Notes :
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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"
#include <stdarg.h>
namespace OVR {
void StringBuffer::AppendFormatV(const char* format, va_list argList) {
char buffer[512];
char* bufferUsed = buffer;
char* bufferAllocated = NULL;
va_list argListSaved;
va_copy(argListSaved, argList);
int requiredStrlen = vsnprintf(
bufferUsed,
OVR_ARRAY_COUNT(buffer),
format,
argListSaved); // The large majority of the time this will succeed.
if (requiredStrlen >= (int)sizeof(buffer)) // If the initial capacity wasn't enough...
{
bufferAllocated = (char*)OVR_ALLOC(sizeof(char) * (requiredStrlen + 1));
bufferUsed = bufferAllocated;
if (bufferAllocated) {
va_end(argListSaved);
va_copy(argListSaved, argList);
requiredStrlen = vsnprintf(bufferAllocated, (requiredStrlen + 1), format, argListSaved);
}
}
if (requiredStrlen < 0) // If there was a printf format error...
{
bufferUsed = NULL;
}
va_end(argListSaved);
if (bufferUsed)
AppendString(bufferUsed);
if (bufferAllocated)
OVR_FREE(bufferAllocated);
}
void StringBuffer::AppendFormat(const char* format, ...) {
va_list argList;
va_start(argList, format);
AppendFormatV(format, argList);
va_end(argList);
}
} // namespace OVR

View File

@ -0,0 +1,183 @@
/************************************************************************************
Filename : OVR_String_PathUtil.cpp
Content : String filename/url helper function
Created : September 19, 2012
Notes :
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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_t 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) {
if (filename)
*pfilename = filename;
else
*pfilename = urlStart;
}
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_t charVal = UTF8Util::DecodeNextChar(&url);
uint32_t 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_t 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));
}
} // namespace OVR

View File

@ -0,0 +1,159 @@
/**************************************************************************
Filename : OVR_SysFile.cpp
Content : File wrapper class implementation (Win32)
Created : April 5, 1999
Authors : Michael Antonov
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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_File.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 int64_t LTell() {
return 0;
}
virtual int GetLength() {
return 0;
}
virtual int64_t LGetLength() {
return 0;
}
// virtual bool Stat(FileStats *pfs) { return 0; }
virtual int GetErrorCode() {
return Error_FileNotFound;
}
// ** Stream implementation & I/O
virtual int Write(const uint8_t* /*pbuffer*/, int /*numBytes*/) {
return -1;
}
virtual int Read(uint8_t* /*pbuffer*/, int /*numBytes*/) {
return -1;
}
virtual int SkipBytes(int /*numBytes*/) {
return 0;
}
virtual int BytesAvailable() {
return 0;
}
virtual bool Flush() {
return 0;
}
virtual int Seek(int /*offset*/, int /*origin*/) {
return -1;
}
virtual int64_t LSeek(int64_t /*offset*/, int /*origin*/) {
return -1;
}
virtual int CopyFromStream(File* /*pstream*/, int /*byteSize*/) {
return -1;
}
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;
}
} // namespace OVR

View File

@ -0,0 +1,105 @@
/************************************************************************************
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 (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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
int64_t ModifyTime;
int64_t AccessTime;
int64_t FileSize;
bool operator==(const FileStat& stat) const {
return (
(ModifyTime == stat.ModifyTime) && (AccessTime == stat.AccessTime) &&
(FileSize == stat.FileSize));
}
};
//-----------------------------------------------------------------------------------
// *** System File
// System file is created to access objects on file system directly
// This file can refer directly to path.
// System file can be open & closed several times; however, such use is not recommended
// This class is realy a wrapper around an implementation of File interface for a
// particular platform.
class SysFile : public DelegatedFile {
protected:
SysFile(const SysFile& source) : DelegatedFile() {
OVR_UNUSED(source);
}
public:
// ** Constructor
SysFile();
// Opens a file
SysFile(const String& path, int flags = Open_Read | Open_Buffered, int mode = Mode_ReadWrite);
// ** Open & management
bool Open(const String& path, int flags = Open_Read | Open_Buffered, int mode = Mode_ReadWrite);
OVR_FORCE_INLINE bool Create(const String& path, int mode = Mode_ReadWrite) {
return Open(path, Open_ReadWrite | Open_Create, mode);
}
// Helper function: obtain file statistics information. In OVR, this is used to detect file
// changes.
// Return 0 if function failed, most likely because the file doesn't exist.
static bool OVR_CDECL GetFileStat(FileStat* pfileStats, const String& path);
// ** Overrides
// Overridden to provide re-open support
virtual int GetErrorCode();
virtual bool IsValid();
virtual bool Close();
};
} // Namespace OVR
#endif

View File

@ -0,0 +1,214 @@
/************************************************************************************
Filename : OVR_System.cpp
Content : General kernel initialization/cleanup, including that
of the memory allocator.
Created : September 19, 2012
Notes :
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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"
#include "OVR_DebugHelp.h"
#include "OVR_Log.h"
#include <new>
#if defined(_MSC_VER)
#include <new.h>
#else
#include <new>
#endif
#ifdef OVR_OS_MS
#pragma warning(push, 0)
#include "OVR_Win32_IncludeWindows.h" // GetModuleHandleEx
#pragma warning(pop)
#endif
static ovrlog::Channel Logger("Kernel:System");
namespace OVR {
//-----------------------------------------------------------------------------
// Initialization/Shutdown state
// If true, then Destroy() was called and is in the process of executing
// Added to fix race condition if thread is started after the call to System::Destroy()
static bool ShuttingDown = false;
//-----------------------------------------------------------------------------
// Initialization/Shutdown Callbacks
static SystemSingletonInternal* SystemShutdownListenerList =
nullptr; // Points to the most recent SystemSingletonInternal added to the list.
static Lock& GetSSILock() { // Put listLock in a function so that it can be constructed on-demand.
static Lock listLock; // Will construct on the first usage. However, the guarding of this
// construction is not thread-safe
return listLock; // under all compilers. However, since we are initially calling this on startup
// before other threads
} // could possibly exist, the first usage of this will be before other threads exist.
void SystemSingletonInternal::RegisterDestroyCallback() {
GetSSILock().DoLock();
if (ShuttingDown) {
GetSSILock().Unlock();
OnThreadDestroy();
} else {
GetSSILock().Unlock();
// Insert the listener at the front of the list (top of the stack). This is an analogue of a C++
// forward_list::push_front or stack::push.
NextShutdownSingleton = SystemShutdownListenerList;
SystemShutdownListenerList = this;
}
}
//-----------------------------------------------------------------------------
// System
static int System_Init_Count = 0;
#if defined(_MSC_VER)
// This allows us to throw OVR::bad_alloc instead of std::bad_alloc, which provides less
// information.
int OVRNewFailureHandler(size_t /*size*/) {
throw OVR::bad_alloc();
// Disabled because otherwise a compiler warning is generated regarding unreachable code.
// return 0; // A return value of 0 tells the Standard Library to not retry the allocation.
}
#else
// This allows us to throw OVR::bad_alloc instead of std::bad_alloc, which provides less
// information.
void OVRNewFailureHandler() {
throw OVR::bad_alloc();
}
#endif
// Initializes System core, installing allocator.
void System::Init() {
// Restart logging if we shut down before
ovrlog::RestartLogging();
#if defined(_MSC_VER)
// Make it so that failure of the C malloc family of functions results in the same behavior as C++
// operator new failure.
// This allows us to throw exceptions for malloc usage the same as for operator new bad_alloc.
_set_new_mode(1);
// Tells the standard library to direct new (and malloc) failures to us. Normally we wouldn't need
// to do this, as the
// C++ Standard Library already throws std::bad_alloc on operator new failure. The problem is that
// the Standard Library doesn't
// throw std::bad_alloc upon malloc failure, and we can only intercept malloc failure via this
// means. _set_new_handler specifies
// a global handler for the current running Standard Library. If the Standard Library is being
// dynamically linked instead
// of statically linked, then this is a problem because a call to _set_new_handler would override
// anything the application
// has already set.
_set_new_handler(OVRNewFailureHandler);
#else
// This allows us to throw OVR::bad_alloc instead of std::bad_alloc, which provides less
// information.
// Question: Does this set the handler for all threads or just the current thread? The C++
// Standard doesn't
// explicitly state this, though it may be implied from other parts of the Standard.
std::set_new_handler(OVRNewFailureHandler);
#endif
if (++System_Init_Count == 1) {
Timer::initializeTimerSystem();
} else {
Logger.LogError("Init recursively called; depth = ", System_Init_Count);
// XXX Should this just exit?
}
}
void System::Stop() {
GetSSILock().DoLock();
ShuttingDown = true;
GetSSILock().Unlock();
if (--System_Init_Count == 0) {
Logger.LogInfo("Graceful shutdown: OnThreadDestroy");
// Invoke all of the post-finish callbacks (normal case)
for (SystemSingletonInternal* listener = SystemShutdownListenerList; listener;
listener = listener->NextShutdownSingleton) {
listener->OnThreadDestroy();
}
} else {
Logger.LogError("Stop recursively called; depth = ", System_Init_Count);
}
}
void System::Destroy() {
if (!ShuttingDown) {
Logger.LogWarning("Destroy called before Stop");
System::Stop();
}
if (System_Init_Count == 0) {
Logger.LogInfo("Graceful shutdown: OnSystemDestroy");
// Invoke all of the post-finish callbacks (normal case)
for (SystemSingletonInternal *next, *listener = SystemShutdownListenerList; listener;
listener = next) {
next = listener->NextShutdownSingleton;
listener->OnSystemDestroy();
}
SystemShutdownListenerList = nullptr;
Timer::shutdownTimerSystem();
} else {
Logger.LogError("Destroy recursively called; depth = ", System_Init_Count);
}
GetSSILock().DoLock();
ShuttingDown = false;
GetSSILock().Unlock();
Logger.LogInfo("Graceful shutdown: Stopping logger");
// Prevent memory leak reports
ovrlog::ShutdownLogging();
}
// Returns 'true' if system was properly initialized.
bool System::IsInitialized() {
return System_Init_Count > 0;
}
// Dump any leaked memory
void System::CheckForAllocatorLeaks() {
if (Allocator::IsTrackingLeaks()) {
int ovrLeakCount = Allocator::DumpMemory();
(void)ovrLeakCount;
OVR_ASSERT(ovrLeakCount == 0);
}
}
} // namespace OVR

View File

@ -0,0 +1,181 @@
/************************************************************************************
PublicHeader: OVR
Filename : OVR_System.h
Content : General kernel initialization/cleanup, including that
of the memory allocator.
Created : September 19, 2012
Notes :
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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_Atomic.h"
namespace OVR {
//-----------------------------------------------------------------------------
// SystemSingleton
// Subsystems are implemented using the Singleton pattern.
// To avoid code duplication in all the places where Singletons are defined,
// The pattern is defined once here and used everywhere.
class SystemSingletonInternal {
friend class System;
// Allows for including this class in the shutdown list.
SystemSingletonInternal* NextShutdownSingleton;
// No copying allowed
OVR_NON_COPYABLE(SystemSingletonInternal);
public:
// Call this to register for a call to OnThreadDestroy and OnSystemDestroy before the
// Kernel is shut down. OnThreadDestroy is called before any remaining existing threads
// are exited. Registered callbacks are called in the reverse order they were registered.
// You would typically call this at the end of your SystemSingletonInternal subclass' constructor.
// The registered objects are not deleted on shutdown; they would have to do that themselves
// within
// OnSystemDestroy or via a compiler-generated static destruction.
void RegisterDestroyCallback();
void PushDestroyCallbacks() {
RegisterDestroyCallback();
} // For backward compatibility.
protected:
SystemSingletonInternal() : NextShutdownSingleton(nullptr) {}
virtual ~SystemSingletonInternal() {}
// Initializes the SystemSingletonInternal.
// You can register for an automatic call to this function by calling PushInitCallbacks.
// The registration of an automatic call to this is not required, but may be useful if
// you need to postpone your initialization until after Kernel is initialized.
// You cannot call PushInitCallbacks or PushDestroyCallbacks while within this function.
virtual void OnSystemInit() {}
// Called just before waiting for threads to exit.
// Listeners are called in the opposite order they were registered.
// This function is useful for terminating threads at the right time before the rest of the system
// is shut down.
// Note: The singleton must not delete itself here, as OnSystemDestroy will subsequently be called
// for it.
virtual void OnThreadDestroy() {}
// Shuts down the SystemSingletonInternal.
// You can register for an automatic call to this function by calling PushDestroyCallbacks.
// The registration of an automatic call to this is not required, but may be useful if
// you need to delay your shutdown until application exit time.
// You cannot call PushInitCallbacks or PushDestroyCallbacks while within this function.
// This function may delete this.
virtual void OnSystemDestroy() {}
};
// Singletons derive from this class
template <class T>
class SystemSingletonBase : public SystemSingletonInternal {
static std::atomic<T*> SingletonInstance;
static T* SlowGetInstance();
struct ZeroInitializer {
ZeroInitializer() {
SingletonInstance = nullptr;
}
};
ZeroInitializer zeroInitializer;
protected:
~SystemSingletonBase() {
// Make sure the instance gets set to zero on dtor
if (SingletonInstance.load() == this)
SingletonInstance = nullptr;
}
public:
static OVR_FORCE_INLINE T* GetInstance() {
// Fast version
// Note: The singleton instance is stored in an std::atomic<> to allow it to be accessed
// atomically from multiple threads without locks.
T* instance = SingletonInstance;
return instance ? instance : SlowGetInstance();
}
};
// For reference, see N3337 14.5.1.3 (Static data members of class templates):
template <class T>
std::atomic<T*> OVR::SystemSingletonBase<T>::SingletonInstance;
// Place this in the singleton class in the header file
#define OVR_DECLARE_SINGLETON(T) \
friend class OVR::SystemSingletonBase<T>; \
\
private: \
T(); \
virtual ~T(); \
virtual void OnSystemDestroy() override;
// Place this in the singleton class source file
#define OVR_DEFINE_SINGLETON(T) \
namespace OVR { \
template <> \
T* SystemSingletonBase<T>::SlowGetInstance() { \
static OVR::Lock lock; \
OVR::Lock::Locker locker(&lock); \
if (!SingletonInstance.load()) \
SingletonInstance = new T; \
return SingletonInstance; \
} \
}
// ***** 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.
class System {
public:
// 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();
// Halt all system threads (call before Destroy).
static void OVR_CDECL Stop();
// De-initializes System more, finalizing the threading system and destroying
// the global memory allocator.
static void OVR_CDECL Destroy();
// Dump any leaked allocations
static void OVR_CDECL CheckForAllocatorLeaks();
};
} // namespace OVR
#endif

View File

@ -0,0 +1,217 @@
/************************************************************************************
PublicHeader: None
Filename : OVR_Threads.h
Content : Contains thread-related (safe) functionality
Created : September 19, 2012
Notes :
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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"
#include <memory>
#include <mutex>
#include <condition_variable>
#if !defined(_WIN32)
#include <unistd.h>
#endif
// 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 Event;
// Implementation forward declarations
class MutexImpl;
//-----------------------------------------------------------------------------------
// ***** 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 MutexImpl;
std::unique_ptr<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(const std::unique_ptr<Mutex>& pmutex) : Locker(pmutex.get()) {}
~Locker() {
pMutex->Unlock();
}
};
};
//-----------------------------------------------------------------------------------
// ***** 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 std::mutex StateMutex;
std::condition_variable 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
// ThreadHandle is a handle to a thread, which on some platforms (e.g. Windows) is
// different from ThreadId. On Unix platforms, a ThreadHandle is the same as a
// ThreadId and is pthread_t.
typedef void* ThreadHandle;
// ThreadId uniquely identifies a thread; returned by Windows GetCurrentThreadId(),
// Unix pthread_self() 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
namespace Thread {
// *** Sleep
// Sleep msecs milliseconds
bool MSleep(unsigned msecs);
// *** Debugging functionality
void SetCurrentThreadName(const char* name);
void GetCurrentThreadName(char* name, size_t nameCapacity);
}; // namespace Thread
// Returns the unique Id of a thread it is called on, intended for
// comparison purposes.
ThreadId GetCurrentThreadId();
// Returns the unique Id of the current running process.
#if !defined(OVR_OS_MS)
#define GetCurrentProcessId getpid
#endif
//-----------------------------------------------------------------------------------
// ***** OVR_THREAD_LOCAL
//
// Example usage:
// #if defined(OVR_THREAD_LOCAL)
// OVR_THREAD_LOCAL int n = 0; // OK
// extern OVR_THREAD_LOCAL struct Data s; // OK
// static OVR_THREAD_LOCAL char* p; // OK
// OVR_THREAD_LOCAL int i = sizeof(i); // OK.
// OVR_THREAD_LOCAL std::string s("hello"); // Can't be used for initialized
// objects.
// OVR_THREAD_LOCAL int Function(); // Can't be used as return value.
// void Function(){ OVR_THREAD_LOCAL int i = 0; } // Can't be used in function.
// void Function(OVR_THREAD_LOCAL int i){ } // can't be used as argument.
// extern int i; OVR_THREAD_LOCAL int i; // Declarations differ.
// int OVR_THREAD_LOCAL i; // Can't be used as a type modifier.
// OVR_THREAD_LOCAL int i = i; // Can't reference self before
// initialization.
// #endif
#if !defined(_MSC_VER) || \
(_MSC_VER >= 1900) // VC++ doesn't support C++11 thread_local storage until VS2015.
#define OVR_THREAD_LOCAL thread_local
#else
#define OVR_THREAD_LOCAL __declspec(thread)
#endif
} // namespace OVR
#endif // OVR_ENABLE_THREADS
#endif // OVR_Threads_h

View File

@ -0,0 +1,236 @@
/************************************************************************************
Filename : OVR_ThreadsPthread.cpp
Content :
Created :
Notes :
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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.
************************************************************************************/
#if !defined(_WIN32) // Skip the entire file under Windows
#include "OVR_Threads.h"
#ifdef OVR_ENABLE_THREADS
#include "OVR_Timer.h"
#include "OVR_Log.h"
#include <pthread.h>
#include <sched.h>
#include <time.h>
#include <unistd.h>
#include <sys/time.h>
#include <errno.h>
#if defined(OVR_OS_MAC) || defined(OVR_OS_BSD)
#include <sys/sysctl.h>
#include <sys/param.h>
#if !defined(OVR_OS_MAC)
#include <pthread_np.h>
#endif
#endif
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;
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
// NOTE: RefCount mode already thread-safe for all waitables.
Mutex::Mutex(bool recursive) : pImpl(new MutexImpl(this, recursive)) {}
Mutex::~Mutex() {}
// 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) {
std::unique_lock<std::mutex> locker(StateMutex);
// Do the correct amount of waiting
if (delay == OVR_WAIT_INFINITE) {
while (!State)
StateWaitCondition.wait(locker);
} else if (delay) {
if (!State)
StateWaitCondition.wait_for(locker, std::chrono::milliseconds(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) {
std::unique_lock<std::mutex> lock(StateMutex);
State = newState;
Temporary = newTemp;
if (mustNotify) {
lock.unlock();
StateWaitCondition.notify_all();
}
}
ThreadId GetCurrentThreadId() {
return (void*)pthread_self();
}
// *** Sleep functions
/* static */
bool Thread::MSleep(unsigned msecs) {
usleep(msecs * 1000);
return 1;
}
void Thread::SetCurrentThreadName(const char* name) {
#if defined(OVR_OS_APPLE)
pthread_setname_np(name);
#else
pthread_setname_np(pthread_self(), name);
#endif
}
void Thread::GetCurrentThreadName(char* name, size_t nameCapacity) {
name[0] = 0;
#if !defined(OVR_OS_ANDROID)
// Android does not have pthread_getname_np (or an equivalent)
pthread_getname_np(pthread_self(), name, nameCapacity);
#endif
}
} // namespace OVR
#endif // OVR_ENABLE_THREADS
#endif // _WIN32

View File

@ -0,0 +1,319 @@
/************************************************************************************
Filename : OVR_ThreadsWinAPI.cpp
Platform : WinAPI
Content : Windows specific thread-related (safe) functionality
Created : September 19, 2012
Notes :
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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_Log.h"
#include "OVR_Timer.h"
#ifdef OVR_ENABLE_THREADS
// For _beginthreadex / _endtheadex
#include <process.h>
#ifdef _WIN32
#include "OVR_DLLHelper.h"
#include <processthreadsapi.h>
#include <sdkddkver.h>
#if !defined(NTDDI_WIN10_RS1) // RS1 SDK introduced these functions.
WINBASEAPI HRESULT WINAPI SetThreadDescription(HANDLE hThread, PCWSTR lpThreadDescription);
WINBASEAPI HRESULT WINAPI GetThreadDescription(HANDLE hThread, PWSTR* ppszThreadDescription);
#endif
// Example usage:
// Kernel32API kernel32API;
//
// if (kernel32API.getThreadDescription) {
// wchar_t* pStr;
//
// if (SUCCEEDED(getThreadDescription(hThread, &pStr)) {
// <use pStr>
// Localfree(pStr);
// }
// }
//
// if (kernel32API.setThreadDescription) {
// HRESULT hr = setThreadDescription(GetCurrentThread(), L"thread name");
// ...
// }
//
class Kernel32API {
public:
Kernel32API()
: dllHelper{"Kernel32.dll"},
getThreadDescription(dllHelper.Load("GetThreadDescription")),
setThreadDescription(dllHelper.Load("SetThreadDescription")) {}
protected:
OVR::DllHelper dllHelper; // Declared first because the members below depend on the ctor order.
public:
// Recognition of GetThreadDescription requires the Windows 10 SDK v10.14393 (a.k.a build 1607,
// a.k.a. Anniversary Update, a.k.a. RS1, a.k.a. Redstone 1) or later.
// GetThreadDescription requires thread to have at least THREAD_QUERY_LIMITED_INFORMATION access.
decltype(GetThreadDescription)* getThreadDescription;
// Required THREAD_SET_LIMITED_INFORMATION access.
decltype(SetThreadDescription)* setThreadDescription;
};
Kernel32API kernel32API;
#endif // _WIN32
namespace OVR {
//-----------------------------------------------------------------------------------
// *** Internal Mutex implementation class
class MutexImpl : public NewOverrideBase {
// System mutex or semaphore
HANDLE hMutexOrSemaphore;
bool Recursive;
volatile unsigned LockCount;
public:
// Constructor/destructor
MutexImpl(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);
};
// *** Constructor/destructor
MutexImpl::MutexImpl(bool recursive) {
Recursive = recursive;
LockCount = 0;
#if defined(OVR_OS_WIN32) // Older versions of Windows don't support CreateSemaphoreEx, so stick
// with CreateSemaphore for portability.
hMutexOrSemaphore = Recursive ? CreateMutexW(NULL, 0, NULL) : CreateSemaphoreW(NULL, 1, 1, NULL);
#else
// No CreateSemaphore() call, so emulate it.
hMutexOrSemaphore = Recursive ? CreateMutexW(NULL, 0, NULL)
: CreateSemaphoreExW(NULL, 1, 1, NULL, 0, SEMAPHORE_ALL_ACCESS);
#endif
}
MutexImpl::~MutexImpl() {
CloseHandle(hMutexOrSemaphore);
}
// Lock and try lock
void MutexImpl::DoLock() {
if (::WaitForSingleObject(hMutexOrSemaphore, INFINITE) != WAIT_OBJECT_0)
return;
LockCount++;
}
bool MutexImpl::TryLock() {
DWORD ret;
if ((ret = ::WaitForSingleObject(hMutexOrSemaphore, 0)) != WAIT_OBJECT_0)
return 0;
LockCount++;
return 1;
}
void MutexImpl::Unlock(Mutex* pmutex) {
OVR_UNUSED(pmutex);
unsigned lockCount;
LockCount--;
lockCount = LockCount;
// Release mutex
if ((Recursive ? ReleaseMutex(hMutexOrSemaphore)
: ReleaseSemaphore(hMutexOrSemaphore, 1, NULL)) != 0) {
// This used to call Wait handlers if lockCount == 0.
}
}
bool MutexImpl::IsLockedByAnotherThread(Mutex* pmutex) {
// There could be multiple interpretations of IsLocked with respect to current thread
if (LockCount == 0)
return 0;
if (!TryLock())
return 1;
Unlock(pmutex);
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) : pImpl(new MutexImpl(recursive)) {}
Mutex::~Mutex() {}
// 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) {
std::unique_lock<std::mutex> locker(StateMutex);
// Do the correct amount of waiting
if (delay == OVR_WAIT_INFINITE) {
while (!State)
StateWaitCondition.wait(locker);
} else if (delay) {
if (!State)
StateWaitCondition.wait_for(locker, std::chrono::milliseconds(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) {
{
std::lock_guard<std::mutex> lock(StateMutex);
State = newState;
Temporary = newTemp;
}
// NOTE: The lock does not need to be held when calling notify_all(),
// and holding it is in fact a pessimization.
if (mustNotify)
StateWaitCondition.notify_all();
}
//-----------------------------------------------------------------------------------
// ***** Thread Namespace
// *** Sleep functions
// static
bool Thread::MSleep(unsigned msecs) {
::Sleep(msecs);
return 1;
}
static OVR_THREAD_LOCAL char ThreadLocaThreadlName[32] = {};
// Older method of informing the debugger about thread names.
// This needs to be in its own function body due to the use of __try.
static void SetCurrentThreadNameViaException(const char* name) {
#if !defined(OVR_BUILD_SHIPPING) || defined(OVR_BUILD_PROFILING)
// http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
#pragma pack(push, 8)
struct THREADNAME_INFO {
DWORD dwType; // Must be 0x1000
LPCSTR szName; // Pointer to name (in user address space)
DWORD dwThreadID; // Thread ID (-1 for caller thread)
DWORD dwFlags; // Reserved for future use; must be zero
};
union TNIUnion {
THREADNAME_INFO tni;
ULONG_PTR upArray[4];
};
#pragma pack(pop)
TNIUnion tniUnion = {{0x1000, name, ::GetCurrentThreadId(), 0}};
__try {
RaiseException(0x406D1388, 0, OVR_ARRAY_COUNT(tniUnion.upArray), tniUnion.upArray);
} __except (
GetExceptionCode() == 0x406D1388 ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_EXECUTE_HANDLER) {
return;
}
#endif // OVR_BUILD_SHIPPING
}
void Thread::SetCurrentThreadName(const char* name) {
OVR_strlcpy(ThreadLocaThreadlName, name, sizeof(ThreadLocaThreadlName));
// https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-setthreaddescription
if (kernel32API.setThreadDescription) {
std::wstring strW = OVR::UTF8StringToUCSString(name);
kernel32API.setThreadDescription(GetCurrentThread(), strW.c_str());
} else {
SetCurrentThreadNameViaException(name);
}
}
void Thread::GetCurrentThreadName(char* name, size_t nameCapacity) {
if (kernel32API.getThreadDescription) {
wchar_t* pStrW;
if (SUCCEEDED(kernel32API.getThreadDescription(GetCurrentThread(), &pStrW))) {
std::string str = OVR::UCSStringToUTF8String(pStrW);
LocalFree(pStrW);
OVR_strlcpy(name, str.c_str(), nameCapacity);
return;
}
}
// Fall back to seeing if we set it above in SetCurrentThreadName.
OVR_strlcpy(name, ThreadLocaThreadlName, nameCapacity);
}
// Returns the unique Id of a thread it is called on, intended for
// comparison purposes.
ThreadId GetCurrentThreadId() {
union {
intptr_t id;
ThreadId threadId;
};
id = ::GetCurrentThreadId();
return threadId;
}
} // namespace OVR
#endif

View File

@ -0,0 +1,458 @@
/************************************************************************************
Filename : OVR_Timer.cpp
Content : Provides static functions for precise timing
Created : September 19, 2012
Notes :
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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_MS) && !defined(OVR_OS_MS_MOBILE)
#include "OVR_Win32_IncludeWindows.h"
#include <MMSystem.h>
#pragma comment(lib, "winmm.lib")
#elif defined(OVR_OS_ANDROID)
#include <time.h>
#include <android/log.h>
#else
#include <chrono>
#endif
#if defined(OVR_BUILD_DEBUG) && defined(OVR_OS_WIN32)
typedef NTSTATUS(
NTAPI* NtQueryTimerResolutionType)(PULONG MaximumTime, PULONG MinimumTime, PULONG CurrentTime);
static NtQueryTimerResolutionType pNtQueryTimerResolution;
#endif
#if defined(OVR_OS_MS) && !defined(OVR_OS_WIN32) // Non-desktop Microsoft platforms...
// Add this alias here because we're not going to include OVR_CAPI.cpp
extern "C" {
double ovr_GetTimeInSeconds() {
return Timer::GetSeconds();
}
}
#endif
namespace OVR {
// For recorded data playback
bool Timer::useVirtualSeconds = false;
double Timer::VirtualSeconds = 0.0;
//------------------------------------------------------------------------
// *** Android Specific Timer
#if defined( \
OVR_OS_ANDROID) // To consider: This implementation can also work on most Linux distributions
//------------------------------------------------------------------------
// *** Timer - Platform Independent functions
// Returns global high-resolution application timer in seconds.
double Timer::GetSeconds() {
if (useVirtualSeconds)
return VirtualSeconds;
// Choreographer vsync timestamp is based on.
struct timespec tp;
const int status = clock_gettime(CLOCK_MONOTONIC, &tp);
#ifdef OVR_BUILD_DEBUG
if (status != 0) {
OVR_DEBUG_LOG(("clock_gettime status=%i", status));
}
#else
OVR_UNUSED(status);
#endif
return (double)tp.tv_sec;
}
uint64_t Timer::GetTicksNanos() {
if (useVirtualSeconds)
return (uint64_t)(VirtualSeconds * NanosPerSecond);
// Choreographer vsync timestamp is based on.
struct timespec tp;
const int status = clock_gettime(CLOCK_MONOTONIC, &tp);
#ifdef OVR_BUILD_DEBUG
if (status != 0) {
OVR_DEBUG_LOG(("clock_gettime status=%i", status));
}
#else
OVR_UNUSED(status);
#endif
const uint64_t result =
(uint64_t)tp.tv_sec * (uint64_t)(1000 * 1000 * 1000) + uint64_t(tp.tv_nsec);
return result;
}
void Timer::initializeTimerSystem() {
// Empty for this platform.
}
void Timer::shutdownTimerSystem() {
// Empty for this platform.
}
//------------------------------------------------------------------------
// *** Win32 Specific Timer
#elif defined(OVR_OS_MS)
// 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()
: UsingVistaOrLater(false),
TimeCS(),
OldMMTimeMs(0),
MMTimeWrapCounter(0),
PerfFrequency(0),
PerfFrequencyInverse(0),
PerfFrequencyInverseNanos(0),
PerfMinusTicksDeltaNanos(0),
LastResultNanos(0) {}
enum { MMTimerResolutionNanos = 1000000 };
void Initialize();
void Shutdown();
uint64_t GetTimeSeconds();
double GetTimeSecondsDouble();
uint64_t GetTimeNanos();
UINT64 getFrequency() {
if (PerfFrequency == 0) {
LARGE_INTEGER freq;
::QueryPerformanceFrequency(&freq);
PerfFrequency = freq.QuadPart;
PerfFrequencyInverse = 1.0 / (double)PerfFrequency;
PerfFrequencyInverseNanos = 1000000000.0 / (double)PerfFrequency;
}
return PerfFrequency;
}
double GetFrequencyInverse() {
OVR_ASSERT(PerfFrequencyInverse != 0.0); // Assert that the frequency has been initialized.
return PerfFrequencyInverse;
}
// In Vista+ we are able to use QPC exclusively.
bool UsingVistaOrLater;
CRITICAL_SECTION TimeCS;
// timeGetTime() support with wrap.
uint32_t OldMMTimeMs;
uint32_t MMTimeWrapCounter;
// Cached performance frequency result.
uint64_t PerfFrequency; // cycles per second, typically a large value like 3000000, but usually
// not the same as the CPU clock rate.
double PerfFrequencyInverse; // seconds per cycle (will be a small fractional value).
double PerfFrequencyInverseNanos; // nanoseconds per cycle.
// Computed as (perfCounterNanos - ticksCounterNanos) initially,
// and used to adjust timing.
uint64_t PerfMinusTicksDeltaNanos;
// Last returned value in nanoseconds, to ensure we don't back-step in time.
uint64_t LastResultNanos;
};
static PerformanceTimer Win32_PerfTimer;
void PerformanceTimer::Initialize() {
::InitializeCriticalSection(&TimeCS);
MMTimeWrapCounter = 0;
getFrequency();
#if defined(OVR_OS_WIN32) // Desktop Windows only
// Set Vista flag. On Vista, we can just use QPC() without all the extra work
OSVERSIONINFOEXW ver;
ZeroMemory(&ver, sizeof(OSVERSIONINFOEXW));
ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
ver.dwMajorVersion = 6; // Vista+
DWORDLONG condMask = 0;
VER_SET_CONDITION(condMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
// VerifyVersionInfo returns true if the OS meets the conditions set above
UsingVistaOrLater = ::VerifyVersionInfoW(&ver, VER_MAJORVERSION, condMask) != 0;
#else
UsingVistaOrLater = true;
#endif
if (!UsingVistaOrLater) {
#if defined(OVR_OS_WIN32) // Desktop Windows only
// The following has the effect of setting the NT timer resolution (NtSetTimerResolution) to 1
// millisecond.
MMRESULT mmr = timeBeginPeriod(1);
OVR_ASSERT(TIMERR_NOERROR == mmr);
OVR_UNUSED(mmr);
#endif
#if defined(OVR_BUILD_DEBUG) && defined(OVR_OS_WIN32)
HMODULE hNtDll = ::LoadLibraryW(L"NtDll.dll");
if (hNtDll) {
pNtQueryTimerResolution =
(NtQueryTimerResolutionType)::GetProcAddress(hNtDll, "NtQueryTimerResolution");
// pNtSetTimerResolution = (NtSetTimerResolutionType)::GetProcAddress(hNtDll,
// "NtSetTimerResolution");
if (pNtQueryTimerResolution) {
ULONG MinimumResolution; // in 100-ns units
ULONG MaximumResolution;
ULONG ActualResolution;
pNtQueryTimerResolution(&MinimumResolution, &MaximumResolution, &ActualResolution);
OVR_DEBUG_LOG(
("NtQueryTimerResolution = Min %ld us, Max %ld us, Current %ld us",
MinimumResolution / 10,
MaximumResolution / 10,
ActualResolution / 10));
}
::FreeLibrary(hNtDll);
}
#endif
}
}
void PerformanceTimer::Shutdown() {
::DeleteCriticalSection(&TimeCS);
if (!UsingVistaOrLater) {
#if defined(OVR_OS_WIN32) // Desktop Windows only
MMRESULT mmr = timeEndPeriod(1);
OVR_ASSERT(TIMERR_NOERROR == mmr);
OVR_UNUSED(mmr);
#endif
}
}
uint64_t PerformanceTimer::GetTimeSeconds() {
if (UsingVistaOrLater) {
LARGE_INTEGER li;
::QueryPerformanceCounter(&li);
OVR_ASSERT(PerfFrequencyInverse != 0); // Initialize should have been called earlier.
return (uint64_t)(li.QuadPart * PerfFrequencyInverse);
}
return (uint64_t)(GetTimeNanos() * .0000000001);
}
double PerformanceTimer::GetTimeSecondsDouble() {
if (UsingVistaOrLater) {
LARGE_INTEGER li;
::QueryPerformanceCounter(&li);
OVR_ASSERT(PerfFrequencyInverse != 0);
return (li.QuadPart * PerfFrequencyInverse);
}
return (GetTimeNanos() * .0000000001);
}
uint64_t PerformanceTimer::GetTimeNanos() {
uint64_t resultNanos;
LARGE_INTEGER li;
OVR_ASSERT(PerfFrequencyInverseNanos != 0); // Initialize should have been called earlier.
if (UsingVistaOrLater) // Includes non-desktop platforms
{
// Then we can use QPC() directly without all that extra work
::QueryPerformanceCounter(&li);
resultNanos = (uint64_t)(li.QuadPart * PerfFrequencyInverseNanos);
return resultNanos;
}
// Pre-Vista computers:
// Note that the Oculus SDK does not run on PCs before Windows 7 SP1
// so this code path should never be taken in practice. We keep it here
// since this is a nice reusable timing library that can be useful for
// other projects.
// 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".
::QueryPerformanceCounter(&li);
DWORD mmTimeMs = timeGetTime();
if (OldMMTimeMs > mmTimeMs)
MMTimeWrapCounter++;
OldMMTimeMs = mmTimeMs;
// Normalize to nanoseconds.
uint64_t perfCounterNanos = (uint64_t)(li.QuadPart * PerfFrequencyInverseNanos);
uint64_t mmCounterNanos = ((uint64_t(MMTimeWrapCounter) << 32) | mmTimeMs) * 1000000;
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);
return resultNanos;
}
//------------------------------------------------------------------------
// *** Timer - Platform Independent functions
// Returns global high-resolution application timer in seconds.
double Timer::GetSeconds() {
return Win32_PerfTimer.GetTimeSecondsDouble();
}
double Timer::GetVirtualSeconds() {
if (useVirtualSeconds)
return VirtualSeconds;
return Win32_PerfTimer.GetTimeSecondsDouble();
}
// Delegate to PerformanceTimer.
uint64_t Timer::GetVirtualTicksNanos() {
if (useVirtualSeconds)
return (uint64_t)(VirtualSeconds * NanosPerSecond);
return Win32_PerfTimer.GetTimeNanos();
}
uint64_t Timer::GetTicksNanos() {
return Win32_PerfTimer.GetTimeNanos();
}
// Windows version also provides the performance frequency inverse.
double Timer::GetPerfFrequencyInverse() {
return Win32_PerfTimer.GetFrequencyInverse();
}
double Timer::GetPerfFrequency() {
return double(Win32_PerfTimer.getFrequency());
}
void Timer::initializeTimerSystem() {
Win32_PerfTimer.Initialize();
}
void Timer::shutdownTimerSystem() {
Win32_PerfTimer.Shutdown();
}
#else // C++11 standard compliant platforms
double Timer::GetSeconds() {
if (useVirtualSeconds)
return VirtualSeconds;
using FpSeconds = std::chrono::duration<double, std::chrono::seconds::period>;
auto now = std::chrono::high_resolution_clock::now();
return FpSeconds(now.time_since_epoch()).count();
}
double Timer::GetVirtualSeconds() {
if (useVirtualSeconds)
return VirtualSeconds;
using FpSeconds = std::chrono::duration<double, std::chrono::seconds::period>;
auto now = std::chrono::high_resolution_clock::now();
return FpSeconds(now.time_since_epoch()).count();
}
uint64_t Timer::GetTicksNanos() {
if (useVirtualSeconds)
return (uint64_t)(VirtualSeconds * NanosPerSecond);
using Uint64Nanoseconds = std::chrono::duration<uint64_t, std::chrono::nanoseconds::period>;
auto now = std::chrono::high_resolution_clock::now();
return Uint64Nanoseconds(now.time_since_epoch()).count();
}
void Timer::initializeTimerSystem() {}
void Timer::shutdownTimerSystem() {}
#endif // OS-specific
CountdownTimer::CountdownTimer(size_t countdownTimeMs, bool start)
: CountdownTime(std::chrono::duration_cast<std::chrono::steady_clock::duration>(
std::chrono::milliseconds(countdownTimeMs))) {
if (start)
Restart();
}
std::chrono::steady_clock::time_point CountdownTimer::CurrentTime() const {
return std::chrono::steady_clock::now();
}
bool CountdownTimer::IsTimeUp() const {
return (CurrentTime() > DoneTime);
}
void CountdownTimer::Restart() {
DoneTime = (CurrentTime() + CountdownTime);
}
void CountdownTimer::Restart(size_t countdownTimeMs) {
CountdownTime = std::chrono::duration_cast<std::chrono::steady_clock::duration>(
std::chrono::milliseconds(countdownTimeMs));
Restart();
};
} // namespace OVR

View File

@ -0,0 +1,143 @@
/************************************************************************************
PublicHeader: OVR
Filename : OVR_Timer.h
Content : Provides static functions for precise timing
Created : September 19, 2012
Notes :
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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"
#include <chrono>
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.
MksPerSecond = 1000 * 1000, // Microseconds in one second.
NanosPerSecond = 1000 * 1000 * 1000, // Nanoseconds in one second.
};
// ***** 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();
// This may return a recorded time if Replaying a recording
static double OVR_STDCALL GetVirtualSeconds();
// Returns time in Nanoseconds, using highest possible system resolution.
static uint64_t OVR_STDCALL GetTicksNanos();
// This may return a recorded time if Replaying a recording
static uint64_t OVR_STDCALL GetVirtualTicksNanos();
#ifdef OVR_OS_MS
static double OVR_STDCALL GetPerfFrequencyInverse();
static double OVR_STDCALL GetPerfFrequency();
#endif
// 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_t OVR_STDCALL GetTicksMs() {
return uint32_t(GetTicksNanos() / 1000000);
}
// This may return a recorded time if Replaying a recording
static uint32_t OVR_STDCALL GetVirtualTicksMs() {
return uint32_t(GetVirtualTicksNanos() / 1000000);
}
// for recorded data playback
static void SetVirtualSeconds(double virtualSeconds, bool enable = true) {
VirtualSeconds = virtualSeconds;
useVirtualSeconds = enable;
}
private:
friend class System;
// System called during program startup/shutdown.
static void initializeTimerSystem();
static void shutdownTimerSystem();
// for recorded data playback.
static double VirtualSeconds;
static bool useVirtualSeconds;
#if defined(OVR_OS_ANDROID)
// Android-specific data
#elif defined(OVR_OS_MS)
// Microsoft-specific data
#endif
}; // class Timer
//-----------------------------------------------------------------------------
// CountdownTimer
//
// Acts like a kitchen timer. Implemented using std::chrono::steady_clock.
// Input resolution is in milliseconds.
// Under the hood, it uses the native resolution of a std::chrono::steady_clock.
//
// Exmample usage:
// CountdownTimer timer(5000, true);
//
// if(timer.IsTimeUp())
// {
// DoSomething();
// timer.Restart();
// }
//
struct CountdownTimer {
std::chrono::steady_clock::time_point DoneTime;
std::chrono::steady_clock::duration CountdownTime;
CountdownTimer(size_t countdownTimeMs = 0, bool start = false);
std::chrono::steady_clock::time_point CurrentTime() const;
bool IsTimeUp() const;
void Restart();
void Restart(size_t countdownTimeMs);
};
} // namespace OVR
// This version of ovr_GetTimeInSeconds should be called internally with Oculus service,
// as public APIs are not available.
inline double ovr_GetTimeInSeconds_Internal() {
return OVR::Timer::GetSeconds();
}
#endif

View File

@ -0,0 +1,390 @@
/**************************************************************************
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 (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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"
#include <wchar.h>
#include <string.h>
// sizeof(wchar_t) in preprocessor-accessible form.
#ifndef OVR_WCHAR_SIZE
#if defined(__WCHAR_MAX__)
#if (__WCHAR_MAX__ == 127) || (__WCHAR_MAX__ == 255)
#define OVR_WCHAR_SIZE 1
#elif (__WCHAR_MAX__ == 32767) || (__WCHAR_MAX__ == 65535)
#define OVR_WCHAR_SIZE 2
#else
#define OVR_WCHAR_SIZE 4
#endif
#elif defined(OVR_OS_UNIX)
#define OVR_WCHAR_SIZE 4
#else
#define OVR_WCHAR_SIZE 2
#endif
#endif
namespace OVR {
namespace UTF8Util {
size_t Strlcpy(char* pDestUTF8, size_t destCharCount, const wchar_t* pSrcUCS, size_t sourceLength) {
if (sourceLength == (size_t)-1)
sourceLength = wcslen(pSrcUCS);
size_t destLength = 0;
size_t i;
for (i = 0; i < sourceLength; ++i) {
char buff[6]; // longest utf8 encoding just to be safe
intptr_t count = 0;
EncodeChar(buff, &count, pSrcUCS[i]);
// If this character occupies more than the remaining space (leaving room for the trailing
// '\0'), truncate here
if ((destLength + count) >= destCharCount)
break;
memcpy(pDestUTF8 + destLength, buff, count);
destLength += (size_t)count;
}
// Should be true for all cases other than destCharCount == 0.
if (destLength < destCharCount)
pDestUTF8[destLength] = '\0';
// Compute the required destination size for any remaining source characters
// Note a very long wchar string with lots of multibyte encodings can overflow destLength
// This should be okay since we'll just treat those cases (likely to be originating
// from an attacker) as shorter strings
while (i < sourceLength)
destLength += GetEncodeCharSize(pSrcUCS[i++]);
// Return the intended strlen of pDestUTF8.
return destLength;
}
size_t Strlcpy(wchar_t* pDestUCS, size_t destCharCount, const char* pSrcUTF8, size_t sourceLength) {
if (sourceLength == (size_t)-1)
sourceLength = strlen(pSrcUTF8);
size_t destLength = 0, requiredLength = 0;
for (const char* pSrcUTF8End = (pSrcUTF8 + sourceLength); pSrcUTF8 < pSrcUTF8End;) {
uint32_t c = DecodeNextChar_Advance0(&pSrcUTF8);
OVR_ASSERT_M(
pSrcUTF8 <= (pSrcUTF8 + sourceLength), "Strlcpy sourceLength was not on a UTF8 boundary.");
#if (OVR_WCHAR_SIZE == 2)
if (c >= 0x0000FFFF)
c = 0x0000FFFD;
#endif
if ((destLength + 1) < destCharCount) // If there is enough space to append a wchar_t (leaving
// room for a trailing '\0')...
{
pDestUCS[destLength] = wchar_t(c);
destLength++;
}
requiredLength++;
}
if (destLength < destCharCount)
pDestUCS[destLength] = L'\0';
return requiredLength; // Return the intended wcslen of pDestUCS.
}
intptr_t GetLength(const char* buf, intptr_t buflen) {
const char* p = buf;
intptr_t 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_t GetCharAt(intptr_t index, const char* putf8str, intptr_t length) {
const char* buf = putf8str;
uint32_t 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;
}
intptr_t GetByteIndex(intptr_t index, const char* putf8str, intptr_t byteLength) {
const char* buf = putf8str;
if (byteLength >= 0) {
const char* lastValid = putf8str;
while ((buf - putf8str) < byteLength && index > 0) {
lastValid = buf;
// XXX this may read up to 5 bytes past byteLength
UTF8Util::DecodeNextChar_Advance0(&buf);
index--;
}
// check for UTF8 characters which ran past the end of the buffer
if (buf - putf8str > byteLength)
return lastValid - putf8str;
return buf - putf8str;
}
while (index > 0) {
uint32_t c = UTF8Util::DecodeNextChar(&buf);
index--;
// okay to index past null-terminator, DecodeNextChar will not advance past it
if (c == 0)
break;
}
return buf - putf8str;
}
intptr_t GetByteIndexChecked(intptr_t index, const char* putf8str, intptr_t byteLength) {
const char* buf = putf8str;
// before start of string?
if (index < 0)
return -1;
if (byteLength >= 0) {
while ((buf - putf8str) < byteLength && index > 0) {
// XXX this may read up to 5 bytes past byteLength
UTF8Util::DecodeNextChar_Advance0(&buf);
index--;
}
// check for UTF8 characters which ran past the end of the buffer
if ((buf - putf8str) > byteLength)
return -1;
} else {
while (index > 0) {
uint32_t c = UTF8Util::DecodeNextChar_Advance0(&buf);
index--;
// ran past null terminator
if (c == 0)
return -1;
}
}
// ran off end of string
if (index != 0)
return -1;
// at the valid index'th character-boundary offset in the string
return buf - putf8str;
}
int GetEncodeCharSize(uint32_t 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_t DecodeNextChar_Advance0(const char** putf8Buffer) {
uint32_t 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_t)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 EncodeChar(char* pbuffer, intptr_t* pindex, uint32_t 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.
}
}
} // namespace UTF8Util
} // namespace OVR

View File

@ -0,0 +1,130 @@
/************************************************************************************
Filename : OVR_UTF8Util.h
Content : UTF8 Unicode character encoding/decoding support
Created : September 19, 2012
Notes :
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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 {
// *** wchar_t / UTF8 Unicode string conversion
// Same behavior as strlcpy except it does an encoding conversion while doing the copy.
// length refers to wcslen(pSrcUCS).
// Returns the intended strlen of the destination.
//
// Example usage:
// wchar_t* strW = L"abcdefgh";
// char buffer[4];
// size_t requiredStrlen = Strlcpy(buffer, OVR_ARRAY_COUNT(buffer), strW);
//
// if(requiredStrlen >= OVR_ARRAY_COUNT(buffer)) // If not enough space...
// {
// char* pBuffer = new char[requiredStrlen + 1];
// Strlcpy(pBuffer, OVR_ARRAY_COUNT(requiredStrlen + 1), strW);
// ...
// }
//
size_t Strlcpy(
char* pDestUTF8,
size_t destCharCount,
const wchar_t* pSrcUCS,
size_t sourceLength = (size_t)-1);
// Same behavior as strlcpy except it does an encoding conversion while doing the copy.
// length refers to strlen(pSrcUTF8).
// Returns the intended wcslen of the destination.
//
// Example usage:
// char* str8 = "abcdefgh";
// wchar_t buffer[4];
// size_t requiredStrlen = Strlcpy(buffer, OVR_ARRAY_COUNT(buffer), str8);
//
// if(requiredStrlen >= OVR_ARRAY_COUNT(buffer)) // If not enough space...
// {
// wchar_t* pBuffer = new wchar_t[requiredStrlen + 1];
// Strlcpy(pBuffer, OVR_ARRAY_COUNT(requiredStrlen + 1), str8);
// ...
// }
//
size_t Strlcpy(
wchar_t* pDestUCS,
size_t destCharCount,
const char* pSrcUTF8,
size_t sourceLength = (size_t)-1);
// *** 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.
intptr_t GetLength(const char* putf8str, intptr_t 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_t GetCharAt(intptr_t index, const char* putf8str, intptr_t length = -1);
// Converts UTF8 character index into byte offset.
// A valid offset is always returned, either to the start of the string if index < 0,
// or to the terminating null character/end of string if the index'th character is past byteLength.
// Characters which straddle byteLength are truncated.
intptr_t GetByteIndex(intptr_t index, const char* putf8str, intptr_t byteLength = -1);
// Converts UTF8 character index into byte offset.
// -1 is returned if index was out of bounds or if the final character straddles byteLength.
intptr_t GetByteIndexChecked(intptr_t index, const char* putf8str, intptr_t byteLength = -1);
// *** Individual character Encoding/Decoding.
// Determined the number of bytes necessary to encode a UCS character.
int GetEncodeCharSize(uint32_t 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 EncodeChar(char* pbuffer, intptr_t* poffset, uint32_t 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_t DecodeNextChar_Advance0(const char** putf8Buffer);
// Safer version of DecodeNextChar, which doesn't advance pointer if
// null character is hit.
inline uint32_t DecodeNextChar(const char** putf8Buffer) {
uint32_t ch = DecodeNextChar_Advance0(putf8Buffer);
if (ch == 0)
(*putf8Buffer)--;
return ch;
}
} // namespace UTF8Util
} // namespace OVR
#endif

View File

@ -0,0 +1,223 @@
/************************************************************************************
Filename : OVR_Win32_IncludeWindows.h
Content : Small helper header to include Windows.h properly
Created : Oct 16, 2014
Authors : Chris Taylor, Scott Bassett
Copyright : Copyright 2014 Oculus, Inc. All Rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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_Win32_IncludeWindows_h
#define OVR_Win32_IncludeWindows_h
#include "OVR_Types.h"
// Automatically avoid including the Windows header on non-Windows platforms.
#ifdef OVR_OS_MS
// It is common practice to define WIN32_LEAN_AND_MEAN to reduce compile times.
// However this then requires us to define our own NTSTATUS data type and other
// irritations throughout our code-base.
#ifdef WIN32_LEAN_AND_MEAN
#undef WIN32_LEAN_AND_MEAN
#endif
// Prevents <Windows.h> from #including <Winsock.h>, as we use <Winsock2.h> instead.
#ifndef _WINSOCKAPI_
#define DID_DEFINE_WINSOCKAPI
#define _WINSOCKAPI_
#endif
// Prevents <Windows.h> from defining min() and max() macro symbols.
#ifndef NOMINMAX
#define NOMINMAX
#endif
OVR_DISABLE_ALL_MSVC_WARNINGS()
// d3dkmthk.h requires an NTSTATUS type, but WIN32_LEAN_AND_MEAN will prevent.
#define WIN32_NO_STATUS
#include <Windows.h>
#undef WIN32_NO_STATUS
#include <ntstatus.h>
OVR_RESTORE_ALL_MSVC_WARNINGS()
#ifdef DID_DEFINE_WINSOCKAPI
#undef _WINSOCKAPI_
#undef DID_DEFINE_WINSOCKAPI
#endif
namespace OVR {
//-----------------------------------------------------------------------------
// ScopedHANDLE
//
// MSVC 2010, and MSVC 2012 do not support the <wrl.h> utility header.
// So we provide our own version of HandleRAII, which is an incredibly
// useful pattern for working with Windows HANDLE values.
//
// HANDLEs have two invalid values in Windows, either nullptr or
// INVALID_HANDLE_VALUE. The invalid value that is correct for the usage must
// be provided as the template argument.
struct ScopedHANDLE_NullTraits {
// We cannot make this a static member variable as it is not an integral type.
inline static HANDLE InvalidValue() {
return nullptr;
}
};
struct ScopedHANDLE_InvalidTraits {
inline static HANDLE InvalidValue() {
return INVALID_HANDLE_VALUE;
}
};
template <typename Traits>
class ScopedHANDLE {
HANDLE hAttachedHandle;
public:
ScopedHANDLE(HANDLE handle) : hAttachedHandle(handle) {}
ScopedHANDLE() {
hAttachedHandle = Traits::InvalidValue();
}
ScopedHANDLE& operator=(HANDLE handle) {
Close();
hAttachedHandle = handle;
return *this;
}
~ScopedHANDLE() {
Close();
}
bool IsValid() const {
return hAttachedHandle != Traits::InvalidValue();
}
#if !(defined(OVR_CPP_NO_EXPLICIT_CONVERSION_OPERATORS) && OVR_CPP_NO_EXPLICIT_CONVERSION_OPERATORS)
operator bool() const {
return IsValid();
}
operator HANDLE() const {
return hAttachedHandle;
}
#endif
HANDLE Get() const {
return hAttachedHandle;
}
HANDLE& GetRawRef() {
return hAttachedHandle;
}
void Attach(HANDLE handle) {
Close();
hAttachedHandle = handle;
}
void Detach() {
// Do not close handle
hAttachedHandle = Traits::InvalidValue();
}
bool Copy() {
Close();
if (DuplicateHandle(
GetCurrentProcess(),
cpuEvent,
GetCurrentProcess() serverProcess.Get(),
&hAttachedHandle,
0,
FALSE,
DUPLICATE_SAME_ACCESS))
return true;
hAttachedHandle = Traits::InvalidValue();
return false;
}
bool Close() {
bool success = true;
if (hAttachedHandle != Traits::InvalidValue()) {
if (::CloseHandle(hAttachedHandle) != TRUE) {
success = false;
}
hAttachedHandle = Traits::InvalidValue();
}
return success;
}
};
// Different Windows API functions have different invalid values.
// These types are provided to improve readability.
typedef ScopedHANDLE<ScopedHANDLE_NullTraits> ScopedMutexHANDLE;
typedef ScopedHANDLE<ScopedHANDLE_NullTraits> ScopedEventHANDLE;
typedef ScopedHANDLE<ScopedHANDLE_InvalidTraits> ScopedFileHANDLE;
typedef ScopedHANDLE<ScopedHANDLE_NullTraits> ScopedProcessHANDLE;
typedef ScopedHANDLE<ScopedHANDLE_NullTraits> ScopedThreadHANDLE;
typedef ScopedHANDLE<ScopedHANDLE_NullTraits> ScopedSemaphoreHANDLE;
// Scoped registry keys
class ScopedHKEY {
HKEY hAttachedHandle;
public:
ScopedHKEY(HKEY handle) : hAttachedHandle(handle) {}
ScopedHKEY() {
hAttachedHandle = nullptr;
}
ScopedHKEY& operator=(HKEY handle) {
Close();
hAttachedHandle = handle;
return *this;
}
~ScopedHKEY() {
Close();
}
bool IsValid() {
return hAttachedHandle != nullptr;
}
HKEY Get() {
return hAttachedHandle;
}
HKEY& GetRawRef() {
return hAttachedHandle;
}
void Attach(HKEY handle) {
Close();
hAttachedHandle = handle;
}
void Detach() {
// Do not close handle
hAttachedHandle = nullptr;
}
bool Close() {
bool success = true;
if (hAttachedHandle != nullptr) {
if (::RegCloseKey(hAttachedHandle) == ERROR_SUCCESS) {
success = false;
}
hAttachedHandle = nullptr;
}
return success;
}
};
} // namespace OVR
#endif // OVR_OS_MS
#endif // OVR_Win32_IncludeWindows_h

View File

@ -0,0 +1,269 @@
#ifndef _mach_exc_user_
#define _mach_exc_user_
/* Module mach_exc */
#include <string.h>
#include <mach/ndr.h>
#include <mach/boolean.h>
#include <mach/kern_return.h>
#include <mach/notify.h>
#include <mach/mach_types.h>
#include <mach/message.h>
#include <mach/mig_errors.h>
#include <mach/port.h>
#ifdef AUTOTEST
#ifndef FUNCTION_PTR_T
#define FUNCTION_PTR_T
typedef void (*function_ptr_t)(mach_port_t, char*, mach_msg_type_number_t);
typedef struct {
char* name;
function_ptr_t function;
} function_table_entry;
typedef function_table_entry* function_table_t;
#endif /* FUNCTION_PTR_T */
#endif /* AUTOTEST */
#ifndef mach_exc_MSG_COUNT
#define mach_exc_MSG_COUNT 3
#endif /* mach_exc_MSG_COUNT */
#include <mach/std_types.h>
#include <mach/mig.h>
#include <mach/mig.h>
#include <mach/mach_types.h>
#ifdef __BeforeMigUserHeader
__BeforeMigUserHeader
#endif /* __BeforeMigUserHeader */
#include <sys/cdefs.h>
__BEGIN_DECLS
#if defined(__cplusplus)
extern "C" {
#endif
/* Routine mach_exception_raise_OVR */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t
mach_exception_raise_OVR(
mach_port_t exception_port,
mach_port_t thread,
mach_port_t task,
exception_type_t exception,
mach_exception_data_t code,
mach_msg_type_number_t codeCnt);
/* Routine mach_exception_raise_state_OVR */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t
mach_exception_raise_state_OVR(
mach_port_t exception_port,
exception_type_t exception,
const mach_exception_data_t code,
mach_msg_type_number_t codeCnt,
int* flavor,
const thread_state_t old_state,
mach_msg_type_number_t old_stateCnt,
thread_state_t new_state,
mach_msg_type_number_t* new_stateCnt);
/* Routine mach_exception_raise_state_identity_OVR */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t
mach_exception_raise_state_identity_OVR(
mach_port_t exception_port,
mach_port_t thread,
mach_port_t task,
exception_type_t exception,
mach_exception_data_t code,
mach_msg_type_number_t codeCnt,
int* flavor,
thread_state_t old_state,
mach_msg_type_number_t old_stateCnt,
thread_state_t new_state,
mach_msg_type_number_t* new_stateCnt);
__END_DECLS
/********************** Caution **************************/
/* The following data types should be used to calculate */
/* maximum message sizes only. The actual message may be */
/* smaller, and the position of the arguments within the */
/* message layout may vary from what is presented here. */
/* For example, if any of the arguments are variable- */
/* sized, and less than the maximum is sent, the data */
/* will be packed tight in the actual message to reduce */
/* the presence of holes. */
/********************** Caution **************************/
/* typedefs for all requests */
#ifndef __Request__mach_exc_subsystem__defined
#define __Request__mach_exc_subsystem__defined
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t thread;
mach_msg_port_descriptor_t task;
/* end of the kernel processed data */
NDR_record_t NDR;
exception_type_t exception;
mach_msg_type_number_t codeCnt;
int64_t code[2];
} __Request__mach_exception_raise_t;
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
exception_type_t exception;
mach_msg_type_number_t codeCnt;
int64_t code[2];
int flavor;
mach_msg_type_number_t old_stateCnt;
natural_t old_state[144];
} __Request__mach_exception_raise_state_t;
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t thread;
mach_msg_port_descriptor_t task;
/* end of the kernel processed data */
NDR_record_t NDR;
exception_type_t exception;
mach_msg_type_number_t codeCnt;
int64_t code[2];
int flavor;
mach_msg_type_number_t old_stateCnt;
natural_t old_state[144];
} __Request__mach_exception_raise_state_identity_t;
#ifdef __MigPackStructs
#pragma pack()
#endif
#endif /* !__Request__mach_exc_subsystem__defined */
/* union of all requests */
#ifndef __RequestUnion__mach_exc_subsystem__defined
#define __RequestUnion__mach_exc_subsystem__defined
union __RequestUnion__mach_exc_subsystem {
__Request__mach_exception_raise_t Request_mach_exception_raise;
__Request__mach_exception_raise_state_t Request_mach_exception_raise_state;
__Request__mach_exception_raise_state_identity_t Request_mach_exception_raise_state_identity;
};
#endif /* !__RequestUnion__mach_exc_subsystem__defined */
/* typedefs for all replies */
#ifndef __Reply__mach_exc_subsystem__defined
#define __Reply__mach_exc_subsystem__defined
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
} __Reply__mach_exception_raise_t;
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
int flavor;
mach_msg_type_number_t new_stateCnt;
natural_t new_state[144];
} __Reply__mach_exception_raise_state_t;
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
int flavor;
mach_msg_type_number_t new_stateCnt;
natural_t new_state[144];
} __Reply__mach_exception_raise_state_identity_t;
#ifdef __MigPackStructs
#pragma pack()
#endif
#endif /* !__Reply__mach_exc_subsystem__defined */
/* union of all replies */
#ifndef __ReplyUnion__mach_exc_subsystem__defined
#define __ReplyUnion__mach_exc_subsystem__defined
union __ReplyUnion__mach_exc_subsystem {
__Reply__mach_exception_raise_t Reply_mach_exception_raise;
__Reply__mach_exception_raise_state_t Reply_mach_exception_raise_state;
__Reply__mach_exception_raise_state_identity_t Reply_mach_exception_raise_state_identity;
};
#endif /* !__RequestUnion__mach_exc_subsystem__defined */
#ifndef subsystem_to_name_map_mach_exc
#define subsystem_to_name_map_mach_exc \
{"mach_exception_raise_OVR", 2405}, {"mach_exception_raise_state_OVR", 2406}, { \
"mach_exception_raise_state_identity_OVR", 2407 \
}
#endif
#ifdef __AfterMigUserHeader
__AfterMigUserHeader
#endif /* __AfterMigUserHeader */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
boolean_t mach_exc_server_OVR(mach_msg_header_t * InHeadP, mach_msg_header_t * OutHeadP);
#if defined(__cplusplus)
} // extern"C"
#endif
#endif /* _mach_exc_user_ */

View File

@ -0,0 +1,523 @@
<?xml version="1.0"?>
<instrumentationManifest xsi:schemaLocation="http://schemas.microsoft.com/win/2004/08/events eventman.xsd" xmlns="http://schemas.microsoft.com/win/2004/08/events" xmlns:win="http://manifests.microsoft.com/win/2004/08/windows/events" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:trace="http://schemas.microsoft.com/win/2004/08/events/trace">
<instrumentation>
<events>
<provider name="OVR-SDK-LibOVR" guid="{553787FC-D3D7-4F5E-ACB2-1597C7209B3C}" symbol="LibOVRProvider" resourceFileName="res" messageFileName="msg">
<events>
<event symbol="Call" value="0" version="0" channel="LibOVR/Analytic" level="win:Informational" task="Function" opcode="Call" template="FunctionWaypoint" message="$(string.OVR-SDK-LibOVR.event.0.message)"></event>
<event symbol="Return" value="1" version="0" channel="LibOVR/Analytic" level="win:Informational" task="Function" opcode="Return" template="FunctionWaypoint" message="$(string.OVR-SDK-LibOVR.event.1.message)"></event>
<event symbol="Waypoint" value="2" version="0" channel="LibOVR/Debug" level="win:Informational" task="Function" opcode="Waypoint" template="FunctionWaypoint" message="$(string.OVR-SDK-LibOVR.event.2.message)"></event>
<event symbol="DistortionBegin" value="4" version="0" channel="LibOVR/Analytic" level="win:Informational" task="Distort" opcode="Begin" template="Distortion" message="$(string.OVR-SDK-LibOVR.event.4.message)"></event>
<event symbol="DistortionWaitGPU" value="5" version="0" channel="LibOVR/Analytic" level="win:Informational" task="Distort" opcode="WaitGPU" template="Distortion" message="$(string.OVR-SDK-LibOVR.event.5.message)"></event>
<event symbol="DistortionPresent" value="6" version="0" channel="LibOVR/Analytic" level="win:Informational" task="Distort" opcode="Present" template="Distortion" message="$(string.OVR-SDK-LibOVR.event.6.message)"></event>
<event symbol="DistortionEnd" value="7" version="0" channel="LibOVR/Analytic" level="win:Informational" task="Distort" opcode="End" template="Distortion" message="$(string.OVR-SDK-LibOVR.event.7.message)"></event>
<event symbol="HmdDesc_v0" value="8" version="0" channel="LibOVR/Analytic" level="win:Informational" task="HmdInfo" opcode="HmdDesc" template="HmdDesc_v0" message="$(string.OVR-SDK-LibOVR.event.8.message)"></event>
<event symbol="HmdDesc" value="8" version="1" channel="LibOVR/Analytic" level="win:Informational" task="HmdInfo" opcode="HmdDesc" template="HmdDesc" message="$(string.OVR-SDK-LibOVR.event.8.message)"></event>
<event symbol="CameraFrameReceived_v0" value="9" version="0" channel="LibOVR/Analytic" level="win:Informational" task="Camera" opcode="Receive" template="CameraFrameData_v0" message="$(string.OVR-SDK-LibOVR.event.9.message)"></event>
<event symbol="CameraFrameReceived" value="9" version="1" channel="LibOVR/Analytic" level="win:Informational" task="Camera" opcode="Receive" template="CameraFrameData" message="$(string.OVR-SDK-LibOVR.event.9.message)"></event>
<event symbol="CameraBeginProcessing_v0" value="10" version="0" channel="LibOVR/Analytic" level="win:Informational" task="Camera" opcode="Begin" template="CameraFrameData_v0" message="$(string.OVR-SDK-LibOVR.event.10.message)"></event>
<event symbol="CameraBeginProcessing" value="10" version="1" channel="LibOVR/Analytic" level="win:Informational" task="Camera" opcode="Begin" template="CameraFrameData" message="$(string.OVR-SDK-LibOVR.event.10.message)"></event>
<event symbol="CameraFrameRequest" value="11" version="0" channel="LibOVR/Analytic" level="win:Informational" task="Camera" opcode="Request" template="CameraFrameRequest" message="$(string.OVR-SDK-LibOVR.event.11.message)"></event>
<event symbol="CameraEndProcessing_v0" value="12" version="0" channel="LibOVR/Analytic" level="win:Informational" task="Camera" opcode="End" template="CameraFrameData_v0" message="$(string.OVR-SDK-LibOVR.event.12.message)"></event>
<event symbol="CameraEndProcessing" value="12" version="1" channel="LibOVR/Analytic" level="win:Informational" task="Camera" opcode="End" template="CameraFrameData" message="$(string.OVR-SDK-LibOVR.event.12.message)"></event>
<event symbol="CameraSkippedFrames_v0" value="13" version="0" channel="LibOVR/Analytic" level="win:Informational" task="Camera" opcode="Waypoint" template="CameraFrameRequest" message="$(string.OVR-SDK-LibOVR.event.13.message)"></event>
<event symbol="CameraSkippedFrames" value="13" version="1" channel="LibOVR/Analytic" level="win:Informational" task="Camera" opcode="Waypoint" template="CameraGetFrame" message="$(string.OVR-SDK-LibOVR.event.13.message)"></event>
<event symbol="JSONChunk" value="14" version="0" channel="LibOVR/Analytic" level="win:Informational" task="HmdInfo" opcode="Waypoint" template="JSONChunk" message="$(string.OVR-SDK-LibOVR.event.14.message)"></event>
<event symbol="LogDebugMessage" value="15" version="0" channel="LibOVR/Debug" level="win:Verbose" task="Log" opcode="Waypoint" template="Log" message="$(string.OVR-SDK-LibOVR.event.15.message)"></event>
<event symbol="LogInfoMessage" value="16" version="0" channel="LibOVR/Analytic" level="win:Informational" task="Log" opcode="Waypoint" template="Log" message="$(string.OVR-SDK-LibOVR.event.16.message)"></event>
<event symbol="LogErrorMessage" value="17" version="0" channel="LibOVR/Error" level="win:Error" task="Log" opcode="Waypoint" template="Log" message="$(string.OVR-SDK-LibOVR.event.17.message)"></event>
<event symbol="HmdTrackingState" value="18" version="0" channel="LibOVR/Analytic" level="win:Informational" task="HmdInfo" opcode="Waypoint" template="HmdTrackingState" message="$(string.OVR-SDK-LibOVR.event.18.message)"></event>
<event symbol="CameraBlobs_v0" value="19" version="0" channel="LibOVR/Analytic" level="win:Informational" task="Camera" opcode="Waypoint" template="CameraBlobs_v0" message="$(string.OVR-SDK-LibOVR.event.19.message)"></event>
<event symbol="CameraBlobs" value="19" version="1" channel="LibOVR/Analytic" level="win:Informational" task="Camera" opcode="Waypoint" template="CameraBlobs" message="$(string.OVR-SDK-LibOVR.event.19.message)"></event>
<event symbol="PoseLatchCPUWrite" value="30" version="0" channel="LibOVR/Analytic" level="win:Informational" task="Distort" opcode="Begin" template="PoseLLCPUWrite" message="$(string.OVR-SDK-LibOVR.event.30.message)"></event>
<event symbol="PoseLatchGPULatchReadback" value="31" version="0" channel="LibOVR/Analytic" level="win:Informational" task="Distort" opcode="End" template="PoseLLGPUReadback" message="$(string.OVR-SDK-LibOVR.event.31.message)"></event>
<event symbol="QueueAheadDelayBegin" value="32" version="0" channel="LibOVR/Analytic" level="win:Informational" task="SubmitFrame" opcode="Begin" template="QueueAhead" message="$(string.OVR-SDK-LibOVR.event.32.message)"></event>
<event symbol="QueueAheadDelayEnd" value="33" version="0" channel="LibOVR/Analytic" level="win:Informational" task="SubmitFrame" opcode="End" template="QueueAhead" message="$(string.OVR-SDK-LibOVR.event.33.message)"></event>
<event symbol="HmdDisplay" value="34" version="0" channel="LibOVR/Analytic" level="win:Informational" task="HmdInfo" opcode="HmdDesc" template="HmdDisplay" message="$(string.OVR-SDK-LibOVR.event.34.message)"></event>
<event symbol="PhaseSyncBegin" value="35" version="0" channel="LibOVR/Analytic" level="win:Informational" task="PhaseSync" opcode="Begin" template="PhaseSyncBegin" message="$(string.OVR-SDK-LibOVR.event.35.message)"></event>
<event symbol="PhaseSyncEnd" value="36" version="0" channel="LibOVR/Analytic" level="win:Informational" task="PhaseSync" opcode="End" template="PhaseSyncEnd" message="$(string.OVR-SDK-LibOVR.event.36.message)"></event>
<event symbol="VSync" value="37" version="0" channel="LibOVR/Analytic" level="win:Informational" task="Distort" opcode="Present" template="RecordedVSync" message="$(string.OVR-SDK-LibOVR.event.37.message)"></event>
<event symbol="AppCompositorFocus" value="38" version="0" channel="LibOVR/Analytic" level="win:Informational" task="Log" opcode="Waypoint" template="AppEvent" message="$(string.OVR-SDK-LibOVR.event.38.message)"></event>
<event symbol="AppConnect" value="39" version="0" channel="LibOVR/Analytic" level="win:Informational" task="Log" opcode="Waypoint" template="AppEvent" message="$(string.OVR-SDK-LibOVR.event.39.message)"></event>
<event symbol="AppDisconnect" value="40" version="0" channel="LibOVR/Analytic" level="win:Informational" task="Log" opcode="Waypoint" template="AppEvent" message="$(string.OVR-SDK-LibOVR.event.40.message)"></event>
<event symbol="AppNoOp" value="41" version="0" channel="LibOVR/Analytic" level="win:Informational" task="Log" opcode="Waypoint" template="AppEvent" message="$(string.OVR-SDK-LibOVR.event.41.message)"></event>
<event symbol="PosePrediction" value="42" version="0" channel="LibOVR/Analytic" level="win:Informational" task="Sensor" opcode="Begin" template="PosePrediction" message="$(string.OVR-SDK-LibOVR.event.42.message)"></event>
<event symbol="LatencyTiming" value="43" version="0" channel="LibOVR/Analytic" level="win:Informational" task="Log" opcode="Waypoint" template="LatencyTiming" message="$(string.OVR-SDK-LibOVR.event.43.message)"></event>
<event symbol="EndFrameAppTiming" value="44" version="0" channel="LibOVR/Analytic" level="win:Informational" task="Log" opcode="Waypoint" template="EndFrameAppTiming" message="$(string.OVR-SDK-LibOVR.event.44.message)"></event>
<event symbol="HardwareInfo" value="45" version="0" channel="LibOVR/Analytic" level="win:Informational" task="HmdInfo" opcode="Waypoint" template="HardwareInfoTemplate" message="$(string.OVR-SDK-LibOVR.event.45.message)"></event>
<event symbol="VirtualDisplayPacketTrace" value="46" version="0" channel="LibOVR/Analytic" level="win:Informational" task="VirtualDisplay" opcode="Waypoint" template="VirtualDisplayPacketTemplate" message="$(string.OVR-SDK-LibOVR.event.46.message)"></event>
<event symbol="ClientFrameMissed" value="47" version="0" channel="LibOVR/Analytic" level="win:Informational" task="VirtualDisplay" opcode="Waypoint" template="ClientMissedFrame" message="$(string.OVR-SDK-LibOVR.event.47.message)"></event>
<event symbol="CompositionBegin" value="48" version="0" channel="LibOVR/Analytic" level="win:Informational" task="CompositorRunLoop" opcode="Begin" template="CompositionBegin" message="$(string.OVR-SDK-LibOVR.event.48.message)"></event>
<event symbol="CompositionEnd" value="49" version="0" channel="LibOVR/Analytic" level="win:Informational" task="CompositorRunLoop" opcode="End" message="$(string.OVR-SDK-LibOVR.event.49.message)"></event>
<event symbol="RenderPacketTrace" value="50" version="0" channel="LibOVR/Analytic" level="win:Informational" task="VirtualDisplay" opcode="Waypoint" template="RenderPacketTemplate" message="$(string.OVR-SDK-LibOVR.event.50.message)"></event>
<event symbol="EndFrameOrigAppTiming" value="51" version="0" channel="LibOVR/Analytic" level="win:Informational" task="Log" opcode="Begin" template="EndFrameAppTiming" message="$(string.OVR-SDK-LibOVR.event.51.message)"></event>
<event symbol="DistortionEndToEndTiming" value="52" version="0" channel="LibOVR/Analytic" level="win:LogAlways" task="CompositorRunLoop" opcode="Call" template="DistortionEndToEndTiming" message="$(string.OVR-SDK-LibOVR.event.52.message)"></event>
<event symbol="CompositionEndSpinWait" value="53" version="0" channel="LibOVR/Analytic" level="win:Informational" task="CompositorRunLoop" opcode="End" message="$(string.OVR-SDK-LibOVR.event.53.message)"></event>
<event symbol="CompositionFlushingToGPU" value="54" version="0" channel="LibOVR/Analytic" level="win:Informational" task="CompositorRunLoop" opcode="Waypoint" message="$(string.OVR-SDK-LibOVR.event.54.message)"></event>
<event symbol="PhaseSyncGPUCompleted" value="55" version="0" channel="LibOVR/Analytic" level="win:Informational" task="PhaseSync" opcode="Waypoint" template="PhaseSyncAppGPUEndTime" message="$(string.OVR-SDK-LibOVR.event.55.message)"></event>
<event symbol="CompositionMissedCompositorFrame" value="56" version="0" channel="LibOVR/Analytic" level="win:Informational" task="CompositorRunLoop" opcode="Waypoint" message="$(string.OVR-SDK-LibOVR.event.56.message)"></event>
<event symbol="CompositionGPUStartTime" value="57" version="0" channel="LibOVR/Analytic" level="win:Informational" task="CompositorRunLoop" opcode="Waypoint" template="CompositionGPUBeginTime" message="$(string.OVR-SDK-LibOVR.event.57.message)"></event>
<event symbol="NotificationBegin" value="58" version="0" channel="LibOVR/Analytic" level="win:Informational" task="Notification" opcode="Waypoint" template="NotificationBegin" message="$(string.OVR-SDK-LibOVR.event.58.message)"></event>
<event symbol="NotificationEnd" value="59" version="0" channel="LibOVR/Analytic" level="win:Informational" task="Notification" opcode="Waypoint" template="NotificationEnd" message="$(string.OVR-SDK-LibOVR.event.59.message)"></event>
<event symbol="NotificationCompSubmit" value="60" version="0" channel="LibOVR/Analytic" level="win:Informational" task="Notification" opcode="Waypoint" template="NotificationCompSubmit" message="$(string.OVR-SDK-LibOVR.event.60.message)"></event>
<event symbol="MotionEstimationCostStats" value="61" version="0" channel="LibOVR/Analytic" level="win:Informational" task="CompositorRunLoop" opcode="Waypoint" template="MotionEstimationCostStats" message="$(string.OVR-SDK-LibOVR.event.61.message)"></event>
<event symbol="PhaseSyncWaitToBeginFrame" value="62" version="0" channel="LibOVR/Analytic" level="win:Informational" task="PhaseSync" opcode="Waypoint" template="PhaseSyncWaitToBeginFrame" message="$(string.OVR-SDK-LibOVR.event.63.message)"></event>
<event symbol="PhaseSyncBeginFrame" value="63" version="0" channel="LibOVR/Analytic" level="win:Informational" task="PhaseSync" opcode="Waypoint" template="PhaseSyncBeginFrame" message="$(string.OVR-SDK-LibOVR.event.64.message)"></event>
<event symbol="PhaseSyncEndFrame" value="64" version="0" channel="LibOVR/Analytic" level="win:Informational" task="PhaseSync" opcode="Waypoint" template="PhaseSyncEndFrame" message="$(string.OVR-SDK-LibOVR.event.65.message)"></event>
<event symbol="PhaseSyncCompleteFrame" value="65" version="0" channel="LibOVR/Analytic" level="win:Informational" task="PhaseSync" opcode="Waypoint" template="PhaseSyncCompleteFrame" message="$(string.OVR-SDK-LibOVR.event.66.message)"></event>
</events>
<levels></levels>
<tasks>
<task name="Function" symbol="FN_TRACE" value="1" eventGUID="{00000000-0000-0000-0000-000000000000}" message="$(string.OVR-SDK-LibOVR.task.FN_TRACE.message)"></task>
<task name="Distort" symbol="DIS_TRACE" value="2" eventGUID="{00000000-0000-0000-0000-000000000000}" message="$(string.OVR-SDK-LibOVR.task.DIS_TRACE.message)"></task>
<task name="HmdInfo" symbol="HMD_TRACE" value="3" eventGUID="{00000000-0000-0000-0000-000000000000}" message="$(string.OVR-SDK-LibOVR.task.HMD_TRACE.message)"></task>
<task name="Camera" symbol="CAMERA_TRACE" value="4" eventGUID="{00000000-0000-0000-0000-000000000000}" message="$(string.OVR-SDK-LibOVR.task.CAMERA_TRACE.message)"></task>
<task name="Log" symbol="LOG_TRACE" value="5" eventGUID="{00000000-0000-0000-0000-000000000000}" message="$(string.OVR-SDK-LibOVR.task.LOG_TRACE.message)"></task>
<task name="SubmitFrame" symbol="SUBMITFRAME_TRACE" value="6" eventGUID="{00000000-0000-0000-0000-000000000000}" message="$(string.OVR-SDK-LibOVR.task.SUBMITFRAME_TRACE.message)"></task>
<task name="PhaseSync" symbol="PHASESYNC_TRACE" value="7" eventGUID="{00000000-0000-0000-0000-000000000000}" message="$(string.OVR-SDK-LibOVR.task.PHASESYNC_TRACE.message)"></task>
<task name="Sensor" symbol="SENSOR_TRACE" value="8" eventGUID="{00000000-0000-0000-0000-000000000000}" message="$(string.OVR-SDK-LibOVR.task.SENSOR_TRACE.message)"></task>
<task name="VirtualDisplay" symbol="VIRTUALDISPLAY_TRACE" value="9" eventGUID="{00000000-0000-0000-0000-000000000000}" message="$(string.OVR-SDK-LibOVR.task.VIRTUALDISPLAY_TRACE.message)"></task>
<task name="CompositorRunLoop" symbol="COMPOSITOR_RUNLOOP_TRACE" value="10" eventGUID="{00000000-0000-0000-0000-000000000000}" message="$(string.OVR-SDK-LibOVR.task.Compositor_RunLoop.message)"></task>
<task name="Notification" symbol="NOTIFICATION_TRACE" value="11" eventGUID="{00000000-0000-0000-0000-000000000000}" message="$(string.OVR-SDK-LibOVR.task.NOTIFICATION_TRACE.message)"></task>
</tasks>
<opcodes>
<opcode name="Call" symbol="FN_CALL" value="10" message="$(string.OVR-SDK-LibOVR.opcode.FN_CALL.message)"></opcode>
<opcode name="Return" symbol="FN_RETURN" value="11" message="$(string.OVR-SDK-LibOVR.opcode.FN_RETURN.message)"></opcode>
<opcode name="Waypoint" symbol="FN_WAYPOINT" value="12" message="$(string.OVR-SDK-LibOVR.opcode.FN_WAYPOINT.message)"></opcode>
<opcode name="Begin" symbol="DIS_BEGIN" value="13" message="$(string.OVR-SDK-LibOVR.opcode.DIS_BEGIN.message)"></opcode>
<opcode name="WaitGPU" symbol="DIS_WAITGPU" value="14" message="$(string.OVR-SDK-LibOVR.opcode.DIS_WAITGPU.message)"></opcode>
<opcode name="Present" symbol="DIS_PRESENT" value="15" message="$(string.OVR-SDK-LibOVR.opcode.DIS_PRESENT.message)"></opcode>
<opcode name="End" symbol="DIS_END" value="16" message="$(string.OVR-SDK-LibOVR.opcode.DIS_END.message)"></opcode>
<opcode name="HmdDesc" symbol="HMD_DESC" value="17" message="$(string.OVR-SDK-LibOVR.opcode.HMD_DESC.message)"></opcode>
<opcode name="Receive" symbol="CAM_RECEIVE" value="18" message="$(string.OVR-SDK-LibOVR.opcode.CAM_RECEIVE.message)"></opcode>
<opcode name="Request" symbol="CAM_REQUEST" value="19" message="$(string.OVR-SDK-LibOVR.opcode.CAM_REQUEST.message)"></opcode>
</opcodes>
<channels>
<channel name="LibOVR/Debug" chid="LibOVR/Debug" symbol="DEBUG_CHANNEL" type="Debug" enabled="false"></channel>
<channel name="LibOVR/Analytic" chid="LibOVR/Analytic" symbol="ANALYTIC_CHANNEL" type="Analytic" enabled="false"></channel>
<channel name="LibOVR/Error" chid="LibOVR/Error" symbol="ERROR_CHANNEL" type="Operational" enabled="false"></channel>
</channels>
<templates>
<template tid="FunctionWaypoint">
<data name="Name" inType="win:UnicodeString" outType="xs:string"></data>
<data name="Line" inType="win:Int32" outType="xs:int"></data>
<data name="FrameID" inType="win:UInt32" outType="xs:unsignedInt"></data>
</template>
<template tid="Distortion">
<data name="VidPnTargetId" inType="win:UInt32" outType="xs:unsignedInt"></data>
<data name="FrameID" inType="win:UInt32" outType="xs:unsignedInt"></data>
</template>
<template tid="HmdDesc_v0">
<data name="Type" inType="win:UInt32" outType="xs:unsignedInt"></data>
<data name="VendorId" inType="win:Int16" outType="xs:short"></data>
<data name="ProductId" inType="win:Int16" outType="xs:short"></data>
<data name="SerialNumber" inType="win:AnsiString" outType="xs:string" length="24"></data>
<data name="FirmwareMajor" inType="win:Int16" outType="xs:short"></data>
<data name="FirmwareMinor" inType="win:Int16" outType="xs:short"></data>
<data name="HmdCaps" inType="win:UInt32" outType="xs:unsignedInt"></data>
<data name="TrackingCaps" inType="win:UInt32" outType="xs:unsignedInt"></data>
<data name="DistortionCaps" inType="win:UInt32" outType="xs:unsignedInt"></data>
<data name="ResolutionWidth" inType="win:Int32" outType="xs:int"></data>
<data name="ResolutionHeight" inType="win:Int32" outType="xs:int"></data>
</template>
<template tid="HmdDesc">
<data name="Type" inType="win:UInt32" outType="xs:unsignedInt"></data>
<data name="VendorId" inType="win:Int16" outType="xs:short"></data>
<data name="ProductId" inType="win:Int16" outType="xs:short"></data>
<data name="SerialNumber" inType="win:AnsiString" outType="xs:string" length="24"></data>
<data name="FirmwareMajor" inType="win:Int16" outType="xs:short"></data>
<data name="FirmwareMinor" inType="win:Int16" outType="xs:short"></data>
<data name="HmdCaps" inType="win:UInt32" outType="xs:unsignedInt"></data>
<data name="TrackingCaps" inType="win:UInt32" outType="xs:unsignedInt"></data>
<data name="ResolutionWidth" inType="win:Int32" outType="xs:int"></data>
<data name="ResolutionHeight" inType="win:Int32" outType="xs:int"></data>
</template>
<template tid="CameraFrameData_v0">
<data name="FrameRate" inType="win:Float" outType="xs:float"></data>
<data name="FrameNumber" inType="win:UInt32" outType="xs:unsignedInt"></data>
<data name="ArrivalTimeSeconds" inType="win:Double" outType="xs:double"></data>
<data name="CaptureTime" inType="win:Double" outType="xs:double"></data>
<data name="LostFrames" inType="win:UInt32" outType="xs:unsignedInt"></data>
</template>
<template tid="CameraFrameData">
<data name="Camera" inType="win:UInt32" outType="xs:unsignedInt"></data>
<data name="FrameNumber" inType="win:Int32" outType="xs:int"></data>
<data name="HmdFrameNumber" inType="win:Int32" outType="xs:int"></data>
<data name="ArrivalTime" inType="win:Double" outType="xs:double"></data>
<data name="CaptureTime" inType="win:Double" outType="xs:double"></data>
</template>
<template tid="CameraFrameRequest">
<data name="RequestNumber" inType="win:UInt64" outType="xs:unsignedLong"></data>
<data name="FrameCounter" inType="win:UInt64" outType="xs:unsignedLong"></data>
<data name="LastFrameNumber" inType="win:UInt32" outType="xs:unsignedInt"></data>
</template>
<template tid="CameraGetFrame">
<data name="Camera" inType="win:UInt32" outType="xs:unsignedInt"></data>
<data name="LastFrameNumber" inType="win:UInt32" outType="xs:unsignedInt"></data>
</template>
<template tid="JSONChunk">
<data name="Name" inType="win:UnicodeString" outType="xs:string"></data>
<data name="TotalChunks" inType="win:UInt32" outType="xs:unsignedInt"></data>
<data name="ChunkSequence" inType="win:UInt32" outType="xs:unsignedInt"></data>
<data name="TotalSize" inType="win:UInt32" outType="xs:unsignedInt"></data>
<data name="ChunkSize" inType="win:UInt32" outType="xs:unsignedInt"></data>
<data name="ChunkOffset" inType="win:UInt32" outType="xs:unsignedInt"></data>
<data name="Chunk" inType="win:Binary" outType="xs:hexBinary" length="ChunkSize"></data>
</template>
<template tid="Log">
<data name="Message" inType="win:AnsiString" outType="xs:string"></data>
</template>
<template tid="HmdTrackingState">
<data name="TimeInSeconds" inType="win:Double" outType="xs:double"></data>
<data name="HeadPoseQuat" inType="win:Float" outType="xs:float" count="4"></data>
<data name="HeadPoseTranslation" inType="win:Float" outType="xs:float" count="3"></data>
<data name="HeadAngularVelocity" inType="win:Float" outType="xs:float" count="3"></data>
<data name="HeadLinearVelocity" inType="win:Float" outType="xs:float" count="3"></data>
<data name="CameraPoseQuat" inType="win:Float" outType="xs:float" count="4"></data>
<data name="CameraPoseTranslation" inType="win:Float" outType="xs:float" count="3"></data>
<data name="StatusFlags" inType="win:UInt32" outType="xs:unsignedInt"></data>
</template>
<template tid="CameraBlobs_v0">
<data name="BlobCount" inType="win:UInt32" outType="xs:unsignedInt"></data>
<data name="PositionX" inType="win:Double" outType="xs:double" count="BlobCount"></data>
<data name="PositionY" inType="win:Double" outType="xs:double" count="BlobCount"></data>
<data name="Size" inType="win:Int32" outType="xs:int" count="BlobCount"></data>
</template>
<template tid="CameraBlobs">
<data name="Camera" inType="win:UInt32" outType="xs:unsignedInt"></data>
<data name="FrameNumber" inType="win:Int32" outType="xs:int"></data>
<data name="ArrivalTime" inType="win:Double" outType="xs:double"></data>
<data name="Width" inType="win:Int32" outType="xs:int"></data>
<data name="Height" inType="win:Int32" outType="xs:int"></data>
<data name="BlobCount" inType="win:UInt32" outType="xs:unsignedInt"></data>
<data name="PositionX" inType="win:Double" outType="xs:double" count="BlobCount"></data>
<data name="PositionY" inType="win:Double" outType="xs:double" count="BlobCount"></data>
<data name="Size" inType="win:Int32" outType="xs:int" count="BlobCount"></data>
</template>
<template tid="PoseLLCPUWrite">
<data name="Sequence" inType="win:UInt32" outType="xs:unsignedInt"></data>
<data name="Layer" inType="win:Int32" outType="xs:int"></data>
<data name="MotionSensorTime" inType="win:Float" outType="xs:float"></data>
<data name="PredictedScanlineFirst" inType="win:Float" outType="xs:float"></data>
<data name="PredictedScanlineLast" inType="win:Float" outType="xs:float"></data>
<data name="TimeToScanlineFirst" inType="win:Float" outType="xs:float"></data>
<data name="TimeToScanlineLast" inType="win:Float" outType="xs:float"></data>
<data name="StartPosition" inType="win:Float" outType="xs:float" count="3"></data>
<data name="EndPosition" inType="win:Float" outType="xs:float" count="3"></data>
<data name="StartQuat" inType="win:Float" outType="xs:float" count="4"></data>
<data name="EndQuat" inType="win:Float" outType="xs:float" count="4"></data>
</template>
<template tid="QueueAhead">
<data name="QueueAheadSeconds" inType="win:Float" outType="xs:float"></data>
</template>
<template tid="HmdDisplay">
<data name="Extended" inType="win:Boolean" outType="xs:boolean"></data>
<data name="DeviceTypeGuess" inType="win:UInt32" outType="xs:unsignedInt"></data>
<data name="EdidVendorId" inType="win:UInt16" outType="xs:unsignedShort"></data>
<data name="EdidModelNumber" inType="win:UInt16" outType="xs:unsignedShort"></data>
<data name="DisplayID" inType="win:AnsiString" outType="xs:string"></data>
<data name="ModelName" inType="win:AnsiString" outType="xs:string"></data>
<data name="EdidSerialNumber" inType="win:AnsiString" outType="xs:string"></data>
<data name="LogicalResolutionInPixels_w" inType="win:Int32" outType="xs:int"></data>
<data name="LogicalResolutionInPixels_h" inType="win:Int32" outType="xs:int"></data>
<data name="NativeResolutionInPixels_w" inType="win:Int32" outType="xs:int"></data>
<data name="NativeResolutionInPixels_h" inType="win:Int32" outType="xs:int"></data>
<data name="DesktopDisplayOffset_x" inType="win:Int32" outType="xs:int"></data>
<data name="DesktopDisplayOffset_y" inType="win:Int32" outType="xs:int"></data>
<data name="DeviceNumber" inType="win:UInt64" outType="xs:unsignedLong"></data>
<data name="Rotation" inType="win:UInt32" outType="xs:unsignedInt"></data>
<data name="ApplicationExclusive" inType="win:Boolean" outType="xs:boolean"></data>
</template>
<template tid="PoseLLGPUReadback">
<data name="Sequence" inType="win:UInt32" outType="xs:unsignedInt"></data>
<data name="Layer" inType="win:Int32" outType="xs:int"></data>
<data name="MotionSensorTime" inType="win:Float" outType="xs:float"></data>
<data name="PredictedScanlineFirst" inType="win:Float" outType="xs:float"></data>
<data name="PredictedScanlineLast" inType="win:Float" outType="xs:float"></data>
<data name="TimeToScanlineFirst" inType="win:Float" outType="xs:float"></data>
<data name="TimeToScanlineLast" inType="win:Float" outType="xs:float"></data>
</template>
<template tid="PhaseSyncBegin">
<data name="LastCompositeTime" inType="win:Double" outType="xs:double"></data>
<data name="LastVSyncTime" inType="win:Double" outType="xs:double"></data>
<data name="FrameIntervalMS" inType="win:Float" outType="xs:float"></data>
<data name="SemaphoreMS" inType="win:Float" outType="xs:float"></data>
<data name="SleepMS" inType="win:Float" outType="xs:float"></data>
<data name="SpinMS" inType="win:Float" outType="xs:float"></data>
<data name="PhaseSyncMS" inType="win:Float" outType="xs:float"></data>
<data name="BeginFrameTime" inType="win:Double" outType="xs:double"></data>
<data name="TargetCompletionTime" inType="win:Double" outType="xs:double"></data>
<data name="TargetCompositeTime" inType="win:Double" outType="xs:double"></data>
<data name="TargetVSyncTime" inType="win:Double" outType="xs:double"></data>
</template>
<template tid="PhaseSyncEnd">
<data name="BeginFrameTime" inType="win:Double" outType="xs:double"></data>
<data name="EndFrameTime" inType="win:Double" outType="xs:double"></data>
<data name="CompletionTime" inType="win:Double" outType="xs:double"></data>
<data name="CompositeTime" inType="win:Double" outType="xs:double"></data>
<data name="VSyncTime" inType="win:Double" outType="xs:double"></data>
<data name="FrameTimeMS" inType="win:Float" outType="xs:float"></data>
<data name="FrameTimeCpuMS" inType="win:Float" outType="xs:float"></data>
<data name="FrameTimeVarianceMS" inType="win:Float" outType="xs:float"></data>
<data name="QueueAhead" inType="win:Float" outType="xs:float"></data>
<data name="FramesMissed" inType="win:UInt32" outType="xs:unsignedInt"></data>
<data name="AvgFrameTimeMS" inType="win:Float" outType="xs:float"></data>
<data name="AvgFrameTimeCpuMS" inType="win:Float" outType="xs:float"></data>
<data name="AvgFrameTimeVarianceMS" inType="win:Float" outType="xs:float"></data>
<data name="AvgQueueAhead" inType="win:Float" outType="xs:float"></data>
<data name="SyncFrameTimeMS" inType="win:Float" outType="xs:float"></data>
<data name="SyncQueueAhead" inType="win:Float" outType="xs:float"></data>
<data name="SyncFramesMissed" inType="win:UInt32" outType="xs:unsignedInt"></data>
<data name="PhaseSyncMS" inType="win:Float" outType="xs:float"></data>
</template>
<template tid="RecordedVSync">
<data name="Time" inType="win:Double" outType="xs:double"></data>
<data name="FrameIndex" inType="win:UInt32" outType="xs:unsignedInt"></data>
<data name="TwGpuEndTime" inType="win:Double" outType="xs:double"></data>
</template>
<template tid="AppEvent">
<data name="ProcessID" inType="win:UInt64" outType="xs:unsignedLong"></data>
</template>
<template tid="PosePrediction">
<data name="OriginalPosition" inType="win:Double" outType="xs:double" count="3"></data>
<data name="OriginalOrientation" inType="win:Double" outType="xs:double" count="4"></data>
<data name="PredictedPosition" inType="win:Double" outType="xs:double" count="3"></data>
<data name="PredictedOrientation" inType="win:Double" outType="xs:double" count="4"></data>
<data name="PredictionTimeDeltaSeconds" inType="win:Double" outType="xs:double"></data>
<data name="TimeInSeconds" inType="win:Double" outType="xs:double"></data>
<data name="id" inType="win:AnsiString" outType="xs:string"></data>
</template>
<template tid="LatencyTiming">
<data name="RenderCpuBegin" inType="win:Double" outType="xs:double"></data>
<data name="RenderCpuEnd" inType="win:Double" outType="xs:double"></data>
<data name="RenderImu" inType="win:Double" outType="xs:double"></data>
<data name="TimewarpCpu" inType="win:Double" outType="xs:double"></data>
<data name="TimewarpLatched" inType="win:Double" outType="xs:double"></data>
<data name="TimewarpGpuEnd" inType="win:Double" outType="xs:double"></data>
<data name="PostPresent" inType="win:Double" outType="xs:double"></data>
<data name="ErrorRender" inType="win:Double" outType="xs:double"></data>
<data name="ErrorTimewarp" inType="win:Double" outType="xs:double"></data>
</template>
<template tid="EndFrameAppTiming">
<data name="FrameIndex" inType="win:UInt32" outType="xs:unsignedInt"></data>
<data name="RenderImuTime" inType="win:Double" outType="xs:double"></data>
<data name="ScanoutStartTime" inType="win:Double" outType="xs:double"></data>
<data name="GpuRenderDuration" inType="win:Double" outType="xs:double"></data>
<data name="BeginRenderingTime" inType="win:Double" outType="xs:double"></data>
<data name="EndRenderingTime" inType="win:Double" outType="xs:double"></data>
<data name="QueueAheadSeconds" inType="win:Double" outType="xs:double"></data>
<data name="RenderCount" inType="win:Int32" outType="xs:int"></data>
</template>
<template tid="HardwareInfoTemplate">
<data name="RequestedBits" inType="win:UInt32" outType="xs:unsignedInt"></data>
<data name="CollectedBits" inType="win:UInt32" outType="xs:unsignedInt"></data>
<data name="ImuTemp" inType="win:UInt16" outType="xs:unsignedShort"></data>
<data name="StmTemp" inType="win:UInt16" outType="xs:unsignedShort"></data>
<data name="NrfTemp" inType="win:UInt16" outType="xs:unsignedShort"></data>
<data name="VBusVoltage" inType="win:UInt16" outType="xs:unsignedShort"></data>
<data name="IAD" inType="win:UInt16" outType="xs:unsignedShort"></data>
<data name="Proximity" inType="win:UInt16" outType="xs:unsignedShort"></data>
<data name="PanelOnTime" inType="win:UInt32" outType="xs:unsignedInt"></data>
<data name="UseRolling" inType="win:Boolean" outType="xs:boolean"></data>
<data name="HighBrightness" inType="win:Boolean" outType="xs:boolean"></data>
<data name="DP" inType="win:Boolean" outType="xs:boolean"></data>
<data name="SelfRefresh" inType="win:Boolean" outType="xs:boolean"></data>
<data name="Persistence" inType="win:UInt16" outType="xs:unsignedShort"></data>
<data name="LightingOffset" inType="win:UInt16" outType="xs:unsignedShort"></data>
<data name="PixelSettle" inType="win:UInt16" outType="xs:unsignedShort"></data>
<data name="TotalRows" inType="win:UInt16" outType="xs:unsignedShort"></data>
</template>
<template tid="VirtualDisplayPacketTemplate">
<data name="PacketType" inType="win:UInt64" outType="xs:unsignedLong"></data>
<data name="Stage" inType="win:Int32" outType="xs:int"></data>
<data name="SubmittingProcessID" inType="win:UInt64" outType="xs:unsignedLong"></data>
<data name="ActiveProcessID" inType="win:UInt64" outType="xs:unsignedLong"></data>
</template>
<template tid="ClientMissedFrame">
<data name="FrameIndex" inType="win:UInt64" outType="xs:unsignedLong"></data>
<data name="ProcessID" inType="win:UInt64" outType="xs:unsignedLong"></data>
</template>
<template tid="RenderPacketTemplate">
<data name="Stage" inType="win:UInt32" outType="xs:unsignedInt"></data>
<data name="ClientPID" inType="win:UInt64" outType="xs:unsignedLong"></data>
</template>
<template tid="DistortionEndToEndTiming">
<data name="ElapsedMs" inType="win:Double" outType="xs:double"></data>
</template>
<template tid="CompositionBegin">
<data name="ExpectedCPUStartTimeInSeconds" inType="win:Double" outType="xs:double"></data>
<data name="ActualCPUStartTimeInSeconds" inType="win:Double" outType="xs:double"></data>
</template>
<template tid="CompositionGPUBeginTime">
<data name="DistortionBeginTimeInSeconds" inType="win:Double" outType="xs:double"></data>
</template>
<template tid="PhaseSyncAppGPUEndTime">
<data name="AppGPUEndTimeSeconds" inType="win:Double" outType="xs:double"></data>
</template>
<template tid="NotificationEnd">
<data name="AppFrameIndex" inType="win:UInt64" outType="xs:unsignedLong"></data>
<data name="CpuBeginToGpuEndSeconds" inType="win:Double" outType="xs:double"></data>
<data name="CpuBeginSeconds" inType="win:Double" outType="xs:double"></data>
<data name="GpuEndSeconds" inType="win:Double" outType="xs:double"></data>
<data name="SleepTimeMilliseconds" inType="win:UInt32" outType="xs:unsignedInt"></data>
</template>
<template tid="NotificationBegin">
<data name="AppFrameIndex" inType="win:UInt64" outType="xs:unsignedLong"></data>
<data name="CpuBeginToGpuEndSeconds" inType="win:Double" outType="xs:double"></data>
<data name="CompositeTimeSeconds" inType="win:Double" outType="xs:double"></data>
<data name="VSyncTimeSeconds" inType="win:Double" outType="xs:double"></data>
<data name="CompositeDeltaSeconds" inType="win:Double" outType="xs:double"></data>
<data name="VSyncDeltaSeconds" inType="win:Double" outType="xs:double"></data>
</template>
<template tid="NotificationCompSubmit">
<data name="ShouldBeVisible" inType="win:Boolean" outType="xs:boolean"></data>
<data name="DisabledLayer" inType="win:Boolean" outType="xs:boolean"></data>
<data name="FrameIndex" inType="win:UInt64" outType="xs:unsignedLong"></data>
</template>
<template tid="MotionEstimationCostStats">
<data name="Count" inType="win:UInt32" outType="xs:unsignedInt"></data>
<data name="Average" inType="win:UInt32" outType="xs:unsignedInt"></data>
<data name="Log2Histogram" inType="win:UInt32" outType="xs:unsignedInt" count="33"></data>
</template>
<template tid="PhaseSyncWaitToBeginFrame">
<data name="Frame" inType="win:UInt64" outType="xs:unsignedLong"></data>
<data name="BeginWaitTime" inType="win:Double" outType="xs:double"></data>
<data name="SemaphoreMS" inType="win:Float" outType="xs:float"></data>
<data name="SleepMS" inType="win:Float" outType="xs:float"></data>
<data name="SpinMS" inType="win:Float" outType="xs:float"></data>
<data name="EndWaitTime" inType="win:Double" outType="xs:double"></data>
<data name="TargetCompletionTime" inType="win:Double" outType="xs:double"></data>
<data name="TargetCompositeTime" inType="win:Double" outType="xs:double"></data>
<data name="TargetVSyncTime" inType="win:Double" outType="xs:double"></data>
</template>
<template tid="PhaseSyncBeginFrame">
<data name="Frame" inType="win:UInt64" outType="xs:unsignedLong"></data>
<data name="BeginFrameTime" inType="win:Double" outType="xs:double"></data>
</template>
<template tid="PhaseSyncEndFrame">
<data name="Frame" inType="win:UInt64" outType="xs:unsignedLong"></data>
<data name="EndFrameTime" inType="win:Double" outType="xs:double"></data>
</template>
<template tid="PhaseSyncCompleteFrame">
<data name="Frame" inType="win:UInt64" outType="xs:unsignedLong"></data>
<data name="CompletionTime" inType="win:Double" outType="xs:double"></data>
<data name="CompositeTime" inType="win:Double" outType="xs:double"></data>
<data name="VSyncTime" inType="win:Double" outType="xs:double"></data>
<data name="FrameTimeMS" inType="win:Float" outType="xs:float"></data>
<data name="AvgFrameTimeMS" inType="win:Float" outType="xs:float"></data>
<data name="FrameTimeCpuMS" inType="win:Float" outType="xs:float"></data>
<data name="AvgFrameTimeCpuMS" inType="win:Float" outType="xs:float"></data>
<data name="FrameTimeGpuMS" inType="win:Float" outType="xs:float"></data>
<data name="AvgFrameTimeGpuMS" inType="win:Float" outType="xs:float"></data>
<data name="FrameVarianceMS" inType="win:Float" outType="xs:float"></data>
<data name="AvgFrameVarianceMS" inType="win:Float" outType="xs:float"></data>
<data name="QueueAheadMS" inType="win:Float" outType="xs:float"></data>
<data name="AvgQueueAheadMS" inType="win:Float" outType="xs:float"></data>
<data name="AdaptiveGpuPerformanceScale" inType="win:Float" outType="xs:float"></data>
<data name="AvgAdaptiveGpuPerformanceScale" inType="win:Float" outType="xs:float"></data>
<data name="PhaseSyncDelayMS" inType="win:Float" outType="xs:float"></data>
</template>
</templates>
</provider>
</events>
</instrumentation>
<localization>
<resources culture="en-US">
<stringTable>
<string id="opcode.Info" value="Info"></string>
<string id="level.Verbose" value="Verbose"></string>
<string id="level.LogAlways" value="Log Always"></string>
<string id="level.Informational" value="Information"></string>
<string id="level.Error" value="Error"></string>
<string id="OVR-SDK-LibOVR.task.VIRTUALDISPLAY_TRACE.message" value="VirtualDisplay"></string>
<string id="OVR-SDK-LibOVR.task.SUBMITFRAME_TRACE.message" value="SubmitFrame"></string>
<string id="OVR-SDK-LibOVR.task.SENSOR_TRACE.message" value="Sensor"></string>
<string id="OVR-SDK-LibOVR.task.PHASESYNC_TRACE.message" value="PhaseSync"></string>
<string id="OVR-SDK-LibOVR.task.NOTIFICATION_TRACE.message" value="Notification"></string>
<string id="OVR-SDK-LibOVR.task.LOG_TRACE.message" value="Log"></string>
<string id="OVR-SDK-LibOVR.task.HMD_TRACE.message" value="HmdInfo"></string>
<string id="OVR-SDK-LibOVR.task.FN_TRACE.message" value="Function"></string>
<string id="OVR-SDK-LibOVR.task.DIS_TRACE.message" value="Distort"></string>
<string id="OVR-SDK-LibOVR.task.Compositor_RunLoop.message" value="Compositor run loop (render thread) events."></string>
<string id="OVR-SDK-LibOVR.task.CAMERA_TRACE.message" value="Camera"></string>
<string id="OVR-SDK-LibOVR.opcode.HMD_DESC.message" value="Descriptor"></string>
<string id="OVR-SDK-LibOVR.opcode.FN_WAYPOINT.message" value="Waypoint"></string>
<string id="OVR-SDK-LibOVR.opcode.FN_RETURN.message" value="Return"></string>
<string id="OVR-SDK-LibOVR.opcode.FN_CALL.message" value="Call"></string>
<string id="OVR-SDK-LibOVR.opcode.DIS_WAITGPU.message" value="WaitGPU"></string>
<string id="OVR-SDK-LibOVR.opcode.DIS_PRESENT.message" value="Present"></string>
<string id="OVR-SDK-LibOVR.opcode.DIS_END.message" value="End"></string>
<string id="OVR-SDK-LibOVR.opcode.DIS_BEGIN.message" value="Begin"></string>
<string id="OVR-SDK-LibOVR.opcode.CAM_REQUEST.message" value="Request"></string>
<string id="OVR-SDK-LibOVR.opcode.CAM_RECEIVE.message" value="Receive"></string>
<string id="OVR-SDK-LibOVR.event.9.message" value="Received Frame %2"></string>
<string id="OVR-SDK-LibOVR.event.8.message" value="Hmd Descriptor for %4"></string>
<string id="OVR-SDK-LibOVR.event.7.message" value="End distortion rendering for %1 (frame %2)"></string>
<string id="OVR-SDK-LibOVR.event.66.message" value="CompleteFrame"></string>
<string id="OVR-SDK-LibOVR.event.65.message" value="EndFrame"></string>
<string id="OVR-SDK-LibOVR.event.64.message" value="BeginFrame"></string>
<string id="OVR-SDK-LibOVR.event.63.message" value="WaitToBeginFrame"></string>
<string id="OVR-SDK-LibOVR.event.62.message" value="BeginWait"></string>
<string id="OVR-SDK-LibOVR.event.61.message" value="Motion Estimation Cost Statistics"></string>
<string id="OVR-SDK-LibOVR.event.60.message" value="Submisison of notification to distortion"></string>
<string id="OVR-SDK-LibOVR.event.6.message" value="Present distortion for %1 (frame %2)"></string>
<string id="OVR-SDK-LibOVR.event.59.message" value="Notification end frame"></string>
<string id="OVR-SDK-LibOVR.event.58.message" value="Notification begin frame"></string>
<string id="OVR-SDK-LibOVR.event.57.message" value="Time GPU started work (after preemption)"></string>
<string id="OVR-SDK-LibOVR.event.56.message" value="Compositor missed frame (glitched)"></string>
<string id="OVR-SDK-LibOVR.event.55.message" value="App GPU work completed."></string>
<string id="OVR-SDK-LibOVR.event.54.message" value="Flushing ATW work to GPU"></string>
<string id="OVR-SDK-LibOVR.event.53.message" value="End of spinwait"></string>
<string id="OVR-SDK-LibOVR.event.52.message" value="Distortion end to end timing %1s"></string>
<string id="OVR-SDK-LibOVR.event.51.message" value="App EndFrame %1"></string>
<string id="OVR-SDK-LibOVR.event.50.message" value="RenderPacket stage %1 client pid %2"></string>
<string id="OVR-SDK-LibOVR.event.5.message" value="Wait for distortion renderer GPU for %1 (frame %2)"></string>
<string id="OVR-SDK-LibOVR.event.49.message" value="End ATW Composition"></string>
<string id="OVR-SDK-LibOVR.event.48.message" value="Begin ATW Composition"></string>
<string id="OVR-SDK-LibOVR.event.47.message" value="Client Missed Frame %1"></string>
<string id="OVR-SDK-LibOVR.event.46.message" value="Virtual Display Packet %1"></string>
<string id="OVR-SDK-LibOVR.event.45.message" value="Hardware info"></string>
<string id="OVR-SDK-LibOVR.event.44.message" value="End frame app timing"></string>
<string id="OVR-SDK-LibOVR.event.43.message" value="Latency Timing"></string>
<string id="OVR-SDK-LibOVR.event.42.message" value="PosePrediction"></string>
<string id="OVR-SDK-LibOVR.event.41.message" value="Testing only. Should not see in production."></string>
<string id="OVR-SDK-LibOVR.event.40.message" value="Application Disconnected"></string>
<string id="OVR-SDK-LibOVR.event.4.message" value="Begin distortion rendering for %1 (frame %2)"></string>
<string id="OVR-SDK-LibOVR.event.39.message" value="Application Connected"></string>
<string id="OVR-SDK-LibOVR.event.38.message" value="Application compositor focus"></string>
<string id="OVR-SDK-LibOVR.event.37.message" value="VSync Service QPC"></string>
<string id="OVR-SDK-LibOVR.event.36.message" value="PhaseSyncEnd"></string>
<string id="OVR-SDK-LibOVR.event.35.message" value="PhaseSyncBegin"></string>
<string id="OVR-SDK-LibOVR.event.34.message" value="Hmd Display %4 %5"></string>
<string id="OVR-SDK-LibOVR.event.33.message" value="End of Queue Ahead frame delay"></string>
<string id="OVR-SDK-LibOVR.event.32.message" value="Beginning timing delay for QueueAhead"></string>
<string id="OVR-SDK-LibOVR.event.31.message" value="Pose latch GPU readback"></string>
<string id="OVR-SDK-LibOVR.event.30.message" value="Pose latch CPU write"></string>
<string id="OVR-SDK-LibOVR.event.29.message" value="Camera %1 Segment Blobs for %2"></string>
<string id="OVR-SDK-LibOVR.event.28.message" value="Camera %1 Get Frame %2"></string>
<string id="OVR-SDK-LibOVR.event.27.message" value="Camera %1 Pose Sensor Fusion for %2"></string>
<string id="OVR-SDK-LibOVR.event.26.message" value="Camera %1 Pose Reconstruction for %2"></string>
<string id="OVR-SDK-LibOVR.event.25.message" value="Synced Camera %1 Clock"></string>
<string id="OVR-SDK-LibOVR.event.24.message" value="Camera Pose Change %1"></string>
<string id="OVR-SDK-LibOVR.event.23.message" value="End Camera LED Matching %1 %2 %3 %4"></string>
<string id="OVR-SDK-LibOVR.event.22.message" value="Begin Camera LED Matching %1 %2 %3 %4"></string>
<string id="OVR-SDK-LibOVR.event.21.message" value="End Global Image Aquisition %2 %3"></string>
<string id="OVR-SDK-LibOVR.event.20.message" value="Begin Global Image Aquisition %1"></string>
<string id="OVR-SDK-LibOVR.event.2.message" value="Waypoint %1:%2 (frame %3)"></string>
<string id="OVR-SDK-LibOVR.event.19.message" value="Blobs %1"></string>
<string id="OVR-SDK-LibOVR.event.18.message" value="Tracking State"></string>
<string id="OVR-SDK-LibOVR.event.17.message" value="Error: %1"></string>
<string id="OVR-SDK-LibOVR.event.16.message" value="Info: %1"></string>
<string id="OVR-SDK-LibOVR.event.15.message" value="Debug: %1"></string>
<string id="OVR-SDK-LibOVR.event.14.message" value="JSON chunk %1 (%3 of %2) size %5"></string>
<string id="OVR-SDK-LibOVR.event.13.message" value="Camera %1 Skipped Frames %2"></string>
<string id="OVR-SDK-LibOVR.event.12.message" value="Finished Processing Frame %2"></string>
<string id="OVR-SDK-LibOVR.event.11.message" value="Request Frame %2"></string>
<string id="OVR-SDK-LibOVR.event.10.message" value="Begin Processing Frame %2"></string>
<string id="OVR-SDK-LibOVR.event.1.message" value="Return %1:%2 (frame %3)"></string>
<string id="OVR-SDK-LibOVR.event.0.message" value="Call %1:%2 (frame %3)"></string>
<string id="OVR-SDK-LibOVR.channel.ERROR_CHANNEL.message" value="Error"></string>
</stringTable>
</resources>
</localization>
</instrumentationManifest>

View File

@ -0,0 +1,3 @@
LANGUAGE 0x9,0x1
1 11 "LibOVREvents_MSG00001.bin"
1 WEVT_TEMPLATE "LibOVREventsTEMP.BIN"

View File

@ -0,0 +1,55 @@
#Setup
If you want stack walking to work on x64:
> reg add "HKLM\System\CurrentControlSet\Control\Session Manager\Memory Management" -v DisablePagingExecutive -d 0x1 -t REG_DWORD -f
Add USERS Read & Execute privileges to the folder (or one of its parents) containing the LibOVREvents.man file:
> icacls . /grant BUILTIN\Users:(OI)(CI)(RX)
To install or reinstall the ETW manifest after building LibOVR run `install.cmd` as Administrator:
> install
Note: the install script will also attempt to install the manifests for the driver and runtime. Also note that the install
script installs the manifest from the newest version of LibOVR.dll, which might not be the version you are debugging in
Visual Studio (this will only matter if the two versions have specified different events). To be safe make sure your build
is up-to-date.
#Adding trace points
See [./Tracing.h] and the examples in [../OVR_CAPI.cpp].
The following macros can be used to trace call/return and progress through a function:
TraceCall(frameIndex)
TraceReturn(frameIndex)
TraceWaypoint(frameIndex)
Try to place the Call/Return instrumentation as close as possible to the function entry/exit points, and don't forget
to instrument all return paths.
Supply a frame index of 0 if a frame index is not applicable/available.
#Adding new trace events
Use the `ECManGen.exe` utility from the Windows 8.1 SDK to edit the `LibOVREvents.man` manifest.
See [http://msdn.microsoft.com/en-us/library/windows/desktop/dd996930%28v=vs.85%29.aspx]
The `F1` help is also useful.
#Rebuilding the ETW headers and resources
Use the `build.cmd` script to regenerate the `LibOVREvents.h`, `LibOVREvents.rc` and `LibOVREvents*.bin` files.
`clean.cmd` will remove all generated files.
Note that the outputs are checked into the repository so you'll need to `p4 edit` them first.
#Capturing ETW traces
See [../../../Tools/XPerf/README.md]
#Viewing ETW traces with GPUView
See [http://msdn.microsoft.com/en-us/library/windows/desktop/jj585574(v=vs.85).aspx]

View File

@ -0,0 +1,436 @@
/************************************************************************************
PublicHeader: n/a
Filename : Tracing.h
Content : Performance tracing
Created : December 4, 2014
Author : Ed Hutchins
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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_Tracing_h
#define OVR_Tracing_h
//-----------------------------------------------------------------------------------
// ***** OVR_ENABLE_ETW_TRACING definition (XXX default to on for windows builds?)
//
#ifdef OVR_OS_WIN32
#define OVR_ENABLE_ETW_TRACING
#endif
//-----------------------------------------------------------------------------------
// ***** Trace* definitions
//
#ifdef OVR_ENABLE_ETW_TRACING
#define TracingIsEnabled() (OVR_SDK_LibOVREnableBits[0] != 0)
#ifdef TRACE_STATE_CAPTURE_FUNC
// hook in our own state capture callback to record the state of all opened HMDs (supress unused
// parameter warnings with void() casts)
#define MCGEN_PRIVATE_ENABLE_CALLBACK_V2( \
SourceId, ControlCode, Level, MatchAnyKeyword, MatchAllKeywords, FilterData, CallbackContext) \
(void(SourceId), \
void(Level), \
void(MatchAnyKeyword), \
void(MatchAllKeywords), \
void(FilterData), \
void(CallbackContext), \
(((ControlCode) == EVENT_CONTROL_CODE_CAPTURE_STATE) ? (TRACE_STATE_CAPTURE_FUNC) : 0))
#endif
#if !defined(_In_reads_)
// get VS2010 working
#define _In_reads_(x)
#endif
#include "LibOVREvents.h"
// Register/Unregister the OVR_SDK_LibOVR provider with ETW
// (MCGEN_PRIVATE_ENABLE_CALLBACK_V2 hooks in our state capture)
#define TraceInit() \
do { \
ULONG status = EventRegisterOVR_SDK_LibOVR(); \
if (ERROR_SUCCESS != status) { \
LogError("[LibOVR] Failed to register ETW provider (%ul)", status); \
} \
} while (0)
#define TraceFini() EventUnregisterOVR_SDK_LibOVR()
// Trace function call and return for perf, and waypoints for debug
#define TraceCall(frameIndex) EventWriteCall(__FUNCTIONW__, __LINE__, (frameIndex))
#define TraceReturn(frameIndex) EventWriteReturn(__FUNCTIONW__, __LINE__, (frameIndex))
#define TraceWaypoint(frameIndex) EventWriteWaypoint(__FUNCTIONW__, __LINE__, (frameIndex))
// DistortionRenderer events
#define TraceDistortionBegin(id, frameIndex) EventWriteDistortionBegin((id), (frameIndex))
#define TraceDistortionWaitGPU(id, frameIndex) EventWriteDistortionWaitGPU((id), (frameIndex))
#define TraceDistortionPresent(id, frameIndex) EventWriteDistortionPresent((id), (frameIndex))
#define TraceDistortionEnd(id, frameIndex) EventWriteDistortionEnd((id), (frameIndex))
#define TraceDistortionEndToEndTiming(elapsedMs) EventWriteDistortionEndToEndTiming((elapsedMs))
// Tracking Camera events
#define _TraceCameraFrameData(fn, camIdx, img) \
fn((camIdx), \
(uint32_t)(img).FrameNumber, \
(img).HmdFrameNumber, \
(img).ArrivalTime, \
(img).CaptureTime)
#define TraceCameraFrameReceived(img) _TraceCameraFrameData(EventWriteCameraFrameReceived, 0, (img))
#define TraceCameraBeginProcessing(camIdx, img) \
_TraceCameraFrameData(EventWriteCameraBeginProcessing, (camIdx), (img))
#define TraceCameraEndProcessing(camIdx, img) \
_TraceCameraFrameData(EventWriteCameraEndProcessing, (camIdx), (img))
#define TraceCameraFrameRequest(requestNumber, frameCount, lastFrameNumber) \
EventWriteCameraFrameRequest(requestNumber, frameCount, lastFrameNumber)
#define TraceCameraSkippedFrames(camIdx, skippedFrameCount) \
EventWriteCameraSkippedFrames(camIdx, skippedFrameCount)
// Trace the interesting parts of an ovrHmdDesc structure
#define TraceHmdDesc(desc) \
EventWriteHmdDesc( \
(desc).Type, \
(desc).VendorId, \
(desc).ProductId, \
(desc).SerialNumber, \
(desc).FirmwareMajor, \
(desc).FirmwareMinor, \
(desc).AvailableHmdCaps, \
(desc).AvailableTrackingCaps, \
(desc).Resolution.w, \
(desc).Resolution.h)
#define TraceHmdDisplay(dpy) \
EventWriteHmdDisplay( \
(0), \
(0), \
(dpy).Edid.VendorID, \
(dpy).Edid.ModelNumber, \
(dpy).DisplayIdentifier.ToCStr(), \
(dpy).ModelName.ToCStr(), \
(dpy).EdidSerialNumber.ToCStr(), \
(dpy).LogicalResolutionInPixels.w, \
(dpy).LogicalResolutionInPixels.h, \
(dpy).NativeResolutionInPixels.w, \
(dpy).NativeResolutionInPixels.h, \
0, \
0, \
(dpy).DeviceNumber, \
(dpy).Rotation, \
(dpy).ApplicationExclusive)
// Trace part of a JSON string (events have a 64k limit)
#define TraceJSONChunk(Name, TotalChunks, ChunkSequence, TotalSize, ChunkSize, ChunkOffset, Chunk) \
EventWriteJSONChunk(Name, TotalChunks, ChunkSequence, TotalSize, ChunkSize, ChunkOffset, Chunk)
// Trace messages from the public ovr_Trace API and our internal logger
#define TraceLogDebug(message) EventWriteLogDebugMessage(message)
#define TraceLogInfo(message) EventWriteLogInfoMessage(message)
#define TraceLogError(message) EventWriteLogErrorMessage(message)
// Trace an ovrTrackingState
#define TraceTrackingState(ts) \
EventWriteHmdTrackingState( \
(ts).HeadPose.TimeInSeconds, \
&(ts).HeadPose.ThePose.Orientation.x, \
&(ts).HeadPose.ThePose.Position.x, \
&(ts).HeadPose.AngularVelocity.x, \
&(ts).HeadPose.LinearVelocity.x, \
0, \
0, \
(ts).StatusFlags)
#define TraceCameraBlobs(camIdx, frame) \
if (EventEnabledCameraBlobs()) { \
const int max_blobs = 80; \
int count = (frame).Blobs.GetSizeI(); \
double x[max_blobs]; \
double y[max_blobs]; \
int size[max_blobs]; \
if (count > max_blobs) \
count = max_blobs; \
for (int i = 0; i < count; ++i) { \
x[i] = (frame).Blobs[i].DistortedPosition.x; \
y[i] = (frame).Blobs[i].DistortedPosition.y; \
size[i] = (frame).Blobs[i].BlobSize; \
} \
EventWriteCameraBlobs( \
camIdx, \
(uint32_t)(frame).Frame->FrameNumber, \
(frame).Frame->ArrivalTime, \
(frame).Frame->Width, \
(frame).Frame->Height, \
count, \
x, \
y, \
size); \
} else \
((void)0)
#define TracePosePrediction( \
OriginalPose, PredictedPose, PredictionTimeDeltaSeconds, CurrentTimeInSeconds, id) \
EventWritePosePrediction( \
&(OriginalPose).Translation.x, \
&(OriginalPose).Rotation.x, \
&(PredictedPose).Translation.x, \
&(PredictedPose).Rotation.x, \
(PredictionTimeDeltaSeconds), \
(CurrentTimeInSeconds), \
(id))
// Trace PoseLatching CPU pinned memory write
#define TracePoseLatchCPUWrite( \
Sequence, \
Layer, \
MotionSensorTime, \
PredictedScanlineFirst, \
PredictedScanlineLast, \
TimeToScanlineFirst, \
TimeToScanlineLast, \
StartPosition, \
EndPosition, \
StartQuat, \
EndQuat) \
EventWritePoseLatchCPUWrite( \
Sequence, \
Layer, \
MotionSensorTime, \
PredictedScanlineFirst, \
PredictedScanlineLast, \
TimeToScanlineFirst, \
TimeToScanlineLast, \
StartPosition, \
EndPosition, \
StartQuat, \
EndQuat)
// Trace PoseLatching GPU latch
#define TracePoseLatchGPULatchReadback( \
Sequence, \
Layer, \
MotionSensorTime, \
PredictedScanlineFirst, \
PredictedScanlineLast, \
TimeToScanlineFirst, \
TimeToScanlineLast) \
EventWritePoseLatchGPULatchReadback( \
Sequence, \
Layer, \
MotionSensorTime, \
PredictedScanlineFirst, \
PredictedScanlineLast, \
TimeToScanlineFirst, \
TimeToScanlineLast)
#define TraceVSync(VSyncTime, FrameIndex, TWGpuEndTime) \
EventWriteVSync(VSyncTime, FrameIndex, TWGpuEndTime)
#define TraceAppCompositorFocus(Pid) EventWriteAppCompositorFocus(Pid)
#define TraceAppConnect(Pid) EventWriteAppConnect(Pid)
#define TraceAppDisconnect(Pid) EventWriteAppDisconnect(Pid)
#define TraceAppNoOp(Pid) EventWriteAppNoOp(Pid)
#define TraceLatencyTiming(LatencyTiming) \
EventWriteLatencyTiming( \
LatencyTiming.LatencyRenderCpuBegin, \
LatencyTiming.LatencyRenderCpuEnd, \
LatencyTiming.LatencyRenderIMU, \
LatencyTiming.LatencyTimewarpCpu, \
LatencyTiming.LatencyTimewarpLatched, \
LatencyTiming.LatencyTimewarpGpuEnd, \
LatencyTiming.LatencyPostPresent, \
LatencyTiming.ErrorRender, \
LatencyTiming.ErrorTimewarp)
#define TraceEndFrameAppTiming(AppTiming, RenderCount) \
EventWriteEndFrameAppTiming( \
AppTiming.AppFrameIndex, \
AppTiming.AppRenderIMUTime, \
AppTiming.AppVisibleMidpointTime, \
AppTiming.AppGpuRenderDuration, \
AppTiming.AppBeginRenderingTime, \
AppTiming.AppEndRenderingTime, \
AppTiming.QueueAheadSeconds, \
RenderCount)
#define TraceEndFrameOrigAppTiming(AppTiming, RenderCount) \
EventWriteEndFrameOrigAppTiming( \
AppTiming.AppFrameIndex, \
AppTiming.AppRenderIMUTime, \
AppTiming.AppVisibleMidpointTime, \
AppTiming.AppGpuRenderDuration, \
AppTiming.AppBeginRenderingTime, \
AppTiming.AppEndRenderingTime, \
AppTiming.QueueAheadSeconds, \
RenderCount)
// XXX for future reference this could have been done with events with different opcodes and
// identical templates
#define VirtualDisplayPacketTrace_Begin 0
#define VirtualDisplayPacketTrace_End 1
#define VirtualDisplayPacketTrace_Queue 2
#define VirtualDisplayPacketTrace_QueueRelease 3
#define VirtualDisplayPacketTrace_Result 5
#define TraceVirtualDisplayPacket(PacketType, Stage, SubmittingProcessID, ActiveProcessID) \
EventWriteVirtualDisplayPacketTrace(PacketType, Stage, SubmittingProcessID, ActiveProcessID)
#define TraceClientFrameMissed(FrameIndex, ProcessID) \
EventWriteClientFrameMissed(FrameIndex, ProcessID)
#define TraceCompositionBegin(ExpectedCPUStartTimeInSeconds, ActualCPUStartTimeInSeconds) \
EventWriteCompositionBegin(ExpectedCPUStartTimeInSeconds, ActualCPUStartTimeInSeconds)
#define TraceCompositionEnd() EventWriteCompositionEnd()
#define TraceCompositionEndSpinWait() EventWriteCompositionEndSpinWait()
#define TraceCompositionFlushingToGPU() EventWriteCompositionFlushingToGPU()
#define TraceRenderPacket(Stage, ClientPID) EventWriteRenderPacketTrace(Stage, ClientPID)
#define TraceHardwareInfo(data) \
EventWriteHardwareInfo( \
data.RequestedBits, \
data.CollectedBits, \
data.ImuTemp, \
data.StmTemp, \
data.NrfTemp, \
data.VBusVoltage, \
data.IAD, \
data.Proximity, \
data.PanelOnTime, \
data.UseRolling, \
data.HighBrightness, \
data.DP, \
data.SelfRefresh, \
data.Persistence, \
data.LightingOffset, \
data.PixelSettle, \
data.TotalRows)
#define TraceCompositionMissedCompositorFrame() EventWriteCompositionMissedCompositorFrame()
#define TraceCompositionGPUStartTime(Seconds) EventWriteCompositionGPUStartTime(Seconds)
#define TraceNotificationEnd( \
AppFrameIndex, CpuBeginToGpuEndSeconds, CpuBeginSeconds, GpuEndSeconds, SleepMs) \
EventWriteNotificationEnd( \
AppFrameIndex, CpuBeginToGpuEndSeconds, CpuBeginSeconds, GpuEndSeconds, SleepMs)
#define TraceNotificationBegin( \
AppFrameIndex, \
CpuBeginToGpuEndSeconds, \
CompositeTimeSeconds, \
VSyncTimeSeconds, \
CompositeDeltaSeconds, \
VSyncDeltaSeconds) \
EventWriteNotificationBegin( \
AppFrameIndex, \
CpuBeginToGpuEndSeconds, \
CompositeTimeSeconds, \
VSyncTimeSeconds, \
CompositeDeltaSeconds, \
VSyncDeltaSeconds)
#define TraceNotificationCompSubmit(IsEnabled, IsDisabled, FrameIndex) \
EventWriteNotificationCompSubmit(IsEnabled, IsDisabled, FrameIndex)
#define TraceMotionEstimationCostStats(Count, Average, Log2Histogram) \
EventWriteMotionEstimationCostStats(Count, Average, Log2Histogram)
#else // OVR_ENABLE_ETW_TRACING
// Eventually other platforms could support their form of performance tracing
#define TracingIsEnabled() (false)
#define TraceInit() ((void)0)
#define TraceFini() ((void)0)
#define TraceCall(frameIndex) ((void)0)
#define TraceReturn(frameIndex) ((void)0)
#define TraceWaypoint(frameIndex) ((void)0)
#define TraceDistortionBegin(id, frameIndex) ((void)0)
#define TraceDistortionWaitGPU(id, frameIndex) ((void)0)
#define TraceDistortionPresent(id, frameIndex) ((void)0)
#define TraceDistortionEnd(id, frameIndex) ((void)0)
#define TraceDistortionEndToEndTiming(elapsedMs) ((void)0)
#define TraceCameraFrameReceived(cfd) ((void)0)
#define TraceCameraBeginProcessing(camIdx, img) ((void)0)
#define TraceCameraFrameRequest(requestNumber, frameCount, lastFrameNumber) ((void)0)
#define TraceCameraEndProcessing(camIdx, img) ((void)0)
#define TraceCameraSkippedFrames(camIdx, skippedFrameCount) ((void)0)
#define TraceHmdDesc(desc) ((void)0)
#define TraceHmdDisplay(dpy) ((void)0)
#define TraceJSONChunk(Name, TotalChunks, ChunkSequence, TotalSize, ChunkSize, ChunkOffset, Chunk) \
((void)0)
#define TraceLogDebug(message) ((void)0)
#define TraceLogInfo(message) ((void)0)
#define TraceLogError(message) ((void)0)
#define TraceTrackingState(ts) ((void)0)
#define TraceCameraBlobs(camIdx, frame) ((void)0)
#define TracePoseLatchCPUWrite( \
Sequence, \
Layer, \
MotionSensorTime, \
PredictedScanlineFirst, \
PredictedScanlineLast, \
TimeToScanlineFirst, \
TimeToScanlineLast, \
StartPosition, \
EndPosition, \
StartQuat, \
EndQuat) \
((void)0)
#define TracePoseLatchGPULatchReadback( \
Sequence, \
Layer, \
MotionSensorTime, \
PredictedScanlineFirst, \
PredictedScanlineLast, \
TimeToScanlineFirst, \
TimeToScanlineLast) \
((void)0)
#define TraceVSync(VSyncTime, FrameIndex, TWGpuEndTime) ((void)0)
#define TracePosePrediction( \
OriginalPose, PredictedPose, PredictionTimeDeltaSeconds, CurrentTimeInSeconds, id) \
((void)0)
#define TraceAppCompositorFocus(Pid) ((void)0)
#define TraceAppConnect(Pid) ((void)0)
#define TraceAppDisconnect(Pid) ((void)0)
#define TraceAppNoOp(Pid) ((void)0)
#define TraceLatencyTiming(LatencyTiming) ((void)0)
#define TraceEndFrameAppTiming(AppTiming, RenderCount) ((void)0)
#define TraceEndFrameOrigAppTiming(AppTiming, RenderCount) ((void)0)
#define TraceVirtualDisplayPacket(PacketType, Stage, SubmittingProcessID, ActiveProcessID) ((void)0)
#define TraceClientFrameMissed(FrameIndex, ProcessID) ((void)0)
#define TraceCompositionBegin(ExpectedCPUStartTimeInSeconds, ActualCPUStartTimeInSeconds) ((void)0)
#define TraceCompositionEnd() ((void)0)
#define TraceCompositionEndSpinWait() ((void)0)
#define TraceCompositionFlushingToGPU() ((void)0)
#define TraceRenderPacket(Stage, ClientPID) ((void)0)
#define TraceHardwareInfo(data) ((void)0)
#define TraceCompositionMissedCompositorFrame() ((void)0)
#define TraceCompositionGPUStartTime(Seconds) ((void)0)
#define TraceNotificationEnd( \
AppFrameIndex, CpuBeginToGpuEndSeconds, CpuBeginSeconds, GpuEndSeconds, SleepMs) \
((void)0)
#define TraceNotificationBegin( \
AppFrameIndex, \
CpuBeginToGpuEndSeconds, \
CompositeTimeSeconds, \
VSyncTimeSeconds, \
CompositeDeltaSeconds, \
VSyncDeltaSeconds) \
((void)0)
#define TraceNotificationCompSubmit(IsEnabled, IsDisabled, FrameIndex) ((void)0)
#define TraceMotionEstimationCostStats(Count, Average, Log2Histogram) ((void)0)
#endif // OVR_ENABLE_ETW_TRACING
#endif // OVR_Tracing_h

View File

@ -0,0 +1,16 @@
@echo off
REM
REM build.cmd - rebuild generated ETW tracing files from LibOVREvents.man
REM
REM assume mc.exe is in a path relative to xperf.exe
for /f "delims=" %%a in ('where /F Xperf') do set XPERF_PATH=%%~dpa
set OSTYPE=x86
if not "%PROCESSOR_ARCHITECTURE%"=="x86" set OSTYPE=x64
if not "%PROCESSOR_ARCHITEW6432%"=="" set OSTYPE=x64
set MC="%XPERF_PATH%..\bin\%OSTYPE%\mc.exe"
echo Using Manifest Compiler: %MC%
%MC% -v -a -A -n -um .\LibOVREvents.man -h . -z LibOVREvents

View File

@ -0,0 +1,6 @@
@echo off
REM
REM clean.cmd - remove generated ETW tracing files
REM
del LibOVREvents.h LibOVREvents.rc LibOVREvents*.bin *LibOVRRT*.dll

View File

@ -0,0 +1,105 @@
@echo off
setlocal
REM run this script from an Admin shell to set up ETW tracing
set SCRIPTDIR=%~dp0
REM set SDK_MANIFEST_PATH to the SDK install path (e.g. C:\Program Files (x86)\Oculus)
for /f "delims=" %%a in ('reg query "HKLM\SOFTWARE\Wow6432Node\Oculus VR, LLC\Oculus" -v "Base"') do set SDK_INSTALL_PATH=%%a
set SDK_INSTALL_PATH=%SDK_INSTALL_PATH: Base REG_SZ =%
set SDK_MANIFEST_PATH=%SDK_INSTALL_PATH%\oculus-tools\etw
REM Add USERS Read & Execute privileges to the folder
icacls . /grant BUILTIN\Users:(OI)(CI)(RX) >nul
if %errorlevel% equ 0 goto CaclsOk
echo Failed to set cacls, installation may fail
:CaclsOk
for /f "delims=" %%a in ('reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -v "ProductName"') do set PRODUCT_NAME=%%a
set PRODUCT_NAME=%PRODUCT_NAME: =%
set PRODUCT_NAME=%PRODUCT_NAME:ProductNameREG_SZ=%
set PRODUCT_NAME=%PRODUCT_NAME:dows=%
set PRODUCT_NAME=%PRODUCT_NAME:Enterprise=%
set PRODUCT_NAME=%PRODUCT_NAME:Professional=%
set SHORT_PRODUCT_NAME=%PRODUCT_NAME:.1=%
echo Installing %PRODUCT_NAME% manifests:
rem we only support x64 oses these days
set OSTYPE=x64
set OCUSBVID_SYS=%windir%\System32\drivers\ocusbvid111.sys
if "%SHORT_PRODUCT_NAME%"=="Win7" set OCUSBVID_SYS=%windir%\System32\drivers\ocusbvid109.sys
if "%PROCESSOR_ARCHITECTURE%"=="AMD64" goto GotOSTYPE
if "%PROCESSOR_ARCHITEW6432%"=="AMD64" goto GotOSTYPE
echo 32-bit OS not supported
exit /b 1
:GotOSTYPE
REM disable paging on x64 systems if stack walks are desired
if %OSTYPE% neq x64 goto SkipRegCheck
for /f "delims=" %%a in ('reg query "HKLM\System\CurrentControlSet\Control\Session Manager\Memory Management" -v "DisablePagingExecutive"') do set REG_DPA=%%a
if %REG_DPA:~-3% equ 0x1 goto SkipRegCheck
echo ************************
echo DisablePagingExecutive should be set if you want stack tracing to work on %OSTYPE%
echo To disable paging run the following as Administrator:
echo reg add "HKLM\System\CurrentControlSet\Control\Session Manager\Memory Management" -v DisablePagingExecutive -d 0x1 -t REG_DWORD -f
echo and reboot
echo ************************
:SkipRegCheck
set RIFTCAMERADRIVER_DIR=%SCRIPTDIR%..\..\..\RiftPTDriver
set USBVID_EVENTS_MAN=%SDK_MANIFEST_PATH%\OVRUSBVidEvents.man
if exist "%RIFTCAMERADRIVER_DIR%\OCUSBVID\OVRUSBVidEvents.man" set USBVID_EVENTS_MAN=%RIFTCAMERADRIVER_DIR%\OCUSBVID\OVRUSBVidEvents.man
if exist "%SCRIPTDIR%OVRUSBVidEvents.man" set USBVID_EVENTS_MAN=%SCRIPTDIR%OVRUSBVidEvents.man
echo Installing %OCUSBVID_SYS% manifest...
REM uninstall any existing manifest first
wevtutil.exe uninstall-manifest "%USBVID_EVENTS_MAN%"
if %errorlevel% neq 0 echo WARNING: This step failed.
wevtutil.exe install-manifest "%USBVID_EVENTS_MAN%" /rf:"%OCUSBVID_SYS%" /mf:"%OCUSBVID_SYS%"
REM make sure it worked
wevtutil get-publisher OVR-USBVid > nul
if %errorlevel% neq 0 echo WARNING: This step failed.
echo Installed %USBVID_EVENTS_MAN%
set LIBOVR_EVENTS_MAN=%SDK_MANIFEST_PATH%\LibOVREvents.man
if exist "%SCRIPTDIR%LibOVREvents.man" set LIBOVR_EVENTS_MAN=%SCRIPTDIR%LibOVREvents.man
REM get rid of stale dll's
del /f /q "%SCRIPTDIR%LibOVRRT*.dll"
set LIBOVR_PATTERN=LibOVRRT*_1.dll
echo Looking for %LIBOVR_PATTERN% dll's
REM this nightmare command copies the newest version of %LIBOVR_PATTERN% into the current directory without prompting...
forfiles /p:"%SDK_INSTALL_PATH%Support\oculus-runtime" /m:%LIBOVR_PATTERN% /c "cmd /c xcopy /y /f /d @path \"%SCRIPTDIR%.\" >nul" >nul 2>nul
if not exist "%SCRIPTDIR%..\..\..\LibOVR\Lib\Windows" goto NoLibOVRSource
forfiles /s /p:"%SCRIPTDIR%..\..\..\LibOVR\Lib\Windows" /m:%LIBOVR_PATTERN% /c "cmd /c xcopy /y /f /d @path \"%SCRIPTDIR%.\" >nul" >nul 2>nul
:NoLibOVRSource
for /f "delims=" %%a in ('dir /b /o:d "%SCRIPTDIR%%LIBOVR_PATTERN%"') do set LIBOVR_DLL=%%a
echo Installing %LIBOVR_DLL% manifest...
REM uninstall any existing manifest first
wevtutil uninstall-manifest "%LIBOVR_EVENTS_MAN%"
if %errorlevel% neq 0 exit /b 1
REM use absolute paths to the RT .dll, otherwise we risk picking up the wrong (e.g. installed) version from %PATH%
echo wevtutil install-manifest "%LIBOVR_EVENTS_MAN%" /rf:"%SCRIPTDIR%%LIBOVR_DLL%" /mf:"%SCRIPTDIR%%LIBOVR_DLL%"
wevtutil install-manifest "%LIBOVR_EVENTS_MAN%" /rf:"%SCRIPTDIR%%LIBOVR_DLL%" /mf:"%SCRIPTDIR%%LIBOVR_DLL%"
REM note we can't do del /f /q "%SCRIPTDIR%%LIBOVR_PATTERN%" here because the binary has to be present for ETW enumeration to work
REM make sure it worked
wevtutil get-publisher OVR-SDK-LibOVR > nul
if %errorlevel% neq 0 exit /b 1
echo Installed %LIBOVR_EVENTS_MAN%
if not exist "%SCRIPTDIR%..\..\..\Tools" exit /b 0
echo You can now start/stop traces with the GUI:
echo cd %SCRIPTDIR%..\..\..\Tools\TraceScript\ovrtap
echo .\startovrtap.cmd
echo or (command-line):
echo cd %SCRIPTDIR%..\..\..\Tools\Xperf
echo ovrlog

View File

@ -0,0 +1,8 @@
Texture2D Input;
sampler Sampler;
float4 main(float4 pos : SV_POSITION,
float2 tex : TEXCOORD) : SV_TARGET
{
return Input.Sample(Sampler, tex);
}

View File

@ -0,0 +1,14 @@
Texture2DMS<float> Input;
sampler Sampler;
float4 main(float4 pos : SV_POSITION,
float2 tex : TEXCOORD) : SV_TARGET
{
uint width, height, sampleCount;
Input.GetDimensions(width, height, sampleCount);
int2 coord = int2(width * tex.x, height * tex.y);
// This is a terrible resolve and shouldn't be used for anything
// where we care to maintain the result
return Input.Load(coord, sampleCount / 2);
}

View File

@ -0,0 +1,8 @@
void main(float2 pos : POSITION,
float2 tex : TEXCOORD,
out float4 oPos : SV_POSITION,
out float2 oTex : TEXCOORD)
{
oPos = float4(pos, 0, 1);
oTex = tex;
}

View File

@ -0,0 +1,9 @@
Texture2D Input;
sampler Sampler;
float4 main(float4 pos : SV_POSITION,
float2 tex : TEXCOORD) : SV_TARGET
{
float4 temp = Input.Sample(Sampler, tex);
return float4(temp.rrr, 1.0f);
}

View File

@ -0,0 +1,686 @@
/************************************************************************************
Filename : Util_D3D11_Blitter.cpp
Content : D3D11 implementation for blitting, supporting scaling & rotation
Created : February 24, 2015
Authors : Reza Nourai
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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 "Util_D3D11_Blitter.h"
#ifdef OVR_OS_MS
#include "Util_Direct3D.h"
#include "Shaders/Blt_vs.h"
#include "Shaders/Blt_ps.h"
#include "Shaders/Blt_ps_ms2.h"
#include "Shaders/GrayBlt_ps.h"
#include <io.h>
struct MSAAShader {
const BYTE* Data;
SIZE_T Size;
};
static MSAAShader PixelShaderList[] = {{Blt_ps, sizeof(Blt_ps)},
{Blt_ps_ms2, sizeof(Blt_ps_ms2)},
{GrayBlt_ps, sizeof(GrayBlt_ps)}};
namespace OVR {
namespace D3DUtil {
static ovrlog::Channel Log("Blitter");
//-------------------------------------------------------------------------------------
// ***** CAPI::Blitter
Blitter::Blitter(const Ptr<ID3D11Device>& device)
: Device(),
Context1(),
BltState(),
IL(),
VB(),
VS(),
PS(),
Sampler(),
DepthState(),
AlreadyInitialized(false),
SingleChannel(false) {
device->QueryInterface(IID_PPV_ARGS(&Device.GetRawRef()));
OVR_ASSERT(Device);
Device->GetImmediateContext1(&Context1.GetRawRef());
OVR_ASSERT(Context1);
}
Blitter::~Blitter() {}
bool Blitter::Initialize(bool single_channel) {
SingleChannel = single_channel;
if (!Device) {
OVR_ASSERT(false);
return false;
}
OVR_ASSERT(!AlreadyInitialized);
if (AlreadyInitialized) {
return false;
}
OVR_ASSERT(_countof(PixelShaderList) == PixelShaders::ShaderCount);
UINT deviceFlags = Device->GetCreationFlags();
D3D_FEATURE_LEVEL featureLevel = Device->GetFeatureLevel();
// If the device is single threaded, the context state must be too
UINT stateFlags = 0;
if (deviceFlags & D3D11_CREATE_DEVICE_SINGLETHREADED) {
stateFlags |= D3D11_1_CREATE_DEVICE_CONTEXT_STATE_SINGLETHREADED;
}
// TODO: Clean this up with OVR_D3D_CREATE() when we move OVRError to kernel.
OVR_ASSERT(!BltState); // Expected to be null on the way in.
BltState = nullptr; // Prevents a potential leak on the next line.
HRESULT hr = Device->CreateDeviceContextState(
stateFlags,
&featureLevel,
1,
D3D11_SDK_VERSION,
__uuidof(ID3D11Device1),
nullptr,
&BltState.GetRawRef());
OVR_D3D_CHECK_RET_FALSE(hr);
OVR_D3D_TAG_OBJECT(BltState);
OVR_ASSERT(!VS); // Expected to be null on the way in.
VS = nullptr; // Prevents a potential leak on the next line.
hr = Device->CreateVertexShader(Blt_vs, sizeof(Blt_vs), nullptr, &VS.GetRawRef());
OVR_D3D_CHECK_RET_FALSE(hr);
OVR_D3D_TAG_OBJECT(VS);
for (int i = 0; i < ShaderCount; ++i) {
Ptr<ID3D11PixelShader> ps;
hr = Device->CreatePixelShader(
PixelShaderList[i].Data, PixelShaderList[i].Size, nullptr, &ps.GetRawRef());
OVR_D3D_CHECK_RET_FALSE(hr);
OVR_D3D_TAG_OBJECT(ps);
PS[i] = ps;
}
D3D11_INPUT_ELEMENT_DESC elems[2] = {};
elems[0].Format = DXGI_FORMAT_R32G32_FLOAT;
elems[0].SemanticName = "POSITION";
elems[1].AlignedByteOffset = sizeof(float) * 2;
elems[1].Format = DXGI_FORMAT_R32G32_FLOAT;
elems[1].SemanticName = "TEXCOORD";
OVR_ASSERT(!IL); // Expected to be null on the way in.
IL = nullptr; // Prevents a potential leak on the next line.
hr = Device->CreateInputLayout(elems, _countof(elems), Blt_vs, sizeof(Blt_vs), &IL.GetRawRef());
OVR_D3D_CHECK_RET_FALSE(hr);
OVR_D3D_TAG_OBJECT(IL);
// Quad with texcoords designed to rotate the source 90deg clockwise
BltVertex vertices[] = {
{-1, 1, 0, 0}, {1, 1, 1, 0}, {1, -1, 1, 1}, {-1, 1, 0, 0}, {1, -1, 1, 1}, {-1, -1, 0, 1}};
D3D11_BUFFER_DESC bd = {};
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bd.ByteWidth = sizeof(vertices);
bd.StructureByteStride = sizeof(BltVertex);
bd.Usage = D3D11_USAGE_DEFAULT;
D3D11_SUBRESOURCE_DATA init = {};
init.pSysMem = vertices;
init.SysMemPitch = sizeof(vertices);
init.SysMemSlicePitch = init.SysMemPitch;
OVR_ASSERT(!VB); // Expected to be null on the way in.
VB = nullptr; // Prevents a potential leak on the next line.
hr = Device->CreateBuffer(&bd, &init, &VB.GetRawRef());
OVR_D3D_CHECK_RET_FALSE(hr);
OVR_D3D_TAG_OBJECT(VB);
D3D11_SAMPLER_DESC ss = {};
ss.AddressU = ss.AddressV = ss.AddressW = D3D11_TEXTURE_ADDRESS_BORDER;
ss.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
ss.MaxLOD = 15;
OVR_ASSERT(!Sampler); // Expected to be null on the way in.
Sampler = nullptr; // Prevents a potential leak on the next line.
hr = Device->CreateSamplerState(&ss, &Sampler.GetRawRef());
OVR_D3D_CHECK_RET_FALSE(hr);
// OVR_D3D_TAG_OBJECT(); Seems to already have a name.
D3D11_DEPTH_STENCIL_DESC depthDesc{};
OVR_ASSERT(!DepthState); // Expected to be null on the way in.
DepthState = nullptr; // Prevents a potential leak on the next line.
hr = Device->CreateDepthStencilState(&depthDesc, &DepthState.GetRawRef());
OVR_D3D_CHECK_RET_FALSE(hr);
// Swap to our blt state to set it up
Ptr<ID3DDeviceContextState> existingState;
Context1->SwapDeviceContextState(BltState, &existingState.GetRawRef());
Context1->IASetInputLayout(IL);
Context1->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
Context1->VSSetShader(VS, nullptr, 0);
Context1->PSSetSamplers(0, 1, &Sampler.GetRawRef());
Context1->OMSetDepthStencilState(DepthState, 0);
// Swap back
Context1->SwapDeviceContextState(existingState, nullptr);
AlreadyInitialized = true;
return true;
}
bool Blitter::Blt(ID3D11RenderTargetView* dest, ID3D11ShaderResourceView* source) {
Ptr<ID3D11Resource> resource;
dest->GetResource(&resource.GetRawRef());
Ptr<ID3D11Texture2D> texture;
HRESULT hr = resource->QueryInterface(IID_PPV_ARGS(&texture.GetRawRef()));
OVR_D3D_CHECK_RET_FALSE(hr);
D3D11_TEXTURE2D_DESC desc = {};
texture->GetDesc(&desc);
return Blt(dest, source, 0, 0, desc.Width, desc.Height);
}
bool Blitter::Blt(
ID3D11RenderTargetView* dest,
ID3D11ShaderResourceView* source,
uint32_t topLeftX,
uint32_t topLeftY,
uint32_t width,
uint32_t height) {
OVR_ASSERT(AlreadyInitialized);
if (!AlreadyInitialized) {
return false;
}
// Switch to our state
Ptr<ID3DDeviceContextState> existingState;
Context1->SwapDeviceContextState(BltState, &existingState.GetRawRef());
ID3D11RenderTargetView* nullRTVs[] = {nullptr, nullptr, nullptr, nullptr};
ID3D11ShaderResourceView* nullSRVs[] = {nullptr, nullptr, nullptr, nullptr};
Context1->OMSetRenderTargets(_countof(nullRTVs), nullRTVs, nullptr);
Context1->PSSetShaderResources(0, _countof(nullSRVs), nullSRVs);
// Set the mirror as the render target
Context1->OMSetRenderTargets(1, &dest, nullptr);
D3D11_VIEWPORT vp = {};
vp.TopLeftX = (float)topLeftX;
vp.TopLeftY = (float)topLeftY;
vp.Width = (float)width;
vp.Height = (float)height;
vp.MaxDepth = 1.0f;
Context1->RSSetViewports(1, &vp);
Context1->PSSetShaderResources(0, 1, &source);
Ptr<ID3D11Resource> resource;
source->GetResource(&resource.GetRawRef());
Ptr<ID3D11Texture2D> tmpTexture;
HRESULT hr = resource->QueryInterface(IID_PPV_ARGS(&tmpTexture.GetRawRef()));
if (FAILED(hr)) {
OVR_ASSERT(false);
return false;
}
D3D11_TEXTURE2D_DESC texDesc;
tmpTexture->GetDesc(&texDesc);
if (SingleChannel) {
Context1->PSSetShader(PS[PixelShaders::Grayscale], nullptr, 0);
} else if (texDesc.SampleDesc.Count == 1) {
Context1->PSSetShader(PS[PixelShaders::OneMSAA], nullptr, 0);
} else {
Context1->PSSetShader(PS[PixelShaders::TwoOrMoreMSAA], nullptr, 0);
}
static const uint32_t stride = sizeof(BltVertex);
static const uint32_t offset = 0;
Context1->IASetVertexBuffers(0, 1, &VB.GetRawRef(), &stride, &offset);
Context1->Draw(6, 0);
Context1->OMSetRenderTargets(_countof(nullRTVs), nullRTVs, nullptr);
Context1->PSSetShaderResources(0, _countof(nullSRVs), nullSRVs);
// Switch back to app state
Context1->SwapDeviceContextState(existingState, nullptr);
return true;
}
static bool operator!=(const DXGI_SAMPLE_DESC& s1, const DXGI_SAMPLE_DESC& s2) {
return (s1.Count != s2.Count) || (s1.Quality != s2.Quality);
}
static bool operator!=(const D3D11_TEXTURE2D_DESC& d1, const D3D11_TEXTURE2D_DESC& d2) {
return (d1.Width != d2.Width) || (d1.Height != d2.Height) || (d1.MipLevels != d2.MipLevels) ||
(d1.ArraySize != d2.ArraySize) || (d1.Format != d2.Format) ||
(d1.SampleDesc != d2.SampleDesc) || (d1.Usage != d2.Usage) ||
(d1.BindFlags != d2.BindFlags) || (d1.CPUAccessFlags != d2.CPUAccessFlags) ||
(d1.MiscFlags != d2.MiscFlags);
}
D3DTextureWriter::D3DTextureWriter(ID3D11Device* deviceNew)
: device(deviceNew), textureCopy(), pixels() {
memset(&textureCopyDesc, 0, sizeof(textureCopyDesc)); // We use memset instead of ={} because the
// former zeroes filler memory between
// variables, allowing comparison via
// memcmp.
}
void D3DTextureWriter::Shutdown() {
device.Clear();
textureCopy.Clear();
textureCopyDesc = {};
pixels.reset();
}
void D3DTextureWriter::SetDevice(ID3D11Device* deviceNew) {
if (device != deviceNew) {
textureCopy.Clear();
textureCopyDesc = {};
// No need to clear the pixels.
device = deviceNew;
}
}
D3DTextureWriter::Result D3DTextureWriter::SavePixelsToBMP(const wchar_t* path) {
// Create & write the file
ScopedFileHANDLE bmpFile(CreateFileW(
path, FILE_GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr));
if (!bmpFile.IsValid()) {
return Result::FILE_CREATION_FAILURE;
}
const int BytesPerPixel = 4;
const auto PixelsWidth = pixelsDimentions.first;
const auto PixelsHeight = pixelsDimentions.second;
const auto ImageSize = PixelsWidth * PixelsHeight * BytesPerPixel;
BITMAPFILEHEADER bfh{};
bfh.bfType = 0x4d42;
bfh.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + ImageSize;
bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
BITMAPINFOHEADER bih{};
bih.biSize = sizeof(bih);
bih.biBitCount = 8 * (WORD)BytesPerPixel;
bih.biPlanes = 1;
bih.biWidth = PixelsWidth;
bih.biHeight = PixelsHeight;
bih.biSizeImage = ImageSize;
DWORD bytesWritten = 0;
WriteFile(bmpFile.Get(), &bfh, sizeof(bfh), &bytesWritten, nullptr);
WriteFile(bmpFile.Get(), &bih, sizeof(bih), &bytesWritten, nullptr);
size_t offset = PixelsWidth * (PixelsHeight - 1);
for (uint32_t y = 0; y < PixelsHeight; ++y) {
WriteFile(
bmpFile.Get(), pixels.get() + offset, PixelsWidth * BytesPerPixel, &bytesWritten, nullptr);
offset -= PixelsWidth;
}
return Result::SUCCESS;
}
D3DTextureWriter::Result D3DTextureWriter::GrabPixels(
ID3D11Texture2D* texture,
UINT subresource,
bool copyTexture,
const ovrTimewarpProjectionDesc* depthProj,
const float* linearDepthScale) {
if (texture == nullptr)
return Result::NULL_SURFACE;
if (device == nullptr)
return Result::NULL_DEVICE;
Ptr<ID3D11DeviceContext> deviceContext;
device->GetImmediateContext(&deviceContext.GetRawRef()); // Always succeeds.
Ptr<ID3D11Texture2D>
textureSource; // This will point to either the input texture or to our textureCopy.
// Create textureCopy surface to copy back to CPU.
D3D11_TEXTURE2D_DESC textureDesc{};
texture->GetDesc(&textureDesc);
if (copyTexture) {
textureDesc.BindFlags = 0;
textureDesc.Usage = D3D11_USAGE_STAGING;
textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
textureDesc.MiscFlags = 0;
// We try to use our existing cached textureCopy as an intermediate texture, which will often
// be possible because a typical usage of this class is to keep copying the same texture.
if (textureDesc != textureCopyDesc) // If not equal...
{
textureCopyDesc = textureDesc;
textureCopy.Clear();
HRESULT hr = device->CreateTexture2D(&textureCopyDesc, nullptr, &textureCopy.GetRawRef());
if (FAILED(hr)) {
textureCopy.Clear();
textureCopyDesc = {};
return Result::TEXTURE_CREATION_FAILURE;
}
}
// Copy texture to textureCopy.
deviceContext->CopyResource(textureCopy, texture); // Always succeeds.
textureSource = textureCopy;
} else {
textureSource = texture;
}
// At this point we have a valid D3D device, source texture, and intermediate texture.
// We will write the source texture to the intermediate texture and then copy the intermediate
// texture to a memory buffer while converting to BGRA, then write the memory buffer to disk.
// We don't copy the source texture directly to the memory buffer because that will block for some
// time.
// Map textureSource so we can read its pixels.
D3D11_MAPPED_SUBRESOURCE mapped{};
HRESULT hr = deviceContext->Map(textureSource, subresource, D3D11_MAP_READ, 0, &mapped);
if (FAILED(hr)) {
return Result::TEXTURE_MAP_FAILURE;
}
// Now copy textureSource to pixels, converting textureSource's format as-needed to make pixels be
// BGRA.
if (pixelsDimentions.first != textureDesc.Width ||
pixelsDimentions.second != textureDesc.Height) {
pixels.reset(new uint32_t[textureDesc.Width * textureDesc.Height]);
pixelsDimentions = {textureDesc.Width, textureDesc.Height};
}
if (textureDesc.Format == DXGI_FORMAT_R11G11B10_FLOAT) {
// Convert from R11G11B10_FLOAT to R8G8B8
uint32_t inputPitchInPixels = (mapped.RowPitch / 4);
for (uint32_t y = 0; y < textureDesc.Height; ++y) {
for (uint32_t x = 0; x < textureDesc.Width; ++x) {
#pragma warning(disable : 4201) // nonstandard extension used: nameless struct/union
union XMFLOAT3PK {
union {
uint32_t v;
struct {
uint32_t xm : 6;
uint32_t xe : 5;
uint32_t ym : 6;
uint32_t ye : 5;
uint32_t zm : 5;
uint32_t ze : 5;
};
};
};
XMFLOAT3PK packedFloat{((uint32_t*)mapped.pData)[y * inputPitchInPixels + x]};
float rFloat, gFloat, bFloat;
uint32_t* floatRef = (uint32_t*)&rFloat;
*floatRef = ((packedFloat.xe - 15 + 127) << 23U) | (packedFloat.xm << 17);
floatRef = (uint32_t*)&gFloat;
*floatRef = ((packedFloat.ye - 15 + 127) << 23U) | (packedFloat.ym << 17);
floatRef = (uint32_t*)&bFloat;
*floatRef = ((packedFloat.ze - 15 + 127) << 23U) | (packedFloat.zm << 18);
// This is back-asswards but we're converting out of linear so all
// the other images stored directly match in brightness for comparison.
uint32_t r = (uint32_t)(powf(rFloat, 1.0f / 2.2f) * 255.0f);
uint32_t g = (uint32_t)(powf(gFloat, 1.0f / 2.2f) * 255.0f);
uint32_t b = (uint32_t)(powf(bFloat, 1.0f / 2.2f) * 255.0f);
uint32_t bgra = (255 << 24) | (r << 16) | (g << 8) | b;
pixels[(y * textureDesc.Width) + x] = bgra;
}
}
} else if (textureDesc.Format == DXGI_FORMAT_R10G10B10A2_UNORM) {
// Convert from R10G10B10 to R8G8B8
uint32_t inputPitchInPixels = mapped.RowPitch / 4;
for (uint32_t y = 0; y < textureDesc.Height; ++y) {
for (uint32_t x = 0; x < textureDesc.Width; ++x) {
uint32_t wideRGBA = ((uint32_t*)mapped.pData)[(y * inputPitchInPixels) + x];
uint32_t r = (wideRGBA >> 00) & 0x3ff;
uint32_t g = (wideRGBA >> 10) & 0x3ff;
uint32_t b = (wideRGBA >> 20) & 0x3ff;
uint32_t a = (wideRGBA >> 30) & 0x003;
// This is back-asswards but we're converting out of linear so all
// the other images stored directly match in brightness for comparison.
r = (uint32_t)(powf((float)r / 1024.0f, 1.0f / 2.2f) * 255.0f);
g = (uint32_t)(powf((float)g / 1024.0f, 1.0f / 2.2f) * 255.0f);
b = (uint32_t)(powf((float)b / 1024.0f, 1.0f / 2.2f) * 255.0f);
uint32_t bgra = (a << 24) | (r << 16) | (g << 8) | b;
pixels[(y * textureDesc.Width) + x] = bgra;
}
}
} else if (
textureDesc.Format == DXGI_FORMAT_R32_FLOAT ||
textureDesc.Format == DXGI_FORMAT_R32_TYPELESS ||
textureDesc.Format == DXGI_FORMAT_D32_FLOAT ||
textureDesc.Format == DXGI_FORMAT_D24_UNORM_S8_UINT ||
textureDesc.Format == DXGI_FORMAT_R24G8_TYPELESS ||
textureDesc.Format == DXGI_FORMAT_R24G8_TYPELESS) {
if (depthProj == nullptr && linearDepthScale == nullptr) {
OVR_ASSERT(false);
Log.LogError("Tried to save depth image but depth projection is null or invalid");
}
uint32_t inputPitchInPixels = mapped.RowPitch / 4;
for (uint32_t y = 0; y < textureDesc.Height; ++y) {
for (uint32_t x = 0; x < textureDesc.Width; ++x) {
float rValue = 0.0f;
// 32-bit float is just a float
if (textureDesc.Format == DXGI_FORMAT_R32_FLOAT ||
textureDesc.Format == DXGI_FORMAT_R32_TYPELESS ||
textureDesc.Format == DXGI_FORMAT_D32_FLOAT) {
rValue = ((float*)mapped.pData)[y * inputPitchInPixels + x];
} else {
// 24-bit depth is a normalized value
uint32_t temp = ((uint32_t*)mapped.pData)[y * inputPitchInPixels + x];
temp &= 0xffffff;
static const float MAX_24FLOAT = (powf(2.0f, 24.0f) - 1.0f);
rValue = ((float)temp) / (MAX_24FLOAT);
}
// linearDepth = -(Proj.M[2][3]) / ( Proj.M[2][2] - Proj.M[3][2] * nonLinearDepth))
float linearDepth = 0.0f;
if (linearDepthScale) {
linearDepth = rValue * *linearDepthScale;
} else {
linearDepth = -(depthProj->Projection23) /
(depthProj->Projection22 - depthProj->Projection32 * rValue);
}
linearDepth *= -10.0f;
// This is back-asswards but we're converting out of linear so
// all the other images stored directly match in brightness
// for comparision
uint32_t r = (uint32_t)(255.0f - linearDepth);
r = std::min(r, 255u);
uint32_t bgra = 0xff << 24 | r << 16 | r << 8 | r;
pixels[y * textureDesc.Width + x] = bgra;
}
}
} else if (
(textureDesc.Format == DXGI_FORMAT_B8G8R8A8_UNORM) ||
(textureDesc.Format == DXGI_FORMAT_B8G8R8A8_UNORM_SRGB) ||
(textureDesc.Format == DXGI_FORMAT_B8G8R8A8_TYPELESS)) {
if (mapped.RowPitch != textureDesc.Height * sizeof(uint32_t)) {
// Copy BGRA texture line by line
auto src = static_cast<uint8_t*>(mapped.pData);
auto end = src + mapped.RowPitch * textureDesc.Height;
for (auto dst = pixels.get(); src < end; src += mapped.RowPitch, dst += textureDesc.Width) {
memcpy(dst, src, textureDesc.Width * sizeof(uint32_t));
}
} else {
memcpy(pixels.get(), mapped.pData, mapped.RowPitch * textureDesc.Height);
}
} else if (
(textureDesc.Format == DXGI_FORMAT_R8G8B8A8_UNORM) ||
(textureDesc.Format == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB) ||
(textureDesc.Format == DXGI_FORMAT_R8G8B8A8_UINT) ||
(textureDesc.Format == DXGI_FORMAT_R8G8B8A8_TYPELESS)) {
// Convert from RGBA to BGRA.
auto dst = pixels.get();
auto src = static_cast<uint8_t*>(mapped.pData);
auto end = src + mapped.RowPitch * textureDesc.Height;
for (; src < end; src += mapped.RowPitch) {
dst = ConvertRGBA2BGRA(reinterpret_cast<uint32_t*>(src), dst, textureDesc.Width);
}
} else {
// DXGI_FORMAT_NV12, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UINT, possibly others.
uint32_t inputPitchInBytes = mapped.RowPitch;
for (uint32_t y = 0; y < textureDesc.Height; ++y) {
for (uint32_t x = 0; x < textureDesc.Width; ++x) {
uint8_t c = ((uint8_t*)mapped.pData)[(y * inputPitchInBytes) + x];
uint32_t bgra = (0xff << 24) | (c << 16) | (c << 8) | c; // Write as an RGB-based gray.
pixels[(y * textureDesc.Width) + x] = bgra;
}
}
}
deviceContext->Unmap(textureSource, 0); // Always succeeds.
return Result::SUCCESS;
}
uint32_t*
D3DTextureWriter::ConvertRGBA2BGRA(const uint32_t* src, uint32_t* dst, unsigned pixelCount) {
#ifdef OVR_64BIT_POINTERS
auto src2 = reinterpret_cast<const uint64_t*>(src);
auto dst2 = reinterpret_cast<uint64_t*>(dst);
auto lineEnd = src2 + (pixelCount >> 1);
// Convert 2 pixels at a time on 64-bit platforms
while (src2 < lineEnd) {
auto pixel = *src2++;
*dst2++ = (pixel & 0xff00ff00ff00ff00LL) | ((pixel & 0xff000000ffLL) << 16) |
((pixel >> 16) & 0xff000000ffLL);
}
if ((pixelCount & 1) == 0) {
return reinterpret_cast<uint32_t*>(dst2);
}
// Convert remaining odd pixel
auto pixel = *reinterpret_cast<const uint32_t*>(src2);
dst = reinterpret_cast<uint32_t*>(dst2);
*dst++ = (pixel & 0xff00ff00) | ((pixel & 0xff) << 16) | ((pixel >> 16) & 0xff);
#else
auto lineEnd = src + pixelCount;
while (src < lineEnd) {
auto pixel = *src++;
*dst++ = (pixel & 0xff00ff00) | ((pixel & 0xff) << 16) | ((pixel >> 16) & 0xff);
}
#endif
return dst;
}
char* D3DTextureWriter::ConvertBGRA2RGB(const uint32_t* src, char* byteDst, unsigned pixelCount) {
// Convert a stream of 16 byte quadruplets B1G1R1A1|B2R2G2A2|B3G3R3A3|B4G4R4A4
// into 12 byte triplets R1G1B1R2|G2B2R3G3|B3R4G4B4
#ifdef OVR_CPU_SSE
const auto* lineSrc = reinterpret_cast<const __m128i*>(src);
const auto* lineEnd = reinterpret_cast<const __m128i*>(src + (pixelCount & ~3));
auto shuffle = _mm_set_epi8(-1, -1, -1, -1, 12, 13, 14, 8, 9, 10, 4, 5, 6, 0, 1, 2);
auto storeMask = _mm_set_epi8(0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1);
while (lineSrc < lineEnd) {
__m128i invec = _mm_lddqu_si128(lineSrc++);
invec = _mm_shuffle_epi8(invec, shuffle);
_mm_maskmoveu_si128(invec, storeMask, byteDst);
byteDst += 12;
}
#else
auto dst = reinterpret_cast<uint32_t*>(byteDst);
auto quadEnd = reinterpret_cast<uint32_t*>(byteDst + 3 * (pixelCount & ~3));
while (dst < quadEnd) {
auto pixel1 = *src++;
auto pixel2 = *src++;
auto pixel3 = *src++;
auto pixel4 = *src++;
*dst++ = ((pixel1 >> 16) & 0xff) | (pixel1 & 0x0000ff00) | ((pixel1 << 16) & 0x00ff0000) |
((pixel2 << 8) & 0xff000000);
*dst++ = ((pixel2 >> 8) & 0xff) | ((pixel2 << 8) & 0x0000ff00) | (pixel3 & 0x00ff0000) |
((pixel3 << 16) & 0xff000000);
*dst++ = (pixel3 & 0xff) | ((pixel4 >> 8) & 0x0000ff00) | ((pixel4 << 8) & 0x00ff0000) |
((pixel4 << 24) & 0xff000000);
}
byteDst = reinterpret_cast<char*>(dst);
#endif
// Convert the reminder
for (UINT x = (pixelCount & ~3); x < pixelCount; ++x) {
auto pixel = *src++;
*byteDst++ = (pixel >> 16) & 0xff;
*byteDst++ = (pixel >> 8) & 0xff;
*byteDst++ = pixel & 0xff;
}
return byteDst;
}
D3DTextureWriter::Result D3DTextureWriter::SaveTexture(
ID3D11Texture2D* texture,
UINT subresource,
bool copyTexture,
const wchar_t* path,
const ovrTimewarpProjectionDesc* depthProj,
const float* linearDepthScale) {
auto rc = GrabPixels(texture, subresource, copyTexture, depthProj, linearDepthScale);
if (rc != Result::SUCCESS) {
return rc;
}
return SavePixelsToBMP(path);
}
} // namespace D3DUtil
} // namespace OVR
#endif // OVR_OS_MS

View File

@ -0,0 +1,144 @@
/************************************************************************************
Filename : Util_D3D11_Blitter.h
Content : D3D11 implementation for blitting, supporting scaling
Created : February 24, 2015
Authors : Reza Nourai
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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_Util_D3D11_Blitter_h
#define OVR_Util_D3D11_Blitter_h
#include "Kernel/OVR_RefCount.h"
#include "Kernel/OVR_Log.h"
#ifdef OVR_OS_MS
#include <d3d11_1.h>
#include "OVR_CAPI.h"
namespace OVR {
namespace D3DUtil {
//-------------------------------------------------------------------------------------
// ***** CAPI::Blitter
// D3D11 implementation of blitter
class Blitter : public RefCountBase<Blitter> {
public:
Blitter(const Ptr<ID3D11Device>& device);
~Blitter();
bool Initialize(bool single_channel = false);
bool Blt(ID3D11RenderTargetView* dest, ID3D11ShaderResourceView* source);
bool Blt(
ID3D11RenderTargetView* dest,
ID3D11ShaderResourceView* source,
uint32_t topLeftX,
uint32_t topLeftY,
uint32_t width,
uint32_t height);
private:
enum PixelShaders { OneMSAA = 0, TwoOrMoreMSAA = 1, Grayscale = 2, ShaderCount = 3 };
Ptr<ID3D11Device1> Device;
Ptr<ID3D11DeviceContext1> Context1;
Ptr<ID3DDeviceContextState> BltState;
Ptr<ID3D11InputLayout> IL;
Ptr<ID3D11Buffer> VB;
Ptr<ID3D11VertexShader> VS;
std::array<Ptr<ID3D11PixelShader>, PixelShaders::ShaderCount> PS;
Ptr<ID3D11SamplerState> Sampler;
Ptr<ID3D11DepthStencilState> DepthState;
bool AlreadyInitialized;
bool SingleChannel;
struct BltVertex {
float x, y;
float u, v;
};
};
// Writes a D3D texture to a file path.
class D3DTextureWriter {
public:
D3DTextureWriter(ID3D11Device* deviceNew = nullptr);
void Shutdown();
void SetDevice(ID3D11Device* deviceNew);
enum class Result {
SUCCESS,
NULL_SURFACE,
NULL_DEVICE,
TEXTURE_CREATION_FAILURE,
TEXTURE_MAP_FAILURE,
FILE_CREATION_FAILURE,
};
// Beware that if the texture being saved is one that is a render target then the rendering to
// that
// texture will need to be complete for this to work properly. You may need to flush the device or
// command buffer to achieve this.
// If copyTexture is true then we make a copy of the input texture before writing it to disk.
// If texture is mapped for writing then you may want to use copyTexture because reading from it
// will be slow.
Result GrabPixels(
ID3D11Texture2D* texture,
UINT subresource,
bool copyTexture,
const ovrTimewarpProjectionDesc* depthProj,
const float* linearDepthScale);
Result SavePixelsToBMP(const wchar_t* path);
// Simple composition of GrabPixels() and SavePixelsToBMP() functions
Result SaveTexture(
ID3D11Texture2D* texture,
UINT subresource,
bool copyTexture,
const wchar_t* path,
const ovrTimewarpProjectionDesc* depthProj,
const float* linearDepthScale);
static uint32_t* ConvertRGBA2BGRA(const uint32_t* src, uint32_t* dst, unsigned pixelCount);
static char* ConvertBGRA2RGB(const uint32_t* src, char* dst, unsigned pixelCount);
protected:
Ptr<ID3D11Device> device; // D3D11Device we use. Must match the textures we work with.
Ptr<ID3D11Texture2D> textureCopy; // The last texture we used. Cached for future use.
D3D11_TEXTURE2D_DESC textureCopyDesc; // This is a D3D11_TEXTURE2D_DESC. The description of
// textureCopy, which allows us to know if we need to free
// it and reallocate it anew.
std::pair<UINT, UINT> pixelsDimentions = {0, 0};
std::unique_ptr<uint32_t[]> pixels; // Windows RGB .bmp files are actually in BGRA or BGR format.
};
} // namespace D3DUtil
} // namespace OVR
#endif // OVR_OS_MS
#endif // OVR_Util_D3D11_Blitter_h

View File

@ -0,0 +1,93 @@
/************************************************************************************
Filename : Util_Direct3D.cpp
Content : Shared code for Direct3D
Created : Oct 14, 2014
Authors : Chris Taylor
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus VR Rift SDK License Version 3.3 (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.3
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 "Util_Direct3D.h"
#include "Kernel/OVR_Log.h"
namespace OVR {
namespace D3DUtil {
bool VerifyHRESULT(const char* file, int line, HRESULT hr) {
if (FAILED(hr)) {
LogError(
"D3D function returned fail HRESULT at %s on line %d : %s",
file,
line,
D3DUtil::GetWindowsErrorString(hr).ToCStr());
OVR_ASSERT(false);
return false;
}
return true;
}
String GetWindowsErrorString(HRESULT hr) {
wchar_t* errorText = nullptr;
DWORD slen = FormatMessageW(
// use system message tables to retrieve error text
FORMAT_MESSAGE_FROM_SYSTEM
// allocate buffer on local heap for error text
| FORMAT_MESSAGE_ALLOCATE_BUFFER
// Important! will fail otherwise, since we're not
// (and CANNOT) pass insertion parameters
| FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, // unused with FORMAT_MESSAGE_FROM_SYSTEM
hr,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR)&errorText, // output, allocated via LocalAlloc (free with LocalFree)
256, // minimum size for output buffer
nullptr); // arguments - see note
char formatStr[512];
snprintf(formatStr, sizeof(formatStr), "[Code=%lx = %ld]", hr, hr);
String retStr = formatStr;
if (slen > 0 && errorText) {
retStr += " ";
retStr += errorText;
// release memory allocated by FormatMessage()
LocalFree(errorText);
}
return retStr;
}
void LogD3DCompileError(HRESULT hr, ID3DBlob* blob) {
if (FAILED(hr)) {
char* errStr = (char*)blob->GetBufferPointer();
SIZE_T len = blob->GetBufferSize();
if (errStr && len > 0) {
LogError("Error compiling shader: %s", errStr);
}
}
}
} // namespace D3DUtil
} // namespace OVR

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