forked from LeenkxTeam/LNXRNT
Add files
This commit is contained in:
245
Kinc/Backends/System/Windows/Libraries/OculusSDK/LICENSE.txt
Normal file
245
Kinc/Backends/System/Windows/Libraries/OculusSDK/LICENSE.txt
Normal 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 |
@ -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
@ -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
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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, ®ion, 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
|
||||
@ -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 */
|
||||
@ -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
|
||||
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
@ -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));
|
||||
}
|
||||
}
|
||||
@ -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
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
@ -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
|
||||
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
File diff suppressed because it is too large
Load Diff
@ -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_ */
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -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>
|
||||
@ -0,0 +1,3 @@
|
||||
LANGUAGE 0x9,0x1
|
||||
1 11 "LibOVREvents_MSG00001.bin"
|
||||
1 WEVT_TEMPLATE "LibOVREventsTEMP.BIN"
|
||||
Binary file not shown.
Binary file not shown.
@ -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]
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -0,0 +1,8 @@
|
||||
Texture2D Input;
|
||||
sampler Sampler;
|
||||
|
||||
float4 main(float4 pos : SV_POSITION,
|
||||
float2 tex : TEXCOORD) : SV_TARGET
|
||||
{
|
||||
return Input.Sample(Sampler, tex);
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
Reference in New Issue
Block a user