ppsspp/Common/VR/VRFramebuffer.cpp

354 lines
12 KiB
C++
Raw Normal View History

2022-07-07 19:30:06 +02:00
#include "VRFramebuffer.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <pthread.h>
#include <sys/prctl.h>
#include <assert.h>
2022-07-08 14:44:20 +02:00
#include <GLES3/gl3.h>
#include <GLES3/gl3ext.h>
2022-07-07 19:30:06 +02:00
double FromXrTime(const XrTime time) {
return (time * 1e-9);
}
2022-08-14 11:37:22 +02:00
typedef void(GL_APIENTRY* PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)(
GLenum target,
GLenum attachment,
GLuint texture,
GLint level,
GLint baseViewIndex,
GLsizei numViews);
2022-07-07 19:30:06 +02:00
/*
================================================================================
ovrFramebuffer
================================================================================
*/
2022-08-14 11:37:22 +02:00
2022-07-07 19:30:06 +02:00
void ovrFramebuffer_Clear(ovrFramebuffer* frameBuffer) {
2022-07-24 14:25:04 +02:00
frameBuffer->Width = 0;
frameBuffer->Height = 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;
2022-07-07 19:30:06 +02:00
}
bool ovrFramebuffer_Create(
2022-07-24 14:25:04 +02:00
XrSession session,
ovrFramebuffer* frameBuffer,
const int width,
const int height) {
frameBuffer->Width = width;
frameBuffer->Height = height;
2022-08-14 11:37:22 +02:00
PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC glFramebufferTextureMultiviewOVR =
(PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)eglGetProcAddress(
"glFramebufferTextureMultiviewOVR");
2022-07-24 14:25:04 +02:00
XrSwapchainCreateInfo swapChainCreateInfo;
memset(&swapChainCreateInfo, 0, sizeof(swapChainCreateInfo));
swapChainCreateInfo.type = XR_TYPE_SWAPCHAIN_CREATE_INFO;
swapChainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT;
swapChainCreateInfo.format = GL_RGBA8;
swapChainCreateInfo.sampleCount = 1;
swapChainCreateInfo.width = width;
swapChainCreateInfo.height = height;
swapChainCreateInfo.faceCount = 1;
2022-08-14 11:37:22 +02:00
swapChainCreateInfo.arraySize = 2;
2022-07-24 14:25:04 +02:00
swapChainCreateInfo.mipCount = 1;
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;
2022-08-14 11:37:22 +02:00
GLenum textureTarget = GL_TEXTURE_2D_ARRAY;
GL(glBindTexture(textureTarget, colorTexture));
GL(glTexParameteri(textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
GL(glTexParameteri(textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
GL(glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
GL(glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
GL(glBindTexture(textureTarget, 0));
2022-07-24 14:25:04 +02:00
// Create depth buffer.
2022-08-14 11:37:22 +02:00
GL(glGenTextures(1, &frameBuffer->DepthBuffers[i]));
GL(glBindTexture(textureTarget, frameBuffer->DepthBuffers[i]));
GL(glTexStorage3D(textureTarget, 1, GL_DEPTH_COMPONENT24, width, height, 2));
GL(glBindTexture(textureTarget, 0));
2022-07-24 14:25:04 +02:00
// Create the frame buffer.
GL(glGenFramebuffers(1, &frameBuffer->FrameBuffers[i]));
GL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer->FrameBuffers[i]));
2022-08-14 11:37:22 +02:00
GL(glFramebufferTextureMultiviewOVR(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, frameBuffer->DepthBuffers[i], 0, 0, 2));
GL(glFramebufferTextureMultiviewOVR(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colorTexture, 0, 0, 2));
2022-07-24 14:25:04 +02:00
GL(GLenum renderFramebufferStatus = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER));
GL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0));
if (renderFramebufferStatus != GL_FRAMEBUFFER_COMPLETE) {
2022-08-14 11:37:22 +02:00
ALOGE("Incomplete frame buffer object: %d", renderFramebufferStatus);
2022-07-24 14:25:04 +02:00
return false;
}
}
return true;
2022-07-07 19:30:06 +02:00
}
void ovrFramebuffer_Destroy(ovrFramebuffer* frameBuffer) {
2022-07-24 14:25:04 +02:00
GL(glDeleteFramebuffers(frameBuffer->TextureSwapChainLength, frameBuffer->FrameBuffers));
GL(glDeleteRenderbuffers(frameBuffer->TextureSwapChainLength, frameBuffer->DepthBuffers));
OXR(xrDestroySwapchain(frameBuffer->ColorSwapChain.Handle));
free(frameBuffer->ColorSwapChainImage);
2022-07-07 19:30:06 +02:00
2022-07-24 14:25:04 +02:00
free(frameBuffer->DepthBuffers);
free(frameBuffer->FrameBuffers);
2022-07-07 19:30:06 +02:00
2022-07-24 14:25:04 +02:00
ovrFramebuffer_Clear(frameBuffer);
2022-07-07 19:30:06 +02:00
}
void ovrFramebuffer_SetCurrent(ovrFramebuffer* frameBuffer) {
2022-07-24 14:25:04 +02:00
GL(glBindFramebuffer(
GL_DRAW_FRAMEBUFFER, frameBuffer->FrameBuffers[frameBuffer->TextureSwapChainIndex]));
2022-07-07 19:30:06 +02:00
}
void ovrFramebuffer_SetNone() {
2022-07-24 14:25:04 +02:00
GL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0));
2022-07-07 19:30:06 +02:00
}
void ovrFramebuffer_Resolve(ovrFramebuffer* frameBuffer) {
2022-07-24 14:25:04 +02:00
// 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);
2022-07-07 19:30:06 +02:00
}
void ovrFramebuffer_Acquire(ovrFramebuffer* frameBuffer) {
2022-07-24 14:25:04 +02:00
// 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 = 1000; /* timeout in nanoseconds */
XrResult res = xrWaitSwapchainImage(frameBuffer->ColorSwapChain.Handle, &waitInfo);
int i = 0;
while (res != XR_SUCCESS) {
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));
}
2022-07-07 19:30:06 +02:00
}
void ovrFramebuffer_Release(ovrFramebuffer* frameBuffer) {
2022-07-24 14:25:04 +02:00
XrSwapchainImageReleaseInfo releaseInfo = {XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO, NULL};
OXR(xrReleaseSwapchainImage(frameBuffer->ColorSwapChain.Handle, &releaseInfo));
2022-07-07 19:30:06 +02:00
}
/*
================================================================================
ovrRenderer
================================================================================
*/
void ovrRenderer_Clear(ovrRenderer* renderer) {
2022-08-14 11:37:22 +02:00
ovrFramebuffer_Clear(&renderer->FrameBuffer);
2022-07-07 19:30:06 +02:00
}
void ovrRenderer_Create(
2022-07-24 14:25:04 +02:00
XrSession session,
ovrRenderer* renderer,
int suggestedEyeTextureWidth,
int suggestedEyeTextureHeight) {
// Create the frame buffers.
2022-08-14 11:37:22 +02:00
ovrFramebuffer_Create(
session,
&renderer->FrameBuffer,
suggestedEyeTextureWidth,
suggestedEyeTextureHeight);
2022-07-07 19:30:06 +02:00
}
void ovrRenderer_Destroy(ovrRenderer* renderer) {
2022-08-14 11:37:22 +02:00
ovrFramebuffer_Destroy(&renderer->FrameBuffer);
2022-07-07 19:30:06 +02:00
}
/*
================================================================================
ovrApp
================================================================================
*/
void ovrApp_Clear(ovrApp* app) {
2022-07-24 14:25:04 +02:00
app->Focused = false;
app->Instance = XR_NULL_HANDLE;
app->Session = XR_NULL_HANDLE;
memset(&app->ViewportConfig, 0, sizeof(XrViewConfigurationProperties));
memset(&app->ViewConfigurationView, 0, ovrMaxNumEyes * sizeof(XrViewConfigurationView));
app->SystemId = XR_NULL_SYSTEM_ID;
app->HeadSpace = XR_NULL_HANDLE;
app->StageSpace = XR_NULL_HANDLE;
app->FakeStageSpace = XR_NULL_HANDLE;
app->CurrentSpace = XR_NULL_HANDLE;
app->SessionActive = false;
app->SwapInterval = 1;
memset(app->Layers, 0, sizeof(ovrCompositorLayer_Union) * ovrMaxLayerCount);
app->LayerCount = 0;
app->MainThreadTid = 0;
app->RenderThreadTid = 0;
ovrRenderer_Clear(&app->Renderer);
2022-07-07 19:30:06 +02:00
}
void ovrApp_Destroy(ovrApp* app) {
2022-07-24 14:25:04 +02:00
ovrApp_Clear(app);
2022-07-07 19:30:06 +02:00
}
void ovrApp_HandleSessionStateChanges(ovrApp* app, XrSessionState state) {
2022-07-24 14:25:04 +02:00
if (state == XR_SESSION_STATE_READY) {
assert(app->SessionActive == false);
2022-07-07 19:30:06 +02:00
2022-07-24 14:25:04 +02:00
XrSessionBeginInfo sessionBeginInfo;
memset(&sessionBeginInfo, 0, sizeof(sessionBeginInfo));
sessionBeginInfo.type = XR_TYPE_SESSION_BEGIN_INFO;
sessionBeginInfo.next = NULL;
sessionBeginInfo.primaryViewConfigurationType = app->ViewportConfig.viewConfigurationType;
2022-07-07 19:30:06 +02:00
2022-07-24 14:25:04 +02:00
XrResult result;
OXR(result = xrBeginSession(app->Session, &sessionBeginInfo));
2022-07-07 19:30:06 +02:00
2022-07-24 14:25:04 +02:00
app->SessionActive = (result == XR_SUCCESS);
} else if (state == XR_SESSION_STATE_STOPPING) {
assert(app->SessionActive);
2022-07-07 19:30:06 +02:00
2022-07-24 14:25:04 +02:00
OXR(xrEndSession(app->Session));
app->SessionActive = false;
}
2022-07-07 19:30:06 +02:00
}
2022-07-08 14:44:20 +02:00
int ovrApp_HandleXrEvents(ovrApp* app) {
2022-07-24 14:25:04 +02:00
XrEventDataBuffer eventDataBuffer = {};
int recenter = 0;
// Poll for events
for (;;) {
XrEventDataBaseHeader* baseEventHeader = (XrEventDataBaseHeader*)(&eventDataBuffer);
baseEventHeader->type = XR_TYPE_EVENT_DATA_BUFFER;
baseEventHeader->next = NULL;
XrResult r;
OXR(r = xrPollEvent(app->Instance, &eventDataBuffer));
if (r != XR_SUCCESS) {
break;
}
switch (baseEventHeader->type) {
case XR_TYPE_EVENT_DATA_EVENTS_LOST:
ALOGV("xrPollEvent: received XR_TYPE_EVENT_DATA_EVENTS_LOST event");
break;
case XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING: {
const XrEventDataInstanceLossPending* instance_loss_pending_event =
(XrEventDataInstanceLossPending*)(baseEventHeader);
ALOGV(
"xrPollEvent: received XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING event: time %f",
FromXrTime(instance_loss_pending_event->lossTime));
} break;
case XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED:
ALOGV("xrPollEvent: received XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED event");
break;
case XR_TYPE_EVENT_DATA_PERF_SETTINGS_EXT: {
const XrEventDataPerfSettingsEXT* perf_settings_event =
(XrEventDataPerfSettingsEXT*)(baseEventHeader);
ALOGV(
"xrPollEvent: received XR_TYPE_EVENT_DATA_PERF_SETTINGS_EXT event: type %d subdomain %d : level %d -> level %d",
perf_settings_event->type,
perf_settings_event->subDomain,
perf_settings_event->fromLevel,
perf_settings_event->toLevel);
} break;
case XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING: {
XrEventDataReferenceSpaceChangePending* ref_space_change_event =
(XrEventDataReferenceSpaceChangePending*)(baseEventHeader);
ALOGV(
"xrPollEvent: received XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING event: changed space: %d for session %p at time %f",
ref_space_change_event->referenceSpaceType,
(void*)ref_space_change_event->session,
FromXrTime(ref_space_change_event->changeTime));
recenter = 1;
} break;
case XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED: {
const XrEventDataSessionStateChanged* session_state_changed_event =
(XrEventDataSessionStateChanged*)(baseEventHeader);
ALOGV(
"xrPollEvent: received XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED: %d for session %p at time %f",
session_state_changed_event->state,
(void*)session_state_changed_event->session,
FromXrTime(session_state_changed_event->time));
switch (session_state_changed_event->state) {
case XR_SESSION_STATE_FOCUSED:
app->Focused = true;
break;
case XR_SESSION_STATE_VISIBLE:
app->Focused = false;
break;
case XR_SESSION_STATE_READY:
case XR_SESSION_STATE_STOPPING:
ovrApp_HandleSessionStateChanges(app, session_state_changed_event->state);
break;
default:
break;
}
} break;
default:
ALOGV("xrPollEvent: Unknown event");
break;
}
}
return recenter;
2022-07-07 19:30:06 +02:00
}