diff --git a/Source/Core/VideoBackends/D3D/FramebufferManager.cpp b/Source/Core/VideoBackends/D3D/FramebufferManager.cpp
index 407e0d31c8..508e2cb1e8 100644
--- a/Source/Core/VideoBackends/D3D/FramebufferManager.cpp
+++ b/Source/Core/VideoBackends/D3D/FramebufferManager.cpp
@@ -57,7 +57,7 @@ FramebufferManager::FramebufferManager()
 	D3D11_TEXTURE2D_DESC texdesc;
 	HRESULT hr;
 
-	m_efb.slices = 1;
+	m_efb.slices = (g_ActiveConfig.iStereoMode > 0) ? 2 : 1;
 
 	// EFB color texture - primary render target
 	texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, target_width, target_height, m_efb.slices, 1, D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET, D3D11_USAGE_DEFAULT, 0, sample_desc.Count, sample_desc.Quality);
diff --git a/Source/Core/VideoBackends/D3D/LineGeometryShader.cpp b/Source/Core/VideoBackends/D3D/LineGeometryShader.cpp
index cd2b11e2b3..7fcb02ff8d 100644
--- a/Source/Core/VideoBackends/D3D/LineGeometryShader.cpp
+++ b/Source/Core/VideoBackends/D3D/LineGeometryShader.cpp
@@ -173,7 +173,7 @@ bool LineGeometryShader::SetShader(u32 components, float lineWidth,
 		static char buffer[16384];
 		ShaderCode code;
 		code.SetBuffer(buffer);
-		GenerateVSOutputStruct(code, API_D3D);
+		GenerateVSOutputStruct<ShaderCode>(code, API_D3D);
 		code.Write("\n%s", LINE_GS_COMMON);
 
 		std::stringstream numTexCoordsStream;
diff --git a/Source/Core/VideoBackends/D3D/PointGeometryShader.cpp b/Source/Core/VideoBackends/D3D/PointGeometryShader.cpp
index cfaca95cf3..3f874b3915 100644
--- a/Source/Core/VideoBackends/D3D/PointGeometryShader.cpp
+++ b/Source/Core/VideoBackends/D3D/PointGeometryShader.cpp
@@ -167,7 +167,7 @@ bool PointGeometryShader::SetShader(u32 components, float pointSize,
 		static char buffer[16384];
 		ShaderCode code;
 		code.SetBuffer(buffer);
-		GenerateVSOutputStruct(code, API_D3D);
+		GenerateVSOutputStruct<ShaderCode>(code, API_D3D);
 		code.Write("\n%s", POINT_GS_COMMON);
 
 		std::stringstream numTexCoordsStream;
diff --git a/Source/Core/VideoBackends/D3D/VertexManager.cpp b/Source/Core/VideoBackends/D3D/VertexManager.cpp
index c782586a65..526cc30a0b 100644
--- a/Source/Core/VideoBackends/D3D/VertexManager.cpp
+++ b/Source/Core/VideoBackends/D3D/VertexManager.cpp
@@ -214,10 +214,20 @@ void VertexManager::vFlush(bool useDstAlpha)
 		GFX_DEBUGGER_PAUSE_LOG_AT(NEXT_ERROR,true,{printf("Fail to set pixel shader\n");});
 		return;
 	}
+
+	if (g_ActiveConfig.iStereoMode > 0)
+	{
+		if (!GeometryShaderCache::SetShader(components))
+		{
+			GFX_DEBUGGER_PAUSE_LOG_AT(NEXT_ERROR, true, { printf("Fail to set pixel shader\n"); });
+		}
+	}
+
 	if (g_ActiveConfig.backend_info.bSupportsBBox && BoundingBox::active)
 	{
 		D3D::context->OMSetRenderTargetsAndUnorderedAccessViews(D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, nullptr, nullptr, 2, 1, &BBox::GetUAV(), nullptr);
 	}
+
 	u32 stride = VertexLoaderManager::GetCurrentVertexFormat()->GetVertexStride();
 
 	PrepareDrawBuffers(stride);
diff --git a/Source/Core/VideoBackends/D3D/main.cpp b/Source/Core/VideoBackends/D3D/main.cpp
index c840c2a9bc..d5ce0f8dab 100644
--- a/Source/Core/VideoBackends/D3D/main.cpp
+++ b/Source/Core/VideoBackends/D3D/main.cpp
@@ -79,7 +79,8 @@ void InitBackendInfo()
 	g_Config.backend_info.bSupportsDualSourceBlend = true;
 	g_Config.backend_info.bSupportsPrimitiveRestart = true;
 	g_Config.backend_info.bSupportsOversizedViewports = false;
-	g_Config.backend_info.bSupportsStereoscopy = false; // TODO: not implemented
+	g_Config.backend_info.bSupportsStereoscopy = true;
+	g_Config.backend_info.bSupportsGSInstancing = false;
 
 	IDXGIFactory* factory;
 	IDXGIAdapter* ad;
diff --git a/Source/Core/VideoCommon/GeometryShaderGen.cpp b/Source/Core/VideoCommon/GeometryShaderGen.cpp
index 424768e2ec..3ebea24585 100644
--- a/Source/Core/VideoCommon/GeometryShaderGen.cpp
+++ b/Source/Core/VideoCommon/GeometryShaderGen.cpp
@@ -52,14 +52,25 @@ static inline void GenerateGeometryShader(T& out, u32 components, API_TYPE ApiTy
 	uid_data->numTexGens = xfmem.numTexGen.numTexGens;
 	uid_data->pixel_lighting = g_ActiveConfig.bEnablePixelLighting;
 
-	GenerateVSOutputStruct(out, ApiType);
+	GenerateVSOutputStruct<T>(out, ApiType);
+	GenerateGSOutputStruct<T>(out, ApiType);
 
-	out.Write("centroid in VS_OUTPUT o[3];\n");
-	out.Write("centroid out VS_OUTPUT f;\n");
+	if (ApiType == API_OPENGL)
+	{
+		out.Write("centroid in VS_OUTPUT o[3];\n");
+		out.Write("centroid out GS_OUTPUT gs;\n");
 
-	out.Write("flat out int layer;\n");
+		out.Write("void main()\n{\n");
+	}
+	else // D3D
+	{
+		out.Write("[maxvertexcount(6)]\n");
+		out.Write("void main(triangle VS_OUTPUT o[3], inout TriangleStream<GS_OUTPUT> Output)\n{\n");
 
-	out.Write("void main()\n{\n");
+		out.Write("\tGS_OUTPUT gs;\n");
+	}
+
+	out.Write("\tVS_OUTPUT f;\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.
@@ -70,7 +81,10 @@ static inline void GenerateGeometryShader(T& out, u32 components, API_TYPE ApiTy
 
 	out.Write("\tfor (int i = 0; i < 3; ++i) {\n");
 	out.Write("\t\tgs.layer = l;\n");
-	out.Write("\t\tgl_Layer = l;\n");
+
+	if (ApiType == API_OPENGL)
+		out.Write("\t\tgl_Layer = l;\n");
+
 	out.Write("\t\tf = o[i];\n");
 	out.Write("\t\tfloat4 pos = o[i].pos;\n");
 
@@ -88,10 +102,23 @@ static inline void GenerateGeometryShader(T& out, u32 components, API_TYPE ApiTy
 	}
 
 	out.Write("\t\tf.pos.x = pos.x;\n");
-	out.Write("\t\tgl_Position = pos;\n");
-	out.Write("\t\tEmitVertex();\n");
+
+	if (ApiType == API_OPENGL)
+		out.Write("\t\tgl_Position = pos;\n");
+
+	out.Write("\t\tgs.vs = f;\n");
+
+	if (ApiType == API_OPENGL)
+		out.Write("\t\tEmitVertex();\n");
+	else
+		out.Write("\t\tOutput.Append(gs);\n");
+
 	out.Write("\t}\n");
-	out.Write("\tEndPrimitive();\n");
+
+	if (ApiType == API_OPENGL)
+		out.Write("\tEndPrimitive();\n");
+	else
+		out.Write("\t\tOutput.RestartStrip();\n");
 
 	if (!g_ActiveConfig.backend_info.bSupportsGSInstancing)
 		out.Write("\t}\n");
diff --git a/Source/Core/VideoCommon/PixelShaderGen.cpp b/Source/Core/VideoCommon/PixelShaderGen.cpp
index 0e0e9d214c..bf48b29666 100644
--- a/Source/Core/VideoCommon/PixelShaderGen.cpp
+++ b/Source/Core/VideoCommon/PixelShaderGen.cpp
@@ -264,7 +264,8 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T
 		}
 	}
 
-	GenerateVSOutputStruct(out, ApiType);
+	GenerateVSOutputStruct<T>(out, ApiType);
+	GenerateGSOutputStruct<T>(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);
@@ -319,8 +320,7 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T
 		uid_data->stereo = g_ActiveConfig.iStereoMode > 0;
 		if (g_ActiveConfig.iStereoMode > 0)
 		{
-			out.Write("centroid in VS_OUTPUT f;\n");
-			out.Write("flat in int layer;\n");
+			out.Write("centroid in GS_OUTPUT gs;\n");
 		}
 		else
 		{
@@ -348,19 +348,19 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T
 			// 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("\tfloat3 uv%d = gs.vs.tex%d;\n", i, i);
 			}
-			out.Write("\tfloat4 clipPos = f.clipPos;\n");
+			out.Write("\tfloat4 clipPos = gs.vs.clipPos;\n");
 			if (g_ActiveConfig.bEnablePixelLighting)
 			{
-				out.Write("\tfloat4 Normal = f.Normal;\n");
+				out.Write("\tfloat4 Normal = gs.vs.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 colors_0 = %s;\n", (g_ActiveConfig.iStereoMode > 0) ? "gs.vs.colors_0" : "colors_02");
+		out.Write("\tfloat4 colors_1 = %s;\n", (g_ActiveConfig.iStereoMode > 0) ? "gs.vs.colors_1" : "colors_12");
 
 		out.Write("\tfloat4 rawpos = gl_FragCoord;\n");
 	}
@@ -940,7 +940,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, float3(%s.xy * " I_TEXDIMS"[%d].xy, %s))).%s;\n", texmap, texcoords, texmap, g_ActiveConfig.iStereoMode > 0 ? "layer" : "0.0", 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 ? "gs.layer" : "0.0", texswap);
 }
 
 static const char *tevAlphaFuncsTable[] =
