OpenXR renderer in progress

This commit is contained in:
Lubos 2022-03-31 17:47:36 +02:00
parent e7a2229edc
commit 7b9d51ec30
7 changed files with 762 additions and 70 deletions

View file

@ -28,6 +28,7 @@ add_dependencies(main copy_libs)
target_include_directories(main PRIVATE
${CMAKE_SOURCE_DIR}/code/OpenXR-SDK/include
${CMAKE_SOURCE_DIR}/code/OpenXR/Include
${CMAKE_SOURCE_DIR}/code/SDL2/include
${CMAKE_SOURCE_DIR}/code)

View file

@ -298,8 +298,6 @@ static void InitOpenGL( void )
// set default state
GL_SetDefaultState();
VR_ReInitRenderer();
}
/*

View file

@ -0,0 +1,555 @@
#include "vr_types.h"
/************************************************************************************
Original file name : XrCompositor_NativeActivity.c
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
*************************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/prctl.h>
#include <android/log.h>
#include <assert.h>
#if !defined(EGL_OPENGL_ES3_BIT_KHR)
#define EGL_OPENGL_ES3_BIT_KHR 0x0040
#endif
// EXT_texture_border_clamp
#ifndef GL_CLAMP_TO_BORDER
#define GL_CLAMP_TO_BORDER 0x812D
#endif
#ifndef GL_TEXTURE_BORDER_COLOR
#define GL_TEXTURE_BORDER_COLOR 0x1004
#endif
#if !defined(GL_EXT_multisampled_render_to_texture)
typedef void(GL_APIENTRY* PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)(
GLenum target,
GLsizei samples,
GLenum internalformat,
GLsizei width,
GLsizei height);
typedef void(GL_APIENTRY* PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC)(
GLenum target,
GLenum attachment,
GLenum textarget,
GLuint texture,
GLint level,
GLsizei samples);
#endif
// GL_EXT_texture_cube_map_array
#if !defined(GL_TEXTURE_CUBE_MAP_ARRAY)
#define GL_TEXTURE_CUBE_MAP_ARRAY 0x9009
#endif
#define MATH_PI 3.14159265358979323846f
#define GL(func) func;
#define OXR(func) func;
#define OVR_LOG_TAG "XrCompositor"
#define ALOGE(...) Com_Printf(__VA_ARGS__)
#define ALOGV(...) Com_Printf(__VA_ARGS__)
static const int CPU_LEVEL = 2;
static const int GPU_LEVEL = 3;
static const int NUM_MULTI_SAMPLES = 4;
typedef union {
XrCompositionLayerProjection Projection;
XrCompositionLayerQuad Quad;
XrCompositionLayerCylinderKHR Cylinder;
XrCompositionLayerCubeKHR Cube;
XrCompositionLayerEquirect2KHR Equirect2;
} ovrCompositorLayer_Union;
/*
================================================================================
OpenGL-ES Utility Functions
================================================================================
*/
static const char* EglErrorString(const EGLint error) {
switch (error) {
case EGL_SUCCESS:
return "EGL_SUCCESS";
case EGL_NOT_INITIALIZED:
return "EGL_NOT_INITIALIZED";
case EGL_BAD_ACCESS:
return "EGL_BAD_ACCESS";
case EGL_BAD_ALLOC:
return "EGL_BAD_ALLOC";
case EGL_BAD_ATTRIBUTE:
return "EGL_BAD_ATTRIBUTE";
case EGL_BAD_CONTEXT:
return "EGL_BAD_CONTEXT";
case EGL_BAD_CONFIG:
return "EGL_BAD_CONFIG";
case EGL_BAD_CURRENT_SURFACE:
return "EGL_BAD_CURRENT_SURFACE";
case EGL_BAD_DISPLAY:
return "EGL_BAD_DISPLAY";
case EGL_BAD_SURFACE:
return "EGL_BAD_SURFACE";
case EGL_BAD_MATCH:
return "EGL_BAD_MATCH";
case EGL_BAD_PARAMETER:
return "EGL_BAD_PARAMETER";
case EGL_BAD_NATIVE_PIXMAP:
return "EGL_BAD_NATIVE_PIXMAP";
case EGL_BAD_NATIVE_WINDOW:
return "EGL_BAD_NATIVE_WINDOW";
case EGL_CONTEXT_LOST:
return "EGL_CONTEXT_LOST";
default:
return "unknown";
}
}
static const char* GlFrameBufferStatusString(GLenum status) {
switch (status) {
case GL_FRAMEBUFFER_UNDEFINED:
return "GL_FRAMEBUFFER_UNDEFINED";
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
case GL_FRAMEBUFFER_UNSUPPORTED:
return "GL_FRAMEBUFFER_UNSUPPORTED";
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
return "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE";
default:
return "unknown";
}
}
/*
================================================================================
ovrFramebuffer
================================================================================
*/
static void ovrFramebuffer_Clear(ovrFramebuffer* frameBuffer) {
frameBuffer->Width = 0;
frameBuffer->Height = 0;
frameBuffer->Multisamples = 0;
frameBuffer->TextureSwapChainLength = 0;
frameBuffer->TextureSwapChainIndex = 0;
frameBuffer->ColorSwapChain.Handle = XR_NULL_HANDLE;
frameBuffer->ColorSwapChain.Width = 0;
frameBuffer->ColorSwapChain.Height = 0;
frameBuffer->ColorSwapChainImage = NULL;
frameBuffer->DepthBuffers = NULL;
frameBuffer->FrameBuffers = NULL;
}
static GLboolean ovrFramebuffer_Create(
XrSession session,
ovrFramebuffer* frameBuffer,
const GLenum colorFormat,
const int width,
const int height,
const int multisamples) {
PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT =
(PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)eglGetProcAddress(
"glRenderbufferStorageMultisampleEXT");
PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC glFramebufferTexture2DMultisampleEXT =
(PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC)eglGetProcAddress(
"glFramebufferTexture2DMultisampleEXT");
frameBuffer->Width = width;
frameBuffer->Height = height;
frameBuffer->Multisamples = multisamples;
GLenum requestedGLFormat = colorFormat;
// Get the number of supported formats.
uint32_t numInputFormats = 0;
uint32_t numOutputFormats = 0;
OXR(xrEnumerateSwapchainFormats(session, numInputFormats, &numOutputFormats, NULL));
// Allocate an array large enough to contain the supported formats.
numInputFormats = numOutputFormats;
int64_t* supportedFormats = (int64_t*)malloc(numOutputFormats * sizeof(int64_t));
if (supportedFormats != NULL) {
OXR(xrEnumerateSwapchainFormats(
session, numInputFormats, &numOutputFormats, supportedFormats));
}
// Verify the requested format is supported.
uint64_t selectedFormat = 0;
for (uint32_t i = 0; i < numOutputFormats; i++) {
if (supportedFormats[i] == requestedGLFormat) {
selectedFormat = supportedFormats[i];
break;
}
}
free(supportedFormats);
if (selectedFormat == 0) {
ALOGE("Format not supported");
}
XrSwapchainCreateInfo swapChainCreateInfo;
memset(&swapChainCreateInfo, 0, sizeof(swapChainCreateInfo));
swapChainCreateInfo.type = XR_TYPE_SWAPCHAIN_CREATE_INFO;
swapChainCreateInfo.usageFlags =
XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT;
swapChainCreateInfo.format = selectedFormat;
swapChainCreateInfo.sampleCount = 1;
swapChainCreateInfo.width = width;
swapChainCreateInfo.height = height;
swapChainCreateInfo.faceCount = 1;
swapChainCreateInfo.arraySize = 1;
swapChainCreateInfo.mipCount = 1;
// Enable Foveation on this swapchain
XrSwapchainCreateInfoFoveationFB swapChainFoveationCreateInfo;
memset(&swapChainFoveationCreateInfo, 0, sizeof(swapChainFoveationCreateInfo));
swapChainFoveationCreateInfo.type = XR_TYPE_SWAPCHAIN_CREATE_INFO_FOVEATION_FB;
swapChainCreateInfo.next = &swapChainFoveationCreateInfo;
frameBuffer->ColorSwapChain.Width = swapChainCreateInfo.width;
frameBuffer->ColorSwapChain.Height = swapChainCreateInfo.height;
// Create the swapchain.
OXR(xrCreateSwapchain(session, &swapChainCreateInfo, &frameBuffer->ColorSwapChain.Handle));
// Get the number of swapchain images.
OXR(xrEnumerateSwapchainImages(
frameBuffer->ColorSwapChain.Handle, 0, &frameBuffer->TextureSwapChainLength, NULL));
// Allocate the swapchain images array.
frameBuffer->ColorSwapChainImage = (XrSwapchainImageOpenGLESKHR*)malloc(
frameBuffer->TextureSwapChainLength * sizeof(XrSwapchainImageOpenGLESKHR));
// Populate the swapchain image array.
for (uint32_t i = 0; i < frameBuffer->TextureSwapChainLength; i++) {
frameBuffer->ColorSwapChainImage[i].type = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR;
frameBuffer->ColorSwapChainImage[i].next = NULL;
}
OXR(xrEnumerateSwapchainImages(
frameBuffer->ColorSwapChain.Handle,
frameBuffer->TextureSwapChainLength,
&frameBuffer->TextureSwapChainLength,
(XrSwapchainImageBaseHeader*)frameBuffer->ColorSwapChainImage));
frameBuffer->DepthBuffers =
(GLuint*)malloc(frameBuffer->TextureSwapChainLength * sizeof(GLuint));
frameBuffer->FrameBuffers =
(GLuint*)malloc(frameBuffer->TextureSwapChainLength * sizeof(GLuint));
for (uint32_t i = 0; i < frameBuffer->TextureSwapChainLength; i++) {
// Create the color buffer texture.
const GLuint colorTexture = frameBuffer->ColorSwapChainImage[i].image;
GLenum colorTextureTarget = 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));
if (multisamples > 1 && glRenderbufferStorageMultisampleEXT != NULL &&
glFramebufferTexture2DMultisampleEXT != NULL) {
// Create multisampled depth buffer.
GL(glGenRenderbuffers(1, &frameBuffer->DepthBuffers[i]));
GL(glBindRenderbuffer(GL_RENDERBUFFER, frameBuffer->DepthBuffers[i]));
GL(glRenderbufferStorageMultisampleEXT(
GL_RENDERBUFFER, multisamples, GL_DEPTH_COMPONENT24, width, height));
GL(glBindRenderbuffer(GL_RENDERBUFFER, 0));
// Create the frame buffer.
// NOTE: glFramebufferTexture2DMultisampleEXT only works with GL_FRAMEBUFFER.
GL(glGenFramebuffers(1, &frameBuffer->FrameBuffers[i]));
GL(glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer->FrameBuffers[i]));
GL(glFramebufferTexture2DMultisampleEXT(
GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D,
colorTexture,
0,
multisamples));
GL(glFramebufferRenderbuffer(
GL_FRAMEBUFFER,
GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER,
frameBuffer->DepthBuffers[i]));
GL(GLenum renderFramebufferStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER));
GL(glBindFramebuffer(GL_FRAMEBUFFER, 0));
if (renderFramebufferStatus != GL_FRAMEBUFFER_COMPLETE) {
ALOGE(
"Incomplete frame buffer object: %s",
GlFrameBufferStatusString(renderFramebufferStatus));
return false;
}
} else {
// Create depth buffer.
GL(glGenRenderbuffers(1, &frameBuffer->DepthBuffers[i]));
GL(glBindRenderbuffer(GL_RENDERBUFFER, frameBuffer->DepthBuffers[i]));
GL(glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height));
GL(glBindRenderbuffer(GL_RENDERBUFFER, 0));
// Create the frame buffer.
GL(glGenFramebuffers(1, &frameBuffer->FrameBuffers[i]));
GL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer->FrameBuffers[i]));
GL(glFramebufferRenderbuffer(
GL_DRAW_FRAMEBUFFER,
GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER,
frameBuffer->DepthBuffers[i]));
GL(glFramebufferTexture2D(
GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 0));
GL(GLenum renderFramebufferStatus = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER));
GL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0));
if (renderFramebufferStatus != GL_FRAMEBUFFER_COMPLETE) {
ALOGE(
"Incomplete frame buffer object: %s",
GlFrameBufferStatusString(renderFramebufferStatus));
return false;
}
}
}
return true;
}
static void ovrFramebuffer_Destroy(ovrFramebuffer* frameBuffer) {
GL(glDeleteFramebuffers(frameBuffer->TextureSwapChainLength, frameBuffer->FrameBuffers));
GL(glDeleteRenderbuffers(frameBuffer->TextureSwapChainLength, frameBuffer->DepthBuffers));
OXR(xrDestroySwapchain(frameBuffer->ColorSwapChain.Handle));
free(frameBuffer->ColorSwapChainImage);
free(frameBuffer->DepthBuffers);
free(frameBuffer->FrameBuffers);
ovrFramebuffer_Clear(frameBuffer);
}
static void ovrFramebuffer_SetCurrent(ovrFramebuffer* frameBuffer) {
GL(glBindFramebuffer(
GL_DRAW_FRAMEBUFFER, frameBuffer->FrameBuffers[frameBuffer->TextureSwapChainIndex]));
}
static void ovrFramebuffer_SetNone() {
GL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0));
}
static void ovrFramebuffer_Resolve(ovrFramebuffer* frameBuffer) {
// Discard the depth buffer, so the tiler won't need to write it back out to memory.
const GLenum depthAttachment[1] = {GL_DEPTH_ATTACHMENT};
glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER, 1, depthAttachment);
// We now let the resolve happen implicitly.
}
static void ovrFramebuffer_Acquire(ovrFramebuffer* frameBuffer) {
// Acquire the swapchain image
XrSwapchainImageAcquireInfo acquireInfo = {XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO, NULL};
OXR(xrAcquireSwapchainImage(
frameBuffer->ColorSwapChain.Handle, &acquireInfo, &frameBuffer->TextureSwapChainIndex));
XrSwapchainImageWaitInfo waitInfo;
waitInfo.type = XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO;
waitInfo.next = NULL;
waitInfo.timeout = 1000000000; /* timeout in nanoseconds */
XrResult res = xrWaitSwapchainImage(frameBuffer->ColorSwapChain.Handle, &waitInfo);
int i = 0;
while (res == XR_TIMEOUT_EXPIRED) {
res = xrWaitSwapchainImage(frameBuffer->ColorSwapChain.Handle, &waitInfo);
i++;
ALOGV(
" Retry xrWaitSwapchainImage %d times due to XR_TIMEOUT_EXPIRED (duration %f seconds)",
i,
waitInfo.timeout * (1E-9));
}
}
static void ovrFramebuffer_Release(ovrFramebuffer* frameBuffer) {
XrSwapchainImageReleaseInfo releaseInfo = {XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO, NULL};
OXR(xrReleaseSwapchainImage(frameBuffer->ColorSwapChain.Handle, &releaseInfo));
}
/*
================================================================================
ovrRenderer
================================================================================
*/
static void ovrRenderer_Clear(ovrRenderer* renderer) {
for (int eye = 0; eye < XR_EYES_COUNT; eye++) {
ovrFramebuffer_Clear(&renderer->FrameBuffer[eye]);
}
}
static void ovrRenderer_Create(
XrSession session,
ovrRenderer* renderer,
int suggestedEyeTextureWidth,
int suggestedEyeTextureHeight) {
// Create the frame buffers.
for (int eye = 0; eye < XR_EYES_COUNT; eye++) {
ovrFramebuffer_Create(
session,
&renderer->FrameBuffer[eye],
GL_SRGB8_ALPHA8,
suggestedEyeTextureWidth,
suggestedEyeTextureHeight,
NUM_MULTI_SAMPLES);
}
}
static void ovrRenderer_Destroy(ovrRenderer* renderer) {
for (int eye = 0; eye < XR_EYES_COUNT; eye++) {
ovrFramebuffer_Destroy(&renderer->FrameBuffer[eye]);
}
}
static void ovrRenderer_SetFoveation(
XrInstance* instance,
XrSession* session,
ovrRenderer* renderer,
XrFoveationLevelFB level,
float verticalOffset,
XrFoveationDynamicFB dynamic) {
PFN_xrCreateFoveationProfileFB pfnCreateFoveationProfileFB;
OXR(xrGetInstanceProcAddr(
*instance,
"xrCreateFoveationProfileFB",
(PFN_xrVoidFunction*)(&pfnCreateFoveationProfileFB)));
PFN_xrDestroyFoveationProfileFB pfnDestroyFoveationProfileFB;
OXR(xrGetInstanceProcAddr(
*instance,
"xrDestroyFoveationProfileFB",
(PFN_xrVoidFunction*)(&pfnDestroyFoveationProfileFB)));
PFN_xrUpdateSwapchainFB pfnUpdateSwapchainFB;
OXR(xrGetInstanceProcAddr(
*instance, "xrUpdateSwapchainFB", (PFN_xrVoidFunction*)(&pfnUpdateSwapchainFB)));
for (int eye = 0; eye < XR_EYES_COUNT; eye++) {
XrFoveationLevelProfileCreateInfoFB levelProfileCreateInfo;
memset(&levelProfileCreateInfo, 0, sizeof(levelProfileCreateInfo));
levelProfileCreateInfo.type = XR_TYPE_FOVEATION_LEVEL_PROFILE_CREATE_INFO_FB;
levelProfileCreateInfo.level = level;
levelProfileCreateInfo.verticalOffset = verticalOffset;
levelProfileCreateInfo.dynamic = dynamic;
XrFoveationProfileCreateInfoFB profileCreateInfo;
memset(&profileCreateInfo, 0, sizeof(profileCreateInfo));
profileCreateInfo.type = XR_TYPE_FOVEATION_PROFILE_CREATE_INFO_FB;
profileCreateInfo.next = &levelProfileCreateInfo;
XrFoveationProfileFB foveationProfile;
pfnCreateFoveationProfileFB(*session, &profileCreateInfo, &foveationProfile);
XrSwapchainStateFoveationFB foveationUpdateState;
memset(&foveationUpdateState, 0, sizeof(foveationUpdateState));
foveationUpdateState.type = XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB;
foveationUpdateState.profile = foveationProfile;
pfnUpdateSwapchainFB(
renderer->FrameBuffer[eye].ColorSwapChain.Handle,
(XrSwapchainStateBaseHeaderFB*)(&foveationUpdateState));
pfnDestroyFoveationProfileFB(foveationProfile);
}
}
static inline ovrMatrix4f ovrMatrix4f_CreateProjection(
const float minX,
const float maxX,
float const minY,
const float maxY,
const float nearZ,
const float farZ) {
const float width = maxX - minX;
const float height = maxY - minY;
const float offsetZ = nearZ; // set to zero for a [0,1] clip space
ovrMatrix4f out;
if (farZ <= nearZ) {
// place the far plane at infinity
out.M[0][0] = 2 * nearZ / width;
out.M[0][1] = 0;
out.M[0][2] = (maxX + minX) / width;
out.M[0][3] = 0;
out.M[1][0] = 0;
out.M[1][1] = 2 * nearZ / height;
out.M[1][2] = (maxY + minY) / height;
out.M[1][3] = 0;
out.M[2][0] = 0;
out.M[2][1] = 0;
out.M[2][2] = -1;
out.M[2][3] = -(nearZ + offsetZ);
out.M[3][0] = 0;
out.M[3][1] = 0;
out.M[3][2] = -1;
out.M[3][3] = 0;
} else {
// normal projection
out.M[0][0] = 2 * nearZ / width;
out.M[0][1] = 0;
out.M[0][2] = (maxX + minX) / width;
out.M[0][3] = 0;
out.M[1][0] = 0;
out.M[1][1] = 2 * nearZ / height;
out.M[1][2] = (maxY + minY) / height;
out.M[1][3] = 0;
out.M[2][0] = 0;
out.M[2][1] = 0;
out.M[2][2] = -(farZ + offsetZ) / (farZ - nearZ);
out.M[2][3] = -(farZ * (nearZ + offsetZ)) / (farZ - nearZ);
out.M[3][0] = 0;
out.M[3][1] = 0;
out.M[3][2] = -1;
out.M[3][3] = 0;
}
return out;
}
static inline ovrMatrix4f ovrMatrix4f_CreateProjectionFov(
const float fovDegreesX,
const float fovDegreesY,
const float offsetX,
const float offsetY,
const float nearZ,
const float farZ) {
const float halfWidth = nearZ * tanf(fovDegreesX * (M_PI / 180.0f * 0.5f));
const float halfHeight = nearZ * tanf(fovDegreesY * (M_PI / 180.0f * 0.5f));
const float minX = offsetX - halfWidth;
const float maxX = offsetX + halfWidth;
const float minY = offsetY - halfHeight;
const float maxY = offsetY + halfHeight;
return ovrMatrix4f_CreateProjection(minX, maxX, minY, maxY, nearZ, farZ);
}

