summaryrefslogtreecommitdiff
path: root/Source/Core/VideoCommon
diff options
context:
space:
mode:
authorRyan Houdek <Sonicadvance1@gmail.com>2014-11-28 11:45:38 -0600
committerRyan Houdek <Sonicadvance1@gmail.com>2014-11-28 11:45:38 -0600
commitce059769f6bf13118366f77fea926727efcf4510 (patch)
tree8ea7f2014f086f1df0f661697863c5b72d633a5b /Source/Core/VideoCommon
parent0e3d20c349ead263a630463beeb4335aaf512e42 (diff)
parent6d51455195e95a1bb97eb263fcd3423c757f59e7 (diff)
Merge pull request #1439 from Armada651/ogl-stereo-3d
OGL: Stereoscopic 3D Support
Diffstat (limited to 'Source/Core/VideoCommon')
-rw-r--r--Source/Core/VideoCommon/CMakeLists.txt1
-rw-r--r--Source/Core/VideoCommon/ConstantManager.h1
-rw-r--r--Source/Core/VideoCommon/FramebufferManagerBase.cpp2
-rw-r--r--Source/Core/VideoCommon/FramebufferManagerBase.h4
-rw-r--r--Source/Core/VideoCommon/GeometryShaderGen.cpp134
-rw-r--r--Source/Core/VideoCommon/GeometryShaderGen.h26
-rw-r--r--Source/Core/VideoCommon/PixelShaderGen.cpp78
-rw-r--r--Source/Core/VideoCommon/PixelShaderGen.h2
-rw-r--r--Source/Core/VideoCommon/PostProcessing.h2
-rw-r--r--Source/Core/VideoCommon/RenderBase.cpp36
-rw-r--r--Source/Core/VideoCommon/RenderBase.h2
-rw-r--r--Source/Core/VideoCommon/ShaderGenCommon.h13
-rw-r--r--Source/Core/VideoCommon/TextureCacheBase.cpp23
-rw-r--r--Source/Core/VideoCommon/TextureCacheBase.h9
-rw-r--r--Source/Core/VideoCommon/TextureConversionShader.cpp4
-rw-r--r--Source/Core/VideoCommon/VertexShaderGen.cpp85
-rw-r--r--Source/Core/VideoCommon/VertexShaderGen.h5
-rw-r--r--Source/Core/VideoCommon/VertexShaderManager.cpp15
-rw-r--r--Source/Core/VideoCommon/VideoCommon.vcxproj2
-rw-r--r--Source/Core/VideoCommon/VideoCommon.vcxproj.filters6
-rw-r--r--Source/Core/VideoCommon/VideoConfig.cpp31
-rw-r--r--Source/Core/VideoCommon/VideoConfig.h22
22 files changed, 410 insertions, 93 deletions
diff --git a/Source/Core/VideoCommon/CMakeLists.txt b/Source/Core/VideoCommon/CMakeLists.txt
index 87b23a25ff..0dfd12b732 100644
--- a/Source/Core/VideoCommon/CMakeLists.txt
+++ b/Source/Core/VideoCommon/CMakeLists.txt
@@ -9,6 +9,7 @@ set(SRCS BoundingBox.cpp
Fifo.cpp
FPSCounter.cpp
FramebufferManagerBase.cpp
+ GeometryShaderGen.cpp
HiresTextures.cpp
ImageWrite.cpp
IndexGenerator.cpp
diff --git a/Source/Core/VideoCommon/ConstantManager.h b/Source/Core/VideoCommon/ConstantManager.h
index 3e52640ca9..116088d76e 100644
--- a/Source/Core/VideoCommon/ConstantManager.h
+++ b/Source/Core/VideoCommon/ConstantManager.h
@@ -43,5 +43,6 @@ struct VertexShaderConstants
float4 normalmatrices[32];
float4 posttransformmatrices[64];
float4 depthparams;
+ float4 stereoparams;
};
diff --git a/Source/Core/VideoCommon/FramebufferManagerBase.cpp b/Source/Core/VideoCommon/FramebufferManagerBase.cpp
index ea865cd275..e2a09c6527 100644
--- a/Source/Core/VideoCommon/FramebufferManagerBase.cpp
+++ b/Source/Core/VideoCommon/FramebufferManagerBase.cpp
@@ -12,6 +12,8 @@ const XFBSourceBase* FramebufferManagerBase::m_overlappingXFBArray[MAX_VIRTUAL_X
unsigned int FramebufferManagerBase::s_last_xfb_width = 1;
unsigned int FramebufferManagerBase::s_last_xfb_height = 1;
+unsigned int FramebufferManagerBase::m_EFBLayers = 1;
+
FramebufferManagerBase::FramebufferManagerBase()
{
m_realXFBSource = nullptr;
diff --git a/Source/Core/VideoCommon/FramebufferManagerBase.h b/Source/Core/VideoCommon/FramebufferManagerBase.h
index 50813539ab..b01e820243 100644
--- a/Source/Core/VideoCommon/FramebufferManagerBase.h
+++ b/Source/Core/VideoCommon/FramebufferManagerBase.h
@@ -55,6 +55,8 @@ public:
static int ScaleToVirtualXfbWidth(int x, unsigned int backbuffer_width);
static int ScaleToVirtualXfbHeight(int y, unsigned int backbuffer_height);
+ static int GetEFBLayers() { return m_EFBLayers; }
+
protected:
struct VirtualXFB
{
@@ -70,6 +72,8 @@ protected:
typedef std::list<VirtualXFB> VirtualXFBListType;
+ static unsigned int m_EFBLayers;
+
private:
virtual XFBSourceBase* CreateXFBSource(unsigned int target_width, unsigned int target_height) = 0;
// TODO: figure out why OGL is different for this guy
diff --git a/Source/Core/VideoCommon/GeometryShaderGen.cpp b/Source/Core/VideoCommon/GeometryShaderGen.cpp
new file mode 100644
index 0000000000..83a590a7ed
--- /dev/null
+++ b/Source/Core/VideoCommon/GeometryShaderGen.cpp
@@ -0,0 +1,134 @@
+// Copyright 2013 Dolphin Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include <cmath>
+#include <locale.h>
+#ifdef __APPLE__
+ #include <xlocale.h>
+#endif
+
+#include "VideoCommon/GeometryShaderGen.h"
+#include "VideoCommon/LightingShaderGen.h"
+#include "VideoCommon/VertexShaderGen.h"
+#include "VideoCommon/VideoConfig.h"
+
+static char text[16384];
+
+template<class T>
+static inline void GenerateGeometryShader(T& out, u32 components, API_TYPE ApiType)
+{
+ // Non-uid template parameters will write to the dummy data (=> gets optimized out)
+ geometry_shader_uid_data dummy_data;
+ geometry_shader_uid_data* uid_data = out.template GetUidData<geometry_shader_uid_data>();
+ if (uid_data == nullptr)
+ uid_data = &dummy_data;
+
+ out.SetBuffer(text);
+ const bool is_writing_shadercode = (out.GetBuffer() != nullptr);
+#ifndef ANDROID
+ locale_t locale;
+ locale_t old_locale;
+ if (is_writing_shadercode)
+ {
+ locale = newlocale(LC_NUMERIC_MASK, "C", nullptr); // New locale for compilation
+ old_locale = uselocale(locale); // Apply the locale for this thread
+ }
+#endif
+
+ if (is_writing_shadercode)
+ text[sizeof(text) - 1] = 0x7C; // canary
+
+ out.Write("//Geometry Shader for 3D stereoscopy\n");
+
+ uid_data->stereo = g_ActiveConfig.iStereoMode > 0;
+ if (ApiType == API_OPENGL)
+ {
+ // Insert layout parameters
+ if (g_ActiveConfig.backend_info.bSupportsGSInstancing)
+ out.Write("layout(triangles, invocations = %d) in;\n", g_ActiveConfig.iStereoMode > 0 ? 2 : 1);
+ else
+ out.Write("layout(triangles) in;\n");
+ out.Write("layout(triangle_strip, max_vertices = %d) out;\n", g_ActiveConfig.backend_info.bSupportsGSInstancing ? 3 : 6);
+ }
+
+ out.Write("%s", s_lighting_struct);
+
+ // uniforms
+ if (ApiType == API_OPENGL)
+ out.Write("layout(std140%s) uniform VSBlock {\n", g_ActiveConfig.backend_info.bSupportsBindingLayout ? ", binding = 2" : "");
+ else
+ out.Write("cbuffer VSBlock {\n");
+ out.Write(s_shader_uniforms);
+ out.Write("};\n");
+
+ uid_data->numTexGens = xfmem.numTexGen.numTexGens;
+ uid_data->pixel_lighting = g_ActiveConfig.bEnablePixelLighting;
+
+ GenerateVSOutputStruct(out, ApiType);
+
+ out.Write("centroid in VS_OUTPUT o[3];\n");
+ out.Write("centroid out VS_OUTPUT f;\n");
+
+ out.Write("flat out int layer;\n");
+
+ out.Write("void main()\n{\n");
+
+ // If the GPU supports invocation we don't need a for loop and can simply use the
+ // invocation identifier to determine which layer we're rendering.
+ if (g_ActiveConfig.backend_info.bSupportsGSInstancing)
+ out.Write("\tint l = gl_InvocationID;\n");
+ else
+ out.Write("\tfor (int l = 0; l < %d; ++l) {\n", g_ActiveConfig.iStereoMode > 0 ? 2 : 1);
+
+ out.Write("\tfor (int i = 0; i < 3; ++i) {\n");
+ out.Write("\t\tlayer = l;\n");
+ out.Write("\t\tgl_Layer = l;\n");
+ out.Write("\t\tf = o[i];\n");
+ out.Write("\t\tfloat4 pos = o[i].pos;\n");
+
+ if (g_ActiveConfig.iStereoMode > 0)
+ {
+ // For stereoscopy add a small horizontal offset in Normalized Device Coordinates proportional
+ // to the depth of the vertex. We retrieve the depth value from the w-component of the projected
+ // vertex which contains the negated z-component of the original vertex.
+ // For negative parallax (out-of-screen effects) we subtract a convergence value from
+ // the depth value. This results in objects at a distance smaller than the convergence
+ // distance to seemingly appear in front of the screen.
+ // This formula is based on page 13 of the "Nvidia 3D Vision Automatic, Best Practices Guide"
+ out.Write("\t\tf.clipPos.x = o[i].clipPos.x + " I_STEREOPARAMS"[l] * (o[i].clipPos.w - " I_STEREOPARAMS"[2]);\n");
+ out.Write("\t\tpos.x = o[i].pos.x + " I_STEREOPARAMS"[l] * (o[i].pos.w - " I_STEREOPARAMS"[2]);\n");
+ }
+
+ out.Write("\t\tf.pos.x = pos.x;\n");
+ out.Write("\t\tgl_Position = pos;\n");
+ out.Write("\t\tEmitVertex();\n");
+ out.Write("\t}\n");
+ out.Write("\tEndPrimitive();\n");
+
+ if (!g_ActiveConfig.backend_info.bSupportsGSInstancing)
+ out.Write("\t}\n");
+
+ out.Write("}\n");
+
+ if (is_writing_shadercode)
+ {
+ if (text[sizeof(text) - 1] != 0x7C)
+ PanicAlert("GeometryShader generator - buffer too small, canary has been eaten!");
+
+#ifndef ANDROID
+ uselocale(old_locale); // restore locale
+ freelocale(locale);
+#endif
+ }
+}
+
+void GetGeometryShaderUid(GeometryShaderUid& object, u32 components, API_TYPE ApiType)
+{
+ GenerateGeometryShader<GeometryShaderUid>(object, components, ApiType);
+}
+
+void GenerateGeometryShaderCode(ShaderCode& object, u32 components, API_TYPE ApiType)
+{
+ GenerateGeometryShader<ShaderCode>(object, components, ApiType);
+}
diff --git a/Source/Core/VideoCommon/GeometryShaderGen.h b/Source/Core/VideoCommon/GeometryShaderGen.h
new file mode 100644
index 0000000000..3f7dc5198b
--- /dev/null
+++ b/Source/Core/VideoCommon/GeometryShaderGen.h
@@ -0,0 +1,26 @@
+// Copyright 2013 Dolphin Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "VideoCommon/ShaderGenCommon.h"
+#include "VideoCommon/VideoCommon.h"
+
+#pragma pack(1)
+
+struct geometry_shader_uid_data
+{
+ u32 NumValues() const { return sizeof(geometry_shader_uid_data); }
+
+ u32 stereo : 1;
+ u32 numTexGens : 4;
+ u32 pixel_lighting : 1;
+};
+
+#pragma pack()
+
+typedef ShaderUid<geometry_shader_uid_data> GeometryShaderUid;
+
+void GenerateGeometryShaderCode(ShaderCode& object, u32 components, API_TYPE ApiType);
+void GetGeometryShaderUid(GeometryShaderUid& object, u32 components, API_TYPE ApiType);
diff --git a/Source/Core/VideoCommon/PixelShaderGen.cpp b/Source/Core/VideoCommon/PixelShaderGen.cpp
index c0b45fdfda..71e534df0a 100644
--- a/Source/Core/VideoCommon/PixelShaderGen.cpp
+++ b/Source/Core/VideoCommon/PixelShaderGen.cpp
@@ -16,6 +16,7 @@
#include "VideoCommon/LightingShaderGen.h"
#include "VideoCommon/NativeVertexFormat.h"
#include "VideoCommon/PixelShaderGen.h"
+#include "VideoCommon/VertexShaderGen.h"
#include "VideoCommon/VideoConfig.h"
#include "VideoCommon/XFMemory.h" // for texture projection mode
@@ -206,7 +207,7 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T
{
// Declare samplers
for (int i = 0; i < 8; ++i)
- out.Write("SAMPLER_BINDING(%d) uniform sampler2D samp%d;\n", i, i);
+ out.Write("SAMPLER_BINDING(%d) uniform sampler2DArray samp%d;\n", i, i);
}
else // D3D
{
@@ -253,17 +254,8 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T
{
out.Write("cbuffer VSBlock : register(b1) {\n");
}
- out.Write(
- "\tfloat4 " I_POSNORMALMATRIX"[6];\n"
- "\tfloat4 " I_PROJECTION"[4];\n"
- "\tint4 " I_MATERIALS"[4];\n"
- "\tLight " I_LIGHTS"[8];\n"
- "\tfloat4 " I_TEXMATRICES"[24];\n"
- "\tfloat4 " I_TRANSFORMMATRICES"[64];\n"
- "\tfloat4 " I_NORMALMATRICES"[32];\n"
- "\tfloat4 " I_POSTTRANSFORMMATRICES"[64];\n"
- "\tfloat4 " I_DEPTHPARAMS";\n"
- "};\n");
+ out.Write(s_shader_uniforms);
+ out.Write("};\n");
}
if (g_ActiveConfig.backend_info.bSupportsBBox)
@@ -275,6 +267,8 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T
);
}
+ GenerateVSOutputStruct(out, ApiType);
+
const bool forced_early_z = g_ActiveConfig.backend_info.bSupportsEarlyZ && bpmem.UseEarlyDepthTest() && (g_ActiveConfig.bFastDepthCalc || bpmem.alpha_test.TestResult() == AlphaTest::UNDETERMINED);
const bool per_pixel_depth = (bpmem.ztex2.op != ZTEXTURE_DISABLE && bpmem.UseLateDepthTest()) || (!g_ActiveConfig.bFastDepthCalc && bpmem.zmode.testenable && !forced_early_z);
@@ -325,22 +319,52 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T
// As a workaround, we interpolate at the centroid of the coveraged pixel, which
// is always inside the primitive.
// Without MSAA, this flag is defined to have no effect.
- out.Write("centroid in float4 colors_02;\n");
- out.Write("centroid in float4 colors_12;\n");
-
- // compute window position if needed because binding semantic WPOS is not widely supported
- // Let's set up attributes
- for (unsigned int i = 0; i < numTexgen; ++i)
+ uid_data->stereo = g_ActiveConfig.iStereoMode > 0;
+ if (g_ActiveConfig.iStereoMode > 0)
{
- out.Write("centroid in float3 uv%d;\n", i);
+ out.Write("centroid in VS_OUTPUT f;\n");
+ out.Write("flat in int layer;\n");
}
- out.Write("centroid in float4 clipPos;\n");
- if (g_ActiveConfig.bEnablePixelLighting)
+ else
{
- out.Write("centroid in float4 Normal;\n");
+ out.Write("centroid in float4 colors_02;\n");
+ out.Write("centroid in float4 colors_12;\n");
+
+ // compute window position if needed because binding semantic WPOS is not widely supported
+ // Let's set up attributes
+ for (unsigned int i = 0; i < numTexgen; ++i)
+ {
+ out.Write("centroid in float3 uv%d;\n", i);
+ }
+ out.Write("centroid in float4 clipPos;\n");
+ if (g_ActiveConfig.bEnablePixelLighting)
+ {
+ out.Write("centroid in float4 Normal;\n");
+ }
}
out.Write("void main()\n{\n");
+
+ if (g_ActiveConfig.iStereoMode > 0)
+ {
+ // compute window position if needed because binding semantic WPOS is not widely supported
+ // Let's set up attributes
+ for (unsigned int i = 0; i < numTexgen; ++i)
+ {
+ out.Write("\tfloat3 uv%d = f.tex%d;\n", i, i);
+ }
+ out.Write("\tfloat4 clipPos = f.clipPos;\n");
+ if (g_ActiveConfig.bEnablePixelLighting)
+ {
+ out.Write("\tfloat4 Normal = f.Normal;\n");
+ }
+ }
+
+ // On Mali, global variables must be initialized as constants.
+ // This is why we initialize these variables locally instead.
+ out.Write("\tfloat4 colors_0 = %s;\n", (g_ActiveConfig.iStereoMode > 0) ? "f.colors_0" : "colors_02");
+ out.Write("\tfloat4 colors_1 = %s;\n", (g_ActiveConfig.iStereoMode > 0) ? "f.colors_1" : "colors_12");
+
out.Write("\tfloat4 rawpos = gl_FragCoord;\n");
}
else // D3D
@@ -370,14 +394,6 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T
"\tint2 wrappedcoord=int2(0,0), tempcoord=int2(0,0);\n"
"\tint4 tevin_a=int4(0,0,0,0),tevin_b=int4(0,0,0,0),tevin_c=int4(0,0,0,0),tevin_d=int4(0,0,0,0);\n\n"); // tev combiner inputs
- if (ApiType == API_OPENGL)
- {
- // On Mali, global variables must be initialized as constants.
- // This is why we initialize these variables locally instead.
- out.Write("\tfloat4 colors_0 = colors_02;\n");
- out.Write("\tfloat4 colors_1 = colors_12;\n");
- }
-
if (g_ActiveConfig.bEnablePixelLighting)
{
out.Write("\tfloat3 _norm0 = normalize(Normal.xyz);\n\n");
@@ -931,7 +947,7 @@ static inline void SampleTexture(T& out, const char *texcoords, const char *texs
if (ApiType == API_D3D)
out.Write("iround(255.0 * Tex%d.Sample(samp%d,%s.xy * " I_TEXDIMS"[%d].xy)).%s;\n", texmap,texmap, texcoords, texmap, texswap);
else
- out.Write("iround(255.0 * texture(samp%d,%s.xy * " I_TEXDIMS"[%d].xy)).%s;\n", texmap, texcoords, texmap, texswap);
+ out.Write("iround(255.0 * texture(samp%d, float3(%s.xy * " I_TEXDIMS"[%d].xy, %s))).%s;\n", texmap, texcoords, texmap, g_ActiveConfig.iStereoMode > 0 ? "layer" : "0.0", texswap);
}
static const char *tevAlphaFuncsTable[] =
diff --git a/Source/Core/VideoCommon/PixelShaderGen.h b/Source/Core/VideoCommon/PixelShaderGen.h
index 369f940619..784523087a 100644
--- a/Source/Core/VideoCommon/PixelShaderGen.h
+++ b/Source/Core/VideoCommon/PixelShaderGen.h
@@ -44,7 +44,7 @@ struct pixel_shader_uid_data
u32 dstAlphaMode : 2;
u32 Pretest : 2;
u32 nIndirectStagesUsed : 4;
- u32 pad0 : 1;
+ u32 stereo : 1;
u32 genMode_numtexgens : 4;
u32 genMode_numtevstages : 4;
diff --git a/Source/Core/VideoCommon/PostProcessing.h b/Source/Core/VideoCommon/PostProcessing.h
index 68ab47cff6..7c4f942214 100644
--- a/Source/Core/VideoCommon/PostProcessing.h
+++ b/Source/Core/VideoCommon/PostProcessing.h
@@ -91,7 +91,7 @@ public:
// Should be implemented by the backends for backend specific code
virtual void BlitFromTexture(TargetRectangle src, TargetRectangle dst,
- int src_texture, int src_width, int src_height) = 0;
+ int src_texture, int src_width, int src_height, int layer = 0) = 0;
virtual void ApplyShader() = 0;
protected:
diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp
index d93d43f490..84c037c753 100644
--- a/Source/Core/VideoCommon/RenderBase.cpp
+++ b/Source/Core/VideoCommon/RenderBase.cpp
@@ -240,6 +240,42 @@ bool Renderer::CalculateTargetSize(unsigned int framebuffer_width, unsigned int
return false;
}
+void Renderer::ConvertStereoRectangle(const TargetRectangle& rc, TargetRectangle& leftRc, TargetRectangle& rightRc)
+{
+ // Resize target to half its original size
+ TargetRectangle drawRc = rc;
+ if (g_ActiveConfig.iStereoMode == STEREO_TAB)
+ {
+ // The height may be negative due to flipped rectangles
+ int height = rc.bottom - rc.top;
+ drawRc.top += height / 4;
+ drawRc.bottom -= height / 4;
+ }
+ else
+ {
+ int width = rc.right - rc.left;
+ drawRc.left += width / 4;
+ drawRc.right -= width / 4;
+ }
+
+ // Create two target rectangle offset to the sides of the backbuffer
+ leftRc = drawRc, rightRc = drawRc;
+ if (g_ActiveConfig.iStereoMode == STEREO_TAB)
+ {
+ leftRc.top -= s_backbuffer_height / 4;
+ leftRc.bottom -= s_backbuffer_height / 4;
+ rightRc.top += s_backbuffer_height / 4;
+ rightRc.bottom += s_backbuffer_height / 4;
+ }
+ else
+ {
+ leftRc.left -= s_backbuffer_width / 4;
+ leftRc.right -= s_backbuffer_width / 4;
+ rightRc.left += s_backbuffer_width / 4;
+ rightRc.right += s_backbuffer_width / 4;
+ }
+}
+
void Renderer::SetScreenshot(const std::string& filename)
{
std::lock_guard<std::mutex> lk(s_criticalScreenshot);
diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h
index 746f75366c..f59458e523 100644
--- a/Source/Core/VideoCommon/RenderBase.h
+++ b/Source/Core/VideoCommon/RenderBase.h
@@ -83,6 +83,8 @@ public:
static const TargetRectangle& GetTargetRectangle() { return target_rc; }
static void UpdateDrawRectangle(int backbuffer_width, int backbuffer_height);
+ // Use this to convert a single target rectangle to two stereo rectangles
+ static void ConvertStereoRectangle(const TargetRectangle& rc, TargetRectangle& leftRc, TargetRectangle& rightRc);
// Use this to upscale native EFB coordinates to IDEAL internal resolution
static int EFBToScaledX(int x);
diff --git a/Source/Core/VideoCommon/ShaderGenCommon.h b/Source/Core/VideoCommon/ShaderGenCommon.h
index 54adb1ba17..330b9f8ced 100644
--- a/Source/Core/VideoCommon/ShaderGenCommon.h
+++ b/Source/Core/VideoCommon/ShaderGenCommon.h
@@ -239,3 +239,16 @@ private:
#define I_NORMALMATRICES "cnmtx"
#define I_POSTTRANSFORMMATRICES "cpostmtx"
#define I_DEPTHPARAMS "cDepth" // farZ, zRange
+#define I_STEREOPARAMS "cstereo"
+
+static const char s_shader_uniforms[] =
+ "\tfloat4 " I_POSNORMALMATRIX"[6];\n"
+ "\tfloat4 " I_PROJECTION"[4];\n"
+ "\tint4 " I_MATERIALS"[4];\n"
+ "\tLight " I_LIGHTS"[8];\n"
+ "\tfloat4 " I_TEXMATRICES"[24];\n"
+ "\tfloat4 " I_TRANSFORMMATRICES"[64];\n"
+ "\tfloat4 " I_NORMALMATRICES"[32];\n"
+ "\tfloat4 " I_POSTTRANSFORMMATRICES"[64];\n"
+ "\tfloat4 " I_DEPTHPARAMS";\n"
+ "\tfloat4 " I_STEREOPARAMS";\n";
diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp
index 0618b3f1b9..7fa540022d 100644
--- a/Source/Core/VideoCommon/TextureCacheBase.cpp
+++ b/Source/Core/VideoCommon/TextureCacheBase.cpp
@@ -115,6 +115,13 @@ void TextureCache::OnConfigChanged(VideoConfig& config)
{
g_texture_cache->ClearRenderTargets();
}
+
+ if ((config.iStereoMode > 0) != backup_config.s_stereo_3d ||
+ config.bStereoMonoEFBDepth != backup_config.s_mono_efb_depth)
+ {
+ g_texture_cache->DeleteShaders();
+ g_texture_cache->CompileShaders();
+ }
}
backup_config.s_colorsamples = config.iSafeTextureCache_ColorSamples;
@@ -126,6 +133,8 @@ void TextureCache::OnConfigChanged(VideoConfig& config)
backup_config.s_texfmt_overlay_center = config.bTexFmtOverlayCenter;
backup_config.s_hires_textures = config.bHiresTextures;
backup_config.s_copy_cache_enable = config.bEFBCopyCacheEnable;
+ backup_config.s_stereo_3d = config.iStereoMode > 0;
+ backup_config.s_mono_efb_depth = config.bStereoMonoEFBDepth;
}
void TextureCache::Cleanup()
@@ -444,14 +453,15 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int const stage,
//
// TODO: Don't we need to force texture decoding to RGBA8 for dynamic EFB copies?
// TODO: Actually, it should be enough if the internal texture format matches...
- if ((entry->type == TCET_NORMAL &&
+ if (((entry->type == TCET_NORMAL &&
width == entry->virtual_width &&
height == entry->virtual_height &&
full_format == entry->format &&
entry->num_mipmaps > maxlevel) ||
(entry->type == TCET_EC_DYNAMIC &&
entry->native_width == width &&
- entry->native_height == height))
+ entry->native_height == height)) &&
+ entry->num_layers == 1)
{
// reuse the texture
}
@@ -519,6 +529,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int const stage,
// But that will currently make the above "existing entry" tests fail as "texLevels" is not calculated until after.
// Currently, we might try to reuse a texture which appears to have more levels than actual, maybe..
entry->num_mipmaps = maxlevel + 1;
+ entry->num_layers = 1;
entry->type = TCET_NORMAL;
GFX_DEBUGGER_PAUSE_AT(NEXT_NEW_TEXTURE, true);
@@ -529,7 +540,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int const stage,
entry->Load(width, height, expandedWidth, 0);
}
- entry->SetGeneralParameters(address, texture_size, full_format, entry->num_mipmaps);
+ entry->SetGeneralParameters(address, texture_size, full_format, entry->num_mipmaps, entry->num_layers);
entry->SetDimensions(nativeW, nativeH, width, height);
entry->hash = tex_hash;
@@ -886,12 +897,12 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
TCacheEntryBase *entry = textures[dstAddr];
if (entry)
{
- if (entry->type == TCET_EC_DYNAMIC && entry->native_width == tex_w && entry->native_height == tex_h)
+ if (entry->type == TCET_EC_DYNAMIC && entry->native_width == tex_w && entry->native_height == tex_h && entry->num_layers == FramebufferManagerBase::GetEFBLayers())
{
scaled_tex_w = tex_w;
scaled_tex_h = tex_h;
}
- else if (!(entry->type == TCET_EC_VRAM && entry->virtual_width == scaled_tex_w && entry->virtual_height == scaled_tex_h))
+ else if (!(entry->type == TCET_EC_VRAM && entry->virtual_width == scaled_tex_w && entry->virtual_height == scaled_tex_h && entry->num_layers == FramebufferManagerBase::GetEFBLayers()))
{
if (entry->type == TCET_EC_VRAM)
{
@@ -914,7 +925,7 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
textures[dstAddr] = entry = AllocateRenderTarget(scaled_tex_w, scaled_tex_h);
// TODO: Using the wrong dstFormat, dumb...
- entry->SetGeneralParameters(dstAddr, 0, dstFormat, 1);
+ entry->SetGeneralParameters(dstAddr, 0, dstFormat, 1, FramebufferManagerBase::GetEFBLayers());
entry->SetDimensions(tex_w, tex_h, scaled_tex_w, scaled_tex_h);
entry->SetHashes(TEXHASH_INVALID);
entry->type = TCET_EC_VRAM;
diff --git a/Source/Core/VideoCommon/TextureCacheBase.h b/Source/Core/VideoCommon/TextureCacheBase.h
index fbe13915fa..d9cd2b8c16 100644
--- a/Source/Core/VideoCommon/TextureCacheBase.h
+++ b/Source/Core/VideoCommon/TextureCacheBase.h
@@ -39,6 +39,7 @@ public:
enum TexCacheEntryType type;
unsigned int num_mipmaps;
+ unsigned int num_layers;
unsigned int native_width, native_height; // Texture dimensions from the GameCube's point of view
unsigned int virtual_width, virtual_height; // Texture dimensions from OUR point of view - for hires textures or scaled EFB copies
@@ -46,12 +47,13 @@ public:
int frameCount;
- void SetGeneralParameters(u32 _addr, u32 _size, u32 _format, unsigned int _num_mipmaps)
+ void SetGeneralParameters(u32 _addr, u32 _size, u32 _format, unsigned int _num_mipmaps, unsigned int _num_layers)
{
addr = _addr;
size_in_bytes = _size;
format = _format;
num_mipmaps = _num_mipmaps;
+ num_layers = _num_layers;
}
void SetDimensions(unsigned int _native_width, unsigned int _native_height, unsigned int _virtual_width, unsigned int _virtual_height)
@@ -101,6 +103,9 @@ public:
unsigned int expanded_width, unsigned int tex_levels, PC_TexFormat pcfmt) = 0;
virtual TCacheEntryBase* CreateRenderTargetTexture(unsigned int scaled_tex_w, unsigned int scaled_tex_h) = 0;
+ virtual void CompileShaders() = 0; // currently only implemented by OGL
+ virtual void DeleteShaders() = 0; // currently only implemented by OGL
+
static TCacheEntryBase* Load(unsigned int stage, u32 address, unsigned int width, unsigned int height,
int format, unsigned int tlutaddr, int tlutfmt, bool use_mipmaps, unsigned int maxlevel, bool from_tmem);
static void CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat, PEControl::PixelFormat srcFormat,
@@ -140,6 +145,8 @@ private:
bool s_texfmt_overlay_center;
bool s_hires_textures;
bool s_copy_cache_enable;
+ bool s_stereo_3d;
+ bool s_mono_efb_depth;
} backup_config;
};
diff --git a/Source/Core/VideoCommon/TextureConversionShader.cpp b/Source/Core/VideoCommon/TextureConversionShader.cpp
index b0215e4c08..1ab973d11b 100644
--- a/Source/Core/VideoCommon/TextureConversionShader.cpp
+++ b/Source/Core/VideoCommon/TextureConversionShader.cpp
@@ -70,7 +70,7 @@ static void WriteSwizzler(char*& p, u32 format, API_TYPE ApiType)
if (ApiType == API_OPENGL)
{
WRITE(p, "#define samp0 samp9\n");
- WRITE(p, "SAMPLER_BINDING(9) uniform sampler2D samp0;\n");
+ WRITE(p, "SAMPLER_BINDING(9) uniform sampler2DArray samp0;\n");
WRITE(p, " out vec4 ocol0;\n");
WRITE(p, "void main()\n");
@@ -120,7 +120,7 @@ static void WriteSwizzler(char*& p, u32 format, API_TYPE ApiType)
static void WriteSampleColor(char*& p, const char* colorComp, const char* dest, int xoffset, API_TYPE ApiType)
{
- WRITE(p, " %s = texture(samp0, uv0 + float2(%d, 0) * sample_offset).%s;\n",
+ WRITE(p, " %s = texture(samp0, float3(uv0 + float2(%d, 0) * sample_offset, 0.0)).%s;\n",
dest, xoffset, colorComp
);
}
diff --git a/Source/Core/VideoCommon/VertexShaderGen.cpp b/Source/Core/VideoCommon/VertexShaderGen.cpp
index 894a18a0e2..24c6f39f46 100644
--- a/Source/Core/VideoCommon/VertexShaderGen.cpp
+++ b/Source/Core/VideoCommon/VertexShaderGen.cpp
@@ -89,17 +89,8 @@ static inline void GenerateVertexShader(T& out, u32 components, API_TYPE api_typ
out.Write("layout(std140%s) uniform VSBlock {\n", g_ActiveConfig.backend_info.bSupportsBindingLayout ? ", binding = 2" : "");
else
out.Write("cbuffer VSBlock {\n");
- out.Write(
- "\tfloat4 " I_POSNORMALMATRIX"[6];\n"
- "\tfloat4 " I_PROJECTION"[4];\n"
- "\tint4 " I_MATERIALS"[4];\n"
- "\tLight " I_LIGHTS"[8];\n"
- "\tfloat4 " I_TEXMATRICES"[24];\n"
- "\tfloat4 " I_TRANSFORMMATRICES"[64];\n"
- "\tfloat4 " I_NORMALMATRICES"[32];\n"
- "\tfloat4 " I_POSTTRANSFORMMATRICES"[64];\n"
- "\tfloat4 " I_DEPTHPARAMS";\n"
- "};\n");
+ out.Write(s_shader_uniforms);
+ out.Write("};\n");
GenerateVSOutputStruct(out, api_type);
@@ -131,22 +122,33 @@ static inline void GenerateVertexShader(T& out, u32 components, API_TYPE api_typ
out.Write("in float%d tex%d; // ATTR%d,\n", hastexmtx ? 3 : 2, i, SHADER_TEXTURE0_ATTRIB + i);
}
- // Let's set up attributes
- for (size_t i = 0; i < 8; ++i)
+ uid_data->stereo = g_ActiveConfig.iStereoMode > 0;
+ if (g_ActiveConfig.iStereoMode > 0)
{
- if (i < xfmem.numTexGen.numTexGens)
+ out.Write("centroid out VS_OUTPUT o;\n");
+ }
+ else
+ {
+ // Let's set up attributes
+ for (size_t i = 0; i < 8; ++i)
{
- out.Write("centroid out float3 uv%d;\n", i);
+ if (i < xfmem.numTexGen.numTexGens)
+ {
+ out.Write("centroid out float3 uv%d;\n", i);
+ }
}
- }
- out.Write("centroid out float4 clipPos;\n");
- if (g_ActiveConfig.bEnablePixelLighting)
- out.Write("centroid out float4 Normal;\n");
- out.Write("centroid out float4 colors_02;\n");
- out.Write("centroid out float4 colors_12;\n");
+ out.Write("centroid out float4 clipPos;\n");
+ if (g_ActiveConfig.bEnablePixelLighting)
+ out.Write("centroid out float4 Normal;\n");
+ out.Write("centroid out float4 colors_02;\n");
+ out.Write("centroid out float4 colors_12;\n");
+ }
out.Write("void main()\n{\n");
+
+ if (g_ActiveConfig.iStereoMode <= 0)
+ out.Write("VS_OUTPUT o;\n");
}
else // D3D
{
@@ -172,8 +174,9 @@ static inline void GenerateVertexShader(T& out, u32 components, API_TYPE api_typ
if (components & VB_HAS_POSMTXIDX)
out.Write(" int posmtx : BLENDINDICES,\n");
out.Write(" float4 rawpos : POSITION) {\n");
+
+ out.Write("VS_OUTPUT o;\n");
}
- out.Write("VS_OUTPUT o;\n");
// transforms
if (components & VB_HAS_POSMTXIDX)
@@ -431,27 +434,32 @@ static inline void GenerateVertexShader(T& out, u32 components, API_TYPE api_typ
if (api_type == API_OPENGL)
{
- // Bit ugly here
- // TODO: Make pretty
- // Will look better when we bind uniforms in GLSL 1.3
- // clipPos/w needs to be done in pixel shader, not here
+ if (g_ActiveConfig.iStereoMode <= 0)
+ {
+ // Bit ugly here
+ // TODO: Make pretty
+ // Will look better when we bind uniforms in GLSL 1.3
+ // clipPos/w needs to be done in pixel shader, not here
+
+ for (unsigned int i = 0; i < xfmem.numTexGen.numTexGens; ++i)
+ out.Write("uv%d.xyz = o.tex%d;\n", i, i);
- for (unsigned int i = 0; i < xfmem.numTexGen.numTexGens; ++i)
- out.Write(" uv%d.xyz = o.tex%d;\n", i, i);
- out.Write(" clipPos = o.clipPos;\n");
+ out.Write("clipPos = o.clipPos;\n");
- if (g_ActiveConfig.bEnablePixelLighting)
- out.Write(" Normal = o.Normal;\n");
+ if (g_ActiveConfig.bEnablePixelLighting)
+ out.Write("Normal = o.Normal;\n");
+
+ out.Write("colors_02 = o.colors_0;\n");
+ out.Write("colors_12 = o.colors_1;\n");
+ }
- out.Write("colors_02 = o.colors_0;\n");
- out.Write("colors_12 = o.colors_1;\n");
out.Write("gl_Position = o.pos;\n");
- out.Write("}\n");
}
else // D3D
{
- out.Write("return o;\n}\n");
+ out.Write("return o;\n");
}
+ out.Write("}\n");
if (is_writing_shadercode)
{
@@ -475,7 +483,12 @@ void GenerateVertexShaderCode(VertexShaderCode& object, u32 components, API_TYPE
GenerateVertexShader<VertexShaderCode>(object, components, api_type);
}
-void GenerateVSOutputStructForGS(ShaderCode& object, API_TYPE api_type)
+void GenerateVSOutputStruct(ShaderCode& object, API_TYPE api_type)
{
GenerateVSOutputStruct<ShaderCode>(object, api_type);
}
+
+void GenerateVSOutputStruct(ShaderGeneratorInterface& object, API_TYPE api_type)
+{
+ // Ignore unknown types
+}
diff --git a/Source/Core/VideoCommon/VertexShaderGen.h b/Source/Core/VideoCommon/VertexShaderGen.h
index 998f8fe6bc..b5e9e33f29 100644
--- a/Source/Core/VideoCommon/VertexShaderGen.h
+++ b/Source/Core/VideoCommon/VertexShaderGen.h
@@ -38,7 +38,7 @@ struct vertex_shader_uid_data
u32 numColorChans : 2;
u32 dualTexTrans_enabled : 1;
u32 pixel_lighting : 1;
- u32 pad0 : 1;
+ u32 stereo : 1;
u32 texMtxInfo_n_projection : 16; // Stored separately to guarantee that the texMtxInfo struct is 8 bits wide
struct {
@@ -64,4 +64,5 @@ typedef ShaderCode VertexShaderCode; // TODO: Obsolete..
void GetVertexShaderUid(VertexShaderUid& object, u32 components, API_TYPE api_type);
void GenerateVertexShaderCode(VertexShaderCode& object, u32 components, API_TYPE api_type);
-void GenerateVSOutputStructForGS(ShaderCode& object, API_TYPE api_type);
+void GenerateVSOutputStruct(ShaderCode& object, API_TYPE api_type);
+void GenerateVSOutputStruct(ShaderGeneratorInterface& object, API_TYPE api_type);
diff --git a/Source/Core/VideoCommon/VertexShaderManager.cpp b/Source/Core/VideoCommon/VertexShaderManager.cpp
index 93f969b0b5..8de50c5436 100644
--- a/Source/Core/VideoCommon/VertexShaderManager.cpp
+++ b/Source/Core/VideoCommon/VertexShaderManager.cpp
@@ -489,7 +489,7 @@ void VertexShaderManager::SetConstants()
PRIM_LOG("Projection: %f %f %f %f %f %f\n", rawProjection[0], rawProjection[1], rawProjection[2], rawProjection[3], rawProjection[4], rawProjection[5]);
- if ((g_ActiveConfig.bFreeLook || g_ActiveConfig.bAnaglyphStereo ) && xfmem.projection.type == GX_PERSPECTIVE)
+ if (g_ActiveConfig.bFreeLook && xfmem.projection.type == GX_PERSPECTIVE)
{
Matrix44 mtxA;
Matrix44 mtxB;
@@ -512,6 +512,19 @@ void VertexShaderManager::SetConstants()
Matrix44::Multiply(s_viewportCorrection, projMtx, correctedMtx);
memcpy(constants.projection, correctedMtx.data, 4*16);
}
+
+ if (g_ActiveConfig.iStereoMode > 0 && xfmem.projection.type == GX_PERSPECTIVE)
+ {
+ float offset = (g_ActiveConfig.iStereoSeparation / 1000.0f) * (g_ActiveConfig.iStereoSeparationPercent / 100.0f);
+ constants.stereoparams[0] = (g_ActiveConfig.bStereoSwapEyes) ? offset : -offset;
+ constants.stereoparams[1] = (g_ActiveConfig.bStereoSwapEyes) ? -offset : offset;
+ constants.stereoparams[2] = (g_ActiveConfig.iStereoConvergence / 10.0f) * (g_ActiveConfig.iStereoConvergencePercent / 100.0f);
+ }
+ else
+ {
+ constants.stereoparams[0] = constants.stereoparams[1] = 0;
+ }
+
dirty = true;
}
}
diff --git a/Source/Core/VideoCommon/VideoCommon.vcxproj b/Source/Core/VideoCommon/VideoCommon.vcxproj
index bda73f396c..31dc089736 100644
--- a/Source/Core/VideoCommon/VideoCommon.vcxproj
+++ b/Source/Core/VideoCommon/VideoCommon.vcxproj
@@ -60,6 +60,7 @@
<ClCompile Include="PostProcessing.cpp" />
<ClCompile Include="RenderBase.cpp" />
<ClCompile Include="Statistics.cpp" />
+ <ClCompile Include="GeometryShaderGen.cpp" />
<ClCompile Include="TextureCacheBase.cpp" />
<ClCompile Include="TextureConversionShader.cpp" />
<ClCompile Include="VertexLoader.cpp" />
@@ -110,6 +111,7 @@
<ClInclude Include="RenderBase.h" />
<ClInclude Include="ShaderGenCommon.h" />
<ClInclude Include="Statistics.h" />
+ <ClInclude Include="GeometryShaderGen.h" />
<ClInclude Include="TextureCacheBase.h" />
<ClInclude Include="TextureConversionShader.h" />
<ClInclude Include="TextureDecoder.h" />
diff --git a/Source/Core/VideoCommon/VideoCommon.vcxproj.filters b/Source/Core/VideoCommon/VideoCommon.vcxproj.filters
index c662422200..f285ce35d4 100644
--- a/Source/Core/VideoCommon/VideoCommon.vcxproj.filters
+++ b/Source/Core/VideoCommon/VideoCommon.vcxproj.filters
@@ -143,6 +143,9 @@
<ClCompile Include="BoundingBox.cpp">
<Filter>Util</Filter>
</ClCompile>
+ <ClCompile Include="GeometryShaderGen.cpp">
+ <Filter>Shader Generators</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="CommandProcessor.h" />
@@ -275,6 +278,9 @@
<ClInclude Include="BoundingBox.h">
<Filter>Util</Filter>
</ClInclude>
+ <ClInclude Include="GeometryShaderGen.h">
+ <Filter>Shader Generators</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<Text Include="CMakeLists.txt" />
diff --git a/Source/Core/VideoCommon/VideoConfig.cpp b/Source/Core/VideoCommon/VideoConfig.cpp
index df72df9be2..2b6025f13e 100644
--- a/Source/Core/VideoCommon/VideoConfig.cpp
+++ b/Source/Core/VideoCommon/VideoConfig.cpp
@@ -38,6 +38,11 @@ VideoConfig::VideoConfig()
backend_info.APIType = API_NONE;
backend_info.bUseMinimalMipCount = false;
backend_info.bSupportsExclusiveFullscreen = false;
+
+ // Game-specific stereoscopy settings
+ bStereoMonoEFBDepth = false;
+ iStereoSeparationPercent = 100;
+ iStereoConvergencePercent = 100;
}
void VideoConfig::Load(const std::string& ini_file)
@@ -66,9 +71,6 @@ void VideoConfig::Load(const std::string& ini_file)
settings->Get("DumpEFBTarget", &bDumpEFBTarget, 0);
settings->Get("FreeLook", &bFreeLook, 0);
settings->Get("UseFFV1", &bUseFFV1, 0);
- settings->Get("AnaglyphStereo", &bAnaglyphStereo, false);
- settings->Get("AnaglyphStereoSeparation", &iAnaglyphStereoSeparation, 200);
- settings->Get("AnaglyphFocalAngle", &iAnaglyphFocalAngle, 0);
settings->Get("EnablePixelLighting", &bEnablePixelLighting, 0);
settings->Get("FastDepthCalc", &bFastDepthCalc, true);
settings->Get("MSAA", &iMultisampleMode, 0);
@@ -85,6 +87,10 @@ void VideoConfig::Load(const std::string& ini_file)
enhancements->Get("ForceFiltering", &bForceFiltering, 0);
enhancements->Get("MaxAnisotropy", &iMaxAnisotropy, 0); // NOTE - this is x in (1 << x)
enhancements->Get("PostProcessingShader", &sPostProcessingShader, "");
+ enhancements->Get("StereoMode", &iStereoMode, 0);
+ enhancements->Get("StereoSeparation", &iStereoSeparation, 20);
+ enhancements->Get("StereoConvergence", &iStereoConvergence, 20);
+ enhancements->Get("StereoSwapEyes", &bStereoSwapEyes, false);
IniFile::Section* hacks = iniFile.GetOrCreateSection("Hacks");
hacks->Get("EFBAccessEnable", &bEFBAccessEnable, true);
@@ -140,9 +146,6 @@ void VideoConfig::GameIniLoad()
CHECK_SETTING("Video_Settings", "UseRealXFB", bUseRealXFB);
CHECK_SETTING("Video_Settings", "SafeTextureCacheColorSamples", iSafeTextureCache_ColorSamples);
CHECK_SETTING("Video_Settings", "HiresTextures", bHiresTextures);
- CHECK_SETTING("Video_Settings", "AnaglyphStereo", bAnaglyphStereo);
- CHECK_SETTING("Video_Settings", "AnaglyphStereoSeparation", iAnaglyphStereoSeparation);
- CHECK_SETTING("Video_Settings", "AnaglyphFocalAngle", iAnaglyphFocalAngle);
CHECK_SETTING("Video_Settings", "EnablePixelLighting", bEnablePixelLighting);
CHECK_SETTING("Video_Settings", "FastDepthCalc", bFastDepthCalc);
CHECK_SETTING("Video_Settings", "MSAA", iMultisampleMode);
@@ -179,6 +182,14 @@ void VideoConfig::GameIniLoad()
CHECK_SETTING("Video_Enhancements", "ForceFiltering", bForceFiltering);
CHECK_SETTING("Video_Enhancements", "MaxAnisotropy", iMaxAnisotropy); // NOTE - this is x in (1 << x)
CHECK_SETTING("Video_Enhancements", "PostProcessingShader", sPostProcessingShader);
+ CHECK_SETTING("Video_Enhancements", "StereoMode", iStereoMode);
+ CHECK_SETTING("Video_Enhancements", "StereoSeparation", iStereoSeparation);
+ CHECK_SETTING("Video_Enhancements", "StereoConvergence", iStereoConvergence);
+ CHECK_SETTING("Video_Enhancements", "StereoSwapEyes", bStereoSwapEyes);
+
+ CHECK_SETTING("Video_Stereoscopy", "StereoMonoEFBDepth", bStereoMonoEFBDepth);
+ CHECK_SETTING("Video_Stereoscopy", "StereoSeparationPercent", iStereoSeparationPercent);
+ CHECK_SETTING("Video_Stereoscopy", "StereoConvergencePercent", iStereoConvergencePercent);
CHECK_SETTING("Video_Hacks", "EFBAccessEnable", bEFBAccessEnable);
CHECK_SETTING("Video_Hacks", "EFBCopyEnable", bEFBCopyEnable);
@@ -203,6 +214,7 @@ void VideoConfig::VerifyValidity()
// TODO: Check iMaxAnisotropy value
if (iAdapter < 0 || iAdapter > ((int)backend_info.Adapters.size() - 1)) iAdapter = 0;
if (iMultisampleMode < 0 || iMultisampleMode >= (int)backend_info.AAModes.size()) iMultisampleMode = 0;
+ if (!backend_info.bSupportsStereoscopy) iStereoMode = 0;
}
void VideoConfig::Save(const std::string& ini_file)
@@ -230,9 +242,6 @@ void VideoConfig::Save(const std::string& ini_file)
settings->Set("DumpEFBTarget", bDumpEFBTarget);
settings->Set("FreeLook", bFreeLook);
settings->Set("UseFFV1", bUseFFV1);
- settings->Set("AnaglyphStereo", bAnaglyphStereo);
- settings->Set("AnaglyphStereoSeparation", iAnaglyphStereoSeparation);
- settings->Set("AnaglyphFocalAngle", iAnaglyphFocalAngle);
settings->Set("EnablePixelLighting", bEnablePixelLighting);
settings->Set("FastDepthCalc", bFastDepthCalc);
settings->Set("ShowEFBCopyRegions", bShowEFBCopyRegions);
@@ -250,6 +259,10 @@ void VideoConfig::Save(const std::string& ini_file)
enhancements->Set("ForceFiltering", bForceFiltering);
enhancements->Set("MaxAnisotropy", iMaxAnisotropy);
enhancements->Set("PostProcessingShader", sPostProcessingShader);
+ enhancements->Set("StereoMode", iStereoMode);
+ enhancements->Set("StereoSeparation", iStereoSeparation);
+ enhancements->Set("StereoConvergence", iStereoConvergence);
+ enhancements->Set("StereoSwapEyes", bStereoSwapEyes);
IniFile::Section* hacks = iniFile.GetOrCreateSection("Hacks");
hacks->Set("EFBAccessEnable", bEFBAccessEnable);
diff --git a/Source/Core/VideoCommon/VideoConfig.h b/Source/Core/VideoCommon/VideoConfig.h
index 44b0740728..c825f8ec53 100644
--- a/Source/Core/VideoCommon/VideoConfig.h
+++ b/Source/Core/VideoCommon/VideoConfig.h
@@ -44,6 +44,14 @@ enum EFBScale
SCALE_4X,
};
+enum StereoMode
+{
+ STEREO_OFF = 0,
+ STEREO_SBS,
+ STEREO_TAB,
+ STEREO_ANAGLYPH
+};
+
// NEVER inherit from this class.
struct VideoConfig final
{
@@ -71,6 +79,10 @@ struct VideoConfig final
bool bForceFiltering;
int iMaxAnisotropy;
std::string sPostProcessingShader;
+ int iStereoMode;
+ int iStereoSeparation;
+ int iStereoConvergence;
+ bool bStereoSwapEyes;
// Information
bool bShowFPS;
@@ -92,9 +104,6 @@ struct VideoConfig final
bool bDumpEFBTarget;
bool bUseFFV1;
bool bFreeLook;
- bool bAnaglyphStereo;
- int iAnaglyphStereoSeparation;
- int iAnaglyphFocalAngle;
bool bBorderlessFullscreen;
// Hacks
@@ -115,6 +124,11 @@ struct VideoConfig final
int iLog; // CONF_ bits
int iSaveTargetId; // TODO: Should be dropped
+ // Stereoscopy
+ bool bStereoMonoEFBDepth;
+ int iStereoSeparationPercent;
+ int iStereoConvergencePercent;
+
// D3D only config, mostly to be merged into the above
int iAdapter;
@@ -136,9 +150,11 @@ struct VideoConfig final
bool bSupportsDualSourceBlend;
bool bSupportsPrimitiveRestart;
bool bSupportsOversizedViewports;
+ bool bSupportsStereoscopy;
bool bSupportsEarlyZ; // needed by PixelShaderGen, so must stay in VideoCommon
bool bSupportsBindingLayout; // Needed by ShaderGen, so must stay in VideoCommon
bool bSupportsBBox;
+ bool bSupportsGSInstancing; // Needed by GeometryShaderGen, so must stay in VideoCommon
} backend_info;
// Utility