diff --git a/Source/Core/VideoCommon/ShaderGenCommon.h b/Source/Core/VideoCommon/ShaderGenCommon.h
index 4d22048ee6..ed9bab9fca 100644
--- a/Source/Core/VideoCommon/ShaderGenCommon.h
+++ b/Source/Core/VideoCommon/ShaderGenCommon.h
@@ -14,6 +14,8 @@
 #include "Common/CommonTypes.h"
 #include "Common/StringUtil.h"
 #include "VideoCommon/VideoCommon.h"
+#include "VideoCommon/VideoConfig.h"
+#include "VideoCommon/XFMemory.h"
 
 /**
  * Common interface for classes that need to go through the shader generation path (GenerateVertexShader, GeneratePixelShader)
@@ -218,6 +220,55 @@ private:
 	std::vector<UidT> m_uids;
 };
 
+template<class T>
+static void DefineOutputStructMember(T& object, API_TYPE api_type, const char* type, const char* name, int var_index, const char* semantic = "", int semantic_index = -1)
+{
+	object.Write("  %s %s", type, name);
+	if (var_index != -1)
+		object.Write("%d", var_index);
+
+	if (api_type == API_D3D && strlen(semantic) > 0)
+	{
+		if (semantic_index != -1)
+			object.Write(" : %s%d", semantic, semantic_index);
+		else
+			object.Write(" : %s", semantic);
+	}
+
+	object.Write(";\n");
+}
+
+template<class T>
+static inline void GenerateVSOutputStruct(T& object, API_TYPE api_type)
+{
+	object.Write("struct VS_OUTPUT {\n");
+
+	DefineOutputStructMember(object, api_type, "float4", "pos", -1, "POSITION");
+	DefineOutputStructMember(object, api_type, "float4", "colors_", 0, "COLOR", 0);
+	DefineOutputStructMember(object, api_type, "float4", "colors_", 1, "COLOR", 1);
+
+	for (unsigned int i = 0; i < xfmem.numTexGen.numTexGens; ++i)
+		DefineOutputStructMember(object, api_type, "float3", "tex", i, "TEXCOORD", i);
+
+	DefineOutputStructMember(object, api_type, "float4", "clipPos", -1, "TEXCOORD", xfmem.numTexGen.numTexGens);
+
+	if (g_ActiveConfig.bEnablePixelLighting)
+		DefineOutputStructMember(object, api_type, "float4", "Normal", -1, "TEXCOORD", xfmem.numTexGen.numTexGens + 1);
+
+	object.Write("};\n");
+}
+
+template<class T>
+static inline void GenerateGSOutputStruct(T& object, API_TYPE api_type)
+{
+	object.Write("struct GS_OUTPUT {\n");
+
+	DefineOutputStructMember(object, api_type, "VS_OUTPUT", "vs", -1, "");
+	DefineOutputStructMember(object, api_type, (api_type == API_OPENGL) ? "flat int" : "uint", "layer", -1, "SV_RenderTargetArrayIndex");
+
+	object.Write("};\n");
+}
+
 // Constant variable names
 #define I_COLORS        "color"
 #define I_KCOLORS       "k"
diff --git a/Source/Core/VideoCommon/VertexShaderGen.cpp b/Source/Core/VideoCommon/VertexShaderGen.cpp
index 6ce3a453b9..00db2b0f02 100644
--- a/Source/Core/VideoCommon/VertexShaderGen.cpp
+++ b/Source/Core/VideoCommon/VertexShaderGen.cpp
@@ -14,43 +14,6 @@
 
 static char text[16768];
 
-template<class T>
-static void DefineVSOutputStructMember(T& object, API_TYPE api_type, const char* type, const char* name, int var_index, const char* semantic, int semantic_index = -1)
-{
-	object.Write("  %s %s", type, name);
-	if (var_index != -1)
-		object.Write("%d", var_index);
-
-	if (api_type == API_OPENGL)
-		object.Write(";\n");
-	else // D3D
-	{
-		if (semantic_index != -1)
-			object.Write(" : %s%d;\n", semantic, semantic_index);
-		else
-			object.Write(" : %s;\n", semantic);
-	}
-}
-
-template<class T>
-static inline void GenerateVSOutputStruct(T& object, API_TYPE api_type)
-{
-	object.Write("struct VS_OUTPUT {\n");
-	DefineVSOutputStructMember(object, api_type, "float4", "pos", -1, "POSITION");
-	DefineVSOutputStructMember(object, api_type, "float4", "colors_", 0, "COLOR", 0);
-	DefineVSOutputStructMember(object, api_type, "float4", "colors_", 1, "COLOR", 1);
-
-	for (unsigned int i = 0; i < xfmem.numTexGen.numTexGens; ++i)
-		DefineVSOutputStructMember(object, api_type, "float3", "tex", i, "TEXCOORD", i);
-
-	DefineVSOutputStructMember(object, api_type, "float4", "clipPos", -1, "TEXCOORD", xfmem.numTexGen.numTexGens);
-
-	if (g_ActiveConfig.bEnablePixelLighting)
-		DefineVSOutputStructMember(object, api_type, "float4", "Normal", -1, "TEXCOORD", xfmem.numTexGen.numTexGens + 1);
-
-	object.Write("};\n");
-}
-
 template<class T>
 static inline void GenerateVertexShader(T& out, u32 components, API_TYPE api_type)
 {
@@ -79,7 +42,7 @@ static inline void GenerateVertexShader(T& out, u32 components, API_TYPE api_typ
 	out.Write(s_shader_uniforms);
 	out.Write("};\n");
 
-	GenerateVSOutputStruct(out, api_type);
+	GenerateVSOutputStruct<T>(out, api_type);
 
 	uid_data->numTexGens = xfmem.numTexGen.numTexGens;
 	uid_data->components = components;
@@ -464,13 +427,3 @@ void GenerateVertexShaderCode(VertexShaderCode& object, u32 components, API_TYPE
 {
 	GenerateVertexShader<VertexShaderCode>(object, components, 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 b5e9e33f29..1f08c1963a 100644
--- a/Source/Core/VideoCommon/VertexShaderGen.h
+++ b/Source/Core/VideoCommon/VertexShaderGen.h
@@ -7,7 +7,6 @@
 #include "VideoCommon/LightingShaderGen.h"
 #include "VideoCommon/ShaderGenCommon.h"
 #include "VideoCommon/VideoCommon.h"
-#include "VideoCommon/XFMemory.h"
 
 // TODO should be reordered
 #define SHADER_POSITION_ATTRIB  0
@@ -64,5 +63,3 @@ 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 GenerateVSOutputStruct(ShaderCode& object, API_TYPE api_type);
-void GenerateVSOutputStruct(ShaderGeneratorInterface& object, API_TYPE api_type);