diff --git a/Common/GPU/OpenGL/GLRenderManager.cpp b/Common/GPU/OpenGL/GLRenderManager.cpp index 01a94fb8b4..01cccb8874 100644 --- a/Common/GPU/OpenGL/GLRenderManager.cpp +++ b/Common/GPU/OpenGL/GLRenderManager.cpp @@ -236,28 +236,12 @@ bool GLRenderManager::ThreadFrame() { firstFrame = false; } - // Start of an OpenXR frame. This updates user's head pose and VR timestamps. - // For fluent rendering, delay between StartVRRender and FinishVRRender must be very short. - if (IsVRBuild() && !vrRenderStarted) { - if (StartVRRender()) { - vrRenderStarted = true; - } else { - return false; - } - } - // Render the scene. Run(threadFrame_); VLOG("PULL: Finished frame %d", threadFrame_); } while (!nextFrame); - // Post OpenXR frame on a screen. - if (IsVRBuild() && vrRenderStarted) { - FinishVRRender(); - vrRenderStarted = false; - } - return true; } diff --git a/Common/GPU/OpenGL/GLRenderManager.h b/Common/GPU/OpenGL/GLRenderManager.h index 089c588aeb..51d7e1e9eb 100644 --- a/Common/GPU/OpenGL/GLRenderManager.h +++ b/Common/GPU/OpenGL/GLRenderManager.h @@ -1051,7 +1051,6 @@ private: bool nextFrame = false; bool firstFrame = true; - bool vrRenderStarted = false; GLDeleter deleter_; bool skipGLCalls_ = false; diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp index 2ad0014c10..22668fb3f3 100644 --- a/Common/VR/VRRenderer.cpp +++ b/Common/VR/VRRenderer.cpp @@ -16,6 +16,7 @@ XrFrameState frameState = {}; GLboolean initialized = GL_FALSE; GLboolean stageSupported = GL_FALSE; int vrConfig[VR_CONFIG_MAX] = {}; +ovrMatrix4f vrMatrix[VR_MATRIX_COUNT]; XrVector3f hmdorientation; XrVector3f hmdposition; @@ -310,6 +311,61 @@ bool VR_InitFrame( engine_t* engine ) { engine->appState.LayerCount = 0; memset(engine->appState.Layers, 0, sizeof(ovrCompositorLayer_Union) * ovrMaxLayerCount); + + // Update matrices + for (int matrix = 0; matrix < VR_MATRIX_COUNT; matrix++) { + if ((matrix == VR_PROJECTION_MATRIX_LEFT_EYE) || (matrix == VR_PROJECTION_MATRIX_RIGHT_EYE)) { + float near = (float)vrConfig[VR_CONFIG_FOV_SCALE] / 200.0f; + vrMatrix[matrix] = ovrMatrix4f_CreateProjectionFov(fov.angleLeft, fov.angleRight, fov.angleUp, fov.angleDown, near, 0.0f ); + } else if ((matrix == VR_VIEW_MATRIX_LEFT_EYE) || (matrix == VR_VIEW_MATRIX_RIGHT_EYE)) { + XrPosef invView = invViewTransform[0]; + + // get axis mirroring configuration + float mx = vrConfig[VR_CONFIG_MIRROR_PITCH] ? -1 : 1; + float my = vrConfig[VR_CONFIG_MIRROR_YAW] ? -1 : 1; + float mz = vrConfig[VR_CONFIG_MIRROR_ROLL] ? -1 : 1; + + // ensure there is maximally one axis to mirror rotation + if (mx + my + mz < 0) { + mx *= -1.0f; + my *= -1.0f; + mz *= -1.0f; + } else { + invView = XrPosef_Inverse(invView); + } + + // create updated quaternion + if (mx + my + mz < 3 - EPSILON) { + XrVector3f rotation = XrQuaternionf_ToEulerAngles(invView.orientation); + XrQuaternionf pitch = XrQuaternionf_CreateFromVectorAngle({1, 0, 0}, mx * ToRadians(rotation.x)); + XrQuaternionf yaw = XrQuaternionf_CreateFromVectorAngle({0, 1, 0}, my * ToRadians(rotation.y)); + XrQuaternionf roll = XrQuaternionf_CreateFromVectorAngle({0, 0, 1}, mz * ToRadians(rotation.z)); + invView.orientation = XrQuaternionf_Multiply(roll, XrQuaternionf_Multiply(pitch, yaw)); + } + + vrMatrix[matrix] = ovrMatrix4f_CreateFromQuaternion(&invView.orientation); + float scale = (float)VR_GetConfig(VR_CONFIG_6DOF_SCALE) * 0.000001f; + if (vrConfig[VR_CONFIG_6DOF_ENABLED]) { + vrMatrix[matrix].M[0][3] -= hmdposition.x * (vrConfig[VR_CONFIG_MIRROR_AXIS_X] ? -1.0f : 1.0f) * scale; + vrMatrix[matrix].M[1][3] -= hmdposition.y * (vrConfig[VR_CONFIG_MIRROR_AXIS_Y] ? -1.0f : 1.0f) * scale; + vrMatrix[matrix].M[2][3] -= hmdposition.z * (vrConfig[VR_CONFIG_MIRROR_AXIS_Z] ? -1.0f : 1.0f) * scale; + } + if (vrConfig[VR_CONFIG_6DOF_PRECISE] && (matrix == VR_VIEW_MATRIX_RIGHT_EYE)) { + float dx = fabs(invViewTransform[1].position.x - invViewTransform[0].position.x); + float dy = fabs(invViewTransform[1].position.y - invViewTransform[0].position.y); + float dz = fabs(invViewTransform[1].position.z - invViewTransform[0].position.z); + float ipd = sqrt(dx * dx + dy * dy + dz * dz); + XrVector3f separation = {ipd * scale, 0.0f, 0.0f}; + separation = XrQuaternionf_Rotate(invView.orientation, separation); + separation = XrVector3f_ScalarMultiply(separation, vrConfig[VR_CONFIG_MIRROR_AXIS_Z] ? -1.0f : 1.0f); + vrMatrix[matrix].M[0][3] -= separation.x; + vrMatrix[matrix].M[1][3] -= separation.y; + vrMatrix[matrix].M[2][3] -= separation.z; + } + } else { + assert(false); + } + } return true; } @@ -468,57 +524,5 @@ void VR_BindFramebuffer(engine_t *engine) { } ovrMatrix4f VR_GetMatrix( VRMatrix matrix ) { - ovrMatrix4f output; - if ((matrix == VR_PROJECTION_MATRIX_LEFT_EYE) || (matrix == VR_PROJECTION_MATRIX_RIGHT_EYE)) { - float near = (float)vrConfig[VR_CONFIG_FOV_SCALE] / 200.0f; - output = ovrMatrix4f_CreateProjectionFov(fov.angleLeft, fov.angleRight, fov.angleUp, fov.angleDown, near, 0.0f ); - } else if ((matrix == VR_VIEW_MATRIX_LEFT_EYE) || (matrix == VR_VIEW_MATRIX_RIGHT_EYE)) { - XrPosef invView = invViewTransform[0]; - - // get axis mirroring configuration - float mx = vrConfig[VR_CONFIG_MIRROR_PITCH] ? -1 : 1; - float my = vrConfig[VR_CONFIG_MIRROR_YAW] ? -1 : 1; - float mz = vrConfig[VR_CONFIG_MIRROR_ROLL] ? -1 : 1; - - // ensure there is maximally one axis to mirror rotation - if (mx + my + mz < 0) { - mx *= -1.0f; - my *= -1.0f; - mz *= -1.0f; - } else { - invView = XrPosef_Inverse(invView); - } - - // create updated quaternion - if (mx + my + mz < 3 - EPSILON) { - XrVector3f rotation = XrQuaternionf_ToEulerAngles(invView.orientation); - XrQuaternionf pitch = XrQuaternionf_CreateFromVectorAngle({1, 0, 0}, mx * ToRadians(rotation.x)); - XrQuaternionf yaw = XrQuaternionf_CreateFromVectorAngle({0, 1, 0}, my * ToRadians(rotation.y)); - XrQuaternionf roll = XrQuaternionf_CreateFromVectorAngle({0, 0, 1}, mz * ToRadians(rotation.z)); - invView.orientation = XrQuaternionf_Multiply(roll, XrQuaternionf_Multiply(pitch, yaw)); - } - - output = ovrMatrix4f_CreateFromQuaternion(&invView.orientation); - float scale = (float)VR_GetConfig(VR_CONFIG_6DOF_SCALE) * 0.000001f; - if (vrConfig[VR_CONFIG_6DOF_ENABLED]) { - output.M[0][3] -= hmdposition.x * (vrConfig[VR_CONFIG_MIRROR_AXIS_X] ? -1.0f : 1.0f) * scale; - output.M[1][3] -= hmdposition.y * (vrConfig[VR_CONFIG_MIRROR_AXIS_Y] ? -1.0f : 1.0f) * scale; - output.M[2][3] -= hmdposition.z * (vrConfig[VR_CONFIG_MIRROR_AXIS_Z] ? -1.0f : 1.0f) * scale; - } - if (vrConfig[VR_CONFIG_6DOF_PRECISE] && (matrix == VR_VIEW_MATRIX_RIGHT_EYE)) { - float dx = fabs(invViewTransform[1].position.x - invViewTransform[0].position.x); - float dy = fabs(invViewTransform[1].position.y - invViewTransform[0].position.y); - float dz = fabs(invViewTransform[1].position.z - invViewTransform[0].position.z); - float ipd = sqrt(dx * dx + dy * dy + dz * dz); - XrVector3f separation = {ipd * scale, 0.0f, 0.0f}; - separation = XrQuaternionf_Rotate(invView.orientation, separation); - separation = XrVector3f_ScalarMultiply(separation, vrConfig[VR_CONFIG_MIRROR_AXIS_Z] ? -1.0f : 1.0f); - output.M[0][3] -= separation.x; - output.M[1][3] -= separation.y; - output.M[2][3] -= separation.z; - } - } else { - assert(false); - } - return output; + return vrMatrix[matrix]; } diff --git a/Common/VR/VRRenderer.h b/Common/VR/VRRenderer.h index 9375370cad..e19a0e82a5 100644 --- a/Common/VR/VRRenderer.h +++ b/Common/VR/VRRenderer.h @@ -26,10 +26,11 @@ enum VRConfig { }; enum VRMatrix { - VR_PROJECTION_MATRIX_LEFT_EYE = 0, - VR_PROJECTION_MATRIX_RIGHT_EYE = 1, - VR_VIEW_MATRIX_LEFT_EYE = 2, - VR_VIEW_MATRIX_RIGHT_EYE = 3 + VR_PROJECTION_MATRIX_LEFT_EYE, + VR_PROJECTION_MATRIX_RIGHT_EYE, + VR_VIEW_MATRIX_LEFT_EYE, + VR_VIEW_MATRIX_RIGHT_EYE, + VR_MATRIX_COUNT }; enum VRMode { diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 482b864ea5..98e1ca6052 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -1057,16 +1057,20 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayRender(JNIEnv *env, SetCurrentThreadName("AndroidRender"); } + if (IsVRBuild() && !StartVRRender()) + return; + if (useCPUThread) { // This is the "GPU thread". - if (graphicsContext) - graphicsContext->ThreadFrame(); + if (!graphicsContext || !graphicsContext->ThreadFrame()) + return; } else { UpdateRunLoopAndroid(env); } if (IsVRBuild()) { UpdateVRInput(NativeKey, NativeTouch, g_Config.bHapticFeedback, dp_xscale, dp_yscale); + FinishVRRender(); } }