diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj
index aa0f9bb1e7..e5e6a5530a 100644
--- a/Common/Common.vcxproj
+++ b/Common/Common.vcxproj
@@ -557,6 +557,13 @@
+
+
+
+
+
+
+
@@ -989,6 +996,76 @@
+
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+
diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters
index 0cb9e79423..e04ecff0c8 100644
--- a/Common/Common.vcxproj.filters
+++ b/Common/Common.vcxproj.filters
@@ -425,6 +425,27 @@
Math
+
+ VR
+
+
+ VR
+
+
+ VR
+
+
+ VR
+
+
+ VR
+
+
+ VR
+
+
+ VR
+
@@ -803,6 +824,27 @@
Math
+
+ VR
+
+
+ VR
+
+
+ VR
+
+
+ VR
+
+
+ VR
+
+
+ VR
+
+
+ VR
+
@@ -907,6 +949,9 @@
{7b17065c-729c-47c3-a02d-66dc383529dd}
+
+ {9d1c29fd-8ac7-4475-8ea6-c8c759b695fe}
+
diff --git a/Common/GPU/OpenGL/GLQueueRunner.cpp b/Common/GPU/OpenGL/GLQueueRunner.cpp
index 47874252e3..84f1b1a375 100644
--- a/Common/GPU/OpenGL/GLQueueRunner.cpp
+++ b/Common/GPU/OpenGL/GLQueueRunner.cpp
@@ -648,7 +648,7 @@ retry_depth:
currentReadHandle_ = fbo->handle;
}
-void GLQueueRunner::RunSteps(const std::vector &steps, bool skipGLCalls, bool keepSteps) {
+void GLQueueRunner::RunSteps(const std::vector &steps, bool skipGLCalls, bool keepSteps, bool useVR) {
if (skipGLCalls) {
if (keepSteps) {
return;
diff --git a/Common/GPU/OpenGL/GLQueueRunner.h b/Common/GPU/OpenGL/GLQueueRunner.h
index 1e009787ae..e9ad214eb4 100644
--- a/Common/GPU/OpenGL/GLQueueRunner.h
+++ b/Common/GPU/OpenGL/GLQueueRunner.h
@@ -363,7 +363,7 @@ public:
void RunInitSteps(const std::vector &steps, bool skipGLCalls);
- void RunSteps(const std::vector &steps, bool skipGLCalls, bool keepSteps = false);
+ void RunSteps(const std::vector &steps, bool skipGLCalls, bool keepSteps, bool useVR);
void LogSteps(const std::vector &steps);
void CreateDeviceObjects();
diff --git a/Common/GPU/OpenGL/GLRenderManager.cpp b/Common/GPU/OpenGL/GLRenderManager.cpp
index bca19e274f..c3d14bb4a7 100644
--- a/Common/GPU/OpenGL/GLRenderManager.cpp
+++ b/Common/GPU/OpenGL/GLRenderManager.cpp
@@ -581,11 +581,11 @@ void GLRenderManager::Run(int frame) {
int passes = GetVRPassesCount();
for (int i = 0; i < passes; i++) {
PreVRFrameRender(i);
- queueRunner_.RunSteps(stepsOnThread, skipGLCalls_, i < passes - 1);
+ queueRunner_.RunSteps(stepsOnThread, skipGLCalls_, i < passes - 1, true);
PostVRFrameRender();
}
} else {
- queueRunner_.RunSteps(stepsOnThread, skipGLCalls_);
+ queueRunner_.RunSteps(stepsOnThread, skipGLCalls_, false, false);
}
stepsOnThread.clear();
diff --git a/Common/GPU/Vulkan/VulkanLoader.cpp b/Common/GPU/Vulkan/VulkanLoader.cpp
index b0c2ab370b..52ece65731 100644
--- a/Common/GPU/Vulkan/VulkanLoader.cpp
+++ b/Common/GPU/Vulkan/VulkanLoader.cpp
@@ -308,8 +308,7 @@ void VulkanSetAvailable(bool available) {
}
bool VulkanMayBeAvailable() {
-
- //unsupported in VR at the moment
+ // Unsupported in VR at the moment
if (IsVRBuild()) {
return false;
}
diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp
index e430374079..b771342e49 100644
--- a/GPU/Common/PresentationCommon.cpp
+++ b/GPU/Common/PresentationCommon.cpp
@@ -74,19 +74,21 @@ void CenterDisplayOutputRect(FRect *rc, float origW, float origH, const FRect &f
bool rotated = rotation == ROTATION_LOCKED_VERTICAL || rotation == ROTATION_LOCKED_VERTICAL180;
+ SmallDisplayZoom zoomType = (SmallDisplayZoom)g_Config.iSmallDisplayZoomType;
+
if (IsVRBuild()) {
if (IsFlatVRScene()) {
- g_Config.iSmallDisplayZoomType = (int)SmallDisplayZoom::AUTO;
+ zoomType = SmallDisplayZoom::AUTO;
} else {
- g_Config.iSmallDisplayZoomType = (int)SmallDisplayZoom::STRETCH;
+ zoomType = SmallDisplayZoom::STRETCH;
}
}
- if (g_Config.iSmallDisplayZoomType == (int)SmallDisplayZoom::STRETCH) {
+ if (zoomType == SmallDisplayZoom::STRETCH) {
outW = frame.w;
outH = frame.h;
} else {
- if (g_Config.iSmallDisplayZoomType == (int)SmallDisplayZoom::MANUAL) {
+ if (zoomType == SmallDisplayZoom::MANUAL) {
float offsetX = (g_Config.fSmallDisplayOffsetX - 0.5f) * 2.0f * frame.w + frame.x;
float offsetY = (g_Config.fSmallDisplayOffsetY - 0.5f) * 2.0f * frame.h + frame.y;
// Have to invert Y for GL
@@ -109,7 +111,7 @@ void CenterDisplayOutputRect(FRect *rc, float origW, float origH, const FRect &f
rc->h = floorf(smallDisplayW);
return;
}
- } else if (g_Config.iSmallDisplayZoomType == (int)SmallDisplayZoom::AUTO) {
+ } else if (zoomType == SmallDisplayZoom::AUTO) {
// Stretch to 1080 for 272*4. But don't distort if not widescreen (i.e. ultrawide of halfwide.)
float pixelCrop = frame.h / 270.0f;
float resCommonWidescreen = pixelCrop - floor(pixelCrop);
@@ -130,13 +132,13 @@ void CenterDisplayOutputRect(FRect *rc, float origW, float origH, const FRect &f
outW = frame.w;
outH = frame.w / origRatio;
// Stretch a little bit
- if (!rotated && g_Config.iSmallDisplayZoomType == (int)SmallDisplayZoom::PARTIAL_STRETCH)
+ if (!rotated && zoomType == SmallDisplayZoom::PARTIAL_STRETCH)
outH = (frame.h + outH) / 2.0f; // (408 + 720) / 2 = 564
} else {
// Image is taller than frame. Center horizontally.
outW = frame.h * origRatio;
outH = frame.h;
- if (rotated && g_Config.iSmallDisplayZoomType == (int)SmallDisplayZoom::PARTIAL_STRETCH)
+ if (rotated && zoomType == SmallDisplayZoom::PARTIAL_STRETCH)
outW = (frame.h + outH) / 2.0f; // (408 + 720) / 2 = 564
}
}
diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp
index 45433a72d7..64258d1103 100644
--- a/GPU/Common/VertexShaderGenerator.cpp
+++ b/GPU/Common/VertexShaderGenerator.cpp
@@ -23,7 +23,6 @@
#include "Common/GPU/OpenGL/GLFeatures.h"
#include "Common/GPU/ShaderWriter.h"
#include "Common/GPU/thin3d.h"
-#include "Common/VR/PPSSPPVR.h"
#include "Core/Config.h"
#include "GPU/ge_constants.h"
#include "GPU/GPUState.h"
@@ -149,10 +148,11 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
if (gl_extensions.ARB_cull_distance && id.Bit(VS_BIT_VERTEX_RANGE_CULLING)) {
gl_exts.push_back("#extension GL_ARB_cull_distance : enable");
}
+ if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY) && gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) {
+ gl_exts.push_back("#extension GL_OVR_multiview2 : enable\nlayout(num_views=2) in;");
+ }
}
- if (IsVRBuild() && IsMultiviewSupported()) {
- gl_exts.push_back("#extension GL_OVR_multiview2 : enable\nlayout(num_views=2) in;");
- }
+
ShaderWriter p(buffer, compat, ShaderStage::Vertex, gl_exts.data(), gl_exts.size());
bool isModeThrough = id.Bit(VS_BIT_IS_THROUGH);
@@ -480,8 +480,8 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
WRITE(p, "uniform mat4 u_proj_through;\n");
*uniformMask |= DIRTY_PROJTHROUGHMATRIX;
} else if (useHWTransform) {
- if (IsVRBuild()) {
- if (IsMultiviewSupported()) {
+ if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) {
+ if (gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) {
WRITE(p, "layout(shared) uniform ProjectionMatrix { uniform mat4 u_proj_lens[2]; };\n");
} else {
WRITE(p, "uniform mat4 u_proj_lens;\n");
@@ -495,7 +495,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
// When transforming by hardware, we need a great deal more uniforms...
// TODO: Use 4x3 matrices where possible. Though probably doesn't matter much.
WRITE(p, "uniform mat4 u_world;\n");
- if (IsVRBuild() && IsMultiviewSupported()) {
+ if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY) && gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) {
WRITE(p, "layout(shared) uniform ViewMatrices { uniform mat4 u_view[2]; };\n");
} else {
WRITE(p, "uniform mat4 u_view;\n");
@@ -560,7 +560,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
WRITE(p, "uniform lowp float u_rotation;\n");
}
- if (IsVRBuild()) {
+ if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) {
WRITE(p, "uniform lowp float u_scaleX;\n");
WRITE(p, "uniform lowp float u_scaleY;\n");
}
@@ -920,7 +920,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
}
std::string matrixPostfix;
- if (IsVRBuild() && IsMultiviewSupported()) {
+ if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY) && gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) {
matrixPostfix = "[gl_ViewID_OVR]";
}
@@ -928,14 +928,14 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
// Final view and projection transforms.
if (gstate_c.Use(GPU_ROUND_DEPTH_TO_16BIT)) {
- if (IsVRBuild()) {
+ if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) {
WRITE(p, " vec4 outPos = depthRoundZVP(mul(u_proj_lens%s, viewPos));\n", matrixPostfix.c_str());
WRITE(p, " vec4 orgPos = depthRoundZVP(mul(u_proj, viewPos));\n");
} else {
WRITE(p, " vec4 outPos = depthRoundZVP(mul(u_proj, viewPos));\n");
}
} else {
- if (IsVRBuild()) {
+ if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) {
WRITE(p, " vec4 outPos = mul(u_proj_lens%s, viewPos);\n", matrixPostfix.c_str());
WRITE(p, " vec4 orgPos = mul(u_proj, viewPos);\n");
} else {
@@ -1284,7 +1284,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
WRITE(p, " }\n");
}
- if (vertexRangeCulling && !IsVRBuild()) {
+ if (vertexRangeCulling && !gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) {
WRITE(p, " vec3 projPos = outPos.xyz / outPos.w;\n");
WRITE(p, " float projZ = (projPos.z - u_depthRange.z) * u_depthRange.w;\n");
@@ -1325,7 +1325,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
// We've named the output gl_Position in HLSL as well.
WRITE(p, " %sgl_Position = outPos;\n", compat.vsOutPrefix);
- if (IsVRBuild()) {
+ if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) {
// Z correction for the depth buffer
if (useHWTransform) {
WRITE(p, " %sgl_Position.z = orgPos.z / abs(orgPos.w) * abs(outPos.w);\n", compat.vsOutPrefix);
diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp
index c2740460db..b6b2b6a661 100644
--- a/GPU/GLES/GPU_GLES.cpp
+++ b/GPU/GLES/GPU_GLES.cpp
@@ -22,6 +22,7 @@
#include "Common/Serialize/Serializer.h"
#include "Common/File/FileUtil.h"
#include "Common/GraphicsContext.h"
+#include "Common/VR/PPSSPPVR.h"
#include "Core/Config.h"
#include "Core/Debugger/Breakpoints.h"
@@ -209,6 +210,13 @@ u32 GPU_GLES::CheckGPUFeatures() const {
features |= GPU_USE_FRAGMENT_TEST_CACHE;
}
+ if (IsVRBuild()) {
+ features |= GPU_USE_VIRTUAL_REALITY;
+ }
+ if (IsMultiviewSupported()) {
+ features |= GPU_USE_SINGLE_PASS_STEREO;
+ }
+
return features;
}
diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp
index 055d626b28..db721ab475 100644
--- a/GPU/GLES/ShaderManagerGLES.cpp
+++ b/GPU/GLES/ShaderManagerGLES.cpp
@@ -130,10 +130,9 @@ LinkedShader::LinkedShader(GLRenderManager *render, VShaderID VSID, Shader *vs,
queries.push_back({ &u_cullRangeMax, "u_cullRangeMax" });
queries.push_back({ &u_rotation, "u_rotation" });
- if (IsVRBuild()) {
- queries.push_back({ &u_scaleX, "u_scaleX" });
- queries.push_back({ &u_scaleY, "u_scaleY" });
- }
+ // These two are only used for VR, but let's always query them for simplicity.
+ queries.push_back({ &u_scaleX, "u_scaleX" });
+ queries.push_back({ &u_scaleY, "u_scaleY" });
#ifdef USE_BONE_ARRAY
queries.push_back({ &u_bone, "u_bone" });
@@ -378,7 +377,7 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu
}
bool is2D, flatScreen;
- if (IsVRBuild()) {
+ if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) {
// Analyze scene
is2D = Is2DVRObject(gstate.projMatrix, gstate.isModeThrough());
flatScreen = IsFlatVRScene();
@@ -402,7 +401,7 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu
// Update any dirty uniforms before we draw
if (dirty & DIRTY_PROJMATRIX) {
- if (IsVRBuild()) {
+ if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) {
Matrix4x4 leftEyeMatrix, rightEyeMatrix;
if (flatScreen || is2D) {
memcpy(&leftEyeMatrix, gstate.projMatrix, 16 * sizeof(float));
@@ -536,7 +535,7 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu
SetMatrix4x3(render_, &u_world, gstate.worldMatrix);
}
if (dirty & DIRTY_VIEWMATRIX) {
- if (IsVRBuild()) {
+ if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) {
float leftEyeView[16];
float rightEyeView[16];
ConvertMatrix4x3To4x4Transposed(leftEyeView, gstate.viewMatrix);
diff --git a/GPU/GPUState.h b/GPU/GPUState.h
index 272b39d70e..e7a15e9536 100644
--- a/GPU/GPUState.h
+++ b/GPU/GPUState.h
@@ -497,6 +497,11 @@ enum {
GPU_ROUND_DEPTH_TO_16BIT = FLAG_BIT(23), // Can be disabled either per game or if we use a real 16-bit depth buffer
GPU_USE_CLIP_DISTANCE = FLAG_BIT(24),
GPU_USE_CULL_DISTANCE = FLAG_BIT(25),
+
+ // VR flags (reserved or in-use)
+ GPU_USE_VIRTUAL_REALITY = FLAG_BIT(29),
+ GPU_USE_SINGLE_PASS_STEREO = FLAG_BIT(30),
+ GPU_USE_SIMPLE_STEREO_PERSPECTIVE = FLAG_BIT(31),
};
struct KnownVertexBounds {
diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp
index 93b11fd53e..36ce962ea4 100644
--- a/UI/NativeApp.cpp
+++ b/UI/NativeApp.cpp
@@ -1296,7 +1296,6 @@ bool NativeTouch(const TouchInput &touch) {
}
bool NativeKey(const KeyInput &key) {
-
// Hack to quickly enable 2D mode in VR game mode.
if (IsVRBuild()) {
UpdateVRScreenKey(key);