Skip to content

Commit

Permalink
Merge pull request #15659 from lvonasek/feature_openxr_quest
Browse files Browse the repository at this point in the history
Oculus Quest native support
  • Loading branch information
hrydgard authored Jul 31, 2022
2 parents 8260b46 + 4691b37 commit 392d83f
Show file tree
Hide file tree
Showing 30 changed files with 9,804 additions and 7 deletions.
22 changes: 22 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,14 @@ include(GNUInstallDirs)

add_definitions(-DASSETS_DIR="${CMAKE_INSTALL_FULL_DATADIR}/ppsspp/assets/")

if(OPENXR)
add_definitions(-DOPENXR)
add_library(openxr SHARED IMPORTED)
include_directories(ext/openxr)
set_property(TARGET openxr PROPERTY IMPORTED_LOCATION "${CMAKE_SOURCE_DIR}/ext/openxr/libs/arm64-v8a/libopenxr_loader.so")
message("OpenXR enabled")
endif()

if(GOLD)
add_definitions(-DGOLD)
message("Gold Build")
Expand Down Expand Up @@ -1056,6 +1064,20 @@ if(ANDROID)
android/jni/OpenSLContext.cpp
android/jni/OpenSLContext.h
)

if (OPENXR)
set(nativeExtra ${nativeExtra}
Common/VR/VRBase.cpp
Common/VR/VRBase.h
Common/VR/VRFramebuffer.cpp
Common/VR/VRFramebuffer.h
Common/VR/VRInput.cpp
Common/VR/VRInput.h
Common/VR/VRRenderer.cpp
Common/VR/VRRenderer.h
)
set(nativeExtraLibs ${nativeExtraLibs} openxr)
endif()
# No target
elseif(IOS)
set(nativeExtra ${nativeExtra}
Expand Down
9 changes: 9 additions & 0 deletions Common/GPU/OpenGL/GLQueueRunner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ static constexpr int TEXCACHE_NAME_CACHE_SIZE = 16;
extern void bindDefaultFBO();
#endif

#ifdef OPENXR
#include "VR/VRBase.h"
#include "VR/VRRenderer.h"
#endif

// Workaround for Retroarch. Simply declare
// extern GLuint g_defaultFBO;
// and set is as appropriate. Can adjust the variables in ext/native/base/display.h as
Expand Down Expand Up @@ -1653,6 +1658,10 @@ void GLQueueRunner::fbo_unbind() {
bindDefaultFBO();
#endif

#ifdef OPENXR
VR_BindFramebuffer(VR_GetEngine(), 0);
#endif

currentDrawHandle_ = 0;
currentReadHandle_ = 0;
CHECK_GL_ERROR_IF_DEBUG();
Expand Down
12 changes: 12 additions & 0 deletions Common/GPU/OpenGL/GLRenderManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
#include "Common/MemoryUtil.h"
#include "Common/Math/math_util.h"

#ifdef OPENXR
#include "VR/VRBase.h"
#include "VR/VRRenderer.h"
#endif

#if 0 // def _DEBUG
#define VLOG(...) INFO_LOG(G3D, __VA_ARGS__)
#else
Expand Down Expand Up @@ -202,6 +207,9 @@ bool GLRenderManager::ThreadFrame() {
std::unique_lock<std::mutex> lock(mutex_);
if (!run_)
return false;
#ifdef OPENXR
VR_BeginFrame(VR_GetEngine());
#endif

// In case of syncs or other partial completion, we keep going until we complete a frame.
do {
Expand Down Expand Up @@ -240,6 +248,9 @@ bool GLRenderManager::ThreadFrame() {
Run(threadFrame_);
VLOG("PULL: Finished frame %d", threadFrame_);
} while (!nextFrame);
#ifdef OPENXR
VR_EndFrame(VR_GetEngine());
#endif
return true;
}

Expand Down Expand Up @@ -300,6 +311,7 @@ void GLRenderManager::BindFramebufferAsRenderTarget(GLRFramebuffer *fb, GLRRende
#ifdef _DEBUG
curProgram_ = nullptr;
#endif

// Eliminate dupes.
if (steps_.size() && steps_.back()->render.framebuffer == fb && steps_.back()->stepType == GLRStepType::RENDER) {
if (color != GLRRenderPassAction::CLEAR && depth != GLRRenderPassAction::CLEAR && stencil != GLRRenderPassAction::CLEAR) {
Expand Down
6 changes: 6 additions & 0 deletions Common/GPU/Vulkan/VulkanLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,12 @@ void VulkanSetAvailable(bool available) {
}

bool VulkanMayBeAvailable() {

#ifdef OPENXR
//unsupported at the moment
return false;
#endif

if (g_vulkanAvailabilityChecked) {
return g_vulkanMayBeAvailable;
}
Expand Down
2 changes: 2 additions & 0 deletions Common/Input/InputState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ const char *GetDeviceName(int deviceId) {
case DEVICE_ID_XINPUT_3: return "x360_4";
case DEVICE_ID_ACCELEROMETER: return "accelerometer";
case DEVICE_ID_MOUSE: return "mouse";
case DEVICE_ID_XR_CONTROLLER_LEFT: return "xr_l";
case DEVICE_ID_XR_CONTROLLER_RIGHT: return "xr_r";
default:
return "unknown";
}
Expand Down
2 changes: 2 additions & 0 deletions Common/Input/InputState.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ enum {
DEVICE_ID_XINPUT_2 = 22,
DEVICE_ID_XINPUT_3 = 23,
DEVICE_ID_ACCELEROMETER = 30,
DEVICE_ID_XR_CONTROLLER_LEFT = 40,
DEVICE_ID_XR_CONTROLLER_RIGHT = 41,
};

//number of contiguous generic joypad IDs
Expand Down
1 change: 1 addition & 0 deletions Common/System/System.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ enum SystemDeviceType {
DEVICE_TYPE_MOBILE = 0, // phones and pads
DEVICE_TYPE_TV = 1, // Android TV and similar
DEVICE_TYPE_DESKTOP = 2, // Desktop computer
DEVICE_TYPE_VR = 3, // VR headset
};

enum SystemKeyboardLayout {
Expand Down
9 changes: 9 additions & 0 deletions Common/UI/UIScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
#include "Common/Log.h"
#include "Common/StringUtils.h"

#ifdef OPENXR
#include "VR/VRBase.h"
#include "VR/VRRenderer.h"
#endif

static const bool ClickDebug = false;

UIScreen::UIScreen()
Expand Down Expand Up @@ -88,6 +93,10 @@ void UIScreen::preRender() {
draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, 0xFF000000 }, "UI");
screenManager()->getUIContext()->BeginFrame();

#ifdef OPENXR
VR_BindFramebuffer(VR_GetEngine(), 0);
#endif

Draw::Viewport viewport;
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
Expand Down
165 changes: 165 additions & 0 deletions Common/VR/VRBase.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
#include "VRBase.h"

#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

static engine_t vr_engine;
int vr_initialized = 0;

const char* const requiredExtensionNames[] = {
XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME,
XR_KHR_COMPOSITION_LAYER_CYLINDER_EXTENSION_NAME};
const uint32_t numRequiredExtensions =
sizeof(requiredExtensionNames) / sizeof(requiredExtensionNames[0]);

void VR_Init( ovrJava java ) {
if (vr_initialized)
return;

ovrApp_Clear(&vr_engine.appState);

PFN_xrInitializeLoaderKHR xrInitializeLoaderKHR;
xrGetInstanceProcAddr(
XR_NULL_HANDLE, "xrInitializeLoaderKHR", (PFN_xrVoidFunction*)&xrInitializeLoaderKHR);
if (xrInitializeLoaderKHR != NULL) {
XrLoaderInitInfoAndroidKHR loaderInitializeInfoAndroid;
memset(&loaderInitializeInfoAndroid, 0, sizeof(loaderInitializeInfoAndroid));
loaderInitializeInfoAndroid.type = XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR;
loaderInitializeInfoAndroid.next = NULL;
loaderInitializeInfoAndroid.applicationVM = java.Vm;
loaderInitializeInfoAndroid.applicationContext = java.ActivityObject;
xrInitializeLoaderKHR((XrLoaderInitInfoBaseHeaderKHR*)&loaderInitializeInfoAndroid);
}

// Create the OpenXR instance.
XrApplicationInfo appInfo;
memset(&appInfo, 0, sizeof(appInfo));
strcpy(appInfo.applicationName, java.AppName);
strcpy(appInfo.engineName, java.AppName);
appInfo.applicationVersion = java.AppVersion;
appInfo.engineVersion = java.AppVersion;
appInfo.apiVersion = XR_CURRENT_API_VERSION;

XrInstanceCreateInfo instanceCreateInfo;
memset(&instanceCreateInfo, 0, sizeof(instanceCreateInfo));
instanceCreateInfo.type = XR_TYPE_INSTANCE_CREATE_INFO;
instanceCreateInfo.next = NULL;
instanceCreateInfo.createFlags = 0;
instanceCreateInfo.applicationInfo = appInfo;
instanceCreateInfo.enabledApiLayerCount = 0;
instanceCreateInfo.enabledApiLayerNames = NULL;
instanceCreateInfo.enabledExtensionCount = numRequiredExtensions;
instanceCreateInfo.enabledExtensionNames = requiredExtensionNames;

XrResult initResult;
OXR(initResult = xrCreateInstance(&instanceCreateInfo, &vr_engine.appState.Instance));
if (initResult != XR_SUCCESS) {
ALOGE("Failed to create XR instance: %d.", initResult);
exit(1);
}

XrInstanceProperties instanceInfo;
instanceInfo.type = XR_TYPE_INSTANCE_PROPERTIES;
instanceInfo.next = NULL;
OXR(xrGetInstanceProperties(vr_engine.appState.Instance, &instanceInfo));
ALOGV(
"Runtime %s: Version : %u.%u.%u",
instanceInfo.runtimeName,
XR_VERSION_MAJOR(instanceInfo.runtimeVersion),
XR_VERSION_MINOR(instanceInfo.runtimeVersion),
XR_VERSION_PATCH(instanceInfo.runtimeVersion));

XrSystemGetInfo systemGetInfo;
memset(&systemGetInfo, 0, sizeof(systemGetInfo));
systemGetInfo.type = XR_TYPE_SYSTEM_GET_INFO;
systemGetInfo.next = NULL;
systemGetInfo.formFactor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;

XrSystemId systemId;
OXR(initResult = xrGetSystem(vr_engine.appState.Instance, &systemGetInfo, &systemId));
if (initResult != XR_SUCCESS) {
ALOGE("Failed to get system.");
exit(1);
}

// Get the graphics requirements.
PFN_xrGetOpenGLESGraphicsRequirementsKHR pfnGetOpenGLESGraphicsRequirementsKHR = NULL;
OXR(xrGetInstanceProcAddr(
vr_engine.appState.Instance,
"xrGetOpenGLESGraphicsRequirementsKHR",
(PFN_xrVoidFunction*)(&pfnGetOpenGLESGraphicsRequirementsKHR)));

XrGraphicsRequirementsOpenGLESKHR graphicsRequirements = {};
graphicsRequirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR;
OXR(pfnGetOpenGLESGraphicsRequirementsKHR(vr_engine.appState.Instance, systemId, &graphicsRequirements));

vr_engine.appState.MainThreadTid = gettid();
vr_engine.appState.SystemId = systemId;

vr_engine.java = java;
vr_initialized = 1;
}

void VR_Destroy( engine_t* engine ) {
if (engine == &vr_engine) {
xrDestroyInstance(engine->appState.Instance);
ovrApp_Destroy(&engine->appState);
}
}

void VR_EnterVR( engine_t* engine ) {

if (engine->appState.Session) {
ALOGE("VR_EnterVR called with existing session");
return;
}

// Create the OpenXR Session.
XrGraphicsBindingOpenGLESAndroidKHR graphicsBindingAndroidGLES = {};
graphicsBindingAndroidGLES.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR;
graphicsBindingAndroidGLES.next = NULL;
graphicsBindingAndroidGLES.display = eglGetCurrentDisplay();
graphicsBindingAndroidGLES.config = eglGetCurrentSurface(EGL_DRAW);
graphicsBindingAndroidGLES.context = eglGetCurrentContext();

XrSessionCreateInfo sessionCreateInfo = {};
memset(&sessionCreateInfo, 0, sizeof(sessionCreateInfo));
sessionCreateInfo.type = XR_TYPE_SESSION_CREATE_INFO;
sessionCreateInfo.next = &graphicsBindingAndroidGLES;
sessionCreateInfo.createFlags = 0;
sessionCreateInfo.systemId = engine->appState.SystemId;

XrResult initResult;
OXR(initResult = xrCreateSession(engine->appState.Instance, &sessionCreateInfo, &engine->appState.Session));
if (initResult != XR_SUCCESS) {
ALOGE("Failed to create XR session: %d.", initResult);
exit(1);
}

// Create a space to the first path
XrReferenceSpaceCreateInfo spaceCreateInfo = {};
spaceCreateInfo.type = XR_TYPE_REFERENCE_SPACE_CREATE_INFO;
spaceCreateInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_VIEW;
spaceCreateInfo.poseInReferenceSpace.orientation.w = 1.0f;
OXR(xrCreateReferenceSpace(engine->appState.Session, &spaceCreateInfo, &engine->appState.HeadSpace));
}

void VR_LeaveVR( engine_t* engine ) {
if (engine->appState.Session) {
OXR(xrDestroySpace(engine->appState.HeadSpace));
// StageSpace is optional.
if (engine->appState.StageSpace != XR_NULL_HANDLE) {
OXR(xrDestroySpace(engine->appState.StageSpace));
}
OXR(xrDestroySpace(engine->appState.FakeStageSpace));
engine->appState.CurrentSpace = XR_NULL_HANDLE;
OXR(xrDestroySession(engine->appState.Session));
engine->appState.Session = NULL;
}
}

engine_t* VR_GetEngine( void ) {
return &vr_engine;
}
10 changes: 10 additions & 0 deletions Common/VR/VRBase.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#pragma once

#include "VRFramebuffer.h"

void VR_Init( ovrJava java );
void VR_Destroy( engine_t* engine );
void VR_EnterVR( engine_t* engine );
void VR_LeaveVR( engine_t* engine );

engine_t* VR_GetEngine( void );
Loading

0 comments on commit 392d83f

Please sign in to comment.