Merge pull request #17636 from lvonasek/review_openxr

OpenXR - Major review
This commit is contained in:
Henrik Rydgård 2023-06-27 20:07:42 +02:00 committed by GitHub
commit e4229886b7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 265 additions and 255 deletions

View file

@ -34,7 +34,6 @@ enum VRMatrix {
};
enum VRMirroring {
VR_MIRRORING_UPDATED,
VR_MIRRORING_AXIS_X,
VR_MIRRORING_AXIS_Y,
VR_MIRRORING_AXIS_Z,
@ -54,6 +53,8 @@ static bool vrFlatForced = false;
static bool vrFlatGame = false;
static float vrMatrix[VR_MATRIX_COUNT][16];
static bool vrMirroring[VR_MIRRORING_COUNT];
static int vrMirroringVariant = -1;
static XrView vrView[2];
static void (*NativeAxis)(const AxisInput &axis);
static bool (*NativeKey)(const KeyInput &key);
@ -624,155 +625,35 @@ bool StartVRRender() {
bool vrScene = !vrFlatForced && (g_Config.bManualForceVR || (vr3DGeometryCount > 15));
bool vrStereo = !PSP_CoreParameter().compat.vrCompat().ForceMono && g_Config.bEnableStereo;
// Get OpenXR view and fov
XrFovf fov = {};
XrPosef invViewTransform[2];
// Get VR status
vrMirroringVariant = -1;
for (int eye = 0; eye < ovrMaxNumEyes; eye++) {
XrView view = VR_GetView(eye);
fov.angleLeft += view.fov.angleLeft / 2.0f;
fov.angleRight += view.fov.angleRight / 2.0f;
fov.angleUp += view.fov.angleUp / 2.0f;
fov.angleDown += view.fov.angleDown / 2.0f;
invViewTransform[eye] = view.pose;
vrView[eye] = VR_GetView(eye);
}
UpdateVRViewMatrices();
// Get 6DoF scale
float scale = 1.0f;
if (PSP_CoreParameter().compat.vrCompat().UnitsPerMeter > 0) {
scale = PSP_CoreParameter().compat.vrCompat().UnitsPerMeter;
}
// Update matrices
for (int matrix = 0; matrix < VR_MATRIX_COUNT; matrix++) {
if (matrix == VR_PROJECTION_MATRIX) {
float nearZ = g_Config.fFieldOfViewPercentage / 200.0f;
float tanAngleLeft = tanf(fov.angleLeft);
float tanAngleRight = tanf(fov.angleRight);
float tanAngleDown = tanf(fov.angleDown);
float tanAngleUp = tanf(fov.angleUp);
float M[16] = {};
M[0] = 2 / (tanAngleRight - tanAngleLeft);
M[2] = (tanAngleRight + tanAngleLeft) / (tanAngleRight - tanAngleLeft);
M[5] = 2 / (tanAngleUp - tanAngleDown);
M[6] = (tanAngleUp + tanAngleDown) / (tanAngleUp - tanAngleDown);
M[10] = -1;
M[11] = -(nearZ + nearZ);
M[14] = -1;
memcpy(vrMatrix[matrix], M, sizeof(float) * 16);
} else if ((matrix == VR_VIEW_MATRIX_LEFT_EYE) || (matrix == VR_VIEW_MATRIX_RIGHT_EYE)) {
bool flatScreen = false;
XrPosef invView = invViewTransform[0];
int vrMode = VR_GetConfig(VR_CONFIG_MODE);
if ((vrMode == VR_MODE_MONO_SCREEN) || (vrMode == VR_MODE_STEREO_SCREEN)) {
invView = XrPosef_Identity();
flatScreen = true;
}
// get axis mirroring configuration
float mx = vrMirroring[VR_MIRRORING_PITCH] ? -1.0f : 1.0f;
float my = vrMirroring[VR_MIRRORING_YAW] ? -1.0f : 1.0f;
float mz = vrMirroring[VR_MIRRORING_ROLL] ? -1.0f : 1.0f;
// 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);
}
// apply camera pitch offset
XrVector3f positionOffset = {g_Config.fCameraSide, g_Config.fCameraHeight, g_Config.fCameraDistance};
if (!flatScreen) {
float pitchOffset = 0;
switch (g_Config.iCameraPitch) {
case 1: //Top view -> First person
pitchOffset = 90;
positionOffset = {positionOffset.x, positionOffset.z, -positionOffset.y};
break;
case 2: //First person -> Top view
pitchOffset = -90;
positionOffset = {positionOffset.x, -positionOffset.z + 20, positionOffset.y};
break;
}
XrQuaternionf rotationOffset = XrQuaternionf_CreateFromVectorAngle({1, 0, 0}, ToRadians(pitchOffset));
invView.orientation = XrQuaternionf_Multiply(rotationOffset, invView.orientation);
}
// decompose rotation
XrVector3f rotation = XrQuaternionf_ToEulerAngles(invView.orientation);
float mPitch = mx * ToRadians(rotation.x);
float mYaw = my * ToRadians(rotation.y);
float mRoll = mz * ToRadians(rotation.z);
// use in-game camera interpolated rotation
if (g_Config.bHeadRotationEnabled) mYaw = -my * ToRadians(hmdMotionDiffLast[1]); // horizontal
// create updated quaternion
XrQuaternionf pitch = XrQuaternionf_CreateFromVectorAngle({1, 0, 0}, mPitch);
XrQuaternionf yaw = XrQuaternionf_CreateFromVectorAngle({0, 1, 0}, mYaw);
XrQuaternionf roll = XrQuaternionf_CreateFromVectorAngle({0, 0, 1}, mRoll);
invView.orientation = XrQuaternionf_Multiply(roll, XrQuaternionf_Multiply(pitch, yaw));
float M[16];
XrQuaternionf_ToMatrix4f(&invView.orientation, M);
// Apply 6Dof head movement
if (!flatScreen && g_Config.bEnable6DoF && !g_Config.bHeadRotationEnabled && (g_Config.iCameraPitch == 0)) {
M[3] -= invViewTransform[0].position.x * (vrMirroring[VR_MIRRORING_AXIS_X] ? -1.0f : 1.0f) * scale;
M[7] -= invViewTransform[0].position.y * (vrMirroring[VR_MIRRORING_AXIS_Y] ? -1.0f : 1.0f) * scale;
M[11] -= invViewTransform[0].position.z * (vrMirroring[VR_MIRRORING_AXIS_Z] ? -1.0f : 1.0f) * scale;
}
// Camera adjust - distance
if (fabsf(positionOffset.z) > 0.0f) {
XrVector3f forward = {0.0f, 0.0f, positionOffset.z * scale};
forward = XrQuaternionf_Rotate(invView.orientation, forward);
forward = XrVector3f_ScalarMultiply(forward, vrMirroring[VR_MIRRORING_AXIS_Z] ? -1.0f : 1.0f);
M[3] += forward.x;
M[7] += forward.y;
M[11] += forward.z;
}
// Camera adjust - height
if (fabsf(positionOffset.y) > 0.0f) {
XrVector3f up = {0.0f, -positionOffset.y * scale, 0.0f};
up = XrQuaternionf_Rotate(invView.orientation, up);
up = XrVector3f_ScalarMultiply(up, vrMirroring[VR_MIRRORING_AXIS_Y] ? -1.0f : 1.0f);
M[3] += up.x;
M[7] += up.y;
M[11] += up.z;
}
// Camera adjust - side
if (fabsf(positionOffset.x) > 0.0f) {
XrVector3f side = {-positionOffset.x * scale, 0.0f, 0.0f};
side = XrQuaternionf_Rotate(invView.orientation, side);
side = XrVector3f_ScalarMultiply(side, vrMirroring[VR_MIRRORING_AXIS_X] ? -1.0f : 1.0f);
M[3] += side.x;
M[7] += side.y;
M[11] += side.z;
}
// Stereoscopy
if (vrStereo) {
bool mirrored = vrMirroring[VR_MIRRORING_AXIS_Z] ^ (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.5f, 0.0f, 0.0f};
separation = XrQuaternionf_Rotate(invView.orientation, separation);
separation = XrVector3f_ScalarMultiply(separation, mirrored ? -1.0f : 1.0f);
M[3] += separation.x;
M[7] += separation.y;
M[11] += separation.z;
}
memcpy(vrMatrix[matrix], M, sizeof(float) * 16);
} else {
assert(false);
}
// Update projection matrix
XrFovf fov = {};
for (int eye = 0; eye < ovrMaxNumEyes; eye++) {
fov.angleLeft += vrView[eye].fov.angleLeft / 2.0f;
fov.angleRight += vrView[eye].fov.angleRight / 2.0f;
fov.angleUp += vrView[eye].fov.angleUp / 2.0f;
fov.angleDown += vrView[eye].fov.angleDown / 2.0f;
}
float nearZ = g_Config.fFieldOfViewPercentage / 200.0f;
float tanAngleLeft = tanf(fov.angleLeft);
float tanAngleRight = tanf(fov.angleRight);
float tanAngleDown = tanf(fov.angleDown);
float tanAngleUp = tanf(fov.angleUp);
float M[16] = {};
M[0] = 2 / (tanAngleRight - tanAngleLeft);
M[2] = (tanAngleRight + tanAngleLeft) / (tanAngleRight - tanAngleLeft);
M[5] = 2 / (tanAngleUp - tanAngleDown);
M[6] = (tanAngleUp + tanAngleDown) / (tanAngleUp - tanAngleDown);
M[10] = -1;
M[11] = -(nearZ + nearZ);
M[14] = -1;
memcpy(vrMatrix[VR_PROJECTION_MATRIX], M, sizeof(float) * 16);
// Decide if the scene is 3D or not
VR_SetConfigFloat(VR_CONFIG_CANVAS_ASPECT, 480.0f / 272.0f);
@ -794,7 +675,6 @@ bool StartVRRender() {
__DisplaySetFramerate(g_Config.bForce72Hz ? 72 : 60);
VR_SetConfigFloat(VR_CONFIG_CANVAS_DISTANCE, g_Config.fCanvasDistance);
VR_SetConfig(VR_CONFIG_PASSTHROUGH, g_Config.bPassthrough);
vrMirroring[VR_MIRRORING_UPDATED] = false;
return true;
}
return false;
@ -869,60 +749,61 @@ bool Is2DVRObject(float* projMatrix, bool ortho) {
void UpdateVRParams(float* projMatrix, float* viewMatrix) {
// Set mirroring of axes
bool identityView = PSP_CoreParameter().compat.vrCompat().IdentityViewHack && IsMatrixIdentity(viewMatrix);
if (!vrMirroring[VR_MIRRORING_UPDATED] && !IsMatrixIdentity(projMatrix) && !identityView) {
vrMirroring[VR_MIRRORING_UPDATED] = true;
vrMirroring[VR_MIRRORING_AXIS_X] = projMatrix[0] < 0;
vrMirroring[VR_MIRRORING_AXIS_Y] = projMatrix[5] < 0;
vrMirroring[VR_MIRRORING_AXIS_Z] = projMatrix[10] > 0;
vrMirroring[VR_MIRRORING_AXIS_X] = projMatrix[0] < 0;
vrMirroring[VR_MIRRORING_AXIS_Y] = projMatrix[5] < 0;
vrMirroring[VR_MIRRORING_AXIS_Z] = projMatrix[10] > 0;
float up = 0;
for (int i = 4; i < 7; i++) {
up += viewMatrix[i];
}
float up = 0;
for (int i = 4; i < 7; i++) {
up += viewMatrix[i];
}
int variant = projMatrix[0] < 0;
variant += (projMatrix[5] < 0) << 1;
variant += (projMatrix[10] < 0) << 2;
variant += (up < 0) << 3;
int variant = projMatrix[0] < 0;
variant += (projMatrix[5] < 0) << 1;
variant += (projMatrix[10] < 0) << 2;
variant += (up < 0) << 3;
switch (variant) {
case 0: //e.g. ATV
vrMirroring[VR_MIRRORING_PITCH] = false;
vrMirroring[VR_MIRRORING_YAW] = true;
vrMirroring[VR_MIRRORING_ROLL] = true;
break;
case 1: //e.g. Tales of the World
vrMirroring[VR_MIRRORING_PITCH] = false;
vrMirroring[VR_MIRRORING_YAW] = false;
vrMirroring[VR_MIRRORING_ROLL] = false;
break;
case 2: //e.g.PES 2014
case 3: //untested
case 5: //e.g Dante's Inferno
case 7: //untested
case 8: //untested
case 9: //untested
case 10: //untested
case 11: //untested
case 13: //untested
case 15: //untested
vrMirroring[VR_MIRRORING_PITCH] = true;
vrMirroring[VR_MIRRORING_YAW] = true;
vrMirroring[VR_MIRRORING_ROLL] = false;
break;
case 4: //e.g. Assassins Creed
case 6: //e.g. Ghost in the shell
case 12: //e.g. GTA Vice City
case 14: //untested
vrMirroring[VR_MIRRORING_PITCH] = true;
vrMirroring[VR_MIRRORING_YAW] = false;
vrMirroring[VR_MIRRORING_ROLL] = true;
break;
default:
assert(false);
std::exit(1);
}
switch (variant) {
case 0: //e.g. ATV
case 8: //e,g, Flatout (dynamic objects only)
vrMirroring[VR_MIRRORING_PITCH] = false;
vrMirroring[VR_MIRRORING_YAW] = true;
vrMirroring[VR_MIRRORING_ROLL] = true;
break;
case 1: //e.g. Tales of the World
vrMirroring[VR_MIRRORING_PITCH] = false;
vrMirroring[VR_MIRRORING_YAW] = false;
vrMirroring[VR_MIRRORING_ROLL] = false;
break;
case 2: //e.g.PES 2014
case 3: //untested
case 5: //e.g Dante's Inferno
case 7: //untested
case 9: //untested
case 10: //untested
case 11: //untested
case 13: //untested
case 15: //untested
vrMirroring[VR_MIRRORING_PITCH] = true;
vrMirroring[VR_MIRRORING_YAW] = true;
vrMirroring[VR_MIRRORING_ROLL] = false;
break;
case 4: //e.g. Assassins Creed
case 6: //e.g. Ghost in the shell
case 12: //e.g. GTA Vice City
case 14: //untested
vrMirroring[VR_MIRRORING_PITCH] = true;
vrMirroring[VR_MIRRORING_YAW] = false;
vrMirroring[VR_MIRRORING_ROLL] = true;
break;
default:
assert(false);
std::exit(1);
}
if (vrMirroringVariant != variant) {
vrMirroringVariant = variant;
UpdateVRViewMatrices();
}
}
@ -960,3 +841,126 @@ void UpdateVRView(float* leftEye, float* rightEye) {
memcpy(dst[index], renderView.m, 16 * sizeof(float));
}
}
void UpdateVRViewMatrices() {
// Get 6DoF scale
float scale = 1.0f;
if (PSP_CoreParameter().compat.vrCompat().UnitsPerMeter > 0) {
scale = PSP_CoreParameter().compat.vrCompat().UnitsPerMeter;
}
// Get input
bool flatScreen = false;
XrPosef invView = vrView[0].pose;
int vrMode = VR_GetConfig(VR_CONFIG_MODE);
if ((vrMode == VR_MODE_MONO_SCREEN) || (vrMode == VR_MODE_STEREO_SCREEN)) {
invView = XrPosef_Identity();
flatScreen = true;
}
// get axis mirroring configuration
float mx = vrMirroring[VR_MIRRORING_PITCH] ? -1.0f : 1.0f;
float my = vrMirroring[VR_MIRRORING_YAW] ? -1.0f : 1.0f;
float mz = vrMirroring[VR_MIRRORING_ROLL] ? -1.0f : 1.0f;
// 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);
}
// apply camera pitch offset
XrVector3f positionOffset = {g_Config.fCameraSide, g_Config.fCameraHeight, g_Config.fCameraDistance};
if (!flatScreen) {
float pitchOffset = 0;
switch (g_Config.iCameraPitch) {
case 1: //Top view -> First person
pitchOffset = 90;
positionOffset = {positionOffset.x, positionOffset.z, -positionOffset.y};
break;
case 2: //First person -> Top view
pitchOffset = -90;
positionOffset = {positionOffset.x, -positionOffset.z + 20, positionOffset.y};
break;
}
XrQuaternionf rotationOffset = XrQuaternionf_CreateFromVectorAngle({1, 0, 0}, ToRadians(pitchOffset));
invView.orientation = XrQuaternionf_Multiply(rotationOffset, invView.orientation);
}
// decompose rotation
XrVector3f rotation = XrQuaternionf_ToEulerAngles(invView.orientation);
float mPitch = mx * ToRadians(rotation.x);
float mYaw = my * ToRadians(rotation.y);
float mRoll = mz * ToRadians(rotation.z);
// use in-game camera interpolated rotation
if (g_Config.bHeadRotationEnabled) mYaw = -my * ToRadians(hmdMotionDiffLast[1]); // horizontal
// create updated quaternion
XrQuaternionf pitch = XrQuaternionf_CreateFromVectorAngle({1, 0, 0}, mPitch);
XrQuaternionf yaw = XrQuaternionf_CreateFromVectorAngle({0, 1, 0}, mYaw);
XrQuaternionf roll = XrQuaternionf_CreateFromVectorAngle({0, 0, 1}, mRoll);
invView.orientation = XrQuaternionf_Multiply(roll, XrQuaternionf_Multiply(pitch, yaw));
float M[16];
XrQuaternionf_ToMatrix4f(&invView.orientation, M);
// Apply 6Dof head movement
if (!flatScreen && g_Config.bEnable6DoF && !g_Config.bHeadRotationEnabled && (g_Config.iCameraPitch == 0)) {
M[3] -= vrView[0].pose.position.x * (vrMirroring[VR_MIRRORING_AXIS_X] ? -1.0f : 1.0f) * scale;
M[7] -= vrView[0].pose.position.y * (vrMirroring[VR_MIRRORING_AXIS_Y] ? -1.0f : 1.0f) * scale;
M[11] -= vrView[0].pose.position.z * (vrMirroring[VR_MIRRORING_AXIS_Z] ? -1.0f : 1.0f) * scale;
}
// Camera adjust - distance
if (fabsf(positionOffset.z) > 0.0f) {
XrVector3f forward = {0.0f, 0.0f, positionOffset.z * scale};
forward = XrQuaternionf_Rotate(invView.orientation, forward);
forward = XrVector3f_ScalarMultiply(forward, vrMirroring[VR_MIRRORING_AXIS_Z] ? -1.0f : 1.0f);
M[3] += forward.x;
M[7] += forward.y;
M[11] += forward.z;
}
// Camera adjust - height
if (fabsf(positionOffset.y) > 0.0f) {
XrVector3f up = {0.0f, -positionOffset.y * scale, 0.0f};
up = XrQuaternionf_Rotate(invView.orientation, up);
up = XrVector3f_ScalarMultiply(up, vrMirroring[VR_MIRRORING_AXIS_Y] ? -1.0f : 1.0f);
M[3] += up.x;
M[7] += up.y;
M[11] += up.z;
}
// Camera adjust - side
if (fabsf(positionOffset.x) > 0.0f) {
XrVector3f side = {-positionOffset.x * scale, 0.0f, 0.0f};
side = XrQuaternionf_Rotate(invView.orientation, side);
side = XrVector3f_ScalarMultiply(side, vrMirroring[VR_MIRRORING_AXIS_X] ? -1.0f : 1.0f);
M[3] += side.x;
M[7] += side.y;
M[11] += side.z;
}
for (int matrix = VR_VIEW_MATRIX_LEFT_EYE; matrix <= VR_VIEW_MATRIX_RIGHT_EYE; matrix++) {
// Stereoscopy
bool vrStereo = !PSP_CoreParameter().compat.vrCompat().ForceMono && g_Config.bEnableStereo;
if (vrStereo) {
bool mirrored = vrMirroring[VR_MIRRORING_AXIS_Z] ^ (matrix == VR_VIEW_MATRIX_RIGHT_EYE);
float dx = fabs(vrView[1].pose.position.x - vrView[0].pose.position.x);
float dy = fabs(vrView[1].pose.position.y - vrView[0].pose.position.y);
float dz = fabs(vrView[1].pose.position.z - vrView[0].pose.position.z);
float ipd = sqrt(dx * dx + dy * dy + dz * dz);
XrVector3f separation = {ipd * scale * 0.5f, 0.0f, 0.0f};
separation = XrQuaternionf_Rotate(invView.orientation, separation);
separation = XrVector3f_ScalarMultiply(separation, mirrored ? -1.0f : 2.0f);
M[3] += separation.x;
M[7] += separation.y;
M[11] += separation.z;
}
memcpy(vrMatrix[matrix], M, sizeof(float) * 16);
}
}

View file

@ -59,3 +59,4 @@ bool Is2DVRObject(float* projMatrix, bool ortho);
void UpdateVRParams(float* projMatrix, float* viewMatrix);
void UpdateVRProjection(float* projMatrix, float* leftEye, float* rightEye);
void UpdateVRView(float* leftEye, float* rightEye);
void UpdateVRViewMatrices();

View file

@ -66,8 +66,9 @@ typedef struct {
uint32_t TextureSwapChainLength;
uint32_t TextureSwapChainIndex;
ovrSwapChain ColorSwapChain;
ovrSwapChain DepthSwapChain;
void* ColorSwapChainImage;
unsigned int* GLDepthBuffers;
void* DepthSwapChainImage;
unsigned int* GLFrameBuffers;
VkFramebuffer* VKFrameBuffers;
VkImageView* VKColorImages;

View file

@ -39,8 +39,11 @@ void ovrFramebuffer_Clear(ovrFramebuffer* frameBuffer) {
frameBuffer->ColorSwapChain.Width = 0;
frameBuffer->ColorSwapChain.Height = 0;
frameBuffer->ColorSwapChainImage = NULL;
frameBuffer->DepthSwapChain.Handle = XR_NULL_HANDLE;
frameBuffer->DepthSwapChain.Width = 0;
frameBuffer->DepthSwapChain.Height = 0;
frameBuffer->DepthSwapChainImage = NULL;
frameBuffer->GLDepthBuffers = NULL;
frameBuffer->GLFrameBuffers = NULL;
frameBuffer->Acquired = false;
}
@ -116,6 +119,8 @@ static bool ovrFramebuffer_CreateGLES(XrSession session, ovrFramebuffer* frameBu
frameBuffer->ColorSwapChain.Width = swapChainCreateInfo.width;
frameBuffer->ColorSwapChain.Height = swapChainCreateInfo.height;
frameBuffer->DepthSwapChain.Width = swapChainCreateInfo.width;
frameBuffer->DepthSwapChain.Height = swapChainCreateInfo.height;
// Create the color swapchain.
swapChainCreateInfo.format = GL_SRGB8_ALPHA8;
@ -124,55 +129,45 @@ static bool ovrFramebuffer_CreateGLES(XrSession session, ovrFramebuffer* frameBu
OXR(xrEnumerateSwapchainImages(frameBuffer->ColorSwapChain.Handle, 0, &frameBuffer->TextureSwapChainLength, NULL));
frameBuffer->ColorSwapChainImage = malloc(frameBuffer->TextureSwapChainLength * sizeof(XrSwapchainImageOpenGLESKHR));
// Create the depth swapchain.
swapChainCreateInfo.format = GL_DEPTH24_STENCIL8;
swapChainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
OXR(xrCreateSwapchain(session, &swapChainCreateInfo, &frameBuffer->DepthSwapChain.Handle));
frameBuffer->DepthSwapChainImage = malloc(frameBuffer->TextureSwapChainLength * sizeof(XrSwapchainImageOpenGLESKHR));
// Populate the swapchain image array.
for (uint32_t i = 0; i < frameBuffer->TextureSwapChainLength; i++) {
((XrSwapchainImageOpenGLESKHR*)frameBuffer->ColorSwapChainImage)[i].type = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR;
((XrSwapchainImageOpenGLESKHR*)frameBuffer->ColorSwapChainImage)[i].next = NULL;
((XrSwapchainImageOpenGLESKHR*)frameBuffer->DepthSwapChainImage)[i].type = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR;
((XrSwapchainImageOpenGLESKHR*)frameBuffer->DepthSwapChainImage)[i].next = NULL;
}
OXR(xrEnumerateSwapchainImages(
frameBuffer->ColorSwapChain.Handle,
frameBuffer->TextureSwapChainLength,
&frameBuffer->TextureSwapChainLength,
(XrSwapchainImageBaseHeader*)frameBuffer->ColorSwapChainImage));
OXR(xrEnumerateSwapchainImages(
frameBuffer->DepthSwapChain.Handle,
frameBuffer->TextureSwapChainLength,
&frameBuffer->TextureSwapChainLength,
(XrSwapchainImageBaseHeader*)frameBuffer->DepthSwapChainImage));
frameBuffer->GLDepthBuffers = (GLuint*)malloc(frameBuffer->TextureSwapChainLength * sizeof(GLuint));
frameBuffer->GLFrameBuffers = (GLuint*)malloc(frameBuffer->TextureSwapChainLength * sizeof(GLuint));
for (uint32_t i = 0; i < frameBuffer->TextureSwapChainLength; i++) {
// Create color texture.
const GLuint colorTexture = ((XrSwapchainImageOpenGLESKHR*)frameBuffer->ColorSwapChainImage)[i].image;
GLenum colorTextureTarget = multiview ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
GL(glBindTexture(colorTextureTarget, colorTexture));
GL(glTexParameteri(colorTextureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
GL(glTexParameteri(colorTextureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
GL(glTexParameteri(colorTextureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
GL(glTexParameteri(colorTextureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
GL(glBindTexture(colorTextureTarget, 0));
// Create depth buffer.
if (multiview) {
GL(glGenTextures(1, &frameBuffer->GLDepthBuffers[i]));
GL(glBindTexture(GL_TEXTURE_2D_ARRAY, frameBuffer->GLDepthBuffers[i]));
GL(glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_DEPTH24_STENCIL8, width, height, 2));
GL(glBindTexture(GL_TEXTURE_2D_ARRAY, 0));
} else {
GL(glGenRenderbuffers(1, &frameBuffer->GLDepthBuffers[i]));
GL(glBindRenderbuffer(GL_RENDERBUFFER, frameBuffer->GLDepthBuffers[i]));
GL(glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height));
GL(glBindRenderbuffer(GL_RENDERBUFFER, 0));
}
const GLuint depthTexture = ((XrSwapchainImageOpenGLESKHR*)frameBuffer->DepthSwapChainImage)[i].image;
// Create the frame buffer.
GL(glGenFramebuffers(1, &frameBuffer->GLFrameBuffers[i]));
GL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer->GLFrameBuffers[i]));
if (multiview) {
GL(glFramebufferTextureMultiviewOVR(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, frameBuffer->GLDepthBuffers[i], 0, 0, 2));
GL(glFramebufferTextureMultiviewOVR(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, frameBuffer->GLDepthBuffers[i], 0, 0, 2));
GL(glFramebufferTextureMultiviewOVR(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, depthTexture, 0, 0, 2));
GL(glFramebufferTextureMultiviewOVR(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexture, 0, 0, 2));
GL(glFramebufferTextureMultiviewOVR(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colorTexture, 0, 0, 2));
} else {
GL(glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, frameBuffer->GLDepthBuffers[i]));
GL(glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, frameBuffer->GLDepthBuffers[i]));
GL(glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0));
GL(glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0));
GL(glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 0));
}
GL(GLenum renderFramebufferStatus = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER));
@ -218,6 +213,8 @@ static bool ovrFramebuffer_CreateVK(XrSession session, ovrFramebuffer* frameBuff
frameBuffer->ColorSwapChain.Width = swapChainCreateInfo.width;
frameBuffer->ColorSwapChain.Height = swapChainCreateInfo.height;
frameBuffer->DepthSwapChain.Width = swapChainCreateInfo.width;
frameBuffer->DepthSwapChain.Height = swapChainCreateInfo.height;
// Create the color swapchain.
swapChainCreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
@ -226,16 +223,29 @@ static bool ovrFramebuffer_CreateVK(XrSession session, ovrFramebuffer* frameBuff
OXR(xrEnumerateSwapchainImages(frameBuffer->ColorSwapChain.Handle, 0, &frameBuffer->TextureSwapChainLength, NULL));
frameBuffer->ColorSwapChainImage = malloc(frameBuffer->TextureSwapChainLength * sizeof(XrSwapchainImageVulkanKHR));
// Create the depth swapchain.
swapChainCreateInfo.format = VK_FORMAT_D24_UNORM_S8_UINT;
swapChainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
OXR(xrCreateSwapchain(session, &swapChainCreateInfo, &frameBuffer->DepthSwapChain.Handle));
frameBuffer->DepthSwapChainImage = malloc(frameBuffer->TextureSwapChainLength * sizeof(XrSwapchainImageVulkanKHR));
// Populate the swapchain image array.
for (uint32_t i = 0; i < frameBuffer->TextureSwapChainLength; i++) {
((XrSwapchainImageVulkanKHR*)frameBuffer->ColorSwapChainImage)[i].type = XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR;
((XrSwapchainImageVulkanKHR*)frameBuffer->ColorSwapChainImage)[i].next = NULL;
((XrSwapchainImageVulkanKHR*)frameBuffer->DepthSwapChainImage)[i].type = XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR;
((XrSwapchainImageVulkanKHR*)frameBuffer->DepthSwapChainImage)[i].next = NULL;
}
OXR(xrEnumerateSwapchainImages(
frameBuffer->ColorSwapChain.Handle,
frameBuffer->TextureSwapChainLength,
&frameBuffer->TextureSwapChainLength,
(XrSwapchainImageBaseHeader*)frameBuffer->ColorSwapChainImage));
OXR(xrEnumerateSwapchainImages(
frameBuffer->DepthSwapChain.Handle,
frameBuffer->TextureSwapChainLength,
&frameBuffer->TextureSwapChainLength,
(XrSwapchainImageBaseHeader*)frameBuffer->DepthSwapChainImage));
frameBuffer->VKColorImages = new VkImageView[frameBuffer->TextureSwapChainLength];
frameBuffer->VKDepthImages = new VkImageView[frameBuffer->TextureSwapChainLength];
@ -260,6 +270,14 @@ static bool ovrFramebuffer_CreateVK(XrSession session, ovrFramebuffer* frameBuff
return false;
}
createInfo.image = ((XrSwapchainImageVulkanKHR*)frameBuffer->DepthSwapChainImage)[i].image;
createInfo.format = VK_FORMAT_D24_UNORM_S8_UINT;
createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
if (vkCreateImageView(frameBuffer->VKContext->device, &createInfo, nullptr, &frameBuffer->VKDepthImages[i]) != VK_SUCCESS) {
ALOGE("failed to create depth image view!");
return false;
}
// Create the frame buffer.
VkImageView attachments[] = { frameBuffer->VKColorImages[i], frameBuffer->VKDepthImages[i] };
VkFramebufferCreateInfo framebufferInfo{};
@ -293,14 +311,14 @@ void ovrFramebuffer_Destroy(ovrFramebuffer* frameBuffer) {
delete[] frameBuffer->VKFrameBuffers;
} else {
#if XR_USE_GRAPHICS_API_OPENGL_ES || XR_USE_GRAPHICS_API_OPENGL
GL(glDeleteRenderbuffers(frameBuffer->TextureSwapChainLength, frameBuffer->GLDepthBuffers));
GL(glDeleteFramebuffers(frameBuffer->TextureSwapChainLength, frameBuffer->GLFrameBuffers));
free(frameBuffer->GLDepthBuffers);
free(frameBuffer->GLFrameBuffers);
#endif
}
OXR(xrDestroySwapchain(frameBuffer->ColorSwapChain.Handle));
OXR(xrDestroySwapchain(frameBuffer->DepthSwapChain.Handle));
free(frameBuffer->ColorSwapChainImage);
free(frameBuffer->DepthSwapChainImage);
ovrFramebuffer_Clear(frameBuffer);
}
@ -323,17 +341,8 @@ void ovrFramebuffer_Acquire(ovrFramebuffer* frameBuffer) {
XrSwapchainImageWaitInfo waitInfo;
waitInfo.type = XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO;
waitInfo.next = NULL;
waitInfo.timeout = 1000000; /* timeout in nanoseconds */
waitInfo.timeout = XR_INFINITE_DURATION;
XrResult res = xrWaitSwapchainImage(frameBuffer->ColorSwapChain.Handle, &waitInfo);
int i = 0;
while ((res != XR_SUCCESS) && (i < 10)) {
res = xrWaitSwapchainImage(frameBuffer->ColorSwapChain.Handle, &waitInfo);
i++;
ALOGV(
" Retry xrWaitSwapchainImage %d times due to XR_TIMEOUT_EXPIRED (duration %f micro seconds)",
i,
waitInfo.timeout * (1E-9));
}
frameBuffer->Acquired = res == XR_SUCCESS;
ovrFramebuffer_SetCurrent(frameBuffer);
@ -355,6 +364,10 @@ void ovrFramebuffer_Acquire(ovrFramebuffer* frameBuffer) {
void ovrFramebuffer_Release(ovrFramebuffer* frameBuffer) {
if (frameBuffer->Acquired) {
XrSwapchainImageReleaseInfo releaseInfo = {XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO, NULL};
OXR(xrReleaseSwapchainImage(frameBuffer->ColorSwapChain.Handle, &releaseInfo));
frameBuffer->Acquired = false;
// Clear the alpha channel, other way OpenXR would not transfer the framebuffer fully
if (VR_GetPlatformFlag(VR_PLATFORM_RENDERER_VULKAN)) {
//TODO:implement
@ -366,10 +379,6 @@ void ovrFramebuffer_Release(ovrFramebuffer* frameBuffer) {
GL(glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
#endif
}
XrSwapchainImageReleaseInfo releaseInfo = {XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO, NULL};
OXR(xrReleaseSwapchainImage(frameBuffer->ColorSwapChain.Handle, &releaseInfo));
frameBuffer->Acquired = false;
}
}

View file

@ -327,7 +327,11 @@ bool VR_InitFrame( engine_t* engine ) {
projectionCapacityInput,
&projectionCountOutput,
projections));
//
if ((viewState.viewStateFlags & XR_VIEW_STATE_POSITION_VALID_BIT) == 0 ||
(viewState.viewStateFlags & XR_VIEW_STATE_ORIENTATION_VALID_BIT) == 0) {
return false; // There is no valid tracking poses for the views.
}
fov = {};
for (int eye = 0; eye < ovrMaxNumEyes; eye++) {
@ -486,14 +490,7 @@ void VR_FinishFrame( engine_t* engine ) {
endFrameInfo.environmentBlendMode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
endFrameInfo.layerCount = engine->appState.LayerCount;
endFrameInfo.layers = layers;
OXR(xrEndFrame(engine->appState.Session, &endFrameInfo));
int instances = engine->appState.Renderer.Multiview ? 1 : ovrMaxNumEyes;
for (int i = 0; i < instances; i++) {
ovrFramebuffer* frameBuffer = &engine->appState.Renderer.FrameBuffer[instances];
frameBuffer->TextureSwapChainIndex++;
frameBuffer->TextureSwapChainIndex %= frameBuffer->TextureSwapChainLength;
}
}
int VR_GetConfig( VRConfig config ) {

View file

@ -427,9 +427,6 @@ void LinkedShader::UpdateUniforms(const ShaderID &vsid, bool useBufferedRenderin
} else {
UpdateVRProjection(gstate.projMatrix, leftEyeMatrix.m, rightEyeMatrix.m);
}
float m4x4[16];
ConvertMatrix4x3To4x4Transposed(m4x4, gstate.viewMatrix);
UpdateVRParams(gstate.projMatrix, m4x4);
FlipProjMatrix(leftEyeMatrix, useBufferedRendering);
FlipProjMatrix(rightEyeMatrix, useBufferedRendering);
@ -574,6 +571,7 @@ void LinkedShader::UpdateUniforms(const ShaderID &vsid, bool useBufferedRenderin
ConvertMatrix4x3To4x4Transposed(leftEyeView, gstate.viewMatrix);
ConvertMatrix4x3To4x4Transposed(rightEyeView, gstate.viewMatrix);
if (!is2D) {
UpdateVRParams(gstate.projMatrix, leftEyeView);
UpdateVRView(leftEyeView, rightEyeView);
}
render_->SetUniformM4x4Stereo("u_view", &u_view, leftEyeView, rightEyeView);