View file

@ -259,7 +259,6 @@ void VR_EnterVR( engine_t* engine, ovrJava java ) {
sessionCreateInfo.next = &graphicsBindingAndroidGLES;
sessionCreateInfo.createFlags = 0;
sessionCreateInfo.systemId = engine->systemId;
if (xrCreateSession(engine->instance, &sessionCreateInfo, &engine->session) != XR_SUCCESS) {
Com_Printf("xrCreateSession failed");
exit(1);

View file

@ -4,6 +4,7 @@
#include "../qcommon/q_shared.h"
#include "../qcommon/qcommon.h"
#include "../client/client.h"
#include "ovr_renderer.inl"
#include "vr_clientinfo.h"
#include "vr_types.h"
@ -23,6 +24,7 @@
extern vr_clientinfo_t vr;
void APIENTRY VR_GLDebugLog(GLenum source, GLenum type, GLuint id,
GLenum severity, GLsizei length, const GLchar* message, const void* userParam)
{
@ -87,64 +89,21 @@ void VR_InitRenderer( engine_t* engine ) {
glDebugMessageCallback(VR_GLDebugLog, 0);
#endif
//TODO:
/*
int eyeW, eyeH;
VR_GetResolution(engine, &eyeW, &eyeH);
ovrRenderer_Create(engine->session, &engine->renderer, eyeW, eyeH);
for (int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; ++eye) {
framebuffer_t* framebuffer = &engine->framebuffers[eye];
framebuffer->colorTexture = vrapi_CreateTextureSwapChain3(VRAPI_TEXTURE_TYPE_2D, GL_RGBA8,
eyeW, eyeH, 1, 3);
framebuffer->swapchainLength = vrapi_GetTextureSwapChainLength(framebuffer->colorTexture);
framebuffer->depthBuffers = (GLuint*)malloc(framebuffer->swapchainLength * sizeof(GLuint));
framebuffer->framebuffers = (GLuint*)malloc(framebuffer->swapchainLength * sizeof(GLuint));
for (int index = 0; index < framebuffer->swapchainLength; ++index) {
GLuint colorTexture;
GLenum framebufferStatus;
colorTexture = vrapi_GetTextureSwapChainHandle(framebuffer->colorTexture, index);
glBindTexture(GL_TEXTURE_2D, colorTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
glGenRenderbuffers(1, &framebuffer->depthBuffers[index]);
glBindRenderbuffer(GL_RENDERBUFFER, framebuffer->depthBuffers[index]);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, eyeW, eyeH);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glGenFramebuffers(1, &framebuffer->framebuffers[index]);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer->framebuffers[index]);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
framebuffer->depthBuffers[index]);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 0);
framebufferStatus = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
assert(framebufferStatus == GL_FRAMEBUFFER_COMPLETE);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
}
}
*/
XrReferenceSpaceCreateInfo spaceCreateInfo = {};
spaceCreateInfo.type = XR_TYPE_REFERENCE_SPACE_CREATE_INFO;
spaceCreateInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_STAGE;
spaceCreateInfo.poseInReferenceSpace.orientation.w = 1.0f;
spaceCreateInfo.poseInReferenceSpace.position.y = 0.0f;
xrCreateReferenceSpace(engine->session, &spaceCreateInfo, &engine->stageSpace);
}
void VR_DestroyRenderer( engine_t* engine ) {
//TODO:
/*
for (int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; ++eye)
{
if (engine->framebuffers[eye].swapchainLength > 0) {
glDeleteFramebuffers(engine->framebuffers[eye].swapchainLength,
engine->framebuffers[eye].depthBuffers);
free(engine->framebuffers[eye].depthBuffers);
free(engine->framebuffers[eye].framebuffers);
vrapi_DestroyTextureSwapChain(engine->framebuffers[eye].colorTexture);
memset(&engine->framebuffers[eye], 0, sizeof(engine->framebuffers[eye]));
}
}
*/
xrDestroySpace(engine->stageSpace);
ovrRenderer_Destroy(&engine->renderer);
}
@ -238,9 +197,8 @@ ovrLayerCylinder2 BuildCylinderLayer(engine_t* engine, const int textureWidth, c
}
*/
void VR_ClearFrameBuffer( GLuint frameBuffer, int width, int height)
void VR_ClearFrameBuffer( int width, int height )
{
glBindFramebuffer( GL_DRAW_FRAMEBUFFER, frameBuffer );
glEnable( GL_SCISSOR_TEST );
glViewport( 0, 0, width, height );
@ -261,11 +219,165 @@ void VR_ClearFrameBuffer( GLuint frameBuffer, int width, int height)
glScissor( 0, 0, 0, 0 );
glDisable( GL_SCISSOR_TEST );
glBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 );
}
void VR_DrawFrame( engine_t* engine ) {
XrEventDataBuffer eventDataBuffer = {};
// Poll for events
for (;;) {
XrEventDataBaseHeader *baseEventHeader = (XrEventDataBaseHeader * )(&eventDataBuffer);
baseEventHeader->type = XR_TYPE_EVENT_DATA_BUFFER;
baseEventHeader->next = NULL;
if (xrPollEvent(engine->instance, &eventDataBuffer) != XR_SUCCESS) {
break;
}
if (baseEventHeader->type == XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED) {
const XrEventDataSessionStateChanged* session_state_changed_event =
(XrEventDataSessionStateChanged*)(baseEventHeader);
switch (session_state_changed_event->state) {
case XR_SESSION_STATE_READY:
if (!engine->sessionActive) {
XrSessionBeginInfo sessionBeginInfo;
memset(&sessionBeginInfo, 0, sizeof(sessionBeginInfo));
sessionBeginInfo.type = XR_TYPE_SESSION_BEGIN_INFO;
sessionBeginInfo.next = NULL;
sessionBeginInfo.primaryViewConfigurationType = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO;
if (xrBeginSession(engine->session, &sessionBeginInfo) != XR_SUCCESS) {
Com_Printf("xrBeginSession failed");
exit(1);
}
engine->sessionActive = GL_TRUE;
}
break;
case XR_SESSION_STATE_STOPPING:
if (engine->sessionActive) {
xrEndSession(engine->session);
engine->sessionActive = GL_FALSE;
}
break;
}
}
}
if (!engine->sessionActive) {
return;
}
// NOTE: OpenXR does not use the concept of frame indices. Instead,
// XrWaitFrame returns the predicted display time.
XrFrameWaitInfo waitFrameInfo = {};
waitFrameInfo.type = XR_TYPE_FRAME_WAIT_INFO;
waitFrameInfo.next = NULL;
XrFrameState frameState = {};
frameState.type = XR_TYPE_FRAME_STATE;
frameState.next = NULL;
xrWaitFrame(engine->session, &waitFrameInfo, &frameState);
XrFrameBeginInfo beginFrameDesc = {};
beginFrameDesc.type = XR_TYPE_FRAME_BEGIN_INFO;
beginFrameDesc.next = NULL;
xrBeginFrame(engine->session, &beginFrameDesc);
float fov_y = 90; //TODO:
float fov_x = 90; //TODO:
if (vr.weapon_zoomed) {
vr.weapon_zoomLevel += 0.05;
if (vr.weapon_zoomLevel > 2.5f)
vr.weapon_zoomLevel = 2.5f;
}
else {
//Zoom back out quicker
vr.weapon_zoomLevel -= 0.25f;
if (vr.weapon_zoomLevel < 1.0f)
vr.weapon_zoomLevel = 1.0f;
}
const ovrMatrix4f projectionMatrix = ovrMatrix4f_CreateProjectionFov(
fov_x / vr.weapon_zoomLevel, fov_y / vr.weapon_zoomLevel, 0.0f, 0.0f, 1.0f, 0.0f );
re.SetVRHeadsetParms(projectionMatrix.M,
engine->renderer.FrameBuffer[0].FrameBuffers[engine->renderer.FrameBuffer[0].TextureSwapChainIndex],
engine->renderer.FrameBuffer[1].FrameBuffers[engine->renderer.FrameBuffer[1].TextureSwapChainIndex]);
for (int eye = 0; eye < XR_EYES_COUNT; eye++) {
ovrFramebuffer* frameBuffer = &engine->renderer.FrameBuffer[eye];
ovrFramebuffer_Acquire(frameBuffer);
ovrFramebuffer_SetCurrent(frameBuffer);
VR_ClearFrameBuffer(frameBuffer->Width, frameBuffer->Height);
Com_Frame();
ovrFramebuffer_Resolve(frameBuffer);
ovrFramebuffer_Release(frameBuffer);
}
ovrFramebuffer_SetNone();
// Compose the layers for this frame.
XrCompositionLayerProjectionView projection_layer_elements[XR_EYES_COUNT] = {};
XrCompositionLayerProjection projection_layer = {};
projection_layer.type = XR_TYPE_COMPOSITION_LAYER_PROJECTION;
projection_layer.layerFlags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
projection_layer.layerFlags |= XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT;
projection_layer.space = engine->stageSpace;
projection_layer.viewCount = XR_EYES_COUNT;
projection_layer.views = projection_layer_elements;
XrPosef viewTransform[2];
ovrSceneMatrices sceneMatrices;
XrView* projections = (XrView*)(malloc(XR_EYES_COUNT * sizeof(XrView)));
for (int eye = 0; eye < XR_EYES_COUNT; eye++) {
XrPosef xfHeadFromEye = projections[eye].pose;
//XrPosef xfStageFromEye = XrPosef_Multiply(xfStageFromHead, xfHeadFromEye);
viewTransform[eye] = XrPosef_Inverse(xfHeadFromEye); //TODO:there should be xfStageFromEye as parameter
sceneMatrices.ViewMatrix[eye] =
XrMatrix4x4f_CreateFromRigidTransform(&viewTransform[eye]);
const XrFovf fov = projections[eye].fov;
XrMatrix4x4f_CreateProjectionFov(
&sceneMatrices.ProjectionMatrix[eye],
fov.angleLeft,
fov.angleRight,
fov.angleUp,
fov.angleDown,
0.1f,
0.0f);
}
for (int eye = 0; eye < XR_EYES_COUNT; eye++) {
ovrFramebuffer* frameBuffer = &engine->renderer.FrameBuffer[eye];
memset(&projection_layer_elements[eye], 0, sizeof(XrCompositionLayerProjectionView));
projection_layer_elements[eye].type = XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW;
projection_layer_elements[eye].pose = XrPosef_Inverse(viewTransform[eye]);
projection_layer_elements[eye].fov = projections[eye].fov;
memset(&projection_layer_elements[eye].subImage, 0, sizeof(XrSwapchainSubImage));
projection_layer_elements[eye].subImage.swapchain = frameBuffer->ColorSwapChain.Handle;
projection_layer_elements[eye].subImage.imageRect.offset.x = 0;
projection_layer_elements[eye].subImage.imageRect.offset.y = 0;
projection_layer_elements[eye].subImage.imageRect.extent.width =
frameBuffer->ColorSwapChain.Width;
projection_layer_elements[eye].subImage.imageRect.extent.height =
frameBuffer->ColorSwapChain.Height;
projection_layer_elements[eye].subImage.imageArrayIndex = 0;
}
// Compose the layers for this frame.
const XrCompositionLayerBaseHeader* layers[1] = {};
layers[0] = (const XrCompositionLayerBaseHeader*)&projection_layer;
XrFrameEndInfo endFrameInfo = {};
endFrameInfo.type = XR_TYPE_FRAME_END_INFO;
endFrameInfo.displayTime = frameState.predictedDisplayTime;
endFrameInfo.environmentBlendMode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
endFrameInfo.layerCount = 1;
endFrameInfo.layers = layers;
xrEndFrame(engine->session, &endFrameInfo);
free(projections);
//TODO
/*

View file

@ -10,13 +10,18 @@
#endif
//OpenXR
#define XR_EYES_COUNT 2
#define XR_USE_GRAPHICS_API_OPENGL_ES 1
#define XR_USE_PLATFORM_ANDROID 1
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES3/gl3.h>
#include <GLES3/gl3ext.h>
#include <jni.h>
#include <openxr/openxr.h>
#include <openxr/openxr_platform.h>
#include <openxr/openxr_oculus.h>
#include <openxr/openxr_oculus_helpers.h>
typedef struct {
JavaVM* Vm;
@ -25,22 +30,45 @@ typedef struct {
} ovrJava;
typedef struct {
int swapchainLength;
int swapchainIndex;
//TODO:ovrTextureSwapChain* colorTexture;
GLuint* depthBuffers;
GLuint* framebuffers;
} framebuffer_t;
XrSwapchain Handle;
uint32_t Width;
uint32_t Height;
} ovrSwapChain;
typedef struct {
int Width;
int Height;
int Multisamples;
uint32_t TextureSwapChainLength;
uint32_t TextureSwapChainIndex;
ovrSwapChain ColorSwapChain;
XrSwapchainImageOpenGLESKHR* ColorSwapChainImage;
GLuint* DepthBuffers;
GLuint* FrameBuffers;
} ovrFramebuffer;
typedef struct {
ovrFramebuffer FrameBuffer[XR_EYES_COUNT];
} ovrRenderer;
typedef struct {
XrMatrix4x4f ViewMatrix[XR_EYES_COUNT];
XrMatrix4x4f ProjectionMatrix[XR_EYES_COUNT];
} ovrSceneMatrices;
typedef struct ovrMatrix4f_ {
float M[4][4];
} ovrMatrix4f;
typedef struct {
uint64_t frameIndex;
ovrJava java;
double predictedDisplayTime;
//TODO:ovrTracking2 tracking;
framebuffer_t framebuffers[2];
ovrRenderer renderer;
XrInstance instance;
XrSession session;
XrSystemId systemId;
XrSpace stageSpace;
GLboolean sessionActive;
} engine_t;
typedef enum {

View file

@ -84,9 +84,8 @@ int main(int argc, char* argv[]) {
Com_Init(args);
NET_Init( );
VR_InitRenderer(engine);
VR_EnterVR(engine, java);
VR_InitRenderer(engine);
bool hasFocus = true;
bool paused = false;