mirror of
https://github.com/DrBeef/ioq3quest.git
synced 2025-04-06 00:20:56 +00:00
OpenXR renderer in progress
This commit is contained in:
parent
e7a2229edc
commit
7b9d51ec30
7 changed files with 762 additions and 70 deletions
|
@ -28,6 +28,7 @@ add_dependencies(main copy_libs)
|
||||||
|
|
||||||
target_include_directories(main PRIVATE
|
target_include_directories(main PRIVATE
|
||||||
${CMAKE_SOURCE_DIR}/code/OpenXR-SDK/include
|
${CMAKE_SOURCE_DIR}/code/OpenXR-SDK/include
|
||||||
|
${CMAKE_SOURCE_DIR}/code/OpenXR/Include
|
||||||
${CMAKE_SOURCE_DIR}/code/SDL2/include
|
${CMAKE_SOURCE_DIR}/code/SDL2/include
|
||||||
${CMAKE_SOURCE_DIR}/code)
|
${CMAKE_SOURCE_DIR}/code)
|
||||||
|
|
||||||
|
|
|
@ -298,8 +298,6 @@ static void InitOpenGL( void )
|
||||||
|
|
||||||
// set default state
|
// set default state
|
||||||
GL_SetDefaultState();
|
GL_SetDefaultState();
|
||||||
|
|
||||||
VR_ReInitRenderer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
555
android/app/src/main/cpp/code/vr/ovr_renderer.inl
Normal file
555
android/app/src/main/cpp/code/vr/ovr_renderer.inl
Normal 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);
|
||||||
|
}
|
|
@ -259,7 +259,6 @@ void VR_EnterVR( engine_t* engine, ovrJava java ) {
|
||||||
sessionCreateInfo.next = &graphicsBindingAndroidGLES;
|
sessionCreateInfo.next = &graphicsBindingAndroidGLES;
|
||||||
sessionCreateInfo.createFlags = 0;
|
sessionCreateInfo.createFlags = 0;
|
||||||
sessionCreateInfo.systemId = engine->systemId;
|
sessionCreateInfo.systemId = engine->systemId;
|
||||||
|
|
||||||
if (xrCreateSession(engine->instance, &sessionCreateInfo, &engine->session) != XR_SUCCESS) {
|
if (xrCreateSession(engine->instance, &sessionCreateInfo, &engine->session) != XR_SUCCESS) {
|
||||||
Com_Printf("xrCreateSession failed");
|
Com_Printf("xrCreateSession failed");
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "../qcommon/q_shared.h"
|
#include "../qcommon/q_shared.h"
|
||||||
#include "../qcommon/qcommon.h"
|
#include "../qcommon/qcommon.h"
|
||||||
#include "../client/client.h"
|
#include "../client/client.h"
|
||||||
|
#include "ovr_renderer.inl"
|
||||||
|
|
||||||
#include "vr_clientinfo.h"
|
#include "vr_clientinfo.h"
|
||||||
#include "vr_types.h"
|
#include "vr_types.h"
|
||||||
|
@ -23,6 +24,7 @@
|
||||||
|
|
||||||
extern vr_clientinfo_t vr;
|
extern vr_clientinfo_t vr;
|
||||||
|
|
||||||
|
|
||||||
void APIENTRY VR_GLDebugLog(GLenum source, GLenum type, GLuint id,
|
void APIENTRY VR_GLDebugLog(GLenum source, GLenum type, GLuint id,
|
||||||
GLenum severity, GLsizei length, const GLchar* message, const void* userParam)
|
GLenum severity, GLsizei length, const GLchar* message, const void* userParam)
|
||||||
{
|
{
|
||||||
|
@ -87,64 +89,21 @@ void VR_InitRenderer( engine_t* engine ) {
|
||||||
glDebugMessageCallback(VR_GLDebugLog, 0);
|
glDebugMessageCallback(VR_GLDebugLog, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//TODO:
|
|
||||||
/*
|
|
||||||
int eyeW, eyeH;
|
int eyeW, eyeH;
|
||||||
VR_GetResolution(engine, &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) {
|
XrReferenceSpaceCreateInfo spaceCreateInfo = {};
|
||||||
GLuint colorTexture;
|
spaceCreateInfo.type = XR_TYPE_REFERENCE_SPACE_CREATE_INFO;
|
||||||
GLenum framebufferStatus;
|
spaceCreateInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_STAGE;
|
||||||
|
spaceCreateInfo.poseInReferenceSpace.orientation.w = 1.0f;
|
||||||
colorTexture = vrapi_GetTextureSwapChainHandle(framebuffer->colorTexture, index);
|
spaceCreateInfo.poseInReferenceSpace.position.y = 0.0f;
|
||||||
glBindTexture(GL_TEXTURE_2D, colorTexture);
|
xrCreateReferenceSpace(engine->session, &spaceCreateInfo, &engine->stageSpace);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VR_DestroyRenderer( engine_t* engine ) {
|
void VR_DestroyRenderer( engine_t* engine ) {
|
||||||
//TODO:
|
xrDestroySpace(engine->stageSpace);
|
||||||
/*
|
ovrRenderer_Destroy(&engine->renderer);
|
||||||
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]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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 );
|
glEnable( GL_SCISSOR_TEST );
|
||||||
glViewport( 0, 0, width, height );
|
glViewport( 0, 0, width, height );
|
||||||
|
@ -261,11 +219,165 @@ void VR_ClearFrameBuffer( GLuint frameBuffer, int width, int height)
|
||||||
|
|
||||||
glScissor( 0, 0, 0, 0 );
|
glScissor( 0, 0, 0, 0 );
|
||||||
glDisable( GL_SCISSOR_TEST );
|
glDisable( GL_SCISSOR_TEST );
|
||||||
|
|
||||||
glBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VR_DrawFrame( engine_t* engine ) {
|
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
|
//TODO
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -10,13 +10,18 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//OpenXR
|
//OpenXR
|
||||||
|
#define XR_EYES_COUNT 2
|
||||||
#define XR_USE_GRAPHICS_API_OPENGL_ES 1
|
#define XR_USE_GRAPHICS_API_OPENGL_ES 1
|
||||||
#define XR_USE_PLATFORM_ANDROID 1
|
#define XR_USE_PLATFORM_ANDROID 1
|
||||||
#include <EGL/egl.h>
|
#include <EGL/egl.h>
|
||||||
#include <EGL/eglext.h>
|
#include <EGL/eglext.h>
|
||||||
|
#include <GLES3/gl3.h>
|
||||||
|
#include <GLES3/gl3ext.h>
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
#include <openxr/openxr.h>
|
#include <openxr/openxr.h>
|
||||||
#include <openxr/openxr_platform.h>
|
#include <openxr/openxr_platform.h>
|
||||||
|
#include <openxr/openxr_oculus.h>
|
||||||
|
#include <openxr/openxr_oculus_helpers.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
JavaVM* Vm;
|
JavaVM* Vm;
|
||||||
|
@ -25,22 +30,45 @@ typedef struct {
|
||||||
} ovrJava;
|
} ovrJava;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int swapchainLength;
|
XrSwapchain Handle;
|
||||||
int swapchainIndex;
|
uint32_t Width;
|
||||||
//TODO:ovrTextureSwapChain* colorTexture;
|
uint32_t Height;
|
||||||
GLuint* depthBuffers;
|
} ovrSwapChain;
|
||||||
GLuint* framebuffers;
|
|
||||||
} framebuffer_t;
|
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 {
|
typedef struct {
|
||||||
uint64_t frameIndex;
|
uint64_t frameIndex;
|
||||||
ovrJava java;
|
ovrJava java;
|
||||||
double predictedDisplayTime;
|
ovrRenderer renderer;
|
||||||
//TODO:ovrTracking2 tracking;
|
|
||||||
framebuffer_t framebuffers[2];
|
|
||||||
XrInstance instance;
|
XrInstance instance;
|
||||||
XrSession session;
|
XrSession session;
|
||||||
XrSystemId systemId;
|
XrSystemId systemId;
|
||||||
|
XrSpace stageSpace;
|
||||||
|
GLboolean sessionActive;
|
||||||
} engine_t;
|
} engine_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|
|
@ -84,9 +84,8 @@ int main(int argc, char* argv[]) {
|
||||||
Com_Init(args);
|
Com_Init(args);
|
||||||
NET_Init( );
|
NET_Init( );
|
||||||
|
|
||||||
VR_InitRenderer(engine);
|
|
||||||
|
|
||||||
VR_EnterVR(engine, java);
|
VR_EnterVR(engine, java);
|
||||||
|
VR_InitRenderer(engine);
|
||||||
|
|
||||||
bool hasFocus = true;
|
bool hasFocus = true;
|
||||||
bool paused = false;
|
bool paused = false;
|
||||||
|
|
Loading…
Reference in a new issue