1
1

Compare commits

...

163 Commits

Author SHA1 Message Date
Julian Eisel
1fcc5adc60 Merge branch 'soc-2019-openxr' into temp-vr-draw-thread 2019-08-07 13:31:17 +02:00
Julian Eisel
5350015d51 Fix dark VR rendering on Windows Mixed Reality by appyling SRGB OETF
Discussed this in length with @sobotka, and it seems WMR has an utterly
broken pixel color pipeline. So we apply a SRGB OETF for this specific
runtime to compensate.
2019-08-07 11:52:30 +02:00
Julian Eisel
3483aa57b3 Allow querying OpenXR runtime ID
Useful in case special treatment is needed for certain runtimes.
Currently only WMR gets its ID assigned correctly, others are TODO.
2019-08-07 03:22:33 +02:00
Julian Eisel
44a220f721 Merge branch 'master' into soc-2019-openxr 2019-08-07 02:20:22 +02:00
Julian Eisel
fa7643bc7b Fix mistake in earlier commit, removed required call
Turns out I my compile and launch directories diverged, so I was running
an outdated executable.
2019-08-06 01:39:31 +02:00
Julian Eisel
02aca1bfb7 Merge branch 'temp-concurrent-viewport-theme' into temp-vr-draw-thread 2019-08-06 00:41:49 +02:00
Julian Eisel
43d4ac5db6 Cleanup: Remove unnecessary call & var 2019-08-05 19:02:08 +02:00
Julian Eisel
834b0b8262 Share code of new functions in resources.c 2019-08-05 18:38:23 +02:00
Julian Eisel
d20393c8bd Cover all UI_GetTheme calls in draw manager
Previous commit wasn't nearly covering all of them.
2019-08-05 18:25:04 +02:00
Julian Eisel
6a46860220 Merge branch 'temp-concurrent-viewport-theme' into temp-vr-draw-thread 2019-08-05 16:38:47 +02:00
Julian Eisel
34506a1276 Merge branch 'soc-2019-openxr' into temp-vr-draw-thread 2019-08-05 12:53:18 +02:00
Julian Eisel
5274c5cce6 Merge branch 'master' into soc-2019-openxr 2019-08-05 12:52:57 +02:00
Julian Eisel
eee5ba5cc3 Merge branch 'master' into temp-concurrent-viewport-theme 2019-08-05 12:50:15 +02:00
Julian Eisel
f5c023dfd7 Avoid change to global theme state in draw-manager
Changing the global state would obviously cause issues for async
execution. This is the simplest solution for a simple problem.

Reviewers: fclem, brecht

Differential Revision: https://developer.blender.org/D5413
2019-08-05 11:55:29 +02:00
Julian Eisel
06e0ea0c16 Remove unnecessary calls 2019-08-03 01:51:08 +02:00
Julian Eisel
41ed61b273 Merge branch 'temp-gpu-context-matrix' into temp-vr-draw-thread
Solves drawing issues while drawing the VR session.
2019-08-03 00:50:55 +02:00
Julian Eisel
88b79cacb2 Merge branch 'soc-2019-openxr' into temp-vr-draw-thread 2019-08-02 23:37:31 +02:00
Julian Eisel
0d70afed19 Merge branch 'master' into soc-2019-openxr 2019-08-02 23:35:40 +02:00
Julian Eisel
c7653fad67 Manage GPU_matrix stacks per GPUContext
Previous global GPU_matrix stacks weren't safe for access from multiple
threads. With this, GPU_matrix stacks are concurrent in combination
with GPUContext.
Needed for VR session drawing on a separate thread.

Reviewers: fclem, brecht

Differential Revision: https://developer.blender.org/D5405
2019-08-02 18:05:40 +02:00
Julian Eisel
7a711e133c Keep a single OpenGL/GPU context alive on the drawing thread
Avoids expensive context switches.
2019-08-02 13:45:11 +02:00
Julian Eisel
7922bd26a2 Fix objects not visible
Object.base_flag was not updated correctly so objects were hidden.
2019-08-02 02:24:36 +02:00
Julian Eisel
9b6ce439bb Fix race condition in state changes + related cleanup + add assert 2019-08-02 00:38:22 +02:00
Julian Eisel
11975d5d95 Merge branch 'soc-2019-openxr' into temp-vr-draw-thread 2019-08-01 23:23:59 +02:00
Julian Eisel
03b09dbe32 Fix compile error after merge and warning 2019-08-01 21:53:57 +02:00
Julian Eisel
f04a5ad1e4 Merge branch 'master' into soc-2019-openxr 2019-08-01 21:27:08 +02:00
Julian Eisel
ab1455e972 Fix error in OpenGL version check for OpenXR 1.0 2019-08-01 01:56:35 +02:00
Julian Eisel
b94af38c31 Fix compile error on GCC 2019-08-01 01:39:27 +02:00
Julian Eisel
40db778de3 Add sources for OpenXR core API validation layer
Had to do quite some changes to CMakeLists.txt from the SDK this time.
2019-08-01 00:28:16 +02:00
Julian Eisel
22966f4d35 Address changes in OpenXR 1.0 to get rendering to work again 2019-07-31 02:19:35 +02:00
Julian Eisel
e8f66ff060 Update OpenXR to version 1.0
Only tested on Windows.

Updates loader sources from the OpenXR SDK to latest 1.0 SDK and updates
requiremed version to 1.0. The compile time generation of files is a
thing of the past now (although you can still force it).
1.0 got released yesterday. Only one line needed fixing in our OpenXR
code to get it to compile. Rendering is black though.

For now I tried to keep edits to CMakeList.txt files minimal. So now
there are OpenXR CMake options exposed (with bad names), CMake prints,
etc.
2019-07-31 02:18:28 +02:00
Julian Eisel
8d3f4a1df3 Merge branch 'soc-2019-openxr' into temp-vr-draw-thread 2019-07-30 22:26:37 +02:00
Julian Eisel
9ac33e56a1 Merge branch 'master' into soc-2019-openxr 2019-07-30 22:19:41 +02:00
Julian Eisel
b961b3f0c9 Initial, mostly broken VR viewport drawing on own thread
Spawns a separate thread to do any VR session drawing on. There are
four reasons for this:
* VR session doesn't need the usual main loop procedure for drawing.
  With the drawing on a separate thread, the session doesn't have the
  overhead of the other parts of the main loop.
* OpenXR performs thread blocking operations to synchronize rendering
  with the device refresh rate. This would conflict with the rest of
  Blender, causing lags on event handling, drawing, etc.
* With an own thread, we can keep a single OpenGL context alive,
  avoiding expensive context switches. This should improve performance
  significantly.
* With a bit more work, viewports can draw entirely in parallel (at
  least the CPU side of it), pushing performance even further.

Drawing the viewport on a separate thread shouldn't be much of an
issue. The draw-manager is already thread safe (mutex guarded). Not much
seems needed to get it entirely concurrent, allowing viewport drawing
from separate threads without any synchronization (i.e. only one at a
time).
I had to create an own depsgraph for the VR draw thread so the viewport
gets its own buffers for its own OpenGL context.

Right now this is utterly broken, but at least an empty viewport is
drawn for the VR session in a separate thread. Issues are:
* VR viewport doesn't draw any objects, just background + overlays
  (apparently the VR session depsgraph isn't built correctly).
* OpenGL context of the main thread seems messed up when drawing the VR
  view. Result is drawing glitches and eventually Blender crashes.
* Exiting the VR session causes failed assertions and memory leaks.
2019-07-30 13:28:20 +02:00
Julian Eisel
091cc94379 Use fixed lighting, don't make it rotate with view rotation 2019-07-24 16:41:46 +02:00
Julian Eisel
fc31be5ab0 Fix broken VR viewport rotation and movement 2019-07-24 02:52:03 +02:00
Julian Eisel
aff49f607a Use draw manager offscreen context for the VR session
This way we avoid the big overhead of context switches. Makes frames
render about twice as fast here. For heavy Spring scenes I'm getting
around 20 FPS here, classroom scene is at 50 FPS.
This is great given that drawing itself still isn't optimized for dual
eye rendering.
2019-07-24 01:39:04 +02:00
Julian Eisel
57b77cd193 Print 8 Frame average FPS for --debug-xr-time
Much more useful than a per frame FPS estimation. 8 frames are used for
the Blender viewport FPS stats too.
Refactored drawing data storage a bit.
2019-07-23 19:16:39 +02:00
Julian Eisel
d58eb8d29d Add --debug-xr-time command line option for VR frame time info prints
Outputs frame render time in milliseconds and FPS this time would add up
to. We could average times so FPS is a bit more stable, but the
precision of un-averaged results may be helpful too.
2019-07-23 02:06:08 +02:00
Julian Eisel
a4310ba85f Merge branch 'master' into soc-2019-openxr 2019-07-23 00:18:08 +02:00
Julian Eisel
bd42740ef1 Silence GCC warning 2019-07-21 13:15:00 +02:00
Julian Eisel
679a4c34fc Fix compile error with bundled OpenXR sources 2019-07-21 03:18:02 +02:00
Julian Eisel
55362436d9 Fix troubling memory leak in offscreen viewport drawing
I'm not really sure why the leak happened - draw manager kept allocating
certain buffers - but I figured I could avoid it by not recreating
GPU_offscreen/GPU_viewport on every redraw.
This should also improve performance a bit.
2019-07-21 01:10:18 +02:00
Julian Eisel
c1d164070b Pure OpenGL backend works now, let it take priority over DirectX 2019-07-20 19:34:50 +02:00
Julian Eisel
3a4034a741 Make OpenGL-only session backend work
Previously, only DirectX HMD rendering would work (and still takes
priority).
2019-07-20 19:33:11 +02:00
Julian Eisel
a0be113d2e Fix DirectX context not freed on session exit
Also rename XrSurfaceData to wmXrSurfaceData
2019-07-17 15:18:27 +02:00
Julian Eisel
151fb129e7 Fix for previous commit, accidental call to xrDestroySwapchain 2019-07-17 14:51:21 +02:00
Julian Eisel
165c5a5259 Fix possible OpenXR swapchain leak by using new unique_oxr_ptr 2019-07-17 14:05:06 +02:00
Julian Eisel
74fc1db25b Add helper class to RAII manage OpenXR handles
Adds generic unique_oxr_ptr to wrap xrCreate and xrDestroy functions of
OpenXR handles into a unique_ptr like RAII interface.

While for most cases, OpenXR resources can be freed by their owning
object, sometimes errors may occor before final ownership is established.
E.g. swapchain ownership is only transfered to the session object once
its swapchain-images are created - which may fail. With this RAII
wrapper, the swapchain would be freed on error (as this triggers stack
unwinding through an exception), no matter who holds ownership to it
currently.
There are other solutions to this problem, e.g. by establishing final
ownership right after/upon creation, or by explicit freeing in case an
error is spotted; it's too easy to make mistakes here though. Plus, we
may want to experiment with using this API for all OpenXR resources, to
entirely avoid the possibility of them leaking.
2019-07-17 13:35:14 +02:00
Julian Eisel
03ff2a8dd5 Fix compile error with USE_FORCE_WINDOWED_SESSION enabled
At least get it to compile, this is still kinda broken though.
2019-07-17 11:29:34 +02:00
d99d15f48d Add helper batch file for testing on oculus rift. 2019-07-16 16:41:44 -06:00
Julian Eisel
6a998833cd Temporarily let DirectX take priority over OpenGL
OpenGL doesn't work yet. Shouldn't be too difficult to get working, but
I don't have a working OpenXR runtime with OpenGL support to test here.
2019-07-16 21:48:29 +02:00
Julian Eisel
fca4826c7f Merge branch 'master' into soc-2019-openxr 2019-07-16 21:09:30 +02:00
Julian Eisel
b0845fc133 Fix some issues, improve error message
Fixes:
* Destruct surface when destroying session on error. Fixes null pointer
  dereference when trying to draw the surface on next redraw.
* Fix trying to enable same extensions/API-layers multiple times due to
  static array usage not being cleared after error.
* Null pointer dereference with OpenGL drawing
2019-07-13 16:22:26 +02:00
Julian Eisel
70cf8bd9c6 Fix crash on OpenXR error before context is created fully 2019-07-13 01:19:58 +02:00
Julian Eisel
3a2e459f58 Show useful error reports in case of errors.
E.g. with an active OpenXR runtime installed, but no HMD plugged in,
Blender will now show: "Failed to get device information. Is a device
plugged in?".
In case of such errors, the VR-session will be cleanly exited, with
no side effects to the rest of Blender (at least if there are no bugs).

The GHOST_Xr API now allows setting a custom error handling callback
which may cleanly destroy all GHOST_Xr data.
2019-07-12 19:51:38 +02:00
Julian Eisel
330f062099 Safe and informative GHOST_Xr error handling
This wraps all functions that could fail into some proper (although
unfinished) error handling.

These were the requirements for the error handling strategy:
* If an error occurs, cleanly exit the VR session (or the context if the
  error happend during its set up), causing no resource leaks or side
  effects to the rest of Blender.
* Show a *useful* error message to the user.
* Don't impair readability of code too much with error handling.

After some back and forth I decided Ghost internal exceptions are the
best way to go about this. I get exceptions are a controversial feature,
IMHO that's because most people use them 'wrong' however. Here's the
rationale:
* Most alternatives require early exiting functions. This early exiting
  has to be 'bubbled up' the call stack to the point that performs error
  handling. So the code gets really impaired by error checking. Tried
  this first and wasn't happy with it at all. Even if error handling is
  wrapped into macros.
* All GHOST_Xr resources are managed via RAII. So stack unwinding will
  cause them to be released cleanly whenever an exception is thrown.
* GHOST_Xr has a clear boundary (the Ghost C-API) with only a handful of
  public functions. That is the only place we need to have try-catch
  blocks at.
  (Generally, try-catch blocks at kinda random places are a bad code
  smell IMHO. Module boundaries are a valid place to put them.)
* Exceptions allow us to pass multiple bits of error information through
  mulitple layers of the call stack. This information can also be made
  specific with a useful error message.
  As of now, they conain a user error message, the OpenXR error code (if
  any), as well as the exact source code location the error was caught
  at.

So if an error is caught inside GHOST_Xr code, an exception is thrown
with specific and hopefully useful information in it. In the Ghost C-API,
these exceptions are caught and passed on to a custom error handling
callback. This callback will be defined by the Blender window-manager
and output the error information via a usual user report popup (not done
yet). It can also ensure the entire session is shut down.

Note that the majority of errors OpenXR can return are for invalid API
usage. Assuming the API usage is valid though, most error messages
should never reach users and can be left a bit more vague. Maybe we can
add something like "This is probably a bug and should be reported" to
those.
2019-07-12 14:40:50 +02:00
Julian Eisel
09872df1c7 Check runtime DirectX requirements for graphics binding too 2019-07-11 21:05:13 +02:00
Julian Eisel
67d6399da6 Check runtime OpenGL requirements prior to creating graphics binding
DirectX will need these checks too.
Also fix warnings due to wrong printf formatting.
2019-07-11 20:36:54 +02:00
Julian Eisel
c29724912b Merge branch 'master' into soc-2019-openxr 2019-07-11 20:28:19 +02:00
Julian Eisel
99560d9657 Disable debug extension on Windows
Unfortunately, enabling XR_EXT_debug_utils crashes instance creation
with the Windows Mixed Reality runtime. Maybe I'm doing something wrong,
for now, just disable it.
2019-07-11 16:44:51 +02:00
Julian Eisel
b8a7b87873 General minor fixes and cleanup
* Initialize all class member variables
* Add version to runtime name printing
* Separate functionality code from debug prints
* Improve code structure using Doxygen groups
* Make accessors const functions
* Add (Doxygen) comments
* Naming
* Reorder functions
2019-07-11 16:36:04 +02:00
Julian Eisel
c9f6c1a054 Fix wrong return value causing OpenXR initialization to fail 2019-07-11 00:51:00 +02:00
Julian Eisel
dd0fcb50b4 Fix compile errors on windows and with bundled OpenXR SDK sources 2019-07-11 00:50:10 +02:00
Julian Eisel
c1e9cf00ac Refactor GHOST_XrContext into class + interface
Makes GHOST_Xr much more consistent with the rest of GHOST. Basically I
added a GHOST_IXrContext interface which can be called by the GHOST
C-API. The internal GHOST_XrContext class implements this.
Outside of GHOST only the opaque GHOST_XrContextHandle is accessible.

Kept GHOST_Xr_intern.h and GHOST_Xr.cpp for now. I'll probably remove
them soon. There's not much reason for both of them to be there.
2019-07-10 23:53:07 +02:00
Julian Eisel
84d609f67b Use OpenXR extension for extra debug messages in debug mode
Enables (or tries to) the XR_EXT_debug_utils extension which allows
setting a custom callback for additional debug prints. Note that I
haven't been able to test this really, as the Monado runtime appears to
not have this fully implemented (had to force sending a custom message
to find that out...). Will test with the Windows MR runtime in a bit. We
can also improve message quality then (it can print the exact function
name the message was sent from, print additional custom labels which
could indicate session state, etc.).
2019-07-10 15:08:52 +02:00
Julian Eisel
86178548d5 Only try to enable OpenXR API validation layer in debug mode 2019-07-10 15:08:10 +02:00
Julian Eisel
d711540a85 Cleanup: Rename XR_DEBUG_BEGIN -> XR_DEBUG_ONLY_BEGIN
Of course also renames XR_DEBUG_END accordingly.
2019-07-10 15:06:08 +02:00
Julian Eisel
6e3158cb00 Only print info messages with --debug-xr enabled 2019-07-09 17:49:54 +02:00
Julian Eisel
b216690505 Add --debug-xr commandline arg and pass on to GHOST XR contexts
Doesn't do anything yet.
2019-07-09 17:20:01 +02:00
Julian Eisel
b98896ddd9 Preparations to allow enabling OpenXR API validation layer
For this to work two environment variables have to be set:
XR_API_LAYER_PATH and LD_LIBRARY_PATH, both have to point to the API
layers built by the OpenXR SDK. It also requires you compile Blender
linked to your own SDK build (OPENXR_USE_BUNDLED_SRC disabled).
Further changes will make this set up unnecessary, so validation layers
can be enabled via some flag.
2019-07-09 16:45:21 +02:00
Julian Eisel
a05104d61f Fix warnings and compile error on GCC 2019-07-09 11:28:17 +02:00
Julian Eisel
7fe1cc8d24 Enable grid floor in VR session
Helps quite a bit orientating.
2019-07-09 10:56:37 +02:00
Julian Eisel
70e84a2c20 Merge branch 'master' into soc-2019-openxr 2019-07-08 14:18:08 +02:00
Julian Eisel
084a33ca94 Use base pose from Blender camera
I was trying to set the camera pose as OpenXR reference pose. But then I
got really strange poses for drawing back from OpenXR. Couldn't figure
out a way to solve this.
Now we just apply OpenXR's draw pose to the Blender camera pose. If we
later want to support moving around in the scene (e.g. via teleporting),
that has to be changed.

Also uses flipped drawing for DirectX surface to correct DirectX upside
down drawing (compared to OpenGL).
2019-07-08 14:13:14 +02:00
Julian Eisel
37f619aea3 Don't recreate reference local space on each redraw
Set this up on session start.
2019-07-07 13:07:51 +02:00
Julian Eisel
6904ab10f4 Add GHOST_XrSession class for cleaner & safer session management
Session code and data structures are now localized. But also, this
enables sessions to use deterministic destruction to end itself cleanly.
So whenever an error occurs, we can use stack unwinding which will cause
graceful ending of the session.
2019-07-07 12:45:37 +02:00
Julian Eisel
146ef0dd1e Properly end VR sessions fixing crash on next session start
Previously, you had to restart Blender to start another session.
2019-07-03 21:01:58 +02:00
Julian Eisel
5891e86420 Cleanup GHOST_Xr types and functions
* Move GHOST_Xr types to GHOST_Types.h
* Add GHOST_XrPose. We'll have to pass around pose data at multiple
  places.
* Don't require extra call to prepare session rendering, handle
everything through GHOST_XrSessionStart
* Naming
2019-07-01 19:04:54 +02:00
Julian Eisel
2cedad990a Initial HMD viewport rendering (DirectX only first)
Finally: This makes it possible to render a viewport to an HMD via
OpenXR. Pure OpenGL rendering will need some more tweaks to work.
To my great delight, performance is quite good for reasonably sized
scenes.

Had to do some hacks and marked some TODOs. Nothing too bad though.

Here are a couple of notes:
* Current initial pose is pretty useless, think it just looks downwards
  from world origin. Will change that soon.
* The rendered viewport has some issues: Too dark (bad lighting?), grid
  doesn't show up even though I told it to, lighting seems to change with
  view position/rotation, etc. Needs some polish.
* Ideally we'd just use the D3D11 Texture given to us via the OpenXR
  swapchain and blit the OpenGL framebuffer into that. However the
  NV_DX_interop extension fails doing this. Seems like this is a NVidia
  Optimus only issue, but I'm missing the hardware to confirm.
  So instead, we blit into the D3D11 back buffer first and then into the
  Texture.
* The draw-manager uses its own offscreen context so we have to get the
  render result from the draw-manager context to the VR session's
  context first. Luckily I've already added code to support blitting from
  one OpenGL context into another. But it requires blitting twice.
  Blitting should be very cheap, but still...
  Draw-manager could get a context to use passed instead.
2019-07-01 15:57:32 +02:00
Julian Eisel
109be29e42 Draw offscreen viewport in XR session surface callback
Not visible yet, but it should draw in the offscreen. The way this is
now, we don't depend on the Window->Workspace->bScreen->... chain. We
simply draw an offscreen viewport in the draw callback of the XR session
surface.

The drawing also uses view and projection matrices from OpenXR (or
calculated from OpenXR data).
2019-06-29 02:30:23 +02:00
Julian Eisel
13442da69f Move WM level XR functions to wm_xr.c
Operator is still in wm_operators.c, but only calls wm_xr.c functions.
2019-06-28 22:53:46 +02:00
Julian Eisel
231dbd53bf Support Window-less (offscreen) VR session on Windows
Uses the new wmSurface type (non-window drawable container) to manage
the OpenGL, DirectX and GPU module contexts. The draw callback of the XR
surface calls the GHOST_Xr session drawing routines.

What you should see when starting a VR session now (using the WMR
runtime): The Windows Mixed Reality Portal pops up, and a blue
background is drawn on the HMD. This is from the blue color clear call
we do in the drawing preparations of the GHOST_Xr session drawing.
2019-06-28 16:24:24 +02:00
Julian Eisel
d3e48fb096 Merge branch 'master' into soc-2019-openxr 2019-06-28 14:09:08 +02:00
Julian Eisel
d544a0b41c Avoid std::vector copy 2019-06-28 13:56:10 +02:00
Julian Eisel
cf4799e299 Add wmSurface for non-Window offscreen VR session drawing
Adds a wmSurface type which acts as a container for non-Window (offscreen)
draw surfaces. Ideally wmWindow would of course also just do C-style
inheritance from wmSurface, but I guess they can co-exist too.
For the VR session a surface is created on Linux and passed to the
graphics binding to use.

Note this is not used on Windows yet, it still opens a window there.
2019-06-28 13:38:34 +02:00
Julian Eisel
57d9f004aa Fix compile/CMake errors and warnings on Linux 2019-06-27 19:55:22 +02:00
Julian Eisel
62cde7a9ef Finish VR view drawing callback set up
* Allow passing custom data to session draw function, passed to the
  callback
* Actually call the callback
* Create and bind a WM level callback. Will later be used to draw the
  viewport.

Also, check if session is actually visible before drawing.
2019-06-27 19:17:12 +02:00
Julian Eisel
e4fcf25fc5 Don't use Microsoft::WRL::ComPtr<...> for COM types
Makes things difficult if you're not familar with COM.
2019-06-27 18:56:20 +02:00
Julian Eisel
215c919b33 Merge branch 'master' into soc-2019-openxr 2019-06-26 18:39:31 +02:00
Julian Eisel
da44a02d00 The first pixels pushed to Windows Mixed Reality HMDs!
Just a clear call for now, so all you see is a blue world. This blue
"world" is however drawn by Blender!

Also fixes use after destruction of compositor layer data.
2019-06-24 21:22:23 +02:00
Julian Eisel
867007d9d7 Set up OpenXR compositing layers for drawing
That should be one of the last steps to prepare pushing pixels to HMDs.
Fingers crossed!
2019-06-24 16:44:43 +02:00
Julian Eisel
e9ea814233 Merge branch 'master' into soc-2019-openxr 2019-06-24 12:52:37 +02:00
Julian Eisel
6b43c82cb5 Set up OpenXR views and spaces for drawing
Using a dummy identity pose at {0, 0, 0} to start with. This should
later use the current viewport position & orientation I guess.

Also adds function to set a draw callback. There's quite some OpenXR
related stuff to be done before and after drawing anyting, as well as
before and after drawing each view (eye). Quite some info would have to
be exposed to WM to let it manage drawing. So I think using a callback
called from GHOST_Xr to draw each eye instead is a good way to go.

VR session currently crashes after opening. Seems to be related to
blocking frame wait call. I'm not too worried about that though, might
disappear once OpenXR frame sync functions get proper timing info
passed.
2019-06-23 18:27:24 +02:00
Julian Eisel
afbb62fecd Bring back wm_xr.c for higher level XR functions 2019-06-23 15:42:18 +02:00
Julian Eisel
8a676e8fa9 Execute necessary OpenXR frame timing calls 2019-06-23 13:47:42 +02:00
Julian Eisel
c52111e983 Correctly destruct swapchain on shutdown 2019-06-23 02:46:25 +02:00
Julian Eisel
d749e8a2c4 Create graphics binding specific swapchain images
Following the OpenXR SDK's example code very closely here. We have to do
some nasty converting of graphics binding specific image vectors to
generalized base ones. The SDK's approach seems like a good way to go
about this.
2019-06-23 02:12:38 +02:00
Julian Eisel
8663aa80e6 Use abstract class/interface for generalized graphics binding operations
Rather than having switch case blocks throughout the session code, give
binding operations an own interface with dedicated implementations.
2019-06-23 00:37:17 +02:00
Julian Eisel
88b39444a0 Fix error causing sessions to not start correctly
With this, the Windows Mixed Reality Portal finally pops up when
starting the session. That is how it's supposed to work. After it's
initialization phase all you see is black. That's expected too as we
don't send anything to the device yet.
2019-06-22 22:08:50 +02:00
Julian Eisel
4cfc3caa09 OpenXR swapchain creation
Nothing special to say. Just calls needed OpenXR functions to create
swapchains. Swapchain images are not created yet.

Interestingly, the Windows Mixed Realtiy portal now pops up when closing
Blender after having created a VR session. So we're getting closer ;)
2019-06-22 21:25:58 +02:00
Julian Eisel
28428b3462 Merge branch 'master' into soc-2019-openxr 2019-06-21 22:31:01 +02:00
Julian Eisel
24146563a0 Cleanup: Use CamelCase for XR functions/types
Also silence warnings.
2019-06-21 22:27:40 +02:00
Julian Eisel
2ee9c60c20 Finish OpenXR GLX binding initialization
Monado now opens a window here when asking it to start a session. That
seems to be the case because it doesn't detect the HMD as direct mode
capable yet. But that shouldn't be an issue from our side.
2019-06-19 21:11:21 +02:00
Julian Eisel
fb64675209 Fix invalid delete operator use
Again a thing MSVC should warn about but didn't...
2019-06-19 19:09:40 +02:00
Julian Eisel
76385139cf Use friend class to access graphics data on Windows too
Also fix memory leak.
2019-06-19 18:30:19 +02:00
Julian Eisel
b18f5a6a81 Pass graphics context data to OpenXR graphics bindings on Linux too
Refactors function into a class, and make this class a friend of
GHOST_ContextGLX. That seems like a better way to access low level
graphics data for this specific case, rather than giving anyone access
via a getter.
2019-06-19 17:23:41 +02:00
Julian Eisel
9d29373b06 Init OpenXR graphics bindings with valid graphics context (Win only)
Will do this for Linux in a separate commit.

Also fixes a stupid mistake from previous commit on lazy-creation of XR
context.
2019-06-19 12:20:18 +02:00
Julian Eisel
f2f1e4dfed Remove CTX_wm_xr_context
Not really useful, plus XR-Context is now GHOST data.
2019-06-19 01:00:37 +02:00
Julian Eisel
0da0f29ade Rename of XR types (WM -> GHOST) 2019-06-19 00:57:50 +02:00
Julian Eisel
a8519dbac2 Lazy-create XR-context
Creating the context causes the OpenXR loader to try connect to a
runtime. That would involve reading the OS'es active_runtime.json and
dynamic linking based on that. So better avoid doing this on startup.
Also: don't pay for what you don't use!
2019-06-19 00:44:42 +02:00
Julian Eisel
d15d07c4f6 Rename wm_xr_ -> GHOST_XR 2019-06-19 00:28:37 +02:00
Julian Eisel
d356787a65 Merge branch 'soc-2019-openxr' into temp-ghost_openxr 2019-06-18 23:50:28 +02:00
Julian Eisel
a284fa3abb Merge branch 'master' into soc-2019-openxr 2019-06-18 23:49:54 +02:00
Julian Eisel
4eeb7523e9 Use some C++ features where useful
Also correct include guards.
2019-06-18 01:02:33 +02:00
Julian Eisel
f30fcd6c85 Initially move XR files to GHOST and compile in C++ 2019-06-17 23:45:28 +02:00
Julian Eisel
47e8133520 Merge branch 'master' into soc-2019-openxr 2019-06-17 22:24:51 +02:00
Julian Eisel
3fa7d59a04 Fail without crashing if no runtime is found
For now simply do nothing. Plan is to work on proper error handling and
reporting later.
2019-06-17 01:24:07 +02:00
Julian Eisel
df8dc43946 Fix compile errors and warnings on certain configs
Addresses:
* Compile error on Linux
* Compile error with WITH_OPENXR disabled
* Unused parameter warnings
2019-06-16 23:28:14 +02:00
Julian Eisel
3b0a2fecfc Fix missing return value... how did this work even?
Looking at the code this should've failed miserably. No idea how this
could still work fine... Maybe return vars used same stack location?
2019-06-16 23:12:13 +02:00
Julian Eisel
80af6d534d Merge branch 'master' into soc-2019-openxr 2019-06-16 22:58:56 +02:00
Julian Eisel
71c7d61808 Draw OpenGL framebuffer upside down in DirectX windows
DirectX is Y coordinates top to bottom, while OpenGL is the opposite.
For the final window manager on-screen drawing, draw to a texture first
and draw that upside down if needed.
2019-06-16 21:46:57 +02:00
Julian Eisel
637b803b97 Support drawing the VR view into a DirectX window!
Phew! That a fight. But this is also a pretty important feature as it
allows interfacing with Windows Mixed Reality OpenXR runtime and the
HMDs supported by it.

Important remaining issue: The rendered viewport is upside down :) That
is of course because DirectX has the opposite vertical direction than
OpenGL.

When creating a DirectX window, we also create an OpenGL offscreen
context to use for all drawing. Just before swapping framebuffers, the
DirectX window blits the framebuffer of the offscreen context into its
swapchain. This requires the WGL_NV_DX_interop and WGL_NV_DX_interop2
extensions.

For testing/dev purposes, also adds:
* Version of the offscreen to onscreen blitting that's OpenGL only. So
  it blits the default framebuffer of the offscreen context into the one
  of the onscreen context.
  This is disabled by a #define.
* Code to draw a colored triangle using DirectX, also for testing.
  Requires the D3DCompiler.lib to be available at compile time. This is
  also disabled using a #define.
2019-06-16 21:05:21 +02:00
Julian Eisel
314eef0df8 Merge branch 'master' into soc-2019-openxr 2019-06-14 20:41:09 +02:00
Julian Eisel
34fa0f8ac6 Set up DirectX window to support drawing
With this the VR window should open fine and get cleared in a red-ish
orange using Direct3D 11 calls (well, on Windows that is).

The window still draws a 3D view to an offscreen buffer. Where we
usually just swap the buffers, we now allow calling a GHOST function to
blit the offscreen OpenGL buffer to whatever type of graphics buffer the
window uses (DirectX here).
The nice thing about this approach is that all DirectX code stays in
GHOST_ContextD3D.cpp. And the entire compatibiliy code can go into a
single function higher level modules don't need to care about.

This also fixes a number of issues introduced in earlier commits.
2019-06-14 19:07:10 +02:00
Julian Eisel
16366724bd Draw into OpenGL offscreen context in the DirectX window.
The window doesn't show anything of course. However we draw (at least I
assume it does) as regular, just into a window offscreen context.

A valid 3D view is created in the window. It's not visible but you see
cursor changes as you move over the window. So handling works.
2019-06-14 02:41:59 +02:00
Julian Eisel
fc8127d070 (Disabled) code to open a DirectX window with the VR session
The window immediately crashes, hence keeping it disabled for now.

Not sure how much of this I'll leave in, for now this is mainly for
testing DirectX compatibility.
2019-06-13 23:24:30 +02:00
Julian Eisel
3ac37fb552 Fix compile errors with older MSVC/Win-SDK versions
Reported by @LazyDodo, thanks!
2019-06-13 18:22:26 +02:00
Julian Eisel
8e51a75772 Fix mistake causing compiler error on Windows
Stupid one...
2019-06-12 23:45:19 +02:00
Julian Eisel
ba2dab402d Merge branch 'master' into soc-2019-openxr 2019-06-12 21:28:40 +02:00
Julian Eisel
796994d222 Refactor graphics context binding to avoid memory leaks
* Retrieve graphics context to bind through callbacks so the XR code can
  manage their lifetime.
* Use static union to store system & chosen graphics lib specific
  graphics binding data.

Makes some things a bit cleaner, too.
2019-06-12 21:27:00 +02:00
Julian Eisel
66e90e9179 Fix compile error and warning on GCC 2019-06-12 19:28:51 +02:00
Julian Eisel
1404edbe3a Support DirectX Ghost context creation
Adds support for creating a DirectX 11 Ghost context. It's not used yet
and more stuff besides creation is needed. Also, other versions than 11
should probably be supported.
We need a DirectX context to support the Windows Mixed Reality OpenXR
Runtime, a rather important one to support. Idea is to use an extension
for OpenGL-DirectX interoperability for drawing the OpenGL offscreen
viewport render using DirectX.
2019-06-12 11:34:21 +02:00
Julian Eisel
2f68a76409 Split wm_xr.c into multiple files
Similar to gizmo/ and message_bus/, there's now a xr/ directory
containing header files and a intern/ directory for source and internal
header files.

Guess this is reasonable to do. And better to do early on to avoid
loosing much git history.
2019-06-11 17:52:04 +02:00
Julian Eisel
304d9a20fc Fix compile errors and crashes on Windows
* Include needed Windows/DirectX headers
* Disable zero sized arraz (GCC extension)
* Add missing break causing failling assert
* Add missing semicolon in Win only code :)
2019-06-11 16:35:31 +02:00
Julian Eisel
b169e327bf Fix compile error with system OpenXR SDK
Graphics binding types were disabled by a compiler flag then.
2019-06-11 14:18:35 +02:00
Julian Eisel
7238bbecc4 Cleanup: Rename graphics-lib to graphics-binding 2019-06-10 22:16:09 +02:00
Julian Eisel
a49b4ca402 Merge branch 'master' into soc-2019-openxr 2019-06-10 22:06:42 +02:00
Julian Eisel
eb0424c946 Proper management of OpenXR graphics bindings for session setup
OpenXR needs to interface with some graphics library (OpenGL, Vulkan,
DirectX, etc.). This is done through graphics binding extensions. The
OpenXR specification requires these to be properly set up before a
session is created.

Adds the following:
* Support priority list of multiple graphics binding extensions (e.g.
  check OpenGL extension availability first, DirectX on Windows second,
  etc.)
* Barebones for passing graphics library data to OpenXR session
  creation. This is highly system dependent, e.g. it requires GLX data
  for OpenGL on X11 systems (XrGraphicsBindingOpenGLXlibKHR). More work,
  including additions to GHOST, will be needed once I get to the more
  graphics related stuff.
* Create an own graphics context for the VR session. It's not doing
  anything useful yet. This is just to fool the Monado OpenXR runtime
  so that it actually attempts to create the OpenXR session.
* Had to add two CMake modules for platform dependent #define's required
  by the OpenXR specification.
2019-06-10 21:59:26 +02:00
Julian Eisel
5d6da57aa3 Cleanup: Move OpenXRData struct out of wmXRContext
Just to make access a bit more convenient.
2019-06-06 18:38:06 +02:00
Julian Eisel
e968bbc5d8 Fix wrong enum-type used for switch
Why doesn't MSVC warn about this, grr...
2019-06-06 17:37:18 +02:00
Julian Eisel
b1b0e05c54 Fix CMake errors after merge (?)
Not sure if this is caused by changes just merged in, or by a system
upgrade I just did. Either way, fixed it now.
2019-06-06 11:25:53 +02:00
Julian Eisel
e547026dfe Merge branch 'master' into soc-2019-openxr 2019-06-06 10:56:19 +02:00
Julian Eisel
f816380af5 Silence warning, fix mem-leak, don't destroy NULL session 2019-06-05 18:03:59 +02:00
Julian Eisel
5e642bfea1 Initial session state handling
To correctly start a session, a graphics extension specific object needs
to be passed to the OpenXR runtime. E.g. for the Windows Mixed Reality
runtime, XrGraphicsBindingD3D11KHR needs to be passed with a valid
DirectX device. Since we don't have any DirectX compatibility working,
I can't test this on Windows yet.
So to test this I finally need to get Monado to work on Linux and
correctly setup the OpenGL extension there.
2019-06-05 16:55:51 +02:00
Julian Eisel
0d1a22f74f Barebones for managing session changes
Adds initial OpenXR event querying so that session state change events
can be handled. Doesn't do any handling yet.
2019-06-05 10:20:51 +02:00
Julian Eisel
20a1af936d Enable graphics extensions if available
Check if available extensions includes the GL one, or the DirectX one on
Windows. Enable them if available.
2019-06-05 01:00:13 +02:00
Julian Eisel
c9c1b90532 Cleanup: Correct local variable name 2019-06-04 18:30:07 +02:00
Julian Eisel
4192281e14 Fix layer and extension count not stored as intended 2019-06-04 18:27:44 +02:00
Julian Eisel
329deadc9e Print OpenXR runtime name once connected 2019-06-04 17:39:12 +02:00
Julian Eisel
53845c554d Merge branch 'master' into soc-2019-openxr 2019-06-04 17:00:58 +02:00
Julian Eisel
35c9e3beed Initial VR-session starting/ending
Adds operator to toggle a VR session, exposed in the Window top-bar
menu. It triggers the needed calls for session creation and destruction.
Setting up the XR-system (a configuration of related devices) is also
done now.

Calling WMR runtime functions fails currently. Not sure why. So while
this executes required routines, it doesn't really work.
2019-06-04 16:42:42 +02:00
Julian Eisel
60f66768cf Fix GCC compile error, warnings and uninitialized use
extension_count could be used uninitialized if no valid OpenXR runtime
was run.
2019-06-02 22:04:52 +02:00
Julian Eisel
3e88974a80 Merge branch 'master' into soc-2019-openxr 2019-06-02 15:24:33 +02:00
Julian Eisel
09e7d6cd26 Correct previous commit
Intended to print out name, not address.
2019-06-02 02:24:04 +02:00
Julian Eisel
5d5ad5d6dd Gather available OpenXR extensions and API-layers on OpenXR setup
We don't actually enable any extension or layer yet. We just put their
names into arrays and print them. The printing can be disabled via a
compiler define, later we should put them behind a proper
logging/debugging mechanism (CLOG).

Also fixes a Visual Studio compile error.
2019-06-01 17:16:49 +02:00
Julian Eisel
e70894c360 Fix compiling with bundled OpenXR SDK sources
Also remove unused include.
2019-05-30 16:22:05 +02:00
Julian Eisel
4c11886c4e Corrections to previous commit
* Remove testing instance creation
* Rename function
2019-05-30 14:56:23 +02:00
Julian Eisel
41e2f2e75f Proper creation & destruction of OpenXR instances
Adds wm_xr.c for an XR management API and creates/destroys the OpenXR
instance through this. This is as planned in my proposal, to lock the
OpenXR calls behind an abstraction.
XR data will be stored in a (non-public) wmXRContext struct within the
window-manager.

For now, creates the OpenXR instance on startup. I think it's better to
lazy setup this, as in, only creating the instance once the user starts
the first XR session. Just to avoid costs for something that may not be
used (the OpenXR loader we use will try loading and parsing the system's
OpenXR active_runtime.json on instance creation). That's for later when
I introduce session management though.

Also added a context getter for the xr-context, which is unused but may
be handy later.
2019-05-30 14:48:13 +02:00
Julian Eisel
864abbd425 Support system installed OpenXR SDK
Adds OPENXR_USE_BUNDLED_SRC so that if disabled, CMake tries to find
the SDK headers and libraries in system paths or in specified root
directory.

I guess this is the way we'd want to do this in master. However for
people testing the branch the bundled sources are much more convenient
(should work out of the box, no need to compile the SDK manually).
2019-05-30 01:44:13 +02:00
Julian Eisel
f333e7eb56 Merge branch 'master' into soc-2019-openxr 2019-05-29 20:14:11 +02:00
Julian Eisel
a2ac2ec3c3 Merge branch 'master' into soc-2019-openxr 2019-05-29 15:17:41 +02:00
Julian Eisel
06d52afcda Linux: OpenXR Linking via OpenXR Loader
Calling OpenXR functions should now work on both Windows and Linux.

Also includes:
* Silence Linux only warnings
* Remove common_cmake_config.h and let CMake generate it when
  configuring (contents vary on system it's compiled on)
* Remove JsonCpp CMake install target
* Remove unnecessary CMakeLists for JsonCpp includes
* Remove unnecessary CMake commands
* Style cleanup
2019-05-28 21:58:18 +02:00
Julian Eisel
e65ba62c37 Windows: OpenXR Linking via OpenXR Loader
Adds needed headers for OpenXR, the loader from the OpenXR SDK and
JsonCpp into extern. Took a while to get this to compile/link, but on
Win10 it works fine now without patching #includes. Linux probably
needs more work.

Added a compile option WITH_OPENXR to toggle XR feature compiling.

Also does a dummy xrCreateInstance() call to test linking.
2019-05-28 01:21:25 +02:00
175 changed files with 43784 additions and 335 deletions

View File

@@ -234,6 +234,17 @@ option(WITH_BULLET "Enable Bullet (Physics Engine)" ON)
option(WITH_SYSTEM_BULLET "Use the systems bullet library (currently unsupported due to missing features in upstream!)" )
mark_as_advanced(WITH_SYSTEM_BULLET)
option(WITH_OPENCOLORIO "Enable OpenColorIO color management" ${_init_OPENCOLORIO})
option(WITH_OPENXR "Enable VR features through the OpenXR specification" ON)
if(WITH_OPENXR)
option(OPENXR_USE_BUNDLED_SRC "Compile using the bundled OpenXR SDK sources (otherwise it has to be compiled manually)" ON)
if(NOT OPENXR_USE_BUNDLED_SRC)
find_package(OpenXR-SDK)
if(NOT OPENXR_SDK_FOUND)
message(WARNING "OpenXR-SDK was not found, disabling WITH_OPENXR")
set(WITH_OPENXR OFF)
endif()
endif()
endif()
# Compositor
option(WITH_COMPOSITOR "Enable the tile based nodal compositor" ON)
@@ -1760,6 +1771,7 @@ if(FIRST_RUN)
info_cfg_option(WITH_CYCLES)
info_cfg_option(WITH_FREESTYLE)
info_cfg_option(WITH_OPENCOLORIO)
info_cfg_option(WITH_OPENXR)
info_cfg_option(WITH_OPENVDB)
info_cfg_option(WITH_ALEMBIC)

View File

@@ -0,0 +1,67 @@
# - Find OpenXR-SDK library
# Find the native OpenXR-SDK includes and library
# This module defines
# OPENXR_SDK_INCLUDE_DIRS, where to find OpenXR-SDK headers, Set when
# OPENXR_SDK_INCLUDE_DIR is found.
# OPENXR_SDK_LIBRARIES, libraries to link against to use OpenXR-SDK.
# OPENXR_SDK_ROOT_DIR, the base directory to search for OpenXR-SDK.
# This can also be an environment variable.
# OPENXR_SDK_FOUND, if false, do not try to use OpenXR-SDK.
#
# also defined, but not for general use are
# OPENXR_LOADER_LIBRARY, where to find the OpenXR-SDK library.
#=============================================================================
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# If OPENXR_SDK_ROOT_DIR was defined in the environment, use it.
IF(NOT OPENXR_SDK_ROOT_DIR AND NOT $ENV{OPENXR_SDK_ROOT_DIR} STREQUAL "")
SET(OPENXR_SDK_ROOT_DIR $ENV{OPENXR_SDK_ROOT_DIR})
ENDIF()
SET(_openxr_sdk_SEARCH_DIRS
${OPENXR_SDK_ROOT_DIR}
/usr/local
/sw # Fink
/opt/local # DarwinPorts
)
FIND_PATH(OPENXR_SDK_INCLUDE_DIR
NAMES
openxr/openxr.h
HINTS
${_openxr_sdk_SEARCH_DIRS}
PATH_SUFFIXES
include
)
FIND_LIBRARY(OPENXR_LOADER_LIBRARY
NAMES
openxr_loader
HINTS
${_openxr_sdk_SEARCH_DIRS}
PATH_SUFFIXES
lib64 lib
)
# handle the QUIETLY and REQUIRED arguments and set OPENXR_SDK_FOUND to TRUE if
# all listed variables are TRUE
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(OPENXR_SDK DEFAULT_MSG
OPENXR_LOADER_LIBRARY OPENXR_SDK_INCLUDE_DIR)
IF(OPENXR_SDK_FOUND)
SET(OPENXR_SDK_LIBRARIES ${OPENXR_LOADER_LIBRARY})
SET(OPENXR_SDK_INCLUDE_DIRS ${OPENXR_SDK_INCLUDE_DIR})
ENDIF(OPENXR_SDK_FOUND)
MARK_AS_ADVANCED(
OPENXR_SDK_INCLUDE_DIR
OPENXR_LOADER_LIBRARY
)

View File

@@ -0,0 +1,101 @@
set(PRESENTATION_BACKENDS xlib xcb wayland)
set(PRESENTATION_BACKEND xlib CACHE STRING
"Presentation backend chosen at configure time")
set_property(CACHE PRESENTATION_BACKEND PROPERTY STRINGS
${PRESENTATION_BACKENDS})
list(FIND PRESENTATION_BACKENDS ${PRESENTATION_BACKEND} index)
if(index EQUAL -1)
message(FATAL_ERROR "Presentation backend must be one of
${PRESENTATION_BACKENDS}")
endif()
message(STATUS "Using presentation backend: ${PRESENTATION_BACKEND}")
if( PRESENTATION_BACKEND MATCHES "xlib" )
find_package(X11 REQUIRED)
if ((NOT X11_Xxf86vm_LIB) OR (NOT X11_Xrandr_LIB))
message(FATAL_ERROR "OpenXR xlib backend requires Xxf86vm and Xrandr")
endif()
add_definitions( -DSUPPORT_X )
add_definitions( -DOS_LINUX_XLIB )
set( XLIB_LIBRARIES
${X11_LIBRARIES}
${X11_Xxf86vm_LIB}
${X11_Xrandr_LIB} )
elseif( PRESENTATION_BACKEND MATCHES "xcb" )
find_package(PkgConfig REQUIRED)
# XCB + XCB GLX is limited to OpenGL 2.1
# add_definitions( -DOS_LINUX_XCB )
# XCB + Xlib GLX 1.3
add_definitions( -DOS_LINUX_XCB_GLX )
pkg_search_module(X11 REQUIRED x11)
pkg_search_module(XCB REQUIRED xcb)
pkg_search_module(XCB_RANDR REQUIRED xcb-randr)
pkg_search_module(XCB_KEYSYMS REQUIRED xcb-keysyms)
pkg_search_module(XCB_GLX REQUIRED xcb-glx)
pkg_search_module(XCB_DRI2 REQUIRED xcb-dri2)
pkg_search_module(XCB_ICCCM REQUIRED xcb-icccm)
set( XCB_LIBRARIES
${XCB_LIBRARIES}
${XCB_KEYSYMS_LIBRARIES}
${XCB_RANDR_LIBRARIES}
${XCB_GLX_LIBRARIES}
${XCB_DRI2_LIBRARIES}
${X11_LIBRARIES} )
elseif( PRESENTATION_BACKEND MATCHES "wayland" )
find_package(PkgConfig REQUIRED)
pkg_search_module(WAYLAND_CLIENT REQUIRED wayland-client)
pkg_search_module(WAYLAND_EGL REQUIRED wayland-egl)
pkg_search_module(WAYLAND_SCANNER REQUIRED wayland-scanner)
pkg_search_module(WAYLAND_PROTOCOLS REQUIRED wayland-protocols>=1.7)
pkg_search_module(EGL REQUIRED egl)
add_definitions( -DOS_LINUX_WAYLAND )
set( WAYLAND_LIBRARIES
${EGL_LIBRARIES}
${WAYLAND_CLIENT_LIBRARIES}
${WAYLAND_EGL_LIBRARIES} )
# generate wayland protocols
set(WAYLAND_PROTOCOLS_DIR ${CMAKE_SOURCE_DIR}/wayland-protocols/)
file(MAKE_DIRECTORY ${WAYLAND_PROTOCOLS_DIR})
pkg_get_variable(WAYLAND_PROTOCOLS_DATADIR wayland-protocols pkgdatadir)
pkg_get_variable(WAYLAND_SCANNER wayland-scanner wayland_scanner)
set(PROTOCOL xdg-shell-unstable-v6)
set(PROTOCOL_XML
${WAYLAND_PROTOCOLS_DATADIR}/unstable/xdg-shell/${PROTOCOL}.xml)
if( EXISTS ${PROTOCOL_XML} )
execute_process(COMMAND
${WAYLAND_SCANNER}
code
${PROTOCOL_XML}
${WAYLAND_PROTOCOLS_DIR}/${PROTOCOL}.c)
execute_process(COMMAND
${WAYLAND_SCANNER}
client-header
${PROTOCOL_XML}
${WAYLAND_PROTOCOLS_DIR}/${PROTOCOL}.h)
set( WAYLAND_PROTOCOL_SRC
${WAYLAND_PROTOCOLS_DIR}/${PROTOCOL}.c
${WAYLAND_PROTOCOLS_DIR}/${PROTOCOL}.h )
include_directories(${WAYLAND_PROTOCOLS_DIR})
else()
message(FATAL_ERROR
"xdg-shell-unstable-v6.xml not found in "
${WAYLAND_PROTOCOLS_DATADIR}
"\nYour wayland-protocols package does not "
"contain xdg-shell-unstable-v6.")
endif()
endif()

View File

@@ -0,0 +1,47 @@
# Copyright (c) 2017 The Khronos Group Inc.
#
# 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.
if(WIN32)
add_definitions(-DXR_OS_WINDOWS)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
add_definitions(-DXR_OS_LINUX)
endif()
# Determine the presentation backend for Linux systems.
# Use an include because the code is pretty big.
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
include(presentation)
endif()
# Several files use these compile-time platform switches
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
add_definitions( -DXR_USE_PLATFORM_WIN32 )
elseif( PRESENTATION_BACKEND MATCHES "xlib" )
add_definitions( -DXR_USE_PLATFORM_XLIB )
elseif( PRESENTATION_BACKEND MATCHES "xcb" )
add_definitions( -DXR_USE_PLATFORM_XCB )
elseif( PRESENTATION_BACKEND MATCHES "wayland" )
add_definitions( -DXR_USE_PLATFORM_WAYLAND )
endif()
add_definitions(-DXR_USE_GRAPHICS_API_OPENGL)
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
add_definitions(-DXR_USE_GRAPHICS_API_D3D)
add_definitions(-DXR_USE_GRAPHICS_API_D3D10)
add_definitions(-DXR_USE_GRAPHICS_API_D3D11)
add_definitions(-DXR_USE_GRAPHICS_API_D3D12)
endif()

View File

@@ -40,6 +40,7 @@ set(WITH_AUDASPACE ON CACHE BOOL "" FORCE)
set(WITH_OPENAL ON CACHE BOOL "" FORCE)
set(WITH_OPENCOLLADA ON CACHE BOOL "" FORCE)
set(WITH_OPENCOLORIO ON CACHE BOOL "" FORCE)
set(WITH_OPENXR ON CACHE BOOL "" FORCE)
set(WITH_OPENMP ON CACHE BOOL "" FORCE)
set(WITH_OPENSUBDIV ON CACHE BOOL "" FORCE)
set(WITH_OPENVDB ON CACHE BOOL "" FORCE)

View File

@@ -45,6 +45,7 @@ set(WITH_AUDASPACE OFF CACHE BOOL "" FORCE)
set(WITH_OPENAL OFF CACHE BOOL "" FORCE)
set(WITH_OPENCOLLADA OFF CACHE BOOL "" FORCE)
set(WITH_OPENCOLORIO OFF CACHE BOOL "" FORCE)
set(WITH_OPENXR OFF CACHE BOOL "" FORCE)
set(WITH_OPENIMAGEIO OFF CACHE BOOL "" FORCE)
set(WITH_OPENMP OFF CACHE BOOL "" FORCE)
set(WITH_OPENSUBDIV OFF CACHE BOOL "" FORCE)

View File

@@ -41,6 +41,7 @@ set(WITH_AUDASPACE ON CACHE BOOL "" FORCE)
set(WITH_OPENAL ON CACHE BOOL "" FORCE)
set(WITH_OPENCOLLADA ON CACHE BOOL "" FORCE)
set(WITH_OPENCOLORIO ON CACHE BOOL "" FORCE)
set(WITH_OPENXR ON CACHE BOOL "" FORCE)
set(WITH_OPENMP ON CACHE BOOL "" FORCE)
set(WITH_OPENSUBDIV ON CACHE BOOL "" FORCE)
set(WITH_OPENVDB ON CACHE BOOL "" FORCE)

View File

@@ -468,6 +468,9 @@ function(setup_liblinks
if(WITH_OPENSUBDIV)
target_link_libraries(${target} ${OPENSUBDIV_LIBRARIES})
endif()
if(WITH_OPENXR)
target_link_libraries(${target} ${OPENXR_SDK_LIBRARIES})
endif()
if(WITH_CYCLES_EMBREE)
target_link_libraries(${target} ${EMBREE_LIBRARIES})
endif()

View File

@@ -105,3 +105,8 @@ if(WITH_AUDASPACE AND NOT WITH_SYSTEM_AUDASPACE)
set(AUDASPACE_CMAKE_CFG ${CMAKE_CURRENT_SOURCE_DIR}/audaspace/blender_config.cmake)
add_subdirectory(audaspace)
endif()
if(WITH_OPENXR AND OPENXR_USE_BUNDLED_SRC)
add_subdirectory(jsoncpp)
add_subdirectory(openxr)
endif()

20
extern/jsoncpp/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,20 @@
# ***** BEGIN GPL LICENSE BLOCK *****
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# All rights reserved.
# ***** END GPL LICENSE BLOCK *****
add_subdirectory(src)

98
extern/jsoncpp/include/json/allocator.h vendored Normal file
View File

@@ -0,0 +1,98 @@
// Copyright 2007-2010 Baptiste Lepilleur
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
#ifndef CPPTL_JSON_ALLOCATOR_H_INCLUDED
#define CPPTL_JSON_ALLOCATOR_H_INCLUDED
#include <cstring>
#include <memory>
#pragma pack(push, 8)
namespace Json {
template<typename T>
class SecureAllocator {
public:
// Type definitions
using value_type = T;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
/**
* Allocate memory for N items using the standard allocator.
*/
pointer allocate(size_type n) {
// allocate using "global operator new"
return static_cast<pointer>(::operator new(n * sizeof(T)));
}
/**
* Release memory which was allocated for N items at pointer P.
*
* The memory block is filled with zeroes before being released.
* The pointer argument is tagged as "volatile" to prevent the
* compiler optimizing out this critical step.
*/
void deallocate(volatile pointer p, size_type n) {
std::memset(p, 0, n * sizeof(T));
// free using "global operator delete"
::operator delete(p);
}
/**
* Construct an item in-place at pointer P.
*/
template<typename... Args>
void construct(pointer p, Args&&... args) {
// construct using "placement new" and "perfect forwarding"
::new (static_cast<void*>(p)) T(std::forward<Args>(args)...);
}
size_type max_size() const {
return size_t(-1) / sizeof(T);
}
pointer address( reference x ) const {
return std::addressof(x);
}
const_pointer address( const_reference x ) const {
return std::addressof(x);
}
/**
* Destroy an item in-place at pointer P.
*/
void destroy(pointer p) {
// destroy using "explicit destructor"
p->~T();
}
// Boilerplate
SecureAllocator() {}
template<typename U> SecureAllocator(const SecureAllocator<U>&) {}
template<typename U> struct rebind { using other = SecureAllocator<U>; };
};
template<typename T, typename U>
bool operator==(const SecureAllocator<T>&, const SecureAllocator<U>&) {
return true;
}
template<typename T, typename U>
bool operator!=(const SecureAllocator<T>&, const SecureAllocator<U>&) {
return false;
}
} //namespace Json
#pragma pack(pop)
#endif // CPPTL_JSON_ALLOCATOR_H_INCLUDED

View File

@@ -0,0 +1,54 @@
// Copyright 2007-2010 Baptiste Lepilleur
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
#ifndef CPPTL_JSON_ASSERTIONS_H_INCLUDED
#define CPPTL_JSON_ASSERTIONS_H_INCLUDED
#include <stdlib.h>
#include <sstream>
#if !defined(JSON_IS_AMALGAMATION)
#include "config.h"
#endif // if !defined(JSON_IS_AMALGAMATION)
/** It should not be possible for a maliciously designed file to
* cause an abort() or seg-fault, so these macros are used only
* for pre-condition violations and internal logic errors.
*/
#if JSON_USE_EXCEPTION
// @todo <= add detail about condition in exception
# define JSON_ASSERT(condition) \
{if (!(condition)) {Json::throwLogicError( "assert json failed" );}}
# define JSON_FAIL_MESSAGE(message) \
{ \
JSONCPP_OSTRINGSTREAM oss; oss << message; \
Json::throwLogicError(oss.str()); \
abort(); \
}
#else // JSON_USE_EXCEPTION
# define JSON_ASSERT(condition) assert(condition)
// The call to assert() will show the failure message in debug builds. In
// release builds we abort, for a core-dump or debugger.
# define JSON_FAIL_MESSAGE(message) \
{ \
JSONCPP_OSTRINGSTREAM oss; oss << message; \
assert(false && oss.str().c_str()); \
abort(); \
}
#endif
#define JSON_ASSERT_MESSAGE(condition, message) \
if (!(condition)) { \
JSON_FAIL_MESSAGE(message); \
}
#endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED

25
extern/jsoncpp/include/json/autolink.h vendored Normal file
View File

@@ -0,0 +1,25 @@
// Copyright 2007-2010 Baptiste Lepilleur
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
#ifndef JSON_AUTOLINK_H_INCLUDED
#define JSON_AUTOLINK_H_INCLUDED
#include "config.h"
#ifdef JSON_IN_CPPTL
#include <cpptl/cpptl_autolink.h>
#endif
#if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && \
!defined(JSON_IN_CPPTL)
#define CPPTL_AUTOLINK_NAME "json"
#undef CPPTL_AUTOLINK_DLL
#ifdef JSON_DLL
#define CPPTL_AUTOLINK_DLL
#endif
#include "autolink.h"
#endif
#endif // JSON_AUTOLINK_H_INCLUDED

184
extern/jsoncpp/include/json/config.h vendored Normal file
View File

@@ -0,0 +1,184 @@
// Copyright 2007-2010 Baptiste Lepilleur
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
#ifndef JSON_CONFIG_H_INCLUDED
#define JSON_CONFIG_H_INCLUDED
#include <stddef.h>
#include <string> //typedef String
#include <stdint.h> //typedef int64_t, uint64_t
/// If defined, indicates that json library is embedded in CppTL library.
//# define JSON_IN_CPPTL 1
/// If defined, indicates that json may leverage CppTL library
//# define JSON_USE_CPPTL 1
/// If defined, indicates that cpptl vector based map should be used instead of
/// std::map
/// as Value container.
//# define JSON_USE_CPPTL_SMALLMAP 1
// If non-zero, the library uses exceptions to report bad input instead of C
// assertion macros. The default is to use exceptions.
#ifndef JSON_USE_EXCEPTION
#define JSON_USE_EXCEPTION 1
#endif
/// If defined, indicates that the source file is amalgated
/// to prevent private header inclusion.
/// Remarks: it is automatically defined in the generated amalgated header.
// #define JSON_IS_AMALGAMATION
#ifdef JSON_IN_CPPTL
#include <cpptl/config.h>
#ifndef JSON_USE_CPPTL
#define JSON_USE_CPPTL 1
#endif
#endif
#ifdef JSON_IN_CPPTL
#define JSON_API CPPTL_API
#elif defined(JSON_DLL_BUILD)
#if defined(_MSC_VER) || defined(__MINGW32__)
#define JSON_API __declspec(dllexport)
#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
#endif // if defined(_MSC_VER)
#elif defined(JSON_DLL)
#if defined(_MSC_VER) || defined(__MINGW32__)
#define JSON_API __declspec(dllimport)
#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
#endif // if defined(_MSC_VER)
#endif // ifdef JSON_IN_CPPTL
#if !defined(JSON_API)
#define JSON_API
#endif
// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for
// integer
// Storages, and 64 bits integer support is disabled.
// #define JSON_NO_INT64 1
#if defined(_MSC_VER) // MSVC
# if _MSC_VER <= 1200 // MSVC 6
// Microsoft Visual Studio 6 only support conversion from __int64 to double
// (no conversion from unsigned __int64).
# define JSON_USE_INT64_DOUBLE_CONVERSION 1
// Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255'
// characters in the debug information)
// All projects I've ever seen with VS6 were using this globally (not bothering
// with pragma push/pop).
# pragma warning(disable : 4786)
# endif // MSVC 6
# if _MSC_VER >= 1500 // MSVC 2008
/// Indicates that the following function is deprecated.
# define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
# endif
#endif // defined(_MSC_VER)
// In c++11 the override keyword allows you to explicity define that a function
// is intended to override the base-class version. This makes the code more
// managable and fixes a set of common hard-to-find bugs.
#if __cplusplus >= 201103L
# define JSONCPP_OVERRIDE override
# define JSONCPP_NOEXCEPT noexcept
#elif defined(_MSC_VER) && _MSC_VER > 1600 && _MSC_VER < 1900
# define JSONCPP_OVERRIDE override
# define JSONCPP_NOEXCEPT throw()
#elif defined(_MSC_VER) && _MSC_VER >= 1900
# define JSONCPP_OVERRIDE override
# define JSONCPP_NOEXCEPT noexcept
#else
# define JSONCPP_OVERRIDE
# define JSONCPP_NOEXCEPT throw()
#endif
#ifndef JSON_HAS_RVALUE_REFERENCES
#if defined(_MSC_VER) && _MSC_VER >= 1600 // MSVC >= 2010
#define JSON_HAS_RVALUE_REFERENCES 1
#endif // MSVC >= 2010
#ifdef __clang__
#if __has_feature(cxx_rvalue_references)
#define JSON_HAS_RVALUE_REFERENCES 1
#endif // has_feature
#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc)
#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L)
#define JSON_HAS_RVALUE_REFERENCES 1
#endif // GXX_EXPERIMENTAL
#endif // __clang__ || __GNUC__
#endif // not defined JSON_HAS_RVALUE_REFERENCES
#ifndef JSON_HAS_RVALUE_REFERENCES
#define JSON_HAS_RVALUE_REFERENCES 0
#endif
#ifdef __clang__
#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc)
# if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
# define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message)))
# elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
# define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__))
# endif // GNUC version
#endif // __clang__ || __GNUC__
#if !defined(JSONCPP_DEPRECATED)
#define JSONCPP_DEPRECATED(message)
#endif // if !defined(JSONCPP_DEPRECATED)
#if __GNUC__ >= 6
# define JSON_USE_INT64_DOUBLE_CONVERSION 1
#endif
#if !defined(JSON_IS_AMALGAMATION)
# include "version.h"
# if JSONCPP_USING_SECURE_MEMORY
# include "allocator.h" //typedef Allocator
# endif
#endif // if !defined(JSON_IS_AMALGAMATION)
namespace Json {
typedef int Int;
typedef unsigned int UInt;
#if defined(JSON_NO_INT64)
typedef int LargestInt;
typedef unsigned int LargestUInt;
#undef JSON_HAS_INT64
#else // if defined(JSON_NO_INT64)
// For Microsoft Visual use specific types as long long is not supported
#if defined(_MSC_VER) // Microsoft Visual Studio
typedef __int64 Int64;
typedef unsigned __int64 UInt64;
#else // if defined(_MSC_VER) // Other platforms, use long long
typedef int64_t Int64;
typedef uint64_t UInt64;
#endif // if defined(_MSC_VER)
typedef Int64 LargestInt;
typedef UInt64 LargestUInt;
#define JSON_HAS_INT64
#endif // if defined(JSON_NO_INT64)
#if JSONCPP_USING_SECURE_MEMORY
#define JSONCPP_STRING std::basic_string<char, std::char_traits<char>, Json::SecureAllocator<char> >
#define JSONCPP_OSTRINGSTREAM std::basic_ostringstream<char, std::char_traits<char>, Json::SecureAllocator<char> >
#define JSONCPP_OSTREAM std::basic_ostream<char, std::char_traits<char>>
#define JSONCPP_ISTRINGSTREAM std::basic_istringstream<char, std::char_traits<char>, Json::SecureAllocator<char> >
#define JSONCPP_ISTREAM std::istream
#else
#define JSONCPP_STRING std::string
#define JSONCPP_OSTRINGSTREAM std::ostringstream
#define JSONCPP_OSTREAM std::ostream
#define JSONCPP_ISTRINGSTREAM std::istringstream
#define JSONCPP_ISTREAM std::istream
#endif // if JSONCPP_USING_SECURE_MEMORY
} // end namespace Json
#endif // JSON_CONFIG_H_INCLUDED

61
extern/jsoncpp/include/json/features.h vendored Normal file
View File

@@ -0,0 +1,61 @@
// Copyright 2007-2010 Baptiste Lepilleur
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
#ifndef CPPTL_JSON_FEATURES_H_INCLUDED
#define CPPTL_JSON_FEATURES_H_INCLUDED
#if !defined(JSON_IS_AMALGAMATION)
#include "forwards.h"
#endif // if !defined(JSON_IS_AMALGAMATION)
#pragma pack(push, 8)
namespace Json {
/** \brief Configuration passed to reader and writer.
* This configuration object can be used to force the Reader or Writer
* to behave in a standard conforming way.
*/
class JSON_API Features {
public:
/** \brief A configuration that allows all features and assumes all strings
* are UTF-8.
* - C & C++ comments are allowed
* - Root object can be any JSON value
* - Assumes Value strings are encoded in UTF-8
*/
static Features all();
/** \brief A configuration that is strictly compatible with the JSON
* specification.
* - Comments are forbidden.
* - Root object must be either an array or an object value.
* - Assumes Value strings are encoded in UTF-8
*/
static Features strictMode();
/** \brief Initialize the configuration like JsonConfig::allFeatures;
*/
Features();
/// \c true if comments are allowed. Default: \c true.
bool allowComments_;
/// \c true if root must be either an array or an object value. Default: \c
/// false.
bool strictRoot_;
/// \c true if dropped null placeholders are allowed. Default: \c false.
bool allowDroppedNullPlaceholders_;
/// \c true if numeric object key are allowed. Default: \c false.
bool allowNumericKeys_;
};
} // namespace Json
#pragma pack(pop)
#endif // CPPTL_JSON_FEATURES_H_INCLUDED

37
extern/jsoncpp/include/json/forwards.h vendored Normal file
View File

@@ -0,0 +1,37 @@
// Copyright 2007-2010 Baptiste Lepilleur
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
#ifndef JSON_FORWARDS_H_INCLUDED
#define JSON_FORWARDS_H_INCLUDED
#if !defined(JSON_IS_AMALGAMATION)
#include "config.h"
#endif // if !defined(JSON_IS_AMALGAMATION)
namespace Json {
// writer.h
class FastWriter;
class StyledWriter;
// reader.h
class Reader;
// features.h
class Features;
// value.h
typedef unsigned int ArrayIndex;
class StaticString;
class Path;
class PathArgument;
class Value;
class ValueIteratorBase;
class ValueIterator;
class ValueConstIterator;
} // namespace Json
#endif // JSON_FORWARDS_H_INCLUDED

15
extern/jsoncpp/include/json/json.h vendored Normal file
View File

@@ -0,0 +1,15 @@
// Copyright 2007-2010 Baptiste Lepilleur
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
#ifndef JSON_JSON_H_INCLUDED
#define JSON_JSON_H_INCLUDED
#include "autolink.h"
#include "value.h"
#include "reader.h"
#include "writer.h"
#include "features.h"
#endif // JSON_JSON_H_INCLUDED

408
extern/jsoncpp/include/json/reader.h vendored Normal file
View File

@@ -0,0 +1,408 @@
// Copyright 2007-2010 Baptiste Lepilleur
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
#ifndef CPPTL_JSON_READER_H_INCLUDED
#define CPPTL_JSON_READER_H_INCLUDED
#if !defined(JSON_IS_AMALGAMATION)
#include "features.h"
#include "value.h"
#endif // if !defined(JSON_IS_AMALGAMATION)
#include <deque>
#include <iosfwd>
#include <stack>
#include <string>
#include <istream>
// Disable warning C4251: <data member>: <type> needs to have dll-interface to
// be used by...
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma warning(push)
#pragma warning(disable : 4251)
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma pack(push, 8)
namespace Json {
/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a
*Value.
*
* \deprecated Use CharReader and CharReaderBuilder.
*/
class JSON_API Reader {
public:
typedef char Char;
typedef const Char* Location;
/** \brief An error tagged with where in the JSON text it was encountered.
*
* The offsets give the [start, limit) range of bytes within the text. Note
* that this is bytes, not codepoints.
*
*/
struct StructuredError {
ptrdiff_t offset_start;
ptrdiff_t offset_limit;
JSONCPP_STRING message;
};
/** \brief Constructs a Reader allowing all features
* for parsing.
*/
Reader();
/** \brief Constructs a Reader allowing the specified feature set
* for parsing.
*/
Reader(const Features& features);
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
* document.
* \param document UTF-8 encoded string containing the document to read.
* \param root [out] Contains the root value of the document if it was
* successfully parsed.
* \param collectComments \c true to collect comment and allow writing them
* back during
* serialization, \c false to discard comments.
* This parameter is ignored if
* Features::allowComments_
* is \c false.
* \return \c true if the document was successfully parsed, \c false if an
* error occurred.
*/
bool
parse(const std::string& document, Value& root, bool collectComments = true);
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
document.
* \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the
document to read.
* \param endDoc Pointer on the end of the UTF-8 encoded string of the
document to read.
* Must be >= beginDoc.
* \param root [out] Contains the root value of the document if it was
* successfully parsed.
* \param collectComments \c true to collect comment and allow writing them
back during
* serialization, \c false to discard comments.
* This parameter is ignored if
Features::allowComments_
* is \c false.
* \return \c true if the document was successfully parsed, \c false if an
error occurred.
*/
bool parse(const char* beginDoc,
const char* endDoc,
Value& root,
bool collectComments = true);
/// \brief Parse from input stream.
/// \see Json::operator>>(std::istream&, Json::Value&).
bool parse(JSONCPP_ISTREAM& is, Value& root, bool collectComments = true);
/** \brief Returns a user friendly string that list errors in the parsed
* document.
* \return Formatted error message with the list of errors with their location
* in
* the parsed document. An empty string is returned if no error
* occurred
* during parsing.
* \deprecated Use getFormattedErrorMessages() instead (typo fix).
*/
JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.")
JSONCPP_STRING getFormatedErrorMessages() const;
/** \brief Returns a user friendly string that list errors in the parsed
* document.
* \return Formatted error message with the list of errors with their location
* in
* the parsed document. An empty string is returned if no error
* occurred
* during parsing.
*/
JSONCPP_STRING getFormattedErrorMessages() const;
/** \brief Returns a vector of structured erros encounted while parsing.
* \return A (possibly empty) vector of StructuredError objects. Currently
* only one error can be returned, but the caller should tolerate
* multiple
* errors. This can occur if the parser recovers from a non-fatal
* parse error and then encounters additional errors.
*/
std::vector<StructuredError> getStructuredErrors() const;
/** \brief Add a semantic error message.
* \param value JSON Value location associated with the error
* \param message The error message.
* \return \c true if the error was successfully added, \c false if the
* Value offset exceeds the document size.
*/
bool pushError(const Value& value, const JSONCPP_STRING& message);
/** \brief Add a semantic error message with extra context.
* \param value JSON Value location associated with the error
* \param message The error message.
* \param extra Additional JSON Value location to contextualize the error
* \return \c true if the error was successfully added, \c false if either
* Value offset exceeds the document size.
*/
bool pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra);
/** \brief Return whether there are any errors.
* \return \c true if there are no errors to report \c false if
* errors have occurred.
*/
bool good() const;
private:
enum TokenType {
tokenEndOfStream = 0,
tokenObjectBegin,
tokenObjectEnd,
tokenArrayBegin,
tokenArrayEnd,
tokenString,
tokenNumber,
tokenTrue,
tokenFalse,
tokenNull,
tokenArraySeparator,
tokenMemberSeparator,
tokenComment,
tokenError
};
class Token {
public:
TokenType type_;
Location start_;
Location end_;
};
class ErrorInfo {
public:
Token token_;
JSONCPP_STRING message_;
Location extra_;
};
typedef std::deque<ErrorInfo> Errors;
bool readToken(Token& token);
void skipSpaces();
bool match(Location pattern, int patternLength);
bool readComment();
bool readCStyleComment();
bool readCppStyleComment();
bool readString();
void readNumber();
bool readValue();
bool readObject(Token& token);
bool readArray(Token& token);
bool decodeNumber(Token& token);
bool decodeNumber(Token& token, Value& decoded);
bool decodeString(Token& token);
bool decodeString(Token& token, JSONCPP_STRING& decoded);
bool decodeDouble(Token& token);
bool decodeDouble(Token& token, Value& decoded);
bool decodeUnicodeCodePoint(Token& token,
Location& current,
Location end,
unsigned int& unicode);
bool decodeUnicodeEscapeSequence(Token& token,
Location& current,
Location end,
unsigned int& unicode);
bool addError(const JSONCPP_STRING& message, Token& token, Location extra = 0);
bool recoverFromError(TokenType skipUntilToken);
bool addErrorAndRecover(const JSONCPP_STRING& message,
Token& token,
TokenType skipUntilToken);
void skipUntilSpace();
Value& currentValue();
Char getNextChar();
void
getLocationLineAndColumn(Location location, int& line, int& column) const;
JSONCPP_STRING getLocationLineAndColumn(Location location) const;
void addComment(Location begin, Location end, CommentPlacement placement);
void skipCommentTokens(Token& token);
typedef std::stack<Value*> Nodes;
Nodes nodes_;
Errors errors_;
JSONCPP_STRING document_;
Location begin_;
Location end_;
Location current_;
Location lastValueEnd_;
Value* lastValue_;
JSONCPP_STRING commentsBefore_;
Features features_;
bool collectComments_;
}; // Reader
/** Interface for reading JSON from a char array.
*/
class JSON_API CharReader {
public:
virtual ~CharReader() {}
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
document.
* The document must be a UTF-8 encoded string containing the document to read.
*
* \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the
document to read.
* \param endDoc Pointer on the end of the UTF-8 encoded string of the
document to read.
* Must be >= beginDoc.
* \param root [out] Contains the root value of the document if it was
* successfully parsed.
* \param errs [out] Formatted error messages (if not NULL)
* a user friendly string that lists errors in the parsed
* document.
* \return \c true if the document was successfully parsed, \c false if an
error occurred.
*/
virtual bool parse(
char const* beginDoc, char const* endDoc,
Value* root, JSONCPP_STRING* errs) = 0;
class JSON_API Factory {
public:
virtual ~Factory() {}
/** \brief Allocate a CharReader via operator new().
* \throw std::exception if something goes wrong (e.g. invalid settings)
*/
virtual CharReader* newCharReader() const = 0;
}; // Factory
}; // CharReader
/** \brief Build a CharReader implementation.
Usage:
\code
using namespace Json;
CharReaderBuilder builder;
builder["collectComments"] = false;
Value value;
JSONCPP_STRING errs;
bool ok = parseFromStream(builder, std::cin, &value, &errs);
\endcode
*/
class JSON_API CharReaderBuilder : public CharReader::Factory {
public:
// Note: We use a Json::Value so that we can add data-members to this class
// without a major version bump.
/** Configuration of this builder.
These are case-sensitive.
Available settings (case-sensitive):
- `"collectComments": false or true`
- true to collect comment and allow writing them
back during serialization, false to discard comments.
This parameter is ignored if allowComments is false.
- `"allowComments": false or true`
- true if comments are allowed.
- `"strictRoot": false or true`
- true if root must be either an array or an object value
- `"allowDroppedNullPlaceholders": false or true`
- true if dropped null placeholders are allowed. (See StreamWriterBuilder.)
- `"allowNumericKeys": false or true`
- true if numeric object keys are allowed.
- `"allowSingleQuotes": false or true`
- true if '' are allowed for strings (both keys and values)
- `"stackLimit": integer`
- Exceeding stackLimit (recursive depth of `readValue()`) will
cause an exception.
- This is a security issue (seg-faults caused by deeply nested JSON),
so the default is low.
- `"failIfExtra": false or true`
- If true, `parse()` returns false when extra non-whitespace trails
the JSON value in the input string.
- `"rejectDupKeys": false or true`
- If true, `parse()` returns false when a key is duplicated within an object.
- `"allowSpecialFloats": false or true`
- If true, special float values (NaNs and infinities) are allowed
and their values are lossfree restorable.
You can examine 'settings_` yourself
to see the defaults. You can also write and read them just like any
JSON Value.
\sa setDefaults()
*/
Json::Value settings_;
CharReaderBuilder();
~CharReaderBuilder() JSONCPP_OVERRIDE;
CharReader* newCharReader() const JSONCPP_OVERRIDE;
/** \return true if 'settings' are legal and consistent;
* otherwise, indicate bad settings via 'invalid'.
*/
bool validate(Json::Value* invalid) const;
/** A simple way to update a specific setting.
*/
Value& operator[](JSONCPP_STRING key);
/** Called by ctor, but you can use this to reset settings_.
* \pre 'settings' != NULL (but Json::null is fine)
* \remark Defaults:
* \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults
*/
static void setDefaults(Json::Value* settings);
/** Same as old Features::strictMode().
* \pre 'settings' != NULL (but Json::null is fine)
* \remark Defaults:
* \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode
*/
static void strictMode(Json::Value* settings);
};
/** Consume entire stream and use its begin/end.
* Someday we might have a real StreamReader, but for now this
* is convenient.
*/
bool JSON_API parseFromStream(
CharReader::Factory const&,
JSONCPP_ISTREAM&,
Value* root, std::string* errs);
/** \brief Read from 'sin' into 'root'.
Always keep comments from the input JSON.
This can be used to read a file into a particular sub-object.
For example:
\code
Json::Value root;
cin >> root["dir"]["file"];
cout << root;
\endcode
Result:
\verbatim
{
"dir": {
"file": {
// The input stream JSON would be nested here.
}
}
}
\endverbatim
\throw std::exception on parse error.
\see Json::operator<<()
*/
JSON_API JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM&, Value&);
} // namespace Json
#pragma pack(pop)
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma warning(pop)
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#endif // CPPTL_JSON_READER_H_INCLUDED

888
extern/jsoncpp/include/json/value.h vendored Normal file
View File

@@ -0,0 +1,888 @@
// Copyright 2007-2010 Baptiste Lepilleur
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
#ifndef CPPTL_JSON_H_INCLUDED
#define CPPTL_JSON_H_INCLUDED
#if !defined(JSON_IS_AMALGAMATION)
#include "forwards.h"
#endif // if !defined(JSON_IS_AMALGAMATION)
#include <string>
#include <vector>
#include <exception>
#ifndef JSON_USE_CPPTL_SMALLMAP
#include <map>
#else
#include <cpptl/smallmap.h>
#endif
#ifdef JSON_USE_CPPTL
#include <cpptl/forwards.h>
#endif
//Conditional NORETURN attribute on the throw functions would:
// a) suppress false positives from static code analysis
// b) possibly improve optimization opportunities.
#if !defined(JSONCPP_NORETURN)
# if defined(_MSC_VER)
# define JSONCPP_NORETURN __declspec(noreturn)
# elif defined(__GNUC__)
# define JSONCPP_NORETURN __attribute__ ((__noreturn__))
# else
# define JSONCPP_NORETURN
# endif
#endif
// Disable warning C4251: <data member>: <type> needs to have dll-interface to
// be used by...
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma warning(push)
#pragma warning(disable : 4251)
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma pack(push, 8)
/** \brief JSON (JavaScript Object Notation).
*/
namespace Json {
/** Base class for all exceptions we throw.
*
* We use nothing but these internally. Of course, STL can throw others.
*/
class JSON_API Exception : public std::exception {
public:
Exception(JSONCPP_STRING const& msg);
~Exception() JSONCPP_NOEXCEPT JSONCPP_OVERRIDE;
char const* what() const JSONCPP_NOEXCEPT JSONCPP_OVERRIDE;
protected:
JSONCPP_STRING msg_;
};
/** Exceptions which the user cannot easily avoid.
*
* E.g. out-of-memory (when we use malloc), stack-overflow, malicious input
*
* \remark derived from Json::Exception
*/
class JSON_API RuntimeError : public Exception {
public:
RuntimeError(JSONCPP_STRING const& msg);
};
/** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros.
*
* These are precondition-violations (user bugs) and internal errors (our bugs).
*
* \remark derived from Json::Exception
*/
class JSON_API LogicError : public Exception {
public:
LogicError(JSONCPP_STRING const& msg);
};
/// used internally
JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg);
/// used internally
JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg);
/** \brief Type of the value held by a Value object.
*/
enum ValueType {
nullValue = 0, ///< 'null' value
intValue, ///< signed integer value
uintValue, ///< unsigned integer value
realValue, ///< double value
stringValue, ///< UTF-8 string value
booleanValue, ///< bool value
arrayValue, ///< array value (ordered list)
objectValue ///< object value (collection of name/value pairs).
};
enum CommentPlacement {
commentBefore = 0, ///< a comment placed on the line before a value
commentAfterOnSameLine, ///< a comment just after a value on the same line
commentAfter, ///< a comment on the line after a value (only make sense for
/// root value)
numberOfCommentPlacement
};
//# ifdef JSON_USE_CPPTL
// typedef CppTL::AnyEnumerator<const char *> EnumMemberNames;
// typedef CppTL::AnyEnumerator<const Value &> EnumValues;
//# endif
/** \brief Lightweight wrapper to tag static string.
*
* Value constructor and objectValue member assignement takes advantage of the
* StaticString and avoid the cost of string duplication when storing the
* string or the member name.
*
* Example of usage:
* \code
* Json::Value aValue( StaticString("some text") );
* Json::Value object;
* static const StaticString code("code");
* object[code] = 1234;
* \endcode
*/
class JSON_API StaticString {
public:
explicit StaticString(const char* czstring) : c_str_(czstring) {}
operator const char*() const { return c_str_; }
const char* c_str() const { return c_str_; }
private:
const char* c_str_;
};
/** \brief Represents a <a HREF="http://www.json.org">JSON</a> value.
*
* This class is a discriminated union wrapper that can represents a:
* - signed integer [range: Value::minInt - Value::maxInt]
* - unsigned integer (range: 0 - Value::maxUInt)
* - double
* - UTF-8 string
* - boolean
* - 'null'
* - an ordered list of Value
* - collection of name/value pairs (javascript object)
*
* The type of the held value is represented by a #ValueType and
* can be obtained using type().
*
* Values of an #objectValue or #arrayValue can be accessed using operator[]()
* methods.
* Non-const methods will automatically create the a #nullValue element
* if it does not exist.
* The sequence of an #arrayValue will be automatically resized and initialized
* with #nullValue. resize() can be used to enlarge or truncate an #arrayValue.
*
* The get() methods can be used to obtain default value in the case the
* required element does not exist.
*
* It is possible to iterate over the list of a #objectValue values using
* the getMemberNames() method.
*
* \note #Value string-length fit in size_t, but keys must be < 2^30.
* (The reason is an implementation detail.) A #CharReader will raise an
* exception if a bound is exceeded to avoid security holes in your app,
* but the Value API does *not* check bounds. That is the responsibility
* of the caller.
*/
class JSON_API Value {
friend class ValueIteratorBase;
public:
typedef std::vector<JSONCPP_STRING> Members;
typedef ValueIterator iterator;
typedef ValueConstIterator const_iterator;
typedef Json::UInt UInt;
typedef Json::Int Int;
#if defined(JSON_HAS_INT64)
typedef Json::UInt64 UInt64;
typedef Json::Int64 Int64;
#endif // defined(JSON_HAS_INT64)
typedef Json::LargestInt LargestInt;
typedef Json::LargestUInt LargestUInt;
typedef Json::ArrayIndex ArrayIndex;
static const Value& null; ///< We regret this reference to a global instance; prefer the simpler Value().
static const Value& nullRef; ///< just a kludge for binary-compatibility; same as null
static Value const& nullSingleton(); ///< Prefer this to null or nullRef.
/// Minimum signed integer value that can be stored in a Json::Value.
static const LargestInt minLargestInt;
/// Maximum signed integer value that can be stored in a Json::Value.
static const LargestInt maxLargestInt;
/// Maximum unsigned integer value that can be stored in a Json::Value.
static const LargestUInt maxLargestUInt;
/// Minimum signed int value that can be stored in a Json::Value.
static const Int minInt;
/// Maximum signed int value that can be stored in a Json::Value.
static const Int maxInt;
/// Maximum unsigned int value that can be stored in a Json::Value.
static const UInt maxUInt;
#if defined(JSON_HAS_INT64)
/// Minimum signed 64 bits int value that can be stored in a Json::Value.
static const Int64 minInt64;
/// Maximum signed 64 bits int value that can be stored in a Json::Value.
static const Int64 maxInt64;
/// Maximum unsigned 64 bits int value that can be stored in a Json::Value.
static const UInt64 maxUInt64;
#endif // defined(JSON_HAS_INT64)
private:
#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
class CZString {
public:
enum DuplicationPolicy {
noDuplication = 0,
duplicate,
duplicateOnCopy
};
CZString(ArrayIndex index);
CZString(char const* str, unsigned length, DuplicationPolicy allocate);
CZString(CZString const& other);
#if JSON_HAS_RVALUE_REFERENCES
CZString(CZString&& other);
#endif
~CZString();
CZString& operator=(const CZString& other);
#if JSON_HAS_RVALUE_REFERENCES
CZString& operator=(CZString&& other);
#endif
bool operator<(CZString const& other) const;
bool operator==(CZString const& other) const;
ArrayIndex index() const;
//const char* c_str() const; ///< \deprecated
char const* data() const;
unsigned length() const;
bool isStaticString() const;
private:
void swap(CZString& other);
struct StringStorage {
unsigned policy_: 2;
unsigned length_: 30; // 1GB max
};
char const* cstr_; // actually, a prefixed string, unless policy is noDup
union {
ArrayIndex index_;
StringStorage storage_;
};
};
public:
#ifndef JSON_USE_CPPTL_SMALLMAP
typedef std::map<CZString, Value> ObjectValues;
#else
typedef CppTL::SmallMap<CZString, Value> ObjectValues;
#endif // ifndef JSON_USE_CPPTL_SMALLMAP
#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
public:
/** \brief Create a default Value of the given type.
This is a very useful constructor.
To create an empty array, pass arrayValue.
To create an empty object, pass objectValue.
Another Value can then be set to this one by assignment.
This is useful since clear() and resize() will not alter types.
Examples:
\code
Json::Value null_value; // null
Json::Value arr_value(Json::arrayValue); // []
Json::Value obj_value(Json::objectValue); // {}
\endcode
*/
Value(ValueType type = nullValue);
Value(Int value);
Value(UInt value);
#if defined(JSON_HAS_INT64)
Value(Int64 value);
Value(UInt64 value);
#endif // if defined(JSON_HAS_INT64)
Value(double value);
Value(const char* value); ///< Copy til first 0. (NULL causes to seg-fault.)
Value(const char* begin, const char* end); ///< Copy all, incl zeroes.
/** \brief Constructs a value from a static string.
* Like other value string constructor but do not duplicate the string for
* internal storage. The given string must remain alive after the call to this
* constructor.
* \note This works only for null-terminated strings. (We cannot change the
* size of this class, so we have nowhere to store the length,
* which might be computed later for various operations.)
*
* Example of usage:
* \code
* static StaticString foo("some text");
* Json::Value aValue(foo);
* \endcode
*/
Value(const StaticString& value);
Value(const JSONCPP_STRING& value); ///< Copy data() til size(). Embedded zeroes too.
#ifdef JSON_USE_CPPTL
Value(const CppTL::ConstString& value);
#endif
Value(bool value);
/// Deep copy.
Value(const Value& other);
#if JSON_HAS_RVALUE_REFERENCES
/// Move constructor
Value(Value&& other);
#endif
~Value();
/// Deep copy, then swap(other).
/// \note Over-write existing comments. To preserve comments, use #swapPayload().
Value& operator=(const Value& other);
#if JSON_HAS_RVALUE_REFERENCES
Value& operator=(Value&& other);
#endif
/// Swap everything.
void swap(Value& other);
/// Swap values but leave comments and source offsets in place.
void swapPayload(Value& other);
/// copy everything.
void copy(const Value& other);
/// copy values but leave comments and source offsets in place.
void copyPayload(const Value& other);
ValueType type() const;
/// Compare payload only, not comments etc.
bool operator<(const Value& other) const;
bool operator<=(const Value& other) const;
bool operator>=(const Value& other) const;
bool operator>(const Value& other) const;
bool operator==(const Value& other) const;
bool operator!=(const Value& other) const;
int compare(const Value& other) const;
const char* asCString() const; ///< Embedded zeroes could cause you trouble!
#if JSONCPP_USING_SECURE_MEMORY
unsigned getCStringLength() const; //Allows you to understand the length of the CString
#endif
JSONCPP_STRING asString() const; ///< Embedded zeroes are possible.
/** Get raw char* of string-value.
* \return false if !string. (Seg-fault if str or end are NULL.)
*/
bool getString(
char const** begin, char const** end) const;
#ifdef JSON_USE_CPPTL
CppTL::ConstString asConstString() const;
#endif
Int asInt() const;
UInt asUInt() const;
#if defined(JSON_HAS_INT64)
Int64 asInt64() const;
UInt64 asUInt64() const;
#endif // if defined(JSON_HAS_INT64)
LargestInt asLargestInt() const;
LargestUInt asLargestUInt() const;
float asFloat() const;
double asDouble() const;
bool asBool() const;
bool isNull() const;
bool isBool() const;
bool isInt() const;
bool isInt64() const;
bool isUInt() const;
bool isUInt64() const;
bool isIntegral() const;
bool isDouble() const;
bool isNumeric() const;
bool isString() const;
bool isArray() const;
bool isObject() const;
bool isConvertibleTo(ValueType other) const;
/// Number of values in array or object
ArrayIndex size() const;
/// \brief Return true if empty array, empty object, or null;
/// otherwise, false.
bool empty() const;
/// Return isNull()
bool operator!() const;
/// Remove all object members and array elements.
/// \pre type() is arrayValue, objectValue, or nullValue
/// \post type() is unchanged
void clear();
/// Resize the array to size elements.
/// New elements are initialized to null.
/// May only be called on nullValue or arrayValue.
/// \pre type() is arrayValue or nullValue
/// \post type() is arrayValue
void resize(ArrayIndex size);
/// Access an array element (zero based index ).
/// If the array contains less than index element, then null value are
/// inserted
/// in the array so that its size is index+1.
/// (You may need to say 'value[0u]' to get your compiler to distinguish
/// this from the operator[] which takes a string.)
Value& operator[](ArrayIndex index);
/// Access an array element (zero based index ).
/// If the array contains less than index element, then null value are
/// inserted
/// in the array so that its size is index+1.
/// (You may need to say 'value[0u]' to get your compiler to distinguish
/// this from the operator[] which takes a string.)
Value& operator[](int index);
/// Access an array element (zero based index )
/// (You may need to say 'value[0u]' to get your compiler to distinguish
/// this from the operator[] which takes a string.)
const Value& operator[](ArrayIndex index) const;
/// Access an array element (zero based index )
/// (You may need to say 'value[0u]' to get your compiler to distinguish
/// this from the operator[] which takes a string.)
const Value& operator[](int index) const;
/// If the array contains at least index+1 elements, returns the element
/// value,
/// otherwise returns defaultValue.
Value get(ArrayIndex index, const Value& defaultValue) const;
/// Return true if index < size().
bool isValidIndex(ArrayIndex index) const;
/// \brief Append value to array at the end.
///
/// Equivalent to jsonvalue[jsonvalue.size()] = value;
Value& append(const Value& value);
#if JSON_HAS_RVALUE_REFERENCES
Value& append(Value&& value);
#endif
/// Access an object value by name, create a null member if it does not exist.
/// \note Because of our implementation, keys are limited to 2^30 -1 chars.
/// Exceeding that will cause an exception.
Value& operator[](const char* key);
/// Access an object value by name, returns null if there is no member with
/// that name.
const Value& operator[](const char* key) const;
/// Access an object value by name, create a null member if it does not exist.
/// \param key may contain embedded nulls.
Value& operator[](const JSONCPP_STRING& key);
/// Access an object value by name, returns null if there is no member with
/// that name.
/// \param key may contain embedded nulls.
const Value& operator[](const JSONCPP_STRING& key) const;
/** \brief Access an object value by name, create a null member if it does not
exist.
* If the object has no entry for that name, then the member name used to store
* the new entry is not duplicated.
* Example of use:
* \code
* Json::Value object;
* static const StaticString code("code");
* object[code] = 1234;
* \endcode
*/
Value& operator[](const StaticString& key);
#ifdef JSON_USE_CPPTL
/// Access an object value by name, create a null member if it does not exist.
Value& operator[](const CppTL::ConstString& key);
/// Access an object value by name, returns null if there is no member with
/// that name.
const Value& operator[](const CppTL::ConstString& key) const;
#endif
/// Return the member named key if it exist, defaultValue otherwise.
/// \note deep copy
Value get(const char* key, const Value& defaultValue) const;
/// Return the member named key if it exist, defaultValue otherwise.
/// \note deep copy
/// \note key may contain embedded nulls.
Value get(const char* begin, const char* end, const Value& defaultValue) const;
/// Return the member named key if it exist, defaultValue otherwise.
/// \note deep copy
/// \param key may contain embedded nulls.
Value get(const JSONCPP_STRING& key, const Value& defaultValue) const;
#ifdef JSON_USE_CPPTL
/// Return the member named key if it exist, defaultValue otherwise.
/// \note deep copy
Value get(const CppTL::ConstString& key, const Value& defaultValue) const;
#endif
/// Most general and efficient version of isMember()const, get()const,
/// and operator[]const
/// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30
Value const* find(char const* begin, char const* end) const;
/// Most general and efficient version of object-mutators.
/// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30
/// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue.
Value const* demand(char const* begin, char const* end);
/// \brief Remove and return the named member.
///
/// Do nothing if it did not exist.
/// \return the removed Value, or null.
/// \pre type() is objectValue or nullValue
/// \post type() is unchanged
/// \deprecated
Value removeMember(const char* key);
/// Same as removeMember(const char*)
/// \param key may contain embedded nulls.
/// \deprecated
Value removeMember(const JSONCPP_STRING& key);
/// Same as removeMember(const char* begin, const char* end, Value* removed),
/// but 'key' is null-terminated.
bool removeMember(const char* key, Value* removed);
/** \brief Remove the named map member.
Update 'removed' iff removed.
\param key may contain embedded nulls.
\return true iff removed (no exceptions)
*/
bool removeMember(JSONCPP_STRING const& key, Value* removed);
/// Same as removeMember(JSONCPP_STRING const& key, Value* removed)
bool removeMember(const char* begin, const char* end, Value* removed);
/** \brief Remove the indexed array element.
O(n) expensive operations.
Update 'removed' iff removed.
\return true iff removed (no exceptions)
*/
bool removeIndex(ArrayIndex i, Value* removed);
/// Return true if the object has a member named key.
/// \note 'key' must be null-terminated.
bool isMember(const char* key) const;
/// Return true if the object has a member named key.
/// \param key may contain embedded nulls.
bool isMember(const JSONCPP_STRING& key) const;
/// Same as isMember(JSONCPP_STRING const& key)const
bool isMember(const char* begin, const char* end) const;
#ifdef JSON_USE_CPPTL
/// Return true if the object has a member named key.
bool isMember(const CppTL::ConstString& key) const;
#endif
/// \brief Return a list of the member names.
///
/// If null, return an empty list.
/// \pre type() is objectValue or nullValue
/// \post if type() was nullValue, it remains nullValue
Members getMemberNames() const;
//# ifdef JSON_USE_CPPTL
// EnumMemberNames enumMemberNames() const;
// EnumValues enumValues() const;
//# endif
/// \deprecated Always pass len.
JSONCPP_DEPRECATED("Use setComment(JSONCPP_STRING const&) instead.")
void setComment(const char* comment, CommentPlacement placement);
/// Comments must be //... or /* ... */
void setComment(const char* comment, size_t len, CommentPlacement placement);
/// Comments must be //... or /* ... */
void setComment(const JSONCPP_STRING& comment, CommentPlacement placement);
bool hasComment(CommentPlacement placement) const;
/// Include delimiters and embedded newlines.
JSONCPP_STRING getComment(CommentPlacement placement) const;
JSONCPP_STRING toStyledString() const;
const_iterator begin() const;
const_iterator end() const;
iterator begin();
iterator end();
// Accessors for the [start, limit) range of bytes within the JSON text from
// which this value was parsed, if any.
void setOffsetStart(ptrdiff_t start);
void setOffsetLimit(ptrdiff_t limit);
ptrdiff_t getOffsetStart() const;
ptrdiff_t getOffsetLimit() const;
private:
void initBasic(ValueType type, bool allocated = false);
Value& resolveReference(const char* key);
Value& resolveReference(const char* key, const char* end);
struct CommentInfo {
CommentInfo();
~CommentInfo();
void setComment(const char* text, size_t len);
char* comment_;
};
// struct MemberNamesTransform
//{
// typedef const char *result_type;
// const char *operator()( const CZString &name ) const
// {
// return name.c_str();
// }
//};
union ValueHolder {
LargestInt int_;
LargestUInt uint_;
double real_;
bool bool_;
char* string_; // actually ptr to unsigned, followed by str, unless !allocated_
ObjectValues* map_;
} value_;
ValueType type_ : 8;
unsigned int allocated_ : 1; // Notes: if declared as bool, bitfield is useless.
// If not allocated_, string_ must be null-terminated.
CommentInfo* comments_;
// [start, limit) byte offsets in the source JSON text from which this Value
// was extracted.
ptrdiff_t start_;
ptrdiff_t limit_;
};
/** \brief Experimental and untested: represents an element of the "path" to
* access a node.
*/
class JSON_API PathArgument {
public:
friend class Path;
PathArgument();
PathArgument(ArrayIndex index);
PathArgument(const char* key);
PathArgument(const JSONCPP_STRING& key);
private:
enum Kind {
kindNone = 0,
kindIndex,
kindKey
};
JSONCPP_STRING key_;
ArrayIndex index_;
Kind kind_;
};
/** \brief Experimental and untested: represents a "path" to access a node.
*
* Syntax:
* - "." => root node
* - ".[n]" => elements at index 'n' of root node (an array value)
* - ".name" => member named 'name' of root node (an object value)
* - ".name1.name2.name3"
* - ".[0][1][2].name1[3]"
* - ".%" => member name is provided as parameter
* - ".[%]" => index is provied as parameter
*/
class JSON_API Path {
public:
Path(const JSONCPP_STRING& path,
const PathArgument& a1 = PathArgument(),
const PathArgument& a2 = PathArgument(),
const PathArgument& a3 = PathArgument(),
const PathArgument& a4 = PathArgument(),
const PathArgument& a5 = PathArgument());
const Value& resolve(const Value& root) const;
Value resolve(const Value& root, const Value& defaultValue) const;
/// Creates the "path" to access the specified node and returns a reference on
/// the node.
Value& make(Value& root) const;
private:
typedef std::vector<const PathArgument*> InArgs;
typedef std::vector<PathArgument> Args;
void makePath(const JSONCPP_STRING& path, const InArgs& in);
void addPathInArg(const JSONCPP_STRING& path,
const InArgs& in,
InArgs::const_iterator& itInArg,
PathArgument::Kind kind);
void invalidPath(const JSONCPP_STRING& path, int location);
Args args_;
};
/** \brief base class for Value iterators.
*
*/
class JSON_API ValueIteratorBase {
public:
typedef std::bidirectional_iterator_tag iterator_category;
typedef unsigned int size_t;
typedef int difference_type;
typedef ValueIteratorBase SelfType;
bool operator==(const SelfType& other) const { return isEqual(other); }
bool operator!=(const SelfType& other) const { return !isEqual(other); }
difference_type operator-(const SelfType& other) const {
return other.computeDistance(*this);
}
/// Return either the index or the member name of the referenced value as a
/// Value.
Value key() const;
/// Return the index of the referenced Value, or -1 if it is not an arrayValue.
UInt index() const;
/// Return the member name of the referenced Value, or "" if it is not an
/// objectValue.
/// \note Avoid `c_str()` on result, as embedded zeroes are possible.
JSONCPP_STRING name() const;
/// Return the member name of the referenced Value. "" if it is not an
/// objectValue.
/// \deprecated This cannot be used for UTF-8 strings, since there can be embedded nulls.
JSONCPP_DEPRECATED("Use `key = name();` instead.")
char const* memberName() const;
/// Return the member name of the referenced Value, or NULL if it is not an
/// objectValue.
/// \note Better version than memberName(). Allows embedded nulls.
char const* memberName(char const** end) const;
protected:
Value& deref() const;
void increment();
void decrement();
difference_type computeDistance(const SelfType& other) const;
bool isEqual(const SelfType& other) const;
void copy(const SelfType& other);
private:
Value::ObjectValues::iterator current_;
// Indicates that iterator is for a null value.
bool isNull_;
public:
// For some reason, BORLAND needs these at the end, rather
// than earlier. No idea why.
ValueIteratorBase();
explicit ValueIteratorBase(const Value::ObjectValues::iterator& current);
};
/** \brief const iterator for object and array value.
*
*/
class JSON_API ValueConstIterator : public ValueIteratorBase {
friend class Value;
public:
typedef const Value value_type;
//typedef unsigned int size_t;
//typedef int difference_type;
typedef const Value& reference;
typedef const Value* pointer;
typedef ValueConstIterator SelfType;
ValueConstIterator();
ValueConstIterator(ValueIterator const& other);
private:
/*! \internal Use by Value to create an iterator.
*/
explicit ValueConstIterator(const Value::ObjectValues::iterator& current);
public:
SelfType& operator=(const ValueIteratorBase& other);
SelfType operator++(int) {
SelfType temp(*this);
++*this;
return temp;
}
SelfType operator--(int) {
SelfType temp(*this);
--*this;
return temp;
}
SelfType& operator--() {
decrement();
return *this;
}
SelfType& operator++() {
increment();
return *this;
}
reference operator*() const { return deref(); }
pointer operator->() const { return &deref(); }
};
/** \brief Iterator for object and array value.
*/
class JSON_API ValueIterator : public ValueIteratorBase {
friend class Value;
public:
typedef Value value_type;
typedef unsigned int size_t;
typedef int difference_type;
typedef Value& reference;
typedef Value* pointer;
typedef ValueIterator SelfType;
ValueIterator();
explicit ValueIterator(const ValueConstIterator& other);
ValueIterator(const ValueIterator& other);
private:
/*! \internal Use by Value to create an iterator.
*/
explicit ValueIterator(const Value::ObjectValues::iterator& current);
public:
SelfType& operator=(const SelfType& other);
SelfType operator++(int) {
SelfType temp(*this);
++*this;
return temp;
}
SelfType operator--(int) {
SelfType temp(*this);
--*this;
return temp;
}
SelfType& operator--() {
decrement();
return *this;
}
SelfType& operator++() {
increment();
return *this;
}
reference operator*() const { return deref(); }
pointer operator->() const { return &deref(); }
};
} // namespace Json
namespace std {
/// Specialize std::swap() for Json::Value.
template<>
inline void swap(Json::Value& a, Json::Value& b) { a.swap(b); }
}
#pragma pack(pop)
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma warning(pop)
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#endif // CPPTL_JSON_H_INCLUDED

20
extern/jsoncpp/include/json/version.h vendored Normal file
View File

@@ -0,0 +1,20 @@
// DO NOT EDIT. This file (and "version") is generated by CMake.
// Run CMake configure step to update it.
#ifndef JSON_VERSION_H_INCLUDED
# define JSON_VERSION_H_INCLUDED
# define JSONCPP_VERSION_STRING "1.8.1"
# define JSONCPP_VERSION_MAJOR 1
# define JSONCPP_VERSION_MINOR 8
# define JSONCPP_VERSION_PATCH 1
# define JSONCPP_VERSION_QUALIFIER
# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8))
#ifdef JSONCPP_USING_SECURE_MEMORY
#undef JSONCPP_USING_SECURE_MEMORY
#endif
#define JSONCPP_USING_SECURE_MEMORY 0
// If non-zero, the library zeroes any memory that it has allocated before
// it frees its memory.
#endif // JSON_VERSION_H_INCLUDED

335
extern/jsoncpp/include/json/writer.h vendored Normal file
View File

@@ -0,0 +1,335 @@
// Copyright 2007-2010 Baptiste Lepilleur
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
#ifndef JSON_WRITER_H_INCLUDED
#define JSON_WRITER_H_INCLUDED
#if !defined(JSON_IS_AMALGAMATION)
#include "value.h"
#endif // if !defined(JSON_IS_AMALGAMATION)
#include <vector>
#include <string>
#include <ostream>
// Disable warning C4251: <data member>: <type> needs to have dll-interface to
// be used by...
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma warning(push)
#pragma warning(disable : 4251)
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma pack(push, 8)
namespace Json {
class Value;
/**
Usage:
\code
using namespace Json;
void writeToStdout(StreamWriter::Factory const& factory, Value const& value) {
std::unique_ptr<StreamWriter> const writer(
factory.newStreamWriter());
writer->write(value, &std::cout);
std::cout << std::endl; // add lf and flush
}
\endcode
*/
class JSON_API StreamWriter {
protected:
JSONCPP_OSTREAM* sout_; // not owned; will not delete
public:
StreamWriter();
virtual ~StreamWriter();
/** Write Value into document as configured in sub-class.
Do not take ownership of sout, but maintain a reference during function.
\pre sout != NULL
\return zero on success (For now, we always return zero, so check the stream instead.)
\throw std::exception possibly, depending on configuration
*/
virtual int write(Value const& root, JSONCPP_OSTREAM* sout) = 0;
/** \brief A simple abstract factory.
*/
class JSON_API Factory {
public:
virtual ~Factory();
/** \brief Allocate a CharReader via operator new().
* \throw std::exception if something goes wrong (e.g. invalid settings)
*/
virtual StreamWriter* newStreamWriter() const = 0;
}; // Factory
}; // StreamWriter
/** \brief Write into stringstream, then return string, for convenience.
* A StreamWriter will be created from the factory, used, and then deleted.
*/
JSONCPP_STRING JSON_API writeString(StreamWriter::Factory const& factory, Value const& root);
/** \brief Build a StreamWriter implementation.
Usage:
\code
using namespace Json;
Value value = ...;
StreamWriterBuilder builder;
builder["commentStyle"] = "None";
builder["indentation"] = " "; // or whatever you like
std::unique_ptr<Json::StreamWriter> writer(
builder.newStreamWriter());
writer->write(value, &std::cout);
std::cout << std::endl; // add lf and flush
\endcode
*/
class JSON_API StreamWriterBuilder : public StreamWriter::Factory {
public:
// Note: We use a Json::Value so that we can add data-members to this class
// without a major version bump.
/** Configuration of this builder.
Available settings (case-sensitive):
- "commentStyle": "None" or "All"
- "indentation": "<anything>"
- "enableYAMLCompatibility": false or true
- slightly change the whitespace around colons
- "dropNullPlaceholders": false or true
- Drop the "null" string from the writer's output for nullValues.
Strictly speaking, this is not valid JSON. But when the output is being
fed to a browser's Javascript, it makes for smaller output and the
browser can handle the output just fine.
- "useSpecialFloats": false or true
- If true, outputs non-finite floating point values in the following way:
NaN values as "NaN", positive infinity as "Infinity", and negative infinity
as "-Infinity".
You can examine 'settings_` yourself
to see the defaults. You can also write and read them just like any
JSON Value.
\sa setDefaults()
*/
Json::Value settings_;
StreamWriterBuilder();
~StreamWriterBuilder() JSONCPP_OVERRIDE;
/**
* \throw std::exception if something goes wrong (e.g. invalid settings)
*/
StreamWriter* newStreamWriter() const JSONCPP_OVERRIDE;
/** \return true if 'settings' are legal and consistent;
* otherwise, indicate bad settings via 'invalid'.
*/
bool validate(Json::Value* invalid) const;
/** A simple way to update a specific setting.
*/
Value& operator[](JSONCPP_STRING key);
/** Called by ctor, but you can use this to reset settings_.
* \pre 'settings' != NULL (but Json::null is fine)
* \remark Defaults:
* \snippet src/lib_json/json_writer.cpp StreamWriterBuilderDefaults
*/
static void setDefaults(Json::Value* settings);
};
/** \brief Abstract class for writers.
* \deprecated Use StreamWriter. (And really, this is an implementation detail.)
*/
class JSON_API Writer {
public:
virtual ~Writer();
virtual JSONCPP_STRING write(const Value& root) = 0;
};
/** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format
*without formatting (not human friendly).
*
* The JSON document is written in a single line. It is not intended for 'human'
*consumption,
* but may be usefull to support feature such as RPC where bandwith is limited.
* \sa Reader, Value
* \deprecated Use StreamWriterBuilder.
*/
class JSON_API FastWriter : public Writer {
public:
FastWriter();
~FastWriter() JSONCPP_OVERRIDE {}
void enableYAMLCompatibility();
/** \brief Drop the "null" string from the writer's output for nullValues.
* Strictly speaking, this is not valid JSON. But when the output is being
* fed to a browser's Javascript, it makes for smaller output and the
* browser can handle the output just fine.
*/
void dropNullPlaceholders();
void omitEndingLineFeed();
public: // overridden from Writer
JSONCPP_STRING write(const Value& root) JSONCPP_OVERRIDE;
private:
void writeValue(const Value& value);
JSONCPP_STRING document_;
bool yamlCompatiblityEnabled_;
bool dropNullPlaceholders_;
bool omitEndingLineFeed_;
};
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a
*human friendly way.
*
* The rules for line break and indent are as follow:
* - Object value:
* - if empty then print {} without indent and line break
* - if not empty the print '{', line break & indent, print one value per
*line
* and then unindent and line break and print '}'.
* - Array value:
* - if empty then print [] without indent and line break
* - if the array contains no object value, empty array or some other value
*types,
* and all the values fit on one lines, then print the array on a single
*line.
* - otherwise, it the values do not fit on one line, or the array contains
* object or non empty array, then print one value per line.
*
* If the Value have comments then they are outputed according to their
*#CommentPlacement.
*
* \sa Reader, Value, Value::setComment()
* \deprecated Use StreamWriterBuilder.
*/
class JSON_API StyledWriter : public Writer {
public:
StyledWriter();
~StyledWriter() JSONCPP_OVERRIDE {}
public: // overridden from Writer
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
* \param root Value to serialize.
* \return String containing the JSON document that represents the root value.
*/
JSONCPP_STRING write(const Value& root) JSONCPP_OVERRIDE;
private:
void writeValue(const Value& value);
void writeArrayValue(const Value& value);
bool isMultineArray(const Value& value);
void pushValue(const JSONCPP_STRING& value);
void writeIndent();
void writeWithIndent(const JSONCPP_STRING& value);
void indent();
void unindent();
void writeCommentBeforeValue(const Value& root);
void writeCommentAfterValueOnSameLine(const Value& root);
bool hasCommentForValue(const Value& value);
static JSONCPP_STRING normalizeEOL(const JSONCPP_STRING& text);
typedef std::vector<JSONCPP_STRING> ChildValues;
ChildValues childValues_;
JSONCPP_STRING document_;
JSONCPP_STRING indentString_;
unsigned int rightMargin_;
unsigned int indentSize_;
bool addChildValues_;
};
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a
human friendly way,
to a stream rather than to a string.
*
* The rules for line break and indent are as follow:
* - Object value:
* - if empty then print {} without indent and line break
* - if not empty the print '{', line break & indent, print one value per
line
* and then unindent and line break and print '}'.
* - Array value:
* - if empty then print [] without indent and line break
* - if the array contains no object value, empty array or some other value
types,
* and all the values fit on one lines, then print the array on a single
line.
* - otherwise, it the values do not fit on one line, or the array contains
* object or non empty array, then print one value per line.
*
* If the Value have comments then they are outputed according to their
#CommentPlacement.
*
* \param indentation Each level will be indented by this amount extra.
* \sa Reader, Value, Value::setComment()
* \deprecated Use StreamWriterBuilder.
*/
class JSON_API StyledStreamWriter {
public:
StyledStreamWriter(JSONCPP_STRING indentation = "\t");
~StyledStreamWriter() {}
public:
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
* \param out Stream to write to. (Can be ostringstream, e.g.)
* \param root Value to serialize.
* \note There is no point in deriving from Writer, since write() should not
* return a value.
*/
void write(JSONCPP_OSTREAM& out, const Value& root);
private:
void writeValue(const Value& value);
void writeArrayValue(const Value& value);
bool isMultineArray(const Value& value);
void pushValue(const JSONCPP_STRING& value);
void writeIndent();
void writeWithIndent(const JSONCPP_STRING& value);
void indent();
void unindent();
void writeCommentBeforeValue(const Value& root);
void writeCommentAfterValueOnSameLine(const Value& root);
bool hasCommentForValue(const Value& value);
static JSONCPP_STRING normalizeEOL(const JSONCPP_STRING& text);
typedef std::vector<JSONCPP_STRING> ChildValues;
ChildValues childValues_;
JSONCPP_OSTREAM* document_;
JSONCPP_STRING indentString_;
unsigned int rightMargin_;
JSONCPP_STRING indentation_;
bool addChildValues_ : 1;
bool indented_ : 1;
};
#if defined(JSON_HAS_INT64)
JSONCPP_STRING JSON_API valueToString(Int value);
JSONCPP_STRING JSON_API valueToString(UInt value);
#endif // if defined(JSON_HAS_INT64)
JSONCPP_STRING JSON_API valueToString(LargestInt value);
JSONCPP_STRING JSON_API valueToString(LargestUInt value);
JSONCPP_STRING JSON_API valueToString(double value);
JSONCPP_STRING JSON_API valueToString(bool value);
JSONCPP_STRING JSON_API valueToQuotedString(const char* value);
/// \brief Output using the StyledStreamWriter.
/// \see Json::operator>>()
JSON_API JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM&, const Value& root);
} // namespace Json
#pragma pack(pop)
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma warning(pop)
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#endif // JSON_WRITER_H_INCLUDED

80
extern/jsoncpp/src/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,80 @@
IF( CMAKE_COMPILER_IS_GNUCXX )
#Get compiler version.
EXECUTE_PROCESS( COMMAND ${CMAKE_CXX_COMPILER} -dumpversion
OUTPUT_VARIABLE GNUCXX_VERSION )
#-Werror=* was introduced -after- GCC 4.1.2
IF( GNUCXX_VERSION VERSION_GREATER 4.1.2 )
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=strict-aliasing")
ENDIF()
ENDIF( CMAKE_COMPILER_IS_GNUCXX )
INCLUDE(CheckIncludeFileCXX)
INCLUDE(CheckTypeSize)
INCLUDE(CheckStructHasMember)
INCLUDE(CheckCXXSymbolExists)
check_include_file_cxx(clocale HAVE_CLOCALE)
check_cxx_symbol_exists(localeconv clocale HAVE_LOCALECONV)
IF(CMAKE_VERSION VERSION_LESS 3.0.0)
# The "LANGUAGE CXX" parameter is not supported in CMake versions below 3,
# so the C compiler and header has to be used.
check_include_file(locale.h HAVE_LOCALE_H)
SET(CMAKE_EXTRA_INCLUDE_FILES locale.h)
check_type_size("struct lconv" LCONV_SIZE)
UNSET(CMAKE_EXTRA_INCLUDE_FILES)
check_struct_has_member("struct lconv" decimal_point locale.h HAVE_DECIMAL_POINT)
ELSE()
SET(CMAKE_EXTRA_INCLUDE_FILES clocale)
check_type_size(lconv LCONV_SIZE LANGUAGE CXX)
UNSET(CMAKE_EXTRA_INCLUDE_FILES)
check_struct_has_member(lconv decimal_point clocale HAVE_DECIMAL_POINT LANGUAGE CXX)
ENDIF()
IF(NOT (HAVE_CLOCALE AND HAVE_LCONV_SIZE AND HAVE_DECIMAL_POINT AND HAVE_LOCALECONV))
MESSAGE(WARNING "Locale functionality is not supported")
ADD_DEFINITIONS(-DJSONCPP_NO_LOCALE_SUPPORT)
ENDIF()
SET( JSONCPP_INCLUDE_DIR ../include )
SET( PUBLIC_HEADERS
${JSONCPP_INCLUDE_DIR}/json/config.h
${JSONCPP_INCLUDE_DIR}/json/forwards.h
${JSONCPP_INCLUDE_DIR}/json/features.h
${JSONCPP_INCLUDE_DIR}/json/value.h
${JSONCPP_INCLUDE_DIR}/json/reader.h
${JSONCPP_INCLUDE_DIR}/json/writer.h
${JSONCPP_INCLUDE_DIR}/json/assertions.h
${JSONCPP_INCLUDE_DIR}/json/version.h
)
SOURCE_GROUP( "Public API" FILES ${PUBLIC_HEADERS} )
SET(jsoncpp_sources
json_tool.h
json_reader.cpp
json_valueiterator.inl
json_value.cpp
json_writer.cpp
version.h.in
)
# Install instructions for this target
IF(JSONCPP_WITH_CMAKE_PACKAGE)
SET(INSTALL_EXPORT EXPORT jsoncpp)
ELSE(JSONCPP_WITH_CMAKE_PACKAGE)
SET(INSTALL_EXPORT)
ENDIF()
set(SRC
${PUBLIC_HEADERS}
${jsoncpp_sources}
)
set(INC
../include
)
blender_add_lib(jsoncpp_lib "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")

2036
extern/jsoncpp/src/json_reader.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

117
extern/jsoncpp/src/json_tool.h vendored Normal file
View File

@@ -0,0 +1,117 @@
// Copyright 2007-2010 Baptiste Lepilleur
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
#ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED
#define LIB_JSONCPP_JSON_TOOL_H_INCLUDED
// Also support old flag NO_LOCALE_SUPPORT
#ifdef NO_LOCALE_SUPPORT
#define JSONCPP_NO_LOCALE_SUPPORT
#endif
#ifndef JSONCPP_NO_LOCALE_SUPPORT
#include <clocale>
#endif
/* This header provides common string manipulation support, such as UTF-8,
* portable conversion from/to string...
*
* It is an internal header that must not be exposed.
*/
namespace Json {
static char getDecimalPoint() {
#ifdef JSONCPP_NO_LOCALE_SUPPORT
return '\0';
#else
struct lconv* lc = localeconv();
return lc ? *(lc->decimal_point) : '\0';
#endif
}
/// Converts a unicode code-point to UTF-8.
static inline JSONCPP_STRING codePointToUTF8(unsigned int cp) {
JSONCPP_STRING result;
// based on description from http://en.wikipedia.org/wiki/UTF-8
if (cp <= 0x7f) {
result.resize(1);
result[0] = static_cast<char>(cp);
} else if (cp <= 0x7FF) {
result.resize(2);
result[1] = static_cast<char>(0x80 | (0x3f & cp));
result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
} else if (cp <= 0xFFFF) {
result.resize(3);
result[2] = static_cast<char>(0x80 | (0x3f & cp));
result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
result[0] = static_cast<char>(0xE0 | (0xf & (cp >> 12)));
} else if (cp <= 0x10FFFF) {
result.resize(4);
result[3] = static_cast<char>(0x80 | (0x3f & cp));
result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));
result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));
}
return result;
}
/// Returns true if ch is a control character (in range [1,31]).
static inline bool isControlCharacter(char ch) { return ch > 0 && ch <= 0x1F; }
enum {
/// Constant that specify the size of the buffer that must be passed to
/// uintToString.
uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1
};
// Defines a char buffer for use with uintToString().
typedef char UIntToStringBuffer[uintToStringBufferSize];
/** Converts an unsigned integer to string.
* @param value Unsigned interger to convert to string
* @param current Input/Output string buffer.
* Must have at least uintToStringBufferSize chars free.
*/
static inline void uintToString(LargestUInt value, char*& current) {
*--current = 0;
do {
*--current = static_cast<char>(value % 10U + static_cast<unsigned>('0'));
value /= 10;
} while (value != 0);
}
/** Change ',' to '.' everywhere in buffer.
*
* We had a sophisticated way, but it did not work in WinCE.
* @see https://github.com/open-source-parsers/jsoncpp/pull/9
*/
static inline void fixNumericLocale(char* begin, char* end) {
while (begin < end) {
if (*begin == ',') {
*begin = '.';
}
++begin;
}
}
static inline void fixNumericLocaleInput(char* begin, char* end) {
char decimalPoint = getDecimalPoint();
if (decimalPoint != '\0' && decimalPoint != '.') {
while (begin < end) {
if (*begin == '.') {
*begin = decimalPoint;
}
++begin;
}
}
}
} // namespace Json {
#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED

1665
extern/jsoncpp/src/json_value.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,167 @@
// Copyright 2007-2010 Baptiste Lepilleur
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
// included by json_value.cpp
namespace Json {
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// class ValueIteratorBase
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
ValueIteratorBase::ValueIteratorBase()
: current_(), isNull_(true) {
}
ValueIteratorBase::ValueIteratorBase(
const Value::ObjectValues::iterator& current)
: current_(current), isNull_(false) {}
Value& ValueIteratorBase::deref() const {
return current_->second;
}
void ValueIteratorBase::increment() {
++current_;
}
void ValueIteratorBase::decrement() {
--current_;
}
ValueIteratorBase::difference_type
ValueIteratorBase::computeDistance(const SelfType& other) const {
#ifdef JSON_USE_CPPTL_SMALLMAP
return other.current_ - current_;
#else
// Iterator for null value are initialized using the default
// constructor, which initialize current_ to the default
// std::map::iterator. As begin() and end() are two instance
// of the default std::map::iterator, they can not be compared.
// To allow this, we handle this comparison specifically.
if (isNull_ && other.isNull_) {
return 0;
}
// Usage of std::distance is not portable (does not compile with Sun Studio 12
// RogueWave STL,
// which is the one used by default).
// Using a portable hand-made version for non random iterator instead:
// return difference_type( std::distance( current_, other.current_ ) );
difference_type myDistance = 0;
for (Value::ObjectValues::iterator it = current_; it != other.current_;
++it) {
++myDistance;
}
return myDistance;
#endif
}
bool ValueIteratorBase::isEqual(const SelfType& other) const {
if (isNull_) {
return other.isNull_;
}
return current_ == other.current_;
}
void ValueIteratorBase::copy(const SelfType& other) {
current_ = other.current_;
isNull_ = other.isNull_;
}
Value ValueIteratorBase::key() const {
const Value::CZString czstring = (*current_).first;
if (czstring.data()) {
if (czstring.isStaticString())
return Value(StaticString(czstring.data()));
return Value(czstring.data(), czstring.data() + czstring.length());
}
return Value(czstring.index());
}
UInt ValueIteratorBase::index() const {
const Value::CZString czstring = (*current_).first;
if (!czstring.data())
return czstring.index();
return Value::UInt(-1);
}
JSONCPP_STRING ValueIteratorBase::name() const {
char const* keey;
char const* end;
keey = memberName(&end);
if (!keey) return JSONCPP_STRING();
return JSONCPP_STRING(keey, end);
}
char const* ValueIteratorBase::memberName() const {
const char* cname = (*current_).first.data();
return cname ? cname : "";
}
char const* ValueIteratorBase::memberName(char const** end) const {
const char* cname = (*current_).first.data();
if (!cname) {
*end = NULL;
return NULL;
}
*end = cname + (*current_).first.length();
return cname;
}
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// class ValueConstIterator
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
ValueConstIterator::ValueConstIterator() {}
ValueConstIterator::ValueConstIterator(
const Value::ObjectValues::iterator& current)
: ValueIteratorBase(current) {}
ValueConstIterator::ValueConstIterator(ValueIterator const& other)
: ValueIteratorBase(other) {}
ValueConstIterator& ValueConstIterator::
operator=(const ValueIteratorBase& other) {
copy(other);
return *this;
}
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// class ValueIterator
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
ValueIterator::ValueIterator() {}
ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current)
: ValueIteratorBase(current) {}
ValueIterator::ValueIterator(const ValueConstIterator& other)
: ValueIteratorBase(other) {
throwRuntimeError("ConstIterator to Iterator should never be allowed.");
}
ValueIterator::ValueIterator(const ValueIterator& other)
: ValueIteratorBase(other) {}
ValueIterator& ValueIterator::operator=(const SelfType& other) {
copy(other);
return *this;
}
} // namespace Json

1223
extern/jsoncpp/src/json_writer.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

8
extern/jsoncpp/src/sconscript vendored Normal file
View File

@@ -0,0 +1,8 @@
Import( 'env buildLibrary' )
buildLibrary( env, Split( """
json_reader.cpp
json_value.cpp
json_writer.cpp
""" ),
'json' )

20
extern/jsoncpp/src/version.h.in vendored Normal file
View File

@@ -0,0 +1,20 @@
// DO NOT EDIT. This file (and "version") is generated by CMake.
// Run CMake configure step to update it.
#ifndef JSON_VERSION_H_INCLUDED
# define JSON_VERSION_H_INCLUDED
# define JSONCPP_VERSION_STRING "@JSONCPP_VERSION@"
# define JSONCPP_VERSION_MAJOR @JSONCPP_VERSION_MAJOR@
# define JSONCPP_VERSION_MINOR @JSONCPP_VERSION_MINOR@
# define JSONCPP_VERSION_PATCH @JSONCPP_VERSION_PATCH@
# define JSONCPP_VERSION_QUALIFIER
# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8))
#ifdef JSONCPP_USING_SECURE_MEMORY
#undef JSONCPP_USING_SECURE_MEMORY
#endif
#define JSONCPP_USING_SECURE_MEMORY @JSONCPP_USE_SECURE_MEMORY@
// If non-zero, the library zeroes any memory that it has allocated before
// it frees its memory.
#endif // JSON_VERSION_H_INCLUDED

71
extern/openxr/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,71 @@
# Copyright (c) 2017-2019 The Khronos Group Inc.
#
# 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.
#
# Author:
#
# Note: This is the top-level CMake file for the OpenXR project.
# It should contain only definitions that are applicable to the
# entire project and includes for the sub-directories.
cmake_minimum_required(VERSION 3.0)
project(OPENXR)
#find_package(PythonInterp 3)
# Enable IDE GUI folders. "Helper targets" that don't have interesting source code should set their FOLDER property to this
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER "CMake predefined targets")
set(LOADER_FOLDER "Loader")
set(HELPER_FOLDER "Helpers")
set(CODEGEN_FOLDER "Generated")
set(TESTS_FOLDER "Tests")
set(API_LAYERS_FOLDER "Layers")
set(SAMPLES_FOLDER "Samples")
option(BUILD_FORCE_GENERATION "Force re-generation of files even in the presence of pre-generated copies, replacing those copies." OFF)
if(BUILD_FORCE_GENERATION AND NOT PYTHON_EXECUTABLE)
message(FATAL_ERROR "BUILD_FORCE_GENERATION requires Python")
endif()
set(OPENXR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR})
add_subdirectory(include)
add_subdirectory(src)
# uninstall target
if(NOT TARGET uninstall)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/cmake/cmake_uninstall.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
IMMEDIATE
@ONLY)
add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
set_target_properties(uninstall PROPERTIES FOLDER ${HELPER_FOLDER})
endif()
find_program(BASH_COMMAND NAMES bash)
if(BASH_COMMAND AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/specification/Makefile")
option(BUILD_SPECIFICATION "Run './makeAllExts all' in the specification directory as part of the build - intended for one-step checking of spec changes" OFF)
if(BUILD_SPECIFICATION)
add_custom_target(spec-all ALL
${BASH_COMMAND} ./makeAllExts all
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/specification"
VERBATIM
COMMENT "Running './makeAllExts all' in the specification directory"
USES_TERMINAL)
endif()
endif()
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE" DESTINATION share/doc/openxr)

202
extern/openxr/LICENSE vendored Normal file
View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

18
extern/openxr/include/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,18 @@
# Copyright (c) 2017 The Khronos Group Inc.
#
# 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.
#
# Author:
#
add_subdirectory(openxr)

View File

@@ -0,0 +1,94 @@
# Copyright (c) 2017-2019 The Khronos Group Inc.
#
# 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.
#
# Author:
#
# Copy the openxr_platform_defines.h file and place it in the binary (build) directory.
configure_file(openxr_platform_defines.h ${CMAKE_CURRENT_BINARY_DIR}/openxr_platform_defines.h COPYONLY)
# Generate OpenXR header files.
set(HEADERS
openxr.h
openxr_platform.h
openxr_reflection.h)
set(HAVE_PREGENERATED TRUE)
set(SOURCE_HEADERS)
foreach(output ${HEADERS})
list(APPEND SOURCE_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/${output})
if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${output})
set(HAVE_PREGENERATED FALSE)
endif()
endforeach()
set(XR_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../..)
if(HAVE_PREGENERATED AND NOT BUILD_FORCE_GENERATION)
add_custom_target(generate_openxr_header
COMMENT "Using found pre-generated OpenXR headers.")
set(INSTALL_HEADERS ${SOURCE_HEADERS})
else()
set(GENERATED_HEADERS)
set(OUTPUT_STAMPS)
# Copy the openxr_platform_defines.h file and place it in the binary (build) directory.
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/openxr_platform_defines.h
${CMAKE_CURRENT_BINARY_DIR}/openxr_platform_defines.h
COPYONLY)
# Generate the header files and place it in the binary (build) directory.
foreach(output ${HEADERS})
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${output}
COMMAND ${PYTHON_EXECUTABLE} ${XR_ROOT}/specification/scripts/genxr.py
-registry ${XR_ROOT}/specification/registry/xr.xml
-o ${CMAKE_CURRENT_BINARY_DIR} ${output}
DEPENDS
${XR_ROOT}/specification/scripts/genxr.py
${XR_ROOT}/specification/scripts/cgenerator.py
${XR_ROOT}/specification/scripts/creflectiongenerator.py
${XR_ROOT}/specification/scripts/generator.py
${XR_ROOT}/specification/scripts/reg.py
${XR_ROOT}/specification/registry/xr.xml
COMMENT "Generating ${CMAKE_CURRENT_BINARY_DIR}/${output}"
)
list(APPEND GENERATED_HEADERS "${CMAKE_CURRENT_BINARY_DIR}/${output}")
endforeach()
set_source_files_properties(
${GENERATED_HEADERS}
PROPERTIES GENERATED TRUE
)
set(INSTALL_HEADERS
${CMAKE_CURRENT_BINARY_DIR}/openxr_platform_defines.h
${CMAKE_CURRENT_BINARY_DIR}/openxr.h
${CMAKE_CURRENT_BINARY_DIR}/openxr_platform.h)
# Define generate_openxr_header target to generate the OpenXR header files.
# Other targets that need the OpenXR headers should use generate_openxr_header as a dependency.
add_custom_target(generate_openxr_header
SOURCES ${XR_ROOT}/specification/registry/xr.xml
DEPENDS
${GENERATED_HEADERS}
${OUTPUT_STAMPS}
)
endif()
set_target_properties(generate_openxr_header PROPERTIES FOLDER ${CODEGEN_FOLDER})
INSTALL(FILES ${INSTALL_HEADERS}
DESTINATION include/openxr
)

1538
extern/openxr/include/openxr/openxr.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,383 @@
#ifndef OPENXR_PLATFORM_H_
#define OPENXR_PLATFORM_H_ 1
/*
** Copyright (c) 2017-2019 The Khronos Group Inc.
**
** 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.
*/
/*
** This header is generated from the Khronos OpenXR XML API Registry.
**
*/
#include "openxr.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef XR_USE_PLATFORM_ANDROID
#define XR_KHR_android_thread_settings 1
#define XR_KHR_android_thread_settings_SPEC_VERSION 5
#define XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME "XR_KHR_android_thread_settings"
typedef enum XrAndroidThreadTypeKHR {
XR_ANDROID_THREAD_TYPE_APPLICATION_MAIN_KHR = 1,
XR_ANDROID_THREAD_TYPE_APPLICATION_WORKER_KHR = 2,
XR_ANDROID_THREAD_TYPE_RENDERER_MAIN_KHR = 3,
XR_ANDROID_THREAD_TYPE_RENDERER_WORKER_KHR = 4,
XR_ANDROID_THREAD_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF
} XrAndroidThreadTypeKHR;
typedef XrResult (XRAPI_PTR *PFN_xrSetAndroidApplicationThreadKHR)(XrSession session, XrAndroidThreadTypeKHR threadType, uint32_t threadId);
#ifndef XR_NO_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrSetAndroidApplicationThreadKHR(
XrSession session,
XrAndroidThreadTypeKHR threadType,
uint32_t threadId);
#endif
#endif /* XR_USE_PLATFORM_ANDROID */
#ifdef XR_USE_PLATFORM_ANDROID
#define XR_KHR_android_surface_swapchain 1
#define XR_KHR_android_surface_swapchain_SPEC_VERSION 4
#define XR_KHR_ANDROID_SURFACE_SWAPCHAIN_EXTENSION_NAME "XR_KHR_android_surface_swapchain"
typedef XrResult (XRAPI_PTR *PFN_xrCreateSwapchainAndroidSurfaceKHR)(XrSession session, const XrSwapchainCreateInfo* info, XrSwapchain* swapchain, jobject* surface);
#ifndef XR_NO_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrCreateSwapchainAndroidSurfaceKHR(
XrSession session,
const XrSwapchainCreateInfo* info,
XrSwapchain* swapchain,
jobject* surface);
#endif
#endif /* XR_USE_PLATFORM_ANDROID */
#ifdef XR_USE_PLATFORM_ANDROID
#define XR_KHR_android_create_instance 1
#define XR_KHR_android_create_instance_SPEC_VERSION 3
#define XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME "XR_KHR_android_create_instance"
typedef struct XrInstanceCreateInfoAndroidKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
void* XR_MAY_ALIAS applicationVM;
void* XR_MAY_ALIAS applicationActivity;
} XrInstanceCreateInfoAndroidKHR;
#endif /* XR_USE_PLATFORM_ANDROID */
#ifdef XR_USE_GRAPHICS_API_VULKAN
#define XR_KHR_vulkan_swapchain_format_list 1
#define XR_KHR_vulkan_swapchain_format_list_SPEC_VERSION 2
#define XR_KHR_VULKAN_SWAPCHAIN_FORMAT_LIST_EXTENSION_NAME "XR_KHR_vulkan_swapchain_format_list"
typedef struct XrVulkanSwapchainFormatListCreateInfoKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
uint32_t viewFormatCount;
const VkFormat* viewFormats;
} XrVulkanSwapchainFormatListCreateInfoKHR;
#endif /* XR_USE_GRAPHICS_API_VULKAN */
#ifdef XR_USE_GRAPHICS_API_OPENGL
#define XR_KHR_opengl_enable 1
#define XR_KHR_opengl_enable_SPEC_VERSION 7
#define XR_KHR_OPENGL_ENABLE_EXTENSION_NAME "XR_KHR_opengl_enable"
#ifdef XR_USE_PLATFORM_WIN32
typedef struct XrGraphicsBindingOpenGLWin32KHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
HDC hDC;
HGLRC hGLRC;
} XrGraphicsBindingOpenGLWin32KHR;
#endif // XR_USE_PLATFORM_WIN32
#ifdef XR_USE_PLATFORM_XLIB
typedef struct XrGraphicsBindingOpenGLXlibKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
Display* xDisplay;
uint32_t visualid;
GLXFBConfig glxFBConfig;
GLXDrawable glxDrawable;
GLXContext glxContext;
} XrGraphicsBindingOpenGLXlibKHR;
#endif // XR_USE_PLATFORM_XLIB
#ifdef XR_USE_PLATFORM_XCB
typedef struct XrGraphicsBindingOpenGLXcbKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
xcb_connection_t* connection;
uint32_t screenNumber;
xcb_glx_fbconfig_t fbconfigid;
xcb_visualid_t visualid;
xcb_glx_drawable_t glxDrawable;
xcb_glx_context_t glxContext;
} XrGraphicsBindingOpenGLXcbKHR;
#endif // XR_USE_PLATFORM_XCB
#ifdef XR_USE_PLATFORM_WAYLAND
typedef struct XrGraphicsBindingOpenGLWaylandKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
struct wl_display* display;
} XrGraphicsBindingOpenGLWaylandKHR;
#endif // XR_USE_PLATFORM_WAYLAND
typedef struct XrSwapchainImageOpenGLKHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
uint32_t image;
} XrSwapchainImageOpenGLKHR;
typedef struct XrGraphicsRequirementsOpenGLKHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
XrVersion minApiVersionSupported;
XrVersion maxApiVersionSupported;
} XrGraphicsRequirementsOpenGLKHR;
typedef XrResult (XRAPI_PTR *PFN_xrGetOpenGLGraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsOpenGLKHR* graphicsRequirements);
#ifndef XR_NO_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrGetOpenGLGraphicsRequirementsKHR(
XrInstance instance,
XrSystemId systemId,
XrGraphicsRequirementsOpenGLKHR* graphicsRequirements);
#endif
#endif /* XR_USE_GRAPHICS_API_OPENGL */
#ifdef XR_USE_GRAPHICS_API_OPENGL_ES
#define XR_KHR_opengl_es_enable 1
#define XR_KHR_opengl_es_enable_SPEC_VERSION 6
#define XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME "XR_KHR_opengl_es_enable"
#ifdef XR_USE_PLATFORM_ANDROID
typedef struct XrGraphicsBindingOpenGLESAndroidKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
EGLDisplay display;
EGLConfig config;
EGLContext context;
} XrGraphicsBindingOpenGLESAndroidKHR;
#endif // XR_USE_PLATFORM_ANDROID
typedef struct XrSwapchainImageOpenGLESKHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
uint32_t image;
} XrSwapchainImageOpenGLESKHR;
typedef struct XrGraphicsRequirementsOpenGLESKHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
XrVersion minApiVersionSupported;
XrVersion maxApiVersionSupported;
} XrGraphicsRequirementsOpenGLESKHR;
typedef XrResult (XRAPI_PTR *PFN_xrGetOpenGLESGraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsOpenGLESKHR* graphicsRequirements);
#ifndef XR_NO_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrGetOpenGLESGraphicsRequirementsKHR(
XrInstance instance,
XrSystemId systemId,
XrGraphicsRequirementsOpenGLESKHR* graphicsRequirements);
#endif
#endif /* XR_USE_GRAPHICS_API_OPENGL_ES */
#ifdef XR_USE_GRAPHICS_API_VULKAN
#define XR_KHR_vulkan_enable 1
#define XR_KHR_vulkan_enable_SPEC_VERSION 6
#define XR_KHR_VULKAN_ENABLE_EXTENSION_NAME "XR_KHR_vulkan_enable"
typedef struct XrGraphicsBindingVulkanKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
VkInstance instance;
VkPhysicalDevice physicalDevice;
VkDevice device;
uint32_t queueFamilyIndex;
uint32_t queueIndex;
} XrGraphicsBindingVulkanKHR;
typedef struct XrSwapchainImageVulkanKHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
VkImage image;
} XrSwapchainImageVulkanKHR;
typedef struct XrGraphicsRequirementsVulkanKHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
XrVersion minApiVersionSupported;
XrVersion maxApiVersionSupported;
} XrGraphicsRequirementsVulkanKHR;
typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanInstanceExtensionsKHR)(XrInstance instance, XrSystemId systemId, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, char* buffer);
typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanDeviceExtensionsKHR)(XrInstance instance, XrSystemId systemId, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, char* buffer);
typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsDeviceKHR)(XrInstance instance, XrSystemId systemId, VkInstance vkInstance, VkPhysicalDevice* vkPhysicalDevice);
typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsVulkanKHR* graphicsRequirements);
#ifndef XR_NO_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanInstanceExtensionsKHR(
XrInstance instance,
XrSystemId systemId,
uint32_t bufferCapacityInput,
uint32_t* bufferCountOutput,
char* buffer);
XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanDeviceExtensionsKHR(
XrInstance instance,
XrSystemId systemId,
uint32_t bufferCapacityInput,
uint32_t* bufferCountOutput,
char* buffer);
XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanGraphicsDeviceKHR(
XrInstance instance,
XrSystemId systemId,
VkInstance vkInstance,
VkPhysicalDevice* vkPhysicalDevice);
XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanGraphicsRequirementsKHR(
XrInstance instance,
XrSystemId systemId,
XrGraphicsRequirementsVulkanKHR* graphicsRequirements);
#endif
#endif /* XR_USE_GRAPHICS_API_VULKAN */
#ifdef XR_USE_GRAPHICS_API_D3D11
#define XR_KHR_D3D11_enable 1
#define XR_KHR_D3D11_enable_SPEC_VERSION 4
#define XR_KHR_D3D11_ENABLE_EXTENSION_NAME "XR_KHR_D3D11_enable"
typedef struct XrGraphicsBindingD3D11KHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
ID3D11Device* device;
} XrGraphicsBindingD3D11KHR;
typedef struct XrSwapchainImageD3D11KHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
ID3D11Texture2D* texture;
} XrSwapchainImageD3D11KHR;
typedef struct XrGraphicsRequirementsD3D11KHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
LUID adapterLuid;
D3D_FEATURE_LEVEL minFeatureLevel;
} XrGraphicsRequirementsD3D11KHR;
typedef XrResult (XRAPI_PTR *PFN_xrGetD3D11GraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsD3D11KHR* graphicsRequirements);
#ifndef XR_NO_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrGetD3D11GraphicsRequirementsKHR(
XrInstance instance,
XrSystemId systemId,
XrGraphicsRequirementsD3D11KHR* graphicsRequirements);
#endif
#endif /* XR_USE_GRAPHICS_API_D3D11 */
#ifdef XR_USE_GRAPHICS_API_D3D12
#define XR_KHR_D3D12_enable 1
#define XR_KHR_D3D12_enable_SPEC_VERSION 5
#define XR_KHR_D3D12_ENABLE_EXTENSION_NAME "XR_KHR_D3D12_enable"
typedef struct XrGraphicsBindingD3D12KHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
ID3D12Device* device;
ID3D12CommandQueue* queue;
} XrGraphicsBindingD3D12KHR;
typedef struct XrSwapchainImageD3D12KHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
ID3D12Resource* texture;
} XrSwapchainImageD3D12KHR;
typedef struct XrGraphicsRequirementsD3D12KHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
LUID adapterLuid;
D3D_FEATURE_LEVEL minFeatureLevel;
} XrGraphicsRequirementsD3D12KHR;
typedef XrResult (XRAPI_PTR *PFN_xrGetD3D12GraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsD3D12KHR* graphicsRequirements);
#ifndef XR_NO_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrGetD3D12GraphicsRequirementsKHR(
XrInstance instance,
XrSystemId systemId,
XrGraphicsRequirementsD3D12KHR* graphicsRequirements);
#endif
#endif /* XR_USE_GRAPHICS_API_D3D12 */
#ifdef XR_USE_PLATFORM_WIN32
#define XR_KHR_win32_convert_performance_counter_time 1
#define XR_KHR_win32_convert_performance_counter_time_SPEC_VERSION 1
#define XR_KHR_WIN32_CONVERT_PERFORMANCE_COUNTER_TIME_EXTENSION_NAME "XR_KHR_win32_convert_performance_counter_time"
typedef XrResult (XRAPI_PTR *PFN_xrConvertWin32PerformanceCounterToTimeKHR)(XrInstance instance, const LARGE_INTEGER* performanceCounter, XrTime* time);
typedef XrResult (XRAPI_PTR *PFN_xrConvertTimeToWin32PerformanceCounterKHR)(XrInstance instance, XrTime time, LARGE_INTEGER* performanceCounter);
#ifndef XR_NO_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrConvertWin32PerformanceCounterToTimeKHR(
XrInstance instance,
const LARGE_INTEGER* performanceCounter,
XrTime* time);
XRAPI_ATTR XrResult XRAPI_CALL xrConvertTimeToWin32PerformanceCounterKHR(
XrInstance instance,
XrTime time,
LARGE_INTEGER* performanceCounter);
#endif
#endif /* XR_USE_PLATFORM_WIN32 */
#ifdef XR_USE_TIMESPEC
#define XR_KHR_convert_timespec_time 1
#define XR_KHR_convert_timespec_time_SPEC_VERSION 1
#define XR_KHR_CONVERT_TIMESPEC_TIME_EXTENSION_NAME "XR_KHR_convert_timespec_time"
typedef XrResult (XRAPI_PTR *PFN_xrConvertTimespecTimeToTimeKHR)(XrInstance instance, const struct timespec* timespecTime, XrTime* time);
typedef XrResult (XRAPI_PTR *PFN_xrConvertTimeToTimespecTimeKHR)(XrInstance instance, XrTime time, struct timespec* timespecTime);
#ifndef XR_NO_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrConvertTimespecTimeToTimeKHR(
XrInstance instance,
const struct timespec* timespecTime,
XrTime* time);
XRAPI_ATTR XrResult XRAPI_CALL xrConvertTimeToTimespecTimeKHR(
XrInstance instance,
XrTime time,
struct timespec* timespecTime);
#endif
#endif /* XR_USE_TIMESPEC */
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,124 @@
/*
** Copyright (c) 2017-2019 The Khronos Group Inc.
**
** 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 OPENXR_PLATFORM_DEFINES_H_
#define OPENXR_PLATFORM_DEFINES_H_ 1
#ifdef __cplusplus
extern "C" {
#endif
/* Platform-specific calling convention macros.
*
* Platforms should define these so that OpenXR clients call OpenXR functions
* with the same calling conventions that the OpenXR implementation expects.
*
* XRAPI_ATTR - Placed before the return type in function declarations.
* Useful for C++11 and GCC/Clang-style function attribute syntax.
* XRAPI_CALL - Placed after the return type in function declarations.
* Useful for MSVC-style calling convention syntax.
* XRAPI_PTR - Placed between the '(' and '*' in function pointer types.
*
* Function declaration: XRAPI_ATTR void XRAPI_CALL xrFunction(void);
* Function pointer type: typedef void (XRAPI_PTR *PFN_xrFunction)(void);
*/
#if defined(_WIN32)
#ifdef XRAPI_DLL_EXPORT
#define XRAPI_ATTR __declspec(dllexport)
#else
#define XRAPI_ATTR
#endif
// On Windows, functions use the stdcall convention
#define XRAPI_CALL __stdcall
#define XRAPI_PTR XRAPI_CALL
#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7
#error "API not supported for the 'armeabi' NDK ABI"
#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE)
// On Android 32-bit ARM targets, functions use the "hardfloat"
// calling convention, i.e. float parameters are passed in registers. This
// is true even if the rest of the application passes floats on the stack,
// as it does by default when compiling for the armeabi-v7a NDK ABI.
#define XRAPI_ATTR __attribute__((pcs("aapcs-vfp")))
#define XRAPI_CALL
#define XRAPI_PTR XRAPI_ATTR
#else
// On other platforms, use the default calling convention
#define XRAPI_ATTR
#define XRAPI_CALL
#define XRAPI_PTR
#endif
#include <stddef.h>
#if !defined(XR_NO_STDINT_H)
#if defined(_MSC_VER) && (_MSC_VER < 1600)
typedef signed __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef signed __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef signed __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef signed __int64 int64_t;
typedef unsigned __int64 uint64_t;
#else
#include <stdint.h>
#endif
#endif // !defined( XR_NO_STDINT_H )
// XR_PTR_SIZE (in bytes)
#if (defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__))
#define XR_PTR_SIZE 8
#else
#define XR_PTR_SIZE 4
#endif
// Needed so we can use clang __has_feature portably.
#if !defined(XR_COMPILER_HAS_FEATURE)
#if defined(__clang__)
#define XR_COMPILER_HAS_FEATURE(x) __has_feature(x)
#else
#define XR_COMPILER_HAS_FEATURE(x) 0
#endif
#endif
// Identifies if the current compiler has C++11 support enabled.
// Does not by itself identify if any given C++11 feature is present.
#if !defined(XR_CPP11_ENABLED) && defined(__cplusplus)
#if defined(__GNUC__) && defined(__GXX_EXPERIMENTAL_CXX0X__)
#define XR_CPP11_ENABLED 1
#elif defined(_MSC_VER) && (_MSC_VER >= 1600)
#define XR_CPP11_ENABLED 1
#elif (__cplusplus >= 201103L) // 201103 is the first C++11 version.
#define XR_CPP11_ENABLED 1
#endif
#endif
// Identifies if the current compiler supports C++11 nullptr.
#if !defined(XR_CPP_NULLPTR_SUPPORTED)
#if defined(XR_CPP11_ENABLED) && \
((defined(__clang__) && XR_COMPILER_HAS_FEATURE(cxx_nullptr)) || \
(defined(__GNUC__) && (((__GNUC__ * 1000) + __GNUC_MINOR__) >= 4006)) || \
(defined(_MSC_VER) && (_MSC_VER >= 1600)) || \
(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 403)))
#define XR_CPP_NULLPTR_SUPPORTED 1
#endif
#endif
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

194
extern/openxr/src/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,194 @@
# Copyright (c) 2017 The Khronos Group Inc.
#
# 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.
#
# Author:
#
# Entire project uses C++11
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
# All options defined here
option(BUILD_LOADER "Build loader" ON)
option(BUILD_LOADER_WITH_EXCEPTION_HANDLING "Enable exception handling in the loader. Leave this on unless your standard library is built to not throw." ON)
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
option(DYNAMIC_LOADER "Build the loader as a .dll library" OFF)
else()
option(DYNAMIC_LOADER "Build the loader as a .dll library" ON)
endif()
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/api_layers")
option(BUILD_API_LAYERS "Build API layers" ON)
endif()
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tests")
option(BUILD_TESTS "Build tests" ON)
endif()
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/conformance")
option(BUILD_CONFORMANCE_TESTS "Build conformance tests" ON)
endif()
# Several files use these compile-time OS switches
if(WIN32)
add_definitions(-DXR_OS_WINDOWS)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
add_definitions(-DXR_OS_LINUX)
endif()
# Determine the presentation backend for Linux systems.
# Use an include because the code is pretty big.
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
include(presentation)
endif()
# Several files use these compile-time platform switches
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
add_definitions( -DXR_USE_PLATFORM_WIN32 )
elseif( PRESENTATION_BACKEND MATCHES "xlib" )
add_definitions( -DXR_USE_PLATFORM_XLIB )
elseif( PRESENTATION_BACKEND MATCHES "xcb" )
add_definitions( -DXR_USE_PLATFORM_XCB )
# TODO remove once conformance supports XCB
set(BUILD_CONFORMANCE_TESTS OFF)
elseif( PRESENTATION_BACKEND MATCHES "wayland" )
add_definitions( -DXR_USE_PLATFORM_WAYLAND )
# TODO remove once conformance supports Wayland
set(BUILD_CONFORMANCE_TESTS OFF)
endif()
# Enable graphics API available to the build.
if (NOT CMAKE_VERSION VERSION_LESS 3.7.0)
# Find the Vulkan headers
find_package(VulkanHeaders)
if (VulkanHeaders_FOUND)
add_definitions(-DXR_USE_GRAPHICS_API_VULKAN)
endif()
# Find the Vulkan loader.
find_package(Vulkan)
# To use simply include ${Vulkan_LIBRARY} in your target_link_library or
# wherever you normally link your library files to your target.
endif()
find_package(OpenGL)
if (OPENGL_FOUND)
add_definitions(-DXR_USE_GRAPHICS_API_OPENGL)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
add_definitions(-DXR_USE_GRAPHICS_API_D3D)
add_definitions(-DXR_USE_GRAPHICS_API_D3D11)
add_definitions(-DXR_USE_GRAPHICS_API_D3D12)
endif()
if(BUILD_LOADER_WITH_EXCEPTION_HANDLING)
set(XRLOADER_ENABLE_EXCEPTION_HANDLING TRUE)
endif()
# Check for the existence of the secure_getenv or __secure_getenv commands
include(CheckFunctionExists)
CHECK_FUNCTION_EXISTS(secure_getenv HAVE_SECURE_GETENV)
CHECK_FUNCTION_EXISTS(__secure_getenv HAVE___SECURE_GETENV)
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/common_cmake_config.h.in ${CMAKE_CURRENT_BINARY_DIR}/common_cmake_config.h)
# Be able to find pre-generated files, if used.
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include
${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
add_definitions(-DXR_USE_TIMESPEC)
# Set up the OpenXR version variables, used by several targets in this project.
include(${CMAKE_CURRENT_SOURCE_DIR}/version.cmake)
# Path separators ( : or ; ) are not handled well in CMake.
# This seems like a reasonable approach.
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
set(CODEGEN_PYTHON_PATH "${CMAKE_SOURCE_DIR}/specification/scripts;${CMAKE_SOURCE_DIR}/src/scripts;$ENV{PYTHONPATH}")
else()
set(CODEGEN_PYTHON_PATH "${CMAKE_SOURCE_DIR}/specification/scripts:${CMAKE_SOURCE_DIR}/src/scripts:$ENV{PYTHONPATH}")
endif()
# General code generation macro used by several targets.
macro(run_xr_xml_generate dependency output)
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${output}" AND NOT BUILD_FORCE_GENERATION)
# pre-generated found
message(STATUS "Found and will use pre-generated ${output} in source tree")
list(APPEND GENERATED_OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/${output}")
else()
if(NOT PYTHON_EXECUTABLE)
message(FATAL_ERROR "Python 3 not found, but pre-generated ${CMAKE_CURRENT_SOURCE_DIR}/${output} not found")
endif()
add_custom_command(OUTPUT ${output}
COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CODEGEN_PYTHON_PATH}"
${PYTHON_EXECUTABLE}
${CMAKE_SOURCE_DIR}/src/scripts/src_genxr.py
-registry ${CMAKE_SOURCE_DIR}/specification/registry/xr.xml
${output}
DEPENDS
"${CMAKE_SOURCE_DIR}/specification/registry/xr.xml"
"${CMAKE_SOURCE_DIR}/specification/scripts/generator.py"
"${CMAKE_SOURCE_DIR}/specification/scripts/reg.py"
"${CMAKE_SOURCE_DIR}/src/scripts/${dependency}"
"${CMAKE_SOURCE_DIR}/src/scripts/src_genxr.py"
${ARGN}
COMMENT "Generating ${output} using ${PYTHON_EXECUTABLE} on ${dependency}"
)
set_source_files_properties(${output} PROPERTIES GENERATED TRUE)
list(APPEND GENERATED_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${output}")
list(APPEND GENERATED_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${output}")
endif()
endmacro()
# Layer JSON generation macro used by several targets.
macro(gen_xr_layer_json filename layername libfile version desc genbad)
add_custom_command(OUTPUT ${filename}
COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CODEGEN_PYTHON_PATH}"
${PYTHON_EXECUTABLE}
${CMAKE_SOURCE_DIR}/src/scripts/generate_api_layer_manifest.py
-f ${filename} -n ${layername} -l ${libfile} -a ${MAJOR}.${MINOR} -v ${version} ${genbad} -d ${desc}
DEPENDS ${CMAKE_SOURCE_DIR}/src/scripts/generate_api_layer_manifest.py
COMMENT "Generating API Layer JSON ${filename} using -f ${filename} -n ${layername} -l ${libfile} -a ${MAJOR}.${MINOR} -v ${version} ${genbad} -d ${desc}"
)
endmacro()
# Custom target for generated dispatch table sources, used by several targets.
set(GENERATED_OUTPUT)
run_xr_xml_generate(utility_source_generator.py xr_generated_dispatch_table.h)
run_xr_xml_generate(utility_source_generator.py xr_generated_dispatch_table.c)
run_xr_xml_generate(utility_source_generator.py xr_generated_utilities.h)
run_xr_xml_generate(utility_source_generator.py xr_generated_utilities.c)
add_custom_target(xr_global_generated_files DEPENDS
${GENERATED_DEPENDS}
)
set_target_properties(xr_global_generated_files PROPERTIES FOLDER ${CODEGEN_FOLDER})
set(COMMON_GENERATED_OUTPUT ${GENERATED_OUTPUT})
if(BUILD_LOADER)
add_subdirectory(loader)
endif()
if(BUILD_API_LAYERS)
add_subdirectory(api_layers)
endif()
if(BUILD_TESTS)
add_subdirectory(tests)
endif()
if(BUILD_CONFORMANCE_TESTS)
add_subdirectory(conformance)
endif()

View File

@@ -0,0 +1,103 @@
# Copyright (c) 2017-2019 The Khronos Group Inc.
#
# 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.
#
# Author:
#
# Force all compilers to output to binary folder without additional output (like Windows adds "Debug" and "Release" folders)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES})
string(TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_CURRENT_BINARY_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_CURRENT_BINARY_DIR})
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_CURRENT_BINARY_DIR})
endforeach(OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES)
# Copy the api_layer_platform_defines.h file and place it in the binary (build) directory.
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/api_layer_platform_defines.h ${CMAKE_CURRENT_BINARY_DIR} COPYONLY)
# Basics for core_validation API Layer
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/XrApiLayer_core_validation.json ${CMAKE_CURRENT_BINARY_DIR}/XrApiLayer_core_validation.json COPYONLY)
add_library(XrApiLayer_core_validation SHARED
core_validation.cpp
${OPENXR_ROOT_DIR}/src/common/hex_and_handles.cpp
${OPENXR_ROOT_DIR}/src/common/hex_and_handles.h
${OPENXR_ROOT_DIR}/src/xr_generated_dispatch_table.c
${OPENXR_ROOT_DIR}/src/api_layers/xr_generated_core_validation.cpp
${OPENXR_ROOT_DIR}/src/api_layers/xr_generated_core_validation.hpp
# Included in this list to force generation
${CMAKE_CURRENT_BINARY_DIR}/XrApiLayer_core_validation.json
)
set_target_properties(XrApiLayer_core_validation PROPERTIES FOLDER ${API_LAYERS_FOLDER})
add_dependencies(XrApiLayer_core_validation
generate_openxr_header
xr_global_generated_files
)
target_include_directories(XrApiLayer_core_validation
PRIVATE ${OPENXR_ROOT_DIR}/src/common
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_BINARY_DIR}/include
PRIVATE ${CMAKE_BINARY_DIR}/src
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
)
if(VulkanHeaders_FOUND)
target_include_directories(XrApiLayer_core_validation
PRIVATE ${Vulkan_INCLUDE_DIRS}
)
endif()
# Flag generated files
set_source_files_properties(
${CMAKE_BINARY_DIR}/src/xr_generated_dispatch_table.c
PROPERTIES GENERATED TRUE
)
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
# Windows core_validation-specific information
target_compile_definitions(XrApiLayer_core_validation PRIVATE _CRT_SECURE_NO_WARNINGS)
# Turn off transitional "changed behavior" warning message for Visual Studio versions prior to 2015.
# The changed behavior is that constructor initializers are now fixed to clear the struct members.
target_compile_options(XrApiLayer_core_validation PRIVATE "$<$<AND:$<CXX_COMPILER_ID:MSVC>,$<VERSION_LESS:$<CXX_COMPILER_VERSION>,19>>:/wd4351>")
FILE(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/XrApiLayer_core_validation.def DEF_FILE)
add_custom_target(copy-core_validation-def-file ALL
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${DEF_FILE} ${CMAKE_CURRENT_BINARY_DIR}/XrApiLayer_core_validation.def
VERBATIM
)
set_target_properties(copy-core_validation-def-file PROPERTIES FOLDER ${HELPER_FOLDER})
elseif(APPLE)
# Apple core_validation-specific information
target_compile_options(XrApiLayer_core_validation PRIVATE -Wpointer-arith -Wno-unused-function -Wno-sign-compare)
set_target_properties(XrApiLayer_core_validation PROPERTIES LINK_FLAGS "-Wl")
else()
# Linux core_validation-specific information
target_compile_options(XrApiLayer_core_validation PRIVATE -Wpointer-arith -Wno-unused-function -Wno-sign-compare)
set_target_properties(XrApiLayer_core_validation PROPERTIES LINK_FLAGS "-Wl,-Bsymbolic,--exclude-libs,ALL")
endif()
# Install explicit layers on Linux
set(TARGET_NAMES
XrApiLayer_core_validation)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
foreach(TARGET_NAME ${TARGET_NAMES})
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}.json DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/openxr/${MAJOR}/api_layers/explicit.d)
install(TARGETS ${TARGET_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR})
endforeach()
endif()

View File

@@ -0,0 +1,27 @@
;;;; Begin Copyright Notice ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Copyright (c) 2017-2019 The Khronos Group Inc.
; Copyright (c) 2017-2019 Valve Corporation
; Copyright (c) 2017-2019 LunarG, Inc.
;
; 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.
;
; Author: Mark Young <marky@lunarg.com>
;
;;;; End Copyright Notice ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LIBRARY XrApiLayer_core_validation
EXPORTS
xrNegotiateLoaderApiLayerInterface

View File

@@ -0,0 +1,10 @@
{
"file_format_version": "1.0.0",
"api_layer": {
"name": "XR_APILAYER_LUNARG_core_validation",
"library_path": "libXrApiLayer_core_validation.dll",
"api_version": "1.0",
"implementation_version": "1",
"description": "API Layer to perform validation of api calls and parameters as they occur"
}
}

View File

@@ -0,0 +1,48 @@
// Copyright (c) 2018-2019 The Khronos Group Inc.
// Copyright (c) 2018-2019 Valve Corporation
// Copyright (c) 2018-2019 LunarG, Inc.
//
// 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.
//
// Author: Mark Young <marky@lunarg.com>
//
#ifndef API_LAYER_PLATFORM_DEFINES_H_
#define API_LAYER_PLATFORM_DEFINES_H_ 1
#ifdef _WIN32
#define XR_USE_PLATFORM_WIN32 1 // Win32 platform
#endif // _WIN32
#if defined(OS_LINUX_XLIB)
#define XR_USE_PLATFORM_XLIB 1 // Xlib platform
#endif // OS_LINUX_XLIB
#if defined(OS_LINUX_XCB) || defined(OS_LINUX_XCB_GLX)
#define XR_USE_PLATFORM_XCB 1 // Xcb platform
#endif // OS_LINUX_XCB || OS_LINUX_XCB_GLX
#if defined(OS_LINUX_WAYLAND)
#define XR_USE_PLATFORM_WAYLAND 1 // Wayland platform
#endif // OS_LINUX_WAYLAND
#if defined(XR_OS_APPLE_IOS)
#define XR_USE_PLATFORM_IOS 1 // iOS platform
#define XR_USE_GRAPHICS_API_OPENGL_ES 1 // OpenGLES exists
#define XR_USE_GRAPHICS_API_METAL 1 // Metal exists
#endif // XR_OS_APPLE_IOS
#if defined(XR_OS_APPLE_MACOS)
#define XR_USE_PLATFORM_MACOS 1 // MacOS platform
#define XR_USE_GRAPHICS_API_OPENGL 1 // OpenGL exists
#define XR_USE_GRAPHICS_API_METAL 1 // Metal exists
#endif // XR_OS_APPLE_MACOS
#include "xr_dependencies.h" // IWYU pragma: export
#endif // API_LAYER_PLATFORM_DEFINES_H_

View File

@@ -0,0 +1,932 @@
// Copyright (c) 2017-2019 The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// 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.
//
// Author: Mark Young <marky@lunarg.com>
//
#include "api_layer_platform_defines.h"
#include "extra_algorithms.h"
#include "hex_and_handles.h"
#include "loader_interfaces.h"
#include "platform_utils.hpp"
#include "validation_utils.h"
#include "xr_generated_core_validation.hpp"
#include "xr_generated_dispatch_table.h"
#include <openxr/openxr.h>
#include <algorithm>
#include <cctype>
#include <cstring>
#include <fstream>
#include <iostream>
#include <memory>
#include <mutex>
#include <sstream>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#if defined(__GNUC__) && __GNUC__ >= 4
#define LAYER_EXPORT __attribute__((visibility("default")))
#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)
#define LAYER_EXPORT __attribute__((visibility("default")))
#else
#define LAYER_EXPORT
#endif
// Log recording information
enum CoreValidationRecordType {
RECORD_NONE = 0,
RECORD_TEXT_COUT,
RECORD_TEXT_FILE,
RECORD_HTML_FILE,
};
struct CoreValidationRecordInfo {
bool initialized;
CoreValidationRecordType type;
std::string file_name;
};
static CoreValidationRecordInfo g_record_info = {};
static std::mutex g_record_mutex = {};
// HTML utilities
bool CoreValidationWriteHtmlHeader() {
try {
std::unique_lock<std::mutex> mlock(g_record_mutex);
std::ofstream html_file;
html_file.open(g_record_info.file_name, std::ios::out);
html_file
<< "<!doctype html>\n"
"<html>\n"
" <head>\n"
" <title>OpenXR Core Validation</title>\n"
" <style type='text/css'>\n"
" html {\n"
" background-color: #0b1e48;\n"
" background-image: url('https://vulkan.lunarg.com/img/bg-starfield.jpg');\n"
" background-position: center;\n"
" -webkit-background-size: cover;\n"
" -moz-background-size: cover;\n"
" -o-background-size: cover;\n"
" background-size: cover;\n"
" background-attachment: fixed;\n"
" background-repeat: no-repeat;\n"
" height: 100%;\n"
" }\n"
" #header {\n"
" z-index: -1;\n"
" }\n"
" #header>img {\n"
" position: absolute;\n"
" width: 160px;\n"
" margin-left: -280px;\n"
" top: -10px;\n"
" left: 50%;\n"
" }\n"
" #header>h1 {\n"
" font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif;\n"
" font-size: 48px;\n"
" font-weight: 200;\n"
" text-shadow: 4px 4px 5px #000;\n"
" color: #eee;\n"
" position: absolute;\n"
" width: 600px;\n"
" margin-left: -80px;\n"
" top: 8px;\n"
" left: 50%;\n"
" }\n"
" body {\n"
" font-family: Consolas, monaco, monospace;\n"
" font-size: 14px;\n"
" line-height: 20px;\n"
" color: #eee;\n"
" height: 100%;\n"
" margin: 0;\n"
" overflow: hidden;\n"
" }\n"
" #wrapper {\n"
" background-color: rgba(0, 0, 0, 0.7);\n"
" border: 1px solid #446;\n"
" box-shadow: 0px 0px 10px #000;\n"
" padding: 8px 12px;\n"
" display: inline-block;\n"
" position: absolute;\n"
" top: 80px;\n"
" bottom: 25px;\n"
" left: 50px;\n"
" right: 50px;\n"
" overflow: auto;\n"
" }\n"
" details>*:not(summary) {\n"
" margin-left: 22px;\n"
" }\n"
" summary:only-child {\n"
" display: block;\n"
" padding-left: 15px;\n"
" }\n"
" details>summary:only-child::-webkit-details-marker {\n"
" display: none;\n"
" padding-left: 15px;\n"
" }\n"
" .headervar, .generalheadertype, .warningheadertype, .errorheadertype, .debugheadertype, .headerval {\n"
" display: inline;\n"
" margin: 0 9px;\n"
" }\n"
" .var, .type, .val {\n"
" display: inline;\n"
" margin: 0 6px;\n"
" }\n"
" .warningheadertype, .type {\n"
" color: #dce22f;\n"
" }\n"
" .errorheadertype, .type {\n"
" color: #ff1616;\n"
" }\n"
" .debugheadertype, .type {\n"
" color: #888;\n"
" }\n"
" .generalheadertype, .type {\n"
" color: #acf;\n"
" }\n"
" .headerval, .val {\n"
" color: #afa;\n"
" text-align: right;\n"
" }\n"
" .thd {\n"
" color: #888;\n"
" }\n"
" </style>\n"
" </head>\n"
" <body>\n"
" <div id='header'>\n"
" <img src='https://lunarg.com/wp-content/uploads/2016/02/LunarG-wReg-150.png' />\n"
" <h1>OpenXR Core Validation</h1>\n"
" </div>\n"
" <div id='wrapper'>\n";
return true;
} catch (...) {
return false;
}
}
bool CoreValidationWriteHtmlFooter() {
try {
std::unique_lock<std::mutex> mlock(g_record_mutex);
std::ofstream html_file;
html_file.open(g_record_info.file_name, std::ios::out | std::ios::app);
html_file << " </div>\n"
" </body>\n"
"</html>";
// Writing the footer means we're done.
if (g_record_info.initialized) {
g_record_info.initialized = false;
g_record_info.type = RECORD_NONE;
}
return true;
} catch (...) {
return false;
}
}
// Function to record all the core validation information
void CoreValidLogMessage(GenValidUsageXrInstanceInfo *instance_info, const std::string &message_id,
GenValidUsageDebugSeverity message_severity, const std::string &command_name,
std::vector<GenValidUsageXrObjectInfo> objects_info, const std::string &message) {
if (g_record_info.initialized) {
std::unique_lock<std::mutex> mlock(g_record_mutex);
// Debug Utils items (in case we need them)
XrDebugUtilsMessageSeverityFlagsEXT debug_utils_severity = 0;
std::vector<XrDebugUtilsObjectNameInfoEXT> debug_utils_objects;
std::vector<XrDebugUtilsLabelEXT> session_labels;
std::string severity_string;
switch (message_severity) {
case VALID_USAGE_DEBUG_SEVERITY_DEBUG:
severity_string = "VALID_DEBUG";
debug_utils_severity = XR_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
break;
case VALID_USAGE_DEBUG_SEVERITY_INFO:
severity_string = "VALID_INFO";
debug_utils_severity = XR_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
break;
case VALID_USAGE_DEBUG_SEVERITY_WARNING:
severity_string = "VALID_WARNING";
debug_utils_severity = XR_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
break;
case VALID_USAGE_DEBUG_SEVERITY_ERROR:
severity_string = "VALID_ERROR";
debug_utils_severity = XR_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
break;
default:
severity_string = "VALID_UNKNOWN";
break;
}
// If we have instance information, see if we need to log this information out to a debug messenger
// callback.
if (nullptr != instance_info) {
if (!objects_info.empty()) {
for (auto &obj : objects_info) {
XrDebugUtilsObjectNameInfoEXT obj_name_info = {};
obj_name_info.next = nullptr;
obj_name_info.objectType = obj.type;
obj_name_info.objectHandle = obj.handle;
// If there's a session in the list, see if it has labels
if (XR_OBJECT_TYPE_SESSION == obj.type) {
XrSession session = TreatIntegerAsHandle<XrSession>(obj.handle);
auto session_label_iterator = g_xr_session_labels.find(session);
if (session_label_iterator != g_xr_session_labels.end()) {
auto rev_iter = session_label_iterator->second->rbegin();
for (; rev_iter != session_label_iterator->second->rend(); ++rev_iter) {
session_labels.push_back((*rev_iter)->debug_utils_label);
}
}
}
// Loop through all object names and see if any match
for (auto &object_name : instance_info->object_names) {
if (object_name->objectType == obj.type && object_name->objectHandle == obj.handle) {
obj_name_info.objectName = object_name->objectName;
break;
}
}
debug_utils_objects.push_back(obj_name_info);
}
}
if (!instance_info->debug_messengers.empty()) {
// Setup our callback data once
XrDebugUtilsMessengerCallbackDataEXT callback_data = {};
callback_data.type = XR_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT;
callback_data.messageId = message_id.c_str();
callback_data.functionName = command_name.c_str();
callback_data.message = message.c_str();
callback_data.objectCount = static_cast<uint8_t>(debug_utils_objects.size());
if (debug_utils_objects.empty()) {
callback_data.objects = nullptr;
} else {
callback_data.objects = debug_utils_objects.data();
}
callback_data.sessionLabelCount = static_cast<uint8_t>(session_labels.size());
if (session_labels.empty()) {
callback_data.sessionLabels = nullptr;
} else {
callback_data.sessionLabels = session_labels.data();
}
// Loop through all active messengers and give each a chance to output information
for (auto &debug_messenger : instance_info->debug_messengers) {
CoreValidationMessengerInfo *validation_messenger_info = debug_messenger.get();
XrDebugUtilsMessengerCreateInfoEXT *messenger_create_info = validation_messenger_info->create_info;
// If a callback exists, and the message is of a type this callback cares about, call it.
if (nullptr != messenger_create_info->userCallback &&
0 != (messenger_create_info->messageSeverities & debug_utils_severity) &&
0 != (messenger_create_info->messageTypes & XR_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT)) {
XrBool32 ret_val = messenger_create_info->userCallback(debug_utils_severity,
XR_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT,
&callback_data, messenger_create_info->userData);
}
}
}
}
switch (g_record_info.type) {
case RECORD_TEXT_COUT: {
std::cout << "[" << severity_string << " | " << message_id << " | " << command_name << "]: " << message
<< std::endl;
if (!objects_info.empty()) {
std::cout << " Objects:" << std::endl;
uint32_t count = 0;
for (auto object_info : objects_info) {
std::string object_type = GenValidUsageXrObjectTypeToString(object_info.type);
std::ostringstream oss_object_handle;
std::cout << " [" << std::to_string(count++) << "] - " << object_type << " ("
<< Uint64ToHexString(object_info.handle) << ")";
std::cout << std::endl;
}
}
if (!session_labels.empty()) {
std::cout << " Session Labels:" << std::endl;
uint32_t count = 0;
for (auto session_label : session_labels) {
std::cout << " [" << std::to_string(count++) << "] - " << session_label.labelName << std::endl;
}
}
std::cout << std::flush;
break;
}
case RECORD_TEXT_FILE: {
std::ofstream text_file;
text_file.open(g_record_info.file_name, std::ios::out | std::ios::app);
text_file << "[" << severity_string << " | " << message_id << " | " << command_name << "]: " << message
<< std::endl;
if (!objects_info.empty()) {
text_file << " Objects:" << std::endl;
uint32_t count = 0;
for (auto object_info : objects_info) {
std::string object_type = GenValidUsageXrObjectTypeToString(object_info.type);
text_file << " [" << std::to_string(count++) << "] - " << object_type << " ("
<< Uint64ToHexString(object_info.handle) << ")";
text_file << std::endl;
}
}
if (!session_labels.empty()) {
text_file << " Session Labels:" << std::endl;
uint32_t count = 0;
for (auto session_label : session_labels) {
text_file << " [" << std::to_string(count++) << "] - " << session_label.labelName << std::endl;
}
}
text_file << std::flush;
text_file.close();
break;
}
case RECORD_HTML_FILE: {
std::ofstream text_file;
text_file.open(g_record_info.file_name, std::ios::out | std::ios::app);
text_file << "<details class='data'>\n";
std::string header_type = "generalheadertype";
switch (message_severity) {
case VALID_USAGE_DEBUG_SEVERITY_DEBUG:
header_type = "debugheadertype";
severity_string = "Debug Message";
break;
case VALID_USAGE_DEBUG_SEVERITY_INFO:
severity_string = "Info Message";
break;
case VALID_USAGE_DEBUG_SEVERITY_WARNING:
header_type = "warningheadertype";
severity_string = "Warning Message";
break;
case VALID_USAGE_DEBUG_SEVERITY_ERROR:
header_type = "errorheadertype";
severity_string = "Error Message";
break;
default:
severity_string = "Unknown Message";
break;
}
text_file << " <summary>\n"
<< " <div class='" << header_type << "'>" << severity_string << "</div>\n"
<< " <div class='headerval'>" << command_name << "</div>\n"
<< " <div class='headervar'>" << message_id << "</div>\n"
<< " </summary>\n";
text_file << " <div class='data'>\n";
text_file << " <div class='val'>" << message << "</div>\n";
if (!objects_info.empty()) {
text_file << " <details class='data'>\n";
text_file << " <summary>\n";
text_file << " <div class='type'>Relevant OpenXR Objects</div>\n";
text_file << " </summary>\n";
uint32_t count = 0;
for (auto object_info : objects_info) {
std::string object_type = GenValidUsageXrObjectTypeToString(object_info.type);
text_file << " <div class='data'>\n";
text_file << " <div class='var'>[" << count++ << "]</div>\n";
text_file << " <div class='type'>" << object_type << "</div>\n";
text_file << " <div class='val'>" << Uint64ToHexString(object_info.handle) << "</div>\n";
text_file << " </div>\n";
}
text_file << " </details>\n";
text_file << std::flush;
}
if (!session_labels.empty()) {
text_file << " <details class='data'>\n";
text_file << " <summary>\n";
text_file << " <div class='type'>Relevant Session Labels</div>\n";
text_file << " </summary>\n";
uint32_t count = 0;
for (auto session_label : session_labels) {
text_file << " <div class='data'>\n";
text_file << " <div class='var'>[" << count++ << "]</div>\n";
text_file << " <div class='type'>" << session_label.labelName << "</div>\n";
text_file << " </div>\n";
}
text_file << " </details>\n";
}
text_file << " </div>\n";
text_file << "</details>\n";
break;
}
default:
break;
}
}
}
void reportInternalError(std::string const &message) {
std::cerr << "INTERNAL VALIDATION LAYER ERROR: " << message << std::endl;
throw std::runtime_error("Internal validation layer error: " + message);
}
void InvalidStructureType(GenValidUsageXrInstanceInfo *instance_info, const std::string &command_name,
std::vector<GenValidUsageXrObjectInfo> &objects_info, const char *structure_name, XrStructureType type,
const char *vuid, XrStructureType expected, const char *expected_name) {
std::ostringstream oss_type;
oss_type << structure_name << " has an invalid XrStructureType ";
oss_type << Uint32ToHexString(static_cast<uint32_t>(type));
if (expected != 0) {
oss_type << ", expected " << Uint32ToHexString(static_cast<uint32_t>(type));
oss_type << " (" << expected_name << ")";
}
if (vuid != nullptr) {
CoreValidLogMessage(instance_info, vuid, VALID_USAGE_DEBUG_SEVERITY_ERROR, command_name, objects_info, oss_type.str());
} else {
CoreValidLogMessage(instance_info, "VUID-" + std::string(structure_name) + "-type-type", VALID_USAGE_DEBUG_SEVERITY_ERROR,
command_name, objects_info, oss_type.str());
}
}
// NOTE: Can't validate the following VUIDs since the command never enters a layer:
// Command: xrEnumerateApiLayerProperties
// VUIDs: "VUID-xrEnumerateApiLayerProperties-propertyCountOutput-parameter"
// "VUID-xrEnumerateApiLayerProperties-properties-parameter"
// Command: xrEnumerateInstanceExtensionProperties
// VUIDs: "VUID-xrEnumerateInstanceExtensionProperties-layerName-parameter"
// "VUID-xrEnumerateInstanceExtensionProperties-propertyCountOutput-parameter"
// "VUID-xrEnumerateInstanceExtensionProperties-properties-parameter"
XrResult CoreValidationXrCreateInstance(const XrInstanceCreateInfo * /*info*/, XrInstance * /*instance*/) {
// Shouldn't be called, coreValidationXrCreateApiLayerInstance should called instead
return XR_SUCCESS;
}
GenValidUsageXrInstanceInfo::GenValidUsageXrInstanceInfo(XrInstance inst, PFN_xrGetInstanceProcAddr next_get_instance_proc_addr)
: instance(inst), dispatch_table(new XrGeneratedDispatchTable()) {
/// @todo smart pointer here!
// Create the dispatch table to the next levels
GeneratedXrPopulateDispatchTable(dispatch_table, instance, next_get_instance_proc_addr);
}
GenValidUsageXrInstanceInfo::~GenValidUsageXrInstanceInfo() { delete dispatch_table; }
// See if there is a debug utils create structure in the "next" chain
XrResult CoreValidationXrCreateApiLayerInstance(const XrInstanceCreateInfo *info, const struct XrApiLayerCreateInfo *apiLayerInfo,
XrInstance *instance) {
try {
XrApiLayerCreateInfo new_api_layer_info = {};
XrResult validation_result = XR_SUCCESS;
bool user_defined_output = false;
bool first_time = !g_record_info.initialized;
if (!g_record_info.initialized) {
g_record_info.initialized = true;
g_record_info.type = RECORD_NONE;
}
char *export_type = PlatformUtilsGetEnv("XR_CORE_VALIDATION_EXPORT_TYPE");
char *file_name = PlatformUtilsGetEnv("XR_CORE_VALIDATION_FILE_NAME");
if (nullptr != file_name) {
g_record_info.file_name = file_name;
PlatformUtilsFreeEnv(file_name);
}
if (nullptr != export_type) {
std::string string_export_type = export_type;
PlatformUtilsFreeEnv(export_type);
std::transform(string_export_type.begin(), string_export_type.end(), string_export_type.begin(),
[](unsigned char c) { return std::tolower(c); });
std::cerr << "Core Validation output type: " << string_export_type << ", first time = " << std::to_string(first_time)
<< std::endl;
if (string_export_type == "text") {
if (!g_record_info.file_name.empty()) {
g_record_info.type = RECORD_TEXT_FILE;
} else {
g_record_info.type = RECORD_TEXT_COUT;
}
user_defined_output = true;
} else if (string_export_type == "html" && first_time) {
g_record_info.type = RECORD_HTML_FILE;
if (!CoreValidationWriteHtmlHeader()) {
return XR_ERROR_INITIALIZATION_FAILED;
}
}
}
// Call the generated pre valid usage check.
validation_result = GenValidUsageInputsXrCreateInstance(info, instance);
// Copy the contents of the layer info struct, but then move the next info up by
// one slot so that the next layer gets information.
memcpy(&new_api_layer_info, apiLayerInfo, sizeof(XrApiLayerCreateInfo));
new_api_layer_info.nextInfo = apiLayerInfo->nextInfo->next;
// Get the function pointers we need
PFN_xrGetInstanceProcAddr next_get_instance_proc_addr = apiLayerInfo->nextInfo->nextGetInstanceProcAddr;
PFN_xrCreateApiLayerInstance next_create_api_layer_instance = apiLayerInfo->nextInfo->nextCreateApiLayerInstance;
// Create the instance using the layer create instance command for the next layer
XrInstance returned_instance = *instance;
XrResult next_result = next_create_api_layer_instance(info, &new_api_layer_info, &returned_instance);
*instance = returned_instance;
// Create the instance information
std::unique_ptr<GenValidUsageXrInstanceInfo> instance_info(
new GenValidUsageXrInstanceInfo(returned_instance, next_get_instance_proc_addr));
// Save the enabled extensions.
for (uint32_t extension = 0; extension < info->enabledExtensionCount; ++extension) {
instance_info->enabled_extensions.emplace_back(info->enabledExtensionNames[extension]);
}
g_instance_info.insert(returned_instance, std::move(instance_info));
// See if a debug utils messenger is supposed to be created as part of the instance
// NOTE: We have to wait until after the instance info is added to the map for this
// to work properly.
const auto *next_header = reinterpret_cast<const XrBaseInStructure *>(info->next);
const XrDebugUtilsMessengerCreateInfoEXT *dbg_utils_create_info = nullptr;
while (next_header != nullptr) {
if (next_header->type == XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) {
dbg_utils_create_info = reinterpret_cast<const XrDebugUtilsMessengerCreateInfoEXT *>(next_header);
// Create the debug messenger. We don't have to keep track of it because it will be tracked as part
// of the instance info from here on out.
XrDebugUtilsMessengerEXT messenger;
validation_result = CoreValidationXrCreateDebugUtilsMessengerEXT(*instance, dbg_utils_create_info, &messenger);
// If we created a debug messenger, turn off the text output unless a user indicates they wanted it
if (XR_SUCCESS == validation_result && !user_defined_output) {
g_record_info.type = RECORD_NONE;
}
break;
}
next_header = reinterpret_cast<const XrBaseInStructure *>(next_header->next);
}
if (XR_SUCCESS == validation_result) {
return next_result;
}
return validation_result;
} catch (std::bad_alloc &) {
return XR_ERROR_OUT_OF_MEMORY;
} catch (...) {
return XR_ERROR_INITIALIZATION_FAILED;
}
}
void EraseAllInstanceTableMapElements(GenValidUsageXrInstanceInfo *search_value) {
typedef typename InstanceHandleInfo::value_t value_t;
auto map_with_lock = g_instance_info.lockMap();
auto &map = map_with_lock.second;
map_erase_if(map, [=](value_t const &data) { return data.second.get() == search_value; });
}
XrResult CoreValidationXrDestroyInstance(XrInstance instance) {
GenValidUsageInputsXrDestroyInstance(instance);
if (XR_NULL_HANDLE != instance) {
auto info_with_lock = g_instance_info.getWithLock(instance);
GenValidUsageXrInstanceInfo *gen_instance_info = info_with_lock.second;
if (nullptr != gen_instance_info) {
gen_instance_info->object_names.clear();
gen_instance_info->debug_messengers.clear();
}
}
XrResult result = GenValidUsageNextXrDestroyInstance(instance);
if (!g_instance_info.empty() && g_record_info.type == RECORD_HTML_FILE) {
CoreValidationWriteHtmlFooter();
}
return result;
return XR_SUCCESS;
}
XrResult CoreValidationXrCreateSession(XrInstance instance, const XrSessionCreateInfo *createInfo, XrSession *session) {
try {
XrResult test_result = GenValidUsageInputsXrCreateSession(instance, createInfo, session);
if (XR_SUCCESS != test_result) {
return test_result;
}
GenValidUsageXrInstanceInfo *gen_instance_info = g_instance_info.get(instance);
// Check the next chain for a graphics binding structure, we need at least one.
uint32_t num_graphics_bindings_found = 0;
const auto *cur_ptr = reinterpret_cast<const XrBaseInStructure *>(createInfo->next);
while (nullptr != cur_ptr) {
switch (cur_ptr->type) {
default:
continue;
#ifdef XR_USE_PLATFORM_WIN32
case XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR:
num_graphics_bindings_found++;
break;
#endif
#ifdef XR_USE_PLATFORM_XLIB
case XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR:
num_graphics_bindings_found++;
break;
#endif
#ifdef XR_USE_PLATFORM_XCB
case XR_TYPE_GRAPHICS_BINDING_OPENGL_XCB_KHR:
num_graphics_bindings_found++;
break;
#endif
#ifdef XR_USE_PLATFORM_WAYLAND
case XR_TYPE_GRAPHICS_BINDING_OPENGL_WAYLAND_KHR:
num_graphics_bindings_found++;
break;
#endif
}
cur_ptr = reinterpret_cast<const XrBaseInStructure *>(cur_ptr->next);
}
auto const &enabled_extensions = gen_instance_info->enabled_extensions;
#ifdef XR_KHR_headless
bool has_headless = (enabled_extensions.end() !=
std::find(enabled_extensions.begin(), enabled_extensions.end(), XR_KHR_HEADLESS_EXTENSION_NAME));
#else
bool has_headless = false;
#endif // XR_KHR_headless
bool got_right_graphics_binding_count = (num_graphics_bindings_found == 1);
if (!got_right_graphics_binding_count && has_headless) {
// This permits 0 as well.
got_right_graphics_binding_count = (num_graphics_bindings_found == 0);
}
if (!got_right_graphics_binding_count) {
std::vector<GenValidUsageXrObjectInfo> objects_info;
objects_info.emplace_back(instance, XR_OBJECT_TYPE_INSTANCE);
std::ostringstream error_stream;
error_stream << "Invalid number of graphics binding structures provided. ";
error_stream << "Expected ";
if (has_headless) {
error_stream << "0 or 1";
} else {
error_stream << "1";
}
error_stream << ", but received ";
error_stream << num_graphics_bindings_found;
error_stream << ".";
// TODO: This needs to be updated with the actual VUID once we generate it.
CoreValidLogMessage(gen_instance_info, "VUID-xrCreateSession-next-parameter", VALID_USAGE_DEBUG_SEVERITY_ERROR,
"xrCreateSession", objects_info, error_stream.str());
return XR_ERROR_GRAPHICS_DEVICE_INVALID;
}
return GenValidUsageNextXrCreateSession(instance, createInfo, session);
} catch (...) {
return XR_SUCCESS;
}
}
// ---- XR_EXT_debug_utils extension commands
XrResult CoreValidationXrSetDebugUtilsObjectNameEXT(XrInstance instance, const XrDebugUtilsObjectNameInfoEXT *nameInfo) {
try {
XrResult result = GenValidUsageInputsXrSetDebugUtilsObjectNameEXT(instance, nameInfo);
if (!XR_UNQUALIFIED_SUCCESS(result)) {
return result;
}
result = GenValidUsageNextXrSetDebugUtilsObjectNameEXT(instance, nameInfo);
if (!XR_UNQUALIFIED_SUCCESS(result)) {
return result;
}
auto info_with_lock = g_instance_info.getWithLock(instance);
GenValidUsageXrInstanceInfo *gen_instance_info = info_with_lock.second;
if (nullptr != gen_instance_info) {
// Create a copy of the base object name info (no next items)
auto len = strlen(nameInfo->objectName);
char *name_string = new char[len + 1];
strncpy(name_string, nameInfo->objectName, len);
bool found = false;
for (auto &object_name : gen_instance_info->object_names) {
if (object_name->objectHandle == nameInfo->objectHandle && object_name->objectType == nameInfo->objectType) {
delete[] object_name->objectName;
object_name->objectName = name_string;
found = true;
break;
}
}
if (!found) {
UniqueXrDebugUtilsObjectNameInfoEXT new_object_name(new XrDebugUtilsObjectNameInfoEXT(*nameInfo));
new_object_name->next = nullptr;
new_object_name->objectName = name_string;
gen_instance_info->object_names.push_back(std::move(new_object_name));
}
}
return result;
} catch (...) {
return XR_ERROR_VALIDATION_FAILURE;
}
}
XrResult CoreValidationXrCreateDebugUtilsMessengerEXT(XrInstance instance, const XrDebugUtilsMessengerCreateInfoEXT *createInfo,
XrDebugUtilsMessengerEXT *messenger) {
try {
XrResult result = GenValidUsageInputsXrCreateDebugUtilsMessengerEXT(instance, createInfo, messenger);
if (!XR_UNQUALIFIED_SUCCESS(result)) {
return result;
}
result = GenValidUsageNextXrCreateDebugUtilsMessengerEXT(instance, createInfo, messenger);
if (!XR_UNQUALIFIED_SUCCESS(result)) {
return result;
}
auto info_with_lock = g_instance_info.getWithLock(instance);
GenValidUsageXrInstanceInfo *gen_instance_info = info_with_lock.second;
if (nullptr != gen_instance_info) {
auto *new_create_info = new XrDebugUtilsMessengerCreateInfoEXT(*createInfo);
new_create_info->next = nullptr;
UniqueCoreValidationMessengerInfo new_messenger_info(new CoreValidationMessengerInfo);
new_messenger_info->messenger = *messenger;
new_messenger_info->create_info = new_create_info;
gen_instance_info->debug_messengers.push_back(std::move(new_messenger_info));
}
return result;
} catch (...) {
return XR_ERROR_VALIDATION_FAILURE;
}
}
XrResult CoreValidationXrDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT messenger) {
try {
XrResult result = GenValidUsageInputsXrDestroyDebugUtilsMessengerEXT(messenger);
if (!XR_UNQUALIFIED_SUCCESS(result)) {
return result;
}
result = GenValidUsageNextXrDestroyDebugUtilsMessengerEXT(messenger);
if (!XR_UNQUALIFIED_SUCCESS(result)) {
return result;
}
if (XR_NULL_HANDLE == messenger) {
return XR_ERROR_HANDLE_INVALID;
}
auto info_with_lock = g_debugutilsmessengerext_info.getWithLock(messenger);
GenValidUsageXrHandleInfo *gen_handle_info = info_with_lock.second;
if (nullptr != gen_handle_info) {
auto &debug_messengers = gen_handle_info->instance_info->debug_messengers;
vector_remove_if_and_erase(debug_messengers,
[=](UniqueCoreValidationMessengerInfo const &msg) { return msg->messenger == messenger; });
}
return result;
} catch (...) {
return XR_ERROR_VALIDATION_FAILURE;
}
}
// We always want to remove the old individual label before we do anything else.
// So, do that in it's own method
void CoreValidationRemoveIndividualLabel(std::vector<GenValidUsageXrInternalSessionLabel *> *label_vec) {
if (!label_vec->empty()) {
GenValidUsageXrInternalSessionLabel *cur_label = label_vec->back();
if (cur_label->is_individual_label) {
label_vec->pop_back();
delete cur_label;
}
}
}
void CoreValidationBeginLabelRegion(XrSession session, const XrDebugUtilsLabelEXT *label_info) {
std::vector<GenValidUsageXrInternalSessionLabel *> *vec_ptr = nullptr;
auto session_label_iterator = g_xr_session_labels.find(session);
if (session_label_iterator == g_xr_session_labels.end()) {
vec_ptr = new std::vector<GenValidUsageXrInternalSessionLabel *>;
g_xr_session_labels[session] = vec_ptr;
} else {
vec_ptr = session_label_iterator->second;
}
// Individual labels do not stay around in the transition into a new label region
CoreValidationRemoveIndividualLabel(vec_ptr);
// Start the new label region
auto *new_session_label = new GenValidUsageXrInternalSessionLabel;
new_session_label->label_name = label_info->labelName;
new_session_label->debug_utils_label = *label_info;
new_session_label->debug_utils_label.labelName = new_session_label->label_name.c_str();
new_session_label->is_individual_label = false;
vec_ptr->push_back(new_session_label);
}
void CoreValidationEndLabelRegion(XrSession session) {
auto session_label_iterator = g_xr_session_labels.find(session);
if (session_label_iterator == g_xr_session_labels.end()) {
return;
}
std::vector<GenValidUsageXrInternalSessionLabel *> *vec_ptr = session_label_iterator->second;
// Individual labels do not stay around in the transition out of label region
CoreValidationRemoveIndividualLabel(vec_ptr);
// Remove the last label region
if (!vec_ptr->empty()) {
GenValidUsageXrInternalSessionLabel *cur_label = vec_ptr->back();
vec_ptr->pop_back();
delete cur_label;
}
}
void CoreValidationInsertLabel(XrSession session, const XrDebugUtilsLabelEXT *label_info) {
std::vector<GenValidUsageXrInternalSessionLabel *> *vec_ptr = nullptr;
auto session_label_iterator = g_xr_session_labels.find(session);
if (session_label_iterator == g_xr_session_labels.end()) {
vec_ptr = new std::vector<GenValidUsageXrInternalSessionLabel *>;
g_xr_session_labels[session] = vec_ptr;
} else {
vec_ptr = session_label_iterator->second;
}
// Remove any individual layer that might already be there
CoreValidationRemoveIndividualLabel(vec_ptr);
// Insert a new individual label
auto *new_session_label = new GenValidUsageXrInternalSessionLabel;
new_session_label->label_name = label_info->labelName;
new_session_label->debug_utils_label = *label_info;
new_session_label->debug_utils_label.labelName = new_session_label->label_name.c_str();
new_session_label->is_individual_label = true;
vec_ptr->push_back(new_session_label);
}
// Called during xrDestroySession. We need to delete all session related labels.
void CoreValidationDeleteSessionLabels(XrSession session) {
std::vector<GenValidUsageXrInternalSessionLabel *> *vec_ptr = nullptr;
auto session_label_iterator = g_xr_session_labels.find(session);
if (session_label_iterator == g_xr_session_labels.end()) {
return;
}
vec_ptr = session_label_iterator->second;
while (!vec_ptr->empty()) {
delete vec_ptr->back();
vec_ptr->pop_back();
}
delete vec_ptr;
g_xr_session_labels.erase(session);
}
XrResult CoreValidationXrSessionBeginDebugUtilsLabelRegionEXT(XrSession session, const XrDebugUtilsLabelEXT *labelInfo) {
XrResult test_result = GenValidUsageInputsXrSessionBeginDebugUtilsLabelRegionEXT(session, labelInfo);
if (XR_SUCCESS != test_result) {
return test_result;
}
CoreValidationBeginLabelRegion(session, labelInfo);
return GenValidUsageNextXrSessionBeginDebugUtilsLabelRegionEXT(session, labelInfo);
}
XrResult CoreValidationXrSessionEndDebugUtilsLabelRegionEXT(XrSession session) {
XrResult test_result = GenValidUsageInputsXrSessionEndDebugUtilsLabelRegionEXT(session);
if (XR_SUCCESS != test_result) {
return test_result;
}
CoreValidationEndLabelRegion(session);
return GenValidUsageNextXrSessionEndDebugUtilsLabelRegionEXT(session);
}
XrResult CoreValidationXrSessionInsertDebugUtilsLabelEXT(XrSession session, const XrDebugUtilsLabelEXT *labelInfo) {
XrResult test_result = GenValidUsageInputsXrSessionInsertDebugUtilsLabelEXT(session, labelInfo);
if (XR_SUCCESS != test_result) {
return test_result;
}
CoreValidationInsertLabel(session, labelInfo);
return GenValidUsageNextXrSessionInsertDebugUtilsLabelEXT(session, labelInfo);
}
// ############################################################
// NOTE: Add new validation checking above this comment block
// ############################################################
extern "C" {
// Function used to negotiate an interface betewen the loader and an API layer. Each library exposing one or
// more API layers needs to expose at least this function.
LAYER_EXPORT XrResult xrNegotiateLoaderApiLayerInterface(const XrNegotiateLoaderInfo *loaderInfo, const char * /*apiLayerName*/,
XrNegotiateApiLayerRequest *apiLayerRequest) {
if (nullptr == loaderInfo || nullptr == apiLayerRequest || loaderInfo->structType != XR_LOADER_INTERFACE_STRUCT_LOADER_INFO ||
loaderInfo->structVersion != XR_LOADER_INFO_STRUCT_VERSION || loaderInfo->structSize != sizeof(XrNegotiateLoaderInfo) ||
apiLayerRequest->structType != XR_LOADER_INTERFACE_STRUCT_API_LAYER_REQUEST ||
apiLayerRequest->structVersion != XR_API_LAYER_INFO_STRUCT_VERSION ||
apiLayerRequest->structSize != sizeof(XrNegotiateApiLayerRequest) ||
loaderInfo->minInterfaceVersion > XR_CURRENT_LOADER_API_LAYER_VERSION ||
loaderInfo->maxInterfaceVersion < XR_CURRENT_LOADER_API_LAYER_VERSION ||
loaderInfo->maxInterfaceVersion > XR_CURRENT_LOADER_API_LAYER_VERSION ||
loaderInfo->maxApiVersion < XR_CORE_VALIDATION_API_VERSION || loaderInfo->minApiVersion > XR_CORE_VALIDATION_API_VERSION) {
return XR_ERROR_INITIALIZATION_FAILED;
}
apiLayerRequest->layerInterfaceVersion = XR_CURRENT_LOADER_API_LAYER_VERSION;
apiLayerRequest->layerApiVersion = XR_CORE_VALIDATION_API_VERSION;
apiLayerRequest->getInstanceProcAddr = reinterpret_cast<PFN_xrGetInstanceProcAddr>(GenValidUsageXrGetInstanceProcAddr);
apiLayerRequest->createApiLayerInstance =
reinterpret_cast<PFN_xrCreateApiLayerInstance>(CoreValidationXrCreateApiLayerInstance);
return XR_SUCCESS;
}
} // extern "C"

View File

@@ -0,0 +1,324 @@
// Copyright (c) 2018-2019 The Khronos Group Inc.
// Copyright (c) 2018-2019 Valve Corporation
// Copyright (c) 2018-2019 LunarG, Inc.
// Copyright (c) 2019, Collabora, Ltd.
//
// 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.
//
// Author: Ryan Pavlik <ryan.pavlik@collabora.com>
// Mark Young <marky@lunarg.com>
//
#ifndef VALIDATION_UTILS_H_
#define VALIDATION_UTILS_H_ 1
#include "api_layer_platform_defines.h"
#include "hex_and_handles.h"
#include "extra_algorithms.h"
#include <openxr/openxr.h>
#include <openxr/openxr_platform.h>
#include <vector>
#include <unordered_map>
#include <string>
#include <mutex>
#include <memory>
/// Prints a message to stderr then throws an exception.
///
/// The printing of the message is because the exception will probably be caught and silently turned into a validation error.
[[noreturn]] void reportInternalError(std::string const &message);
// Structure used for storing the instance information we need for validating
// various aspects of the OpenXR API.
// Debug Utils items
struct CoreValidationMessengerInfo {
XrDebugUtilsMessengerEXT messenger;
XrDebugUtilsMessengerCreateInfoEXT *create_info;
};
struct XrGeneratedDispatchTable;
struct CoreValidationMessengerInfoDeleter {
void operator()(CoreValidationMessengerInfo *ptr) const {
delete ptr->create_info;
delete ptr;
}
};
struct XrDebugUtilsObjectNameInfoEXTDeleter {
void operator()(XrDebugUtilsObjectNameInfoEXT *ptr) const {
delete ptr->objectName;
delete ptr;
}
};
typedef std::unique_ptr<XrDebugUtilsObjectNameInfoEXT, XrDebugUtilsObjectNameInfoEXTDeleter> UniqueXrDebugUtilsObjectNameInfoEXT;
typedef std::unique_ptr<CoreValidationMessengerInfo, CoreValidationMessengerInfoDeleter> UniqueCoreValidationMessengerInfo;
// Define the instance struct used for passing information around.
// This information includes things like the dispatch table as well as the
// enabled extensions.
struct GenValidUsageXrInstanceInfo {
GenValidUsageXrInstanceInfo(XrInstance inst, PFN_xrGetInstanceProcAddr next_get_instance_proc_addr);
~GenValidUsageXrInstanceInfo();
const XrInstance instance;
XrGeneratedDispatchTable *dispatch_table;
std::vector<std::string> enabled_extensions;
std::vector<UniqueCoreValidationMessengerInfo> debug_messengers;
std::vector<UniqueXrDebugUtilsObjectNameInfoEXT> object_names;
};
// Structure used for storing information for other handles
struct GenValidUsageXrHandleInfo {
GenValidUsageXrInstanceInfo *instance_info;
XrObjectType direct_parent_type;
uint64_t direct_parent_handle;
};
// Structure used for storing session label information
struct GenValidUsageXrInternalSessionLabel {
XrDebugUtilsLabelEXT debug_utils_label;
std::string label_name;
bool is_individual_label;
};
// Enum used for indicating handle validation status.
enum ValidateXrHandleResult {
VALIDATE_XR_HANDLE_NULL,
VALIDATE_XR_HANDLE_INVALID,
VALIDATE_XR_HANDLE_SUCCESS,
};
// Unordered Map associating pointer to a vector of session label information to a session's handle
extern std::unordered_map<XrSession, std::vector<GenValidUsageXrInternalSessionLabel *> *> g_xr_session_labels;
// This function is used to delete session labels when a session is destroyed
extern void CoreValidationDeleteSessionLabels(XrSession session);
// Object information used for logging.
struct GenValidUsageXrObjectInfo {
uint64_t handle;
XrObjectType type;
GenValidUsageXrObjectInfo() = default;
template <typename T>
GenValidUsageXrObjectInfo(T h, XrObjectType t) : handle(MakeHandleGeneric(h)), type(t) {}
};
// Debug message severity levels for logging.
enum GenValidUsageDebugSeverity {
VALID_USAGE_DEBUG_SEVERITY_DEBUG = 0,
VALID_USAGE_DEBUG_SEVERITY_INFO = 7,
VALID_USAGE_DEBUG_SEVERITY_WARNING = 14,
VALID_USAGE_DEBUG_SEVERITY_ERROR = 21,
};
// in core_validation.cpp
void EraseAllInstanceTableMapElements(GenValidUsageXrInstanceInfo *search_value);
typedef std::unique_lock<std::mutex> UniqueLock;
template <typename HandleType, typename InfoType>
class HandleInfoBase {
public:
typedef InfoType info_t;
typedef HandleType handle_t;
typedef std::unordered_map<HandleType, std::unique_ptr<InfoType>> map_t;
typedef typename map_t::value_type value_t;
/// Validate a handle.
///
/// Returns an enum indicating null, invalid (not found), or success.
ValidateXrHandleResult verifyHandle(HandleType const *handle_to_check);
/// Lookup a handle.
/// Throws if not found.
InfoType *get(HandleType handle);
/// Lookup a handle, returning a pointer (if found) as well as a lock for this object's dispatch mutex.
std::pair<UniqueLock, InfoType *> getWithLock(HandleType handle);
bool empty() const { return info_map_.empty(); }
/// Insert an info for the supplied handle.
/// Throws if it's already there.
void insert(HandleType handle, std::unique_ptr<InfoType> &&info);
/// Remove the info associated with the supplied handle.
/// Throws if not found.
void erase(HandleType handle);
/// Get a constant reference to the whole map as well as a lock for this object's dispatch mutex.
std::pair<UniqueLock, map_t const &> lockMapConst();
/// Get a reference to the whole map as well as a lock for this object's dispatch mutex.
std::pair<UniqueLock, map_t &> lockMap();
protected:
map_t info_map_;
std::mutex dispatch_mutex_;
};
/// Subclass used exclusively for instances.
class InstanceHandleInfo : public HandleInfoBase<XrInstance, GenValidUsageXrInstanceInfo> {
public:
typedef HandleInfoBase<XrInstance, GenValidUsageXrInstanceInfo> base_t;
typedef typename base_t::info_t info_t;
typedef typename base_t::handle_t handle_t;
};
/// Generic handle info for everything-except-instance handles.
template <typename HandleType>
class HandleInfo : public HandleInfoBase<HandleType, GenValidUsageXrHandleInfo> {
public:
typedef HandleInfoBase<HandleType, GenValidUsageXrHandleInfo> base_t;
typedef typename base_t::info_t info_t;
typedef typename base_t::handle_t handle_t;
/// Lookup a handle and its instance info
/// Throws if not found.
std::pair<GenValidUsageXrHandleInfo *, GenValidUsageXrInstanceInfo *> getWithInstanceInfo(HandleType handle);
/// Removes handles associated with an instance.
void removeHandlesForInstance(GenValidUsageXrInstanceInfo *search_value);
};
/// Function to record all the core validation information
void CoreValidLogMessage(GenValidUsageXrInstanceInfo *instance_info, const std::string &message_id,
GenValidUsageDebugSeverity message_severity, const std::string &command_name,
std::vector<GenValidUsageXrObjectInfo> objects_info, const std::string &message);
void InvalidStructureType(GenValidUsageXrInstanceInfo *instance_info, const std::string &command_name,
std::vector<GenValidUsageXrObjectInfo> &objects_info, const char *structure_name, XrStructureType type,
const char *vuid = nullptr, XrStructureType expected = XrStructureType(0),
const char *expected_name = "");
// -- Only implementations of templates follow --//
template <typename HT, typename IT>
inline std::pair<UniqueLock, typename HandleInfoBase<HT, IT>::map_t const &> HandleInfoBase<HT, IT>::lockMapConst() {
return {UniqueLock(dispatch_mutex_), info_map_};
}
template <typename HT, typename IT>
inline std::pair<UniqueLock, typename HandleInfoBase<HT, IT>::map_t &> HandleInfoBase<HT, IT>::lockMap() {
return {UniqueLock(dispatch_mutex_), info_map_};
}
template <typename HandleType, typename InfoType>
inline ValidateXrHandleResult HandleInfoBase<HandleType, InfoType>::verifyHandle(HandleType const *handle_to_check) {
try {
if (nullptr == handle_to_check) {
return VALIDATE_XR_HANDLE_INVALID;
}
// XR_NULL_HANDLE is valid in some cases, so we want to return that we found that value
// and let the calling function decide what to do with it.
if (*handle_to_check == XR_NULL_HANDLE) {
return VALIDATE_XR_HANDLE_NULL;
}
// Try to find the handle in the appropriate map
UniqueLock lock(dispatch_mutex_);
auto entry_returned = info_map_.find(*handle_to_check);
// If it is not a valid handle, it should return the end of the map.
if (info_map_.end() == entry_returned) {
return VALIDATE_XR_HANDLE_INVALID;
}
return VALIDATE_XR_HANDLE_SUCCESS;
} catch (...) {
return VALIDATE_XR_HANDLE_INVALID;
}
}
template <typename HandleType, typename InfoType>
inline InfoType *HandleInfoBase<HandleType, InfoType>::get(HandleType handle) {
if (handle == XR_NULL_HANDLE) {
reportInternalError("Null handle passed to HandleInfoBase::get()");
}
// Try to find the handle in the appropriate map
UniqueLock lock(dispatch_mutex_);
auto entry_returned = info_map_.find(handle);
if (entry_returned == info_map_.end()) {
reportInternalError("Handle passed to HandleInfoBase::insert() not inserted");
}
return entry_returned->second.get();
}
template <typename HandleType, typename InfoType>
inline std::pair<UniqueLock, InfoType *> HandleInfoBase<HandleType, InfoType>::getWithLock(HandleType handle) {
if (handle == XR_NULL_HANDLE) {
reportInternalError("Null handle passed to HandleInfoBase::getWithLock()");
}
// Try to find the handle in the appropriate map
UniqueLock lock(dispatch_mutex_);
auto it = info_map_.find(handle);
// If it is not a valid handle, it should return the end of the map.
if (info_map_.end() == it) {
return {std::move(lock), nullptr};
}
return {std::move(lock), it->second.get()};
}
template <typename HandleType, typename InfoType>
inline void HandleInfoBase<HandleType, InfoType>::insert(HandleType handle, std::unique_ptr<InfoType> &&info) {
if (handle == XR_NULL_HANDLE) {
reportInternalError("Null handle passed to HandleInfoBase::insert()");
}
UniqueLock lock(dispatch_mutex_);
auto entry_returned = info_map_.find(handle);
if (entry_returned != info_map_.end()) {
reportInternalError("Handle passed to HandleInfoBase::insert() already inserted");
}
info_map_[handle] = std::move(info);
}
template <typename HandleType, typename InfoType>
inline void HandleInfoBase<HandleType, InfoType>::erase(HandleType handle) {
if (handle == XR_NULL_HANDLE) {
reportInternalError("Null handle passed to HandleInfoBase::erase()");
}
UniqueLock lock(dispatch_mutex_);
auto entry_returned = info_map_.find(handle);
if (entry_returned == info_map_.end()) {
reportInternalError("Handle passed to HandleInfoBase::insert() not inserted");
}
info_map_.erase(handle);
}
template <typename HandleType>
inline std::pair<GenValidUsageXrHandleInfo *, GenValidUsageXrInstanceInfo *> HandleInfo<HandleType>::getWithInstanceInfo(
HandleType handle) {
if (handle == XR_NULL_HANDLE) {
reportInternalError("Null handle passed to HandleInfoBase::getWithInstanceInfo()");
}
// Try to find the handle in the appropriate map
UniqueLock lock(this->dispatch_mutex_);
auto entry_returned = this->info_map_.find(handle);
if (entry_returned == this->info_map_.end()) {
reportInternalError("Handle passed to HandleInfoBase::getWithInstanceInfo() not inserted");
}
GenValidUsageXrHandleInfo *info = entry_returned->second.get();
GenValidUsageXrInstanceInfo *instance_info = info->instance_info;
return {info, instance_info};
}
template <typename HandleType>
inline void HandleInfo<HandleType>::removeHandlesForInstance(GenValidUsageXrInstanceInfo *search_value) {
typedef typename base_t::value_t value_t;
UniqueLock lock(this->dispatch_mutex_);
map_erase_if(this->info_map_, [=](value_t const &data) { return data.second && data.second->instance_info == search_value; });
}
#endif // VALIDATION_UTILS_H_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,156 @@
// *********** THIS FILE IS GENERATED - DO NOT EDIT ***********
// See validation_layer_generator.py for modifications
// ************************************************************
// Copyright (c) 2017-2019 The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// 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.
//
// Author: Mark Young <marky@lunarg.com>
//
#pragma once
#include "xr_generated_dispatch_table.h"
#include "validation_utils.h"
#include "api_layer_platform_defines.h"
#include "xr_dependencies.h"
#include <openxr/openxr.h>
#include <openxr/openxr_platform.h>
#include <vector>
#include <string>
#include <unordered_map>
#include <thread>
#include <mutex>
// Unordered Map associating pointer to a vector of session label information to a session's handle
extern std::unordered_map<XrSession, std::vector<GenValidUsageXrInternalSessionLabel*>*> g_xr_session_labels;
// ---- Core 1.0 commands
XrResult GenValidUsageXrGetInstanceProcAddr(
XrInstance instance,
const char* name,
PFN_xrVoidFunction* function);
XrResult CoreValidationXrCreateInstance(
const XrInstanceCreateInfo* createInfo,
XrInstance* instance);
XrResult GenValidUsageInputsXrCreateInstance(const XrInstanceCreateInfo* createInfo, XrInstance* instance);
XrResult GenValidUsageNextXrCreateInstance(
const XrInstanceCreateInfo* createInfo,
XrInstance* instance);
XrResult CoreValidationXrDestroyInstance(
XrInstance instance);
XrResult GenValidUsageInputsXrDestroyInstance(XrInstance instance);
XrResult GenValidUsageNextXrDestroyInstance(
XrInstance instance);
XrResult CoreValidationXrCreateSession(
XrInstance instance,
const XrSessionCreateInfo* createInfo,
XrSession* session);
XrResult GenValidUsageInputsXrCreateSession(XrInstance instance, const XrSessionCreateInfo* createInfo, XrSession* session);
XrResult GenValidUsageNextXrCreateSession(
XrInstance instance,
const XrSessionCreateInfo* createInfo,
XrSession* session);
// ---- XR_KHR_android_thread_settings extension commands
// ---- XR_KHR_android_surface_swapchain extension commands
// ---- XR_KHR_opengl_enable extension commands
// ---- XR_KHR_opengl_es_enable extension commands
// ---- XR_KHR_vulkan_enable extension commands
// ---- XR_KHR_D3D11_enable extension commands
// ---- XR_KHR_D3D12_enable extension commands
// ---- XR_KHR_visibility_mask extension commands
// ---- XR_KHR_win32_convert_performance_counter_time extension commands
// ---- XR_KHR_convert_timespec_time extension commands
// ---- XR_EXT_performance_settings extension commands
// ---- XR_EXT_thermal_query extension commands
// ---- XR_EXT_debug_utils extension commands
XrResult CoreValidationXrSetDebugUtilsObjectNameEXT(
XrInstance instance,
const XrDebugUtilsObjectNameInfoEXT* nameInfo);
XrResult GenValidUsageInputsXrSetDebugUtilsObjectNameEXT(XrInstance instance, const XrDebugUtilsObjectNameInfoEXT* nameInfo);
XrResult GenValidUsageNextXrSetDebugUtilsObjectNameEXT(
XrInstance instance,
const XrDebugUtilsObjectNameInfoEXT* nameInfo);
XrResult CoreValidationXrCreateDebugUtilsMessengerEXT(
XrInstance instance,
const XrDebugUtilsMessengerCreateInfoEXT* createInfo,
XrDebugUtilsMessengerEXT* messenger);
XrResult GenValidUsageInputsXrCreateDebugUtilsMessengerEXT(XrInstance instance, const XrDebugUtilsMessengerCreateInfoEXT* createInfo, XrDebugUtilsMessengerEXT* messenger);
XrResult GenValidUsageNextXrCreateDebugUtilsMessengerEXT(
XrInstance instance,
const XrDebugUtilsMessengerCreateInfoEXT* createInfo,
XrDebugUtilsMessengerEXT* messenger);
XrResult CoreValidationXrDestroyDebugUtilsMessengerEXT(
XrDebugUtilsMessengerEXT messenger);
XrResult GenValidUsageInputsXrDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT messenger);
XrResult GenValidUsageNextXrDestroyDebugUtilsMessengerEXT(
XrDebugUtilsMessengerEXT messenger);
XrResult CoreValidationXrSessionBeginDebugUtilsLabelRegionEXT(
XrSession session,
const XrDebugUtilsLabelEXT* labelInfo);
XrResult GenValidUsageInputsXrSessionBeginDebugUtilsLabelRegionEXT(XrSession session, const XrDebugUtilsLabelEXT* labelInfo);
XrResult GenValidUsageNextXrSessionBeginDebugUtilsLabelRegionEXT(
XrSession session,
const XrDebugUtilsLabelEXT* labelInfo);
XrResult CoreValidationXrSessionEndDebugUtilsLabelRegionEXT(
XrSession session);
XrResult GenValidUsageInputsXrSessionEndDebugUtilsLabelRegionEXT(XrSession session);
XrResult GenValidUsageNextXrSessionEndDebugUtilsLabelRegionEXT(
XrSession session);
XrResult CoreValidationXrSessionInsertDebugUtilsLabelEXT(
XrSession session,
const XrDebugUtilsLabelEXT* labelInfo);
XrResult GenValidUsageInputsXrSessionInsertDebugUtilsLabelEXT(XrSession session, const XrDebugUtilsLabelEXT* labelInfo);
XrResult GenValidUsageNextXrSessionInsertDebugUtilsLabelEXT(
XrSession session,
const XrDebugUtilsLabelEXT* labelInfo);
// Current API version of the Core Validation API Layer
#define XR_CORE_VALIDATION_API_VERSION XR_CURRENT_API_VERSION
// Externs for Core Validation
extern InstanceHandleInfo g_instance_info;
extern HandleInfo<XrSession> g_session_info;
extern HandleInfo<XrSpace> g_space_info;
extern HandleInfo<XrAction> g_action_info;
extern HandleInfo<XrSwapchain> g_swapchain_info;
extern HandleInfo<XrActionSet> g_actionset_info;
extern HandleInfo<XrDebugUtilsMessengerEXT> g_debugutilsmessengerext_info;void GenValidUsageCleanUpMaps(GenValidUsageXrInstanceInfo *instance_info);
// Function to convert XrObjectType to string
std::string GenValidUsageXrObjectTypeToString(const XrObjectType& type);
// Function to record all the core validation information
extern void CoreValidLogMessage(GenValidUsageXrInstanceInfo *instance_info, const std::string &message_id,
GenValidUsageDebugSeverity message_severity, const std::string &command_name,
std::vector<GenValidUsageXrObjectInfo> objects_info, const std::string &message);

View File

@@ -0,0 +1,86 @@
# ~~~
# Copyright (c) 2018-2019 Valve Corporation
# Copyright (c) 2018-2019 LunarG, Inc.
#
# 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.
# ~~~
#.rst:
# FindVulkanHeaders
# -----------------
#
# Try to find Vulkan Headers and Registry.
#
# This module is intended to be used by projects that build Vulkan
# "system" components such as the loader and layers.
# Vulkan applications should instead use the FindVulkan (or similar)
# find module that locates the headers and the loader library.
#
# When using this find module to locate the headers and registry
# in a Vulkan-Headers repository, the Vulkan-Headers repository
# should be built with 'install' target and the following environment
# or CMake variable set to the location of the install directory.
#
# VULKAN_HEADERS_INSTALL_DIR
#
# IMPORTED Targets
# ^^^^^^^^^^^^^^^^
#
# This module defines no IMPORTED targets
#
# Result Variables
# ^^^^^^^^^^^^^^^^
#
# This module defines the following variables::
#
# VulkanHeaders_FOUND - True if VulkanHeaders was found
# VulkanHeaders_INCLUDE_DIRS - include directories for VulkanHeaders
#
# VulkanRegistry_FOUND - True if VulkanRegistry was found
# VulkanRegistry_DIRS - directories for VulkanRegistry
#
# The module will also define two cache variables::
#
# VulkanHeaders_INCLUDE_DIR - the VulkanHeaders include directory
# VulkanRegistry_DIR - the VulkanRegistry directory
#
# Use HINTS instead of PATH to search these locations before
# searching system environment variables like $PATH that may
# contain SDK directories.
find_path(VulkanHeaders_INCLUDE_DIR
NAMES vulkan/vulkan.h
HINTS
${VULKAN_HEADERS_INSTALL_DIR}/include
"$ENV{VULKAN_HEADERS_INSTALL_DIR}/include"
"$ENV{VULKAN_SDK}/include")
if(VulkanHeaders_INCLUDE_DIR)
get_filename_component(VULKAN_REGISTRY_PATH_HINT ${VulkanHeaders_INCLUDE_DIR} DIRECTORY)
find_path(VulkanRegistry_DIR
NAMES vk.xml
HINTS "${VULKAN_REGISTRY_PATH_HINT}/share/vulkan/registry")
endif()
set(VulkanHeaders_INCLUDE_DIRS ${VulkanHeaders_INCLUDE_DIR})
set(VulkanRegistry_DIRS ${VulkanRegistry_DIR})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(VulkanHeaders
DEFAULT_MSG
VulkanHeaders_INCLUDE_DIR)
find_package_handle_standard_args(VulkanRegistry
DEFAULT_MSG
VulkanRegistry_DIR)
mark_as_advanced(VulkanHeaders_INCLUDE_DIR VulkanRegistry_DIR)

View File

@@ -0,0 +1,21 @@
if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
string(REGEX REPLACE "\n" ";" files "${files}")
foreach(file ${files})
message(STATUS "Uninstalling $ENV{DESTDIR}${file}")
if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
exec_program(
"@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
OUTPUT_VARIABLE rm_out
RETURN_VALUE rm_retval
)
if(NOT "${rm_retval}" STREQUAL 0)
message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
endif(NOT "${rm_retval}" STREQUAL 0)
else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
message(STATUS "File $ENV{DESTDIR}${file} does not exist.")
endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
endforeach(file)

View File

@@ -0,0 +1,101 @@
set(PRESENTATION_BACKENDS xlib xcb wayland)
set(PRESENTATION_BACKEND xlib CACHE STRING
"Presentation backend chosen at configure time")
set_property(CACHE PRESENTATION_BACKEND PROPERTY STRINGS
${PRESENTATION_BACKENDS})
list(FIND PRESENTATION_BACKENDS ${PRESENTATION_BACKEND} index)
if(index EQUAL -1)
message(FATAL_ERROR "Presentation backend must be one of
${PRESENTATION_BACKENDS}")
endif()
message(STATUS "Using presentation backend: ${PRESENTATION_BACKEND}")
if( PRESENTATION_BACKEND MATCHES "xlib" )
find_package(X11 REQUIRED)
if ((NOT X11_Xxf86vm_LIB) OR (NOT X11_Xrandr_LIB))
message(FATAL_ERROR "OpenXR xlib backend requires Xxf86vm and Xrandr")
endif()
add_definitions( -DSUPPORT_X )
add_definitions( -DOS_LINUX_XLIB )
set( XLIB_LIBRARIES
${X11_LIBRARIES}
${X11_Xxf86vm_LIB}
${X11_Xrandr_LIB} )
elseif( PRESENTATION_BACKEND MATCHES "xcb" )
find_package(PkgConfig REQUIRED)
# XCB + XCB GLX is limited to OpenGL 2.1
# add_definitions( -DOS_LINUX_XCB )
# XCB + Xlib GLX 1.3
add_definitions( -DOS_LINUX_XCB_GLX )
pkg_search_module(X11 REQUIRED x11)
pkg_search_module(XCB REQUIRED xcb)
pkg_search_module(XCB_RANDR REQUIRED xcb-randr)
pkg_search_module(XCB_KEYSYMS REQUIRED xcb-keysyms)
pkg_search_module(XCB_GLX REQUIRED xcb-glx)
pkg_search_module(XCB_DRI2 REQUIRED xcb-dri2)
pkg_search_module(XCB_ICCCM REQUIRED xcb-icccm)
set( XCB_LIBRARIES
${XCB_LIBRARIES}
${XCB_KEYSYMS_LIBRARIES}
${XCB_RANDR_LIBRARIES}
${XCB_GLX_LIBRARIES}
${XCB_DRI2_LIBRARIES}
${X11_LIBRARIES} )
elseif( PRESENTATION_BACKEND MATCHES "wayland" )
find_package(PkgConfig REQUIRED)
pkg_search_module(WAYLAND_CLIENT REQUIRED wayland-client)
pkg_search_module(WAYLAND_EGL REQUIRED wayland-egl)
pkg_search_module(WAYLAND_SCANNER REQUIRED wayland-scanner)
pkg_search_module(WAYLAND_PROTOCOLS REQUIRED wayland-protocols>=1.7)
pkg_search_module(EGL REQUIRED egl)
add_definitions( -DOS_LINUX_WAYLAND )
set( WAYLAND_LIBRARIES
${EGL_LIBRARIES}
${WAYLAND_CLIENT_LIBRARIES}
${WAYLAND_EGL_LIBRARIES} )
# generate wayland protocols
set(WAYLAND_PROTOCOLS_DIR ${CMAKE_SOURCE_DIR}/wayland-protocols/)
file(MAKE_DIRECTORY ${WAYLAND_PROTOCOLS_DIR})
pkg_get_variable(WAYLAND_PROTOCOLS_DATADIR wayland-protocols pkgdatadir)
pkg_get_variable(WAYLAND_SCANNER wayland-scanner wayland_scanner)
set(PROTOCOL xdg-shell-unstable-v6)
set(PROTOCOL_XML
${WAYLAND_PROTOCOLS_DATADIR}/unstable/xdg-shell/${PROTOCOL}.xml)
if( EXISTS ${PROTOCOL_XML} )
execute_process(COMMAND
${WAYLAND_SCANNER}
code
${PROTOCOL_XML}
${WAYLAND_PROTOCOLS_DIR}/${PROTOCOL}.c)
execute_process(COMMAND
${WAYLAND_SCANNER}
client-header
${PROTOCOL_XML}
${WAYLAND_PROTOCOLS_DIR}/${PROTOCOL}.h)
set( WAYLAND_PROTOCOL_SRC
${WAYLAND_PROTOCOLS_DIR}/${PROTOCOL}.c
${WAYLAND_PROTOCOLS_DIR}/${PROTOCOL}.h )
include_directories(${WAYLAND_PROTOCOLS_DIR})
else()
message(FATAL_ERROR
"xdg-shell-unstable-v6.xml not found in "
${WAYLAND_PROTOCOLS_DATADIR}
"\nYour wayland-protocols package does not "
"contain xdg-shell-unstable-v6.")
endif()
endif()

View File

@@ -0,0 +1,57 @@
// Copyright (c) 2017-2019 The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
// Copyright (c) 2019 Collabora, Ltd.
//
// 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.
//
// Author: Ryan Pavlik <ryan.pavlik@collabora.com>
//
/*!
* @file
*
* Additional functions along the lines of the standard library algorithms.
*/
#pragma once
#include <algorithm>
#include <vector>
/// Like std::remove_if, except it works on associative containers and it actually removes this.
///
/// The iterator stuff in here is subtle - .erase() invalidates only that iterator, but it returns a non-invalidated iterator to the
/// next valid element which we can use instead of incrementing.
template <typename T, typename Pred>
static inline void map_erase_if(T &container, Pred &&predicate) {
for (auto it = container.begin(); it != container.end();) {
if (predicate(*it)) {
it = container.erase(it);
} else {
++it;
}
}
}
/*!
* Moves all elements matching the predicate to the end of the vector then erases them.
*
* Combines the two parts of the erase-remove idiom to simplify things and avoid accidentally using the wrong erase overload.
*/
template <typename T, typename Alloc, typename Pred>
static inline void vector_remove_if_and_erase(std::vector<T, Alloc> &vec, Pred &&predicate) {
auto b = vec.begin();
auto e = vec.end();
vec.erase(std::remove_if(b, e, std::forward<Pred>(predicate)), e);
}

View File

@@ -0,0 +1,330 @@
// Copyright (c) 2017 The Khronos Group Inc.
// Copyright (c) 2017 Valve Corporation
// Copyright (c) 2017 LunarG, Inc.
//
// 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.
//
// Authors: Mark Young <marky@lunarg.com>
// Nat Brown <natb@valvesoftware.com>
//
#include "filesystem_utils.hpp"
#include "platform_utils.hpp"
#ifdef _WIN32
#include "xr_dependencies.h"
#endif
#include <cstring>
#if defined DISABLE_STD_FILESYSTEM
#define USE_EXPERIMENTAL_FS 0
#define USE_FINAL_FS 0
#else
// If the C++ macro is set to the version containing C++17, it must support
// the final C++17 package
#if __cplusplus >= 201703L
#define USE_EXPERIMENTAL_FS 0
#define USE_FINAL_FS 1
#elif defined(_MSC_VER) && _MSC_VER >= 1900
#if defined(_HAS_CXX17) && _HAS_CXX17
// When MSC supports c++17 use <filesystem> package.
#define USE_EXPERIMENTAL_FS 0
#define USE_FINAL_FS 1
#endif // !_HAS_CXX17
// Right now, GCC still only supports the experimental filesystem items starting in GCC 6
#elif (__GNUC__ >= 6)
#define USE_EXPERIMENTAL_FS 1
#define USE_FINAL_FS 0
// If Clang, check for feature support
#elif defined(__clang__) && (__cpp_lib_filesystem || __cpp_lib_experimental_filesystem)
#if __cpp_lib_filesystem
#define USE_EXPERIMENTAL_FS 0
#define USE_FINAL_FS 1
#else
#define USE_EXPERIMENTAL_FS 1
#define USE_FINAL_FS 0
#endif
// If all above fails, fall back to standard C++ and OS-specific items
#else
#define USE_EXPERIMENTAL_FS 0
#define USE_FINAL_FS 0
#endif
#endif
#if USE_FINAL_FS == 1
#include <filesystem>
#define FS_PREFIX std::filesystem
#elif USE_EXPERIMENTAL_FS == 1
#include <experimental/filesystem>
#define FS_PREFIX std::experimental::filesystem
#elif defined(XR_USE_PLATFORM_WIN32)
// Windows fallback includes
#include <stdint.h>
#include <direct.h>
#else
// Linux/Apple fallback includes
#include <sys/stat.h>
#include <unistd.h>
#include <limits.h>
#include <stdlib.h>
#include <dirent.h>
#endif
#if defined(XR_USE_PLATFORM_WIN32)
#define PATH_SEPARATOR ';'
#define DIRECTORY_SYMBOL '\\'
#else
#define PATH_SEPARATOR ':'
#define DIRECTORY_SYMBOL '/'
#endif
#if (USE_FINAL_FS == 1) || (USE_EXPERIMENTAL_FS == 1)
// We can use one of the C++ filesystem packages
bool FileSysUtilsIsRegularFile(const std::string& path) { return FS_PREFIX::is_regular_file(path); }
bool FileSysUtilsIsDirectory(const std::string& path) { return FS_PREFIX::is_directory(path); }
bool FileSysUtilsPathExists(const std::string& path) { return FS_PREFIX::exists(path); }
bool FileSysUtilsIsAbsolutePath(const std::string& path) {
FS_PREFIX::path file_path(path);
return file_path.is_absolute();
}
bool FileSysUtilsGetCurrentPath(std::string& path) {
FS_PREFIX::path cur_path = FS_PREFIX::current_path();
path = cur_path.string();
return true;
}
bool FileSysUtilsGetParentPath(const std::string& file_path, std::string& parent_path) {
FS_PREFIX::path path_var(file_path);
parent_path = path_var.parent_path().string();
return true;
}
bool FileSysUtilsGetAbsolutePath(const std::string& path, std::string& absolute) {
absolute = FS_PREFIX::absolute(path).string();
return true;
}
bool FileSysUtilsCombinePaths(const std::string& parent, const std::string& child, std::string& combined) {
FS_PREFIX::path parent_path(parent);
FS_PREFIX::path child_path(child);
FS_PREFIX::path full_path = parent_path / child_path;
combined = full_path.string();
return true;
}
bool FileSysUtilsParsePathList(std::string& path_list, std::vector<std::string>& paths) {
std::string::size_type start = 0;
std::string::size_type location = path_list.find(PATH_SEPARATOR);
while (location != std::string::npos) {
paths.push_back(path_list.substr(start, location));
start = location + 1;
location = path_list.find(PATH_SEPARATOR, start);
}
paths.push_back(path_list.substr(start, location));
return true;
}
bool FileSysUtilsFindFilesInPath(const std::string& path, std::vector<std::string>& files) {
for (auto& dir_iter : FS_PREFIX::directory_iterator(path)) {
files.push_back(dir_iter.path().filename().string());
}
return true;
}
#elif defined(XR_OS_WINDOWS)
// For pre C++17 compiler that doesn't support experimental filesystem
#include <shlwapi.h>
bool FileSysUtilsIsRegularFile(const std::string& path) { return (1 != PathIsDirectoryW(utf8_to_wide(path).c_str())); }
bool FileSysUtilsIsDirectory(const std::string& path) { return (1 == PathIsDirectoryW(utf8_to_wide(path).c_str())); }
bool FileSysUtilsPathExists(const std::string& path) { return (1 == PathFileExistsW(utf8_to_wide(path).c_str())); }
bool FileSysUtilsIsAbsolutePath(const std::string& path) {
if ((path[0] == '\\') || (path[1] == ':' && (path[2] == '\\' || path[2] == '/'))) {
return true;
}
return false;
}
bool FileSysUtilsGetCurrentPath(std::string& path) {
wchar_t tmp_path[MAX_PATH];
if (nullptr != _wgetcwd(tmp_path, MAX_PATH - 1)) {
path = wide_to_utf8(tmp_path);
return true;
}
return false;
}
bool FileSysUtilsGetParentPath(const std::string& file_path, std::string& parent_path) {
std::string full_path;
if (FileSysUtilsGetAbsolutePath(file_path, full_path)) {
std::string::size_type lastSeperator = full_path.find_last_of(DIRECTORY_SYMBOL);
parent_path = (lastSeperator == 0) ? full_path : full_path.substr(0, lastSeperator);
return true;
}
return false;
}
bool FileSysUtilsGetAbsolutePath(const std::string& path, std::string& absolute) {
wchar_t tmp_path[MAX_PATH];
if (0 != GetFullPathNameW(utf8_to_wide(path).c_str(), MAX_PATH, tmp_path, NULL)) {
absolute = wide_to_utf8(tmp_path);
return true;
}
return false;
}
bool FileSysUtilsCombinePaths(const std::string& parent, const std::string& child, std::string& combined) {
std::string::size_type parent_len = parent.length();
if (0 == parent_len || "." == parent || ".\\" == parent || "./" == parent) {
combined = child;
return true;
}
char last_char = parent[parent_len - 1];
if (last_char == DIRECTORY_SYMBOL) {
parent_len--;
}
combined = parent.substr(0, parent_len) + DIRECTORY_SYMBOL + child;
return true;
}
bool FileSysUtilsParsePathList(std::string& path_list, std::vector<std::string>& paths) {
std::string::size_type start = 0;
std::string::size_type location = path_list.find(PATH_SEPARATOR);
while (location != std::string::npos) {
paths.push_back(path_list.substr(start, location));
start = location + 1;
location = path_list.find(PATH_SEPARATOR, start);
}
paths.push_back(path_list.substr(start, location));
return true;
}
bool FileSysUtilsFindFilesInPath(const std::string& path, std::vector<std::string>& files) {
WIN32_FIND_DATAW file_data;
HANDLE file_handle = FindFirstFileW(utf8_to_wide(path).c_str(), &file_data);
if (file_handle != INVALID_HANDLE_VALUE) {
do {
if (!(file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
files.push_back(wide_to_utf8(file_data.cFileName));
}
} while (FindNextFileW(file_handle, &file_data));
return true;
}
return false;
}
#else // XR_OS_LINUX/XR_OS_APPLE fallback
// simple POSIX-compatible implementation of the <filesystem> pieces used by OpenXR
bool FileSysUtilsIsRegularFile(const std::string& path) {
struct stat path_stat;
stat(path.c_str(), &path_stat);
return S_ISREG(path_stat.st_mode);
}
bool FileSysUtilsIsDirectory(const std::string& path) {
struct stat path_stat;
stat(path.c_str(), &path_stat);
return S_ISDIR(path_stat.st_mode);
}
bool FileSysUtilsPathExists(const std::string& path) { return (access(path.c_str(), F_OK) != -1); }
bool FileSysUtilsIsAbsolutePath(const std::string& path) { return (path[0] == DIRECTORY_SYMBOL); }
bool FileSysUtilsGetCurrentPath(std::string& path) {
char tmp_path[PATH_MAX];
if (nullptr != getcwd(tmp_path, PATH_MAX - 1)) {
path = tmp_path;
return true;
}
return false;
}
bool FileSysUtilsGetParentPath(const std::string& file_path, std::string& parent_path) {
std::string full_path;
if (FileSysUtilsGetAbsolutePath(file_path, full_path)) {
std::string::size_type lastSeperator = full_path.find_last_of(DIRECTORY_SYMBOL);
parent_path = (lastSeperator == 0) ? full_path : full_path.substr(0, lastSeperator);
return true;
}
return false;
}
bool FileSysUtilsGetAbsolutePath(const std::string& path, std::string& absolute) {
char buf[PATH_MAX];
if (nullptr != realpath(path.c_str(), buf)) {
absolute = buf;
return true;
}
return false;
}
bool FileSysUtilsCombinePaths(const std::string& parent, const std::string& child, std::string& combined) {
std::string::size_type parent_len = parent.length();
if (0 == parent_len || "." == parent || "./" == parent) {
combined = child;
return true;
}
char last_char = parent[parent_len - 1];
if (last_char == DIRECTORY_SYMBOL) {
parent_len--;
}
combined = parent.substr(0, parent_len) + DIRECTORY_SYMBOL + child;
return true;
}
bool FileSysUtilsParsePathList(std::string& path_list, std::vector<std::string>& paths) {
std::string::size_type start = 0;
std::string::size_type location = path_list.find(PATH_SEPARATOR);
while (location != std::string::npos) {
paths.push_back(path_list.substr(start, location));
start = location + 1;
location = path_list.find(PATH_SEPARATOR, start);
}
paths.push_back(path_list.substr(start, location));
return true;
}
bool FileSysUtilsFindFilesInPath(const std::string& path, std::vector<std::string>& files) {
DIR* dir = opendir(path.c_str());
if (dir == nullptr) {
return false;
}
struct dirent* entry;
while ((entry = readdir(dir)) != nullptr) {
files.emplace_back(entry->d_name);
}
closedir(dir);
return true;
}
#endif

View File

@@ -0,0 +1,53 @@
// Copyright (c) 2017 The Khronos Group Inc.
// Copyright (c) 2017 Valve Corporation
// Copyright (c) 2017 LunarG, Inc.
//
// 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.
//
// Author: Mark Young <marky@lunarg.com>
//
#pragma once
#include <string>
#include <vector>
// Determine if the path indicates a regular file (not a directory or symbolic link)
bool FileSysUtilsIsRegularFile(const std::string& path);
// Determine if the path indicates a directory
bool FileSysUtilsIsDirectory(const std::string& path);
// Determine if the provided path exists on the filesystem
bool FileSysUtilsPathExists(const std::string& path);
// Get the current directory of the executable
bool FileSysUtilsGetCurrentPath(std::string& path);
// Get the parent path of a file
bool FileSysUtilsGetParentPath(const std::string& file_path, std::string& parent_path);
// Determine if the provided path is an absolute path
bool FileSysUtilsIsAbsolutePath(const std::string& path);
// Get the absolute path for a provided file
bool FileSysUtilsGetAbsolutePath(const std::string& path, std::string& absolute);
// Combine a parent and child directory
bool FileSysUtilsCombinePaths(const std::string& parent, const std::string& child, std::string& combined);
// Parse out individual paths in a path list
bool FileSysUtilsParsePathList(std::string& path_list, std::vector<std::string>& paths);
// Record all the filenames for files found in the provided path.
bool FileSysUtilsFindFilesInPath(const std::string& path, std::vector<std::string>& files);

View File

@@ -0,0 +1,44 @@
// Copyright (c) 2017-2019 The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
// Copyright (c) 2019 Collabora, Ltd.
//
// 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.
//
// Author: Ryan Pavlik <ryan.pavlik@collabora.com>
//
/*!
* @file
*
* Implementations of the include-requiring hex conversion functions.
*/
#include "hex_and_handles.h"
#include <sstream>
#include <iomanip>
std::string Uint64ToHexString(uint64_t val) {
std::ostringstream oss;
oss << "0x";
oss << std::hex << std::setw(16) << std::setfill('0') << val;
return oss.str();
}
std::string Uint32ToHexString(uint32_t val) {
std::ostringstream oss;
oss << "0x";
oss << std::hex << std::setw(8) << std::setfill('0') << val;
return oss.str();
}

View File

@@ -0,0 +1,108 @@
// Copyright (c) 2017-2019 The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
// Copyright (c) 2019 Collabora, Ltd.
//
// 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.
//
// Author: Ryan Pavlik <ryan.pavlik@collabora.com>
//
/*!
* @file
*
* Some utilities, primarily for working with OpenXR handles in a generic way.
*
* Most are trivial and inlined by default, but a few involve some non-trivial standard headers:
* the various `...ToHexString`functions.
* If you want those, make sure your build includes the corresponding hex_and_handles.cpp file.
*/
#pragma once
#include <openxr/openxr.h>
#include <string>
#include <stdint.h>
#if XR_PTR_SIZE == 8
/// Convert a handle into a same-sized integer.
template <typename T>
static inline uint64_t MakeHandleGeneric(T handle) {
return reinterpret_cast<uint64_t>(handle);
}
/// Treat an integer as a handle
template <typename T>
static inline T& TreatIntegerAsHandle(uint64_t& handle) {
return reinterpret_cast<T&>(handle);
}
/// @overload
template <typename T>
static inline T const& TreatIntegerAsHandle(uint64_t const& handle) {
return reinterpret_cast<T const&>(handle);
}
/// Does a correctly-sized integer represent a null handle?
static inline bool IsIntegerNullHandle(uint64_t handle) { return XR_NULL_HANDLE == reinterpret_cast<void*>(handle); }
#else
/// Convert a handle into a same-sized integer: no-op on 32-bit systems
static inline uint64_t MakeHandleGeneric(uint64_t handle) { return handle; }
/// Treat an integer as a handle: no-op on 32-bit systems
template <typename T>
static inline T& TreatIntegerAsHandle(uint64_t& handle) {
return handle;
}
/// @overload
template <typename T>
static inline T const& TreatIntegerAsHandle(uint64_t const& handle) {
return handle;
}
/// Does a correctly-sized integer represent a null handle?
static inline bool IsIntegerNullHandle(uint64_t handle) { return XR_NULL_HANDLE == handle; }
#endif
/// Turns a uint64_t into a string formatted as hex.
///
/// The core of the HandleToHexString implementation is in here.
std::string Uint64ToHexString(uint64_t val);
/// Turns a uint32_t into a string formatted as hex.
std::string Uint32ToHexString(uint32_t val);
/// Turns an OpenXR handle into a string formatted as hex.
template <typename T>
static inline std::string HandleToHexString(T handle) {
return Uint64ToHexString(MakeHandleGeneric(handle));
}
#if XR_PTR_SIZE == 8
/// Turns a pointer-sized integer into a string formatted as hex.
static inline std::string UintptrToHexString(uintptr_t val) { return Uint64ToHexString(val); }
#else
/// Turns a pointer-sized integer into a string formatted as hex.
static inline std::string UintptrToHexString(uintptr_t val) { return Uint32ToHexString(val); }
#endif
/// Convert a pointer to a string formatted as hex.
template <typename T>
static inline std::string PointerToHexString(T const* ptr) {
return UintptrToHexString(reinterpret_cast<uintptr_t>(ptr));
}

View File

@@ -0,0 +1,122 @@
// Copyright (c) 2017 The Khronos Group Inc.
// Copyright (c) 2017 Valve Corporation
// Copyright (c) 2017 LunarG, Inc.
//
// 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.
//
// Author: Mark Young <marky@lunarg.com>
//
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
// Forward declare.
typedef struct XrApiLayerCreateInfo XrApiLayerCreateInfo;
// Function pointer prototype for the xrCreateApiLayerInstance function used in place of xrCreateInstance.
// This function allows us to pass special API layer information to each layer during the process of creating an Instance.
typedef XrResult(XRAPI_PTR *PFN_xrCreateApiLayerInstance)(const XrInstanceCreateInfo *info,
const XrApiLayerCreateInfo *apiLayerInfo, XrInstance *instance);
// Loader/API Layer Interface versions
// 1 - First version, introduces negotiation structure and functions
#define XR_CURRENT_LOADER_API_LAYER_VERSION 1
// Loader/Runtime Interface versions
// 1 - First version, introduces negotiation structure and functions
#define XR_CURRENT_LOADER_RUNTIME_VERSION 1
// Version negotiation values
typedef enum XrLoaderInterfaceStructs {
XR_LOADER_INTERFACE_STRUCT_UNINTIALIZED = 0,
XR_LOADER_INTERFACE_STRUCT_LOADER_INFO,
XR_LOADER_INTERFACE_STRUCT_API_LAYER_REQUEST,
XR_LOADER_INTERFACE_STRUCT_RUNTIME_REQUEST,
XR_LOADER_INTERFACE_STRUCT_API_LAYER_CREATE_INFO,
XR_LOADER_INTERFACE_STRUCT_API_LAYER_NEXT_INFO,
} XrLoaderInterfaceStructs;
#define XR_LOADER_INFO_STRUCT_VERSION 1
typedef struct XrNegotiateLoaderInfo {
XrLoaderInterfaceStructs structType; // XR_LOADER_INTERFACE_STRUCT_LOADER_INFO
uint32_t structVersion; // XR_LOADER_INFO_STRUCT_VERSION
size_t structSize; // sizeof(XrNegotiateLoaderInfo)
uint32_t minInterfaceVersion;
uint32_t maxInterfaceVersion;
XrVersion minApiVersion;
XrVersion maxApiVersion;
} XrNegotiateLoaderInfo;
#define XR_API_LAYER_INFO_STRUCT_VERSION 1
typedef struct XrNegotiateApiLayerRequest {
XrLoaderInterfaceStructs structType; // XR_LOADER_INTERFACE_STRUCT_API_LAYER_REQUEST
uint32_t structVersion; // XR_API_LAYER_INFO_STRUCT_VERSION
size_t structSize; // sizeof(XrNegotiateApiLayerRequest)
uint32_t layerInterfaceVersion; // CURRENT_LOADER_API_LAYER_VERSION
XrVersion layerApiVersion;
PFN_xrGetInstanceProcAddr getInstanceProcAddr;
PFN_xrCreateApiLayerInstance createApiLayerInstance;
} XrNegotiateApiLayerRequest;
#define XR_RUNTIME_INFO_STRUCT_VERSION 1
typedef struct XrNegotiateRuntimeRequest {
XrLoaderInterfaceStructs structType; // XR_LOADER_INTERFACE_STRUCT_RUNTIME_REQUEST
uint32_t structVersion; // XR_RUNTIME_INFO_STRUCT_VERSION
size_t structSize; // sizeof(XrNegotiateRuntimeRequest)
uint32_t runtimeInterfaceVersion; // CURRENT_LOADER_RUNTIME_VERSION
XrVersion runtimeApiVersion;
PFN_xrGetInstanceProcAddr getInstanceProcAddr;
} XrNegotiateRuntimeRequest;
// Function used to negotiate an interface betewen the loader and an API layer. Each library exposing one or
// more API layers needs to expose at least this function.
typedef XrResult(XRAPI_PTR *PFN_xrNegotiateLoaderApiLayerInterface)(const XrNegotiateLoaderInfo *loaderInfo,
const char *apiLayerName,
XrNegotiateApiLayerRequest *apiLayerRequest);
// Function used to negotiate an interface betewen the loader and a runtime. Each runtime should expose
// at least this function.
typedef XrResult(XRAPI_PTR *PFN_xrNegotiateLoaderRuntimeInterface)(const XrNegotiateLoaderInfo *loaderInfo,
XrNegotiateRuntimeRequest *runtimeRequest);
// Forward declare.
typedef struct XrApiLayerNextInfo XrApiLayerNextInfo;
#define XR_API_LAYER_NEXT_INFO_STRUCT_VERSION 1
struct XrApiLayerNextInfo {
XrLoaderInterfaceStructs structType; // XR_LOADER_INTERFACE_STRUCT_API_LAYER_NEXT_INFO
uint32_t structVersion; // XR_API_LAYER_NEXT_INFO_STRUCT_VERSION
size_t structSize; // sizeof(XrApiLayerNextInfo)
char layerName[XR_MAX_API_LAYER_NAME_SIZE]; // Name of API layer which should receive this info
PFN_xrGetInstanceProcAddr nextGetInstanceProcAddr; // Pointer to next API layer's xrGetInstanceProcAddr
PFN_xrCreateApiLayerInstance nextCreateApiLayerInstance; // Pointer to next API layer's xrCreateApiLayerInstance
XrApiLayerNextInfo *next; // Pointer to the next API layer info in the sequence
};
#define XR_API_LAYER_MAX_SETTINGS_PATH_SIZE 512
#define XR_API_LAYER_CREATE_INFO_STRUCT_VERSION 1
typedef struct XrApiLayerCreateInfo {
XrLoaderInterfaceStructs structType; // XR_LOADER_INTERFACE_STRUCT_API_LAYER_CREATE_INFO
uint32_t structVersion; // XR_API_LAYER_CREATE_INFO_STRUCT_VERSION
size_t structSize; // sizeof(XrApiLayerCreateInfo)
void *loaderInstance; // Pointer to the LoaderInstance class
char settings_file_location[XR_API_LAYER_MAX_SETTINGS_PATH_SIZE]; // Location to the found settings file (or empty '\0')
XrApiLayerNextInfo *nextInfo; // Pointer to the next API layer's Info
} XrApiLayerCreateInfo;
#ifdef __cplusplus
} // extern "C"
#endif

View File

@@ -0,0 +1,221 @@
// Copyright (c) 2017 The Khronos Group Inc.
// Copyright (c) 2017 Valve Corporation
// Copyright (c) 2017 LunarG, Inc.
//
// 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.
//
// Author: Mark Young <marky@lunarg.com>
//
#pragma once
#include "xr_dependencies.h"
#include <string>
#if defined(XR_OS_LINUX)
#include <unistd.h>
#include <fcntl.h>
#include <iostream>
#endif
// This is a CMake generated file with #defines for any functions/includes
// that it found present. This is currently necessary to properly determine
// if secure_getenv or __secure_getenv are present
#if !defined(OPENXR_NON_CMAKE_BUILD)
#include "common_cmake_config.h"
#endif // !defined(OPENXR_NON_CMAKE_BUILD)
// Environment variables
#if defined(XR_OS_LINUX)
static inline char* PlatformUtilsGetEnv(const char* name) { return getenv(name); }
static inline char* PlatformUtilsGetSecureEnv(const char* name) {
#ifdef HAVE_SECURE_GETENV
return secure_getenv(name);
#elif defined(HAVE___SECURE_GETENV)
return __secure_getenv(name);
#else
#pragma message( \
"Warning: Falling back to non-secure getenv for environmental" \
"lookups! Consider updating to a different libc.")
return PlatformUtilsGetEnv(name);
#endif
}
static inline void PlatformUtilsFreeEnv(const char* val) {
// No freeing of memory necessary for Linux, but we should at least touch
// the val and inst pointers to get rid of compiler warnings.
(void)val;
}
#elif defined(XR_OS_APPLE)
static inline char *PlatformUtilsGetEnv(const char *name) { return getenv(name); }
static inline char *PlatformUtilsGetSecureEnv(const char *name) {
#ifdef HAVE_SECURE_GETENV
return secure_getenv(name);
#elif defined(HAVE___SECURE_GETENV)
return __secure_getenv(name);
#else
#pragma message( \
"Warning: Falling back to non-secure getenv for environmental" \
"lookups! Consider updating to a different libc.")
return PlatformUtilsGetEnv(name);
#endif
}
static inline void PlatformUtilsFreeEnv(char *val) {
// No freeing of memory necessary for Linux, but we should at least touch
// the val and inst pointers to get rid of compiler warnings.
(void)val;
}
// Prefix for the Apple global runtime JSON file name
static const std::string rt_dir_prefix = "/usr/local/share/openxr/";
static const std::string rt_filename = "/active_runtime.json";
static inline bool PlatformGetGlobalRuntimeFileName(uint16_t major_version, std::string &file_name) {
file_name = rt_dir_prefix;
file_name += std::to_string(major_version);
file_name += rt_filename;
return true;
}
#elif defined(XR_OS_WINDOWS)
#if defined(_DEBUG)
inline void LogError(const std::string& error) { OutputDebugStringA(error.c_str()); }
#else
#define LogError(x)
#endif
inline std::wstring utf8_to_wide(const std::string& utf8Text) {
if (utf8Text.empty()) {
return {};
}
std::wstring wideText;
const int wideLength = ::MultiByteToWideChar(CP_UTF8, 0, utf8Text.data(), (int)utf8Text.size(), nullptr, 0);
if (wideLength == 0) {
LogError("utf8_to_wide get size error: " + std::to_string(::GetLastError()));
return {};
}
// MultiByteToWideChar returns number of chars of the input buffer, regardless of null terminitor
wideText.resize(wideLength, 0);
wchar_t* wideString = const_cast<wchar_t*>(wideText.data()); // mutable data() only exists in c++17
const int length = ::MultiByteToWideChar(CP_UTF8, 0, utf8Text.data(), (int)utf8Text.size(), wideString, wideLength);
if (length != wideLength) {
LogError("utf8_to_wide convert string error: " + std::to_string(::GetLastError()));
return {};
}
return wideText;
}
inline std::string wide_to_utf8(const std::wstring& wideText) {
if (wideText.empty()) {
return {};
}
std::string narrowText;
int narrowLength = ::WideCharToMultiByte(CP_UTF8, 0, wideText.data(), (int)wideText.size(), nullptr, 0, nullptr, nullptr);
if (narrowLength == 0) {
LogError("wide_to_utf8 get size error: " + std::to_string(::GetLastError()));
return {};
}
// WideCharToMultiByte returns number of chars of the input buffer, regardless of null terminitor
narrowText.resize(narrowLength, 0);
char* narrowString = const_cast<char*>(narrowText.data()); // mutable data() only exists in c++17
const int length =
::WideCharToMultiByte(CP_UTF8, 0, wideText.data(), (int)wideText.size(), narrowString, narrowLength, nullptr, nullptr);
if (length != narrowLength) {
LogError("wide_to_utf8 convert string error: " + std::to_string(::GetLastError()));
return {};
}
return narrowText;
}
static inline char* PlatformUtilsGetEnv(const char* name) {
const std::wstring wname = utf8_to_wide(name);
const DWORD valSize = ::GetEnvironmentVariableW(wname.c_str(), nullptr, 0);
// GetEnvironmentVariable returns 0 when environment variable does not exist
if (valSize == 0) {
return nullptr;
}
// GetEnvironmentVariable returns size including null terminator for "query size" call.
std::wstring wValue(valSize, 0);
wchar_t* wValueData = const_cast<wchar_t*>(wValue.data()); // mutable data() only exists in c++17
// GetEnvironmentVariable returns string length, excluding null terminator for "get value" call.
const int length = ::GetEnvironmentVariableW(wname.c_str(), wValueData, (DWORD)wValue.size());
if (!length) {
LogError("GetEnvironmentVariable get value error: " + std::to_string(::GetLastError()));
return nullptr;
}
const std::string value = wide_to_utf8(wValue);
// Allocate the space necessary for the result
char* retVal = new char[value.size() + 1]{};
value.copy(retVal, value.size());
return retVal;
}
static inline char* PlatformUtilsGetSecureEnv(const char* name) {
// No secure version for Windows as far as I know
return PlatformUtilsGetEnv(name);
}
static inline void PlatformUtilsFreeEnv(char* val) {
if (nullptr != val) {
delete[] val;
val = nullptr;
}
}
#else // Not Linux or Windows
static inline char *PlatformUtilsGetEnv(const char *name) {
// Stub func
(void)name;
return nullptr;
}
static inline char *PlatformUtilsGetSecureEnv(const char *name) {
// Stub func
(void)name;
return nullptr;
}
static inline void PlatformUtilsFreeEnv(char *val) {
// Stub func
(void)val;
}
static inline bool PlatformGetGlobalRuntimeFileName(uint16_t major_version, std::string &file_name) {
// Stub func
(void)major_version;
(void)file_name;
return false;
}
#endif

View File

@@ -0,0 +1,78 @@
// Copyright (c) 2018-2019 The Khronos Group Inc.
//
// 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.
//
// This file includes headers with types which openxr.h depends on in order
// to compile when platforms, graphics apis, and the like are enabled.
#pragma once
#ifdef XR_USE_PLATFORM_ANDROID
#include <android/native_window.h>
#endif // XR_USE_PLATFORM_ANDROID
#ifdef XR_USE_PLATFORM_WIN32
#include <winapifamily.h>
#if !(WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM))
// Enable desktop partition APIs, such as RegOpenKeyEx, LoadLibraryEx, PathFileExists etc.
#undef WINAPI_PARTITION_DESKTOP
#define WINAPI_PARTITION_DESKTOP 1
#endif
#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif // XR_USE_PLATFORM_WIN32
#ifdef XR_USE_GRAPHICS_API_D3D11
#include <d3d11.h>
#endif // XR_USE_GRAPHICS_API_D3D11
#ifdef XR_USE_GRAPHICS_API_D3D12
#include <d3d12.h>
#endif // XR_USE_GRAPHICS_API_D3D12
#ifdef XR_USE_PLATFORM_XLIB
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#endif // XR_USE_PLATFORM_XLIB
#ifdef XR_USE_PLATFORM_XCB
#include <xcb/xcb.h>
#endif // XR_USE_PLATFORM_XCB
#ifdef XR_USE_GRAPHICS_API_OPENGL
#if defined(XR_USE_PLATFORM_XLIB) || defined(XR_USE_PLATFORM_XCB)
#include <GL/glx.h>
#endif // (XR_USE_PLATFORM_XLIB || XR_USE_PLATFORM_XCB)
#ifdef XR_USE_PLATFORM_XCB
#include <xcb/glx.h>
#endif // XR_USE_PLATFORM_XCB
#ifdef XR_USE_PLATFORM_MACOS
#include <CL/cl_gl_ext.h>
#endif // XR_USE_PLATFORM_MACOS
#endif // XR_USE_GRAPHICS_API_OPENGL
#ifdef XR_USE_GRAPHICS_API_OPENGL_ES
#include <EGL/egl.h>
#endif // XR_USE_GRAPHICS_API_OPENGL_ES
#ifdef XR_USE_GRAPHICS_API_VULKAN
#include <vulkan/vulkan.h>
#endif // XR_USE_GRAPHICS_API_VULKAN
#ifdef XR_USE_PLATFORM_WAYLAND
#include "wayland-client.h"
#endif // XR_USE_PLATFORM_WAYLAND

773
extern/openxr/src/common/xr_linear.h vendored Normal file
View File

@@ -0,0 +1,773 @@
// Copyright (c) 2017 The Khronos Group Inc.
// Copyright (c) 2016 Oculus VR, LLC.
//
// 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.
//
// Author: J.M.P. van Waveren
//
#ifndef XR_LINEAR_H_
#define XR_LINEAR_H_
#if defined(OS_LINUX_XCB) || defined(OS_LINUX_XCB_GLX) || defined(OS_LINUX_WAYLAND)
#pragma GCC diagnostic ignored "-Wunused-function"
#pragma clang diagnostic ignored "-Wunused-function"
#endif
#include <openxr/openxr.h>
/*
================================================================================================
Description : Vector, matrix and quaternion math.
Author : J.M.P. van Waveren
Date : 12/10/2016
Language : C99
Format : Indent 4 spaces - no tabs.
Copyright : Copyright (c) 2016 Oculus VR, LLC. All Rights reserved.
DESCRIPTION
===========
All matrices are column-major.
INTERFACE
=========
XrVector2f
XrVector3f
XrVector4f
XrQuaternionf
XrMatrix4x4f
inline static void XrVector3f_Set(XrVector3f* v, const float value);
inline static void XrVector3f_Add(XrVector3f* result, const XrVector3f* a, const XrVector3f* b);
inline static void XrVector3f_Sub(XrVector3f* result, const XrVector3f* a, const XrVector3f* b);
inline static void XrVector3f_Min(XrVector3f* result, const XrVector3f* a, const XrVector3f* b);
inline static void XrVector3f_Max(XrVector3f* result, const XrVector3f* a, const XrVector3f* b);
inline static void XrVector3f_Decay(XrVector3f* result, const XrVector3f* a, const float value);
inline static void XrVector3f_Lerp(XrVector3f* result, const XrVector3f* a, const XrVector3f* b, const float fraction);
inline static void XrVector3f_Normalize(XrVector3f* v);
inline static float XrVector3f_Length(const XrVector3f* v);
inline static void XrQuaternionf_Lerp(XrQuaternionf* result, const XrQuaternionf* a, const XrQuaternionf* b, const float fraction);
inline static void XrMatrix4x4f_CreateIdentity(XrMatrix4x4f* result);
inline static void XrMatrix4x4f_CreateTranslation(XrMatrix4x4f* result, const float x, const float y, const float z);
inline static void XrMatrix4x4f_CreateRotation(XrMatrix4x4f* result, const float degreesX, const float degreesY,
const float degreesZ);
inline static void XrMatrix4x4f_CreateScale(XrMatrix4x4f* result, const float x, const float y, const float z);
inline static void XrMatrix4x4f_CreateTranslationRotationScale(XrMatrix4x4f* result, const XrVector3f* translation,
const XrQuaternionf* rotation, const XrVector3f* scale);
inline static void XrMatrix4x4f_CreateProjection(XrMatrix4x4f* result, const float tanAngleLeft, const float tanAngleRight,
const float tanAngleUp, float const tanAngleDown, const float nearZ,
const float farZ);
inline static void XrMatrix4x4f_CreateProjectionFov(XrMatrix4x4f* result, const float fovDegreesLeft, const float fovDegreesRight,
const float fovDegreeUp, const float fovDegreesDown, const float nearZ,
const float farZ);
inline static void XrMatrix4x4f_CreateFromQuaternion(XrMatrix4x4f* result, const XrQuaternionf* src);
inline static void XrMatrix4x4f_CreateOffsetScaleForBounds(XrMatrix4x4f* result, const XrMatrix4x4f* matrix, const XrVector3f* mins,
const XrVector3f* maxs);
inline static bool XrMatrix4x4f_IsAffine(const XrMatrix4x4f* matrix, const float epsilon);
inline static bool XrMatrix4x4f_IsOrthogonal(const XrMatrix4x4f* matrix, const float epsilon);
inline static bool XrMatrix4x4f_IsOrthonormal(const XrMatrix4x4f* matrix, const float epsilon);
inline static bool XrMatrix4x4f_IsRigidBody(const XrMatrix4x4f* matrix, const float epsilon);
inline static void XrMatrix4x4f_GetTranslation(XrVector3f* result, const XrMatrix4x4f* src);
inline static void XrMatrix4x4f_GetRotation(XrQuaternionf* result, const XrMatrix4x4f* src);
inline static void XrMatrix4x4f_GetScale(XrVector3f* result, const XrMatrix4x4f* src);
inline static void XrMatrix4x4f_Multiply(XrMatrix4x4f* result, const XrMatrix4x4f* a, const XrMatrix4x4f* b);
inline static void XrMatrix4x4f_Transpose(XrMatrix4x4f* result, const XrMatrix4x4f* src);
inline static void XrMatrix4x4f_Invert(XrMatrix4x4f* result, const XrMatrix4x4f* src);
inline static void XrMatrix4x4f_InvertRigidBody(XrMatrix4x4f* result, const XrMatrix4x4f* src);
inline static void XrMatrix4x4f_TransformVector3f(XrVector3f* result, const XrMatrix4x4f* m, const XrVector3f* v);
inline static void XrMatrix4x4f_TransformVector4f(XrVector4f* result, const XrMatrix4x4f* m, const XrVector4f* v);
inline static void XrMatrix4x4f_TransformBounds(XrVector3f* resultMins, XrVector3f* resultMaxs, const XrMatrix4x4f* matrix,
const XrVector3f* mins, const XrVector3f* maxs);
inline static bool XrMatrix4x4f_CullBounds(const XrMatrix4x4f* mvp, const XrVector3f* mins, const XrVector3f* maxs);
================================================================================================
*/
#include <assert.h>
#include <math.h>
#include <stdbool.h>
#define MATH_PI 3.14159265358979323846f
#define DEFAULT_NEAR_Z 0.015625f // exact floating point representation
#define INFINITE_FAR_Z 0.0f
static const XrColor4f XrColorRed = {1.0f, 0.0f, 0.0f, 1.0f};
static const XrColor4f XrColorGreen = {0.0f, 1.0f, 0.0f, 1.0f};
static const XrColor4f XrColorBlue = {0.0f, 0.0f, 1.0f, 1.0f};
static const XrColor4f XrColorYellow = {1.0f, 1.0f, 0.0f, 1.0f};
static const XrColor4f XrColorPurple = {1.0f, 0.0f, 1.0f, 1.0f};
static const XrColor4f XrColorCyan = {0.0f, 1.0f, 1.0f, 1.0f};
static const XrColor4f XrColorLightGrey = {0.7f, 0.7f, 0.7f, 1.0f};
static const XrColor4f XrColorDarkGrey = {0.3f, 0.3f, 0.3f, 1.0f};
enum GraphicsAPI { GRAPHICS_VULKAN, GRAPHICS_OPENGL, GRAPHICS_OPENGL_ES, GRAPHICS_D3D };
// Column-major, pre-multiplied. This type does not exist in the OpenXR API and is provided for convenience.
struct XrMatrix4x4f {
float m[16];
};
inline static float XrRcpSqrt(const float x) {
const float SMALLEST_NON_DENORMAL = 1.1754943508222875e-038f; // ( 1U << 23 )
const float rcp = (x >= SMALLEST_NON_DENORMAL) ? 1.0f / sqrtf(x) : 1.0f;
return rcp;
}
inline static void XrVector3f_Set(XrVector3f* v, const float value) {
v->x = value;
v->y = value;
v->z = value;
}
inline static void XrVector3f_Add(XrVector3f* result, const XrVector3f* a, const XrVector3f* b) {
result->x = a->x + b->x;
result->y = a->y + b->y;
result->z = a->z + b->z;
}
inline static void XrVector3f_Sub(XrVector3f* result, const XrVector3f* a, const XrVector3f* b) {
result->x = a->x - b->x;
result->y = a->y - b->y;
result->z = a->z - b->z;
}
inline static void XrVector3f_Min(XrVector3f* result, const XrVector3f* a, const XrVector3f* b) {
result->x = (a->x < b->x) ? a->x : b->x;
result->y = (a->y < b->y) ? a->y : b->y;
result->z = (a->z < b->z) ? a->z : b->z;
}
inline static void XrVector3f_Max(XrVector3f* result, const XrVector3f* a, const XrVector3f* b) {
result->x = (a->x > b->x) ? a->x : b->x;
result->y = (a->y > b->y) ? a->y : b->y;
result->z = (a->z > b->z) ? a->z : b->z;
}
inline static void XrVector3f_Decay(XrVector3f* result, const XrVector3f* a, const float value) {
result->x = (fabsf(a->x) > value) ? ((a->x > 0.0f) ? (a->x - value) : (a->x + value)) : 0.0f;
result->y = (fabsf(a->y) > value) ? ((a->y > 0.0f) ? (a->y - value) : (a->y + value)) : 0.0f;
result->z = (fabsf(a->z) > value) ? ((a->z > 0.0f) ? (a->z - value) : (a->z + value)) : 0.0f;
}
inline static void XrVector3f_Lerp(XrVector3f* result, const XrVector3f* a, const XrVector3f* b, const float fraction) {
result->x = a->x + fraction * (b->x - a->x);
result->y = a->y + fraction * (b->y - a->y);
result->z = a->z + fraction * (b->z - a->z);
}
inline static float XrVector3f_Dot(const XrVector3f* a, const XrVector3f* b) { return a->x * b->x + a->y * b->y + a->z * b->z; }
// Compute cross product, which generates a normal vector.
// Direction vector can be determined by right-hand rule: Pointing index finder in
// direction a and middle finger in direction b, thumb will point in Cross(a, b).
inline static void XrVector3f_Cross(XrVector3f* result, const XrVector3f* a, const XrVector3f* b) {
result->x = a->y * b->z - a->z * b->y;
result->y = a->z * b->x - a->x * b->z;
result->x = a->x * b->y - a->y * b->x;
}
inline static void XrVector3f_Normalize(XrVector3f* v) {
const float lengthRcp = XrRcpSqrt(v->x * v->x + v->y * v->y + v->z * v->z);
v->x *= lengthRcp;
v->y *= lengthRcp;
v->z *= lengthRcp;
}
inline static float XrVector3f_Length(const XrVector3f* v) { return sqrtf(v->x * v->x + v->y * v->y + v->z * v->z); }
inline static void XrQuaternionf_CreateFromAxisAngle(XrQuaternionf* result, const XrVector3f* axis, const float angleInRadians) {
float s = sinf(angleInRadians / 2.0f);
float lengthRcp = XrRcpSqrt(axis->x * axis->x + axis->y * axis->y + axis->z * axis->z);
result->x = s * axis->x * lengthRcp;
result->y = s * axis->y * lengthRcp;
result->z = s * axis->z * lengthRcp;
result->w = cosf(angleInRadians / 2.0f);
}
inline static void XrQuaternionf_Lerp(XrQuaternionf* result, const XrQuaternionf* a, const XrQuaternionf* b, const float fraction) {
const float s = a->x * b->x + a->y * b->y + a->z * b->z + a->w * b->w;
const float fa = 1.0f - fraction;
const float fb = (s < 0.0f) ? -fraction : fraction;
const float x = a->x * fa + b->x * fb;
const float y = a->y * fa + b->y * fb;
const float z = a->z * fa + b->z * fb;
const float w = a->w * fa + b->w * fb;
const float lengthRcp = XrRcpSqrt(x * x + y * y + z * z + w * w);
result->x = x * lengthRcp;
result->y = y * lengthRcp;
result->z = z * lengthRcp;
result->w = w * lengthRcp;
}
// Use left-multiplication to accumulate transformations.
inline static void XrMatrix4x4f_Multiply(XrMatrix4x4f* result, const XrMatrix4x4f* a, const XrMatrix4x4f* b) {
result->m[0] = a->m[0] * b->m[0] + a->m[4] * b->m[1] + a->m[8] * b->m[2] + a->m[12] * b->m[3];
result->m[1] = a->m[1] * b->m[0] + a->m[5] * b->m[1] + a->m[9] * b->m[2] + a->m[13] * b->m[3];
result->m[2] = a->m[2] * b->m[0] + a->m[6] * b->m[1] + a->m[10] * b->m[2] + a->m[14] * b->m[3];
result->m[3] = a->m[3] * b->m[0] + a->m[7] * b->m[1] + a->m[11] * b->m[2] + a->m[15] * b->m[3];
result->m[4] = a->m[0] * b->m[4] + a->m[4] * b->m[5] + a->m[8] * b->m[6] + a->m[12] * b->m[7];
result->m[5] = a->m[1] * b->m[4] + a->m[5] * b->m[5] + a->m[9] * b->m[6] + a->m[13] * b->m[7];
result->m[6] = a->m[2] * b->m[4] + a->m[6] * b->m[5] + a->m[10] * b->m[6] + a->m[14] * b->m[7];
result->m[7] = a->m[3] * b->m[4] + a->m[7] * b->m[5] + a->m[11] * b->m[6] + a->m[15] * b->m[7];
result->m[8] = a->m[0] * b->m[8] + a->m[4] * b->m[9] + a->m[8] * b->m[10] + a->m[12] * b->m[11];
result->m[9] = a->m[1] * b->m[8] + a->m[5] * b->m[9] + a->m[9] * b->m[10] + a->m[13] * b->m[11];
result->m[10] = a->m[2] * b->m[8] + a->m[6] * b->m[9] + a->m[10] * b->m[10] + a->m[14] * b->m[11];
result->m[11] = a->m[3] * b->m[8] + a->m[7] * b->m[9] + a->m[11] * b->m[10] + a->m[15] * b->m[11];
result->m[12] = a->m[0] * b->m[12] + a->m[4] * b->m[13] + a->m[8] * b->m[14] + a->m[12] * b->m[15];
result->m[13] = a->m[1] * b->m[12] + a->m[5] * b->m[13] + a->m[9] * b->m[14] + a->m[13] * b->m[15];
result->m[14] = a->m[2] * b->m[12] + a->m[6] * b->m[13] + a->m[10] * b->m[14] + a->m[14] * b->m[15];
result->m[15] = a->m[3] * b->m[12] + a->m[7] * b->m[13] + a->m[11] * b->m[14] + a->m[15] * b->m[15];
}
// Creates the transpose of the given matrix.
inline static void XrMatrix4x4f_Transpose(XrMatrix4x4f* result, const XrMatrix4x4f* src) {
result->m[0] = src->m[0];
result->m[1] = src->m[4];
result->m[2] = src->m[8];
result->m[3] = src->m[12];
result->m[4] = src->m[1];
result->m[5] = src->m[5];
result->m[6] = src->m[9];
result->m[7] = src->m[13];
result->m[8] = src->m[2];
result->m[9] = src->m[6];
result->m[10] = src->m[10];
result->m[11] = src->m[14];
result->m[12] = src->m[3];
result->m[13] = src->m[7];
result->m[14] = src->m[11];
result->m[15] = src->m[15];
}
// Returns a 3x3 minor of a 4x4 matrix.
inline static float XrMatrix4x4f_Minor(const XrMatrix4x4f* matrix, int r0, int r1, int r2, int c0, int c1, int c2) {
return matrix->m[4 * r0 + c0] *
(matrix->m[4 * r1 + c1] * matrix->m[4 * r2 + c2] - matrix->m[4 * r2 + c1] * matrix->m[4 * r1 + c2]) -
matrix->m[4 * r0 + c1] *
(matrix->m[4 * r1 + c0] * matrix->m[4 * r2 + c2] - matrix->m[4 * r2 + c0] * matrix->m[4 * r1 + c2]) +
matrix->m[4 * r0 + c2] *
(matrix->m[4 * r1 + c0] * matrix->m[4 * r2 + c1] - matrix->m[4 * r2 + c0] * matrix->m[4 * r1 + c1]);
}
// Calculates the inverse of a 4x4 matrix.
inline static void XrMatrix4x4f_Invert(XrMatrix4x4f* result, const XrMatrix4x4f* src) {
const float rcpDet =
1.0f / (src->m[0] * XrMatrix4x4f_Minor(src, 1, 2, 3, 1, 2, 3) - src->m[1] * XrMatrix4x4f_Minor(src, 1, 2, 3, 0, 2, 3) +
src->m[2] * XrMatrix4x4f_Minor(src, 1, 2, 3, 0, 1, 3) - src->m[3] * XrMatrix4x4f_Minor(src, 1, 2, 3, 0, 1, 2));
result->m[0] = XrMatrix4x4f_Minor(src, 1, 2, 3, 1, 2, 3) * rcpDet;
result->m[1] = -XrMatrix4x4f_Minor(src, 0, 2, 3, 1, 2, 3) * rcpDet;
result->m[2] = XrMatrix4x4f_Minor(src, 0, 1, 3, 1, 2, 3) * rcpDet;
result->m[3] = -XrMatrix4x4f_Minor(src, 0, 1, 2, 1, 2, 3) * rcpDet;
result->m[4] = -XrMatrix4x4f_Minor(src, 1, 2, 3, 0, 2, 3) * rcpDet;
result->m[5] = XrMatrix4x4f_Minor(src, 0, 2, 3, 0, 2, 3) * rcpDet;
result->m[6] = -XrMatrix4x4f_Minor(src, 0, 1, 3, 0, 2, 3) * rcpDet;
result->m[7] = XrMatrix4x4f_Minor(src, 0, 1, 2, 0, 2, 3) * rcpDet;
result->m[8] = XrMatrix4x4f_Minor(src, 1, 2, 3, 0, 1, 3) * rcpDet;
result->m[9] = -XrMatrix4x4f_Minor(src, 0, 2, 3, 0, 1, 3) * rcpDet;
result->m[10] = XrMatrix4x4f_Minor(src, 0, 1, 3, 0, 1, 3) * rcpDet;
result->m[11] = -XrMatrix4x4f_Minor(src, 0, 1, 2, 0, 1, 3) * rcpDet;
result->m[12] = -XrMatrix4x4f_Minor(src, 1, 2, 3, 0, 1, 2) * rcpDet;
result->m[13] = XrMatrix4x4f_Minor(src, 0, 2, 3, 0, 1, 2) * rcpDet;
result->m[14] = -XrMatrix4x4f_Minor(src, 0, 1, 3, 0, 1, 2) * rcpDet;
result->m[15] = XrMatrix4x4f_Minor(src, 0, 1, 2, 0, 1, 2) * rcpDet;
}
// Calculates the inverse of a rigid body transform.
inline static void XrMatrix4x4f_InvertRigidBody(XrMatrix4x4f* result, const XrMatrix4x4f* src) {
result->m[0] = src->m[0];
result->m[1] = src->m[4];
result->m[2] = src->m[8];
result->m[3] = 0.0f;
result->m[4] = src->m[1];
result->m[5] = src->m[5];
result->m[6] = src->m[9];
result->m[7] = 0.0f;
result->m[8] = src->m[2];
result->m[9] = src->m[6];
result->m[10] = src->m[10];
result->m[11] = 0.0f;
result->m[12] = -(src->m[0] * src->m[12] + src->m[1] * src->m[13] + src->m[2] * src->m[14]);
result->m[13] = -(src->m[4] * src->m[12] + src->m[5] * src->m[13] + src->m[6] * src->m[14]);
result->m[14] = -(src->m[8] * src->m[12] + src->m[9] * src->m[13] + src->m[10] * src->m[14]);
result->m[15] = 1.0f;
}
// Creates an identity matrix.
inline static void XrMatrix4x4f_CreateIdentity(XrMatrix4x4f* result) {
result->m[0] = 1.0f;
result->m[1] = 0.0f;
result->m[2] = 0.0f;
result->m[3] = 0.0f;
result->m[4] = 0.0f;
result->m[5] = 1.0f;
result->m[6] = 0.0f;
result->m[7] = 0.0f;
result->m[8] = 0.0f;
result->m[9] = 0.0f;
result->m[10] = 1.0f;
result->m[11] = 0.0f;
result->m[12] = 0.0f;
result->m[13] = 0.0f;
result->m[14] = 0.0f;
result->m[15] = 1.0f;
}
// Creates a translation matrix.
inline static void XrMatrix4x4f_CreateTranslation(XrMatrix4x4f* result, const float x, const float y, const float z) {
result->m[0] = 1.0f;
result->m[1] = 0.0f;
result->m[2] = 0.0f;
result->m[3] = 0.0f;
result->m[4] = 0.0f;
result->m[5] = 1.0f;
result->m[6] = 0.0f;
result->m[7] = 0.0f;
result->m[8] = 0.0f;
result->m[9] = 0.0f;
result->m[10] = 1.0f;
result->m[11] = 0.0f;
result->m[12] = x;
result->m[13] = y;
result->m[14] = z;
result->m[15] = 1.0f;
}
// Creates a rotation matrix.
// If -Z=forward, +Y=up, +X=right, then degreesX=pitch, degreesY=yaw, degreesZ=roll.
inline static void XrMatrix4x4f_CreateRotation(XrMatrix4x4f* result, const float degreesX, const float degreesY,
const float degreesZ) {
const float sinX = sinf(degreesX * (MATH_PI / 180.0f));
const float cosX = cosf(degreesX * (MATH_PI / 180.0f));
const XrMatrix4x4f rotationX = {{1, 0, 0, 0, 0, cosX, sinX, 0, 0, -sinX, cosX, 0, 0, 0, 0, 1}};
const float sinY = sinf(degreesY * (MATH_PI / 180.0f));
const float cosY = cosf(degreesY * (MATH_PI / 180.0f));
const XrMatrix4x4f rotationY = {{cosY, 0, -sinY, 0, 0, 1, 0, 0, sinY, 0, cosY, 0, 0, 0, 0, 1}};
const float sinZ = sinf(degreesZ * (MATH_PI / 180.0f));
const float cosZ = cosf(degreesZ * (MATH_PI / 180.0f));
const XrMatrix4x4f rotationZ = {{cosZ, sinZ, 0, 0, -sinZ, cosZ, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}};
XrMatrix4x4f rotationXY;
XrMatrix4x4f_Multiply(&rotationXY, &rotationY, &rotationX);
XrMatrix4x4f_Multiply(result, &rotationZ, &rotationXY);
}
// Creates a scale matrix.
inline static void XrMatrix4x4f_CreateScale(XrMatrix4x4f* result, const float x, const float y, const float z) {
result->m[0] = x;
result->m[1] = 0.0f;
result->m[2] = 0.0f;
result->m[3] = 0.0f;
result->m[4] = 0.0f;
result->m[5] = y;
result->m[6] = 0.0f;
result->m[7] = 0.0f;
result->m[8] = 0.0f;
result->m[9] = 0.0f;
result->m[10] = z;
result->m[11] = 0.0f;
result->m[12] = 0.0f;
result->m[13] = 0.0f;
result->m[14] = 0.0f;
result->m[15] = 1.0f;
}
// Creates a matrix from a quaternion.
inline static void XrMatrix4x4f_CreateFromQuaternion(XrMatrix4x4f* result, const XrQuaternionf* quat) {
const float x2 = quat->x + quat->x;
const float y2 = quat->y + quat->y;
const float z2 = quat->z + quat->z;
const float xx2 = quat->x * x2;
const float yy2 = quat->y * y2;
const float zz2 = quat->z * z2;
const float yz2 = quat->y * z2;
const float wx2 = quat->w * x2;
const float xy2 = quat->x * y2;
const float wz2 = quat->w * z2;
const float xz2 = quat->x * z2;
const float wy2 = quat->w * y2;
result->m[0] = 1.0f - yy2 - zz2;
result->m[1] = xy2 + wz2;
result->m[2] = xz2 - wy2;
result->m[3] = 0.0f;
result->m[4] = xy2 - wz2;
result->m[5] = 1.0f - xx2 - zz2;
result->m[6] = yz2 + wx2;
result->m[7] = 0.0f;
result->m[8] = xz2 + wy2;
result->m[9] = yz2 - wx2;
result->m[10] = 1.0f - xx2 - yy2;
result->m[11] = 0.0f;
result->m[12] = 0.0f;
result->m[13] = 0.0f;
result->m[14] = 0.0f;
result->m[15] = 1.0f;
}
// Creates a combined translation(rotation(scale(object))) matrix.
inline static void XrMatrix4x4f_CreateTranslationRotationScale(XrMatrix4x4f* result, const XrVector3f* translation,
const XrQuaternionf* rotation, const XrVector3f* scale) {
XrMatrix4x4f scaleMatrix;
XrMatrix4x4f_CreateScale(&scaleMatrix, scale->x, scale->y, scale->z);
XrMatrix4x4f rotationMatrix;
XrMatrix4x4f_CreateFromQuaternion(&rotationMatrix, rotation);
XrMatrix4x4f translationMatrix;
XrMatrix4x4f_CreateTranslation(&translationMatrix, translation->x, translation->y, translation->z);
XrMatrix4x4f combinedMatrix;
XrMatrix4x4f_Multiply(&combinedMatrix, &rotationMatrix, &scaleMatrix);
XrMatrix4x4f_Multiply(result, &translationMatrix, &combinedMatrix);
}
// Creates a projection matrix based on the specified dimensions.
// The projection matrix transforms -Z=forward, +Y=up, +X=right to the appropriate clip space for the graphics API.
// The far plane is placed at infinity if farZ <= nearZ.
// An infinite projection matrix is preferred for rasterization because, except for
// things *right* up against the near plane, it always provides better precision:
// "Tightening the Precision of Perspective Rendering"
// Paul Upchurch, Mathieu Desbrun
// Journal of Graphics Tools, Volume 16, Issue 1, 2012
inline static void XrMatrix4x4f_CreateProjection(XrMatrix4x4f* result, GraphicsAPI graphicsApi, const float tanAngleLeft,
const float tanAngleRight, const float tanAngleUp, float const tanAngleDown,
const float nearZ, const float farZ) {
const float tanAngleWidth = tanAngleRight - tanAngleLeft;
// Set to tanAngleDown - tanAngleUp for a clip space with positive Y down (Vulkan).
// Set to tanAngleUp - tanAngleDown for a clip space with positive Y up (OpenGL / D3D / Metal).
const float tanAngleHeight = graphicsApi == GRAPHICS_VULKAN ? (tanAngleDown - tanAngleUp) : (tanAngleUp - tanAngleDown);
// Set to nearZ for a [-1,1] Z clip space (OpenGL / OpenGL ES).
// Set to zero for a [0,1] Z clip space (Vulkan / D3D / Metal).
const float offsetZ = (graphicsApi == GRAPHICS_OPENGL || graphicsApi == GRAPHICS_OPENGL_ES) ? nearZ : 0;
if (farZ <= nearZ) {
// place the far plane at infinity
result->m[0] = 2 / tanAngleWidth;
result->m[4] = 0;
result->m[8] = (tanAngleRight + tanAngleLeft) / tanAngleWidth;
result->m[12] = 0;
result->m[1] = 0;
result->m[5] = 2 / tanAngleHeight;
result->m[9] = (tanAngleUp + tanAngleDown) / tanAngleHeight;
result->m[13] = 0;
result->m[2] = 0;
result->m[6] = 0;
result->m[10] = -1;
result->m[14] = -(nearZ + offsetZ);
result->m[3] = 0;
result->m[7] = 0;
result->m[11] = -1;
result->m[15] = 0;
} else {
// normal projection
result->m[0] = 2 / tanAngleWidth;
result->m[4] = 0;
result->m[8] = (tanAngleRight + tanAngleLeft) / tanAngleWidth;
result->m[12] = 0;
result->m[1] = 0;
result->m[5] = 2 / tanAngleHeight;
result->m[9] = (tanAngleUp + tanAngleDown) / tanAngleHeight;
result->m[13] = 0;
result->m[2] = 0;
result->m[6] = 0;
result->m[10] = -(farZ + offsetZ) / (farZ - nearZ);
result->m[14] = -(farZ * (nearZ + offsetZ)) / (farZ - nearZ);
result->m[3] = 0;
result->m[7] = 0;
result->m[11] = -1;
result->m[15] = 0;
}
}
// Creates a projection matrix based on the specified FOV.
inline static void XrMatrix4x4f_CreateProjectionFov(XrMatrix4x4f* result, GraphicsAPI graphicsApi, const XrFovf fov,
const float nearZ, const float farZ) {
const float tanLeft = tanf(fov.angleLeft);
const float tanRight = tanf(fov.angleRight);
const float tanDown = tanf(fov.angleDown);
const float tanUp = tanf(fov.angleUp);
XrMatrix4x4f_CreateProjection(result, graphicsApi, tanLeft, tanRight, tanUp, tanDown, nearZ, farZ);
}
// Creates a matrix that transforms the -1 to 1 cube to cover the given 'mins' and 'maxs' transformed with the given 'matrix'.
inline static void XrMatrix4x4f_CreateOffsetScaleForBounds(XrMatrix4x4f* result, const XrMatrix4x4f* matrix, const XrVector3f* mins,
const XrVector3f* maxs) {
const XrVector3f offset = {(maxs->x + mins->x) * 0.5f, (maxs->y + mins->y) * 0.5f, (maxs->z + mins->z) * 0.5f};
const XrVector3f scale = {(maxs->x - mins->x) * 0.5f, (maxs->y - mins->y) * 0.5f, (maxs->z - mins->z) * 0.5f};
result->m[0] = matrix->m[0] * scale.x;
result->m[1] = matrix->m[1] * scale.x;
result->m[2] = matrix->m[2] * scale.x;
result->m[3] = matrix->m[3] * scale.x;
result->m[4] = matrix->m[4] * scale.y;
result->m[5] = matrix->m[5] * scale.y;
result->m[6] = matrix->m[6] * scale.y;
result->m[7] = matrix->m[7] * scale.y;
result->m[8] = matrix->m[8] * scale.z;
result->m[9] = matrix->m[9] * scale.z;
result->m[10] = matrix->m[10] * scale.z;
result->m[11] = matrix->m[11] * scale.z;
result->m[12] = matrix->m[12] + matrix->m[0] * offset.x + matrix->m[4] * offset.y + matrix->m[8] * offset.z;
result->m[13] = matrix->m[13] + matrix->m[1] * offset.x + matrix->m[5] * offset.y + matrix->m[9] * offset.z;
result->m[14] = matrix->m[14] + matrix->m[2] * offset.x + matrix->m[6] * offset.y + matrix->m[10] * offset.z;
result->m[15] = matrix->m[15] + matrix->m[3] * offset.x + matrix->m[7] * offset.y + matrix->m[11] * offset.z;
}
// Returns true if the given matrix is affine.
inline static bool XrMatrix4x4f_IsAffine(const XrMatrix4x4f* matrix, const float epsilon) {
return fabsf(matrix->m[3]) <= epsilon && fabsf(matrix->m[7]) <= epsilon && fabsf(matrix->m[11]) <= epsilon &&
fabsf(matrix->m[15] - 1.0f) <= epsilon;
}
// Returns true if the given matrix is orthogonal.
inline static bool XrMatrix4x4f_IsOrthogonal(const XrMatrix4x4f* matrix, const float epsilon) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (i != j) {
if (fabsf(matrix->m[4 * i + 0] * matrix->m[4 * j + 0] + matrix->m[4 * i + 1] * matrix->m[4 * j + 1] +
matrix->m[4 * i + 2] * matrix->m[4 * j + 2]) > epsilon) {
return false;
}
if (fabsf(matrix->m[4 * 0 + i] * matrix->m[4 * 0 + j] + matrix->m[4 * 1 + i] * matrix->m[4 * 1 + j] +
matrix->m[4 * 2 + i] * matrix->m[4 * 2 + j]) > epsilon) {
return false;
}
}
}
}
return true;
}
// Returns true if the given matrix is orthonormal.
inline static bool XrMatrix4x4f_IsOrthonormal(const XrMatrix4x4f* matrix, const float epsilon) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
const float kd = (i == j) ? 1.0f : 0.0f; // Kronecker delta
if (fabsf(kd - (matrix->m[4 * i + 0] * matrix->m[4 * j + 0] + matrix->m[4 * i + 1] * matrix->m[4 * j + 1] +
matrix->m[4 * i + 2] * matrix->m[4 * j + 2])) > epsilon) {
return false;
}
if (fabsf(kd - (matrix->m[4 * 0 + i] * matrix->m[4 * 0 + j] + matrix->m[4 * 1 + i] * matrix->m[4 * 1 + j] +
matrix->m[4 * 2 + i] * matrix->m[4 * 2 + j])) > epsilon) {
return false;
}
}
}
return true;
}
// Returns true if the given matrix is a rigid body transform.
inline static bool XrMatrix4x4f_IsRigidBody(const XrMatrix4x4f* matrix, const float epsilon) {
return XrMatrix4x4f_IsAffine(matrix, epsilon) && XrMatrix4x4f_IsOrthonormal(matrix, epsilon);
}
// Get the translation from a combined translation(rotation(scale(object))) matrix.
inline static void XrMatrix4x4f_GetTranslation(XrVector3f* result, const XrMatrix4x4f* src) {
assert(XrMatrix4x4f_IsAffine(src, 1e-4f));
assert(XrMatrix4x4f_IsOrthogonal(src, 1e-4f));
result->x = src->m[12];
result->y = src->m[13];
result->z = src->m[14];
}
// Get the rotation from a combined translation(rotation(scale(object))) matrix.
inline static void XrMatrix4x4f_GetRotation(XrQuaternionf* result, const XrMatrix4x4f* src) {
assert(XrMatrix4x4f_IsAffine(src, 1e-4f));
assert(XrMatrix4x4f_IsOrthogonal(src, 1e-4f));
const float rcpScaleX = XrRcpSqrt(src->m[0] * src->m[0] + src->m[1] * src->m[1] + src->m[2] * src->m[2]);
const float rcpScaleY = XrRcpSqrt(src->m[4] * src->m[4] + src->m[5] * src->m[5] + src->m[6] * src->m[6]);
const float rcpScaleZ = XrRcpSqrt(src->m[8] * src->m[8] + src->m[9] * src->m[9] + src->m[10] * src->m[10]);
const float m[9] = {src->m[0] * rcpScaleX, src->m[1] * rcpScaleX, src->m[2] * rcpScaleX,
src->m[4] * rcpScaleY, src->m[5] * rcpScaleY, src->m[6] * rcpScaleY,
src->m[8] * rcpScaleZ, src->m[9] * rcpScaleZ, src->m[10] * rcpScaleZ};
if (m[0 * 3 + 0] + m[1 * 3 + 1] + m[2 * 3 + 2] > 0.0f) {
float t = +m[0 * 3 + 0] + m[1 * 3 + 1] + m[2 * 3 + 2] + 1.0f;
float s = XrRcpSqrt(t) * 0.5f;
result->w = s * t;
result->z = (m[0 * 3 + 1] - m[1 * 3 + 0]) * s;
result->y = (m[2 * 3 + 0] - m[0 * 3 + 2]) * s;
result->x = (m[1 * 3 + 2] - m[2 * 3 + 1]) * s;
} else if (m[0 * 3 + 0] > m[1 * 3 + 1] && m[0 * 3 + 0] > m[2 * 3 + 2]) {
float t = +m[0 * 3 + 0] - m[1 * 3 + 1] - m[2 * 3 + 2] + 1.0f;
float s = XrRcpSqrt(t) * 0.5f;
result->x = s * t;
result->y = (m[0 * 3 + 1] + m[1 * 3 + 0]) * s;
result->z = (m[2 * 3 + 0] + m[0 * 3 + 2]) * s;
result->w = (m[1 * 3 + 2] - m[2 * 3 + 1]) * s;
} else if (m[1 * 3 + 1] > m[2 * 3 + 2]) {
float t = -m[0 * 3 + 0] + m[1 * 3 + 1] - m[2 * 3 + 2] + 1.0f;
float s = XrRcpSqrt(t) * 0.5f;
result->y = s * t;
result->x = (m[0 * 3 + 1] + m[1 * 3 + 0]) * s;
result->w = (m[2 * 3 + 0] - m[0 * 3 + 2]) * s;
result->z = (m[1 * 3 + 2] + m[2 * 3 + 1]) * s;
} else {
float t = -m[0 * 3 + 0] - m[1 * 3 + 1] + m[2 * 3 + 2] + 1.0f;
float s = XrRcpSqrt(t) * 0.5f;
result->z = s * t;
result->w = (m[0 * 3 + 1] - m[1 * 3 + 0]) * s;
result->x = (m[2 * 3 + 0] + m[0 * 3 + 2]) * s;
result->y = (m[1 * 3 + 2] + m[2 * 3 + 1]) * s;
}
}
// Get the scale from a combined translation(rotation(scale(object))) matrix.
inline static void XrMatrix4x4f_GetScale(XrVector3f* result, const XrMatrix4x4f* src) {
assert(XrMatrix4x4f_IsAffine(src, 1e-4f));
assert(XrMatrix4x4f_IsOrthogonal(src, 1e-4f));
result->x = sqrtf(src->m[0] * src->m[0] + src->m[1] * src->m[1] + src->m[2] * src->m[2]);
result->y = sqrtf(src->m[4] * src->m[4] + src->m[5] * src->m[5] + src->m[6] * src->m[6]);
result->z = sqrtf(src->m[8] * src->m[8] + src->m[9] * src->m[9] + src->m[10] * src->m[10]);
}
// Transforms a 3D vector.
inline static void XrMatrix4x4f_TransformVector3f(XrVector3f* result, const XrMatrix4x4f* m, const XrVector3f* v) {
const float w = m->m[3] * v->x + m->m[7] * v->y + m->m[11] * v->z + m->m[15];
const float rcpW = 1.0f / w;
result->x = (m->m[0] * v->x + m->m[4] * v->y + m->m[8] * v->z + m->m[12]) * rcpW;
result->y = (m->m[1] * v->x + m->m[5] * v->y + m->m[9] * v->z + m->m[13]) * rcpW;
result->z = (m->m[2] * v->x + m->m[6] * v->y + m->m[10] * v->z + m->m[14]) * rcpW;
}
// Transforms a 4D vector.
inline static void XrMatrix4x4f_TransformVector4f(XrVector4f* result, const XrMatrix4x4f* m, const XrVector4f* v) {
result->x = m->m[0] * v->x + m->m[4] * v->y + m->m[8] * v->z + m->m[12] * v->w;
result->y = m->m[1] * v->x + m->m[5] * v->y + m->m[9] * v->z + m->m[13] * v->w;
result->z = m->m[2] * v->x + m->m[6] * v->y + m->m[10] * v->z + m->m[14] * v->w;
result->w = m->m[3] * v->x + m->m[7] * v->y + m->m[11] * v->z + m->m[15] * v->w;
}
// Transforms the 'mins' and 'maxs' bounds with the given 'matrix'.
inline static void XrMatrix4x4f_TransformBounds(XrVector3f* resultMins, XrVector3f* resultMaxs, const XrMatrix4x4f* matrix,
const XrVector3f* mins, const XrVector3f* maxs) {
assert(XrMatrix4x4f_IsAffine(matrix, 1e-4f));
const XrVector3f center = {(mins->x + maxs->x) * 0.5f, (mins->y + maxs->y) * 0.5f, (mins->z + maxs->z) * 0.5f};
const XrVector3f extents = {maxs->x - center.x, maxs->y - center.y, maxs->z - center.z};
const XrVector3f newCenter = {matrix->m[0] * center.x + matrix->m[4] * center.y + matrix->m[8] * center.z + matrix->m[12],
matrix->m[1] * center.x + matrix->m[5] * center.y + matrix->m[9] * center.z + matrix->m[13],
matrix->m[2] * center.x + matrix->m[6] * center.y + matrix->m[10] * center.z + matrix->m[14]};
const XrVector3f newExtents = {
fabsf(extents.x * matrix->m[0]) + fabsf(extents.y * matrix->m[4]) + fabsf(extents.z * matrix->m[8]),
fabsf(extents.x * matrix->m[1]) + fabsf(extents.y * matrix->m[5]) + fabsf(extents.z * matrix->m[9]),
fabsf(extents.x * matrix->m[2]) + fabsf(extents.y * matrix->m[6]) + fabsf(extents.z * matrix->m[10])};
XrVector3f_Sub(resultMins, &newCenter, &newExtents);
XrVector3f_Add(resultMaxs, &newCenter, &newExtents);
}
// Returns true if the 'mins' and 'maxs' bounds is completely off to one side of the projection matrix.
inline static bool XrMatrix4x4f_CullBounds(const XrMatrix4x4f* mvp, const XrVector3f* mins, const XrVector3f* maxs) {
if (maxs->x <= mins->x && maxs->y <= mins->y && maxs->z <= mins->z) {
return false;
}
XrVector4f c[8];
for (int i = 0; i < 8; i++) {
const XrVector4f corner = {(i & 1) ? maxs->x : mins->x, (i & 2) ? maxs->y : mins->y, (i & 4) ? maxs->z : mins->z, 1.0f};
XrMatrix4x4f_TransformVector4f(&c[i], mvp, &corner);
}
int i;
for (i = 0; i < 8; i++) {
if (c[i].x > -c[i].w) {
break;
}
}
if (i == 8) {
return true;
}
for (i = 0; i < 8; i++) {
if (c[i].x < c[i].w) {
break;
}
}
if (i == 8) {
return true;
}
for (i = 0; i < 8; i++) {
if (c[i].y > -c[i].w) {
break;
}
}
if (i == 8) {
return true;
}
for (i = 0; i < 8; i++) {
if (c[i].y < c[i].w) {
break;
}
}
if (i == 8) {
return true;
}
for (i = 0; i < 8; i++) {
if (c[i].z > -c[i].w) {
break;
}
}
if (i == 8) {
return true;
}
for (i = 0; i < 8; i++) {
if (c[i].z < c[i].w) {
break;
}
}
if (i == 8) {
return true;
}
return false;
}
#endif // XR_LINEAR_H_

View File

@@ -0,0 +1,3 @@
#cmakedefine HAVE_SECURE_GETENV
#cmakedefine HAVE___SECURE_GETENV
#cmakedefine XRLOADER_ENABLE_EXCEPTION_HANDLING

183
extern/openxr/src/loader/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,183 @@
# Copyright (c) 2017 The Khronos Group Inc.
#
# 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.
#
# Author:
#
#set (CMAKE_VERBOSE_MAKEFILE 1)
include(GNUInstallDirs)
# Use this feature for Windows to automatically generate an exports file for the DLL.
# See https://blog.kitware.com/create-dlls-on-windows-without-declspec-using-new-cmake-export-all-feature/
include(GenerateExportHeader)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS false)
set(LOADER_NAME openxr_loader)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(FALLBACK_CONFIG_DIRS "/etc/xdg" CACHE STRING
"Search path to use when XDG_CONFIG_DIRS is unset or empty or the current process is SUID/SGID. Default is freedesktop compliant.")
set(FALLBACK_DATA_DIRS "/usr/local/share:/usr/share" CACHE STRING
"Search path to use when XDG_DATA_DIRS is unset or empty or the current process is SUID/SGID. Default is freedesktop compliant.")
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
set(openxr_loader_RESOURCE_FILE ${CMAKE_CURRENT_SOURCE_DIR}/loader.rc)
set(LOADER_NAME ${LOADER_NAME}-${MAJOR}_${MINOR})
endif()
# List of all files externally generated outside of the loader that the loader
# needs to build with.
SET(LOADER_EXTERNAL_GEN_FILES
${COMMON_GENERATED_OUTPUT}
)
run_xr_xml_generate(loader_source_generator.py xr_generated_loader.hpp)
run_xr_xml_generate(loader_source_generator.py xr_generated_loader.cpp)
if(DYNAMIC_LOADER)
add_definitions(-DXRAPI_DLL_EXPORT)
set(LIBRARY_TYPE SHARED)
else() # build static lib
set(LIBRARY_TYPE STATIC)
endif()
set(JSONCPP_ROOT_DIR ${CMAKE_SOURCE_DIR}/extern/jsoncpp)
add_library(${LOADER_NAME} ${LIBRARY_TYPE}
api_layer_interface.cpp
api_layer_interface.hpp
loader_core.cpp
loader_instance.cpp
loader_instance.hpp
loader_logger.cpp
loader_logger.hpp
loader_logger_recorders.cpp
loader_logger_recorders.hpp
manifest_file.cpp
${GENERATED_OUTPUT}
manifest_file.hpp
runtime_interface.cpp
runtime_interface.hpp
${OPENXR_ROOT_DIR}/src/common/filesystem_utils.cpp
${OPENXR_ROOT_DIR}/src/common/filesystem_utils.hpp
${OPENXR_ROOT_DIR}/src/common/hex_and_handles.cpp
${OPENXR_ROOT_DIR}/src/common/hex_and_handles.h
${JSONCPP_ROOT_DIR}/src/json_reader.cpp
${JSONCPP_ROOT_DIR}/src/json_value.cpp
${JSONCPP_ROOT_DIR}/src/json_writer.cpp
${LOADER_EXTERNAL_GEN_FILES}
${openxr_loader_RESOURCE_FILE}
)
set_target_properties(${LOADER_NAME} PROPERTIES FOLDER ${LOADER_FOLDER})
set_source_files_properties(
${LOADER_EXTERNAL_GEN_FILES}
PROPERTIES GENERATED TRUE
)
add_dependencies(${LOADER_NAME}
generate_openxr_header
xr_global_generated_files
)
target_include_directories(${LOADER_NAME}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
PRIVATE ${CMAKE_BINARY_DIR}/include
PRIVATE ${CMAKE_BINARY_DIR}/src
PRIVATE ${OPENXR_ROOT_DIR}/src/common
PRIVATE ${JSONCPP_ROOT_DIR}/include
)
if(VulkanHeaders_FOUND)
target_include_directories(${LOADER_NAME}
PRIVATE ${Vulkan_INCLUDE_DIRS}
)
endif()
target_compile_definitions(${LOADER_NAME}
PRIVATE API_NAME="OpenXR"
)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_compile_definitions(${LOADER_NAME}
PRIVATE FALLBACK_CONFIG_DIRS="${FALLBACK_CONFIG_DIRS}"
PRIVATE FALLBACK_DATA_DIRS="${FALLBACK_DATA_DIRS}"
PRIVATE SYSCONFDIR="${CMAKE_INSTALL_FULL_SYSCONFDIR}"
)
if(NOT(CMAKE_INSTALL_FULL_SYSCONFDIR STREQUAL "/etc"))
target_compile_definitions(openxr_loader PRIVATE EXTRASYSCONFDIR="/etc")
endif()
set_target_properties(${LOADER_NAME} PROPERTIES SOVERSION "${MAJOR}" VERSION "${MAJOR}.${MINOR}.${PATCH}")
target_link_libraries(${LOADER_NAME} -lstdc++fs -ldl -lpthread -lm)
add_custom_target(lib${LOADER_NAME}.so.${MAJOR}.${MINOR} ALL
COMMAND ${CMAKE_COMMAND} -E create_symlink lib${LOADER_NAME}.so.${MAJOR}.${MINOR}.${PATCH} lib${LOADER_NAME}.so.${MAJOR}.${MINOR})
install(TARGETS ${LOADER_NAME}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
set(XR_API_VERSION "${MAJOR}.${MINOR}")
configure_file("openxr.pc.in" "openxr.pc" @ONLY)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/openxr.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
foreach(configuration in CMAKE_C_FLAGS_DEBUG
CMAKE_C_FLAGS_RELEASE
CMAKE_C_FLAGS_RELWITHDEBINFO
CMAKE_CXX_FLAGS_DEBUG
CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_RELWITHDEBINFO)
# If building DLLs, force static CRT linkage
if(DYNAMIC_LOADER)
if (${configuration} MATCHES "/MD")
# string(REGEX REPLACE "/MD" "/MT" ${configuration} "${${configuration}}")
endif()
else() # Otherwise for static libs, link the CRT dynamically
if (${configuration} MATCHES "/MT")
# string(REGEX REPLACE "/MT" "/MD" ${configuration} "${${configuration}}")
endif()
endif()
endforeach()
target_link_libraries(${LOADER_NAME} shlwapi)
target_compile_options(${LOADER_NAME} PRIVATE)
generate_export_header(${LOADER_NAME})
# set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS false)
# Need to copy DLL to client directories so clients can easily load it.
if( (DYNAMIC_LOADER) AND (CMAKE_GENERATOR MATCHES "^Visual Studio.*") )
file( TO_NATIVE_PATH ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIGURATION>/${LOADER_NAME}.dll COPY_SRC_PATH )
# file( TO_NATIVE_PATH ${CMAKE_CURRENT_BINARY_DIR}/../tests/triangle/$<CONFIGURATION>/ COPY_DST_TEST_PATH )
file( TO_NATIVE_PATH ${CMAKE_CURRENT_BINARY_DIR}/../tests/hello_xr/$<CONFIGURATION>/ COPY_DST_TEST_PATH )
file( TO_NATIVE_PATH ${CMAKE_CURRENT_BINARY_DIR}/../tests/loader_test/$<CONFIGURATION>/ COPY_DST_LOADER_TEST_PATH )
add_custom_command( TARGET ${LOADER_NAME} POST_BUILD
COMMAND xcopy /Y /I ${COPY_SRC_PATH} ${COPY_DST_TEST_PATH}
COMMAND xcopy /Y /I ${COPY_SRC_PATH} ${COPY_DST_LOADER_TEST_PATH}
)
endif()
endif()
if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
target_compile_options(openxr_loader
PRIVATE -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -Wpointer-arith
PRIVATE -fno-strict-aliasing -fno-builtin-memcmp "$<$<COMPILE_LANGUAGE:CXX>:-fno-rtti>"
)
# For GCC version 7.1 or greater, we need to disable the implicit fallthrough warning since
# there's no consistent way to satisfy all compilers until they all accept the C++17 standard
if (CMAKE_COMPILER_IS_GNUCC AND NOT (CMAKE_CXX_COMPILER_VERSION LESS 7.1))
target_compile_options(openxr_loader PRIVATE -Wimplicit-fallthrough=0)
endif()
endif()
install(TARGETS ${LOADER_NAME} DESTINATION lib)
# Custom commands to build dependencies for above targets

View File

@@ -0,0 +1,403 @@
// Copyright (c) 2017-2019 The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// 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.
//
// Author: Mark Young <marky@lunarg.com>
//
#include "api_layer_interface.hpp"
#include "loader_interfaces.h"
#include "loader_logger.hpp"
#include "loader_platform.hpp"
#include "manifest_file.hpp"
#include "platform_utils.hpp"
#include <openxr/openxr.h>
#include <cstring>
#include <memory>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
#define OPENXR_ENABLE_LAYERS_ENV_VAR "XR_ENABLE_API_LAYERS"
// Add any layers defined in the loader layer environment variable.
static void AddEnvironmentApiLayers(const std::string& openxr_command, std::vector<std::string>& enabled_layers) {
char* layer_environment_variable = PlatformUtilsGetEnv(OPENXR_ENABLE_LAYERS_ENV_VAR);
if (nullptr != layer_environment_variable) {
std::string layers = layer_environment_variable;
PlatformUtilsFreeEnv(layer_environment_variable);
std::size_t last_found = 0;
std::size_t found = layers.find_first_of(PATH_SEPARATOR);
std::string cur_search;
// Handle any path listings in the string (separated by the appropriate path separator)
while (found != std::string::npos) {
cur_search = layers.substr(last_found, found);
enabled_layers.push_back(cur_search);
last_found = found + 1;
found = layers.find_first_of(PATH_SEPARATOR, last_found);
}
// If there's something remaining in the string, copy it over
if (last_found < layers.size()) {
cur_search = layers.substr(last_found);
enabled_layers.push_back(cur_search);
}
}
}
XrResult ApiLayerInterface::GetApiLayerProperties(const std::string& openxr_command, uint32_t incoming_count,
uint32_t* outgoing_count, XrApiLayerProperties* api_layer_properties) {
std::vector<std::unique_ptr<ApiLayerManifestFile>> manifest_files;
uint32_t manifest_count = 0;
// Find any implicit layers which we may need to report information for.
XrResult result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_IMPLICIT_API_LAYER, manifest_files);
if (XR_SUCCESS == result) {
// Find any explicit layers which we may need to report information for.
result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_EXPLICIT_API_LAYER, manifest_files);
}
if (XR_SUCCESS != result) {
LoaderLogger::LogErrorMessage(openxr_command,
"ApiLayerInterface::GetApiLayerProperties - failed searching for API layer manifest files");
return result;
}
manifest_count = static_cast<uint32_t>(manifest_files.size());
if (0 == incoming_count) {
if (nullptr == outgoing_count) {
return XR_ERROR_VALIDATION_FAILURE;
}
*outgoing_count = manifest_count;
} else if (nullptr != api_layer_properties) {
if (incoming_count < manifest_count && nullptr != api_layer_properties) {
LoaderLogger::LogErrorMessage(
"xrEnumerateInstanceExtensionProperties",
"VUID-xrEnumerateApiLayerProperties-propertyCapacityInput-parameter: insufficient space in array");
*outgoing_count = manifest_count;
return XR_ERROR_SIZE_INSUFFICIENT;
}
uint32_t prop = 0;
bool properties_valid = true;
for (; prop < incoming_count && prop < manifest_count; ++prop) {
if (XR_TYPE_API_LAYER_PROPERTIES != api_layer_properties[prop].type) {
LoaderLogger::LogErrorMessage(openxr_command,
"VUID-XrApiLayerProperties-type-type: unknown type in api_layer_properties");
properties_valid = false;
}
if (nullptr != api_layer_properties[prop].next) {
LoaderLogger::LogErrorMessage(openxr_command, "VUID-XrApiLayerProperties-next-next: expected NULL");
properties_valid = false;
}
if (properties_valid) {
api_layer_properties[prop] = manifest_files[prop]->GetApiLayerProperties();
}
}
if (!properties_valid) {
LoaderLogger::LogErrorMessage(openxr_command,
"VUID-xrEnumerateApiLayerProperties-properties-parameter: invalid properties");
return XR_ERROR_VALIDATION_FAILURE;
}
if (nullptr != outgoing_count) {
*outgoing_count = prop;
}
}
return XR_SUCCESS;
}
XrResult ApiLayerInterface::GetInstanceExtensionProperties(const std::string& openxr_command, const char* layer_name,
std::vector<XrExtensionProperties>& extension_properties) {
std::vector<std::unique_ptr<ApiLayerManifestFile>> manifest_files;
// If a layer name is supplied, only use the information out of that one layer
if (nullptr != layer_name && 0 != strlen(layer_name)) {
XrResult result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_IMPLICIT_API_LAYER, manifest_files);
if (XR_SUCCESS == result) {
// Find any explicit layers which we may need to report information for.
result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_EXPLICIT_API_LAYER, manifest_files);
if (XR_SUCCESS != result) {
LoaderLogger::LogErrorMessage(
openxr_command,
"ApiLayerInterface::GetInstanceExtensionProperties - failed searching for API layer manifest files");
return result;
}
bool found = false;
auto num_files = static_cast<uint32_t>(manifest_files.size());
for (uint32_t man_file = 0; man_file < num_files; ++man_file) {
// If a layer with the provided name exists, get it's instance extension information.
if (manifest_files[man_file]->LayerName() == layer_name) {
manifest_files[man_file]->GetInstanceExtensionProperties(extension_properties);
found = true;
break;
}
}
// If nothing found, report 0
if (!found) {
return XR_ERROR_API_LAYER_NOT_PRESENT;
}
}
// Otherwise, we want to add only implicit API layers and explicit API layers enabled using the environment variables
} else {
XrResult result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_IMPLICIT_API_LAYER, manifest_files);
if (XR_SUCCESS == result) {
// Find any environmentally enabled explicit layers. If they're present, treat them like implicit layers
// since we know that they're going to be enabled.
std::vector<std::string> env_enabled_layers;
AddEnvironmentApiLayers(openxr_command, env_enabled_layers);
if (!env_enabled_layers.empty()) {
std::vector<std::unique_ptr<ApiLayerManifestFile>> exp_layer_man_files = {};
result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_EXPLICIT_API_LAYER, exp_layer_man_files);
if (XR_SUCCESS == result) {
for (auto l_iter = exp_layer_man_files.begin();
!exp_layer_man_files.empty() && l_iter != exp_layer_man_files.end();
/* No iterate */) {
for (std::string& enabled_layer : env_enabled_layers) {
// If this is an enabled layer, transfer it over to the manifest list.
if (enabled_layer == (*l_iter)->LayerName()) {
manifest_files.push_back(std::move(*l_iter));
break;
}
}
exp_layer_man_files.erase(l_iter);
}
}
}
}
// Grab the layer instance extensions information
auto num_files = static_cast<uint32_t>(manifest_files.size());
for (uint32_t man_file = 0; man_file < num_files; ++man_file) {
manifest_files[man_file]->GetInstanceExtensionProperties(extension_properties);
}
}
return XR_SUCCESS;
}
XrResult ApiLayerInterface::LoadApiLayers(const std::string& openxr_command, uint32_t enabled_api_layer_count,
const char* const* enabled_api_layer_names,
std::vector<std::unique_ptr<ApiLayerInterface>>& api_layer_interfaces) {
XrResult last_error = XR_SUCCESS;
bool any_loaded = false;
std::vector<bool> layer_found;
std::vector<std::unique_ptr<ApiLayerManifestFile>> layer_manifest_files = {};
// Find any implicit layers which we may need to report information for.
XrResult result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_IMPLICIT_API_LAYER, layer_manifest_files);
if (XR_SUCCESS == result) {
// Find any explicit layers which we may need to report information for.
result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_EXPLICIT_API_LAYER, layer_manifest_files);
}
// Put all the enabled layers into a string vector
std::vector<std::string> enabled_api_layers = {};
AddEnvironmentApiLayers(openxr_command, enabled_api_layers);
if (enabled_api_layer_count > 0) {
if (nullptr == enabled_api_layer_names) {
LoaderLogger::LogErrorMessage(
"xrCreateInstance",
"VUID-XrInstanceCreateInfo-enabledApiLayerNames-parameter: enabledApiLayerCount is non-0 but array is NULL");
LoaderLogger::LogErrorMessage(
"xrCreateInstance", "VUID-xrCreateInstance-info-parameter: something wrong with XrInstanceCreateInfo contents");
return XR_ERROR_VALIDATION_FAILURE;
}
auto num_env_api_layers = static_cast<uint32_t>(enabled_api_layers.size());
uint32_t total_api_layers = num_env_api_layers + enabled_api_layer_count;
enabled_api_layers.resize(total_api_layers);
for (uint32_t layer = 0; layer < enabled_api_layer_count; ++layer) {
enabled_api_layers[num_env_api_layers + layer] = enabled_api_layer_names[layer];
}
}
// Initialize the layer found vector to false
layer_found.resize(enabled_api_layers.size());
for (auto&& layer : layer_found) {
layer = false;
}
for (std::unique_ptr<ApiLayerManifestFile>& manifest_file : layer_manifest_files) {
bool enabled = false;
// Always add implicit layers. They would only be in this list if they were enabled
// (i.e. the disable environment variable is not set).
if (manifest_file->Type() == MANIFEST_TYPE_IMPLICIT_API_LAYER) {
enabled = true;
} else {
// Only add explicit layers if they are called out by the application
for (uint32_t layer = 0; layer < enabled_api_layers.size(); ++layer) {
if (enabled_api_layers[layer] == manifest_file->LayerName()) {
layer_found[layer] = true;
enabled = true;
break;
}
}
}
// If this layer isn't enabled, skip it.
if (!enabled) {
continue;
}
LoaderPlatformLibraryHandle layer_library = LoaderPlatformLibraryOpen(manifest_file->LibraryPath());
if (nullptr == layer_library) {
if (!any_loaded) {
last_error = XR_ERROR_FILE_ACCESS_ERROR;
}
std::string library_message = LoaderPlatformLibraryOpenError(manifest_file->LibraryPath());
std::string warning_message = "ApiLayerInterface::LoadApiLayers skipping layer ";
warning_message += manifest_file->LayerName();
warning_message += ", failed to load with message \"";
warning_message += library_message;
warning_message += "\"";
LoaderLogger::LogWarningMessage(openxr_command, warning_message);
continue;
}
// Get and settle on an layer interface version (using any provided name if required).
std::string function_name = manifest_file->GetFunctionName("xrNegotiateLoaderApiLayerInterface");
auto negotiate = reinterpret_cast<PFN_xrNegotiateLoaderApiLayerInterface>(
LoaderPlatformLibraryGetProcAddr(layer_library, function_name));
if (nullptr == negotiate) {
std::ostringstream oss;
oss << "ApiLayerInterface::LoadApiLayers skipping layer " << manifest_file->LayerName()
<< " because negotiation function " << function_name << " was not found";
LoaderLogger::LogErrorMessage(openxr_command, oss.str());
LoaderPlatformLibraryClose(layer_library);
last_error = XR_ERROR_API_LAYER_NOT_PRESENT;
continue;
}
// Loader info for negotiation
XrNegotiateLoaderInfo loader_info = {};
loader_info.structType = XR_LOADER_INTERFACE_STRUCT_LOADER_INFO;
loader_info.structVersion = XR_LOADER_INFO_STRUCT_VERSION;
loader_info.structSize = sizeof(XrNegotiateLoaderInfo);
loader_info.minInterfaceVersion = 1;
loader_info.maxInterfaceVersion = XR_CURRENT_LOADER_API_LAYER_VERSION;
loader_info.minApiVersion = XR_MAKE_VERSION(1, 0, 0);
loader_info.maxApiVersion = XR_MAKE_VERSION(1, 0x3ff, 0xfff); // Maximum allowed version for this major version.
// Set up the layer return structure
XrNegotiateApiLayerRequest api_layer_info = {};
api_layer_info.structType = XR_LOADER_INTERFACE_STRUCT_API_LAYER_REQUEST;
api_layer_info.structVersion = XR_API_LAYER_INFO_STRUCT_VERSION;
api_layer_info.structSize = sizeof(XrNegotiateApiLayerRequest);
XrResult res = negotiate(&loader_info, manifest_file->LayerName().c_str(), &api_layer_info);
// If we supposedly succeeded, but got a nullptr for getInstanceProcAddr
// then something still went wrong, so return with an error.
if (XR_SUCCESS == res && nullptr == api_layer_info.getInstanceProcAddr) {
std::string warning_message = "ApiLayerInterface::LoadApiLayers skipping layer ";
warning_message += manifest_file->LayerName();
warning_message += ", negotiation did not return a valid getInstanceProcAddr";
LoaderLogger::LogWarningMessage(openxr_command, warning_message);
res = XR_ERROR_FILE_CONTENTS_INVALID;
}
if (XR_SUCCESS != res) {
if (!any_loaded) {
last_error = res;
}
std::ostringstream oss;
oss << "ApiLayerInterface::LoadApiLayers skipping layer " << manifest_file->LayerName()
<< " due to failed negotiation with error " << res;
LoaderLogger::LogWarningMessage(openxr_command, oss.str());
LoaderPlatformLibraryClose(layer_library);
continue;
}
{
std::ostringstream oss;
oss << "ApiLayerInterface::LoadApiLayers succeeded loading layer " << manifest_file->LayerName()
<< " using interface version " << api_layer_info.layerInterfaceVersion << " and OpenXR API version "
<< XR_VERSION_MAJOR(api_layer_info.layerApiVersion) << "." << XR_VERSION_MINOR(api_layer_info.layerApiVersion);
LoaderLogger::LogInfoMessage(openxr_command, oss.str());
}
// Grab the list of extensions this layer supports for easy filtering after the
// xrCreateInstance call
std::vector<std::string> supported_extensions;
std::vector<XrExtensionProperties> extension_properties;
manifest_file->GetInstanceExtensionProperties(extension_properties);
supported_extensions.reserve(extension_properties.size());
for (XrExtensionProperties& ext_prop : extension_properties) {
supported_extensions.emplace_back(ext_prop.extensionName);
}
// Add this runtime to the vector
api_layer_interfaces.emplace_back(new ApiLayerInterface(manifest_file->LayerName(), layer_library, supported_extensions,
api_layer_info.getInstanceProcAddr,
api_layer_info.createApiLayerInstance));
// If we load one, clear all errors.
any_loaded = true;
last_error = XR_SUCCESS;
}
// If even one of the layers wasn't found, we want to return an error
for (uint32_t layer = 0; layer < layer_found.size(); ++layer) {
if (!layer_found[layer]) {
std::string error_message = "ApiLayerInterface::LoadApiLayers - failed to find layer ";
error_message += enabled_api_layers[layer];
LoaderLogger::LogErrorMessage(openxr_command, error_message);
last_error = XR_ERROR_API_LAYER_NOT_PRESENT;
}
}
// Always clear the manifest file list. Either we use them or we don't.
layer_manifest_files.clear();
// If we failed catastrophically for some reason, clean up everything.
if (XR_SUCCESS != last_error) {
api_layer_interfaces.clear();
}
return last_error;
}
ApiLayerInterface::ApiLayerInterface(const std::string& layer_name, LoaderPlatformLibraryHandle layer_library,
std::vector<std::string>& supported_extensions,
PFN_xrGetInstanceProcAddr get_instant_proc_addr,
PFN_xrCreateApiLayerInstance create_api_layer_instance)
: _layer_name(layer_name),
_layer_library(layer_library),
_get_instant_proc_addr(get_instant_proc_addr),
_create_api_layer_instance(create_api_layer_instance),
_supported_extensions(supported_extensions) {}
ApiLayerInterface::~ApiLayerInterface() {
std::string info_message = "ApiLayerInterface being destroyed for layer ";
info_message += _layer_name;
LoaderLogger::LogInfoMessage("", info_message);
LoaderPlatformLibraryClose(_layer_library);
}
bool ApiLayerInterface::SupportsExtension(const std::string& extension_name) {
bool found_prop = false;
for (const std::string& supported_extension : _supported_extensions) {
if (supported_extension == extension_name) {
found_prop = true;
break;
}
}
return found_prop;
}

View File

@@ -0,0 +1,65 @@
// Copyright (c) 2017-2019 The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// 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.
//
// Author: Mark Young <marky@lunarg.com>
//
#pragma once
#include <string>
#include <vector>
#include <memory>
#include <openxr/openxr.h>
#include "loader_platform.hpp"
#include "loader_interfaces.h"
struct XrGeneratedDispatchTable;
class ApiLayerInterface {
public:
// Factory method
static XrResult LoadApiLayers(const std::string& openxr_command, uint32_t enabled_api_layer_count,
const char* const* enabled_api_layer_names,
std::vector<std::unique_ptr<ApiLayerInterface>>& api_layer_interfaces);
// Static queries
static XrResult GetApiLayerProperties(const std::string& openxr_command, uint32_t incoming_count, uint32_t* outgoing_count,
XrApiLayerProperties* api_layer_properties);
static XrResult GetInstanceExtensionProperties(const std::string& openxr_command, const char* layer_name,
std::vector<XrExtensionProperties>& extension_properties);
ApiLayerInterface(const std::string& layer_name, LoaderPlatformLibraryHandle layer_library,
std::vector<std::string>& supported_extensions, PFN_xrGetInstanceProcAddr get_instant_proc_addr,
PFN_xrCreateApiLayerInstance create_api_layer_instance);
virtual ~ApiLayerInterface();
PFN_xrGetInstanceProcAddr GetInstanceProcAddrFuncPointer() { return _get_instant_proc_addr; }
PFN_xrCreateApiLayerInstance GetCreateApiLayerInstanceFuncPointer() { return _create_api_layer_instance; }
std::string LayerName() { return _layer_name; }
// Generated methods
void GenUpdateInstanceDispatchTable(XrInstance instance, std::unique_ptr<XrGeneratedDispatchTable>& table);
bool SupportsExtension(const std::string& extension_name);
private:
std::string _layer_name;
LoaderPlatformLibraryHandle _layer_library;
PFN_xrGetInstanceProcAddr _get_instant_proc_addr;
PFN_xrCreateApiLayerInstance _create_api_layer_instance;
std::vector<std::string> _supported_extensions;
};

View File

@@ -0,0 +1,45 @@
// Copyright (c) 2019 The Khronos Group Inc.
//
// 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.
//
// Author: Ryan Pavlik <ryan.pavlik@collabora.com
//
// Provides protection for C ABI functions if standard library functions may throw.
#pragma once
#include "common_cmake_config.h"
#ifdef XRLOADER_ENABLE_EXCEPTION_HANDLING
#include <stdexcept>
#define XRLOADER_ABI_TRY try
#define XRLOADER_ABI_CATCH_BAD_ALLOC_OOM \
catch (const std::bad_alloc&) { \
LoaderLogger::LogErrorMessage("", "failed allocating memory"); \
return XR_ERROR_OUT_OF_MEMORY; \
}
#define XRLOADER_ABI_CATCH_FALLBACK \
catch (const std::exception& e) { \
LoaderLogger::LogErrorMessage("", "Unknown failure: " + std::string(e.what())); \
return XR_ERROR_RUNTIME_FAILURE; \
} \
catch (...) { \
LoaderLogger::LogErrorMessage("", "Unknown failure"); \
return XR_ERROR_RUNTIME_FAILURE; \
}
#else
#define XRLOADER_ABI_TRY
#define XRLOADER_ABI_CATCH_BAD_ALLOC_OOM
#define XRLOADER_ABI_CATCH_FALLBACK
#endif

98
extern/openxr/src/loader/loader.rc vendored Normal file
View File

@@ -0,0 +1,98 @@
//
// Copyright (c) 2017 The Khronos Group Inc.
// Copyright (c) 2017 Valve Corporation
// Copyright (c) 2017 LunarG, Inc.
//
// 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.
//
// Author: Mark Young <marky@LunarG.com>
//
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Start customize section
// Edit this section for your build
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
#define VERSION_MAJOR 1
#define VERSION_MINOR 0
#define VERSION_PATCH 1111
#define VERSION_BUILDNO 2222
#define VERSION_BUILD_DESCRIPTION "Dev Build"
// All builds except release builds should set this to 0.
// Release builds should set this to 1.
#define VERSION_IS_RELEASEBUILD 0
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// End of customize section
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
#include "winres.h"
#define VER_FILE_VERSION VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_BUILDNO
#define STRINGIZE2(s) #s
#define STRINGIZE(s) STRINGIZE2(s)
#if VERSION_IS_RELEASEBUILD==1
#define VER_FILE_DESCRIPTION_STR "OpenXR Loader"
#define VER_FILE_VERSION_STR STRINGIZE(VERSION_MAJOR) \
"." STRINGIZE(VERSION_MINOR) \
"." STRINGIZE(VERSION_PATCH) \
"." STRINGIZE(VERSION_BUILDNO)
#else
#define VER_FILE_DESCRIPTION_STR "OpenXR Loader - " VERSION_BUILD_DESCRIPTION
#define VER_FILE_VERSION_STR STRINGIZE(VERSION_MAJOR) \
"." STRINGIZE(VERSION_MINOR) \
"." STRINGIZE(VERSION_PATCH) \
"." STRINGIZE(VERSION_BUILDNO) \
"." VERSION_BUILD_DESCRIPTION
#endif
VS_VERSION_INFO VERSIONINFO
FILEVERSION VER_FILE_VERSION
PRODUCTVERSION VER_FILE_VERSION
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x00000L
FILETYPE VFT_DLL
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "04090000"
BEGIN
VALUE "FileDescription", VER_FILE_DESCRIPTION_STR
VALUE "FileVersion", VER_FILE_VERSION_STR
VALUE "LegalCopyright", "Copyright (C) 2015-2017"
VALUE "ProductName", "OpenXR Loader"
VALUE "ProductVersion", VER_FILE_VERSION_STR
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 0000
END
END

650
extern/openxr/src/loader/loader_core.cpp vendored Normal file
View File

@@ -0,0 +1,650 @@
// Copyright (c) 2017-2019 The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// 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.
//
// Author: Mark Young <marky@lunarg.com>
//
#ifdef XR_OS_WINDOWS
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "api_layer_interface.hpp"
#include "exception_handling.hpp"
#include "hex_and_handles.h"
#include "loader_instance.hpp"
#include "loader_logger_recorders.hpp"
#include "loader_logger.hpp"
#include "loader_platform.hpp"
#include "runtime_interface.hpp"
#include "xr_generated_dispatch_table.h"
#include "xr_generated_loader.hpp"
#include <openxr/openxr.h>
#include <cstring>
#include <memory>
#include <mutex>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
// Flag to cause the one time to init to only occur one time.
std::once_flag g_one_time_init_flag;
// Global lock to prevent reading JSON manifest files at the same time.
static std::mutex g_loader_json_mutex;
// Global lock to prevent simultaneous instance creation/destruction
static std::mutex g_loader_instance_mutex;
// Utility template function meant to validate if a fixed size string contains
// a null-terminator.
template <size_t max_length>
inline bool IsMissingNullTerminator(const char (&str)[max_length]) {
for (size_t index = 0; index < max_length; ++index) {
if (str[index] == '\0') {
return false;
}
}
return true;
}
extern "C" {
// ---- Core 1.0 manual loader trampoline functions
LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateApiLayerProperties(uint32_t propertyCapacityInput,
uint32_t *propertyCountOutput,
XrApiLayerProperties *properties) XRLOADER_ABI_TRY {
LoaderLogger::LogVerboseMessage("xrEnumerateApiLayerProperties", "Entering loader trampoline");
// Make sure only one thread is attempting to read the JSON files at a time.
std::unique_lock<std::mutex> json_lock(g_loader_json_mutex);
XrResult result = ApiLayerInterface::GetApiLayerProperties("xrEnumerateApiLayerProperties", propertyCapacityInput,
propertyCountOutput, properties);
if (XR_SUCCESS != result) {
LoaderLogger::LogErrorMessage("xrEnumerateApiLayerProperties", "Failed ApiLayerInterface::GetApiLayerProperties");
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL
xrEnumerateInstanceExtensionProperties(const char *layerName, uint32_t propertyCapacityInput, uint32_t *propertyCountOutput,
XrExtensionProperties *properties) XRLOADER_ABI_TRY {
bool just_layer_properties = false;
LoaderLogger::LogVerboseMessage("xrEnumerateInstanceExtensionProperties", "Entering loader trampoline");
if (nullptr != layerName && 0 != strlen(layerName)) {
// Application is only interested in layer's properties, not all of them.
just_layer_properties = true;
}
std::vector<XrExtensionProperties> extension_properties = {};
XrResult result;
{
// Make sure only one thread is attempting to read the JSON files at a time.
std::unique_lock<std::mutex> json_lock(g_loader_json_mutex);
// Get the layer extension properties
result = ApiLayerInterface::GetInstanceExtensionProperties("xrEnumerateInstanceExtensionProperties", layerName,
extension_properties);
if (XR_SUCCESS == result && !just_layer_properties) {
// If not specific to a layer, get the runtime extension properties
result = RuntimeInterface::LoadRuntime("xrEnumerateInstanceExtensionProperties");
if (XR_SUCCESS == result) {
RuntimeInterface::GetRuntime().GetInstanceExtensionProperties(extension_properties);
RuntimeInterface::UnloadRuntime("xrEnumerateInstanceExtensionProperties");
} else {
LoaderLogger::LogErrorMessage("xrEnumerateInstanceExtensionProperties",
"Failed to find default runtime with RuntimeInterface::LoadRuntime()");
}
}
}
if (XR_SUCCESS != result) {
LoaderLogger::LogErrorMessage("xrEnumerateInstanceExtensionProperties", "Failed querying extension properties");
return result;
}
// If this is not in reference to a specific layer, then add the loader-specific extension properties as well.
// These are extensions that the loader directly supports.
if (!just_layer_properties) {
auto loader_extension_props = LoaderInstance::LoaderSpecificExtensions();
for (XrExtensionProperties &loader_prop : loader_extension_props) {
bool found_prop = false;
for (XrExtensionProperties &existing_prop : extension_properties) {
if (0 == strcmp(existing_prop.extensionName, loader_prop.extensionName)) {
found_prop = true;
// Use the loader version if it is newer
if (existing_prop.extensionVersion < loader_prop.extensionVersion) {
existing_prop.extensionVersion = loader_prop.extensionVersion;
}
break;
}
}
// Only add extensions not supported by the loader
if (!found_prop) {
extension_properties.push_back(loader_prop);
}
}
}
auto num_extension_properties = static_cast<uint32_t>(extension_properties.size());
if (propertyCapacityInput == 0) {
if (nullptr == propertyCountOutput) {
return XR_ERROR_VALIDATION_FAILURE;
}
*propertyCountOutput = num_extension_properties;
} else if (nullptr != properties) {
if (propertyCapacityInput < num_extension_properties) {
*propertyCountOutput = num_extension_properties;
LoaderLogger::LogValidationErrorMessage("VUID-xrEnumerateInstanceExtensionProperties-propertyCountOutput-parameter",
"xrEnumerateInstanceExtensionProperties", "insufficient space in array");
return XR_ERROR_SIZE_INSUFFICIENT;
}
uint32_t num_to_copy = num_extension_properties;
// Determine how many extension properties we can copy over
if (propertyCapacityInput < num_to_copy) {
num_to_copy = propertyCapacityInput;
}
bool properties_valid = true;
for (uint32_t prop = 0; prop < propertyCapacityInput && prop < extension_properties.size(); ++prop) {
if (XR_TYPE_EXTENSION_PROPERTIES != properties[prop].type) {
properties_valid = false;
LoaderLogger::LogValidationErrorMessage("VUID-XrExtensionProperties-type-type",
"xrEnumerateInstanceExtensionProperties", "unknown type in properties");
}
if (nullptr != properties[prop].next) {
LoaderLogger::LogValidationErrorMessage("VUID-XrExtensionProperties-next-next",
"xrEnumerateInstanceExtensionProperties", "expected NULL");
properties_valid = false;
}
if (properties_valid) {
properties[prop] = extension_properties[prop];
}
}
if (!properties_valid) {
LoaderLogger::LogValidationErrorMessage("VUID-xrEnumerateInstanceExtensionProperties-properties-parameter",
"xrEnumerateInstanceExtensionProperties", "invalid properties");
return XR_ERROR_VALIDATION_FAILURE;
}
if (nullptr != propertyCountOutput) {
*propertyCountOutput = num_to_copy;
}
}
LoaderLogger::LogVerboseMessage("xrEnumerateInstanceExtensionProperties", "Completed loader trampoline");
return XR_SUCCESS;
}
XRLOADER_ABI_CATCH_FALLBACK
LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateInstance(const XrInstanceCreateInfo *info,
XrInstance *instance) XRLOADER_ABI_TRY {
bool runtime_loaded = false;
LoaderLogger::LogVerboseMessage("xrCreateInstance", "Entering loader trampoline");
if (nullptr == info) {
LoaderLogger::LogValidationErrorMessage("VUID-xrCreateInstance-info-parameter", "xrCreateInstance", "must be non-NULL");
return XR_ERROR_VALIDATION_FAILURE;
}
// If application requested OpenXR API version is higher than the loader version, then we need to throw
// an error.
uint16_t app_major = XR_VERSION_MAJOR(info->applicationInfo.apiVersion); // NOLINT
uint16_t app_minor = XR_VERSION_MINOR(info->applicationInfo.apiVersion); // NOLINT
uint16_t loader_major = XR_VERSION_MAJOR(XR_CURRENT_API_VERSION); // NOLINT
uint16_t loader_minor = XR_VERSION_MINOR(XR_CURRENT_API_VERSION); // NOLINT
if (app_major > loader_major || (app_major == loader_major && app_minor > loader_minor)) {
std::ostringstream oss;
oss << "xrCreateInstance called with invalid API version " << app_major << "." << app_minor
<< ". Max supported version is " << loader_major << "." << loader_minor;
LoaderLogger::LogErrorMessage("xrCreateInstance", oss.str());
return XR_ERROR_API_VERSION_UNSUPPORTED;
}
if (nullptr == instance) {
LoaderLogger::LogValidationErrorMessage("VUID-xrCreateInstance-instance-parameter", "xrCreateInstance", "must be non-NULL");
return XR_ERROR_VALIDATION_FAILURE;
}
std::vector<std::unique_ptr<ApiLayerInterface>> api_layer_interfaces;
// Make sure only one thread is attempting to read the JSON files and use the instance.
XrResult result;
{
std::unique_lock<std::mutex> json_lock(g_loader_json_mutex);
// Load the available runtime
result = RuntimeInterface::LoadRuntime("xrCreateInstance");
if (XR_SUCCESS != result) {
LoaderLogger::LogErrorMessage("xrCreateInstance", "Failed loading runtime information");
} else {
runtime_loaded = true;
// Load the appropriate layers
result = ApiLayerInterface::LoadApiLayers("xrCreateInstance", info->enabledApiLayerCount, info->enabledApiLayerNames,
api_layer_interfaces);
if (XR_SUCCESS != result) {
LoaderLogger::LogErrorMessage("xrCreateInstance", "Failed loading layer information");
}
}
}
if (XR_FAILED(result)) {
if (runtime_loaded) {
RuntimeInterface::UnloadRuntime("xrCreateInstance");
}
return result;
}
std::unique_lock<std::mutex> instance_lock(g_loader_instance_mutex);
// Create the loader instance (only send down first runtime interface)
XrInstance created_instance = XR_NULL_HANDLE;
result = LoaderInstance::CreateInstance(std::move(api_layer_interfaces), info, &created_instance);
if (XR_SUCCEEDED(result)) {
*instance = created_instance;
LoaderInstance *loader_instance = g_instance_map.Get(created_instance);
// Create a debug utils messenger if the create structure is in the "next" chain
const auto *next_header = reinterpret_cast<const XrBaseInStructure *>(info->next);
const XrDebugUtilsMessengerCreateInfoEXT *dbg_utils_create_info = nullptr;
while (next_header != nullptr) {
if (next_header->type == XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) {
LoaderLogger::LogInfoMessage("xrCreateInstance", "Found XrDebugUtilsMessengerCreateInfoEXT in \'next\' chain.");
dbg_utils_create_info = reinterpret_cast<const XrDebugUtilsMessengerCreateInfoEXT *>(next_header);
XrDebugUtilsMessengerEXT messenger;
result = xrCreateDebugUtilsMessengerEXT(*instance, dbg_utils_create_info, &messenger);
if (XR_SUCCESS != result) {
return XR_ERROR_VALIDATION_FAILURE;
}
loader_instance->SetDefaultDebugUtilsMessenger(messenger);
break;
}
next_header = reinterpret_cast<const XrBaseInStructure *>(next_header->next);
}
}
LoaderLogger::LogVerboseMessage("xrCreateInstance", "Completed loader trampoline");
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroyInstance(XrInstance instance) XRLOADER_ABI_TRY {
LoaderLogger::LogVerboseMessage("xrDestroyInstance", "Entering loader trampoline");
// Runtimes may detect XR_NULL_HANDLE provided as a required handle parameter and return XR_ERROR_HANDLE_INVALID. - 2.9
if (XR_NULL_HANDLE == instance) {
return XR_ERROR_HANDLE_INVALID;
}
LoaderInstance *const loader_instance = g_instance_map.Get(instance);
if (loader_instance == nullptr) {
LoaderLogger::LogValidationErrorMessage("VUID-xrDestroyInstance-instance-parameter", "xrDestroyInstance",
"invalid instance");
return XR_ERROR_HANDLE_INVALID;
}
const std::unique_ptr<XrGeneratedDispatchTable> &dispatch_table = loader_instance->DispatchTable();
// If we allocated a default debug utils messenger, free it
XrDebugUtilsMessengerEXT messenger = loader_instance->DefaultDebugUtilsMessenger();
if (messenger != XR_NULL_HANDLE) {
xrDestroyDebugUtilsMessengerEXT(messenger);
}
// Now destroy the instance
if (XR_SUCCESS != dispatch_table->DestroyInstance(instance)) {
LoaderLogger::LogErrorMessage("xrDestroyInstance", "Unknown error occurred calling down chain");
}
// Cleanup any map entries that may still be using this instance
LoaderCleanUpMapsForInstance(loader_instance);
// Lock the instance create/destroy mutex
std::unique_lock<std::mutex> loader_instance_lock(g_loader_instance_mutex);
delete loader_instance;
LoaderLogger::LogVerboseMessage("xrDestroyInstance", "Completed loader trampoline");
// Finally, unload the runtime if necessary
RuntimeInterface::UnloadRuntime("xrDestroyInstance");
return XR_SUCCESS;
}
XRLOADER_ABI_CATCH_FALLBACK
// ---- Core 1.0 manual loader terminator functions
// Validate that the applicationInfo structure in the XrInstanceCreateInfo is valid.
static XrResult ValidateApplicationInfo(LoaderInstance *loader_instance, const XrApplicationInfo &info) {
if (IsMissingNullTerminator<XR_MAX_APPLICATION_NAME_SIZE>(info.applicationName)) {
LoaderLogger::LogValidationErrorMessage("VUID-XrApplicationInfo-applicationName-parameter", "xrCreateInstance",
"application name missing NULL terminator.");
return XR_ERROR_NAME_INVALID;
}
if (IsMissingNullTerminator<XR_MAX_ENGINE_NAME_SIZE>(info.engineName)) {
LoaderLogger::LogValidationErrorMessage("VUID-XrApplicationInfo-engineName-parameter", "xrCreateInstance",
"engine name missing NULL terminator.");
return XR_ERROR_NAME_INVALID;
}
if (strlen(info.applicationName) == 0) {
LoaderLogger::LogErrorMessage("xrCreateInstance",
"VUID-XrApplicationInfo-engineName-parameter: application name can not be empty.");
return XR_ERROR_NAME_INVALID;
}
return XR_SUCCESS;
}
// Validate that the XrInstanceCreateInfo is valid
static XrResult ValidateInstanceCreateInfo(LoaderInstance *loader_instance, const XrInstanceCreateInfo *info) {
// Should have a valid 'type'
if (XR_TYPE_INSTANCE_CREATE_INFO != info->type) {
LoaderLogger::LogValidationErrorMessage("VUID-XrInstanceCreateInfo-type-type", "xrCreateInstance",
"expected XR_TYPE_INSTANCE_CREATE_INFO.");
return XR_ERROR_VALIDATION_FAILURE;
}
// Flags must be 0
if (0 != info->createFlags) {
LoaderLogger::LogValidationErrorMessage("VUID-XrInstanceCreateInfo-createFlags-zerobitmask", "xrCreateInstance",
"flags must be 0.");
return XR_ERROR_VALIDATION_FAILURE;
}
// ApplicationInfo struct must be valid
XrResult result = ValidateApplicationInfo(loader_instance, info->applicationInfo);
if (XR_SUCCESS != result) {
LoaderLogger::LogValidationErrorMessage("VUID-XrInstanceCreateInfo-applicationInfo-parameter", "xrCreateInstance",
"info->applicationInfo is not valid.");
return result;
}
// VUID-XrInstanceCreateInfo-enabledApiLayerNames-parameter already tested in LoadApiLayers()
if ((info->enabledExtensionCount != 0u) && nullptr == info->enabledExtensionNames) {
LoaderLogger::LogValidationErrorMessage("VUID-XrInstanceCreateInfo-enabledExtensionNames-parameter", "xrCreateInstance",
"enabledExtensionCount is non-0 but array is NULL");
return XR_ERROR_VALIDATION_FAILURE;
}
return XR_SUCCESS;
}
XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateInstance(const XrInstanceCreateInfo *info, XrInstance *instance) XRLOADER_ABI_TRY {
LoaderLogger::LogVerboseMessage("xrCreateInstance", "Entering loader terminator");
LoaderInstance *loader_instance = reinterpret_cast<LoaderInstance *>(*instance);
XrResult result = ValidateInstanceCreateInfo(loader_instance, info);
if (XR_SUCCESS != result) {
LoaderLogger::LogValidationErrorMessage("VUID-xrCreateInstance-info-parameter", "xrCreateInstance",
"something wrong with XrInstanceCreateInfo contents");
return result;
}
result = RuntimeInterface::GetRuntime().CreateInstance(info, instance);
loader_instance->SetRuntimeInstance(*instance);
LoaderLogger::LogVerboseMessage("xrCreateInstance", "Completed loader terminator");
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateApiLayerInstance(const XrInstanceCreateInfo *info,
const struct XrApiLayerCreateInfo * /*apiLayerInfo*/,
XrInstance *instance) {
return LoaderXrTermCreateInstance(info, instance);
}
XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermDestroyInstance(XrInstance instance) XRLOADER_ABI_TRY {
XrResult result;
LoaderLogger::LogVerboseMessage("xrDestroyInstance", "Entering loader terminator");
result = RuntimeInterface::GetRuntime().DestroyInstance(instance);
LoaderLogger::LogVerboseMessage("xrDestroyInstance", "Completed loader terminator");
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
// ---- Extension manual loader trampoline functions
XRAPI_ATTR XrResult XRAPI_CALL xrCreateDebugUtilsMessengerEXT(XrInstance instance,
const XrDebugUtilsMessengerCreateInfoEXT *createInfo,
XrDebugUtilsMessengerEXT *messenger) XRLOADER_ABI_TRY {
LoaderLogger::LogVerboseMessage("xrCreateDebugUtilsMessengerEXT", "Entering loader trampoline");
LoaderInstance *loader_instance = g_instance_map.Get(instance);
if (loader_instance == nullptr) {
LoaderLogger::LogValidationErrorMessage("VUID-xrCreateDebugUtilsMessengerEXT-instance-parameter",
"xrCreateDebugUtilsMessengerEXT", "invalid instance");
return XR_ERROR_HANDLE_INVALID;
}
if (!loader_instance->ExtensionIsEnabled(XR_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
std::string error_str = "The ";
error_str += XR_EXT_DEBUG_UTILS_EXTENSION_NAME;
error_str += " extension has not been enabled prior to calling xrCreateDebugUtilsMessengerEXT";
LoaderLogger::LogValidationErrorMessage("VUID-xrCreateDebugUtilsMessengerEXT-extension-notenabled",
"xrCreateDebugUtilsMessengerEXT", error_str);
return XR_ERROR_FUNCTION_UNSUPPORTED;
}
const std::unique_ptr<XrGeneratedDispatchTable> &dispatch_table = loader_instance->DispatchTable();
XrResult result = XR_SUCCESS;
result = dispatch_table->CreateDebugUtilsMessengerEXT(instance, createInfo, messenger);
if (XR_SUCCESS == result && nullptr != messenger) {
result = g_debugutilsmessengerext_map.Insert(*messenger, *loader_instance);
if (XR_FAILED(result)) {
LoaderLogger::LogErrorMessage("xrCreateDebugUtilsMessengerEXT",
"Failed inserting new messenger into map: may be null or not unique");
return result;
}
}
LoaderLogger::LogVerboseMessage("xrCreateDebugUtilsMessengerEXT", "Completed loader trampoline");
return result;
}
XRLOADER_ABI_CATCH_BAD_ALLOC_OOM XRLOADER_ABI_CATCH_FALLBACK
XRAPI_ATTR XrResult XRAPI_CALL
xrDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT messenger) XRLOADER_ABI_TRY {
// TODO: get instance from messenger in loader
// Also, is the loader really doing all this every call?
LoaderLogger::LogVerboseMessage("xrDestroyDebugUtilsMessengerEXT", "Entering loader trampoline");
if (XR_NULL_HANDLE == messenger) {
return XR_SUCCESS;
}
LoaderInstance *loader_instance = g_debugutilsmessengerext_map.Get(messenger);
if (loader_instance == nullptr) {
LoaderLogger::LogValidationErrorMessage("VUID-xrDestroyDebugUtilsMessengerEXT-messenger-parameter",
"xrDestroyDebugUtilsMessengerEXT", "invalid messenger");
return XR_ERROR_HANDLE_INVALID;
}
if (!loader_instance->ExtensionIsEnabled(XR_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
std::string error_str = "The ";
error_str += XR_EXT_DEBUG_UTILS_EXTENSION_NAME;
error_str += " extension has not been enabled prior to calling xrDestroyDebugUtilsMessengerEXT";
LoaderLogger::LogValidationErrorMessage("VUID-xrDestroyDebugUtilsMessengerEXT-extension-notenabled",
"xrDestroyDebugUtilsMessengerEXT", error_str);
return XR_ERROR_FUNCTION_UNSUPPORTED;
}
const std::unique_ptr<XrGeneratedDispatchTable> &dispatch_table = loader_instance->DispatchTable();
XrResult result = dispatch_table->DestroyDebugUtilsMessengerEXT(messenger);
LoaderLogger::LogVerboseMessage("xrDestroyDebugUtilsMessengerEXT", "Completed loader trampoline");
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
// ---- Extension manual loader terminator functions
XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateDebugUtilsMessengerEXT(XrInstance instance,
const XrDebugUtilsMessengerCreateInfoEXT *createInfo,
XrDebugUtilsMessengerEXT *messenger) XRLOADER_ABI_TRY {
LoaderLogger::LogVerboseMessage("xrCreateDebugUtilsMessengerEXT", "Entering loader terminator");
if (nullptr == messenger) {
LoaderLogger::LogValidationErrorMessage("VUID-xrCreateDebugUtilsMessengerEXT-messenger-parameter",
"xrCreateDebugUtilsMessengerEXT", "invalid messenger pointer");
return XR_ERROR_VALIDATION_FAILURE;
}
const XrGeneratedDispatchTable *dispatch_table = RuntimeInterface::GetDispatchTable(instance);
XrResult result = XR_SUCCESS;
// This extension is supported entirely by the loader which means the runtime may or may not support it.
if (nullptr != dispatch_table->CreateDebugUtilsMessengerEXT) {
result = dispatch_table->CreateDebugUtilsMessengerEXT(instance, createInfo, messenger);
} else {
// Just allocate a character so we have a unique value
char *temp_mess_ptr = new char;
*messenger = reinterpret_cast<XrDebugUtilsMessengerEXT>(temp_mess_ptr);
}
if (XR_SUCCESS == result) {
LoaderLogger::GetInstance().AddLogRecorder(MakeDebugUtilsLoaderLogRecorder(createInfo, *messenger));
RuntimeInterface::GetRuntime().TrackDebugMessenger(instance, *messenger);
}
LoaderLogger::LogVerboseMessage("xrCreateDebugUtilsMessengerEXT", "Completed loader terminator");
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT messenger) XRLOADER_ABI_TRY {
LoaderLogger::LogVerboseMessage("xrDestroyDebugUtilsMessengerEXT", "Entering loader terminator");
const XrGeneratedDispatchTable *dispatch_table = RuntimeInterface::GetDebugUtilsMessengerDispatchTable(messenger);
XrResult result = XR_SUCCESS;
LoaderLogger::GetInstance().RemoveLogRecorder(MakeHandleGeneric(messenger));
RuntimeInterface::GetRuntime().ForgetDebugMessenger(messenger);
// This extension is supported entirely by the loader which means the runtime may or may not support it.
if (nullptr != dispatch_table->DestroyDebugUtilsMessengerEXT) {
result = dispatch_table->DestroyDebugUtilsMessengerEXT(messenger);
} else {
// Delete the character we would've created
delete (reinterpret_cast<char *>(MakeHandleGeneric(messenger)));
}
LoaderLogger::LogVerboseMessage("xrDestroyDebugUtilsMessengerEXT", "Completed loader terminator");
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermSubmitDebugUtilsMessageEXT(
XrInstance instance, XrDebugUtilsMessageSeverityFlagsEXT messageSeverity, XrDebugUtilsMessageTypeFlagsEXT messageTypes,
const XrDebugUtilsMessengerCallbackDataEXT *callbackData) XRLOADER_ABI_TRY {
LoaderLogger::LogVerboseMessage("xrSubmitDebugUtilsMessageEXT", "Entering loader terminator");
const XrGeneratedDispatchTable *dispatch_table = RuntimeInterface::GetDispatchTable(instance);
XrResult result = XR_SUCCESS;
if (nullptr != dispatch_table->SubmitDebugUtilsMessageEXT) {
result = dispatch_table->SubmitDebugUtilsMessageEXT(instance, messageSeverity, messageTypes, callbackData);
} else {
// Only log the message from the loader if the runtime doesn't support this extension. If we did,
// then the user would receive multiple instances of the same message.
LoaderLogger::GetInstance().LogDebugUtilsMessage(messageSeverity, messageTypes, callbackData);
}
LoaderLogger::LogVerboseMessage("xrSubmitDebugUtilsMessageEXT", "Completed loader terminator");
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
XRAPI_ATTR XrResult XRAPI_CALL
LoaderXrTermSetDebugUtilsObjectNameEXT(XrInstance instance, const XrDebugUtilsObjectNameInfoEXT *nameInfo) XRLOADER_ABI_TRY {
LoaderLogger::LogVerboseMessage("xrSetDebugUtilsObjectNameEXT", "Entering loader terminator");
const XrGeneratedDispatchTable *dispatch_table = RuntimeInterface::GetDispatchTable(instance);
XrResult result = XR_SUCCESS;
if (nullptr != dispatch_table->SetDebugUtilsObjectNameEXT) {
result = dispatch_table->SetDebugUtilsObjectNameEXT(instance, nameInfo);
}
LoaderLogger::GetInstance().AddObjectName(nameInfo->objectHandle, nameInfo->objectType, nameInfo->objectName);
LoaderLogger::LogVerboseMessage("xrSetDebugUtilsObjectNameEXT", "Completed loader terminator");
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
XRAPI_ATTR XrResult XRAPI_CALL xrSessionBeginDebugUtilsLabelRegionEXT(XrSession session,
const XrDebugUtilsLabelEXT *labelInfo) XRLOADER_ABI_TRY {
LoaderInstance *loader_instance = g_session_map.Get(session);
if (nullptr == loader_instance) {
LoaderLogger::LogValidationErrorMessage("VUID-xrSessionBeginDebugUtilsLabelRegionEXT-session-parameter",
"xrSessionBeginDebugUtilsLabelRegionEXT", "session is not a valid XrSession",
{XrLoaderLogObjectInfo{session, XR_OBJECT_TYPE_SESSION}});
return XR_ERROR_HANDLE_INVALID;
}
if (!loader_instance->ExtensionIsEnabled(XR_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
LoaderLogger::LogValidationErrorMessage("TBD", "xrSessionBeginDebugUtilsLabelRegionEXT",
"Extension entrypoint called without enabling appropriate extension",
{XrLoaderLogObjectInfo{session, XR_OBJECT_TYPE_SESSION}});
return XR_ERROR_FUNCTION_UNSUPPORTED;
}
if (nullptr == labelInfo) {
LoaderLogger::LogValidationErrorMessage("VUID-xrSessionBeginDebugUtilsLabelRegionEXT-labelInfo-parameter",
"xrSessionBeginDebugUtilsLabelRegionEXT", "labelInfo must be non-NULL",
{XrLoaderLogObjectInfo{session, XR_OBJECT_TYPE_SESSION}});
return XR_ERROR_VALIDATION_FAILURE;
}
LoaderLogger::GetInstance().BeginLabelRegion(session, labelInfo);
const std::unique_ptr<XrGeneratedDispatchTable> &dispatch_table = loader_instance->DispatchTable();
if (nullptr != dispatch_table->SessionBeginDebugUtilsLabelRegionEXT) {
return dispatch_table->SessionBeginDebugUtilsLabelRegionEXT(session, labelInfo);
}
return XR_SUCCESS;
}
XRLOADER_ABI_CATCH_FALLBACK
XRAPI_ATTR XrResult XRAPI_CALL xrSessionEndDebugUtilsLabelRegionEXT(XrSession session) XRLOADER_ABI_TRY {
LoaderInstance *loader_instance = g_session_map.Get(session);
if (nullptr == loader_instance) {
LoaderLogger::LogValidationErrorMessage("VUID-xrSessionEndDebugUtilsLabelRegionEXT-session-parameter",
"xrSessionEndDebugUtilsLabelRegionEXT", "session is not a valid XrSession",
{XrLoaderLogObjectInfo{session, XR_OBJECT_TYPE_SESSION}});
return XR_ERROR_HANDLE_INVALID;
}
if (!loader_instance->ExtensionIsEnabled(XR_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
return XR_ERROR_FUNCTION_UNSUPPORTED;
}
LoaderLogger::GetInstance().EndLabelRegion(session);
const std::unique_ptr<XrGeneratedDispatchTable> &dispatch_table = loader_instance->DispatchTable();
if (nullptr != dispatch_table->SessionBeginDebugUtilsLabelRegionEXT) {
return dispatch_table->SessionEndDebugUtilsLabelRegionEXT(session);
}
return XR_SUCCESS;
}
XRLOADER_ABI_CATCH_FALLBACK
XRAPI_ATTR XrResult XRAPI_CALL xrSessionInsertDebugUtilsLabelEXT(XrSession session,
const XrDebugUtilsLabelEXT *labelInfo) XRLOADER_ABI_TRY {
LoaderInstance *loader_instance = g_session_map.Get(session);
if (nullptr == loader_instance) {
LoaderLogger::LogValidationErrorMessage("VUID-xrSessionInsertDebugUtilsLabelEXT-session-parameter",
"xrSessionInsertDebugUtilsLabelEXT", "session is not a valid XrSession",
{XrLoaderLogObjectInfo{session, XR_OBJECT_TYPE_SESSION}});
return XR_ERROR_HANDLE_INVALID;
}
if (!loader_instance->ExtensionIsEnabled(XR_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
LoaderLogger::LogValidationErrorMessage("TBD", "xrSessionInsertDebugUtilsLabelEXT",
"Extension entrypoint called without enabling appropriate extension",
{XrLoaderLogObjectInfo{session, XR_OBJECT_TYPE_SESSION}});
return XR_ERROR_FUNCTION_UNSUPPORTED;
}
if (nullptr == labelInfo) {
LoaderLogger::LogValidationErrorMessage("VUID-xrSessionInsertDebugUtilsLabelEXT-labelInfo-parameter",
"xrSessionInsertDebugUtilsLabelEXT", "labelInfo must be non-NULL",
{XrLoaderLogObjectInfo{session, XR_OBJECT_TYPE_SESSION}});
return XR_ERROR_VALIDATION_FAILURE;
}
LoaderLogger::GetInstance().InsertLabel(session, labelInfo);
const std::unique_ptr<XrGeneratedDispatchTable> &dispatch_table = loader_instance->DispatchTable();
if (nullptr != dispatch_table->SessionInsertDebugUtilsLabelEXT) {
return dispatch_table->SessionInsertDebugUtilsLabelEXT(session, labelInfo);
}
return XR_SUCCESS;
}
XRLOADER_ABI_CATCH_FALLBACK
} // extern "C"

View File

@@ -0,0 +1,235 @@
// Copyright (c) 2017-2019 The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// 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.
//
// Author: Mark Young <marky@lunarg.com>
//
#ifdef XR_OS_WINDOWS
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "loader_instance.hpp"
#include "api_layer_interface.hpp"
#include "hex_and_handles.h"
#include "loader_interfaces.h"
#include "loader_logger.hpp"
#include "runtime_interface.hpp"
#include "xr_generated_dispatch_table.h"
#include "xr_generated_loader.hpp"
#include <openxr/openxr.h>
#include <cstring>
#include <memory>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
// Extensions that are supported by the loader, but may not be supported
// the the runtime.
static const XrExtensionProperties g_debug_utils_props = {XR_TYPE_EXTENSION_PROPERTIES, nullptr, XR_EXT_DEBUG_UTILS_EXTENSION_NAME,
XR_EXT_debug_utils_SPEC_VERSION};
const std::vector<XrExtensionProperties> LoaderInstance::_loader_supported_extensions = {g_debug_utils_props};
// Factory method
XrResult LoaderInstance::CreateInstance(std::vector<std::unique_ptr<ApiLayerInterface>>&& api_layer_interfaces,
const XrInstanceCreateInfo* info, XrInstance* instance) {
XrResult last_error = XR_SUCCESS;
LoaderLogger::LogVerboseMessage("xrCreateInstance", "Entering LoaderInstance::CreateInstance");
// Topmost means "closest to the application"
PFN_xrCreateInstance topmost_ci_fp = LoaderXrTermCreateInstance;
PFN_xrCreateApiLayerInstance topmost_cali_fp = LoaderXrTermCreateApiLayerInstance;
// Create the loader instance
std::unique_ptr<LoaderInstance> loader_instance(new LoaderInstance(std::move(api_layer_interfaces)));
*instance = reinterpret_cast<XrInstance>(loader_instance.get());
// Only start the xrCreateApiLayerInstance stack if we have layers.
std::vector<std::unique_ptr<ApiLayerInterface>>& layer_interfaces = loader_instance->LayerInterfaces();
if (!layer_interfaces.empty()) {
// Initialize an array of ApiLayerNextInfo structs
auto* next_info_list = new XrApiLayerNextInfo[layer_interfaces.size()];
auto ni_index = static_cast<uint32_t>(layer_interfaces.size() - 1);
for (uint32_t i = 0; i <= ni_index; i++) {
next_info_list[i].structType = XR_LOADER_INTERFACE_STRUCT_API_LAYER_NEXT_INFO;
next_info_list[i].structVersion = XR_API_LAYER_NEXT_INFO_STRUCT_VERSION;
next_info_list[i].structSize = sizeof(XrApiLayerNextInfo);
}
// Go through all layers, and override the instance pointers with the layer version. However,
// go backwards through the layer list so we replace in reverse order so the layers can call their next function
// appropriately.
XrApiLayerNextInfo* prev_nextinfo = nullptr;
PFN_xrGetInstanceProcAddr prev_gipa_fp = LoaderXrTermGetInstanceProcAddr;
PFN_xrCreateApiLayerInstance prev_cali_fp = LoaderXrTermCreateApiLayerInstance;
for (auto layer_interface = layer_interfaces.rbegin(); layer_interface != layer_interfaces.rend(); ++layer_interface) {
// Collect current layer's function pointers
PFN_xrGetInstanceProcAddr cur_gipa_fp = (*layer_interface)->GetInstanceProcAddrFuncPointer();
PFN_xrCreateApiLayerInstance cur_cali_fp = (*layer_interface)->GetCreateApiLayerInstanceFuncPointer();
// Update topmosts
cur_gipa_fp(XR_NULL_HANDLE, "xrCreateInstance", reinterpret_cast<PFN_xrVoidFunction*>(&topmost_ci_fp));
topmost_cali_fp = cur_cali_fp;
// Fill in layer info and link previous (lower) layer fxn pointers
strncpy(next_info_list[ni_index].layerName, (*layer_interface)->LayerName().c_str(), XR_MAX_API_LAYER_NAME_SIZE - 1);
next_info_list[ni_index].layerName[XR_MAX_API_LAYER_NAME_SIZE - 1] = '\0';
next_info_list[ni_index].next = prev_nextinfo;
next_info_list[ni_index].nextGetInstanceProcAddr = prev_gipa_fp;
next_info_list[ni_index].nextCreateApiLayerInstance = prev_cali_fp;
// Update saved pointers for next iteration
prev_nextinfo = &next_info_list[ni_index];
prev_gipa_fp = cur_gipa_fp;
prev_cali_fp = cur_cali_fp;
ni_index--;
}
// Populate the ApiLayerCreateInfo struct and pass to topmost CreateApiLayerInstance()
XrApiLayerCreateInfo api_layer_ci = {};
api_layer_ci.structType = XR_LOADER_INTERFACE_STRUCT_API_LAYER_CREATE_INFO;
api_layer_ci.structVersion = XR_API_LAYER_CREATE_INFO_STRUCT_VERSION;
api_layer_ci.structSize = sizeof(XrApiLayerCreateInfo);
api_layer_ci.loaderInstance = reinterpret_cast<void*>(loader_instance.get());
api_layer_ci.settings_file_location[0] = '\0';
api_layer_ci.nextInfo = next_info_list;
last_error = topmost_cali_fp(info, &api_layer_ci, instance);
delete[] next_info_list;
} else {
last_error = topmost_ci_fp(info, instance);
}
if (XR_SUCCEEDED(last_error)) {
// Check the list of enabled extensions to make sure something supports them, and, if we do,
// add it to the list of enabled extensions
for (uint32_t ext = 0; ext < info->enabledExtensionCount; ++ext) {
bool found = false;
// First check the runtime
if (RuntimeInterface::GetRuntime().SupportsExtension(info->enabledExtensionNames[ext])) {
found = true;
}
// Next check the loader
if (!found) {
for (auto loader_extension : LoaderInstance::_loader_supported_extensions) {
if (strcmp(loader_extension.extensionName, info->enabledExtensionNames[ext]) == 0) {
found = true;
break;
}
}
}
// Finally, check the enabled layers
if (!found) {
for (auto& layer_interface : layer_interfaces) {
if (layer_interface->SupportsExtension(info->enabledExtensionNames[ext])) {
found = true;
break;
}
}
}
if (!found) {
std::string msg = "LoaderInstance::CreateInstance, no support found for requested extension: ";
msg += info->enabledExtensionNames[ext];
LoaderLogger::LogErrorMessage("xrCreateInstance", msg);
last_error = XR_ERROR_EXTENSION_NOT_PRESENT;
break;
}
loader_instance->AddEnabledExtension(info->enabledExtensionNames[ext]);
}
} else {
LoaderLogger::LogErrorMessage("xrCreateInstance", "LoaderInstance::CreateInstance chained CreateInstance call failed");
}
if (XR_SUCCEEDED(last_error)) {
// Create the top-level dispatch table for the instance. This will contain the function pointers to the
// first instantiation of every command, whether that is in a layer, or a runtime.
last_error = loader_instance->CreateDispatchTable(*instance);
if (XR_FAILED(last_error)) {
LoaderLogger::LogErrorMessage("xrCreateInstance",
"LoaderInstance::CreateInstance failed creating top-level dispatch table");
} else {
last_error = g_instance_map.Insert(*instance, *loader_instance);
if (XR_FAILED(last_error)) {
LoaderLogger::LogErrorMessage(
"xrCreateInstance",
"LoaderInstance::CreateInstance failed inserting new instance into map: may be null or not unique");
}
}
}
if (XR_SUCCEEDED(last_error)) {
std::ostringstream oss;
oss << "LoaderInstance::CreateInstance succeeded with ";
oss << loader_instance->LayerInterfaces().size();
oss << " layers enabled and runtime interface - created instance = ";
oss << HandleToHexString(*instance);
LoaderLogger::LogInfoMessage("xrCreateInstance", oss.str());
// Make the unique_ptr no longer delete this.
// Don't need to save the return value because we already set *instance
(void)loader_instance.release();
}
// Always clear the input lists. Either we use them or we don't.
api_layer_interfaces.clear();
return last_error;
}
LoaderInstance::LoaderInstance(std::vector<std::unique_ptr<ApiLayerInterface>>&& api_layer_interfaces)
: _unique_id(0xDECAFBAD),
_api_version(XR_CURRENT_API_VERSION),
_api_layer_interfaces(std::move(api_layer_interfaces)),
_dispatch_valid(false),
_messenger(XR_NULL_HANDLE) {}
LoaderInstance::~LoaderInstance() {
std::ostringstream oss;
oss << "Destroying LoaderInstance = ";
oss << PointerToHexString(this);
LoaderLogger::LogInfoMessage("xrDestroyInstance", oss.str());
}
XrResult LoaderInstance::CreateDispatchTable(XrInstance instance) {
XrResult res = XR_SUCCESS;
// Create the top-level dispatch table. First, we want to start with a dispatch table generated
// using the commands from the runtime, with the exception of commands that we need a terminator
// for. The loaderGenInitInstanceDispatchTable utility function handles that automatically for us.
std::unique_ptr<XrGeneratedDispatchTable> new_instance_dispatch_table(new XrGeneratedDispatchTable());
LoaderGenInitInstanceDispatchTable(_runtime_instance, new_instance_dispatch_table);
// Go through all layers, and override the instance pointers with the layer version. However,
// go backwards through the layer list so we replace in reverse order so the layers can call their next function
// appropriately.
if (!_api_layer_interfaces.empty()) {
(*_api_layer_interfaces.begin())->GenUpdateInstanceDispatchTable(instance, new_instance_dispatch_table);
}
// Set the top-level instance dispatch table to the top-most commands now that we've figured them out.
_dispatch_table = std::move(new_instance_dispatch_table);
_dispatch_valid = true;
return res;
}
bool LoaderInstance::ExtensionIsEnabled(const std::string& extension) {
for (std::string& cur_enabled : _enabled_extensions) {
if (cur_enabled == extension) {
return true;
}
}
return false;
}

View File

@@ -0,0 +1,155 @@
// Copyright (c) 2017-2019 The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// 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.
//
// Author: Mark Young <marky@lunarg.com>
//
#pragma once
#include "extra_algorithms.h"
#include <openxr/openxr.h>
#include <cmath>
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
#include <vector>
class LoaderInstance;
class ApiLayerInterface;
struct XrGeneratedDispatchTable;
typedef std::unique_lock<std::mutex> UniqueLock;
template <typename HandleType>
class HandleLoaderMap {
public:
using handle_t = HandleType;
using map_t = std::unordered_map<HandleType, LoaderInstance*>;
using value_t = typename map_t::value_type;
/// Lookup a handle.
/// Returns nullptr if not found.
LoaderInstance* Get(HandleType handle);
/// Insert an info for the supplied handle.
/// Returns XR_ERROR_RUNTIME_FAILURE if it's null.
/// Does not error if already there, because the loader is not currently very good at cleaning up handles.
XrResult Insert(HandleType handle, LoaderInstance& loader);
/// Remove the info associated with the supplied handle.
/// Returns XR_ERROR_RUNTIME_FAILURE if it's null or not there.
XrResult Erase(HandleType handle);
/// Removes handles associated with a loader instance.
void RemoveHandlesForLoader(LoaderInstance& loader);
protected:
map_t instance_map_;
std::mutex mutex_;
};
class LoaderInstance {
public:
// Factory method
static XrResult CreateInstance(std::vector<std::unique_ptr<ApiLayerInterface>>&& layer_interfaces,
const XrInstanceCreateInfo* info, XrInstance* instance);
LoaderInstance(std::vector<std::unique_ptr<ApiLayerInterface>>&& api_layer_interfaces);
virtual ~LoaderInstance();
bool IsValid() { return _unique_id == 0xDECAFBAD; }
XrVersion ApiVersion() { return _api_version; }
XrResult CreateDispatchTable(XrInstance instance);
void SetRuntimeInstance(XrInstance instance) { _runtime_instance = instance; }
const std::unique_ptr<XrGeneratedDispatchTable>& DispatchTable() { return _dispatch_table; }
std::vector<std::unique_ptr<ApiLayerInterface>>& LayerInterfaces() { return _api_layer_interfaces; }
void AddEnabledExtension(const std::string& extension) { return _enabled_extensions.push_back(extension); }
bool ExtensionIsEnabled(const std::string& extension);
static const std::vector<XrExtensionProperties>& LoaderSpecificExtensions() { return _loader_supported_extensions; }
XrDebugUtilsMessengerEXT DefaultDebugUtilsMessenger() { return _messenger; }
void SetDefaultDebugUtilsMessenger(XrDebugUtilsMessengerEXT messenger) { _messenger = messenger; }
private:
uint32_t _unique_id; // 0xDECAFBAD - for debugging
XrVersion _api_version;
std::vector<std::unique_ptr<ApiLayerInterface>> _api_layer_interfaces;
XrInstance _runtime_instance;
bool _dispatch_valid;
std::unique_ptr<XrGeneratedDispatchTable> _dispatch_table;
static const std::vector<XrExtensionProperties> _loader_supported_extensions;
std::vector<std::string> _enabled_extensions;
// Internal debug messenger created during xrCreateInstance
XrDebugUtilsMessengerEXT _messenger;
};
template <typename HandleType>
inline LoaderInstance* HandleLoaderMap<HandleType>::Get(HandleType handle) {
if (handle == XR_NULL_HANDLE) {
return nullptr;
}
// Try to find the handle in the appropriate map
UniqueLock lock(mutex_);
auto entry_returned = instance_map_.find(handle);
if (entry_returned == instance_map_.end()) {
return nullptr;
}
return entry_returned->second;
}
template <typename HandleType>
inline XrResult HandleLoaderMap<HandleType>::Insert(HandleType handle, LoaderInstance& loader) {
if (handle == XR_NULL_HANDLE) {
// Internal error in loader or runtime.
return XR_ERROR_RUNTIME_FAILURE;
}
UniqueLock lock(mutex_);
//! @todo This check is currently disabled, because the loader is not good at cleaning up handles when their parent handles are
//! destroyed.
#if 0
auto entry_returned = instance_map_.find(handle);
if (entry_returned != instance_map_.end()) {
// Internal error in loader or runtime.
return XR_ERROR_RUNTIME_FAILURE;
}
#endif
instance_map_[handle] = &loader;
return XR_SUCCESS;
}
template <typename HandleType>
inline XrResult HandleLoaderMap<HandleType>::Erase(HandleType handle) {
if (handle == XR_NULL_HANDLE) {
// Internal error in loader or runtime.
return XR_ERROR_RUNTIME_FAILURE;
}
UniqueLock lock(mutex_);
auto entry_returned = instance_map_.find(handle);
if (entry_returned == instance_map_.end()) {
// Internal error in loader or runtime.
return XR_ERROR_RUNTIME_FAILURE;
}
instance_map_.erase(handle);
return XR_SUCCESS;
}
template <typename HandleType>
inline void HandleLoaderMap<HandleType>::RemoveHandlesForLoader(LoaderInstance& loader) {
UniqueLock lock(mutex_);
auto search_value = &loader;
map_erase_if(instance_map_, [=](value_t const& data) { return data.second && data.second == search_value; });
}

View File

@@ -0,0 +1,405 @@
// Copyright (c) 2017-2019 The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// 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.
//
// Author: Mark Young <marky@lunarg.com>
//
#include "loader_logger.hpp"
#include "extra_algorithms.h"
#include "hex_and_handles.h"
#include "loader_logger_recorders.hpp"
#include "platform_utils.hpp"
#include <openxr/openxr.h>
#include <algorithm>
#include <iterator>
#include <memory>
#include <mutex>
#include <sstream>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
std::unique_ptr<LoaderLogger> LoaderLogger::_instance;
std::once_flag LoaderLogger::_once_flag;
std::string XrLoaderLogObjectInfo::ToString() const {
std::ostringstream oss;
oss << Uint64ToHexString(handle);
if (!name.empty()) {
oss << " (" << name << ")";
}
return oss.str();
}
bool LoaderLogRecorder::LogDebugUtilsMessage(XrDebugUtilsMessageSeverityFlagsEXT /*message_severity*/,
XrDebugUtilsMessageTypeFlagsEXT /*message_type*/,
const XrDebugUtilsMessengerCallbackDataEXT* /*callback_data*/) {
return false;
}
void ObjectInfoCollection::AddObjectName(uint64_t object_handle, XrObjectType object_type, const std::string& object_name) {
// If name is empty, we should erase it
if (object_name.empty()) {
vector_remove_if_and_erase(_object_info, [=](XrLoaderLogObjectInfo const& info) { return info.handle == object_handle; });
return;
}
// Otherwise, add it or update the name
XrLoaderLogObjectInfo new_obj = {object_handle, object_type};
// If it already exists, update the name
auto lookup_info = LookUpStoredObjectInfo(new_obj);
if (lookup_info != nullptr) {
lookup_info->name = object_name;
return;
}
// It doesn't exist, so add a new info block
new_obj.name = object_name;
_object_info.push_back(new_obj);
}
XrLoaderLogObjectInfo const* ObjectInfoCollection::LookUpStoredObjectInfo(XrLoaderLogObjectInfo const& info) const {
auto e = _object_info.end();
auto it = std::find_if(_object_info.begin(), e, [&](XrLoaderLogObjectInfo const& stored) { return Equivalent(stored, info); });
if (it != e) {
return &(*it);
}
return nullptr;
}
XrLoaderLogObjectInfo* ObjectInfoCollection::LookUpStoredObjectInfo(XrLoaderLogObjectInfo const& info) {
auto e = _object_info.end();
auto it = std::find_if(_object_info.begin(), e, [&](XrLoaderLogObjectInfo const& stored) { return Equivalent(stored, info); });
if (it != e) {
return &(*it);
}
return nullptr;
}
bool ObjectInfoCollection::LookUpObjectName(XrDebugUtilsObjectNameInfoEXT& info) const {
auto info_lookup = LookUpStoredObjectInfo(info.objectHandle, info.objectType);
if (info_lookup != nullptr) {
info.objectName = info_lookup->name.c_str();
return true;
}
return false;
}
bool ObjectInfoCollection::LookUpObjectName(XrLoaderLogObjectInfo& info) const {
auto info_lookup = LookUpStoredObjectInfo(info);
if (info_lookup != nullptr) {
info.name = info_lookup->name;
return true;
}
return false;
}
// Utility functions for converting to/from XR_EXT_debug_utils values
XrLoaderLogMessageSeverityFlags DebugUtilsSeveritiesToLoaderLogMessageSeverities(
XrDebugUtilsMessageSeverityFlagsEXT utils_severities) {
XrLoaderLogMessageSeverityFlags log_severities = 0UL;
if ((utils_severities & XR_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) != 0u) {
log_severities |= XR_LOADER_LOG_MESSAGE_SEVERITY_VERBOSE_BIT;
}
if ((utils_severities & XR_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) != 0u) {
log_severities |= XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT;
}
if ((utils_severities & XR_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) != 0u) {
log_severities |= XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT;
}
if ((utils_severities & XR_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) != 0u) {
log_severities |= XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT;
}
return log_severities;
}
XrDebugUtilsMessageSeverityFlagsEXT LoaderLogMessageSeveritiesToDebugUtilsMessageSeverities(
XrLoaderLogMessageSeverityFlags log_severities) {
XrDebugUtilsMessageSeverityFlagsEXT utils_severities = 0UL;
if ((log_severities & XR_LOADER_LOG_MESSAGE_SEVERITY_VERBOSE_BIT) != 0u) {
utils_severities |= XR_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
}
if ((log_severities & XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT) != 0u) {
utils_severities |= XR_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
}
if ((log_severities & XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT) != 0u) {
utils_severities |= XR_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
}
if ((log_severities & XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT) != 0u) {
utils_severities |= XR_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
}
return utils_severities;
}
XrLoaderLogMessageTypeFlagBits DebugUtilsMessageTypesToLoaderLogMessageTypes(XrDebugUtilsMessageTypeFlagsEXT utils_types) {
XrLoaderLogMessageTypeFlagBits log_types = 0UL;
if ((utils_types & XR_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) != 0u) {
log_types |= XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT;
}
if ((utils_types & XR_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT) != 0u) {
log_types |= XR_LOADER_LOG_MESSAGE_TYPE_SPECIFICATION_BIT;
}
if ((utils_types & XR_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) != 0u) {
log_types |= XR_LOADER_LOG_MESSAGE_TYPE_PERFORMANCE_BIT;
}
return log_types;
}
XrDebugUtilsMessageTypeFlagsEXT LoaderLogMessageTypesToDebugUtilsMessageTypes(XrLoaderLogMessageTypeFlagBits log_types) {
XrDebugUtilsMessageTypeFlagsEXT utils_types = 0UL;
if ((log_types & XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT) != 0u) {
utils_types |= XR_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT;
}
if ((log_types & XR_LOADER_LOG_MESSAGE_TYPE_SPECIFICATION_BIT) != 0u) {
utils_types |= XR_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
}
if ((log_types & XR_LOADER_LOG_MESSAGE_TYPE_PERFORMANCE_BIT) != 0u) {
utils_types |= XR_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
}
return utils_types;
}
LoaderLogger::LoaderLogger() {
// Add an error logger by default so that we at least get errors out to std::cerr.
AddLogRecorder(MakeStdErrLoaderLogRecorder(nullptr));
// If the environment variable to enable loader debugging is set, then enable the
// appropriate logging out to std::cout.
char* loader_debug = PlatformUtilsGetSecureEnv("XR_LOADER_DEBUG");
if (nullptr != loader_debug) {
std::string debug_string = loader_debug;
PlatformUtilsFreeEnv(loader_debug);
XrLoaderLogMessageSeverityFlags debug_flags = {};
if (debug_string == "error") {
debug_flags = XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT;
} else if (debug_string == "warn") {
debug_flags = XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT | XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT;
} else if (debug_string == "info") {
debug_flags = XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT | XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT |
XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT;
} else if (debug_string == "all" || debug_string == "verbose") {
debug_flags = XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT | XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT |
XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT | XR_LOADER_LOG_MESSAGE_SEVERITY_VERBOSE_BIT;
}
AddLogRecorder(MakeStdOutLoaderLogRecorder(nullptr, debug_flags));
}
}
void LoaderLogger::AddLogRecorder(std::unique_ptr<LoaderLogRecorder>&& recorder) { _recorders.push_back(std::move(recorder)); }
void LoaderLogger::RemoveLogRecorder(uint64_t unique_id) {
vector_remove_if_and_erase(
_recorders, [=](std::unique_ptr<LoaderLogRecorder> const& recorder) { return recorder->UniqueId() == unique_id; });
}
bool LoaderLogger::LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity, XrLoaderLogMessageTypeFlags message_type,
const std::string& message_id, const std::string& command_name, const std::string& message,
const std::vector<XrLoaderLogObjectInfo>& objects) {
XrLoaderLogMessengerCallbackData callback_data = {};
callback_data.message_id = message_id.c_str();
callback_data.command_name = command_name.c_str();
callback_data.message = message.c_str();
std::vector<XrDebugUtilsLabelEXT> labels;
// Copy objects into a vector we can modify and will keep around past the callback.
std::vector<XrLoaderLogObjectInfo> object_vector = objects;
for (auto& obj : object_vector) {
// Check for any names that have been associated with the objects and set them up here
_object_names.LookUpObjectName(obj);
// If this is a session, see if there are any labels associated with it for us to add
// to the callback content.
if (XR_OBJECT_TYPE_SESSION == obj.type) {
LookUpSessionLabels(obj.GetTypedHandle<XrSession>(), labels);
}
}
callback_data.objects = object_vector.empty() ? nullptr : object_vector.data();
callback_data.object_count = static_cast<uint8_t>(object_vector.size());
callback_data.session_labels = labels.empty() ? nullptr : labels.data();
callback_data.session_labels_count = static_cast<uint8_t>(labels.size());
bool exit_app = false;
for (std::unique_ptr<LoaderLogRecorder>& recorder : _recorders) {
if ((recorder->MessageSeverities() & message_severity) == message_severity &&
(recorder->MessageTypes() & message_type) == message_type) {
exit_app |= recorder->LogMessage(message_severity, message_type, &callback_data);
}
}
return exit_app;
}
void LoaderLogger::LookUpSessionLabels(XrSession session, std::vector<XrDebugUtilsLabelEXT>& labels) const {
auto session_label_iterator = _session_labels.find(session);
if (session_label_iterator != _session_labels.end()) {
auto& internalSessionLabels = *session_label_iterator->second;
// Copy the debug utils labels in reverse order in the the labels vector.
std::transform(internalSessionLabels.rbegin(), internalSessionLabels.rend(), std::back_inserter(labels),
[](InternalSessionLabelPtr const& label) { return label->debug_utils_label; });
}
}
// Extension-specific logging functions
bool LoaderLogger::LogDebugUtilsMessage(XrDebugUtilsMessageSeverityFlagsEXT message_severity,
XrDebugUtilsMessageTypeFlagsEXT message_type,
const XrDebugUtilsMessengerCallbackDataEXT* callback_data) {
bool exit_app = false;
XrLoaderLogMessageSeverityFlags log_message_severity = DebugUtilsSeveritiesToLoaderLogMessageSeverities(message_severity);
XrLoaderLogMessageTypeFlags log_message_type = DebugUtilsMessageTypesToLoaderLogMessageTypes(message_type);
bool obj_name_found = false;
std::vector<XrDebugUtilsLabelEXT> labels;
if (!_object_names.Empty() && callback_data->objectCount > 0) {
for (uint32_t obj = 0; obj < callback_data->objectCount; ++obj) {
auto& current_obj = callback_data->objects[obj];
auto stored_info = _object_names.LookUpStoredObjectInfo(current_obj.objectHandle, current_obj.objectType);
if (stored_info != nullptr) {
obj_name_found = true;
}
// If this is a session, see if there are any labels associated with it for us to add
// to the callback content.
if (XR_OBJECT_TYPE_SESSION == current_obj.objectType) {
XrSession session = TreatIntegerAsHandle<XrSession>(current_obj.objectHandle);
LookUpSessionLabels(session, labels);
}
}
}
// Use unmodified ones by default.
XrDebugUtilsMessengerCallbackDataEXT const* callback_data_to_use = callback_data;
XrDebugUtilsMessengerCallbackDataEXT new_callback_data = *callback_data;
std::vector<XrDebugUtilsObjectNameInfoEXT> new_objects;
// If a name or a label has been found, we should update it in a new version of the callback
if (obj_name_found || !labels.empty()) {
// Copy objects
new_objects =
std::vector<XrDebugUtilsObjectNameInfoEXT>(callback_data->objects, callback_data->objects + callback_data->objectCount);
for (auto& obj : new_objects) {
// Check for any names that have been associated with the objects and set them up here
_object_names.LookUpObjectName(obj);
}
new_callback_data.objects = new_objects.data();
new_callback_data.sessionLabelCount = static_cast<uint32_t>(labels.size());
new_callback_data.sessionLabels = labels.empty() ? nullptr : labels.data();
callback_data_to_use = &new_callback_data;
}
// Loop through the recorders
for (std::unique_ptr<LoaderLogRecorder>& recorder : _recorders) {
// Only send the message if it's a debug utils recorder and of the type the recorder cares about.
if (recorder->Type() != XR_LOADER_LOG_DEBUG_UTILS ||
(recorder->MessageSeverities() & log_message_severity) != log_message_severity ||
(recorder->MessageTypes() & log_message_type) != log_message_type) {
continue;
}
exit_app |= recorder->LogDebugUtilsMessage(message_severity, message_type, callback_data_to_use);
}
return exit_app;
}
void LoaderLogger::AddObjectName(uint64_t object_handle, XrObjectType object_type, const std::string& object_name) {
_object_names.AddObjectName(object_handle, object_type, object_name);
}
// We always want to remove the old individual label before we do anything else.
// So, do that in it's own method
void LoaderLogger::RemoveIndividualLabel(InternalSessionLabelList& label_vec) {
if (!label_vec.empty() && label_vec.back()->is_individual_label) {
label_vec.pop_back();
}
}
InternalSessionLabelList* LoaderLogger::GetSessionLabelList(XrSession session) {
auto session_label_iterator = _session_labels.find(session);
if (session_label_iterator == _session_labels.end()) {
return nullptr;
}
return session_label_iterator->second.get();
}
InternalSessionLabelList& LoaderLogger::GetOrCreateSessionLabelList(XrSession session) {
InternalSessionLabelList* vec_ptr = GetSessionLabelList(session);
if (vec_ptr == nullptr) {
std::unique_ptr<InternalSessionLabelList> vec(new InternalSessionLabelList);
vec_ptr = vec.get();
_session_labels[session] = std::move(vec);
}
return *vec_ptr;
}
void LoaderLogger::BeginLabelRegion(XrSession session, const XrDebugUtilsLabelEXT* label_info) {
auto& vec = GetOrCreateSessionLabelList(session);
// Individual labels do not stay around in the transition into a new label region
RemoveIndividualLabel(vec);
// Start the new label region
InternalSessionLabelPtr new_session_label(new InternalSessionLabel);
new_session_label->label_name = label_info->labelName;
new_session_label->debug_utils_label = *label_info;
new_session_label->debug_utils_label.labelName = new_session_label->label_name.c_str();
new_session_label->is_individual_label = false;
vec.emplace_back(std::move(new_session_label));
}
void LoaderLogger::EndLabelRegion(XrSession session) {
InternalSessionLabelList* vec_ptr = GetSessionLabelList(session);
if (vec_ptr == nullptr) {
return;
}
// Individual labels do not stay around in the transition out of label region
RemoveIndividualLabel(*vec_ptr);
// Remove the last label region
if (!vec_ptr->empty()) {
vec_ptr->pop_back();
}
}
void LoaderLogger::InsertLabel(XrSession session, const XrDebugUtilsLabelEXT* label_info) {
//! @todo only difference from BeginLabelRegion is value of is_individual_label
auto& vec = GetOrCreateSessionLabelList(session);
// Remove any individual layer that might already be there
RemoveIndividualLabel(vec);
// Insert a new individual label
InternalSessionLabelPtr new_session_label(new InternalSessionLabel);
new_session_label->label_name = label_info->labelName;
new_session_label->debug_utils_label = *label_info;
new_session_label->debug_utils_label.labelName = new_session_label->label_name.c_str();
new_session_label->is_individual_label = true;
vec.emplace_back(std::move(new_session_label));
}
// Called during xrDestroySession. We need to delete all session related labels.
void LoaderLogger::DeleteSessionLabels(XrSession session) {
InternalSessionLabelList* vec_ptr = GetSessionLabelList(session);
if (vec_ptr == nullptr) {
return;
}
_session_labels.erase(session);
}

View File

@@ -0,0 +1,289 @@
// Copyright (c) 2017-2019 The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// 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.
//
// Author: Mark Young <marky@lunarg.com>
//
#pragma once
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
#include <vector>
#include <openxr/openxr.h>
#include "hex_and_handles.h"
// Use internal versions of flags similar to XR_EXT_debug_utils so that
// we're not tightly coupled to that extension. This way, if the extension
// changes or gets replaced, we can be flexible in the loader.
#define XR_LOADER_LOG_MESSAGE_SEVERITY_VERBOSE_BIT 0x00000001
#define XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT 0x00000010
#define XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT 0x00000100
#define XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT 0x00001000
#define XR_LOADER_LOG_MESSAGE_SEVERITY_DEFAULT_BITS 0x00000000
typedef XrFlags64 XrLoaderLogMessageSeverityFlagBits;
typedef XrFlags64 XrLoaderLogMessageSeverityFlags;
#define XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT 0x00000001
#define XR_LOADER_LOG_MESSAGE_TYPE_SPECIFICATION_BIT 0x00000002
#define XR_LOADER_LOG_MESSAGE_TYPE_PERFORMANCE_BIT 0x00000004
#define XR_LOADER_LOG_MESSAGE_TYPE_DEFAULT_BITS 0xffffffff
typedef XrFlags64 XrLoaderLogMessageTypeFlagBits;
typedef XrFlags64 XrLoaderLogMessageTypeFlags;
struct XrLoaderLogObjectInfo {
//! Type-erased handle value
uint64_t handle;
//! Kind of object this handle refers to
XrObjectType type;
//! To be assigned by the application - not part of this object's identity
std::string name;
/// Un-erase the type of the handle and get it properly typed again.
///
/// Note: Does not check the type before doing it!
template <typename HandleType>
HandleType& GetTypedHandle() {
return TreatIntegerAsHandle<HandleType&>(handle);
}
//! @overload
template <typename HandleType>
HandleType const& GetTypedHandle() const {
return TreatIntegerAsHandle<HandleType&>(handle);
}
XrLoaderLogObjectInfo() = default;
//! Create from a typed handle and object type
template <typename T>
XrLoaderLogObjectInfo(T h, XrObjectType t) : handle(MakeHandleGeneric(h)), type(t) {}
//! Create from an untyped handle value (integer) and object type
XrLoaderLogObjectInfo(uint64_t h, XrObjectType t) : handle(h), type(t) {}
std::string ToString() const;
};
//! True if the two object infos have the same handle value and handle type
static inline bool Equivalent(XrLoaderLogObjectInfo const& a, XrLoaderLogObjectInfo const& b) {
return a.handle == b.handle && a.type == b.type;
}
//! @overload
static inline bool Equivalent(XrDebugUtilsObjectNameInfoEXT const& a, XrLoaderLogObjectInfo const& b) {
return a.objectHandle == b.handle && a.objectType == b.type;
}
//! @overload
static inline bool Equivalent(XrLoaderLogObjectInfo const& a, XrDebugUtilsObjectNameInfoEXT const& b) { return Equivalent(b, a); }
struct XrLoaderLogMessengerCallbackData {
const char* message_id;
const char* command_name;
const char* message;
uint8_t object_count;
XrLoaderLogObjectInfo* objects;
uint8_t session_labels_count;
XrDebugUtilsLabelEXT* session_labels;
};
enum XrLoaderLogType {
XR_LOADER_LOG_UNKNOWN = 0,
XR_LOADER_LOG_STDERR,
XR_LOADER_LOG_STDOUT,
XR_LOADER_LOG_DEBUG_UTILS,
};
class LoaderLogRecorder {
public:
LoaderLogRecorder(XrLoaderLogType type, void* user_data, XrLoaderLogMessageSeverityFlags message_severities,
XrLoaderLogMessageTypeFlags message_types) {
_active = false;
_user_data = user_data;
_type = type;
_unique_id = 0;
_message_severities = message_severities;
_message_types = message_types;
}
virtual ~LoaderLogRecorder() = default;
XrLoaderLogType Type() { return _type; }
uint64_t UniqueId() { return _unique_id; }
XrLoaderLogMessageSeverityFlags MessageSeverities() { return _message_severities; }
XrLoaderLogMessageTypeFlags MessageTypes() { return _message_types; }
virtual void Start() { _active = true; }
bool IsPaused() { return _active; }
virtual void Pause() { _active = false; }
virtual void Resume() { _active = true; }
virtual void Stop() { _active = false; }
virtual bool LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity, XrLoaderLogMessageTypeFlags message_type,
const XrLoaderLogMessengerCallbackData* callback_data) = 0;
// Extension-specific logging functions - defaults to do nothing.
virtual bool LogDebugUtilsMessage(XrDebugUtilsMessageSeverityFlagsEXT message_severity,
XrDebugUtilsMessageTypeFlagsEXT message_type,
const XrDebugUtilsMessengerCallbackDataEXT* callback_data);
protected:
bool _active;
XrLoaderLogType _type;
uint64_t _unique_id;
void* _user_data;
XrLoaderLogMessageSeverityFlags _message_severities;
XrLoaderLogMessageTypeFlags _message_types;
};
class ObjectInfoCollection {
public:
//! Called from LoaderXrTermSetDebugUtilsObjectNameEXT - an empty name means remove
void AddObjectName(uint64_t object_handle, XrObjectType object_type, const std::string& object_name);
//! Find the stored object info, if any, matching handle and type.
//! Return nullptr if not found.
XrLoaderLogObjectInfo const* LookUpStoredObjectInfo(XrLoaderLogObjectInfo const& info) const;
//! Find the stored object info, if any, matching handle and type.
//! Return nullptr if not found.
XrLoaderLogObjectInfo* LookUpStoredObjectInfo(XrLoaderLogObjectInfo const& info);
//! Find the stored object info, if any.
//! Return nullptr if not found.
XrLoaderLogObjectInfo const* LookUpStoredObjectInfo(uint64_t handle, XrObjectType type) const {
return LookUpStoredObjectInfo({handle, type});
}
//! Find the object name, if any, and update debug utils info accordingly.
//! Return true if found and updated.
bool LookUpObjectName(XrDebugUtilsObjectNameInfoEXT& info) const;
//! Find the object name, if any, and update logging info accordingly.
//! Return true if found and updated.
bool LookUpObjectName(XrLoaderLogObjectInfo& info) const;
//! Is the collection empty?
bool Empty() const { return _object_info.empty(); }
private:
// Object names that have been set for given objects
std::vector<XrLoaderLogObjectInfo> _object_info;
};
struct InternalSessionLabel {
XrDebugUtilsLabelEXT debug_utils_label;
std::string label_name;
bool is_individual_label;
};
using InternalSessionLabelPtr = std::unique_ptr<InternalSessionLabel>;
using InternalSessionLabelList = std::vector<InternalSessionLabelPtr>;
class LoaderLogger {
public:
static LoaderLogger& GetInstance() {
std::call_once(LoaderLogger::_once_flag, []() { _instance.reset(new LoaderLogger); });
return *(_instance.get());
}
void AddLogRecorder(std::unique_ptr<LoaderLogRecorder>&& recorder);
void RemoveLogRecorder(uint64_t unique_id);
//! Called from LoaderXrTermSetDebugUtilsObjectNameEXT - an empty name means remove
void AddObjectName(uint64_t object_handle, XrObjectType object_type, const std::string& object_name);
void BeginLabelRegion(XrSession session, const XrDebugUtilsLabelEXT* label_info);
void EndLabelRegion(XrSession session);
void InsertLabel(XrSession session, const XrDebugUtilsLabelEXT* label_info);
void DeleteSessionLabels(XrSession session);
bool LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity, XrLoaderLogMessageTypeFlags message_type,
const std::string& message_id, const std::string& command_name, const std::string& message,
const std::vector<XrLoaderLogObjectInfo>& objects = {});
static bool LogErrorMessage(const std::string& command_name, const std::string& message,
const std::vector<XrLoaderLogObjectInfo>& objects = {}) {
return GetInstance().LogMessage(XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT, XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT,
"OpenXR-Loader", command_name, message, objects);
}
static bool LogWarningMessage(const std::string& command_name, const std::string& message,
const std::vector<XrLoaderLogObjectInfo>& objects = {}) {
return GetInstance().LogMessage(XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT, XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT,
"OpenXR-Loader", command_name, message, objects);
}
static bool LogInfoMessage(const std::string& command_name, const std::string& message,
const std::vector<XrLoaderLogObjectInfo>& objects = {}) {
return GetInstance().LogMessage(XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT, XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT,
"OpenXR-Loader", command_name, message, objects);
}
static bool LogVerboseMessage(const std::string& command_name, const std::string& message,
const std::vector<XrLoaderLogObjectInfo>& objects = {}) {
return GetInstance().LogMessage(XR_LOADER_LOG_MESSAGE_SEVERITY_VERBOSE_BIT, XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT,
"OpenXR-Loader", command_name, message, objects);
}
static bool LogValidationErrorMessage(const std::string& vuid, const std::string& command_name, const std::string& message,
const std::vector<XrLoaderLogObjectInfo>& objects = {}) {
return GetInstance().LogMessage(XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT, XR_LOADER_LOG_MESSAGE_TYPE_SPECIFICATION_BIT,
vuid, command_name, message, objects);
}
static bool LogValidationWarningMessage(const std::string& vuid, const std::string& command_name, const std::string& message,
const std::vector<XrLoaderLogObjectInfo>& objects = {}) {
return GetInstance().LogMessage(XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT, XR_LOADER_LOG_MESSAGE_TYPE_SPECIFICATION_BIT,
vuid, command_name, message, objects);
}
// Extension-specific logging functions
bool LogDebugUtilsMessage(XrDebugUtilsMessageSeverityFlagsEXT message_severity, XrDebugUtilsMessageTypeFlagsEXT message_type,
const XrDebugUtilsMessengerCallbackDataEXT* callback_data);
private:
LoaderLogger();
LoaderLogger(const LoaderLogger&) = delete;
LoaderLogger& operator=(const LoaderLogger&) = delete;
/// Retrieve labels for the given session, if any, and push them in reverse order on the vector.
void LookUpSessionLabels(XrSession session, std::vector<XrDebugUtilsLabelEXT>& labels) const;
void RemoveIndividualLabel(InternalSessionLabelList& label_vec);
InternalSessionLabelList* GetSessionLabelList(XrSession session);
InternalSessionLabelList& GetOrCreateSessionLabelList(XrSession session);
static std::unique_ptr<LoaderLogger> _instance;
static std::once_flag _once_flag;
// List of available recorder objects
std::vector<std::unique_ptr<LoaderLogRecorder>> _recorders;
ObjectInfoCollection _object_names;
// Session labels
std::unordered_map<XrSession, std::unique_ptr<InternalSessionLabelList>> _session_labels;
};
// Utility functions for converting to/from XR_EXT_debug_utils values
XrLoaderLogMessageSeverityFlags DebugUtilsSeveritiesToLoaderLogMessageSeverities(
XrDebugUtilsMessageSeverityFlagsEXT utils_severities);
XrDebugUtilsMessageSeverityFlagsEXT LoaderLogMessageSeveritiesToDebugUtilsMessageSeverities(
XrLoaderLogMessageSeverityFlags log_severities);
XrLoaderLogMessageTypeFlagBits DebugUtilsMessageTypesToLoaderLogMessageTypes(XrDebugUtilsMessageTypeFlagsEXT utils_types);
XrDebugUtilsMessageTypeFlagsEXT LoaderLogMessageTypesToDebugUtilsMessageTypes(XrLoaderLogMessageTypeFlagBits log_types);

View File

@@ -0,0 +1,188 @@
// Copyright (c) 2017-2019 The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// 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.
//
// Author: Mark Young <marky@lunarg.com>
//
#include "loader_logger_recorders.hpp"
#include "hex_and_handles.h"
#include "loader_logger.hpp"
#include <openxr/openxr.h>
#include <memory>
#include <string>
#include <vector>
#include <iostream>
// Anonymous namespace to keep these types private
namespace {
// With std::cerr: Standard Error logger, always on for now
// With std::cout: Standard Output logger used with XR_LOADER_DEBUG
class OstreamLoaderLogRecorder : public LoaderLogRecorder {
public:
OstreamLoaderLogRecorder(std::ostream& os, void* user_data, XrLoaderLogMessageSeverityFlags flags);
bool LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity, XrLoaderLogMessageTypeFlags message_type,
const XrLoaderLogMessengerCallbackData* callback_data) override;
private:
std::ostream& os_;
};
// Debug Utils logger used with XR_EXT_debug_utils
class DebugUtilsLogRecorder : public LoaderLogRecorder {
public:
DebugUtilsLogRecorder(const XrDebugUtilsMessengerCreateInfoEXT* create_info, XrDebugUtilsMessengerEXT debug_messenger);
bool LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity, XrLoaderLogMessageTypeFlags message_type,
const XrLoaderLogMessengerCallbackData* callback_data) override;
// Extension-specific logging functions
bool LogDebugUtilsMessage(XrDebugUtilsMessageSeverityFlagsEXT message_severity, XrDebugUtilsMessageTypeFlagsEXT message_type,
const XrDebugUtilsMessengerCallbackDataEXT* callback_data) override;
private:
PFN_xrDebugUtilsMessengerCallbackEXT _user_callback;
};
// Unified stdout/stderr logger
OstreamLoaderLogRecorder::OstreamLoaderLogRecorder(std::ostream& os, void* user_data, XrLoaderLogMessageSeverityFlags flags)
: LoaderLogRecorder(XR_LOADER_LOG_STDOUT, user_data, flags, 0xFFFFFFFFUL), os_(os) {
// Automatically start
Start();
}
bool OstreamLoaderLogRecorder::LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity,
XrLoaderLogMessageTypeFlags message_type,
const XrLoaderLogMessengerCallbackData* callback_data) {
if (_active && 0 != (_message_severities & message_severity) && 0 != (_message_types & message_type)) {
if (XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT > message_severity) {
os_ << "Verbose [";
} else if (XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT > message_severity) {
os_ << "Info [";
} else if (XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT > message_severity) {
os_ << "Warning [";
} else {
os_ << "Error [";
}
switch (message_type) {
case XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT:
os_ << "GENERAL";
break;
case XR_LOADER_LOG_MESSAGE_TYPE_SPECIFICATION_BIT:
os_ << "SPEC";
break;
case XR_LOADER_LOG_MESSAGE_TYPE_PERFORMANCE_BIT:
os_ << "PERF";
break;
default:
os_ << "UNKNOWN";
break;
}
os_ << " | " << callback_data->command_name << " | " << callback_data->message_id << "] : " << callback_data->message
<< std::endl;
for (uint32_t obj = 0; obj < callback_data->object_count; ++obj) {
os_ << " Object[" << obj << "] = " << callback_data->objects[obj].ToString();
os_ << std::endl;
}
for (uint32_t label = 0; label < callback_data->session_labels_count; ++label) {
os_ << " SessionLabel[" << std::to_string(label) << "] = " << callback_data->session_labels[label].labelName;
os_ << std::endl;
}
}
// Return of "true" means that we should exit the application after the logged message. We
// don't want to do that for our internal logging. Only let a user return true.
return false;
}
// A logger associated with the XR_EXT_debug_utils extension
DebugUtilsLogRecorder::DebugUtilsLogRecorder(const XrDebugUtilsMessengerCreateInfoEXT* create_info,
XrDebugUtilsMessengerEXT debug_messenger)
: LoaderLogRecorder(XR_LOADER_LOG_DEBUG_UTILS, static_cast<void*>(create_info->userData),
DebugUtilsSeveritiesToLoaderLogMessageSeverities(create_info->messageSeverities),
DebugUtilsMessageTypesToLoaderLogMessageTypes(create_info->messageTypes)),
_user_callback(create_info->userCallback) {
// Use the debug messenger value to uniquely identify this logger with that messenger
_unique_id = MakeHandleGeneric(debug_messenger);
Start();
}
// Extension-specific logging functions
bool DebugUtilsLogRecorder::LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity,
XrLoaderLogMessageTypeFlags message_type,
const XrLoaderLogMessengerCallbackData* callback_data) {
bool should_exit = false;
if (_active && 0 != (_message_severities & message_severity) && 0 != (_message_types & message_type)) {
XrDebugUtilsMessageSeverityFlagsEXT utils_severity = DebugUtilsSeveritiesToLoaderLogMessageSeverities(message_severity);
XrDebugUtilsMessageTypeFlagsEXT utils_type = LoaderLogMessageTypesToDebugUtilsMessageTypes(message_type);
// Convert the loader log message into the debug utils log message information
XrDebugUtilsMessengerCallbackDataEXT utils_callback_data = {};
utils_callback_data.type = XR_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT;
utils_callback_data.messageId = callback_data->message_id;
utils_callback_data.functionName = callback_data->command_name;
utils_callback_data.message = callback_data->message;
std::vector<XrDebugUtilsObjectNameInfoEXT> utils_objects;
utils_objects.resize(callback_data->object_count);
for (uint8_t object = 0; object < callback_data->object_count; ++object) {
utils_objects[object].type = XR_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
utils_objects[object].next = nullptr;
utils_objects[object].objectHandle = callback_data->objects[object].handle;
utils_objects[object].objectType = callback_data->objects[object].type;
utils_objects[object].objectName = callback_data->objects[object].name.c_str();
}
utils_callback_data.objectCount = callback_data->object_count;
utils_callback_data.objects = utils_objects.data();
utils_callback_data.sessionLabelCount = callback_data->session_labels_count;
utils_callback_data.sessionLabels = callback_data->session_labels;
// Call the user callback with the appropriate info
// Return of "true" means that we should exit the application after the logged message.
should_exit = (_user_callback(utils_severity, utils_type, &utils_callback_data, _user_data) == XR_TRUE);
}
return should_exit;
}
bool DebugUtilsLogRecorder::LogDebugUtilsMessage(XrDebugUtilsMessageSeverityFlagsEXT message_severity,
XrDebugUtilsMessageTypeFlagsEXT message_type,
const XrDebugUtilsMessengerCallbackDataEXT* callback_data) {
// Call the user callback with the appropriate info
// Return of "true" means that we should exit the application after the logged message.
return (_user_callback(message_severity, message_type, callback_data, _user_data) == XR_TRUE);
}
} // namespace
std::unique_ptr<LoaderLogRecorder> MakeStdOutLoaderLogRecorder(void* user_data, XrLoaderLogMessageSeverityFlags flags) {
std::unique_ptr<LoaderLogRecorder> recorder(new OstreamLoaderLogRecorder(std::cout, user_data, flags));
return recorder;
}
std::unique_ptr<LoaderLogRecorder> MakeStdErrLoaderLogRecorder(void* user_data) {
std::unique_ptr<LoaderLogRecorder> recorder(
new OstreamLoaderLogRecorder(std::cerr, user_data, XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT));
return recorder;
}
std::unique_ptr<LoaderLogRecorder> MakeDebugUtilsLoaderLogRecorder(const XrDebugUtilsMessengerCreateInfoEXT* create_info,
XrDebugUtilsMessengerEXT debug_messenger) {
std::unique_ptr<LoaderLogRecorder> recorder(new DebugUtilsLogRecorder(create_info, debug_messenger));
return recorder;
}

View File

@@ -0,0 +1,40 @@
// Copyright (c) 2017-2019 The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// 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.
//
// Author: Ryan Pavlik <ryan.pavlik@collabora.com>
//
#pragma once
#include "loader_logger.hpp"
#include <openxr/openxr.h>
#include <memory>
//! Standard Error logger, always on for now
std::unique_ptr<LoaderLogRecorder> MakeStdErrLoaderLogRecorder(void* user_data);
//! Standard Output logger used with XR_LOADER_DEBUG
std::unique_ptr<LoaderLogRecorder> MakeStdOutLoaderLogRecorder(void* user_data, XrLoaderLogMessageSeverityFlags flags);
// Debug Utils logger used with XR_EXT_debug_utils
std::unique_ptr<LoaderLogRecorder> MakeDebugUtilsLoaderLogRecorder(const XrDebugUtilsMessengerCreateInfoEXT* create_info,
XrDebugUtilsMessengerEXT debug_messenger);
// TODO: Add other Derived classes:
// - FileLoaderLogRecorder - During/after xrCreateInstance
// - PipeLoaderLogRecorder? - During/after xrCreateInstance

View File

@@ -0,0 +1,215 @@
// Copyright (c) 2017-2019 The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// 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.
//
// Author: Mark Young <marky@lunarg.com>
// Author: Dave Houlton <daveh@lunarg.com>
//
#pragma once
#include <cassert>
#include <sstream>
#include <string>
#include "xr_dependencies.h"
#include "platform_utils.hpp"
#if defined(__GNUC__) && __GNUC__ >= 4
#define LOADER_EXPORT __attribute__((visibility("default")))
#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)
#define LOADER_EXPORT __attribute__((visibility("default")))
#else
#define LOADER_EXPORT
#endif
// Environment variables
#if defined(XR_OS_LINUX) || defined(XR_OS_APPLE)
#include <sys/types.h>
#include <sys/stat.h>
#include <dlfcn.h>
#include <unistd.h>
#include <stdlib.h>
#include <dirent.h>
#ifndef PATH_MAX
#define PATH_MAX 1024
#endif
#define PATH_SEPARATOR ':'
#define DIRECTORY_SYMBOL '/'
// Dynamic Loading of libraries:
typedef void *LoaderPlatformLibraryHandle;
static inline LoaderPlatformLibraryHandle LoaderPlatformLibraryOpen(const std::string &path) {
// When loading the library, we use RTLD_LAZY so that not all symbols have to be
// resolved at this time (which improves performance). Note that if not all symbols
// can be resolved, this could cause crashes later.
// For experimenting/debugging: Define the LD_BIND_NOW environment variable to force all
// symbols to be resolved here.
return dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
}
static inline const char *LoaderPlatformLibraryOpenError(const std::string &path) {
(void)path;
return dlerror();
}
static inline void LoaderPlatformLibraryClose(LoaderPlatformLibraryHandle library) { dlclose(library); }
static inline void *LoaderPlatformLibraryGetProcAddr(LoaderPlatformLibraryHandle library, const std::string &name) {
assert(library);
assert(!name.empty());
return dlsym(library, name.c_str());
}
static inline const char *LoaderPlatformLibraryGetProcAddrError(const std::string &name) {
(void)name;
return dlerror();
}
#elif defined(XR_OS_WINDOWS)
#define PATH_SEPARATOR ';'
#define DIRECTORY_SYMBOL '\\'
// Workaround for MS VS 2010/2013 missing snprintf and vsnprintf
#if defined(_MSC_VER) && _MSC_VER < 1900
#include <stdint.h>
static inline int32_t xr_vsnprintf(char *result_buffer, size_t buffer_size, const char *print_format, va_list varying_list) {
int32_t copy_count = -1;
if (buffer_size != 0) {
copy_count = _vsnprintf_s(result_buffer, buffer_size, _TRUNCATE, print_format, varying_list);
}
if (copy_count == -1) {
copy_count = _vscprintf(print_format, varying_list);
}
return copy_count;
}
static inline int32_t xr_snprintf(char *result_buffer, size_t buffer_size, const char *print_format, ...) {
va_list varying_list;
va_start(varying_list, print_format);
int32_t copy_count = xr_vsnprintf(result_buffer, buffer_size, print_format, varying_list);
va_end(varying_list);
return copy_count;
}
#define snprintf xr_snprintf
#define vsnprintf xr_vsnprintf
#endif
static std::string DescribeError(uint32_t code, bool prefixErrorCode = true) {
std::string str;
if (prefixErrorCode) {
char prefixBuffer[64];
snprintf(prefixBuffer, sizeof(prefixBuffer), "0x%llx (%lld): ", (uint64_t)code, (int64_t)code);
str = prefixBuffer;
}
// Could use FORMAT_MESSAGE_FROM_HMODULE to specify an error source.
WCHAR errorBufferW[1024]{};
const DWORD errorBufferWCapacity = sizeof(errorBufferW) / sizeof(errorBufferW[0]);
const DWORD length = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, (DWORD)code,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), errorBufferW, errorBufferWCapacity, nullptr);
if (length) { // If errorBufferW contains what we are looking for...
str += wide_to_utf8(errorBufferW);
} else {
str = "(unknown)";
}
return str;
}
// Dynamic Loading:
typedef HMODULE LoaderPlatformLibraryHandle;
static LoaderPlatformLibraryHandle LoaderPlatformLibraryOpen(const std::string &path) {
const std::wstring pathW = utf8_to_wide(path);
// Try loading the library the original way first.
LoaderPlatformLibraryHandle handle = LoadLibraryW(pathW.c_str());
if (handle == NULL && GetLastError() == ERROR_MOD_NOT_FOUND) {
const DWORD dwAttrib = GetFileAttributesW(pathW.c_str());
const bool fileExists = (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
if (fileExists) {
// If that failed, then try loading it with broader search folders.
handle = LoadLibraryExW(pathW.c_str(), NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR);
}
}
return handle;
}
static std::string LoaderPlatformLibraryOpenError(const std::string &path) {
std::stringstream ss;
const DWORD dwLastError = GetLastError();
const std::string strError = DescribeError(dwLastError);
ss << "Failed to open dynamic library " << path << " with error " << dwLastError << ": " << strError;
return ss.str();
}
static void LoaderPlatformLibraryClose(LoaderPlatformLibraryHandle library) { FreeLibrary(library); }
static void *LoaderPlatformLibraryGetProcAddr(LoaderPlatformLibraryHandle library, const std::string &name) {
assert(library);
assert(name.size() > 0);
return GetProcAddress(library, name.c_str());
}
static std::string LoaderPlatformLibraryGetProcAddrAddrError(const std::string &name) {
std::stringstream ss;
ss << "Failed to find function " << name << " in dynamic library";
return ss.str();
}
#else // Not Linux or Windows
#define PATH_SEPARATOR ':'
#define DIRECTORY_SYMBOL '/'
static inline LoaderPlatformLibraryHandle LoaderPlatformLibraryOpen(const std::string &path) {
// Stub func
#error("Unknown platform, undefined dynamic library routines resulting");
(void)path;
}
static inline const char *LoaderPlatformLibraryOpenError(const std::string &path) {
// Stub func
(void)path;
}
static inline void LoaderPlatformLibraryClose(LoaderPlatformLibraryHandle library) {
// Stub func
(void)library;
}
static inline void *LoaderPlatformLibraryGetProcAddr(LoaderPlatformLibraryHandle library, const std::string &name) {
// Stub func
void(library);
void(name);
}
static inline const char *LoaderPlatformLibraryGetProcAddrError(const std::string &name) {
// Stub func
(void)name;
}
#endif

View File

@@ -0,0 +1,977 @@
// Copyright (c) 2017-2019 The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// 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.
//
// Author: Mark Young <marky@lunarg.com>
//
#ifdef XR_OS_WINDOWS
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "manifest_file.hpp"
#include "common_cmake_config.h"
#include "filesystem_utils.hpp"
#include "loader_platform.hpp"
#include "platform_utils.hpp"
#include "loader_logger.hpp"
#include <json/json.h>
#include <openxr/openxr.h>
#include <algorithm>
#include <cstring>
#include <fstream>
#include <memory>
#include <sstream>
#include <stdexcept>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
// OpenXR paths and registry key locations
#define OPENXR_RELATIVE_PATH "openxr/"
#define OPENXR_IMPLICIT_API_LAYER_RELATIVE_PATH "/api_layers/implicit.d"
#define OPENXR_EXPLICIT_API_LAYER_RELATIVE_PATH "/api_layers/explicit.d"
#ifdef XR_OS_WINDOWS
#define OPENXR_REGISTRY_LOCATION "SOFTWARE\\Khronos\\OpenXR\\"
#define OPENXR_IMPLICIT_API_LAYER_REGISTRY_LOCATION "\\ApiLayers\\Implicit"
#define OPENXR_EXPLICIT_API_LAYER_REGISTRY_LOCATION "\\ApiLayers\\Explicit"
#endif
// OpenXR Loader environment variables of interest
#define OPENXR_RUNTIME_JSON_ENV_VAR "XR_RUNTIME_JSON"
#define OPENXR_API_LAYER_PATH_ENV_VAR "XR_API_LAYER_PATH"
#ifndef XRLOADER_ENABLE_EXCEPTION_HANDLING
#if JSON_USE_EXCEPTIONS
#error \
"Loader is configured to not catch exceptions, but jsoncpp was built with exception-throwing enabled, which could violate the C ABI. One of those two things needs to change."
#endif // JSON_USE_EXCEPTIONS
#endif // !XRLOADER_ENABLE_EXCEPTION_HANDLING
// Utility functions for finding files in the appropriate paths
static inline bool StringEndsWith(const std::string &value, const std::string &ending) {
if (ending.size() > value.size()) {
return false;
}
return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
}
// If the file found is a manifest file name, add it to the out_files manifest list.
static void AddIfJson(const std::string &full_file, std::vector<std::string> &manifest_files) {
if (full_file.empty() || !StringEndsWith(full_file, ".json")) {
return;
}
manifest_files.push_back(full_file);
}
// Check the current path for any manifest files. If the provided search_path is a directory, look for
// all included JSON files in that directory. Otherwise, just check the provided search_path which should
// be a single filename.
static void CheckAllFilesInThePath(const std::string &search_path, bool is_directory_list,
std::vector<std::string> &manifest_files) {
if (FileSysUtilsPathExists(search_path)) {
std::string absolute_path;
if (!is_directory_list) {
// If the file exists, try to add it
if (FileSysUtilsIsRegularFile(search_path)) {
FileSysUtilsGetAbsolutePath(search_path, absolute_path);
AddIfJson(absolute_path, manifest_files);
}
} else {
std::vector<std::string> files;
if (FileSysUtilsFindFilesInPath(search_path, files)) {
for (std::string &cur_file : files) {
std::string relative_path;
FileSysUtilsCombinePaths(search_path, cur_file, relative_path);
if (!FileSysUtilsGetAbsolutePath(relative_path, absolute_path)) {
continue;
}
AddIfJson(absolute_path, manifest_files);
}
}
}
}
}
// Add all manifest files in the provided paths to the manifest_files list. If search_path
// is made up of directory listings (versus direct manifest file names) search each path for
// any manifest files.
static void AddFilesInPath(const std::string &search_path, bool is_directory_list, std::vector<std::string> &manifest_files) {
std::size_t last_found = 0;
std::size_t found = search_path.find_first_of(PATH_SEPARATOR);
std::string cur_search;
// Handle any path listings in the string (separated by the appropriate path separator)
while (found != std::string::npos) {
// substr takes a start index and length.
std::size_t length = found - last_found;
cur_search = search_path.substr(last_found, length);
CheckAllFilesInThePath(cur_search, is_directory_list, manifest_files);
// This works around issue if multiple path separator follow each other directly.
last_found = found;
while (found == last_found) {
last_found = found + 1;
found = search_path.find_first_of(PATH_SEPARATOR, last_found);
}
}
// If there's something remaining in the string, copy it over
if (last_found < search_path.size()) {
cur_search = search_path.substr(last_found);
CheckAllFilesInThePath(cur_search, is_directory_list, manifest_files);
}
}
// Copy all paths listed in the cur_path string into output_path and append the appropriate relative_path onto the end of each.
static void CopyIncludedPaths(bool is_directory_list, const std::string &cur_path, const std::string &relative_path,
std::string &output_path) {
if (!cur_path.empty()) {
std::size_t last_found = 0;
std::size_t found = cur_path.find_first_of(PATH_SEPARATOR);
// Handle any path listings in the string (separated by the appropriate path separator)
while (found != std::string::npos) {
std::size_t length = found - last_found;
output_path += cur_path.substr(last_found, length);
if (is_directory_list && (cur_path[found - 1] != '\\' && cur_path[found - 1] != '/')) {
output_path += DIRECTORY_SYMBOL;
}
output_path += relative_path;
output_path += PATH_SEPARATOR;
last_found = found;
found = cur_path.find_first_of(PATH_SEPARATOR, found + 1);
}
// If there's something remaining in the string, copy it over
size_t last_char = cur_path.size() - 1;
if (last_found != last_char) {
output_path += cur_path.substr(last_found);
if (is_directory_list && (cur_path[last_char] != '\\' && cur_path[last_char] != '/')) {
output_path += DIRECTORY_SYMBOL;
}
output_path += relative_path;
output_path += PATH_SEPARATOR;
}
}
}
// Look for data files in the provided paths, but first check the environment override to determine if we should use that instead.
static void ReadDataFilesInSearchPaths(ManifestFileType type, const std::string &override_env_var, const std::string &relative_path,
bool &override_active, std::vector<std::string> &manifest_files) {
bool is_directory_list = true;
bool is_runtime = (type == MANIFEST_TYPE_RUNTIME);
char *override_env = nullptr;
std::string override_path;
std::string search_path;
if (!override_env_var.empty()) {
#ifndef XR_OS_WINDOWS
if (geteuid() != getuid() || getegid() != getgid()) {
// Don't allow setuid apps to use the env var:
override_env = nullptr;
} else
#endif
{
override_env = PlatformUtilsGetSecureEnv(override_env_var.c_str());
if (nullptr != override_env) {
// The runtime override is actually a specific list of filenames, not directories
if (is_runtime) {
is_directory_list = false;
}
override_path = override_env;
}
}
}
if (nullptr != override_env && !override_path.empty()) {
CopyIncludedPaths(is_directory_list, override_path, "", search_path);
PlatformUtilsFreeEnv(override_env);
override_active = true;
} else {
override_active = false;
#ifndef XR_OS_WINDOWS
bool xdg_conf_dirs_alloc = true;
bool xdg_data_dirs_alloc = true;
const char home_additional[] = ".local/share/";
// Determine how much space is needed to generate the full search path
// for the current manifest files.
char *xdg_conf_dirs = PlatformUtilsGetSecureEnv("XDG_CONFIG_DIRS");
char *xdg_data_dirs = PlatformUtilsGetSecureEnv("XDG_DATA_DIRS");
char *xdg_data_home = PlatformUtilsGetSecureEnv("XDG_DATA_HOME");
char *home = PlatformUtilsGetSecureEnv("HOME");
if (nullptr == xdg_conf_dirs) {
xdg_conf_dirs_alloc = false;
}
if (nullptr == xdg_data_dirs) {
xdg_data_dirs_alloc = false;
}
if (nullptr == xdg_conf_dirs || xdg_conf_dirs[0] == '\0') {
CopyIncludedPaths(true, FALLBACK_CONFIG_DIRS, relative_path, search_path);
} else {
CopyIncludedPaths(true, xdg_conf_dirs, relative_path, search_path);
}
CopyIncludedPaths(true, SYSCONFDIR, relative_path, search_path);
#if defined(EXTRASYSCONFDIR)
CopyIncludedPaths(true, EXTRASYSCONFDIR, relative_path, search_path);
#endif
if (xdg_data_dirs == nullptr || xdg_data_dirs[0] == '\0') {
CopyIncludedPaths(true, FALLBACK_DATA_DIRS, relative_path, search_path);
} else {
CopyIncludedPaths(true, xdg_data_dirs, relative_path, search_path);
}
if (nullptr != xdg_data_home) {
CopyIncludedPaths(true, xdg_data_home, relative_path, search_path);
} else if (nullptr != home) {
std::string relative_home_path = home_additional;
relative_home_path += relative_path;
CopyIncludedPaths(true, home, relative_home_path, search_path);
}
if (xdg_conf_dirs_alloc) {
PlatformUtilsFreeEnv(xdg_conf_dirs);
}
if (xdg_data_dirs_alloc) {
PlatformUtilsFreeEnv(xdg_data_dirs);
}
if (nullptr != xdg_data_home) {
PlatformUtilsFreeEnv(xdg_data_home);
}
if (nullptr != home) {
PlatformUtilsFreeEnv(home);
}
#endif
}
// Now, parse the paths and add any manifest files found in them.
AddFilesInPath(search_path, is_directory_list, manifest_files);
}
#ifdef XR_OS_LINUX
// If ${name} has a nonempty value, return it; if both other arguments are supplied return
// ${fallback_env}/fallback_path; otherwise, return whichever of ${fallback_env} and fallback_path
// is supplied. If ${fallback_env} or ${fallback_env}/... would be returned but that environment
// variable is unset or empty, return the empty string.
static std::string GetXDGEnv(const char *name, const char *fallback_env, const char *fallback_path) {
char *path = PlatformUtilsGetSecureEnv(name);
std::string result;
if (path != nullptr) {
result = path;
PlatformUtilsFreeEnv(path);
if (!result.empty()) {
return result;
}
}
if (fallback_env != nullptr) {
char *path = PlatformUtilsGetSecureEnv(fallback_env);
if (path != nullptr) {
result = path;
PlatformUtilsFreeEnv(path);
}
if (result.empty()) {
return "";
}
if (fallback_path != nullptr) {
result += "/";
}
}
if (fallback_path != nullptr) {
result += fallback_path;
}
return result;
}
// Return the first instance of relative_path occurring in an XDG config dir according to standard
// precedence order.
static bool FindXDGConfigFile(const std::string &relative_path, std::string &out) {
out = GetXDGEnv("XDG_CONFIG_HOME", "HOME", ".config");
if (!out.empty()) {
out += "/";
out += relative_path;
if (FileSysUtilsPathExists(out)) {
return true;
}
}
std::istringstream iss(GetXDGEnv("XDG_CONFIG_DIRS", nullptr, FALLBACK_CONFIG_DIRS));
std::string path;
while (std::getline(iss, path, PATH_SEPARATOR)) {
if (path.empty()) {
continue;
}
out = path;
out += "/";
out += relative_path;
if (FileSysUtilsPathExists(out)) {
return true;
}
}
out = SYSCONFDIR;
out += "/";
out += relative_path;
if (FileSysUtilsPathExists(out)) {
return true;
}
#if defined(EXTRASYSCONFDIR)
out = EXTRASYSCONFDIR;
out += "/";
out += relative_path;
if (FileSysUtilsPathExists(out)) {
return true;
}
#endif
out.clear();
return false;
}
#endif
#ifdef XR_OS_WINDOWS
// Look for runtime data files in the provided paths, but first check the environment override to determine
// if we should use that instead.
static void ReadRuntimeDataFilesInRegistry(ManifestFileType type, const std::string &runtime_registry_location,
const std::string &default_runtime_value_name,
std::vector<std::string> &manifest_files) {
HKEY hkey;
DWORD access_flags;
wchar_t value_w[1024];
DWORD value_size_w = sizeof(value_w); // byte size of the buffer.
// Generate the full registry location for the registry information
std::string full_registry_location = OPENXR_REGISTRY_LOCATION;
full_registry_location += std::to_string(XR_VERSION_MAJOR(XR_CURRENT_API_VERSION));
full_registry_location += runtime_registry_location;
const std::wstring full_registry_location_w = utf8_to_wide(full_registry_location);
const std::wstring default_runtime_value_name_w = utf8_to_wide(default_runtime_value_name);
// Use 64 bit regkey for 64bit application, and use 32 bit regkey in WOW for 32bit application.
access_flags = KEY_QUERY_VALUE;
LONG open_value = RegOpenKeyExW(HKEY_LOCAL_MACHINE, full_registry_location_w.c_str(), 0, access_flags, &hkey);
if (ERROR_SUCCESS != open_value) {
std::string warning_message = "ReadLayerDataFilesInRegistry - failed to open registry key ";
warning_message += full_registry_location;
LoaderLogger::LogWarningMessage("", warning_message);
} else if (ERROR_SUCCESS != RegGetValueW(hkey, nullptr, default_runtime_value_name_w.c_str(),
RRF_RT_REG_SZ | REG_EXPAND_SZ | RRF_ZEROONFAILURE, NULL,
reinterpret_cast<LPBYTE>(&value_w), &value_size_w)) {
std::string warning_message = "ReadLayerDataFilesInRegistry - failed to read registry value ";
warning_message += default_runtime_value_name;
LoaderLogger::LogWarningMessage("", warning_message);
} else {
AddFilesInPath(wide_to_utf8(value_w), false, manifest_files);
}
}
// Look for layer data files in the provided paths, but first check the environment override to determine
// if we should use that instead.
static void ReadLayerDataFilesInRegistry(ManifestFileType type, const std::string &registry_location,
std::vector<std::string> &manifest_files) {
HKEY hive[2] = {HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER};
bool found[2] = {false, false};
HKEY hkey;
DWORD access_flags;
LONG rtn_value;
wchar_t name_w[1024]{};
DWORD value;
DWORD name_size = 1023;
DWORD value_size = sizeof(value);
for (uint8_t hive_index = 0; hive_index < 2; ++hive_index) {
DWORD key_index = 0;
std::string full_registry_location = OPENXR_REGISTRY_LOCATION;
full_registry_location += std::to_string(XR_VERSION_MAJOR(XR_CURRENT_API_VERSION));
full_registry_location += registry_location;
access_flags = KEY_QUERY_VALUE;
std::wstring full_registry_location_w = utf8_to_wide(full_registry_location);
LONG open_value = RegOpenKeyExW(hive[hive_index], full_registry_location_w.c_str(), 0, access_flags, &hkey);
if (ERROR_SUCCESS != open_value) {
if (hive_index == 1 && !found[0]) {
std::string warning_message = "ReadLayerDataFilesInRegistry - failed to read registry location ";
warning_message += registry_location;
warning_message += " in either HKEY_LOCAL_MACHINE or KHEY_CURRENT_USER";
LoaderLogger::LogWarningMessage("", warning_message);
}
continue;
}
found[hive_index] = true;
while (ERROR_SUCCESS ==
(rtn_value = RegEnumValueW(hkey, key_index++, name_w, &name_size, NULL, NULL, (LPBYTE)&value, &value_size))) {
if (value_size == sizeof(value) && value == 0) {
const std::string filename = wide_to_utf8(name_w);
AddFilesInPath(filename, false, manifest_files);
}
// Reset some items for the next loop
name_size = 1023;
}
}
}
#endif // XR_OS_WINDOWS
ManifestFile::ManifestFile(ManifestFileType type, const std::string &filename, const std::string &library_path)
: _filename(filename), _type(type), _library_path(library_path) {}
ManifestFile::~ManifestFile() = default;
bool ManifestFile::IsValidJson(const Json::Value &root_node, JsonVersion &version) {
if (root_node["file_format_version"].isNull() || !root_node["file_format_version"].isString()) {
LoaderLogger::LogErrorMessage("", "ManifestFile::IsValidJson - JSON file missing \"file_format_version\"");
return false;
}
std::string file_format = root_node["file_format_version"].asString();
sscanf(file_format.c_str(), "%d.%d.%d", &version.major, &version.minor, &version.patch);
// Only version 1.0.0 is defined currently. Eventually we may have more version, but
// some of the versions may only be valid for layers or runtimes specifically.
if (version.major != 1 || version.minor != 0 || version.patch != 0) {
std::string error_message = "ManifestFile::IsValidJson - JSON \"file_format_version\" ";
error_message += std::to_string(version.major);
error_message += ".";
error_message += std::to_string(version.minor);
error_message += ".";
error_message += std::to_string(version.patch);
error_message += " is not supported";
LoaderLogger::LogErrorMessage("", error_message);
return false;
}
return true;
}
static void GetExtensionProperties(const std::vector<ExtensionListing> &extensions, std::vector<XrExtensionProperties> &props) {
for (const auto &ext : extensions) {
auto it =
std::find_if(props.begin(), props.end(), [&](XrExtensionProperties &prop) { return prop.extensionName == ext.name; });
if (it != props.end()) {
it->extensionVersion = std::max(it->extensionVersion, ext.extension_version);
} else {
XrExtensionProperties prop = {};
prop.type = XR_TYPE_EXTENSION_PROPERTIES;
prop.next = nullptr;
strncpy(prop.extensionName, ext.name.c_str(), XR_MAX_EXTENSION_NAME_SIZE - 1);
prop.extensionName[XR_MAX_EXTENSION_NAME_SIZE - 1] = '\0';
prop.extensionVersion = ext.extension_version;
props.push_back(prop);
}
}
}
// Return any instance extensions found in the manifest files in the proper form for
// OpenXR (XrExtensionProperties).
void ManifestFile::GetInstanceExtensionProperties(std::vector<XrExtensionProperties> &props) {
GetExtensionProperties(_instance_extensions, props);
}
// Return any device extensions found in the manifest files in the proper form for
// OpenXR (XrExtensionProperties).
void ManifestFile::GetDeviceExtensionProperties(std::vector<XrExtensionProperties> &props) {
GetExtensionProperties(_device_extensions, props);
}
const std::string &ManifestFile::GetFunctionName(const std::string &func_name) {
if (!_functions_renamed.empty()) {
auto found = _functions_renamed.find(func_name);
if (found != _functions_renamed.end()) {
return found->second;
}
}
return func_name;
}
RuntimeManifestFile::RuntimeManifestFile(const std::string &filename, const std::string &library_path)
: ManifestFile(MANIFEST_TYPE_RUNTIME, filename, library_path) {}
RuntimeManifestFile::~RuntimeManifestFile() = default;
void RuntimeManifestFile::CreateIfValid(const std::string &filename,
std::vector<std::unique_ptr<RuntimeManifestFile>> &manifest_files) {
std::ifstream json_stream = std::ifstream(filename, std::ifstream::in);
if (!json_stream.is_open()) {
std::string error_message = "RuntimeManifestFile::createIfValid failed to open ";
error_message += filename;
error_message += ". Does it exist?";
LoaderLogger::LogErrorMessage("", error_message);
return;
}
Json::Reader reader;
Json::Value root_node = Json::nullValue;
Json::Value runtime_root_node = Json::nullValue;
JsonVersion file_version = {};
if (!reader.parse(json_stream, root_node, false) || root_node.isNull()) {
std::string error_message = "RuntimeManifestFile::CreateIfValid failed to parse ";
error_message += filename;
error_message += ". Is it a valid runtime manifest file? Error was:\n ";
error_message += reader.getFormattedErrorMessages();
LoaderLogger::LogErrorMessage("", error_message);
return;
}
if (!ManifestFile::IsValidJson(root_node, file_version)) {
std::string error_message = "RuntimeManifestFile::CreateIfValid isValidJson indicates ";
error_message += filename;
error_message += " is not a valid manifest file.";
LoaderLogger::LogErrorMessage("", error_message);
return;
}
runtime_root_node = root_node["runtime"];
// The Runtime manifest file needs the "runtime" root as well as sub-nodes for "api_version" and
// "library_path". If any of those aren't there, fail.
if (runtime_root_node.isNull() || runtime_root_node["library_path"].isNull() || !runtime_root_node["library_path"].isString()) {
std::string error_message = "RuntimeManifestFile::CreateIfValid ";
error_message += filename;
error_message += " is missing required fields. Verify all proper fields exist.";
LoaderLogger::LogErrorMessage("", error_message);
return;
}
std::string lib_path = runtime_root_node["library_path"].asString();
// If the library_path variable has no directory symbol, it's just a file name and should be accessible on the
// global library path.
if (lib_path.find('\\') != std::string::npos || lib_path.find('/') != std::string::npos) {
// If the library_path is an absolute path, just use that if it exists
if (FileSysUtilsIsAbsolutePath(lib_path)) {
if (!FileSysUtilsPathExists(lib_path)) {
std::string error_message = "RuntimeManifestFile::CreateIfValid ";
error_message += filename;
error_message += " library ";
error_message += lib_path;
error_message += " does not appear to exist";
LoaderLogger::LogErrorMessage("", error_message);
return;
}
} else {
// Otherwise, treat the library path as a relative path based on the JSON file.
std::string combined_path;
std::string file_parent;
if (!FileSysUtilsGetParentPath(filename, file_parent) ||
!FileSysUtilsCombinePaths(file_parent, lib_path, combined_path) || !FileSysUtilsPathExists(combined_path)) {
std::string error_message = "RuntimeManifestFile::CreateIfValid ";
error_message += filename;
error_message += " library ";
error_message += combined_path;
error_message += " does not appear to exist";
LoaderLogger::LogErrorMessage("", error_message);
return;
}
lib_path = combined_path;
}
}
// Add this runtime manifest file
manifest_files.emplace_back(new RuntimeManifestFile(filename, lib_path));
// Add any extensions to it after the fact.
Json::Value dev_exts = runtime_root_node["device_extensions"];
if (!dev_exts.isNull() && dev_exts.isArray()) {
for (Json::ValueIterator dev_ext_it = dev_exts.begin(); dev_ext_it != dev_exts.end(); ++dev_ext_it) {
Json::Value dev_ext = (*dev_ext_it);
Json::Value dev_ext_name = dev_ext["name"];
Json::Value dev_ext_version = dev_ext["extension_version"];
Json::Value dev_ext_entries = dev_ext["entrypoints"];
if (!dev_ext_name.isNull() && dev_ext_name.isString() && !dev_ext_version.isNull() && dev_ext_version.isUInt() &&
!dev_ext_entries.isNull() && dev_ext_entries.isArray()) {
ExtensionListing ext = {};
ext.name = dev_ext_name.asString();
ext.extension_version = dev_ext_version.asUInt();
for (Json::ValueIterator entry_it = dev_ext_entries.begin(); entry_it != dev_ext_entries.end(); ++entry_it) {
Json::Value entry = (*entry_it);
if (!entry.isNull() && entry.isString()) {
ext.entrypoints.push_back(entry.asString());
}
}
manifest_files.back()->_device_extensions.push_back(ext);
}
}
}
Json::Value inst_exts = runtime_root_node["instance_extensions"];
if (!inst_exts.isNull() && inst_exts.isArray()) {
for (Json::ValueIterator inst_ext_it = inst_exts.begin(); inst_ext_it != inst_exts.end(); ++inst_ext_it) {
Json::Value inst_ext = (*inst_ext_it);
Json::Value inst_ext_name = inst_ext["name"];
Json::Value inst_ext_version = inst_ext["extension_version"];
if (!inst_ext_name.isNull() && inst_ext_name.isString() && !inst_ext_version.isNull() && inst_ext_version.isUInt()) {
ExtensionListing ext = {};
ext.name = inst_ext_name.asString();
ext.extension_version = inst_ext_version.asUInt();
manifest_files.back()->_instance_extensions.push_back(ext);
}
}
}
Json::Value funcs_renamed = runtime_root_node["functions"];
if (!funcs_renamed.isNull() && !funcs_renamed.empty()) {
for (Json::ValueIterator func_it = funcs_renamed.begin(); func_it != funcs_renamed.end(); ++func_it) {
if (!(*func_it).isString()) {
std::string warning_message = "RuntimeManifestFile::CreateIfValid ";
warning_message += filename;
warning_message += " \"functions\" section contains non-string values.";
LoaderLogger::LogWarningMessage("", warning_message);
continue;
}
std::string original_name = func_it.key().asString();
std::string new_name = (*func_it).asString();
manifest_files.back()->_functions_renamed.insert(std::make_pair(original_name, new_name));
}
}
}
// Find all manifest files in the appropriate search paths/registries for the given type.
XrResult RuntimeManifestFile::FindManifestFiles(ManifestFileType type,
std::vector<std::unique_ptr<RuntimeManifestFile>> &manifest_files) {
XrResult result = XR_SUCCESS;
if (MANIFEST_TYPE_RUNTIME != type) {
LoaderLogger::LogErrorMessage("", "RuntimeManifestFile::FindManifestFiles - unknown manifest file requested");
return XR_ERROR_FILE_ACCESS_ERROR;
}
std::string filename;
char *override_path = PlatformUtilsGetSecureEnv(OPENXR_RUNTIME_JSON_ENV_VAR);
if (override_path != nullptr && *override_path != '\0') {
filename = override_path;
PlatformUtilsFreeEnv(override_path);
std::string info_message = "RuntimeManifestFile::FindManifestFiles - using environment variable override runtime file ";
info_message += filename;
LoaderLogger::LogInfoMessage("", info_message);
} else {
PlatformUtilsFreeEnv(override_path);
#ifdef XR_OS_WINDOWS
std::vector<std::string> filenames;
ReadRuntimeDataFilesInRegistry(type, "", "ActiveRuntime", filenames);
if (filenames.size() == 0) {
LoaderLogger::LogErrorMessage(
"", "RuntimeManifestFile::FindManifestFiles - failed to find active runtime file in registry");
return XR_ERROR_FILE_ACCESS_ERROR;
}
if (filenames.size() > 1) {
LoaderLogger::LogWarningMessage(
"", "RuntimeManifestFile::FindManifestFiles - found too many default runtime files in registry");
}
filename = filenames[0];
#elif defined(XR_OS_LINUX)
const std::string relative_path =
"openxr/" + std::to_string(XR_VERSION_MAJOR(XR_CURRENT_API_VERSION)) + "/active_runtime.json";
if (!FindXDGConfigFile(relative_path, filename)) {
LoaderLogger::LogErrorMessage(
"", "RuntimeManifestFile::FindManifestFiles - failed to determine active runtime file path for this environment");
return XR_ERROR_FILE_ACCESS_ERROR;
}
#else
if (!PlatformGetGlobalRuntimeFileName(XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), filename)) {
LoaderLogger::LogErrorMessage(
"", "RuntimeManifestFile::FindManifestFiles - failed to determine active runtime file path for this environment");
return XR_ERROR_FILE_ACCESS_ERROR;
}
#endif
std::string info_message = "RuntimeManifestFile::FindManifestFiles - using global runtime file ";
info_message += filename;
LoaderLogger::LogInfoMessage("", info_message);
}
RuntimeManifestFile::CreateIfValid(filename, manifest_files);
return result;
}
ApiLayerManifestFile::ApiLayerManifestFile(ManifestFileType type, const std::string &filename, const std::string &layer_name,
const std::string &description, const JsonVersion &api_version,
const uint32_t &implementation_version, const std::string &library_path)
: ManifestFile(type, filename, library_path),
_api_version(api_version),
_layer_name(layer_name),
_description(description),
_implementation_version(implementation_version) {}
ApiLayerManifestFile::~ApiLayerManifestFile() = default;
void ApiLayerManifestFile::CreateIfValid(ManifestFileType type, const std::string &filename,
std::vector<std::unique_ptr<ApiLayerManifestFile>> &manifest_files) {
std::ifstream json_stream = std::ifstream(filename, std::ifstream::in);
Json::Reader reader;
Json::Value root_node = Json::nullValue;
if (!reader.parse(json_stream, root_node, false) || root_node.isNull()) {
std::string error_message = "ApiLayerManifestFile::CreateIfValid failed to parse ";
error_message += filename;
error_message += ". Is it a valid layer manifest file? Error was:\n";
error_message += reader.getFormattedErrorMessages();
LoaderLogger::LogErrorMessage("", error_message);
return;
}
JsonVersion file_version = {};
if (!ManifestFile::IsValidJson(root_node, file_version)) {
std::string error_message = "ApiLayerManifestFile::CreateIfValid isValidJson indicates ";
error_message += filename;
error_message += " is not a valid manifest file.";
LoaderLogger::LogErrorMessage("", error_message);
return;
}
Json::Value layer_root_node = root_node["api_layer"];
// The API Layer manifest file needs the "api_layer" root as well as other sub-nodes.
// If any of those aren't there, fail.
if (layer_root_node.isNull() || layer_root_node["name"].isNull() || !layer_root_node["name"].isString() ||
layer_root_node["api_version"].isNull() || !layer_root_node["api_version"].isString() ||
layer_root_node["library_path"].isNull() || !layer_root_node["library_path"].isString() ||
layer_root_node["implementation_version"].isNull() || !layer_root_node["implementation_version"].isString()) {
std::string error_message = "ApiLayerManifestFile::CreateIfValid ";
error_message += filename;
error_message += " is missing required fields. Verify all proper fields exist.";
LoaderLogger::LogErrorMessage("", error_message);
return;
}
if (MANIFEST_TYPE_IMPLICIT_API_LAYER == type) {
bool enabled = true;
// Implicit layers require the disable environment variable.
if (layer_root_node["disable_environment"].isNull() || !layer_root_node["disable_environment"].isString()) {
std::string error_message = "ApiLayerManifestFile::CreateIfValid Implicit layer ";
error_message += filename;
error_message += " is missing \"disable_environment\"";
LoaderLogger::LogErrorMessage("", error_message);
return;
}
// Check if there's an enable environment variable provided
if (!layer_root_node["enable_environment"].isNull() && layer_root_node["enable_environment"].isString()) {
char *enable_val = PlatformUtilsGetEnv(layer_root_node["enable_environment"].asString().c_str());
// If it's not set in the environment, disable the layer
if (nullptr == enable_val) {
enabled = false;
}
PlatformUtilsFreeEnv(enable_val);
}
// Check for the disable environment variable, which must be provided in the JSON
char *disable_val = PlatformUtilsGetEnv(layer_root_node["disable_environment"].asString().c_str());
// If the envar is set, disable the layer. Disable envar overrides enable above
if (nullptr != disable_val) {
enabled = false;
}
PlatformUtilsFreeEnv(disable_val);
// Not enabled, so pretend like it isn't even there.
if (!enabled) {
std::string info_message = "ApiLayerManifestFile::CreateIfValid Implicit layer ";
info_message += filename;
info_message += " is disabled";
LoaderLogger::LogInfoMessage("", info_message);
return;
}
}
std::string layer_name = layer_root_node["name"].asString();
std::string api_version_string = layer_root_node["api_version"].asString();
JsonVersion api_version = {};
sscanf(api_version_string.c_str(), "%d.%d", &api_version.major, &api_version.minor);
api_version.patch = 0;
if ((api_version.major == 0 && api_version.minor == 0) || api_version.major > XR_VERSION_MAJOR(XR_CURRENT_API_VERSION)) {
std::string warning_message = "ApiLayerManifestFile::CreateIfValid layer ";
warning_message += filename;
warning_message += " has invalid API Version. Skipping layer.";
LoaderLogger::LogWarningMessage("", warning_message);
return;
}
uint32_t implementation_version = atoi(layer_root_node["implementation_version"].asString().c_str());
std::string library_path = layer_root_node["library_path"].asString();
// If the library_path variable has no directory symbol, it's just a file name and should be accessible on the
// global library path.
if (library_path.find('\\') != std::string::npos || library_path.find('/') != std::string::npos) {
// If the library_path is an absolute path, just use that if it exists
if (FileSysUtilsIsAbsolutePath(library_path)) {
if (!FileSysUtilsPathExists(library_path)) {
std::string error_message = "ApiLayerManifestFile::CreateIfValid ";
error_message += filename;
error_message += " library ";
error_message += library_path;
error_message += " does not appear to exist";
LoaderLogger::LogErrorMessage("", error_message);
return;
}
} else {
// Otherwise, treat the library path as a relative path based on the JSON file.
std::string combined_path;
std::string file_parent;
if (!FileSysUtilsGetParentPath(filename, file_parent) ||
!FileSysUtilsCombinePaths(file_parent, library_path, combined_path) || !FileSysUtilsPathExists(combined_path)) {
std::string error_message = "ApiLayerManifestFile::CreateIfValid ";
error_message += filename;
error_message += " library ";
error_message += combined_path;
error_message += " does not appear to exist";
LoaderLogger::LogErrorMessage("", error_message);
return;
}
library_path = combined_path;
}
}
std::string description;
if (!layer_root_node["description"].isNull() && layer_root_node["description"].isString()) {
description = layer_root_node["description"].asString();
}
// Add this layer manifest file
manifest_files.emplace_back(
new ApiLayerManifestFile(type, filename, layer_name, description, api_version, implementation_version, library_path));
// Add any extensions to it after the fact.
Json::Value dev_exts = layer_root_node["device_extensions"];
if (!dev_exts.isNull() && dev_exts.isArray()) {
for (Json::ValueIterator dev_ext_it = dev_exts.begin(); dev_ext_it != dev_exts.end(); ++dev_ext_it) {
Json::Value dev_ext = (*dev_ext_it);
Json::Value dev_ext_name = dev_ext["name"];
Json::Value dev_ext_version = dev_ext["extension_version"];
Json::Value dev_ext_entries = dev_ext["entrypoints"];
if (!dev_ext_name.isNull() && dev_ext_name.isString() && !dev_ext_version.isNull() && dev_ext_version.isString() &&
!dev_ext_entries.isNull() && dev_ext_entries.isArray()) {
ExtensionListing ext = {};
ext.name = dev_ext_name.asString();
ext.extension_version = atoi(dev_ext_version.asString().c_str());
for (Json::ValueIterator entry_it = dev_ext_entries.begin(); entry_it != dev_ext_entries.end(); ++entry_it) {
Json::Value entry = (*entry_it);
if (!entry.isNull() && entry.isString()) {
ext.entrypoints.push_back(entry.asString());
}
}
manifest_files.back()->_device_extensions.push_back(ext);
}
}
}
Json::Value inst_exts = layer_root_node["instance_extensions"];
if (!inst_exts.isNull() && inst_exts.isArray()) {
for (Json::ValueIterator inst_ext_it = inst_exts.begin(); inst_ext_it != inst_exts.end(); ++inst_ext_it) {
Json::Value inst_ext = (*inst_ext_it);
Json::Value inst_ext_name = inst_ext["name"];
Json::Value inst_ext_version = inst_ext["extension_version"];
if (!inst_ext_name.isNull() && inst_ext_name.isString() && !inst_ext_version.isNull() && inst_ext_version.isString()) {
ExtensionListing ext = {};
ext.name = inst_ext_name.asString();
ext.extension_version = atoi(inst_ext_version.asString().c_str());
manifest_files.back()->_instance_extensions.push_back(ext);
}
}
}
Json::Value funcs_renamed = layer_root_node["functions"];
if (!funcs_renamed.isNull() && !funcs_renamed.empty()) {
for (Json::ValueIterator func_it = funcs_renamed.begin(); func_it != funcs_renamed.end(); ++func_it) {
if (!(*func_it).isString()) {
std::string warning_message = "ApiLayerManifestFile::CreateIfValid ";
warning_message += filename;
warning_message += " \"functions\" section contains non-string values.";
LoaderLogger::LogWarningMessage("", warning_message);
continue;
}
std::string original_name = func_it.key().asString();
std::string new_name = (*func_it).asString();
manifest_files.back()->_functions_renamed.insert(std::make_pair(original_name, new_name));
}
}
}
XrApiLayerProperties ApiLayerManifestFile::GetApiLayerProperties() {
XrApiLayerProperties props = {};
props.type = XR_TYPE_API_LAYER_PROPERTIES;
props.next = nullptr;
props.layerVersion = _implementation_version;
props.specVersion = XR_MAKE_VERSION(_api_version.major, _api_version.minor, _api_version.patch);
strncpy(props.layerName, _layer_name.c_str(), XR_MAX_API_LAYER_NAME_SIZE - 1);
if (_layer_name.size() >= XR_MAX_API_LAYER_NAME_SIZE - 1) {
props.layerName[XR_MAX_API_LAYER_NAME_SIZE - 1] = '\0';
}
strncpy(props.description, _description.c_str(), XR_MAX_API_LAYER_DESCRIPTION_SIZE - 1);
if (_description.size() >= XR_MAX_API_LAYER_DESCRIPTION_SIZE - 1) {
props.description[XR_MAX_API_LAYER_DESCRIPTION_SIZE - 1] = '\0';
}
return props;
}
// Find all layer manifest files in the appropriate search paths/registries for the given type.
XrResult ApiLayerManifestFile::FindManifestFiles(ManifestFileType type,
std::vector<std::unique_ptr<ApiLayerManifestFile>> &manifest_files) {
std::string relative_path;
std::string override_env_var;
std::string registry_location;
// Add the appropriate top-level folders for the relative path. These should be
// the string "openxr/" followed by the API major version as a string.
relative_path = OPENXR_RELATIVE_PATH;
relative_path += std::to_string(XR_VERSION_MAJOR(XR_CURRENT_API_VERSION));
switch (type) {
case MANIFEST_TYPE_IMPLICIT_API_LAYER:
relative_path += OPENXR_IMPLICIT_API_LAYER_RELATIVE_PATH;
override_env_var = "";
#ifdef XR_OS_WINDOWS
registry_location = OPENXR_IMPLICIT_API_LAYER_REGISTRY_LOCATION;
#endif
break;
case MANIFEST_TYPE_EXPLICIT_API_LAYER:
relative_path += OPENXR_EXPLICIT_API_LAYER_RELATIVE_PATH;
override_env_var = OPENXR_API_LAYER_PATH_ENV_VAR;
#ifdef XR_OS_WINDOWS
registry_location = OPENXR_EXPLICIT_API_LAYER_REGISTRY_LOCATION;
#endif
break;
default:
LoaderLogger::LogErrorMessage("", "ApiLayerManifestFile::FindManifestFiles - unknown manifest file requested");
return XR_ERROR_FILE_ACCESS_ERROR;
}
bool override_active = false;
std::vector<std::string> filenames;
ReadDataFilesInSearchPaths(type, override_env_var, relative_path, override_active, filenames);
#ifdef XR_OS_WINDOWS
// Read the registry if the override wasn't active.
if (!override_active) {
ReadLayerDataFilesInRegistry(type, registry_location, filenames);
}
#endif
switch (type) {
case MANIFEST_TYPE_IMPLICIT_API_LAYER:
case MANIFEST_TYPE_EXPLICIT_API_LAYER:
for (std::string &cur_file : filenames) {
ApiLayerManifestFile::CreateIfValid(type, cur_file, manifest_files);
}
break;
default:
break;
}
return XR_SUCCESS;
}

View File

@@ -0,0 +1,121 @@
// Copyright (c) 2017 The Khronos Group Inc.
// Copyright (c) 2017 Valve Corporation
// Copyright (c) 2017 LunarG, Inc.
//
// 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.
//
// Author: Mark Young <marky@lunarg.com>
//
#pragma once
#include <openxr/openxr.h>
#include <memory>
#include <string>
#include <vector>
#include <unordered_map>
namespace Json {
class Value;
}
enum ManifestFileType {
MANIFEST_TYPE_UNDEFINED = 0,
MANIFEST_TYPE_RUNTIME,
MANIFEST_TYPE_IMPLICIT_API_LAYER,
MANIFEST_TYPE_EXPLICIT_API_LAYER,
};
struct JsonVersion {
uint32_t major;
uint32_t minor;
uint32_t patch;
};
struct ExtensionListing {
std::string name;
uint32_t extension_version;
std::vector<std::string> entrypoints;
};
// ManifestFile class -
// Base class responsible for finding and parsing manifest files.
class ManifestFile {
public:
ManifestFile(ManifestFileType type, const std::string &filename, const std::string &library_path);
virtual ~ManifestFile();
static bool IsValidJson(const Json::Value &root, JsonVersion &version);
// We don't want any copy constructors
ManifestFile &operator=(const ManifestFile &manifest_file) = delete;
ManifestFileType Type() { return _type; }
std::string Filename() { return _filename; }
std::string LibraryPath() { return _library_path; }
void GetInstanceExtensionProperties(std::vector<XrExtensionProperties> &props);
void GetDeviceExtensionProperties(std::vector<XrExtensionProperties> &props);
const std::string &GetFunctionName(const std::string &func_name);
protected:
std::string _filename;
ManifestFileType _type;
std::string _library_path;
std::vector<ExtensionListing> _instance_extensions;
std::vector<ExtensionListing> _device_extensions;
std::unordered_map<std::string, std::string> _functions_renamed;
};
// RuntimeManifestFile class -
// Responsible for finding and parsing Runtime-specific manifest files.
class RuntimeManifestFile : public ManifestFile {
public:
// Factory method
static XrResult FindManifestFiles(ManifestFileType type, std::vector<std::unique_ptr<RuntimeManifestFile>> &manifest_files);
RuntimeManifestFile(const std::string &filename, const std::string &library_path);
~RuntimeManifestFile() override;
static void CreateIfValid(const std::string &filename, std::vector<std::unique_ptr<RuntimeManifestFile>> &manifest_files);
// Non-copyable
RuntimeManifestFile(const RuntimeManifestFile &) = delete;
RuntimeManifestFile &operator=(const RuntimeManifestFile &) = delete;
};
// ApiLayerManifestFile class -
// Responsible for finding and parsing API Layer-specific manifest files.
class ApiLayerManifestFile : public ManifestFile {
public:
// Factory method
static XrResult FindManifestFiles(ManifestFileType type, std::vector<std::unique_ptr<ApiLayerManifestFile>> &manifest_files);
ApiLayerManifestFile(ManifestFileType type, const std::string &filename, const std::string &layer_name,
const std::string &description, const JsonVersion &api_version, const uint32_t &implementation_version,
const std::string &library_path);
~ApiLayerManifestFile() override;
static void CreateIfValid(ManifestFileType type, const std::string &filename,
std::vector<std::unique_ptr<ApiLayerManifestFile>> &manifest_files);
std::string LayerName() { return _layer_name; }
XrApiLayerProperties GetApiLayerProperties();
// Non-copyable
ApiLayerManifestFile(const ApiLayerManifestFile &) = delete;
ApiLayerManifestFile &operator=(const ApiLayerManifestFile &) = delete;
private:
JsonVersion _api_version;
std::string _layer_name;
std::string _description;
uint32_t _implementation_version;
};

11
extern/openxr/src/loader/openxr.pc.in vendored Normal file
View File

@@ -0,0 +1,11 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=@CMAKE_INSTALL_PREFIX@
libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@
includedir=${prefix}/include
Name: @CMAKE_PROJECT_NAME@
Description: OpenXR Loader
Version: @XR_API_VERSION@
Libs: -L${libdir} -lopenxr_loader @PRIVATE_LIBS@
Cflags: -I${includedir}

View File

@@ -0,0 +1,342 @@
// Copyright (c) 2017-2019 The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// 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.
//
// Author: Mark Young <marky@lunarg.com>
//
#include "runtime_interface.hpp"
#include "manifest_file.hpp"
#include "loader_interfaces.h"
#include "loader_logger.hpp"
#include "loader_platform.hpp"
#include "xr_generated_dispatch_table.h"
#include <openxr/openxr.h>
#include <cstring>
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
std::unique_ptr<RuntimeInterface> RuntimeInterface::_single_runtime_interface;
uint32_t RuntimeInterface::_single_runtime_count = 0;
XrResult RuntimeInterface::LoadRuntime(const std::string& openxr_command) {
XrResult last_error = XR_SUCCESS;
bool any_loaded = false;
// If something's already loaded, we're done here.
if (_single_runtime_interface != nullptr) {
_single_runtime_count++;
return XR_SUCCESS;
}
std::vector<std::unique_ptr<RuntimeManifestFile>> runtime_manifest_files = {};
// Find the available runtimes which we may need to report information for.
last_error = RuntimeManifestFile::FindManifestFiles(MANIFEST_TYPE_RUNTIME, runtime_manifest_files);
if (XR_SUCCESS != last_error) {
LoaderLogger::LogErrorMessage(openxr_command, "RuntimeInterface::LoadRuntimes - unknown error");
last_error = XR_ERROR_FILE_ACCESS_ERROR;
} else {
for (std::unique_ptr<RuntimeManifestFile>& manifest_file : runtime_manifest_files) {
LoaderPlatformLibraryHandle runtime_library = LoaderPlatformLibraryOpen(manifest_file->LibraryPath());
if (nullptr == runtime_library) {
if (!any_loaded) {
last_error = XR_ERROR_INSTANCE_LOST;
}
std::string library_message = LoaderPlatformLibraryOpenError(manifest_file->LibraryPath());
std::string warning_message = "RuntimeInterface::LoadRuntime skipping manifest file ";
warning_message += manifest_file->Filename();
warning_message += ", failed to load with message \"";
warning_message += library_message;
warning_message += "\"";
LoaderLogger::LogErrorMessage(openxr_command, warning_message);
continue;
}
// Get and settle on an runtime interface version (using any provided name if required).
std::string function_name = manifest_file->GetFunctionName("xrNegotiateLoaderRuntimeInterface");
auto negotiate = reinterpret_cast<PFN_xrNegotiateLoaderRuntimeInterface>(
LoaderPlatformLibraryGetProcAddr(runtime_library, function_name));
// Loader info for negotiation
XrNegotiateLoaderInfo loader_info = {};
loader_info.structType = XR_LOADER_INTERFACE_STRUCT_LOADER_INFO;
loader_info.structVersion = XR_LOADER_INFO_STRUCT_VERSION;
loader_info.structSize = sizeof(XrNegotiateLoaderInfo);
loader_info.minInterfaceVersion = 1;
loader_info.maxInterfaceVersion = XR_CURRENT_LOADER_RUNTIME_VERSION;
loader_info.minApiVersion = XR_MAKE_VERSION(1, 0, 0);
loader_info.maxApiVersion = XR_MAKE_VERSION(1, 0x3ff, 0xfff); // Maximum allowed version for this major version.
// Set up the runtime return structure
XrNegotiateRuntimeRequest runtime_info = {};
runtime_info.structType = XR_LOADER_INTERFACE_STRUCT_RUNTIME_REQUEST;
runtime_info.structVersion = XR_RUNTIME_INFO_STRUCT_VERSION;
runtime_info.structSize = sizeof(XrNegotiateRuntimeRequest);
// Skip calling the negotiate function and fail if the function pointer
// could not get loaded
XrResult res = XR_ERROR_RUNTIME_FAILURE;
if (nullptr != negotiate) {
res = negotiate(&loader_info, &runtime_info);
}
// If we supposedly succeeded, but got a nullptr for GetInstanceProcAddr
// then something still went wrong, so return with an error.
if (XR_SUCCESS == res) {
uint32_t runtime_major = XR_VERSION_MAJOR(runtime_info.runtimeApiVersion);
uint32_t runtime_minor = XR_VERSION_MINOR(runtime_info.runtimeApiVersion);
uint32_t loader_major = XR_VERSION_MAJOR(XR_CURRENT_API_VERSION);
if (nullptr == runtime_info.getInstanceProcAddr) {
std::string error_message = "RuntimeInterface::LoadRuntime skipping manifest file ";
error_message += manifest_file->Filename();
error_message += ", negotiation succeeded but returned NULL getInstanceProcAddr";
LoaderLogger::LogErrorMessage(openxr_command, error_message);
res = XR_ERROR_FILE_CONTENTS_INVALID;
} else if (0 >= runtime_info.runtimeInterfaceVersion ||
XR_CURRENT_LOADER_RUNTIME_VERSION < runtime_info.runtimeInterfaceVersion) {
std::string error_message = "RuntimeInterface::LoadRuntime skipping manifest file ";
error_message += manifest_file->Filename();
error_message += ", negotiation succeeded but returned invalid interface version";
LoaderLogger::LogErrorMessage(openxr_command, error_message);
res = XR_ERROR_FILE_CONTENTS_INVALID;
} else if (runtime_major != loader_major || (runtime_major == 0 && runtime_minor == 0)) {
std::string error_message = "RuntimeInterface::LoadRuntime skipping manifest file ";
error_message += manifest_file->Filename();
error_message += ", OpenXR version returned not compatible with this loader";
LoaderLogger::LogErrorMessage(openxr_command, error_message);
res = XR_ERROR_FILE_CONTENTS_INVALID;
}
}
if (XR_SUCCESS != res) {
if (!any_loaded) {
last_error = res;
}
std::string warning_message = "RuntimeInterface::LoadRuntime skipping manifest file ";
warning_message += manifest_file->Filename();
warning_message += ", negotiation failed with error ";
warning_message += std::to_string(res);
LoaderLogger::LogErrorMessage(openxr_command, warning_message);
LoaderPlatformLibraryClose(runtime_library);
continue;
}
std::string info_message = "RuntimeInterface::LoadRuntime succeeded loading runtime defined in manifest file ";
info_message += manifest_file->Filename();
info_message += " using interface version ";
info_message += std::to_string(runtime_info.runtimeInterfaceVersion);
info_message += " and OpenXR API version ";
info_message += std::to_string(XR_VERSION_MAJOR(runtime_info.runtimeApiVersion));
info_message += ".";
info_message += std::to_string(XR_VERSION_MINOR(runtime_info.runtimeApiVersion));
LoaderLogger::LogInfoMessage(openxr_command, info_message);
// Use this runtime
_single_runtime_interface.reset(new RuntimeInterface(runtime_library, runtime_info.getInstanceProcAddr));
_single_runtime_count++;
// Grab the list of extensions this runtime supports for easy filtering after the
// xrCreateInstance call
std::vector<std::string> supported_extensions;
std::vector<XrExtensionProperties> extension_properties;
_single_runtime_interface->GetInstanceExtensionProperties(extension_properties);
supported_extensions.reserve(extension_properties.size());
for (XrExtensionProperties ext_prop : extension_properties) {
supported_extensions.emplace_back(ext_prop.extensionName);
}
_single_runtime_interface->SetSupportedExtensions(supported_extensions);
// If we load one, clear all errors.
any_loaded = true;
last_error = XR_SUCCESS;
break;
}
}
// Always clear the manifest file list. Either we use them or we don't.
runtime_manifest_files.clear();
// We found no valid runtimes, throw the initialization failed message
if (!any_loaded) {
LoaderLogger::LogErrorMessage(openxr_command, "RuntimeInterface::LoadRuntimes - failed to find a valid runtime");
last_error = XR_ERROR_INSTANCE_LOST;
}
return last_error;
}
void RuntimeInterface::UnloadRuntime(const std::string& openxr_command) {
if (_single_runtime_count == 1) {
_single_runtime_count = 0;
_single_runtime_interface.reset();
} else if (_single_runtime_count > 0) {
--_single_runtime_count;
}
LoaderLogger::LogInfoMessage(openxr_command, "RuntimeInterface being unloaded.");
}
XrResult RuntimeInterface::GetInstanceProcAddr(XrInstance instance, const char* name, PFN_xrVoidFunction* function) {
return _single_runtime_interface->_get_instant_proc_addr(instance, name, function);
}
const XrGeneratedDispatchTable* RuntimeInterface::GetDispatchTable(XrInstance instance) {
XrGeneratedDispatchTable* table = nullptr;
std::lock_guard<std::mutex> mlock(_single_runtime_interface->_dispatch_table_mutex);
auto it = _single_runtime_interface->_dispatch_table_map.find(instance);
if (it != _single_runtime_interface->_dispatch_table_map.end()) {
table = it->second.get();
}
return table;
}
const XrGeneratedDispatchTable* RuntimeInterface::GetDebugUtilsMessengerDispatchTable(XrDebugUtilsMessengerEXT messenger) {
XrInstance runtime_instance = XR_NULL_HANDLE;
{
std::lock_guard<std::mutex> mlock(_single_runtime_interface->_messenger_to_instance_mutex);
auto it = _single_runtime_interface->_messenger_to_instance_map.find(messenger);
if (it != _single_runtime_interface->_messenger_to_instance_map.end()) {
runtime_instance = it->second;
}
}
return GetDispatchTable(runtime_instance);
}
RuntimeInterface::RuntimeInterface(LoaderPlatformLibraryHandle runtime_library, PFN_xrGetInstanceProcAddr get_instant_proc_addr)
: _runtime_library(runtime_library), _get_instant_proc_addr(get_instant_proc_addr) {}
RuntimeInterface::~RuntimeInterface() {
std::string info_message = "RuntimeInterface being destroyed.";
LoaderLogger::LogInfoMessage("", info_message);
{
std::lock_guard<std::mutex> mlock(_dispatch_table_mutex);
_dispatch_table_map.clear();
}
LoaderPlatformLibraryClose(_runtime_library);
}
void RuntimeInterface::GetInstanceExtensionProperties(std::vector<XrExtensionProperties>& extension_properties) {
std::vector<XrExtensionProperties> runtime_extension_properties;
PFN_xrEnumerateInstanceExtensionProperties rt_xrEnumerateInstanceExtensionProperties;
_get_instant_proc_addr(XR_NULL_HANDLE, "xrEnumerateInstanceExtensionProperties",
reinterpret_cast<PFN_xrVoidFunction*>(&rt_xrEnumerateInstanceExtensionProperties));
uint32_t count = 0;
uint32_t count_output = 0;
// Get the count from the runtime
rt_xrEnumerateInstanceExtensionProperties(nullptr, count, &count_output, nullptr);
if (count_output > 0) {
runtime_extension_properties.resize(count_output);
count = count_output;
for (XrExtensionProperties& ext_prop : runtime_extension_properties) {
ext_prop.type = XR_TYPE_EXTENSION_PROPERTIES;
ext_prop.next = nullptr;
}
rt_xrEnumerateInstanceExtensionProperties(nullptr, count, &count_output, runtime_extension_properties.data());
}
size_t ext_count = runtime_extension_properties.size();
size_t props_count = extension_properties.size();
for (size_t ext = 0; ext < ext_count; ++ext) {
bool found = false;
for (size_t prop = 0; prop < props_count; ++prop) {
// If we find it, then make sure the spec version matches that of the runtime instead of the
// layer.
if (strcmp(extension_properties[prop].extensionName, runtime_extension_properties[ext].extensionName) == 0) {
// Make sure the spec version used is the runtime's
extension_properties[prop].extensionVersion = runtime_extension_properties[ext].extensionVersion;
found = true;
break;
}
}
if (!found) {
extension_properties.push_back(runtime_extension_properties[ext]);
}
}
}
XrResult RuntimeInterface::CreateInstance(const XrInstanceCreateInfo* info, XrInstance* instance) {
XrResult res = XR_SUCCESS;
bool create_succeeded = false;
PFN_xrCreateInstance rt_xrCreateInstance;
_get_instant_proc_addr(XR_NULL_HANDLE, "xrCreateInstance", reinterpret_cast<PFN_xrVoidFunction*>(&rt_xrCreateInstance));
res = rt_xrCreateInstance(info, instance);
if (XR_SUCCESS == res) {
create_succeeded = true;
std::unique_ptr<XrGeneratedDispatchTable> dispatch_table(new XrGeneratedDispatchTable());
GeneratedXrPopulateDispatchTable(dispatch_table.get(), *instance, _get_instant_proc_addr);
std::lock_guard<std::mutex> mlock(_dispatch_table_mutex);
_dispatch_table_map[*instance] = std::move(dispatch_table);
}
// If the failure occurred during the populate, clean up the instance we had picked up from the runtime
if (XR_SUCCESS != res && create_succeeded) {
PFN_xrDestroyInstance rt_xrDestroyInstance;
_get_instant_proc_addr(*instance, "xrDestroyInstance", reinterpret_cast<PFN_xrVoidFunction*>(&rt_xrDestroyInstance));
rt_xrDestroyInstance(*instance);
*instance = XR_NULL_HANDLE;
}
return res;
}
XrResult RuntimeInterface::DestroyInstance(XrInstance instance) {
if (XR_NULL_HANDLE != instance) {
// Destroy the dispatch table for this instance first
{
std::lock_guard<std::mutex> mlock(_dispatch_table_mutex);
auto map_iter = _dispatch_table_map.find(instance);
if (map_iter != _dispatch_table_map.end()) {
_dispatch_table_map.erase(map_iter);
}
}
// Now delete the instance
PFN_xrDestroyInstance rt_xrDestroyInstance;
_get_instant_proc_addr(instance, "xrDestroyInstance", reinterpret_cast<PFN_xrVoidFunction*>(&rt_xrDestroyInstance));
rt_xrDestroyInstance(instance);
}
return XR_SUCCESS;
}
bool RuntimeInterface::TrackDebugMessenger(XrInstance instance, XrDebugUtilsMessengerEXT messenger) {
std::lock_guard<std::mutex> mlock(_messenger_to_instance_mutex);
_messenger_to_instance_map[messenger] = instance;
return true;
}
void RuntimeInterface::ForgetDebugMessenger(XrDebugUtilsMessengerEXT messenger) {
if (XR_NULL_HANDLE != messenger) {
std::lock_guard<std::mutex> mlock(_messenger_to_instance_mutex);
_messenger_to_instance_map.erase(messenger);
}
}
void RuntimeInterface::SetSupportedExtensions(std::vector<std::string>& supported_extensions) {
_supported_extensions = supported_extensions;
}
bool RuntimeInterface::SupportsExtension(const std::string& extension_name) {
bool found_prop = false;
for (const std::string& supported_extension : _supported_extensions) {
if (supported_extension == extension_name) {
found_prop = true;
break;
}
}
return found_prop;
}

View File

@@ -0,0 +1,73 @@
// Copyright (c) 2017-2019 The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// 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.
//
// Author: Mark Young <marky@lunarg.com>
//
#pragma once
#include "loader_platform.hpp"
#include <openxr/openxr.h>
#include <string>
#include <vector>
#include <unordered_map>
#include <mutex>
#include <memory>
struct XrGeneratedDispatchTable;
class RuntimeInterface {
public:
virtual ~RuntimeInterface();
// Helper functions for loading and unloading the runtime (but only when necessary)
static XrResult LoadRuntime(const std::string& openxr_command);
static void UnloadRuntime(const std::string& openxr_command);
static RuntimeInterface& GetRuntime() { return *(_single_runtime_interface.get()); }
static XrResult GetInstanceProcAddr(XrInstance instance, const char* name, PFN_xrVoidFunction* function);
static const XrGeneratedDispatchTable* GetDispatchTable(XrInstance instance);
static const XrGeneratedDispatchTable* GetDebugUtilsMessengerDispatchTable(XrDebugUtilsMessengerEXT messenger);
void GetInstanceExtensionProperties(std::vector<XrExtensionProperties>& extension_properties);
bool SupportsExtension(const std::string& extension_name);
XrResult CreateInstance(const XrInstanceCreateInfo* info, XrInstance* instance);
XrResult DestroyInstance(XrInstance instance);
bool TrackDebugMessenger(XrInstance instance, XrDebugUtilsMessengerEXT messenger);
void ForgetDebugMessenger(XrDebugUtilsMessengerEXT messenger);
// No default construction
RuntimeInterface() = delete;
// Non-copyable
RuntimeInterface(const RuntimeInterface&) = delete;
RuntimeInterface& operator=(const RuntimeInterface&) = delete;
private:
RuntimeInterface(LoaderPlatformLibraryHandle runtime_library, PFN_xrGetInstanceProcAddr get_instant_proc_addr);
void SetSupportedExtensions(std::vector<std::string>& supported_extensions);
static std::unique_ptr<RuntimeInterface> _single_runtime_interface;
static uint32_t _single_runtime_count;
LoaderPlatformLibraryHandle _runtime_library;
PFN_xrGetInstanceProcAddr _get_instant_proc_addr;
std::unordered_map<XrInstance, std::unique_ptr<XrGeneratedDispatchTable>> _dispatch_table_map;
std::mutex _dispatch_table_mutex;
std::unordered_map<XrDebugUtilsMessengerEXT, XrInstance> _messenger_to_instance_map;
std::mutex _messenger_to_instance_mutex;
std::vector<std::string> _supported_extensions;
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,307 @@
// *********** THIS FILE IS GENERATED - DO NOT EDIT ***********
// See loader_source_generator.py for modifications
// ************************************************************
// Copyright (c) 2017-2019 The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// 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.
//
// Author: Mark Young <marky@lunarg.com>
//
#pragma once
#include <unordered_map>
#include <thread>
#include <mutex>
#include "xr_dependencies.h"
#include "openxr/openxr.h"
#include "openxr/openxr_platform.h"
#include "loader_interfaces.h"
#include "loader_instance.hpp"
#ifdef __cplusplus
extern "C" {
#endif
// Loader manually generated function prototypes
// ---- Core 1.0 loader manual functions
XRAPI_ATTR XrResult XRAPI_CALL xrGetInstanceProcAddr(
XrInstance instance,
const char* name,
PFN_xrVoidFunction* function);
XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermGetInstanceProcAddr(
XrInstance instance,
const char* name,
PFN_xrVoidFunction* function);
XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateApiLayerProperties(
uint32_t propertyCapacityInput,
uint32_t* propertyCountOutput,
XrApiLayerProperties* properties);
XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateInstanceExtensionProperties(
const char* layerName,
uint32_t propertyCapacityInput,
uint32_t* propertyCountOutput,
XrExtensionProperties* properties);
XRAPI_ATTR XrResult XRAPI_CALL xrCreateInstance(
const XrInstanceCreateInfo* createInfo,
XrInstance* instance);
XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateInstance(
const XrInstanceCreateInfo* createInfo,
XrInstance* instance);
XRAPI_ATTR XrResult XRAPI_CALL xrDestroyInstance(
XrInstance instance);
XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermDestroyInstance(
XrInstance instance);
XRAPI_ATTR XrResult XRAPI_CALL xrGetInstanceProperties(
XrInstance instance,
XrInstanceProperties* instanceProperties);
XRAPI_ATTR XrResult XRAPI_CALL xrPollEvent(
XrInstance instance,
XrEventDataBuffer* eventData);
XRAPI_ATTR XrResult XRAPI_CALL xrResultToString(
XrInstance instance,
XrResult value,
char buffer[XR_MAX_RESULT_STRING_SIZE]);
XRAPI_ATTR XrResult XRAPI_CALL xrStructureTypeToString(
XrInstance instance,
XrStructureType value,
char buffer[XR_MAX_STRUCTURE_NAME_SIZE]);
XRAPI_ATTR XrResult XRAPI_CALL xrGetSystem(
XrInstance instance,
const XrSystemGetInfo* getInfo,
XrSystemId* systemId);
XRAPI_ATTR XrResult XRAPI_CALL xrGetSystemProperties(
XrInstance instance,
XrSystemId systemId,
XrSystemProperties* properties);
XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateEnvironmentBlendModes(
XrInstance instance,
XrSystemId systemId,
XrViewConfigurationType viewConfigurationType,
uint32_t environmentBlendModeCapacityInput,
uint32_t* environmentBlendModeCountOutput,
XrEnvironmentBlendMode* environmentBlendModes);
XRAPI_ATTR XrResult XRAPI_CALL xrCreateSession(
XrInstance instance,
const XrSessionCreateInfo* createInfo,
XrSession* session);
XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateViewConfigurations(
XrInstance instance,
XrSystemId systemId,
uint32_t viewConfigurationTypeCapacityInput,
uint32_t* viewConfigurationTypeCountOutput,
XrViewConfigurationType* viewConfigurationTypes);
XRAPI_ATTR XrResult XRAPI_CALL xrGetViewConfigurationProperties(
XrInstance instance,
XrSystemId systemId,
XrViewConfigurationType viewConfigurationType,
XrViewConfigurationProperties* configurationProperties);
XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateViewConfigurationViews(
XrInstance instance,
XrSystemId systemId,
XrViewConfigurationType viewConfigurationType,
uint32_t viewCapacityInput,
uint32_t* viewCountOutput,
XrViewConfigurationView* views);
XRAPI_ATTR XrResult XRAPI_CALL xrStringToPath(
XrInstance instance,
const char* pathString,
XrPath* path);
XRAPI_ATTR XrResult XRAPI_CALL xrPathToString(
XrInstance instance,
XrPath path,
uint32_t bufferCapacityInput,
uint32_t* bufferCountOutput,
char* buffer);
XRAPI_ATTR XrResult XRAPI_CALL xrCreateActionSet(
XrInstance instance,
const XrActionSetCreateInfo* createInfo,
XrActionSet* actionSet);
XRAPI_ATTR XrResult XRAPI_CALL xrSuggestInteractionProfileBindings(
XrInstance instance,
const XrInteractionProfileSuggestedBinding* suggestedBindings);
// ---- XR_KHR_opengl_enable loader manual functions
#if defined(XR_USE_GRAPHICS_API_OPENGL)
XRAPI_ATTR XrResult XRAPI_CALL xrGetOpenGLGraphicsRequirementsKHR(
XrInstance instance,
XrSystemId systemId,
XrGraphicsRequirementsOpenGLKHR* graphicsRequirements);
#endif // defined(XR_USE_GRAPHICS_API_OPENGL)
// ---- XR_KHR_opengl_es_enable loader manual functions
#if defined(XR_USE_GRAPHICS_API_OPENGL_ES)
XRAPI_ATTR XrResult XRAPI_CALL xrGetOpenGLESGraphicsRequirementsKHR(
XrInstance instance,
XrSystemId systemId,
XrGraphicsRequirementsOpenGLESKHR* graphicsRequirements);
#endif // defined(XR_USE_GRAPHICS_API_OPENGL_ES)
// ---- XR_KHR_vulkan_enable loader manual functions
#if defined(XR_USE_GRAPHICS_API_VULKAN)
XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanInstanceExtensionsKHR(
XrInstance instance,
XrSystemId systemId,
uint32_t bufferCapacityInput,
uint32_t* bufferCountOutput,
char* buffer);
#endif // defined(XR_USE_GRAPHICS_API_VULKAN)
#if defined(XR_USE_GRAPHICS_API_VULKAN)
XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanDeviceExtensionsKHR(
XrInstance instance,
XrSystemId systemId,
uint32_t bufferCapacityInput,
uint32_t* bufferCountOutput,
char* buffer);
#endif // defined(XR_USE_GRAPHICS_API_VULKAN)
#if defined(XR_USE_GRAPHICS_API_VULKAN)
XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanGraphicsDeviceKHR(
XrInstance instance,
XrSystemId systemId,
VkInstance vkInstance,
VkPhysicalDevice* vkPhysicalDevice);
#endif // defined(XR_USE_GRAPHICS_API_VULKAN)
#if defined(XR_USE_GRAPHICS_API_VULKAN)
XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanGraphicsRequirementsKHR(
XrInstance instance,
XrSystemId systemId,
XrGraphicsRequirementsVulkanKHR* graphicsRequirements);
#endif // defined(XR_USE_GRAPHICS_API_VULKAN)
// ---- XR_KHR_D3D11_enable loader manual functions
#if defined(XR_USE_GRAPHICS_API_D3D11)
XRAPI_ATTR XrResult XRAPI_CALL xrGetD3D11GraphicsRequirementsKHR(
XrInstance instance,
XrSystemId systemId,
XrGraphicsRequirementsD3D11KHR* graphicsRequirements);
#endif // defined(XR_USE_GRAPHICS_API_D3D11)
// ---- XR_KHR_D3D12_enable loader manual functions
#if defined(XR_USE_GRAPHICS_API_D3D12)
XRAPI_ATTR XrResult XRAPI_CALL xrGetD3D12GraphicsRequirementsKHR(
XrInstance instance,
XrSystemId systemId,
XrGraphicsRequirementsD3D12KHR* graphicsRequirements);
#endif // defined(XR_USE_GRAPHICS_API_D3D12)
// ---- XR_KHR_win32_convert_performance_counter_time loader manual functions
#if defined(XR_USE_PLATFORM_WIN32)
XRAPI_ATTR XrResult XRAPI_CALL xrConvertWin32PerformanceCounterToTimeKHR(
XrInstance instance,
const LARGE_INTEGER* performanceCounter,
XrTime* time);
#endif // defined(XR_USE_PLATFORM_WIN32)
#if defined(XR_USE_PLATFORM_WIN32)
XRAPI_ATTR XrResult XRAPI_CALL xrConvertTimeToWin32PerformanceCounterKHR(
XrInstance instance,
XrTime time,
LARGE_INTEGER* performanceCounter);
#endif // defined(XR_USE_PLATFORM_WIN32)
// ---- XR_KHR_convert_timespec_time loader manual functions
#if defined(XR_USE_TIMESPEC)
XRAPI_ATTR XrResult XRAPI_CALL xrConvertTimespecTimeToTimeKHR(
XrInstance instance,
const struct timespec* timespecTime,
XrTime* time);
#endif // defined(XR_USE_TIMESPEC)
#if defined(XR_USE_TIMESPEC)
XRAPI_ATTR XrResult XRAPI_CALL xrConvertTimeToTimespecTimeKHR(
XrInstance instance,
XrTime time,
struct timespec* timespecTime);
#endif // defined(XR_USE_TIMESPEC)
// ---- XR_EXT_debug_utils loader manual functions
XRAPI_ATTR XrResult XRAPI_CALL xrSetDebugUtilsObjectNameEXT(
XrInstance instance,
const XrDebugUtilsObjectNameInfoEXT* nameInfo);
XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermSetDebugUtilsObjectNameEXT(
XrInstance instance,
const XrDebugUtilsObjectNameInfoEXT* nameInfo);
XRAPI_ATTR XrResult XRAPI_CALL xrCreateDebugUtilsMessengerEXT(
XrInstance instance,
const XrDebugUtilsMessengerCreateInfoEXT* createInfo,
XrDebugUtilsMessengerEXT* messenger);
XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateDebugUtilsMessengerEXT(
XrInstance instance,
const XrDebugUtilsMessengerCreateInfoEXT* createInfo,
XrDebugUtilsMessengerEXT* messenger);
XRAPI_ATTR XrResult XRAPI_CALL xrDestroyDebugUtilsMessengerEXT(
XrDebugUtilsMessengerEXT messenger);
XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermDestroyDebugUtilsMessengerEXT(
XrDebugUtilsMessengerEXT messenger);
XRAPI_ATTR XrResult XRAPI_CALL xrSubmitDebugUtilsMessageEXT(
XrInstance instance,
XrDebugUtilsMessageSeverityFlagsEXT messageSeverity,
XrDebugUtilsMessageTypeFlagsEXT messageTypes,
const XrDebugUtilsMessengerCallbackDataEXT* callbackData);
XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermSubmitDebugUtilsMessageEXT(
XrInstance instance,
XrDebugUtilsMessageSeverityFlagsEXT messageSeverity,
XrDebugUtilsMessageTypeFlagsEXT messageTypes,
const XrDebugUtilsMessengerCallbackDataEXT* callbackData);
XRAPI_ATTR XrResult XRAPI_CALL xrSessionBeginDebugUtilsLabelRegionEXT(
XrSession session,
const XrDebugUtilsLabelEXT* labelInfo);
XRAPI_ATTR XrResult XRAPI_CALL xrSessionEndDebugUtilsLabelRegionEXT(
XrSession session);
XRAPI_ATTR XrResult XRAPI_CALL xrSessionInsertDebugUtilsLabelEXT(
XrSession session,
const XrDebugUtilsLabelEXT* labelInfo);
// Special use function to handle creating API Layer information during xrCreateInstance
XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateApiLayerInstance(const XrInstanceCreateInfo* info,
const struct XrApiLayerCreateInfo* apiLayerInfo,
XrInstance* instance);
// Generated loader terminator prototypes
XRAPI_ATTR XrResult XRAPI_CALL LoaderGenTermXrResultToString(
XrInstance instance,
XrResult value,
char buffer[XR_MAX_RESULT_STRING_SIZE]);
XRAPI_ATTR XrResult XRAPI_CALL LoaderGenTermXrStructureTypeToString(
XrInstance instance,
XrStructureType value,
char buffer[XR_MAX_STRUCTURE_NAME_SIZE]);
// Instance Init Dispatch Table (put all terminators in first)
void LoaderGenInitInstanceDispatchTable(XrInstance runtime_instance,
std::unique_ptr<XrGeneratedDispatchTable>& table);
#ifdef __cplusplus
} // extern "C"
#endif
// Unordered maps and mutexes to lookup the instance for a given object type
extern HandleLoaderMap<XrInstance> g_instance_map;
extern HandleLoaderMap<XrSession> g_session_map;
extern HandleLoaderMap<XrSpace> g_space_map;
extern HandleLoaderMap<XrAction> g_action_map;
extern HandleLoaderMap<XrSwapchain> g_swapchain_map;
extern HandleLoaderMap<XrActionSet> g_actionset_map;
extern HandleLoaderMap<XrDebugUtilsMessengerEXT> g_debugutilsmessengerext_map;
// Function used to clean up any residual map values that point to an instance prior to that
// instance being deleted.
void LoaderCleanUpMapsForInstance(LoaderInstance *instance);

41
extern/openxr/src/version.cmake vendored Normal file
View File

@@ -0,0 +1,41 @@
# Copyright (c) 2017-2019 The Khronos Group Inc.
#
# 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.
# Set up the OpenXR version variables, used by several targets in this project.
set(MAJOR "0")
set(MINOR "0")
set(PATCH "0")
if(EXISTS "${OPENXR_ROOT_DIR}/specification/registry/xr.xml")
file(STRINGS ${OPENXR_ROOT_DIR}/specification/registry/xr.xml lines REGEX "#define <name>XR_CURRENT_API_VERSION")
else()
file(STRINGS ${OPENXR_ROOT_DIR}/include/openxr/openxr.h lines REGEX "#define XR_CURRENT_API_VERSION")
endif()
list(LENGTH lines len)
if(${len} EQUAL 1)
list(GET lines 0 cur_line)
# Erase everything up to the open parentheses
string(REGEX REPLACE "^[^\(]+" "" VERSION_BEFORE_ERASED ${cur_line})
# Erase everything after the close parentheses
string(REGEX REPLACE "[^\)]+$" "" VERSION_AFTER_ERASED ${VERSION_BEFORE_ERASED})
# Erase the parentheses
string(REPLACE "(" "" VERSION_AFTER_ERASED2 ${VERSION_AFTER_ERASED})
string(REPLACE ")" "" VERSION_AFTER_ERASED3 ${VERSION_AFTER_ERASED2})
string(REPLACE " " "" VERSION_AFTER_ERASED4 ${VERSION_AFTER_ERASED3})
string(REGEX REPLACE "^([0-9]+)\\,[0-9]+\\,[0-9]+" "\\1" MAJOR "${VERSION_AFTER_ERASED4}")
string(REGEX REPLACE "^[0-9]+\\,([0-9]+)\\,[0-9]+" "\\1" MINOR "${VERSION_AFTER_ERASED4}")
string(REGEX REPLACE "^[0-9]+\\,[0-9]+\\,([0-9]+)" "\\1" PATCH "${VERSION_AFTER_ERASED4}")
else()
message(FATAL_ERROR "Unable to fetch major/minor version from registry or header")
endif()

View File

@@ -0,0 +1,175 @@
// *********** THIS FILE IS GENERATED - DO NOT EDIT ***********
// See utility_source_generator.py for modifications
// ************************************************************
// Copyright (c) 2017-2019 The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// 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.
//
// Author: Mark Young <marky@lunarg.com>
//
#include "xr_dependencies.h"
#include <openxr/openxr.h>
#include <openxr/openxr_platform.h>
#include "xr_generated_dispatch_table.h"
#ifdef __cplusplus
extern "C" {
#endif
// Helper function to populate an instance dispatch table
void GeneratedXrPopulateDispatchTable(struct XrGeneratedDispatchTable *table,
XrInstance instance,
PFN_xrGetInstanceProcAddr get_inst_proc_addr) {
// ---- Core 1.0 commands
table->GetInstanceProcAddr = get_inst_proc_addr;
(get_inst_proc_addr(instance, "xrCreateInstance", (PFN_xrVoidFunction*)&table->CreateInstance));
(get_inst_proc_addr(instance, "xrDestroyInstance", (PFN_xrVoidFunction*)&table->DestroyInstance));
(get_inst_proc_addr(instance, "xrGetInstanceProperties", (PFN_xrVoidFunction*)&table->GetInstanceProperties));
(get_inst_proc_addr(instance, "xrPollEvent", (PFN_xrVoidFunction*)&table->PollEvent));
(get_inst_proc_addr(instance, "xrResultToString", (PFN_xrVoidFunction*)&table->ResultToString));
(get_inst_proc_addr(instance, "xrStructureTypeToString", (PFN_xrVoidFunction*)&table->StructureTypeToString));
(get_inst_proc_addr(instance, "xrGetSystem", (PFN_xrVoidFunction*)&table->GetSystem));
(get_inst_proc_addr(instance, "xrGetSystemProperties", (PFN_xrVoidFunction*)&table->GetSystemProperties));
(get_inst_proc_addr(instance, "xrEnumerateEnvironmentBlendModes", (PFN_xrVoidFunction*)&table->EnumerateEnvironmentBlendModes));
(get_inst_proc_addr(instance, "xrCreateSession", (PFN_xrVoidFunction*)&table->CreateSession));
(get_inst_proc_addr(instance, "xrDestroySession", (PFN_xrVoidFunction*)&table->DestroySession));
(get_inst_proc_addr(instance, "xrEnumerateReferenceSpaces", (PFN_xrVoidFunction*)&table->EnumerateReferenceSpaces));
(get_inst_proc_addr(instance, "xrCreateReferenceSpace", (PFN_xrVoidFunction*)&table->CreateReferenceSpace));
(get_inst_proc_addr(instance, "xrGetReferenceSpaceBoundsRect", (PFN_xrVoidFunction*)&table->GetReferenceSpaceBoundsRect));
(get_inst_proc_addr(instance, "xrCreateActionSpace", (PFN_xrVoidFunction*)&table->CreateActionSpace));
(get_inst_proc_addr(instance, "xrLocateSpace", (PFN_xrVoidFunction*)&table->LocateSpace));
(get_inst_proc_addr(instance, "xrDestroySpace", (PFN_xrVoidFunction*)&table->DestroySpace));
(get_inst_proc_addr(instance, "xrEnumerateViewConfigurations", (PFN_xrVoidFunction*)&table->EnumerateViewConfigurations));
(get_inst_proc_addr(instance, "xrGetViewConfigurationProperties", (PFN_xrVoidFunction*)&table->GetViewConfigurationProperties));
(get_inst_proc_addr(instance, "xrEnumerateViewConfigurationViews", (PFN_xrVoidFunction*)&table->EnumerateViewConfigurationViews));
(get_inst_proc_addr(instance, "xrEnumerateSwapchainFormats", (PFN_xrVoidFunction*)&table->EnumerateSwapchainFormats));
(get_inst_proc_addr(instance, "xrCreateSwapchain", (PFN_xrVoidFunction*)&table->CreateSwapchain));
(get_inst_proc_addr(instance, "xrDestroySwapchain", (PFN_xrVoidFunction*)&table->DestroySwapchain));
(get_inst_proc_addr(instance, "xrEnumerateSwapchainImages", (PFN_xrVoidFunction*)&table->EnumerateSwapchainImages));
(get_inst_proc_addr(instance, "xrAcquireSwapchainImage", (PFN_xrVoidFunction*)&table->AcquireSwapchainImage));
(get_inst_proc_addr(instance, "xrWaitSwapchainImage", (PFN_xrVoidFunction*)&table->WaitSwapchainImage));
(get_inst_proc_addr(instance, "xrReleaseSwapchainImage", (PFN_xrVoidFunction*)&table->ReleaseSwapchainImage));
(get_inst_proc_addr(instance, "xrBeginSession", (PFN_xrVoidFunction*)&table->BeginSession));
(get_inst_proc_addr(instance, "xrEndSession", (PFN_xrVoidFunction*)&table->EndSession));
(get_inst_proc_addr(instance, "xrRequestExitSession", (PFN_xrVoidFunction*)&table->RequestExitSession));
(get_inst_proc_addr(instance, "xrWaitFrame", (PFN_xrVoidFunction*)&table->WaitFrame));
(get_inst_proc_addr(instance, "xrBeginFrame", (PFN_xrVoidFunction*)&table->BeginFrame));
(get_inst_proc_addr(instance, "xrEndFrame", (PFN_xrVoidFunction*)&table->EndFrame));
(get_inst_proc_addr(instance, "xrLocateViews", (PFN_xrVoidFunction*)&table->LocateViews));
(get_inst_proc_addr(instance, "xrStringToPath", (PFN_xrVoidFunction*)&table->StringToPath));
(get_inst_proc_addr(instance, "xrPathToString", (PFN_xrVoidFunction*)&table->PathToString));
(get_inst_proc_addr(instance, "xrCreateActionSet", (PFN_xrVoidFunction*)&table->CreateActionSet));
(get_inst_proc_addr(instance, "xrDestroyActionSet", (PFN_xrVoidFunction*)&table->DestroyActionSet));
(get_inst_proc_addr(instance, "xrCreateAction", (PFN_xrVoidFunction*)&table->CreateAction));
(get_inst_proc_addr(instance, "xrDestroyAction", (PFN_xrVoidFunction*)&table->DestroyAction));
(get_inst_proc_addr(instance, "xrSuggestInteractionProfileBindings", (PFN_xrVoidFunction*)&table->SuggestInteractionProfileBindings));
(get_inst_proc_addr(instance, "xrAttachSessionActionSets", (PFN_xrVoidFunction*)&table->AttachSessionActionSets));
(get_inst_proc_addr(instance, "xrGetCurrentInteractionProfile", (PFN_xrVoidFunction*)&table->GetCurrentInteractionProfile));
(get_inst_proc_addr(instance, "xrGetActionStateBoolean", (PFN_xrVoidFunction*)&table->GetActionStateBoolean));
(get_inst_proc_addr(instance, "xrGetActionStateFloat", (PFN_xrVoidFunction*)&table->GetActionStateFloat));
(get_inst_proc_addr(instance, "xrGetActionStateVector2f", (PFN_xrVoidFunction*)&table->GetActionStateVector2f));
(get_inst_proc_addr(instance, "xrGetActionStatePose", (PFN_xrVoidFunction*)&table->GetActionStatePose));
(get_inst_proc_addr(instance, "xrSyncActions", (PFN_xrVoidFunction*)&table->SyncActions));
(get_inst_proc_addr(instance, "xrEnumerateBoundSourcesForAction", (PFN_xrVoidFunction*)&table->EnumerateBoundSourcesForAction));
(get_inst_proc_addr(instance, "xrGetInputSourceLocalizedName", (PFN_xrVoidFunction*)&table->GetInputSourceLocalizedName));
(get_inst_proc_addr(instance, "xrApplyHapticFeedback", (PFN_xrVoidFunction*)&table->ApplyHapticFeedback));
(get_inst_proc_addr(instance, "xrStopHapticFeedback", (PFN_xrVoidFunction*)&table->StopHapticFeedback));
// ---- XR_KHR_android_thread_settings extension commands
#if defined(XR_USE_PLATFORM_ANDROID)
(get_inst_proc_addr(instance, "xrSetAndroidApplicationThreadKHR", (PFN_xrVoidFunction*)&table->SetAndroidApplicationThreadKHR));
#endif // defined(XR_USE_PLATFORM_ANDROID)
// ---- XR_KHR_android_surface_swapchain extension commands
#if defined(XR_USE_PLATFORM_ANDROID)
(get_inst_proc_addr(instance, "xrCreateSwapchainAndroidSurfaceKHR", (PFN_xrVoidFunction*)&table->CreateSwapchainAndroidSurfaceKHR));
#endif // defined(XR_USE_PLATFORM_ANDROID)
// ---- XR_KHR_opengl_enable extension commands
#if defined(XR_USE_GRAPHICS_API_OPENGL)
(get_inst_proc_addr(instance, "xrGetOpenGLGraphicsRequirementsKHR", (PFN_xrVoidFunction*)&table->GetOpenGLGraphicsRequirementsKHR));
#endif // defined(XR_USE_GRAPHICS_API_OPENGL)
// ---- XR_KHR_opengl_es_enable extension commands
#if defined(XR_USE_GRAPHICS_API_OPENGL_ES)
(get_inst_proc_addr(instance, "xrGetOpenGLESGraphicsRequirementsKHR", (PFN_xrVoidFunction*)&table->GetOpenGLESGraphicsRequirementsKHR));
#endif // defined(XR_USE_GRAPHICS_API_OPENGL_ES)
// ---- XR_KHR_vulkan_enable extension commands
#if defined(XR_USE_GRAPHICS_API_VULKAN)
(get_inst_proc_addr(instance, "xrGetVulkanInstanceExtensionsKHR", (PFN_xrVoidFunction*)&table->GetVulkanInstanceExtensionsKHR));
#endif // defined(XR_USE_GRAPHICS_API_VULKAN)
#if defined(XR_USE_GRAPHICS_API_VULKAN)
(get_inst_proc_addr(instance, "xrGetVulkanDeviceExtensionsKHR", (PFN_xrVoidFunction*)&table->GetVulkanDeviceExtensionsKHR));
#endif // defined(XR_USE_GRAPHICS_API_VULKAN)
#if defined(XR_USE_GRAPHICS_API_VULKAN)
(get_inst_proc_addr(instance, "xrGetVulkanGraphicsDeviceKHR", (PFN_xrVoidFunction*)&table->GetVulkanGraphicsDeviceKHR));
#endif // defined(XR_USE_GRAPHICS_API_VULKAN)
#if defined(XR_USE_GRAPHICS_API_VULKAN)
(get_inst_proc_addr(instance, "xrGetVulkanGraphicsRequirementsKHR", (PFN_xrVoidFunction*)&table->GetVulkanGraphicsRequirementsKHR));
#endif // defined(XR_USE_GRAPHICS_API_VULKAN)
// ---- XR_KHR_D3D11_enable extension commands
#if defined(XR_USE_GRAPHICS_API_D3D11)
(get_inst_proc_addr(instance, "xrGetD3D11GraphicsRequirementsKHR", (PFN_xrVoidFunction*)&table->GetD3D11GraphicsRequirementsKHR));
#endif // defined(XR_USE_GRAPHICS_API_D3D11)
// ---- XR_KHR_D3D12_enable extension commands
#if defined(XR_USE_GRAPHICS_API_D3D12)
(get_inst_proc_addr(instance, "xrGetD3D12GraphicsRequirementsKHR", (PFN_xrVoidFunction*)&table->GetD3D12GraphicsRequirementsKHR));
#endif // defined(XR_USE_GRAPHICS_API_D3D12)
// ---- XR_KHR_visibility_mask extension commands
(get_inst_proc_addr(instance, "xrGetVisibilityMaskKHR", (PFN_xrVoidFunction*)&table->GetVisibilityMaskKHR));
// ---- XR_KHR_win32_convert_performance_counter_time extension commands
#if defined(XR_USE_PLATFORM_WIN32)
(get_inst_proc_addr(instance, "xrConvertWin32PerformanceCounterToTimeKHR", (PFN_xrVoidFunction*)&table->ConvertWin32PerformanceCounterToTimeKHR));
#endif // defined(XR_USE_PLATFORM_WIN32)
#if defined(XR_USE_PLATFORM_WIN32)
(get_inst_proc_addr(instance, "xrConvertTimeToWin32PerformanceCounterKHR", (PFN_xrVoidFunction*)&table->ConvertTimeToWin32PerformanceCounterKHR));
#endif // defined(XR_USE_PLATFORM_WIN32)
// ---- XR_KHR_convert_timespec_time extension commands
#if defined(XR_USE_TIMESPEC)
(get_inst_proc_addr(instance, "xrConvertTimespecTimeToTimeKHR", (PFN_xrVoidFunction*)&table->ConvertTimespecTimeToTimeKHR));
#endif // defined(XR_USE_TIMESPEC)
#if defined(XR_USE_TIMESPEC)
(get_inst_proc_addr(instance, "xrConvertTimeToTimespecTimeKHR", (PFN_xrVoidFunction*)&table->ConvertTimeToTimespecTimeKHR));
#endif // defined(XR_USE_TIMESPEC)
// ---- XR_EXT_performance_settings extension commands
(get_inst_proc_addr(instance, "xrPerfSettingsSetPerformanceLevelEXT", (PFN_xrVoidFunction*)&table->PerfSettingsSetPerformanceLevelEXT));
// ---- XR_EXT_thermal_query extension commands
(get_inst_proc_addr(instance, "xrThermalGetTemperatureTrendEXT", (PFN_xrVoidFunction*)&table->ThermalGetTemperatureTrendEXT));
// ---- XR_EXT_debug_utils extension commands
(get_inst_proc_addr(instance, "xrSetDebugUtilsObjectNameEXT", (PFN_xrVoidFunction*)&table->SetDebugUtilsObjectNameEXT));
(get_inst_proc_addr(instance, "xrCreateDebugUtilsMessengerEXT", (PFN_xrVoidFunction*)&table->CreateDebugUtilsMessengerEXT));
(get_inst_proc_addr(instance, "xrDestroyDebugUtilsMessengerEXT", (PFN_xrVoidFunction*)&table->DestroyDebugUtilsMessengerEXT));
(get_inst_proc_addr(instance, "xrSubmitDebugUtilsMessageEXT", (PFN_xrVoidFunction*)&table->SubmitDebugUtilsMessageEXT));
(get_inst_proc_addr(instance, "xrSessionBeginDebugUtilsLabelRegionEXT", (PFN_xrVoidFunction*)&table->SessionBeginDebugUtilsLabelRegionEXT));
(get_inst_proc_addr(instance, "xrSessionEndDebugUtilsLabelRegionEXT", (PFN_xrVoidFunction*)&table->SessionEndDebugUtilsLabelRegionEXT));
(get_inst_proc_addr(instance, "xrSessionInsertDebugUtilsLabelEXT", (PFN_xrVoidFunction*)&table->SessionInsertDebugUtilsLabelEXT));
}
#ifdef __cplusplus
} // extern "C"
#endif

View File

@@ -0,0 +1,181 @@
// *********** THIS FILE IS GENERATED - DO NOT EDIT ***********
// See utility_source_generator.py for modifications
// ************************************************************
// Copyright (c) 2017-2019 The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// 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.
//
// Author: Mark Young <marky@lunarg.com>
//
#pragma once
#include "xr_dependencies.h"
#include <openxr/openxr.h>
#include <openxr/openxr_platform.h>
#ifdef __cplusplus
extern "C" {
#endif
// Generated dispatch table
struct XrGeneratedDispatchTable {
// ---- Core 1.0 commands
PFN_xrGetInstanceProcAddr GetInstanceProcAddr;
PFN_xrEnumerateApiLayerProperties EnumerateApiLayerProperties;
PFN_xrEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties;
PFN_xrCreateInstance CreateInstance;
PFN_xrDestroyInstance DestroyInstance;
PFN_xrGetInstanceProperties GetInstanceProperties;
PFN_xrPollEvent PollEvent;
PFN_xrResultToString ResultToString;
PFN_xrStructureTypeToString StructureTypeToString;
PFN_xrGetSystem GetSystem;
PFN_xrGetSystemProperties GetSystemProperties;
PFN_xrEnumerateEnvironmentBlendModes EnumerateEnvironmentBlendModes;
PFN_xrCreateSession CreateSession;
PFN_xrDestroySession DestroySession;
PFN_xrEnumerateReferenceSpaces EnumerateReferenceSpaces;
PFN_xrCreateReferenceSpace CreateReferenceSpace;
PFN_xrGetReferenceSpaceBoundsRect GetReferenceSpaceBoundsRect;
PFN_xrCreateActionSpace CreateActionSpace;
PFN_xrLocateSpace LocateSpace;
PFN_xrDestroySpace DestroySpace;
PFN_xrEnumerateViewConfigurations EnumerateViewConfigurations;
PFN_xrGetViewConfigurationProperties GetViewConfigurationProperties;
PFN_xrEnumerateViewConfigurationViews EnumerateViewConfigurationViews;
PFN_xrEnumerateSwapchainFormats EnumerateSwapchainFormats;
PFN_xrCreateSwapchain CreateSwapchain;
PFN_xrDestroySwapchain DestroySwapchain;
PFN_xrEnumerateSwapchainImages EnumerateSwapchainImages;
PFN_xrAcquireSwapchainImage AcquireSwapchainImage;
PFN_xrWaitSwapchainImage WaitSwapchainImage;
PFN_xrReleaseSwapchainImage ReleaseSwapchainImage;
PFN_xrBeginSession BeginSession;
PFN_xrEndSession EndSession;
PFN_xrRequestExitSession RequestExitSession;
PFN_xrWaitFrame WaitFrame;
PFN_xrBeginFrame BeginFrame;
PFN_xrEndFrame EndFrame;
PFN_xrLocateViews LocateViews;
PFN_xrStringToPath StringToPath;
PFN_xrPathToString PathToString;
PFN_xrCreateActionSet CreateActionSet;
PFN_xrDestroyActionSet DestroyActionSet;
PFN_xrCreateAction CreateAction;
PFN_xrDestroyAction DestroyAction;
PFN_xrSuggestInteractionProfileBindings SuggestInteractionProfileBindings;
PFN_xrAttachSessionActionSets AttachSessionActionSets;
PFN_xrGetCurrentInteractionProfile GetCurrentInteractionProfile;
PFN_xrGetActionStateBoolean GetActionStateBoolean;
PFN_xrGetActionStateFloat GetActionStateFloat;
PFN_xrGetActionStateVector2f GetActionStateVector2f;
PFN_xrGetActionStatePose GetActionStatePose;
PFN_xrSyncActions SyncActions;
PFN_xrEnumerateBoundSourcesForAction EnumerateBoundSourcesForAction;
PFN_xrGetInputSourceLocalizedName GetInputSourceLocalizedName;
PFN_xrApplyHapticFeedback ApplyHapticFeedback;
PFN_xrStopHapticFeedback StopHapticFeedback;
// ---- XR_KHR_android_thread_settings extension commands
#if defined(XR_USE_PLATFORM_ANDROID)
PFN_xrSetAndroidApplicationThreadKHR SetAndroidApplicationThreadKHR;
#endif // defined(XR_USE_PLATFORM_ANDROID)
// ---- XR_KHR_android_surface_swapchain extension commands
#if defined(XR_USE_PLATFORM_ANDROID)
PFN_xrCreateSwapchainAndroidSurfaceKHR CreateSwapchainAndroidSurfaceKHR;
#endif // defined(XR_USE_PLATFORM_ANDROID)
// ---- XR_KHR_opengl_enable extension commands
#if defined(XR_USE_GRAPHICS_API_OPENGL)
PFN_xrGetOpenGLGraphicsRequirementsKHR GetOpenGLGraphicsRequirementsKHR;
#endif // defined(XR_USE_GRAPHICS_API_OPENGL)
// ---- XR_KHR_opengl_es_enable extension commands
#if defined(XR_USE_GRAPHICS_API_OPENGL_ES)
PFN_xrGetOpenGLESGraphicsRequirementsKHR GetOpenGLESGraphicsRequirementsKHR;
#endif // defined(XR_USE_GRAPHICS_API_OPENGL_ES)
// ---- XR_KHR_vulkan_enable extension commands
#if defined(XR_USE_GRAPHICS_API_VULKAN)
PFN_xrGetVulkanInstanceExtensionsKHR GetVulkanInstanceExtensionsKHR;
#endif // defined(XR_USE_GRAPHICS_API_VULKAN)
#if defined(XR_USE_GRAPHICS_API_VULKAN)
PFN_xrGetVulkanDeviceExtensionsKHR GetVulkanDeviceExtensionsKHR;
#endif // defined(XR_USE_GRAPHICS_API_VULKAN)
#if defined(XR_USE_GRAPHICS_API_VULKAN)
PFN_xrGetVulkanGraphicsDeviceKHR GetVulkanGraphicsDeviceKHR;
#endif // defined(XR_USE_GRAPHICS_API_VULKAN)
#if defined(XR_USE_GRAPHICS_API_VULKAN)
PFN_xrGetVulkanGraphicsRequirementsKHR GetVulkanGraphicsRequirementsKHR;
#endif // defined(XR_USE_GRAPHICS_API_VULKAN)
// ---- XR_KHR_D3D11_enable extension commands
#if defined(XR_USE_GRAPHICS_API_D3D11)
PFN_xrGetD3D11GraphicsRequirementsKHR GetD3D11GraphicsRequirementsKHR;
#endif // defined(XR_USE_GRAPHICS_API_D3D11)
// ---- XR_KHR_D3D12_enable extension commands
#if defined(XR_USE_GRAPHICS_API_D3D12)
PFN_xrGetD3D12GraphicsRequirementsKHR GetD3D12GraphicsRequirementsKHR;
#endif // defined(XR_USE_GRAPHICS_API_D3D12)
// ---- XR_KHR_visibility_mask extension commands
PFN_xrGetVisibilityMaskKHR GetVisibilityMaskKHR;
// ---- XR_KHR_win32_convert_performance_counter_time extension commands
#if defined(XR_USE_PLATFORM_WIN32)
PFN_xrConvertWin32PerformanceCounterToTimeKHR ConvertWin32PerformanceCounterToTimeKHR;
#endif // defined(XR_USE_PLATFORM_WIN32)
#if defined(XR_USE_PLATFORM_WIN32)
PFN_xrConvertTimeToWin32PerformanceCounterKHR ConvertTimeToWin32PerformanceCounterKHR;
#endif // defined(XR_USE_PLATFORM_WIN32)
// ---- XR_KHR_convert_timespec_time extension commands
#if defined(XR_USE_TIMESPEC)
PFN_xrConvertTimespecTimeToTimeKHR ConvertTimespecTimeToTimeKHR;
#endif // defined(XR_USE_TIMESPEC)
#if defined(XR_USE_TIMESPEC)
PFN_xrConvertTimeToTimespecTimeKHR ConvertTimeToTimespecTimeKHR;
#endif // defined(XR_USE_TIMESPEC)
// ---- XR_EXT_performance_settings extension commands
PFN_xrPerfSettingsSetPerformanceLevelEXT PerfSettingsSetPerformanceLevelEXT;
// ---- XR_EXT_thermal_query extension commands
PFN_xrThermalGetTemperatureTrendEXT ThermalGetTemperatureTrendEXT;
// ---- XR_EXT_debug_utils extension commands
PFN_xrSetDebugUtilsObjectNameEXT SetDebugUtilsObjectNameEXT;
PFN_xrCreateDebugUtilsMessengerEXT CreateDebugUtilsMessengerEXT;
PFN_xrDestroyDebugUtilsMessengerEXT DestroyDebugUtilsMessengerEXT;
PFN_xrSubmitDebugUtilsMessageEXT SubmitDebugUtilsMessageEXT;
PFN_xrSessionBeginDebugUtilsLabelRegionEXT SessionBeginDebugUtilsLabelRegionEXT;
PFN_xrSessionEndDebugUtilsLabelRegionEXT SessionEndDebugUtilsLabelRegionEXT;
PFN_xrSessionInsertDebugUtilsLabelEXT SessionInsertDebugUtilsLabelEXT;
};
// Prototype for dispatch table helper function
void GeneratedXrPopulateDispatchTable(struct XrGeneratedDispatchTable *table,
XrInstance instance,
PFN_xrGetInstanceProcAddr get_inst_proc_addr);
#ifdef __cplusplus
} // extern "C"
#endif

View File

@@ -0,0 +1,488 @@
// *********** THIS FILE IS GENERATED - DO NOT EDIT ***********
// See utility_source_generator.py for modifications
// ************************************************************
// Copyright (c) 2017-2019 The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// 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.
//
// Author: Mark Young <marky@lunarg.com>
//
#ifdef _WIN32
// Disable Windows warning about using strncpy_s instead of strncpy
#define _CRT_SECURE_NO_WARNINGS 1
#endif // _WIN32
#include "xr_generated_utilities.h"
#include <openxr/openxr.h>
#include <stdio.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
XrResult GeneratedXrUtilitiesResultToString(XrResult result,
char buffer[XR_MAX_RESULT_STRING_SIZE]) {
if (NULL == buffer) {
return XR_ERROR_VALIDATION_FAILURE;
}
XrResult int_result = XR_SUCCESS;
switch (result) {
case XR_SUCCESS:
strncpy(buffer, "XR_SUCCESS", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_TIMEOUT_EXPIRED:
strncpy(buffer, "XR_TIMEOUT_EXPIRED", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_SESSION_LOSS_PENDING:
strncpy(buffer, "XR_SESSION_LOSS_PENDING", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_EVENT_UNAVAILABLE:
strncpy(buffer, "XR_EVENT_UNAVAILABLE", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_SPACE_BOUNDS_UNAVAILABLE:
strncpy(buffer, "XR_SPACE_BOUNDS_UNAVAILABLE", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_SESSION_NOT_FOCUSED:
strncpy(buffer, "XR_SESSION_NOT_FOCUSED", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_FRAME_DISCARDED:
strncpy(buffer, "XR_FRAME_DISCARDED", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_VALIDATION_FAILURE:
strncpy(buffer, "XR_ERROR_VALIDATION_FAILURE", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_RUNTIME_FAILURE:
strncpy(buffer, "XR_ERROR_RUNTIME_FAILURE", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_OUT_OF_MEMORY:
strncpy(buffer, "XR_ERROR_OUT_OF_MEMORY", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_API_VERSION_UNSUPPORTED:
strncpy(buffer, "XR_ERROR_API_VERSION_UNSUPPORTED", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_INITIALIZATION_FAILED:
strncpy(buffer, "XR_ERROR_INITIALIZATION_FAILED", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_FUNCTION_UNSUPPORTED:
strncpy(buffer, "XR_ERROR_FUNCTION_UNSUPPORTED", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_FEATURE_UNSUPPORTED:
strncpy(buffer, "XR_ERROR_FEATURE_UNSUPPORTED", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_EXTENSION_NOT_PRESENT:
strncpy(buffer, "XR_ERROR_EXTENSION_NOT_PRESENT", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_LIMIT_REACHED:
strncpy(buffer, "XR_ERROR_LIMIT_REACHED", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_SIZE_INSUFFICIENT:
strncpy(buffer, "XR_ERROR_SIZE_INSUFFICIENT", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_HANDLE_INVALID:
strncpy(buffer, "XR_ERROR_HANDLE_INVALID", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_INSTANCE_LOST:
strncpy(buffer, "XR_ERROR_INSTANCE_LOST", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_SESSION_RUNNING:
strncpy(buffer, "XR_ERROR_SESSION_RUNNING", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_SESSION_NOT_RUNNING:
strncpy(buffer, "XR_ERROR_SESSION_NOT_RUNNING", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_SESSION_LOST:
strncpy(buffer, "XR_ERROR_SESSION_LOST", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_SYSTEM_INVALID:
strncpy(buffer, "XR_ERROR_SYSTEM_INVALID", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_PATH_INVALID:
strncpy(buffer, "XR_ERROR_PATH_INVALID", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_PATH_COUNT_EXCEEDED:
strncpy(buffer, "XR_ERROR_PATH_COUNT_EXCEEDED", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_PATH_FORMAT_INVALID:
strncpy(buffer, "XR_ERROR_PATH_FORMAT_INVALID", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_PATH_UNSUPPORTED:
strncpy(buffer, "XR_ERROR_PATH_UNSUPPORTED", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_LAYER_INVALID:
strncpy(buffer, "XR_ERROR_LAYER_INVALID", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_LAYER_LIMIT_EXCEEDED:
strncpy(buffer, "XR_ERROR_LAYER_LIMIT_EXCEEDED", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_SWAPCHAIN_RECT_INVALID:
strncpy(buffer, "XR_ERROR_SWAPCHAIN_RECT_INVALID", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_SWAPCHAIN_FORMAT_UNSUPPORTED:
strncpy(buffer, "XR_ERROR_SWAPCHAIN_FORMAT_UNSUPPORTED", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_ACTION_TYPE_MISMATCH:
strncpy(buffer, "XR_ERROR_ACTION_TYPE_MISMATCH", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_SESSION_NOT_READY:
strncpy(buffer, "XR_ERROR_SESSION_NOT_READY", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_SESSION_NOT_STOPPING:
strncpy(buffer, "XR_ERROR_SESSION_NOT_STOPPING", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_TIME_INVALID:
strncpy(buffer, "XR_ERROR_TIME_INVALID", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_REFERENCE_SPACE_UNSUPPORTED:
strncpy(buffer, "XR_ERROR_REFERENCE_SPACE_UNSUPPORTED", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_FILE_ACCESS_ERROR:
strncpy(buffer, "XR_ERROR_FILE_ACCESS_ERROR", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_FILE_CONTENTS_INVALID:
strncpy(buffer, "XR_ERROR_FILE_CONTENTS_INVALID", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_FORM_FACTOR_UNSUPPORTED:
strncpy(buffer, "XR_ERROR_FORM_FACTOR_UNSUPPORTED", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_FORM_FACTOR_UNAVAILABLE:
strncpy(buffer, "XR_ERROR_FORM_FACTOR_UNAVAILABLE", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_API_LAYER_NOT_PRESENT:
strncpy(buffer, "XR_ERROR_API_LAYER_NOT_PRESENT", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_CALL_ORDER_INVALID:
strncpy(buffer, "XR_ERROR_CALL_ORDER_INVALID", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_GRAPHICS_DEVICE_INVALID:
strncpy(buffer, "XR_ERROR_GRAPHICS_DEVICE_INVALID", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_POSE_INVALID:
strncpy(buffer, "XR_ERROR_POSE_INVALID", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_INDEX_OUT_OF_RANGE:
strncpy(buffer, "XR_ERROR_INDEX_OUT_OF_RANGE", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED:
strncpy(buffer, "XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_ENVIRONMENT_BLEND_MODE_UNSUPPORTED:
strncpy(buffer, "XR_ERROR_ENVIRONMENT_BLEND_MODE_UNSUPPORTED", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_NAME_DUPLICATED:
strncpy(buffer, "XR_ERROR_NAME_DUPLICATED", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_NAME_INVALID:
strncpy(buffer, "XR_ERROR_NAME_INVALID", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_ACTIONSET_NOT_ATTACHED:
strncpy(buffer, "XR_ERROR_ACTIONSET_NOT_ATTACHED", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_ACTIONSETS_ALREADY_ATTACHED:
strncpy(buffer, "XR_ERROR_ACTIONSETS_ALREADY_ATTACHED", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_LOCALIZED_NAME_DUPLICATED:
strncpy(buffer, "XR_ERROR_LOCALIZED_NAME_DUPLICATED", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_LOCALIZED_NAME_INVALID:
strncpy(buffer, "XR_ERROR_LOCALIZED_NAME_INVALID", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_ANDROID_THREAD_SETTINGS_ID_INVALID_KHR:
strncpy(buffer, "XR_ERROR_ANDROID_THREAD_SETTINGS_ID_INVALID_KHR", XR_MAX_RESULT_STRING_SIZE);
break;
case XR_ERROR_ANDROID_THREAD_SETTINGS_FAILURE_KHR:
strncpy(buffer, "XR_ERROR_ANDROID_THREAD_SETTINGS_FAILURE_KHR", XR_MAX_RESULT_STRING_SIZE);
break;
default:
// Unknown result type
if (XR_SUCCEEDED(result)) {
snprintf(buffer, XR_MAX_RESULT_STRING_SIZE, "XR_UNKNOWN_SUCCESS_%d", result);
} else {
snprintf(buffer, XR_MAX_RESULT_STRING_SIZE, "XR_UNKNOWN_FAILURE_%d", result);
}
int_result = XR_ERROR_VALIDATION_FAILURE;
break;
}
return int_result;
}
XrResult GeneratedXrUtilitiesStructureTypeToString(XrStructureType struct_type,
char buffer[XR_MAX_STRUCTURE_NAME_SIZE]) {
if (NULL == buffer) {
return XR_ERROR_VALIDATION_FAILURE;
}
XrResult int_result = XR_SUCCESS;
switch (struct_type) {
case XR_TYPE_UNKNOWN:
strncpy(buffer, "XR_TYPE_UNKNOWN", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_API_LAYER_PROPERTIES:
strncpy(buffer, "XR_TYPE_API_LAYER_PROPERTIES", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_EXTENSION_PROPERTIES:
strncpy(buffer, "XR_TYPE_EXTENSION_PROPERTIES", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_INSTANCE_CREATE_INFO:
strncpy(buffer, "XR_TYPE_INSTANCE_CREATE_INFO", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_SYSTEM_GET_INFO:
strncpy(buffer, "XR_TYPE_SYSTEM_GET_INFO", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_SYSTEM_PROPERTIES:
strncpy(buffer, "XR_TYPE_SYSTEM_PROPERTIES", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_VIEW_LOCATE_INFO:
strncpy(buffer, "XR_TYPE_VIEW_LOCATE_INFO", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_VIEW:
strncpy(buffer, "XR_TYPE_VIEW", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_SESSION_CREATE_INFO:
strncpy(buffer, "XR_TYPE_SESSION_CREATE_INFO", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_SWAPCHAIN_CREATE_INFO:
strncpy(buffer, "XR_TYPE_SWAPCHAIN_CREATE_INFO", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_SESSION_BEGIN_INFO:
strncpy(buffer, "XR_TYPE_SESSION_BEGIN_INFO", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_VIEW_STATE:
strncpy(buffer, "XR_TYPE_VIEW_STATE", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_FRAME_END_INFO:
strncpy(buffer, "XR_TYPE_FRAME_END_INFO", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_HAPTIC_VIBRATION:
strncpy(buffer, "XR_TYPE_HAPTIC_VIBRATION", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_EVENT_DATA_BUFFER:
strncpy(buffer, "XR_TYPE_EVENT_DATA_BUFFER", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING:
strncpy(buffer, "XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED:
strncpy(buffer, "XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_ACTION_STATE_BOOLEAN:
strncpy(buffer, "XR_TYPE_ACTION_STATE_BOOLEAN", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_ACTION_STATE_FLOAT:
strncpy(buffer, "XR_TYPE_ACTION_STATE_FLOAT", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_ACTION_STATE_VECTOR2F:
strncpy(buffer, "XR_TYPE_ACTION_STATE_VECTOR2F", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_ACTION_STATE_POSE:
strncpy(buffer, "XR_TYPE_ACTION_STATE_POSE", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_ACTION_SET_CREATE_INFO:
strncpy(buffer, "XR_TYPE_ACTION_SET_CREATE_INFO", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_ACTION_CREATE_INFO:
strncpy(buffer, "XR_TYPE_ACTION_CREATE_INFO", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_INSTANCE_PROPERTIES:
strncpy(buffer, "XR_TYPE_INSTANCE_PROPERTIES", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_FRAME_WAIT_INFO:
strncpy(buffer, "XR_TYPE_FRAME_WAIT_INFO", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_COMPOSITION_LAYER_PROJECTION:
strncpy(buffer, "XR_TYPE_COMPOSITION_LAYER_PROJECTION", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_COMPOSITION_LAYER_QUAD:
strncpy(buffer, "XR_TYPE_COMPOSITION_LAYER_QUAD", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_REFERENCE_SPACE_CREATE_INFO:
strncpy(buffer, "XR_TYPE_REFERENCE_SPACE_CREATE_INFO", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_ACTION_SPACE_CREATE_INFO:
strncpy(buffer, "XR_TYPE_ACTION_SPACE_CREATE_INFO", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING:
strncpy(buffer, "XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_VIEW_CONFIGURATION_VIEW:
strncpy(buffer, "XR_TYPE_VIEW_CONFIGURATION_VIEW", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_SPACE_LOCATION:
strncpy(buffer, "XR_TYPE_SPACE_LOCATION", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_SPACE_VELOCITY:
strncpy(buffer, "XR_TYPE_SPACE_VELOCITY", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_FRAME_STATE:
strncpy(buffer, "XR_TYPE_FRAME_STATE", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_VIEW_CONFIGURATION_PROPERTIES:
strncpy(buffer, "XR_TYPE_VIEW_CONFIGURATION_PROPERTIES", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_FRAME_BEGIN_INFO:
strncpy(buffer, "XR_TYPE_FRAME_BEGIN_INFO", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW:
strncpy(buffer, "XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_EVENT_DATA_EVENTS_LOST:
strncpy(buffer, "XR_TYPE_EVENT_DATA_EVENTS_LOST", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING:
strncpy(buffer, "XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED:
strncpy(buffer, "XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_INTERACTION_PROFILE_STATE:
strncpy(buffer, "XR_TYPE_INTERACTION_PROFILE_STATE", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO:
strncpy(buffer, "XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO:
strncpy(buffer, "XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO:
strncpy(buffer, "XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_ACTION_STATE_GET_INFO:
strncpy(buffer, "XR_TYPE_ACTION_STATE_GET_INFO", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_HAPTIC_ACTION_INFO:
strncpy(buffer, "XR_TYPE_HAPTIC_ACTION_INFO", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO:
strncpy(buffer, "XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_ACTIONS_SYNC_INFO:
strncpy(buffer, "XR_TYPE_ACTIONS_SYNC_INFO", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO:
strncpy(buffer, "XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_INPUT_SOURCE_LOCALIZED_NAME_GET_INFO:
strncpy(buffer, "XR_TYPE_INPUT_SOURCE_LOCALIZED_NAME_GET_INFO", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_COMPOSITION_LAYER_CUBE_KHR:
strncpy(buffer, "XR_TYPE_COMPOSITION_LAYER_CUBE_KHR", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR:
strncpy(buffer, "XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR:
strncpy(buffer, "XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_VULKAN_SWAPCHAIN_FORMAT_LIST_CREATE_INFO_KHR:
strncpy(buffer, "XR_TYPE_VULKAN_SWAPCHAIN_FORMAT_LIST_CREATE_INFO_KHR", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_EVENT_DATA_PERF_SETTINGS_EXT:
strncpy(buffer, "XR_TYPE_EVENT_DATA_PERF_SETTINGS_EXT", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR:
strncpy(buffer, "XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_COMPOSITION_LAYER_EQUIRECT_KHR:
strncpy(buffer, "XR_TYPE_COMPOSITION_LAYER_EQUIRECT_KHR", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT:
strncpy(buffer, "XR_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT:
strncpy(buffer, "XR_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT:
strncpy(buffer, "XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_DEBUG_UTILS_LABEL_EXT:
strncpy(buffer, "XR_TYPE_DEBUG_UTILS_LABEL_EXT", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR:
strncpy(buffer, "XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR:
strncpy(buffer, "XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_GRAPHICS_BINDING_OPENGL_XCB_KHR:
strncpy(buffer, "XR_TYPE_GRAPHICS_BINDING_OPENGL_XCB_KHR", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_GRAPHICS_BINDING_OPENGL_WAYLAND_KHR:
strncpy(buffer, "XR_TYPE_GRAPHICS_BINDING_OPENGL_WAYLAND_KHR", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR:
strncpy(buffer, "XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR:
strncpy(buffer, "XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR:
strncpy(buffer, "XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR:
strncpy(buffer, "XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR:
strncpy(buffer, "XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR:
strncpy(buffer, "XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR:
strncpy(buffer, "XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR:
strncpy(buffer, "XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_GRAPHICS_BINDING_D3D11_KHR:
strncpy(buffer, "XR_TYPE_GRAPHICS_BINDING_D3D11_KHR", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_SWAPCHAIN_IMAGE_D3D11_KHR:
strncpy(buffer, "XR_TYPE_SWAPCHAIN_IMAGE_D3D11_KHR", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_GRAPHICS_REQUIREMENTS_D3D11_KHR:
strncpy(buffer, "XR_TYPE_GRAPHICS_REQUIREMENTS_D3D11_KHR", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_GRAPHICS_BINDING_D3D12_KHR:
strncpy(buffer, "XR_TYPE_GRAPHICS_BINDING_D3D12_KHR", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_SWAPCHAIN_IMAGE_D3D12_KHR:
strncpy(buffer, "XR_TYPE_SWAPCHAIN_IMAGE_D3D12_KHR", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_GRAPHICS_REQUIREMENTS_D3D12_KHR:
strncpy(buffer, "XR_TYPE_GRAPHICS_REQUIREMENTS_D3D12_KHR", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_VISIBILITY_MASK_KHR:
strncpy(buffer, "XR_TYPE_VISIBILITY_MASK_KHR", XR_MAX_STRUCTURE_NAME_SIZE);
break;
case XR_TYPE_EVENT_DATA_VISIBILITY_MASK_CHANGED_KHR:
strncpy(buffer, "XR_TYPE_EVENT_DATA_VISIBILITY_MASK_CHANGED_KHR", XR_MAX_STRUCTURE_NAME_SIZE);
break;
default:
// Unknown structure type
snprintf(buffer, XR_MAX_STRUCTURE_NAME_SIZE, "XR_UNKNOWN_STRUCTURE_TYPE_%d", struct_type);
int_result = XR_ERROR_VALIDATION_FAILURE;
break;
}
return int_result;
}
#ifdef __cplusplus
} // extern "C"
#endif

View File

@@ -0,0 +1,43 @@
// *********** THIS FILE IS GENERATED - DO NOT EDIT ***********
// See utility_source_generator.py for modifications
// ************************************************************
// Copyright (c) 2017-2019 The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// 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.
//
// Author: Mark Young <marky@lunarg.com>
//
#pragma once
#include <openxr/openxr.h>
#ifdef __cplusplus
extern "C" {
#endif
XrResult GeneratedXrUtilitiesResultToString(XrResult result,
char buffer[XR_MAX_RESULT_STRING_SIZE]);
XrResult GeneratedXrUtilitiesStructureTypeToString(XrStructureType struct_type,
char buffer[XR_MAX_STRUCTURE_NAME_SIZE]);
#ifdef __cplusplus
} // extern "C"
#endif
// Current API version of the utililties
#define XR_UTILITIES_API_VERSION XR_CURRENT_API_VERSION

View File

@@ -270,11 +270,13 @@ elseif(WIN32)
)
list(APPEND SRC
intern/GHOST_ContextD3D.cpp
intern/GHOST_DisplayManagerWin32.cpp
intern/GHOST_DropTargetWin32.cpp
intern/GHOST_SystemWin32.cpp
intern/GHOST_WindowWin32.cpp
intern/GHOST_ContextD3D.h
intern/GHOST_DisplayManagerWin32.h
intern/GHOST_DropTargetWin32.h
intern/GHOST_SystemWin32.h
@@ -345,6 +347,43 @@ elseif(WIN32)
endif()
if(WITH_OPENXR)
list(APPEND SRC
intern/GHOST_Xr.cpp
intern/GHOST_XrContext.cpp
intern/GHOST_XrEvent.cpp
intern/GHOST_XrGraphicsBinding.cpp
intern/GHOST_XrSession.cpp
GHOST_IXrContext.h
intern/GHOST_Xr_intern.h
intern/GHOST_Xr_openxr_includes.h
intern/GHOST_XrContext.h
intern/GHOST_IXrGraphicsBinding.h
intern/GHOST_XrSession.h
)
list(APPEND INC
)
list(APPEND INC_SYS
${OPENXR_SDK_INCLUDES}
)
include(xr_platform_defines)
if(OPENXR_USE_BUNDLED_SRC)
if(WIN32)
set(OPENXR_LOADER_NAME openxr_loader-1_0)
else()
set(OPENXR_LOADER_NAME openxr_loader)
endif()
list(APPEND LIB ${OPENXR_LOADER_NAME})
list(APPEND INC ../../extern/openxr/include)
endif()
add_definitions(-DWITH_OPENXR)
endif()
add_definitions(${GL_DEFINITIONS})
blender_add_lib(bf_intern_ghost "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")

View File

@@ -30,21 +30,6 @@
extern "C" {
#endif
/**
* Creates a "handle" for a C++ GHOST object.
* A handle is just an opaque pointer to an empty struct.
* In the API the pointer is cast to the actual C++ class.
* The 'name' argument to the macro is the name of the handle to create.
*/
GHOST_DECLARE_HANDLE(GHOST_SystemHandle);
GHOST_DECLARE_HANDLE(GHOST_TimerTaskHandle);
GHOST_DECLARE_HANDLE(GHOST_WindowHandle);
GHOST_DECLARE_HANDLE(GHOST_EventHandle);
GHOST_DECLARE_HANDLE(GHOST_RectangleHandle);
GHOST_DECLARE_HANDLE(GHOST_EventConsumerHandle);
GHOST_DECLARE_HANDLE(GHOST_ContextHandle);
/**
* Definition of a callback routine that receives events.
* \param event The event received.
@@ -193,6 +178,36 @@ extern GHOST_ContextHandle GHOST_CreateOpenGLContext(GHOST_SystemHandle systemha
extern GHOST_TSuccess GHOST_DisposeOpenGLContext(GHOST_SystemHandle systemhandle,
GHOST_ContextHandle contexthandle);
#ifdef WIN32
/**
* Create a new offscreen context.
* Never explicitly delete the context, use disposeContext() instead.
* \param systemhandle The handle to the system
* \return A handle to the new context ( == NULL if creation failed).
*/
GHOST_ContextHandle GHOST_CreateDirectXContext(GHOST_SystemHandle systemhandle);
/**
* Dispose of a context.
* \param systemhandle The handle to the system
* \param contexthandle Handle to the context to be disposed.
* \return Indication of success.
*/
GHOST_TSuccess GHOST_DisposeDirectXContext(GHOST_SystemHandle systemhandle,
GHOST_ContextHandle contexthandle);
#endif
GHOST_TSuccess GHOST_BlitOpenGLOffscreenContext(GHOST_WindowHandle windowhandle,
GHOST_ContextHandle offscreen_contexthandle);
extern GHOST_TSuccess GHOST_ContextBlitOpenGLOffscreenContext(
GHOST_ContextHandle onscreen_contexthandle,
GHOST_ContextHandle offscreen_contexthandle,
GHOST_TInt32 width,
GHOST_TInt32 height);
extern GHOST_ContextHandle GHOST_GetWindowContext(GHOST_WindowHandle windowhandle);
/**
* Returns the window user data.
* \param windowhandle The handle to the window
@@ -207,6 +222,11 @@ extern GHOST_TUserDataPtr GHOST_GetWindowUserData(GHOST_WindowHandle windowhandl
*/
extern void GHOST_SetWindowUserData(GHOST_WindowHandle windowhandle, GHOST_TUserDataPtr userdata);
/**
* Returns whether a window is rendered upside down compared to OpenGL.
*/
extern int GHOST_isUpsideDownWindow(GHOST_WindowHandle windowhandle);
/**
* Dispose a window.
* \param systemhandle The handle to the system
@@ -662,6 +682,13 @@ extern GHOST_TSuccess GHOST_SetWindowOrder(GHOST_WindowHandle windowhandle,
*/
extern GHOST_TSuccess GHOST_SwapWindowBuffers(GHOST_WindowHandle windowhandle);
/**
* Swaps front and back buffers of a context.
* \param contexthandle The handle to the context
* \return A success indicator.
*/
extern GHOST_TSuccess GHOST_SwapContextBuffers(GHOST_ContextHandle contexthandle);
/**
* Sets the swap interval for swapBuffers.
* \param interval The swap interval to use.
@@ -706,6 +733,16 @@ extern GHOST_TSuccess GHOST_ActivateOpenGLContext(GHOST_ContextHandle contexthan
*/
extern GHOST_TSuccess GHOST_ReleaseOpenGLContext(GHOST_ContextHandle contexthandle);
/**
* Get the OpenGL framebuffer handle that serves as a default framebuffer.
*/
extern unsigned int GHOST_GetContextDefaultOpenGLFramebuffer(GHOST_ContextHandle contexthandle);
/**
* Returns whether a context is rendered upside down compared to OpenGL.
*/
extern int GHOST_isUpsideDownContext(GHOST_ContextHandle contexthandle);
/**
* Get the OpenGL framebuffer handle that serves as a default framebuffer.
*/
@@ -941,6 +978,37 @@ extern void GHOST_BeginIME(GHOST_WindowHandle windowhandle,
*/
extern void GHOST_EndIME(GHOST_WindowHandle windowhandle);
#ifdef WITH_OPENXR
/* xr-context */
/**
* Set a custom callback to be executed whenever an error occurs. Should be set before calling
* #GHOST_XrContextCreate().
*/
void GHOST_XrErrorHandler(GHOST_XrErrorHandlerFn handler_fn, void *customdata);
GHOST_XrContextHandle GHOST_XrContextCreate(const GHOST_XrContextCreateInfo *create_info);
void GHOST_XrContextDestroy(GHOST_XrContextHandle xr_context);
void GHOST_XrGraphicsContextBindFuncs(GHOST_XrContextHandle xr_context,
GHOST_XrGraphicsContextBindFn bind_fn,
GHOST_XrGraphicsContextUnbindFn unbind_fn);
void GHOST_XrDrawViewFunc(GHOST_XrContextHandle xr_context, GHOST_XrDrawViewFn draw_view_fn);
/* sessions */
void GHOST_XrSessionStart(GHOST_XrContextHandle xr_context,
const GHOST_XrSessionBeginInfo *begin_info);
void GHOST_XrSessionEnd(GHOST_XrContextHandle xr_context);
int GHOST_XrHasSession(const GHOST_XrContextHandle xr_contexthandle);
int GHOST_XrSessionShouldRunDrawLoop(const GHOST_XrContextHandle xr_context);
void GHOST_XrSessionDrawViews(GHOST_XrContextHandle xr_context, void *customdata);
/* events */
GHOST_TSuccess GHOST_XrEventsHandle(GHOST_XrContextHandle xr_context);
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -56,6 +56,16 @@ class GHOST_IContext {
*/
virtual GHOST_TSuccess releaseDrawingContext() = 0;
virtual GHOST_TSuccess blitOpenGLOffscreenContext(class GHOST_Context *offscreen,
GHOST_TInt32 width,
GHOST_TInt32 height) = 0;
virtual unsigned int getDefaultFramebuffer() = 0;
virtual GHOST_TSuccess swapBuffers() = 0;
virtual bool isUpsideDown() const = 0;
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("GHOST:GHOST_IContext")
#endif

View File

@@ -264,6 +264,12 @@ class GHOST_ISystem {
*/
virtual GHOST_IContext *createOffscreenContext() = 0;
/**
* Overload to allow requesting a different context type. By default only OpenGL is supported.
* However by explicitly overloading this a system may add support for others.
*/
virtual GHOST_IContext *createOffscreenContext(GHOST_TDrawingContextType type) = 0;
/**
* Dispose of a context.
* \param context Pointer to the context to be disposed.

View File

@@ -77,6 +77,10 @@ class GHOST_IWindow {
*/
virtual GHOST_TSuccess setDrawingContextType(GHOST_TDrawingContextType type) = 0;
virtual class GHOST_IContext *getDrawingContext() = 0;
virtual GHOST_TSuccess blitOpenGLOffscreenContext(GHOST_IContext *offscreen) = 0;
/**
* Sets the title displayed in the title bar.
* \param title The title to display in the title bar.
@@ -241,6 +245,11 @@ class GHOST_IWindow {
*/
virtual void setUserData(const GHOST_TUserDataPtr userData) = 0;
/**
* Returns if the window is rendered upside down compared to OpenGL.
*/
virtual bool isUpsideDown() const = 0;
/**
* Returns the tablet data (pressure etc).
* \return The tablet data (pressure etc).

View File

@@ -0,0 +1,43 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/** \file
* \ingroup GHOST
*/
#ifndef __GHOST_IXRCONTEXT_H__
#define __GHOST_IXRCONTEXT_H__
#include "GHOST_Types.h"
class GHOST_IXrContext {
public:
virtual ~GHOST_IXrContext() = default;
virtual void startSession(const GHOST_XrSessionBeginInfo *begin_info) = 0;
virtual void endSession() = 0;
virtual bool hasSession() const = 0;
virtual bool shouldRunSessionDrawLoop() const = 0;
virtual void drawSessionViews(void *draw_customdata) = 0;
virtual void dispatchErrorMessage(const class GHOST_XrException *) const = 0;
virtual void setGraphicsContextBindFuncs(GHOST_XrGraphicsContextBindFn bind_fn,
GHOST_XrGraphicsContextUnbindFn unbind_fn) = 0;
virtual void setDrawViewFunc(GHOST_XrDrawViewFn draw_view_fn) = 0;
};
#endif // __GHOST_IXRCONTEXT_H__

View File

@@ -41,6 +41,22 @@
} * name
#endif
/**
* Creates a "handle" for a C++ GHOST object.
* A handle is just an opaque pointer to an empty struct.
* In the API the pointer is cast to the actual C++ class.
* The 'name' argument to the macro is the name of the handle to create.
*/
GHOST_DECLARE_HANDLE(GHOST_SystemHandle);
GHOST_DECLARE_HANDLE(GHOST_TimerTaskHandle);
GHOST_DECLARE_HANDLE(GHOST_WindowHandle);
GHOST_DECLARE_HANDLE(GHOST_EventHandle);
GHOST_DECLARE_HANDLE(GHOST_RectangleHandle);
GHOST_DECLARE_HANDLE(GHOST_EventConsumerHandle);
GHOST_DECLARE_HANDLE(GHOST_ContextHandle);
GHOST_DECLARE_HANDLE(GHOST_XrContextHandle);
typedef char GHOST_TInt8;
typedef unsigned char GHOST_TUns8;
typedef short GHOST_TInt16;
@@ -129,7 +145,10 @@ typedef enum { GHOST_kWindowOrderTop = 0, GHOST_kWindowOrderBottom } GHOST_TWind
typedef enum {
GHOST_kDrawingContextTypeNone = 0,
GHOST_kDrawingContextTypeOpenGL
GHOST_kDrawingContextTypeOpenGL,
#ifdef WIN32
GHOST_kDrawingContextTypeD3D,
#endif
} GHOST_TDrawingContextType;
typedef enum {
@@ -542,4 +561,84 @@ struct GHOST_TimerTaskHandle__;
typedef void (*GHOST_TimerProcPtr)(struct GHOST_TimerTaskHandle__ *task, GHOST_TUns64 time);
#endif
#ifdef WITH_OPENXR
/**
* The XR view (i.e. the OpenXR runtime) may require a different graphics library than OpenGL. An
* offscreen texture of the viewport will then be drawn into using OpenGL, but the final texture
* draw call will happen through another lib (say DirectX).
*
* This enum defines the possible graphics bindings to attempt to enable.
*/
typedef enum {
GHOST_kXrGraphicsUnknown = 0,
GHOST_kXrGraphicsOpenGL,
# ifdef WIN32
GHOST_kXrGraphicsD3D11,
# endif
/* For later */
// GHOST_kXrGraphicsVulkan,
} GHOST_TXrGraphicsBinding;
/* An array of GHOST_TXrGraphicsBinding items defining the candidate bindings to use. The first
* available candidate will be chosen, so order defines priority. */
typedef const GHOST_TXrGraphicsBinding *GHOST_XrGraphicsBindingCandidates;
typedef struct {
float position[3];
/* Blender convention (w, x, y, z) */
float orientation_quat[4];
} GHOST_XrPose;
enum {
GHOST_kXrContextDebug = (1 << 0),
GHOST_kXrContextDebugTime = (1 << 1),
};
typedef struct {
const GHOST_XrGraphicsBindingCandidates gpu_binding_candidates;
unsigned int gpu_binding_candidates_count;
unsigned int context_flag;
} GHOST_XrContextCreateInfo;
typedef struct {
GHOST_XrPose base_pose;
} GHOST_XrSessionBeginInfo;
typedef struct {
int ofsx, ofsy;
int width, height;
GHOST_XrPose pose;
struct {
float angle_left, angle_right;
float angle_up, angle_down;
} fov;
/** Set if the buffer should be submitted with a srgb transfer applied. */
char expects_srgb_buffer;
} GHOST_XrDrawViewInfo;
typedef struct {
const char *user_message;
/** File path and line number the error was found at. */
const char *source_location;
void *customdata;
} GHOST_XrError;
typedef void (*GHOST_XrErrorHandlerFn)(const GHOST_XrError *);
typedef void *(*GHOST_XrGraphicsContextBindFn)(GHOST_TXrGraphicsBinding graphics_lib);
typedef void (*GHOST_XrGraphicsContextUnbindFn)(GHOST_TXrGraphicsBinding graphics_lib,
void *graphics_context);
/* XXX hacky: returns GHOST_ContextHandle so DirectX binding can get a handle to the OpenGL
* offscreen context. */
typedef GHOST_ContextHandle (*GHOST_XrDrawViewFn)(const GHOST_XrDrawViewInfo *draw_view,
void *customdata);
#endif
#endif // __GHOST_TYPES_H__

View File

@@ -30,7 +30,9 @@
#include "GHOST_ISystem.h"
#include "GHOST_IEvent.h"
#include "GHOST_IEventConsumer.h"
#include "GHOST_IXrContext.h"
#include "intern/GHOST_CallbackEventConsumer.h"
#include "intern/GHOST_XrException.h"
GHOST_SystemHandle GHOST_CreateSystem(void)
{
@@ -127,6 +129,51 @@ GHOST_TSuccess GHOST_DisposeOpenGLContext(GHOST_SystemHandle systemhandle,
return system->disposeContext(context);
}
#ifdef WIN32
GHOST_ContextHandle GHOST_CreateDirectXContext(GHOST_SystemHandle systemhandle)
{
GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
return (GHOST_ContextHandle)system->createOffscreenContext(GHOST_kDrawingContextTypeD3D);
}
GHOST_TSuccess GHOST_DisposeDirectXContext(GHOST_SystemHandle systemhandle,
GHOST_ContextHandle contexthandle)
{
GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
GHOST_IContext *context = (GHOST_IContext *)contexthandle;
return system->disposeContext(context);
}
#endif
GHOST_TSuccess GHOST_BlitOpenGLOffscreenContext(GHOST_WindowHandle windowhandle,
GHOST_ContextHandle offscreen_contexthandle)
{
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
return window->blitOpenGLOffscreenContext((GHOST_IContext *)offscreen_contexthandle);
}
GHOST_TSuccess GHOST_ContextBlitOpenGLOffscreenContext(GHOST_ContextHandle onscreen_contexthandle,
GHOST_ContextHandle offscreen_contexthandle,
GHOST_TInt32 width,
GHOST_TInt32 height)
{
GHOST_IContext *context = (GHOST_IContext *)onscreen_contexthandle;
return context->blitOpenGLOffscreenContext(
(class GHOST_Context *)offscreen_contexthandle, width, height);
}
GHOST_ContextHandle GHOST_GetWindowContext(GHOST_WindowHandle windowhandle)
{
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
return (GHOST_ContextHandle)window->getDrawingContext();
}
GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle,
const char *title,
GHOST_TInt32 left,
@@ -156,6 +203,13 @@ void GHOST_SetWindowUserData(GHOST_WindowHandle windowhandle, GHOST_TUserDataPtr
window->setUserData(userdata);
}
int GHOST_isUpsideDownWindow(GHOST_WindowHandle windowhandle)
{
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
return window->isUpsideDown();
}
GHOST_TSuccess GHOST_DisposeWindow(GHOST_SystemHandle systemhandle,
GHOST_WindowHandle windowhandle)
{
@@ -586,6 +640,13 @@ GHOST_TSuccess GHOST_SwapWindowBuffers(GHOST_WindowHandle windowhandle)
return window->swapBuffers();
}
GHOST_TSuccess GHOST_SwapContextBuffers(GHOST_ContextHandle contexthandle)
{
GHOST_IContext *context = (GHOST_IContext *)contexthandle;
return context->swapBuffers();
}
GHOST_TSuccess GHOST_SetSwapInterval(GHOST_WindowHandle windowhandle, int interval)
{
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
@@ -621,6 +682,20 @@ GHOST_TSuccess GHOST_ReleaseOpenGLContext(GHOST_ContextHandle contexthandle)
return context->releaseDrawingContext();
}
unsigned int GHOST_GetContextDefaultOpenGLFramebuffer(GHOST_ContextHandle contexthandle)
{
GHOST_IContext *context = (GHOST_IContext *)contexthandle;
return context->getDefaultFramebuffer();
}
int GHOST_isUpsideDownContext(GHOST_ContextHandle contexthandle)
{
GHOST_IContext *context = (GHOST_IContext *)contexthandle;
return context->isUpsideDown();
}
unsigned int GHOST_GetDefaultOpenGLFramebuffer(GHOST_WindowHandle windowhandle)
{
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
@@ -830,3 +905,70 @@ void GHOST_EndIME(GHOST_WindowHandle windowhandle)
}
#endif /* WITH_INPUT_IME */
#ifdef WITH_OPENXR
# define GHOST_XR_CAPI_CALL(call, ctx) \
try { \
call; \
} \
catch (GHOST_XrException & e) { \
(ctx)->dispatchErrorMessage(&e); \
}
# define GHOST_XR_CAPI_CALL_RET(call, ctx) \
try { \
return call; \
} \
catch (GHOST_XrException & e) { \
(ctx)->dispatchErrorMessage(&e); \
}
void GHOST_XrSessionStart(GHOST_XrContextHandle xr_contexthandle,
const GHOST_XrSessionBeginInfo *begin_info)
{
GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
GHOST_XR_CAPI_CALL(xr_context->startSession(begin_info), xr_context);
}
void GHOST_XrSessionEnd(GHOST_XrContextHandle xr_contexthandle)
{
GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
GHOST_XR_CAPI_CALL(xr_context->endSession(), xr_context);
}
int GHOST_XrHasSession(const GHOST_XrContextHandle xr_contexthandle)
{
const GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
GHOST_XR_CAPI_CALL_RET(xr_context->hasSession(), xr_context);
return 0; // Only reached if exception is thrown.
}
int GHOST_XrSessionShouldRunDrawLoop(const GHOST_XrContextHandle xr_contexthandle)
{
const GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
GHOST_XR_CAPI_CALL_RET(xr_context->shouldRunSessionDrawLoop(), xr_context);
return 0; // Only reached if exception is thrown.
}
void GHOST_XrSessionDrawViews(GHOST_XrContextHandle xr_contexthandle, void *draw_customdata)
{
GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
GHOST_XR_CAPI_CALL(xr_context->drawSessionViews(draw_customdata), xr_context);
}
void GHOST_XrGraphicsContextBindFuncs(GHOST_XrContextHandle xr_contexthandle,
GHOST_XrGraphicsContextBindFn bind_fn,
GHOST_XrGraphicsContextUnbindFn unbind_fn)
{
GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
GHOST_XR_CAPI_CALL(xr_context->setGraphicsContextBindFuncs(bind_fn, unbind_fn), xr_context);
}
void GHOST_XrDrawViewFunc(GHOST_XrContextHandle xr_contexthandle, GHOST_XrDrawViewFn draw_view_fn)
{
GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
GHOST_XR_CAPI_CALL(xr_context->setDrawViewFunc(draw_view_fn), xr_context);
}
#endif

View File

@@ -149,3 +149,68 @@ void GHOST_Context::initClearGL()
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0.000, 0.000, 0.000, 0.000);
}
GHOST_TSuccess GHOST_Context::blitOpenGLOffscreenContext(GHOST_Context *offscreen,
GHOST_TInt32 width,
GHOST_TInt32 height)
{
GLuint fbo_offscreen;
GLuint fbo_onscreen;
GLuint render_buf_shared;
GLint fbo_prev_draw;
if ((m_type != GHOST_kDrawingContextTypeOpenGL) ||
(offscreen->m_type != GHOST_kDrawingContextTypeOpenGL)) {
return GHOST_kFailure;
}
offscreen->setDefaultFramebufferSize(width, height);
/* Logic here:
* We can't simply blit from one context's framebuffer into the other. Unlike Framebuffers/FBOs,
* Renderbuffers can be shared though. So create one, and blit the offscreen context framebuffer
* contents into it. To share it, an FBO has to be created for each context though, as the
* default framebuffer doesn't allow any attachments. */
offscreen->activateDrawingContext();
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &fbo_prev_draw);
/* Create shared renderbuffer */
glGenRenderbuffers(1, &render_buf_shared);
glBindRenderbuffer(GL_RENDERBUFFER, render_buf_shared);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height);
/* Create offscreen FBO and assign renderbuffer */
glGenFramebuffers(1, &fbo_offscreen);
glBindFramebuffer(GL_FRAMEBUFFER, fbo_offscreen);
glFramebufferRenderbuffer(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, render_buf_shared);
/* Blit offscreen framebuffer into renderbuffer */
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_prev_draw);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_offscreen);
glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_LINEAR);
glDeleteFramebuffers(1, &fbo_offscreen); /* Can delete already. Do before context change. */
activateDrawingContext();
/* Create onscreen FBO and assign renderbuffer */
glGenFramebuffers(1, &fbo_onscreen);
glBindFramebuffer(GL_FRAMEBUFFER, fbo_onscreen);
glFramebufferRenderbuffer(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, render_buf_shared);
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_onscreen);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, getDefaultFramebuffer());
/* Finally, blit to onscreen buffer. */
glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_LINEAR);
glDeleteFramebuffers(1, &fbo_onscreen);
glDeleteRenderbuffers(1, &render_buf_shared);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
return GHOST_kSuccess;
}

View File

@@ -38,7 +38,8 @@ class GHOST_Context : public GHOST_IContext {
* Constructor.
* \param stereoVisual Stereo visual for quad buffered stereo.
*/
GHOST_Context(bool stereoVisual) : m_stereoVisual(stereoVisual)
GHOST_Context(GHOST_TDrawingContextType type, bool stereoVisual)
: m_type(type), m_stereoVisual(stereoVisual)
{
}
@@ -119,6 +120,11 @@ class GHOST_Context : public GHOST_IContext {
return m_stereoVisual;
}
inline bool isUpsideDown() const
{
return false;
}
/**
* Gets the OpenGL framebuffer associated with the OpenGL context
* \return The ID of an OpenGL framebuffer object.
@@ -128,9 +134,26 @@ class GHOST_Context : public GHOST_IContext {
return 0;
}
/**
* For offscreen rendering, we create an invisible window. So this can be used to update the
* offscreen buffer size by changing the size of this context's window.
*
* \note This actually changes the window size! That is the only way to change the default
* framebuffer size. Better only use for offscreen contexts.
*/
virtual GHOST_TSuccess setDefaultFramebufferSize(GHOST_TUns32 /*width*/, GHOST_TUns32 /*height*/)
{
return GHOST_kFailure;
}
GHOST_TSuccess blitOpenGLOffscreenContext(GHOST_Context *offscreen,
GHOST_TInt32 width,
GHOST_TInt32 height);
protected:
void initContextGLEW();
GHOST_TDrawingContextType m_type;
bool m_stereoVisual;
static void initClearGL();

View File

@@ -55,7 +55,7 @@ GHOST_ContextCGL::GHOST_ContextCGL(bool stereoVisual,
NSView *metalView,
CAMetalLayer *metalLayer,
NSOpenGLView *openGLView)
: GHOST_Context(stereoVisual),
: GHOST_Context(GHOST_kDrawingContextTypeOpenGL, stereoVisual),
m_metalView(metalView),
m_metalLayer(metalLayer),
m_metalCmdQueue(nil),

View File

@@ -0,0 +1,500 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/** \file
* \ingroup GHOST
*/
#include <iostream>
#include <string>
#include <GL/glew.h>
#include <GL/wglew.h>
#include "GHOST_ContextWGL.h" /* For shared drawing */
#include "GHOST_ContextD3D.h"
// #define USE_DRAW_D3D_TEST_TRIANGLE
HMODULE GHOST_ContextD3D::s_d3d_lib = NULL;
PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN GHOST_ContextD3D::s_D3D11CreateDeviceAndSwapChainFn = NULL;
#ifdef USE_DRAW_D3D_TEST_TRIANGLE
static void drawTestTriangle(ID3D11Device *m_device,
ID3D11DeviceContext *m_device_ctx,
HWND hwnd,
GHOST_TInt32 width,
GHOST_TInt32 height);
#endif
class SharedOpenGLContext {
ID3D11Device *m_d3d_device;
GHOST_ContextWGL *m_wgl_ctx;
/* NV_DX_interop2 requires ID3D11Texture2D as backbuffer when sharing with GL_RENDERBUFFER */
ID3D11Texture2D *m_d3d_render_target;
GLuint m_gl_render_buf;
public:
struct SharedData {
HANDLE device;
GLuint fbo;
HANDLE render_buf{nullptr};
} m_shared;
/* XXX Should have a map of render_target items to shared resource data (SharedData) to
* allow multiple shared surfaces in a context. Current code assumes a single one. That would be
* an issue if we wanted to use the OpenXR provided textures (changes for each eye and each
* redraw) and not the constant D3D swapchain texture like now. */
SharedOpenGLContext(ID3D11Device *d3d_device,
GHOST_ContextWGL *wgl_ctx,
ID3D11Texture2D *render_target)
: m_d3d_device(d3d_device), m_wgl_ctx(wgl_ctx), m_d3d_render_target(render_target)
{
}
~SharedOpenGLContext()
{
if (m_shared.render_buf) {
wglDXUnregisterObjectNV(m_shared.device, m_shared.render_buf);
}
if (m_shared.device) {
wglDXCloseDeviceNV(m_shared.device);
}
glDeleteFramebuffers(1, &m_shared.fbo);
glDeleteRenderbuffers(1, &m_gl_render_buf);
}
void reregisterSharedObject()
{
if (m_shared.render_buf) {
wglDXUnregisterObjectNV(m_shared.device, m_shared.render_buf);
m_shared.render_buf = nullptr;
}
m_shared.render_buf = wglDXRegisterObjectNV(m_shared.device,
m_d3d_render_target,
m_gl_render_buf,
GL_RENDERBUFFER,
WGL_ACCESS_READ_WRITE_NV);
if (!m_shared.render_buf) {
fprintf(stderr, "Error registering shared object using wglDXRegisterObjectNV()\n");
return;
}
}
GHOST_TSuccess initialize()
{
m_wgl_ctx->activateDrawingContext();
m_shared.device = wglDXOpenDeviceNV(m_d3d_device);
if (m_shared.device == NULL) {
fprintf(stderr, "Error opening shared device using wglDXOpenDeviceNV()\n");
return GHOST_kFailure;
}
/* Build the renderbuffer. */
glGenRenderbuffers(1, &m_gl_render_buf);
glBindRenderbuffer(GL_RENDERBUFFER, m_gl_render_buf);
reregisterSharedObject();
/* Build the framebuffer */
glGenFramebuffers(1, &m_shared.fbo);
glBindFramebuffer(GL_FRAMEBUFFER, m_shared.fbo);
glFramebufferRenderbuffer(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_gl_render_buf);
return GHOST_kSuccess;
}
void update(int width, int height)
{
m_wgl_ctx->setDefaultFramebufferSize(width, height);
m_wgl_ctx->activateDrawingContext();
/* TODO avoid re-registering if resource to share has not changed. */
reregisterSharedObject();
}
void beginGLOnly()
{
wglDXLockObjectsNV(m_shared.device, 1, &m_shared.render_buf);
}
void endGLOnly()
{
wglDXUnlockObjectsNV(m_shared.device, 1, &m_shared.render_buf);
}
};
GHOST_ContextD3D::GHOST_ContextD3D(bool stereoVisual, HWND hWnd)
: GHOST_Context(GHOST_kDrawingContextTypeD3D, stereoVisual), m_hWnd(hWnd)
{
}
GHOST_ContextD3D::~GHOST_ContextD3D()
{
delete glshared;
m_swapchain->Release();
m_backbuffer_view->Release();
m_device->Release();
m_device_ctx->ClearState();
m_device_ctx->Release();
}
GHOST_TSuccess GHOST_ContextD3D::swapBuffers()
{
HRESULT res = m_swapchain->Present(0, 0);
return (res == S_OK) ? GHOST_kSuccess : GHOST_kFailure;
}
GHOST_TSuccess GHOST_ContextD3D::activateDrawingContext()
{
return GHOST_kFailure;
}
GHOST_TSuccess GHOST_ContextD3D::releaseDrawingContext()
{
return GHOST_kFailure;
}
GHOST_TSuccess GHOST_ContextD3D::setDefaultFramebufferSize(GHOST_TUns32 width, GHOST_TUns32 height)
{
RECT rect = {0, 0, (long)width, (long)height};
RECT winrect;
/* To use swapchain buffers/textures with custom size, the hidden window has to be resized. */
GetWindowRect(m_hWnd, &winrect);
WIN32_CHK(AdjustWindowRectEx(&rect, WS_OVERLAPPEDWINDOW, false, 0));
width = rect.right - rect.left;
height = rect.bottom - rect.top;
if (((winrect.right - winrect.left) != width) || ((winrect.bottom - winrect.top) != height)) {
return SetWindowPos(m_hWnd,
HWND_TOP,
0,
0,
width,
height,
SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOMOVE | SWP_NOZORDER) ?
GHOST_kSuccess :
GHOST_kFailure;
}
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_ContextD3D::updateSwapchain(GHOST_TUns32 width, GHOST_TUns32 height)
{
HRESULT hres;
DXGI_SWAP_CHAIN_DESC swapchain_desc;
m_swapchain->GetDesc(&swapchain_desc);
if ((swapchain_desc.BufferDesc.Width == width) && (swapchain_desc.BufferDesc.Height == height)) {
// Nothing to do.
return GHOST_kSuccess;
}
#define CHECK_HRES \
if (hres != S_OK) { \
printf("Error updating swapchain (error code %x): %s line %i\n", hres, __FILE__, __LINE__); \
} \
(void)0
setDefaultFramebufferSize(width, height);
m_device_ctx->OMSetRenderTargets(0, nullptr, nullptr);
m_backbuffer_view->Release();
m_device_ctx->ClearState();
hres = m_swapchain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
CHECK_HRES;
ID3D11Texture2D *buf;
hres = m_swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void **)&buf);
CHECK_HRES;
hres = m_device->CreateRenderTargetView(buf, NULL, &m_backbuffer_view);
CHECK_HRES;
buf->Release();
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_ContextD3D::setupD3DLib()
{
if (s_d3d_lib == NULL) {
s_d3d_lib = LoadLibraryA("d3d11.dll");
WIN32_CHK(s_d3d_lib != NULL);
if (s_d3d_lib == NULL) {
fprintf(stderr, "LoadLibrary(\"d3d11.dll\") failed!\n");
return GHOST_kFailure;
}
}
if (s_D3D11CreateDeviceAndSwapChainFn == NULL) {
s_D3D11CreateDeviceAndSwapChainFn = (PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN)GetProcAddress(
s_d3d_lib, "D3D11CreateDeviceAndSwapChain");
WIN32_CHK(s_D3D11CreateDeviceAndSwapChainFn != NULL);
if (s_D3D11CreateDeviceAndSwapChainFn == NULL) {
fprintf(stderr, "GetProcAddress(s_d3d_lib, \"D3D11CreateDeviceAndSwapChain\") failed!\n");
return GHOST_kFailure;
}
}
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_ContextD3D::initializeDrawingContext()
{
if (setupD3DLib() == GHOST_kFailure) {
return GHOST_kFailure;
}
DXGI_SWAP_CHAIN_DESC sd{};
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.SampleDesc.Count = 1;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.BufferCount = 3;
sd.OutputWindow = m_hWnd;
sd.Windowed = TRUE;
sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
HRESULT hres = s_D3D11CreateDeviceAndSwapChainFn(NULL,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
// D3D11_CREATE_DEVICE_DEBUG,
0,
NULL,
0,
D3D11_SDK_VERSION,
&sd,
&m_swapchain,
&m_device,
NULL,
&m_device_ctx);
WIN32_CHK(hres == S_OK);
ID3D11Texture2D *back_buffer;
m_swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void **)&back_buffer);
m_device->CreateRenderTargetView(back_buffer, nullptr, &m_backbuffer_view);
back_buffer->Release();
m_swapchain->Present(0, 0);
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_ContextD3D::releaseNativeHandles()
{
return GHOST_kFailure;
}
GHOST_TSuccess GHOST_ContextD3D::blitOpenGLOffscreenContext(GHOST_Context *offscreen_ctx,
ID3D11RenderTargetView *render_target,
GHOST_TInt32 width,
GHOST_TInt32 height)
{
if (!(WGL_NV_DX_interop && WGL_NV_DX_interop2)) {
fprintf(stderr,
"Error: Can't render OpenGL framebuffer using Direct3D. NV_DX_interop extension not "
"available.");
return GHOST_kFailure;
}
m_device_ctx->OMSetRenderTargets(1, &render_target, nullptr);
offscreen_ctx->activateDrawingContext();
GLint fbo;
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &fbo);
if (glshared == NULL) {
ID3D11Resource *backbuffer_res;
ID3D11Texture2D *backbuffer_tex;
render_target->GetResource(&backbuffer_res);
backbuffer_res->QueryInterface<ID3D11Texture2D>(&backbuffer_tex);
glshared = new SharedOpenGLContext(
m_device, (GHOST_ContextWGL *)offscreen_ctx, backbuffer_tex);
backbuffer_res->Release();
backbuffer_tex->Release();
if (glshared->initialize() == GHOST_kFailure) {
return GHOST_kFailure;
}
}
SharedOpenGLContext::SharedData *shared = &glshared->m_shared;
glshared->update(width, height);
const float clear_col[] = {0.8f, 0.5f, 1.0f, 1.0f};
m_device_ctx->ClearRenderTargetView(render_target, clear_col);
glshared->beginGLOnly();
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, shared->fbo);
GLenum err = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (err != GL_FRAMEBUFFER_COMPLETE) {
fprintf(stderr, "Error: Framebuffer incomplete %u\n", err);
return GHOST_kFailure;
}
/* Not needed, usefull for debugging. */
initClearGL();
/* No glBlitNamedFramebuffer, gotta be 3.3 compatible. */
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, shared->fbo);
glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_LINEAR);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glshared->endGLOnly();
#ifdef USE_DRAW_D3D_TEST_TRIANGLE
drawTestTriangle(m_device.Get(), m_device_ctx.Get(), m_hWnd, width, height);
#endif
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_ContextD3D::blitOpenGLOffscreenContext(GHOST_Context *offscreen_ctx,
GHOST_TInt32 width,
GHOST_TInt32 height)
{
updateSwapchain(width, height);
return blitOpenGLOffscreenContext(offscreen_ctx, m_backbuffer_view, width, height);
}
#ifdef USE_DRAW_D3D_TEST_TRIANGLE
# pragma comment(lib, "D3DCompiler.lib")
const static std::string vertex_shader_str{
"struct VSOut {"
"float3 color : Color;"
"float4 pos : SV_POSITION;"
"};"
"VSOut main(float2 pos : Position, float3 color : Color)"
"{"
" VSOut vso;"
" vso.pos = float4(pos.x, pos.y, 0.0f, 1.0f);"
" vso.color = color;"
" return vso;"
"}"};
const static std::string pixel_shader_str{
" float4 main(float3 color : Color) : SV_TARGET"
"{"
" return float4(color, 1.0f);"
"}"};
# include <d3dcompiler.h>
static void drawTestTriangle(ID3D11Device *m_device,
ID3D11DeviceContext *m_device_ctx,
HWND hwnd,
GHOST_TInt32 width,
GHOST_TInt32 height)
{
struct Vertex {
float x, y;
unsigned char r, g, b, a;
};
Vertex vertices[] = {
{0.0f, 0.5f, 255, 0, 0},
{0.5f, -0.5f, 0, 255, 0},
{-0.5f, -0.5f, 0, 0, 255},
};
const unsigned int stride = sizeof(Vertex);
const unsigned int offset = 0;
ID3D11Buffer *vertex_buffer;
D3D11_BUFFER_DESC buffer_desc{};
buffer_desc.Usage = D3D11_USAGE_DEFAULT;
buffer_desc.ByteWidth = sizeof(vertices);
buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
D3D11_SUBRESOURCE_DATA init_data{};
init_data.pSysMem = vertices;
m_device->CreateBuffer(&buffer_desc, &init_data, &vertex_buffer);
m_device_ctx->IASetVertexBuffers(0, 1, &vertex_buffer, &stride, &offset);
Microsoft::WRL::ComPtr<ID3DBlob> blob;
D3DCompile(pixel_shader_str.c_str(),
pixel_shader_str.length(),
NULL,
NULL,
NULL,
"main",
"ps_5_0",
0,
0,
&blob,
NULL);
Microsoft::WRL::ComPtr<ID3D11PixelShader> pixel_shader;
m_device->CreatePixelShader(
blob->GetBufferPointer(), blob->GetBufferSize(), NULL, &pixel_shader);
D3DCompile(vertex_shader_str.c_str(),
vertex_shader_str.length(),
NULL,
NULL,
NULL,
"main",
"vs_5_0",
0,
0,
&blob,
NULL);
Microsoft::WRL::ComPtr<ID3D11VertexShader> vertex_shader;
m_device->CreateVertexShader(
blob->GetBufferPointer(), blob->GetBufferSize(), NULL, &vertex_shader);
m_device_ctx->PSSetShader(pixel_shader.Get(), NULL, 0);
m_device_ctx->VSSetShader(vertex_shader.Get(), 0, 0);
Microsoft::WRL::ComPtr<ID3D11InputLayout> input_layout;
const D3D11_INPUT_ELEMENT_DESC input_desc[] = {
{"Position", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"Color", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0},
};
m_device->CreateInputLayout(input_desc,
(unsigned int)std::size(input_desc),
blob->GetBufferPointer(),
blob->GetBufferSize(),
&input_layout);
m_device_ctx->IASetInputLayout(input_layout.Get());
m_device_ctx->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
D3D11_VIEWPORT viewport = {};
viewport.Width = width;
viewport.Height = height;
viewport.MaxDepth = 1;
m_device_ctx->RSSetViewports(1, &viewport);
m_device_ctx->Draw(std::size(vertices), 0);
}
#endif

View File

@@ -0,0 +1,141 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/** \file
* \ingroup GHOST
*/
#ifndef __GHOST_CONTEXTD3D_H__
#define __GHOST_CONTEXTD3D_H__
#ifndef WIN32
# error WIN32 only!
#endif // WIN32
#include <D3D11.h>
#include "GHOST_Context.h"
class GHOST_ContextD3D : public GHOST_Context {
/* XR code needs low level graphics data to send to OpenXR. */
friend class GHOST_XrGraphicsBindingD3D;
public:
GHOST_ContextD3D(bool stereoVisual, HWND hWnd);
~GHOST_ContextD3D();
/**
* Swaps front and back buffers of a window.
* \return A boolean success indicator.
*/
GHOST_TSuccess swapBuffers();
/**
* Activates the drawing context of this window.
* \return A boolean success indicator.
*/
GHOST_TSuccess activateDrawingContext();
/**
* Release the drawing context of the calling thread.
* \return A boolean success indicator.
*/
GHOST_TSuccess releaseDrawingContext();
GHOST_TSuccess setDefaultFramebufferSize(GHOST_TUns32 width, GHOST_TUns32 height);
/**
* Call immediately after new to initialize. If this fails then immediately delete the object.
* \return Indication as to whether initialization has succeeded.
*/
GHOST_TSuccess initializeDrawingContext();
/**
* Updates the drawing context of this window. Needed
* whenever the window is changed.
* \return Indication of success.
*/
GHOST_TSuccess updateDrawingContext()
{
return GHOST_kFailure;
}
/**
* Checks if it is OK for a remove the native display
* \return Indication as to whether removal has succeeded.
*/
GHOST_TSuccess releaseNativeHandles();
/**
* Sets the swap interval for swapBuffers.
* \param interval The swap interval to use.
* \return A boolean success indicator.
*/
GHOST_TSuccess setSwapInterval(int /*interval*/)
{
return GHOST_kFailure;
}
/**
* Gets the current swap interval for swapBuffers.
* \param intervalOut Variable to store the swap interval if it can be read.
* \return Whether the swap interval can be read.
*/
GHOST_TSuccess getSwapInterval(int &)
{
return GHOST_kFailure;
}
/**
* Gets the OpenGL framebuffer associated with the OpenGL context
* \return The ID of an OpenGL framebuffer object.
*/
unsigned int getDefaultFramebuffer()
{
return 0;
}
GHOST_TSuccess blitOpenGLOffscreenContext(GHOST_Context *offscreen_ctx,
GHOST_TInt32 width,
GHOST_TInt32 height);
GHOST_TSuccess blitOpenGLOffscreenContext(GHOST_Context *offscreen_ctx,
ID3D11RenderTargetView *render_target,
GHOST_TInt32 width,
GHOST_TInt32 height);
bool isUpsideDown() const
{
return true;
}
private:
GHOST_TSuccess setupD3DLib();
GHOST_TSuccess updateSwapchain(GHOST_TUns32 width, GHOST_TUns32 height);
static HMODULE s_d3d_lib;
static PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN s_D3D11CreateDeviceAndSwapChainFn;
HWND m_hWnd;
ID3D11Device *m_device;
ID3D11DeviceContext *m_device_ctx;
IDXGISwapChain *m_swapchain;
ID3D11RenderTargetView *m_backbuffer_view;
class SharedOpenGLContext *glshared{nullptr};
};
#endif /* __GHOST_CONTEXTD3D_H__ */

View File

@@ -208,7 +208,7 @@ GHOST_ContextEGL::GHOST_ContextEGL(bool stereoVisual,
EGLint contextFlags,
EGLint contextResetNotificationStrategy,
EGLenum api)
: GHOST_Context(stereoVisual),
: GHOST_Context(GHOST_kDrawingContextTypeOpenGL, stereoVisual),
m_nativeDisplay(nativeDisplay),
m_nativeWindow(nativeWindow),
m_contextProfileMask(contextProfileMask),

View File

@@ -52,7 +52,7 @@ GHOST_ContextGLX::GHOST_ContextGLX(bool stereoVisual,
int contextMinorVersion,
int contextFlags,
int contextResetNotificationStrategy)
: GHOST_Context(stereoVisual),
: GHOST_Context(GHOST_kDrawingContextTypeOpenGL, stereoVisual),
m_display(display),
m_fbconfig(fbconfig),
m_window(window),
@@ -273,6 +273,7 @@ GHOST_TSuccess GHOST_ContextGLX::initializeDrawingContext()
m_window = (Window)glXCreatePbuffer(m_display, framebuffer_config[0], pbuffer_attribs);
}
m_fbconfig = framebuffer_config[0];
XFree(framebuffer_config);
}
}

View File

@@ -38,6 +38,9 @@
#endif
class GHOST_ContextGLX : public GHOST_Context {
/* XR code needs low level graphics data to send to OpenXR. */
friend class GHOST_XrGraphicsBindingOpenGL;
public:
/**
* Constructor.

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