diff --git a/Common/GPU/OpenGL/GLRenderManager.cpp b/Common/GPU/OpenGL/GLRenderManager.cpp index b9173c2beb..6aebd20a70 100644 --- a/Common/GPU/OpenGL/GLRenderManager.cpp +++ b/Common/GPU/OpenGL/GLRenderManager.cpp @@ -5,6 +5,8 @@ #include "Common/Thread/ThreadUtil.h" #include "Common/VR/PPSSPPVR.h" +#include "Core/Config.h" + #include "Common/Log.h" #include "Common/MemoryUtil.h" #include "Common/Math/math_util.h" @@ -233,15 +235,7 @@ bool GLRenderManager::ThreadFrame() { INFO_LOG(G3D, "Running first frame (%d)", threadFrame_); firstFrame = false; } - - if (IsVRBuild()) { - if (PreVRRender()) { - Run(threadFrame_); - PostVRRender(); - } - } else { - Run(threadFrame_); - } + Run(threadFrame_); VLOG("PULL: Finished frame %d", threadFrame_); } while (!nextFrame); @@ -564,8 +558,7 @@ void GLRenderManager::EndSubmitFrame(int frame) { } // Render thread -void GLRenderManager::Run(int frame) { - BeginSubmitFrame(frame); +void GLRenderManager::Render(int frame) { FrameData &frameData = frameData_[frame]; @@ -584,6 +577,7 @@ void GLRenderManager::Run(int frame) { } queueRunner_.RunSteps(stepsOnThread, skipGLCalls_); + stepsOnThread.clear(); if (!skipGLCalls_) { @@ -591,8 +585,30 @@ void GLRenderManager::Run(int frame) { iter->MapDevice(bufferStrategy_); } } +} - switch (frameData.type) { +// Render thread +void GLRenderManager::Run(int frame) { + BeginSubmitFrame(frame); + + if (IsVRBuild()) { + if (PreVRRender()) { + int passes = 1; + if (!IsMultiviewSupported() && g_Config.bEnableStereo) { + passes = 2; + } + for (int i = 0; i < passes; i++) { + PreVRFrameRender(i); + Render(frame); + PostVRFrameRender(); + } + PostVRRender(); + } + } else { + Render(frame); + } + + switch (frameData_[frame].type) { case GLRRunType::END: EndSubmitFrame(frame); break; diff --git a/Common/GPU/OpenGL/GLRenderManager.h b/Common/GPU/OpenGL/GLRenderManager.h index 5423262c98..5f4b8216f8 100644 --- a/Common/GPU/OpenGL/GLRenderManager.h +++ b/Common/GPU/OpenGL/GLRenderManager.h @@ -377,6 +377,7 @@ public: void BeginFrame(); // Can run on a different thread! void Finish(); + void Render(int frame); void Run(int frame); // Zaps queued up commands. Use if you know there's a risk you've queued up stuff that has already been deleted. Can happen during in-game shutdown. diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index e66e87d991..2d3562468c 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -225,7 +225,7 @@ bool PreVRRender() { VR_SetConfig(VR_CONFIG_VIEWPORT_VALID, true); } - if (VR_BeginFrame(VR_GetEngine())) { + if (VR_InitFrame(VR_GetEngine())) { // Decide if the scene is 3D or not if (g_Config.bEnableVR && !VR_GetConfig(VR_CONFIG_FORCE_2D) && (VR_GetConfig(VR_CONFIG_3D_GEOMETRY_COUNT) > 15)) { @@ -245,9 +245,21 @@ bool PreVRRender() { } void PostVRRender() { + VR_FinishFrame(VR_GetEngine()); +} + +void PreVRFrameRender(int fboIndex) { + VR_BeginFrame(VR_GetEngine(), fboIndex); +} + +void PostVRFrameRender() { VR_EndFrame(VR_GetEngine()); } +int GetVRFBOIndex() { + return VR_GetConfig(VR_CONFIG_CURRENT_FBO); +} + bool IsMultiviewSupported() { return false; } diff --git a/Common/VR/PPSSPPVR.h b/Common/VR/PPSSPPVR.h index 76dafc6d07..b41b69f1be 100644 --- a/Common/VR/PPSSPPVR.h +++ b/Common/VR/PPSSPPVR.h @@ -17,6 +17,9 @@ void UpdateVRScreenKey(const KeyInput &key); void BindVRFramebuffer(); bool PreVRRender(); void PostVRRender(); +void PreVRFrameRender(int fboIndex); +void PostVRFrameRender(); +int GetVRFBOIndex(); bool IsMultiviewSupported(); bool IsFlatVRScene(); bool Is2DVRObject(float* projMatrix, bool ortho); @@ -37,6 +40,9 @@ inline void UpdateVRScreenKey(const KeyInput &key) {} inline void BindVRFramebuffer() {} inline bool PreVRRender() { return false; } inline void PostVRRender() {} +inline void PreVRFrameRender(int fboIndex) {} +inline void PostVRFrameRender() {} +inline int GetVRFBOIndex() { return 0; } inline bool IsMultiviewSupported() { return false; } inline bool IsFlatVRScene() { return true; } inline bool Is2DVRObject(float* projMatrix, bool ortho) { return false; } diff --git a/Common/VR/VRBase.h b/Common/VR/VRBase.h index 2d0be5d8d2..fffd234868 100644 --- a/Common/VR/VRBase.h +++ b/Common/VR/VRBase.h @@ -92,7 +92,6 @@ typedef struct { typedef struct { int Width; int Height; - bool Multiview; uint32_t TextureSwapChainLength; uint32_t TextureSwapChainIndex; ovrSwapChain ColorSwapChain; @@ -104,7 +103,8 @@ typedef struct { } ovrFramebuffer; typedef struct { - ovrFramebuffer FrameBuffer; + bool Multiview; + ovrFramebuffer FrameBuffer[ovrMaxNumEyes]; } ovrRenderer; typedef struct { diff --git a/Common/VR/VRFramebuffer.cpp b/Common/VR/VRFramebuffer.cpp index 0f13150b3e..b01775c588 100644 --- a/Common/VR/VRFramebuffer.cpp +++ b/Common/VR/VRFramebuffer.cpp @@ -47,12 +47,10 @@ bool ovrFramebuffer_Create(XrSession session, ovrFramebuffer* frameBuffer, int w frameBuffer->Width = width; frameBuffer->Height = height; - frameBuffer->Multiview = multiview; if (strstr((const char*)glGetString(GL_EXTENSIONS), "GL_OVR_multiview2") == nullptr) { ALOGE("OpenGL implementation does not support GL_OVR_multiview2 extension.\n"); - exit(EXIT_FAILURE); } typedef void (*PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVR)(GLenum, GLenum, GLuint, GLint, GLint, GLsizei); @@ -60,7 +58,6 @@ bool ovrFramebuffer_Create(XrSession session, ovrFramebuffer* frameBuffer, int w if (!glFramebufferTextureMultiviewOVR) { ALOGE("Can not get proc address for glFramebufferTextureMultiviewOVR.\n"); - exit(EXIT_FAILURE); } XrSwapchainCreateInfo swapChainCreateInfo; @@ -200,15 +197,24 @@ ovrRenderer */ void ovrRenderer_Clear(ovrRenderer* renderer) { - ovrFramebuffer_Clear(&renderer->FrameBuffer); + for (int i = 0; i < ovrMaxNumEyes; i++) { + ovrFramebuffer_Clear(&renderer->FrameBuffer[i]); + } } void ovrRenderer_Create(XrSession session, ovrRenderer* renderer, int width, int height, bool multiview) { - ovrFramebuffer_Create(session, &renderer->FrameBuffer, width, height, multiview); + renderer->Multiview = multiview; + int instances = renderer->Multiview ? 1 : ovrMaxNumEyes; + for (int i = 0; i < instances; i++) { + ovrFramebuffer_Create(session, &renderer->FrameBuffer[i], width, height, multiview); + } } void ovrRenderer_Destroy(ovrRenderer* renderer) { - ovrFramebuffer_Destroy(&renderer->FrameBuffer); + int instances = renderer->Multiview ? 1 : ovrMaxNumEyes; + for (int i = 0; i < instances; i++) { + ovrFramebuffer_Destroy(&renderer->FrameBuffer[i]); + } } /* diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp index f4c4d7f805..bc066035d2 100644 --- a/Common/VR/VRRenderer.cpp +++ b/Common/VR/VRRenderer.cpp @@ -235,7 +235,7 @@ void VR_ClearFrameBuffer( int width, int height) { glDisable( GL_SCISSOR_TEST ); } -bool VR_BeginFrame( engine_t* engine ) { +bool VR_InitFrame( engine_t* engine ) { GLboolean stageBoundsDirty = GL_TRUE; if (ovrApp_HandleXrEvents(&engine->appState)) { VR_Recenter(engine); @@ -304,16 +304,21 @@ bool VR_BeginFrame( engine_t* engine ) { engine->appState.LayerCount = 0; memset(engine->appState.Layers, 0, sizeof(ovrCompositorLayer_Union) * ovrMaxLayerCount); - - ovrFramebuffer* frameBuffer = &engine->appState.Renderer.FrameBuffer; - ovrFramebuffer_Acquire(frameBuffer); - ovrFramebuffer_SetCurrent(frameBuffer); - VR_ClearFrameBuffer(frameBuffer->ColorSwapChain.Width, frameBuffer->ColorSwapChain.Height); return true; } +void VR_BeginFrame( engine_t* engine, int fboIndex ) { + vrConfig[VR_CONFIG_CURRENT_FBO] = fboIndex; + ovrFramebuffer* frameBuffer = &engine->appState.Renderer.FrameBuffer[fboIndex]; + ovrFramebuffer_Acquire(frameBuffer); + ovrFramebuffer_SetCurrent(frameBuffer); + VR_ClearFrameBuffer(frameBuffer->ColorSwapChain.Width, frameBuffer->ColorSwapChain.Height); +} + void VR_EndFrame( engine_t* engine ) { + int fboIndex = vrConfig[VR_CONFIG_CURRENT_FBO]; + // Clear the alpha channel, other way OpenXR would not transfer the framebuffer fully VR_BindFramebuffer(engine); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); @@ -322,9 +327,8 @@ void VR_EndFrame( engine_t* engine ) { glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); // Show mouse cursor - int vrMode = vrConfig[VR_CONFIG_MODE]; int size = vrConfig[VR_CONFIG_MOUSE_SIZE]; - if ((vrMode == VR_MODE_FLAT_SCREEN) && (size > 0)) { + if ((vrConfig[VR_CONFIG_MODE] == VR_MODE_FLAT_SCREEN) && (size > 0)) { glEnable(GL_SCISSOR_TEST); glScissor(vrConfig[VR_CONFIG_MOUSE_X], vrConfig[VR_CONFIG_MOUSE_Y], size, size); glViewport(vrConfig[VR_CONFIG_MOUSE_X], vrConfig[VR_CONFIG_MOUSE_Y], size, size); @@ -333,21 +337,27 @@ void VR_EndFrame( engine_t* engine ) { glDisable(GL_SCISSOR_TEST); } - ovrFramebuffer* frameBuffer = &engine->appState.Renderer.FrameBuffer; + ovrFramebuffer* frameBuffer = &engine->appState.Renderer.FrameBuffer[fboIndex]; //ovrFramebuffer_Resolve(frameBuffer); ovrFramebuffer_Release(frameBuffer); ovrFramebuffer_SetNone(); +} +void VR_FinishFrame( engine_t* engine ) { + + int vrMode = vrConfig[VR_CONFIG_MODE]; XrCompositionLayerProjectionView projection_layer_elements[2] = {}; if ((vrMode == VR_MODE_MONO_6DOF) || (vrMode == VR_MODE_STEREO_6DOF)) { vrConfig[VR_CONFIG_MENU_YAW] = (int)hmdorientation.y; for (int eye = 0; eye < ovrMaxNumEyes; eye++) { - int imageLayer = eye; + int imageLayer = engine->appState.Renderer.Multiview ? eye : 0; + ovrFramebuffer* frameBuffer = &engine->appState.Renderer.FrameBuffer[0]; XrFovf fov = projections[eye].fov; if (vrMode == VR_MODE_MONO_6DOF) { fov = projections[0].fov; - imageLayer = 0; + } else if (!engine->appState.Renderer.Multiview) { + frameBuffer = &engine->appState.Renderer.FrameBuffer[eye]; } memset(&projection_layer_elements[eye], 0, sizeof(XrCompositionLayerProjectionView)); @@ -376,15 +386,15 @@ void VR_EndFrame( engine_t* engine ) { } else if (vrMode == VR_MODE_FLAT_SCREEN) { // Build the cylinder layer - int width = engine->appState.Renderer.FrameBuffer.ColorSwapChain.Width; - int height = engine->appState.Renderer.FrameBuffer.ColorSwapChain.Height; + int width = engine->appState.Renderer.FrameBuffer[0].ColorSwapChain.Width; + int height = engine->appState.Renderer.FrameBuffer[0].ColorSwapChain.Height; XrCompositionLayerCylinderKHR cylinder_layer = {}; cylinder_layer.type = XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR; cylinder_layer.layerFlags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT; cylinder_layer.space = engine->appState.CurrentSpace; cylinder_layer.eyeVisibility = XR_EYE_VISIBILITY_BOTH; memset(&cylinder_layer.subImage, 0, sizeof(XrSwapchainSubImage)); - cylinder_layer.subImage.swapchain = engine->appState.Renderer.FrameBuffer.ColorSwapChain.Handle; + cylinder_layer.subImage.swapchain = engine->appState.Renderer.FrameBuffer[0].ColorSwapChain.Handle; cylinder_layer.subImage.imageRect.offset.x = 0; cylinder_layer.subImage.imageRect.offset.y = 0; cylinder_layer.subImage.imageRect.extent.width = width; @@ -425,8 +435,12 @@ void VR_EndFrame( engine_t* engine ) { endFrameInfo.layers = layers; OXR(xrEndFrame(engine->appState.Session, &endFrameInfo)); - frameBuffer->TextureSwapChainIndex++; - frameBuffer->TextureSwapChainIndex %= frameBuffer->TextureSwapChainLength; + 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 ) { @@ -439,7 +453,8 @@ void VR_SetConfig( VRConfig config, int value) { void VR_BindFramebuffer(engine_t *engine) { if (!initialized) return; - ovrFramebuffer* frameBuffer = &engine->appState.Renderer.FrameBuffer; + int fboIndex = vrConfig[VR_CONFIG_CURRENT_FBO]; + ovrFramebuffer* frameBuffer = &engine->appState.Renderer.FrameBuffer[fboIndex]; unsigned int swapchainIndex = frameBuffer->TextureSwapChainIndex; unsigned int glFramebuffer = frameBuffer->FrameBuffers[swapchainIndex]; GL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, glFramebuffer)); diff --git a/Common/VR/VRRenderer.h b/Common/VR/VRRenderer.h index 82173a060b..abec8dfbaf 100644 --- a/Common/VR/VRRenderer.h +++ b/Common/VR/VRRenderer.h @@ -18,6 +18,8 @@ enum VRConfig { VR_CONFIG_MOUSE_SIZE, VR_CONFIG_MOUSE_X, VR_CONFIG_MOUSE_Y, //viewport setup VR_CONFIG_VIEWPORT_WIDTH, VR_CONFIG_VIEWPORT_HEIGHT, VR_CONFIG_VIEWPORT_VALID, + //render status + VR_CONFIG_CURRENT_FBO, //end VR_CONFIG_MAX @@ -41,8 +43,10 @@ void VR_GetResolution( engine_t* engine, int *pWidth, int *pHeight ); void VR_InitRenderer( engine_t* engine, bool multiview ); void VR_DestroyRenderer( engine_t* engine ); -bool VR_BeginFrame( engine_t* engine ); +bool VR_InitFrame( engine_t* engine ); +void VR_BeginFrame( engine_t* engine, int fboIndex ); void VR_EndFrame( engine_t* engine ); +void VR_FinishFrame( engine_t* engine ); int VR_GetConfig( VRConfig config ); void VR_SetConfig( VRConfig config, int value); diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index bb3ba416c4..29a6d391b5 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -410,7 +410,7 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu if (IsMultiviewSupported()) { render_->SetUniformM4x4Stereo("u_proj", &u_proj, leftEyeMatrix.m, rightEyeMatrix.m); } else { - render_->SetUniformM4x4(&u_proj, leftEyeMatrix.m); + render_->SetUniformM4x4(&u_proj, GetVRFBOIndex() == 0 ? leftEyeMatrix.m : rightEyeMatrix.m); } } else { Matrix4x4 flippedMatrix; @@ -537,7 +537,7 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu if (IsMultiviewSupported()) { render_->SetUniformM4x4Stereo("u_view", &u_view, leftEyeView, rightEyeView); } else { - render_->SetUniformM4x4(&u_view, leftEyeView); + render_->SetUniformM4x4(&u_view, GetVRFBOIndex() == 0 ? leftEyeView : rightEyeView); } } else { SetMatrix4x3(render_, &u_view, gstate.viewMatrix); diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 896a74dea5..e6303f2f10 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1120,10 +1120,8 @@ void GameSettingsScreen::CreateViews() { vrSettings->Add(new CheckBox(&g_Config.bEnableVR, vr->T("Enable virtual reality"))); CheckBox *vr6DoF = vrSettings->Add(new CheckBox(&g_Config.bEnable6DoF, vr->T("Enable 6 degrees of freedom movement"))); vr6DoF->SetEnabledPtr(&g_Config.bEnableVR); - if (IsMultiviewSupported()) { - CheckBox *vrStereo = vrSettings->Add(new CheckBox(&g_Config.bEnableStereo, vr->T("Enable stereoscopic vision"))); - vrStereo->SetEnabledPtr(&g_Config.bEnableVR); - } + CheckBox *vrStereo = vrSettings->Add(new CheckBox(&g_Config.bEnableStereo, vr->T("Enable stereoscopic vision"))); + vrStereo->SetEnabledPtr(&g_Config.bEnableVR); PopupSliderChoice *vrFieldOfView = vrSettings->Add(new PopupSliderChoice(&g_Config.iFieldOfViewPercentage, 100, 150, vr->T("Field of view scale", "Headset's field of view scale"), 10, screenManager(), vr->T("% of native FoV"))); vrFieldOfView->SetEnabledPtr(&g_Config.bEnableVR); vrSettings->Add(new PopupSliderChoice(&g_Config.iCanvasDistance, 1, 10, vr->T("Distance to 2D menus and scenes", "Distance to 2D menus and scenes"), 1, screenManager(), ""));