From 9253bb7d9651f3062e4b7002a2caff377e2290b7 Mon Sep 17 00:00:00 2001 From: Jules Blok Date: Sun, 2 Nov 2014 23:40:52 +0100 Subject: [PATCH] D3D: Add geometry shader stereoscopy support. --- .../VideoBackends/D3D/FramebufferManager.cpp | 2 +- .../VideoBackends/D3D/LineGeometryShader.cpp | 2 +- .../VideoBackends/D3D/PointGeometryShader.cpp | 2 +- .../Core/VideoBackends/D3D/VertexManager.cpp | 10 ++++ Source/Core/VideoBackends/D3D/main.cpp | 3 +- Source/Core/VideoCommon/GeometryShaderGen.cpp | 45 ++++++++++++---- Source/Core/VideoCommon/PixelShaderGen.cpp | 18 +++---- Source/Core/VideoCommon/ShaderGenCommon.h | 51 +++++++++++++++++++ Source/Core/VideoCommon/VertexShaderGen.cpp | 49 +----------------- Source/Core/VideoCommon/VertexShaderGen.h | 3 -- 10 files changed, 112 insertions(+), 73 deletions(-) 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(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(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(out, ApiType); + GenerateGSOutputStruct(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 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(out, ApiType); + GenerateGSOutputStruct(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 m_uids; }; +template +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 +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 +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 -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 -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 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(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(object, components, api_type); } - -void GenerateVSOutputStruct(ShaderCode& object, API_TYPE api_type) -{ - GenerateVSOutputStruct(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);