diff --git a/Source/Core/DolphinWX/VideoConfigDiag.cpp b/Source/Core/DolphinWX/VideoConfigDiag.cpp index 6ccba4251d..c1a26c2387 100644 --- a/Source/Core/DolphinWX/VideoConfigDiag.cpp +++ b/Source/Core/DolphinWX/VideoConfigDiag.cpp @@ -449,7 +449,7 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string &title, con // - stereoscopy - if (vconfig.backend_info.bSupportsStereoscopy && vconfig.iStereoMode > 0) + if (vconfig.backend_info.bSupportsGeometryShaders && vconfig.iStereoMode > 0) { wxFlexGridSizer* const szr_stereo = new wxFlexGridSizer(2, 5, 5); diff --git a/Source/Core/VideoBackends/D3D/D3D.vcxproj b/Source/Core/VideoBackends/D3D/D3D.vcxproj index f70efea502..a83e265c34 100644 --- a/Source/Core/VideoBackends/D3D/D3D.vcxproj +++ b/Source/Core/VideoBackends/D3D/D3D.vcxproj @@ -44,12 +44,10 @@ - - @@ -69,11 +67,9 @@ - - diff --git a/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters b/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters index a83db06c6a..e5f5baf882 100644 --- a/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters +++ b/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters @@ -33,9 +33,6 @@ Render - - Render - Render @@ -45,9 +42,6 @@ Render - - Render - Render @@ -99,18 +93,12 @@ Render - - Render - Render Render - - Render - Render diff --git a/Source/Core/VideoBackends/D3D/D3DUtil.cpp b/Source/Core/VideoBackends/D3D/D3DUtil.cpp index 50eac8665b..ad9acc809f 100644 --- a/Source/Core/VideoBackends/D3D/D3DUtil.cpp +++ b/Source/Core/VideoBackends/D3D/D3DUtil.cpp @@ -350,6 +350,7 @@ int CD3DFont::DrawTextScaled(float x, float y, float size, float spacing, u32 dw D3D::stateman->SetPixelShader(m_pshader); D3D::stateman->SetVertexShader(m_vshader); + D3D::stateman->SetGeometryShader(nullptr); D3D::stateman->SetInputLayout(m_InputLayout); D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); diff --git a/Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp b/Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp index 29172f91a1..9a9da67b63 100644 --- a/Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp +++ b/Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp @@ -17,6 +17,8 @@ #include "VideoCommon/Debugger.h" #include "VideoCommon/GeometryShaderGen.h" +#include "VideoCommon/GeometryShaderManager.h" +#include "VideoCommon/Statistics.h" #include "VideoCommon/VideoConfig.h" namespace DX11 @@ -26,6 +28,7 @@ GeometryShaderCache::GSCache GeometryShaderCache::GeometryShaders; const GeometryShaderCache::GSCacheEntry* GeometryShaderCache::last_entry; GeometryShaderUid GeometryShaderCache::last_uid; UidChecker GeometryShaderCache::geometry_uid_checker; +const GeometryShaderCache::GSCacheEntry GeometryShaderCache::pass_entry; ID3D11GeometryShader* ClearGeometryShader = nullptr; ID3D11GeometryShader* CopyGeometryShader = nullptr; @@ -37,6 +40,22 @@ ID3D11GeometryShader* GeometryShaderCache::GetCopyGeometryShader() { return Copy ID3D11Buffer* gscbuf = nullptr; +ID3D11Buffer* &GeometryShaderCache::GetConstantBuffer() +{ + // TODO: divide the global variables of the generated shaders into about 5 constant buffers to speed this up + if (GeometryShaderManager::dirty) + { + D3D11_MAPPED_SUBRESOURCE map; + D3D::context->Map(gscbuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + memcpy(map.pData, &GeometryShaderManager::constants, sizeof(GeometryShaderConstants)); + D3D::context->Unmap(gscbuf, 0); + GeometryShaderManager::dirty = false; + + ADDSTAT(stats.thisFrame.bytesUniformStreamed, sizeof(GeometryShaderConstants)); + } + return gscbuf; +} + // this class will load the precompiled shaders into our cache class GeometryShaderCacheInserter : public LinearDiskCacheReader { @@ -113,6 +132,12 @@ const char copy_shader_code[] = { void GeometryShaderCache::Init() { + unsigned int gbsize = ROUND_UP(sizeof(GeometryShaderConstants), 16); // must be a multiple of 16 + D3D11_BUFFER_DESC gbdesc = CD3D11_BUFFER_DESC(gbsize, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); + HRESULT hr = D3D::device->CreateBuffer(&gbdesc, nullptr, &gscbuf); + CHECK(hr == S_OK, "Create geometry shader constant buffer (size=%u)", gbsize); + D3D::SetDebugObjectName((ID3D11DeviceChild*)gscbuf, "geometry shader constant buffer used to emulate the GX pipeline"); + // used when drawing clear quads ClearGeometryShader = D3D::CompileAndCreateGeometryShader(clear_shader_code); CHECK(ClearGeometryShader != nullptr, "Create clear geometry shader"); @@ -152,6 +177,8 @@ void GeometryShaderCache::Clear() void GeometryShaderCache::Shutdown() { + SAFE_RELEASE(gscbuf); + SAFE_RELEASE(ClearGeometryShader); SAFE_RELEASE(CopyGeometryShader); @@ -160,14 +187,14 @@ void GeometryShaderCache::Shutdown() g_gs_disk_cache.Close(); } -bool GeometryShaderCache::SetShader(u32 components) +bool GeometryShaderCache::SetShader(u32 primitive_type) { GeometryShaderUid uid; - GetGeometryShaderUid(uid, components, API_D3D); + GetGeometryShaderUid(uid, primitive_type, API_D3D); if (g_ActiveConfig.bEnableShaderDebugging) { ShaderCode code; - GenerateGeometryShaderCode(code, components, API_D3D); + GenerateGeometryShaderCode(code, primitive_type, API_D3D); geometry_uid_checker.AddToIndexAndCheck(code, uid, "Geometry", "g"); } @@ -177,12 +204,20 @@ bool GeometryShaderCache::SetShader(u32 components) if (uid == last_uid) { GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE,true); - return (last_entry->shader != nullptr); + return true; } } last_uid = uid; + // Check if the shader is a pass-through shader + if (IsPassthroughGeometryShader(uid)) + { + // Return the default pass-through shader + last_entry = &pass_entry; + return true; + } + // Check if the shader is already in the cache GSCache::iterator iter; iter = GeometryShaders.find(uid); @@ -196,7 +231,7 @@ bool GeometryShaderCache::SetShader(u32 components) // Need to compile a new shader ShaderCode code; - GenerateGeometryShaderCode(code, components, API_D3D); + GenerateGeometryShaderCode(code, primitive_type, API_D3D); D3DBlob* pbytecode; if (!D3D::CompileGeometryShader(code.GetBuffer(), &pbytecode)) diff --git a/Source/Core/VideoBackends/D3D/GeometryShaderCache.h b/Source/Core/VideoBackends/D3D/GeometryShaderCache.h index 9d38922d04..d88b88f4ae 100644 --- a/Source/Core/VideoBackends/D3D/GeometryShaderCache.h +++ b/Source/Core/VideoBackends/D3D/GeometryShaderCache.h @@ -18,13 +18,14 @@ public: static void Init(); static void Clear(); static void Shutdown(); - static bool SetShader(u32 components); // TODO: Should be renamed to LoadShader + static bool SetShader(u32 primitive_type); // TODO: Should be renamed to LoadShader static bool InsertByteCode(const GeometryShaderUid &uid, const void* bytecode, unsigned int bytecodelen); static ID3D11GeometryShader* GeometryShaderCache::GetClearGeometryShader(); static ID3D11GeometryShader* GeometryShaderCache::GetCopyGeometryShader(); static ID3D11GeometryShader* GetActiveShader() { return last_entry->shader; } + static ID3D11Buffer* &GetConstantBuffer(); private: struct GSCacheEntry @@ -42,6 +43,7 @@ private: static GSCache GeometryShaders; static const GSCacheEntry* last_entry; static GeometryShaderUid last_uid; + static const GSCacheEntry pass_entry; static UidChecker geometry_uid_checker; }; diff --git a/Source/Core/VideoBackends/D3D/LineGeometryShader.cpp b/Source/Core/VideoBackends/D3D/LineGeometryShader.cpp deleted file mode 100644 index 7fcb02ff8d..0000000000 --- a/Source/Core/VideoBackends/D3D/LineGeometryShader.cpp +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include - -#include "VideoBackends/D3D/D3DBase.h" -#include "VideoBackends/D3D/D3DShader.h" -#include "VideoBackends/D3D/D3DState.h" -#include "VideoBackends/D3D/LineGeometryShader.h" -#include "VideoCommon/VertexShaderGen.h" - -namespace DX11 -{ - -struct LineGSParams -{ - FLOAT LineWidth; // In units of 1/6 of an EFB pixel - FLOAT TexOffset; - FLOAT VpWidth; // Width and height of the viewport in EFB pixels - FLOAT VpHeight; - FLOAT TexOffsetEnable[8]; // For each tex coordinate, whether to apply offset to it (1 on, 0 off) -}; - -union LineGSParams_Padded -{ - LineGSParams params; - // Constant buffers must be a multiple of 16 bytes in size. - u8 pad[(sizeof(LineGSParams) + 15) & ~15]; -}; - -static const char LINE_GS_COMMON[] = -// The struct VS_OUTPUT used by the vertex shader goes here. -"// dolphin-emu line geometry shader common part\n" - -"cbuffer cbParams : register(b0)\n" -"{\n" - "struct\n" // Should match LineGSParams above - "{\n" - "float LineWidth;\n" - "float TexOffset;\n" - "float VpWidth;\n" - "float VpHeight;\n" - "float TexOffsetEnable[8];\n" - "} Params;\n" -"}\n" - -"[maxvertexcount(4)]\n" -"void main(line VS_OUTPUT input[2], inout TriangleStream outStream)\n" -"{\n" - // Pretend input[0] is on the bottom and input[1] is on top. - // We generate vertices to the left and right. - - "VS_OUTPUT l0 = input[0];\n" - "VS_OUTPUT r0 = l0;\n" - "VS_OUTPUT l1 = input[1];\n" - "VS_OUTPUT r1 = l1;\n" - - // GameCube/Wii's line drawing algorithm is a little quirky. It does not - // use the correct line caps. Instead, the line caps are vertical or - // horizontal depending the slope of the line. - - "float2 offset;\n" - "float2 to = abs(input[1].pos.xy - input[0].pos.xy);\n" - // FIXME: What does real hardware do when line is at a 45-degree angle? - // FIXME: Lines aren't drawn at the correct width. See Twilight Princess map. - "if (Params.VpHeight*to.y > Params.VpWidth*to.x) {\n" - // Line is more tall. Extend geometry left and right. - // Lerp Params.LineWidth/2 from [0..VpWidth] to [-1..1] - "offset = float2(Params.LineWidth/Params.VpWidth, 0);\n" - "} else {\n" - // Line is more wide. Extend geometry up and down. - // Lerp Params.LineWidth/2 from [0..VpHeight] to [1..-1] - "offset = float2(0, -Params.LineWidth/Params.VpHeight);\n" - "}\n" - - "l0.pos.xy -= offset * input[0].pos.w;\n" - "r0.pos.xy += offset * input[0].pos.w;\n" - "l1.pos.xy -= offset * input[1].pos.w;\n" - "r1.pos.xy += offset * input[1].pos.w;\n" - -"#ifndef NUM_TEXCOORDS\n" -"#error NUM_TEXCOORDS not defined\n" -"#endif\n" - - // Apply TexOffset to all tex coordinates in the vertex. - // They can each be enabled separately. -"#if NUM_TEXCOORDS >= 1\n" - "r0.tex0.x += Params.TexOffset * Params.TexOffsetEnable[0];\n" - "r1.tex0.x += Params.TexOffset * Params.TexOffsetEnable[0];\n" -"#endif\n" -"#if NUM_TEXCOORDS >= 2\n" - "r0.tex1.x += Params.TexOffset * Params.TexOffsetEnable[1];\n" - "r1.tex1.x += Params.TexOffset * Params.TexOffsetEnable[1];\n" -"#endif\n" -"#if NUM_TEXCOORDS >= 3\n" - "r0.tex2.x += Params.TexOffset * Params.TexOffsetEnable[2];\n" - "r1.tex2.x += Params.TexOffset * Params.TexOffsetEnable[2];\n" -"#endif\n" -"#if NUM_TEXCOORDS >= 4\n" - "r0.tex3.x += Params.TexOffset * Params.TexOffsetEnable[3];\n" - "r1.tex3.x += Params.TexOffset * Params.TexOffsetEnable[3];\n" -"#endif\n" -"#if NUM_TEXCOORDS >= 5\n" - "r0.tex4.x += Params.TexOffset * Params.TexOffsetEnable[4];\n" - "r1.tex4.x += Params.TexOffset * Params.TexOffsetEnable[4];\n" -"#endif\n" -"#if NUM_TEXCOORDS >= 6\n" - "r0.tex5.x += Params.TexOffset * Params.TexOffsetEnable[5];\n" - "r1.tex5.x += Params.TexOffset * Params.TexOffsetEnable[5];\n" -"#endif\n" -"#if NUM_TEXCOORDS >= 7\n" - "r0.tex6.x += Params.TexOffset * Params.TexOffsetEnable[6];\n" - "r1.tex6.x += Params.TexOffset * Params.TexOffsetEnable[6];\n" -"#endif\n" -"#if NUM_TEXCOORDS >= 8\n" - "r0.tex7.x += Params.TexOffset * Params.TexOffsetEnable[7];\n" - "r1.tex7.x += Params.TexOffset * Params.TexOffsetEnable[7];\n" -"#endif\n" - - "outStream.Append(l0);\n" - "outStream.Append(r0);\n" - "outStream.Append(l1);\n" - "outStream.Append(r1);\n" -"}\n" -; - -LineGeometryShader::LineGeometryShader() - : m_ready(false), m_paramsBuffer(nullptr) -{ } - -void LineGeometryShader::Init() -{ - m_ready = false; - - HRESULT hr; - - // Create constant buffer for uploading data to geometry shader - - D3D11_BUFFER_DESC bd = CD3D11_BUFFER_DESC(sizeof(LineGSParams_Padded), - D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); - hr = D3D::device->CreateBuffer(&bd, nullptr, &m_paramsBuffer); - CHECK(SUCCEEDED(hr), "create line geometry shader params buffer"); - D3D::SetDebugObjectName(m_paramsBuffer, "line geometry shader params buffer"); - - m_ready = true; -} - -void LineGeometryShader::Shutdown() -{ - m_ready = false; - - for (auto& it : m_shaders) - { - SAFE_RELEASE(it.second); - } - m_shaders.clear(); - - SAFE_RELEASE(m_paramsBuffer); -} - -bool LineGeometryShader::SetShader(u32 components, float lineWidth, - float texOffset, float vpWidth, float vpHeight, const bool* texOffsetEnable) -{ - if (!m_ready) - return false; - - // Make sure geometry shader for "components" is available - ComboMap::iterator shaderIt = m_shaders.find(components); - if (shaderIt == m_shaders.end()) - { - // Generate new shader. Warning: not thread-safe. - static char buffer[16384]; - ShaderCode code; - code.SetBuffer(buffer); - GenerateVSOutputStruct(code, API_D3D); - code.Write("\n%s", LINE_GS_COMMON); - - std::stringstream numTexCoordsStream; - numTexCoordsStream << xfmem.numTexGen.numTexGens; - - INFO_LOG(VIDEO, "Compiling line geometry shader for components 0x%.08X (num texcoords %d)", - components, xfmem.numTexGen.numTexGens); - - const std::string& numTexCoordsStr = numTexCoordsStream.str(); - D3D_SHADER_MACRO macros[] = { - { "NUM_TEXCOORDS", numTexCoordsStr.c_str() }, - { nullptr, nullptr } - }; - ID3D11GeometryShader* newShader = D3D::CompileAndCreateGeometryShader(code.GetBuffer(), macros); - if (!newShader) - { - WARN_LOG(VIDEO, "Line geometry shader for components 0x%.08X failed to compile", components); - // Add dummy shader to prevent trying to compile again - m_shaders[components] = nullptr; - return false; - } - - shaderIt = m_shaders.insert(std::make_pair(components, newShader)).first; - } - - if (shaderIt != m_shaders.end()) - { - if (shaderIt->second) - { - D3D11_MAPPED_SUBRESOURCE map; - HRESULT hr = D3D::context->Map(m_paramsBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - if (SUCCEEDED(hr)) - { - LineGSParams* params = (LineGSParams*)map.pData; - params->LineWidth = lineWidth; - - params->TexOffset = texOffset; - params->VpWidth = vpWidth; - params->VpHeight = vpHeight; - for (int i = 0; i < 8; ++i) - params->TexOffsetEnable[i] = texOffsetEnable[i] ? 1.f : 0.f; - - D3D::context->Unmap(m_paramsBuffer, 0); - } - else - ERROR_LOG(VIDEO, "Failed to map line gs params buffer"); - - DEBUG_LOG(VIDEO, "Line params: width %f, texOffset %f, vpWidth %f, vpHeight %f", - lineWidth, texOffset, vpWidth, vpHeight); - - D3D::stateman->SetGeometryShader(shaderIt->second); - D3D::stateman->SetGeometryConstants(m_paramsBuffer); - - return true; - } - else - return false; - } - else - return false; -} - -} diff --git a/Source/Core/VideoBackends/D3D/LineGeometryShader.h b/Source/Core/VideoBackends/D3D/LineGeometryShader.h deleted file mode 100644 index 4bcb159314..0000000000 --- a/Source/Core/VideoBackends/D3D/LineGeometryShader.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -#include "VideoCommon/VideoCommon.h" - -struct ID3D11Buffer; -struct ID3D11GeometryShader; - -namespace DX11 -{ - -// This class manages a collection of line geometry shaders, one for each -// vertex format. -class LineGeometryShader -{ - -public: - - LineGeometryShader(); - - void Init(); - void Shutdown(); - // Returns true on success, false on failure - bool SetShader(u32 components, float lineWidth, float texOffset, - float vpWidth, float vpHeight, const bool* texOffsetEnable); - -private: - - bool m_ready; - - ID3D11Buffer* m_paramsBuffer; - - typedef std::map ComboMap; - - ComboMap m_shaders; - -}; - -} diff --git a/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp b/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp index fcc40cc9e5..0ca9ee2211 100644 --- a/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp +++ b/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp @@ -1084,6 +1084,7 @@ size_t PSTextureEncoder::Encode(u8* dst, unsigned int dstFormat, #endif { D3D::stateman->SetVertexShader(m_vShader); + D3D::stateman->SetGeometryShader(nullptr); D3D::stateman->PushBlendState(m_efbEncodeBlendState); D3D::stateman->PushDepthState(m_efbEncodeDepthState); diff --git a/Source/Core/VideoBackends/D3D/PixelShaderCache.cpp b/Source/Core/VideoBackends/D3D/PixelShaderCache.cpp index d8fbd62158..ae1919c91e 100644 --- a/Source/Core/VideoBackends/D3D/PixelShaderCache.cpp +++ b/Source/Core/VideoBackends/D3D/PixelShaderCache.cpp @@ -432,7 +432,7 @@ public: void PixelShaderCache::Init() { - unsigned int cbsize = ((sizeof(PixelShaderConstants))&(~0xf))+0x10; // must be a multiple of 16 + unsigned int cbsize = ROUND_UP(sizeof(PixelShaderConstants), 16); // must be a multiple of 16 D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(cbsize, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); D3D::device->CreateBuffer(&cbdesc, nullptr, &pscbuf); CHECK(pscbuf!=nullptr, "Create pixel shader constant buffer"); diff --git a/Source/Core/VideoBackends/D3D/PointGeometryShader.cpp b/Source/Core/VideoBackends/D3D/PointGeometryShader.cpp deleted file mode 100644 index 3f874b3915..0000000000 --- a/Source/Core/VideoBackends/D3D/PointGeometryShader.cpp +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include - -#include "VideoBackends/D3D/D3DBase.h" -#include "VideoBackends/D3D/D3DShader.h" -#include "VideoBackends/D3D/D3DState.h" -#include "VideoBackends/D3D/PointGeometryShader.h" -#include "VideoCommon/VertexShaderGen.h" - -namespace DX11 -{ - -struct PointGSParams -{ - FLOAT PointSize; // In units of 1/6 of an EFB pixel - FLOAT TexOffset; - FLOAT VpWidth; // Width and height of viewport in EFB pixels - FLOAT VpHeight; - FLOAT TexOffsetEnable[8]; // For each tex coordinate, whether to apply offset to it (1 on, 0 off) -}; - -union PointGSParams_Padded -{ - PointGSParams params; - // Constant buffers must be a multiple of 16 bytes in size. - u8 pad[(sizeof(PointGSParams) + 15) & ~15]; -}; - -static const char POINT_GS_COMMON[] = -// The struct VS_OUTPUT used by the vertex shader goes here. -"// dolphin-emu point geometry shader common part\n" - -"cbuffer cbParams : register(b0)\n" -"{\n" - "struct\n" // Should match PointGSParams above - "{\n" - "float PointSize;\n" - "float TexOffset;\n" - "float VpWidth;\n" - "float VpHeight;\n" - "float TexOffsetEnable[8];\n" - "} Params;\n" -"}\n" - -"[maxvertexcount(4)]\n" -"void main(point VS_OUTPUT input[1], inout TriangleStream outStream)\n" -"{\n" - "VS_OUTPUT ptLL = input[0];\n" - "VS_OUTPUT ptLR = ptLL;\n" - "VS_OUTPUT ptUL = ptLL;\n" - "VS_OUTPUT ptUR = ptLL;\n" - - // Offset from center to upper right vertex - // Lerp Params.PointSize/2 from [0,0..VpWidth,VpHeight] to [-1,1..1,-1] - "float2 offset = float2(Params.PointSize/Params.VpWidth, -Params.PointSize/Params.VpHeight) * input[0].pos.w;\n" - - "ptLL.pos.xy += float2(-1,-1) * offset;\n" - "ptLR.pos.xy += float2(1,-1) * offset;\n" - "ptUL.pos.xy += float2(-1,1) * offset;\n" - "ptUR.pos.xy += offset;\n" - - "float2 texOffset = float2(Params.TexOffset, Params.TexOffset);\n" - -"#ifndef NUM_TEXCOORDS\n" -"#error NUM_TEXCOORDS not defined\n" -"#endif\n" - - // Apply TexOffset to all tex coordinates in the vertex - // FIXME: The game may be able to enable TexOffset for some coords and - // disable for others, but where is that information stored? -"#if NUM_TEXCOORDS >= 1\n" - "ptLL.tex0.xy += float2(0,1) * texOffset * Params.TexOffsetEnable[0];\n" - "ptLR.tex0.xy += texOffset * Params.TexOffsetEnable[0];\n" - "ptUR.tex0.xy += float2(1,0) * texOffset * Params.TexOffsetEnable[0];\n" -"#endif\n" -"#if NUM_TEXCOORDS >= 2\n" - "ptLL.tex1.xy += float2(0,1) * texOffset * Params.TexOffsetEnable[1];\n" - "ptLR.tex1.xy += texOffset * Params.TexOffsetEnable[1];\n" - "ptUR.tex1.xy += float2(1,0) * texOffset * Params.TexOffsetEnable[1];\n" -"#endif\n" -"#if NUM_TEXCOORDS >= 3\n" - "ptLL.tex2.xy += float2(0,1) * texOffset * Params.TexOffsetEnable[2];\n" - "ptLR.tex2.xy += texOffset * Params.TexOffsetEnable[2];\n" - "ptUR.tex2.xy += float2(1,0) * texOffset * Params.TexOffsetEnable[2];\n" -"#endif\n" -"#if NUM_TEXCOORDS >= 4\n" - "ptLL.tex3.xy += float2(0,1) * texOffset * Params.TexOffsetEnable[3];\n" - "ptLR.tex3.xy += texOffset * Params.TexOffsetEnable[3];\n" - "ptUR.tex3.xy += float2(1,0) * texOffset * Params.TexOffsetEnable[3];\n" -"#endif\n" -"#if NUM_TEXCOORDS >= 5\n" - "ptLL.tex4.xy += float2(0,1) * texOffset * Params.TexOffsetEnable[4];\n" - "ptLR.tex4.xy += texOffset * Params.TexOffsetEnable[4];\n" - "ptUR.tex4.xy += float2(1,0) * texOffset * Params.TexOffsetEnable[4];\n" -"#endif\n" -"#if NUM_TEXCOORDS >= 6\n" - "ptLL.tex5.xy += float2(0,1) * texOffset * Params.TexOffsetEnable[5];\n" - "ptLR.tex5.xy += texOffset * Params.TexOffsetEnable[5];\n" - "ptUR.tex5.xy += float2(1,0) * texOffset * Params.TexOffsetEnable[5];\n" -"#endif\n" -"#if NUM_TEXCOORDS >= 7\n" - "ptLL.tex6.xy += float2(0,1) * texOffset * Params.TexOffsetEnable[6];\n" - "ptLR.tex6.xy += texOffset * Params.TexOffsetEnable[6];\n" - "ptUR.tex6.xy += float2(1,0) * texOffset * Params.TexOffsetEnable[6];\n" -"#endif\n" -"#if NUM_TEXCOORDS >= 8\n" - "ptLL.tex7.xy += float2(0,1) * texOffset * Params.TexOffsetEnable[7];\n" - "ptLR.tex7.xy += texOffset * Params.TexOffsetEnable[7];\n" - "ptUR.tex7.xy += float2(1,0) * texOffset * Params.TexOffsetEnable[7];\n" -"#endif\n" - - "outStream.Append(ptLL);\n" - "outStream.Append(ptLR);\n" - "outStream.Append(ptUL);\n" - "outStream.Append(ptUR);\n" -"}\n" -; - -PointGeometryShader::PointGeometryShader() - : m_ready(false), m_paramsBuffer(nullptr) -{ } - -void PointGeometryShader::Init() -{ - m_ready = false; - - HRESULT hr; - - // Create constant buffer for uploading data to geometry shader - - D3D11_BUFFER_DESC bd = CD3D11_BUFFER_DESC(sizeof(PointGSParams_Padded), - D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); - hr = D3D::device->CreateBuffer(&bd, nullptr, &m_paramsBuffer); - CHECK(SUCCEEDED(hr), "create point geometry shader params buffer"); - D3D::SetDebugObjectName(m_paramsBuffer, "point geometry shader params buffer"); - - m_ready = true; -} - -void PointGeometryShader::Shutdown() -{ - m_ready = false; - - for (auto& it : m_shaders) - { - SAFE_RELEASE(it.second); - } - m_shaders.clear(); - - SAFE_RELEASE(m_paramsBuffer); -} - -bool PointGeometryShader::SetShader(u32 components, float pointSize, - float texOffset, float vpWidth, float vpHeight, const bool* texOffsetEnable) -{ - if (!m_ready) - return false; - - // Make sure geometry shader for "components" is available - ComboMap::iterator shaderIt = m_shaders.find(components); - if (shaderIt == m_shaders.end()) - { - // Generate new shader. Warning: not thread-safe. - static char buffer[16384]; - ShaderCode code; - code.SetBuffer(buffer); - GenerateVSOutputStruct(code, API_D3D); - code.Write("\n%s", POINT_GS_COMMON); - - std::stringstream numTexCoordsStream; - numTexCoordsStream << xfmem.numTexGen.numTexGens; - - INFO_LOG(VIDEO, "Compiling point geometry shader for components 0x%.08X (num texcoords %d)", - components, xfmem.numTexGen.numTexGens); - - const std::string& numTexCoordsStr = numTexCoordsStream.str(); - D3D_SHADER_MACRO macros[] = { - { "NUM_TEXCOORDS", numTexCoordsStr.c_str() }, - { nullptr, nullptr } - }; - ID3D11GeometryShader* newShader = D3D::CompileAndCreateGeometryShader(code.GetBuffer(), macros); - if (!newShader) - { - WARN_LOG(VIDEO, "Point geometry shader for components 0x%.08X failed to compile", components); - // Add dummy shader to prevent trying to compile again - m_shaders[components] = nullptr; - return false; - } - - shaderIt = m_shaders.insert(std::make_pair(components, newShader)).first; - } - - if (shaderIt != m_shaders.end()) - { - if (shaderIt->second) - { - D3D11_MAPPED_SUBRESOURCE map; - HRESULT hr = D3D::context->Map(m_paramsBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - if (SUCCEEDED(hr)) - { - PointGSParams* params = (PointGSParams*)map.pData; - params->PointSize = pointSize; - - params->TexOffset = texOffset; - params->VpWidth = vpWidth; - params->VpHeight = vpHeight; - for (int i = 0; i < 8; ++i) - params->TexOffsetEnable[i] = texOffsetEnable[i] ? 1.f : 0.f; - - D3D::context->Unmap(m_paramsBuffer, 0); - } - else - ERROR_LOG(VIDEO, "Failed to map point gs params buffer"); - - DEBUG_LOG(VIDEO, "Point params: size %f, texOffset %f, vpWidth %f, vpHeight %f", - pointSize, texOffset, vpWidth, vpHeight); - - D3D::stateman->SetGeometryShader(shaderIt->second); - D3D::stateman->SetGeometryConstants(m_paramsBuffer); - - return true; - } - else - return false; - } - else - return false; -} - -} diff --git a/Source/Core/VideoBackends/D3D/PointGeometryShader.h b/Source/Core/VideoBackends/D3D/PointGeometryShader.h deleted file mode 100644 index b24f73d486..0000000000 --- a/Source/Core/VideoBackends/D3D/PointGeometryShader.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -#include "VideoCommon/VideoCommon.h" - -struct ID3D11Buffer; -struct ID3D11GeometryShader; - -namespace DX11 -{ - -// This class manages a collection of point geometry shaders, one for each -// vertex format. -class PointGeometryShader -{ - -public: - - PointGeometryShader(); - - void Init(); - void Shutdown(); - // Returns true on success, false on failure - bool SetShader(u32 components, float pointSize, float texOffset, - float vpWidth, float vpHeight, const bool* texOffsetEnable); - -private: - - bool m_ready; - - ID3D11Buffer* m_paramsBuffer; - - typedef std::map ComboMap; - - ComboMap m_shaders; - -}; - -} diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index 0f5aaa8853..95fa5e1e57 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -1105,13 +1105,14 @@ void Renderer::ApplyState(bool bUseDstAlpha) } ID3D11Buffer* vertexConstants = VertexShaderCache::GetConstantBuffer(); - ID3D11Buffer* pixelConstants = PixelShaderCache::GetConstantBuffer(); - D3D::stateman->SetPixelConstants(pixelConstants, g_ActiveConfig.bEnablePixelLighting ? vertexConstants : nullptr); + D3D::stateman->SetPixelConstants(PixelShaderCache::GetConstantBuffer(), g_ActiveConfig.bEnablePixelLighting ? vertexConstants : nullptr); D3D::stateman->SetVertexConstants(vertexConstants); + D3D::stateman->SetGeometryConstants(GeometryShaderCache::GetConstantBuffer()); D3D::stateman->SetPixelShader(PixelShaderCache::GetActiveShader()); D3D::stateman->SetVertexShader(VertexShaderCache::GetActiveShader()); + D3D::stateman->SetGeometryShader(GeometryShaderCache::GetActiveShader()); } void Renderer::RestoreState() @@ -1252,11 +1253,6 @@ void Renderer::SetDitherMode() // TODO: Set dither mode to bpmem.blendmode.dither } -void Renderer::SetLineWidth() -{ - // TODO -} - void Renderer::SetSamplerState(int stage, int texindex) { const FourTexUnits &tex = bpmem.tex[texindex]; diff --git a/Source/Core/VideoBackends/D3D/Render.h b/Source/Core/VideoBackends/D3D/Render.h index ac03cace98..33e3cf0681 100644 --- a/Source/Core/VideoBackends/D3D/Render.h +++ b/Source/Core/VideoBackends/D3D/Render.h @@ -19,7 +19,6 @@ public: void SetDepthMode() override; void SetLogicOpMode() override; void SetDitherMode() override; - void SetLineWidth() override; void SetSamplerState(int stage,int texindex) override; void SetInterlacingMode() override; void SetViewport() override; diff --git a/Source/Core/VideoBackends/D3D/VertexManager.cpp b/Source/Core/VideoBackends/D3D/VertexManager.cpp index abc7f18e33..5a15ca2a0b 100644 --- a/Source/Core/VideoBackends/D3D/VertexManager.cpp +++ b/Source/Core/VideoBackends/D3D/VertexManager.cpp @@ -12,7 +12,6 @@ #include "VideoBackends/D3D/VertexShaderCache.h" #include "VideoCommon/BoundingBox.h" -#include "VideoCommon/BPMemory.h" #include "VideoCommon/Debugger.h" #include "VideoCommon/IndexGenerator.h" #include "VideoCommon/MainBase.h" @@ -49,16 +48,10 @@ void VertexManager::CreateDeviceObjects() m_currentBuffer = 0; m_bufferCursor = MAX_BUFFER_SIZE; - - m_lineShader.Init(); - m_pointShader.Init(); } void VertexManager::DestroyDeviceObjects() { - m_pointShader.Shutdown(); - m_lineShader.Shutdown(); - for (int i = 0; i < MAX_BUFFER_COUNT; i++) { SAFE_RELEASE(m_buffers[i]); @@ -122,10 +115,6 @@ void VertexManager::PrepareDrawBuffers(u32 stride) ADDSTAT(stats.thisFrame.bytesIndexStreamed, indexBufferSize); } -static const float LINE_PT_TEX_OFFSETS[8] = { - 0.f, 0.0625f, 0.125f, 0.25f, 0.5f, 1.f, 1.f, 1.f -}; - void VertexManager::Draw(u32 stride) { u32 components = VertexLoaderManager::GetCurrentVertexFormat()->m_components; @@ -137,69 +126,28 @@ void VertexManager::Draw(u32 stride) u32 baseVertex = m_vertexDrawOffset / stride; u32 startIndex = m_indexDrawOffset / sizeof(u16); - if (current_primitive_type == PRIMITIVE_TRIANGLES) + switch (current_primitive_type) { - D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - D3D::stateman->SetGeometryConstants(VertexShaderCache::GetConstantBuffer()); - D3D::stateman->SetGeometryShader(g_ActiveConfig.iStereoMode > 0 ? GeometryShaderCache::GetActiveShader() : nullptr); - - D3D::stateman->Apply(); - D3D::context->DrawIndexed(indices, startIndex, baseVertex); - - INCSTAT(stats.thisFrame.numDrawCalls); - - D3D::stateman->SetGeometryShader(nullptr); - } - else if (current_primitive_type == PRIMITIVE_LINES) - { - float lineWidth = float(bpmem.lineptwidth.linesize) / 6.f; - float texOffset = LINE_PT_TEX_OFFSETS[bpmem.lineptwidth.lineoff]; - float vpWidth = 2.0f * xfmem.viewport.wd; - float vpHeight = -2.0f * xfmem.viewport.ht; - - bool texOffsetEnable[8]; - - for (int i = 0; i < 8; ++i) - texOffsetEnable[i] = bpmem.texcoords[i].s.line_offset; - - if (m_lineShader.SetShader(components, lineWidth, - texOffset, vpWidth, vpHeight, texOffsetEnable)) - { - D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST); - - D3D::stateman->Apply(); - D3D::context->DrawIndexed(indices, startIndex, baseVertex); - - INCSTAT(stats.thisFrame.numDrawCalls); - - D3D::stateman->SetGeometryShader(nullptr); - } - } - else //if (current_primitive_type == PRIMITIVE_POINTS) - { - float pointSize = float(bpmem.lineptwidth.pointsize) / 6.f; - float texOffset = LINE_PT_TEX_OFFSETS[bpmem.lineptwidth.pointoff]; - float vpWidth = 2.0f * xfmem.viewport.wd; - float vpHeight = -2.0f * xfmem.viewport.ht; - - bool texOffsetEnable[8]; - - for (int i = 0; i < 8; ++i) - texOffsetEnable[i] = bpmem.texcoords[i].s.point_offset; - - if (m_pointShader.SetShader(components, pointSize, - texOffset, vpWidth, vpHeight, texOffsetEnable)) - { + case PRIMITIVE_POINTS: D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST); - - D3D::stateman->Apply(); - D3D::context->DrawIndexed(indices, startIndex, baseVertex); - - INCSTAT(stats.thisFrame.numDrawCalls); - - D3D::stateman->SetGeometryShader(nullptr); - } + ((DX11::Renderer*)g_renderer)->ApplyCullDisable(); + break; + case PRIMITIVE_LINES: + D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST); + ((DX11::Renderer*)g_renderer)->ApplyCullDisable(); + break; + case PRIMITIVE_TRIANGLES: + D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + break; } + + D3D::stateman->Apply(); + D3D::context->DrawIndexed(indices, startIndex, baseVertex); + + INCSTAT(stats.thisFrame.numDrawCalls); + + if (current_primitive_type != PRIMITIVE_TRIANGLES) + ((DX11::Renderer*)g_renderer)->RestoreCull(); } void VertexManager::vFlush(bool useDstAlpha) @@ -219,13 +167,10 @@ void VertexManager::vFlush(bool useDstAlpha) return; } - if (g_ActiveConfig.iStereoMode > 0) + if (!GeometryShaderCache::SetShader(current_primitive_type)) { - if (!GeometryShaderCache::SetShader(components)) - { - GFX_DEBUGGER_PAUSE_LOG_AT(NEXT_ERROR, true, { printf("Fail to set pixel shader\n"); }); - return; - } + GFX_DEBUGGER_PAUSE_LOG_AT(NEXT_ERROR, true, { printf("Fail to set pixel shader\n"); }); + return; } if (g_ActiveConfig.backend_info.bSupportsBBox && BoundingBox::active) diff --git a/Source/Core/VideoBackends/D3D/VertexManager.h b/Source/Core/VideoBackends/D3D/VertexManager.h index bd84128ff1..0b124d7512 100644 --- a/Source/Core/VideoBackends/D3D/VertexManager.h +++ b/Source/Core/VideoBackends/D3D/VertexManager.h @@ -4,8 +4,6 @@ #pragma once -#include "VideoBackends/D3D/LineGeometryShader.h" -#include "VideoBackends/D3D/PointGeometryShader.h" #include "VideoCommon/VertexManagerBase.h" namespace DX11 @@ -40,9 +38,6 @@ private: enum { MAX_BUFFER_COUNT = 2 }; ID3D11Buffer* m_buffers[MAX_BUFFER_COUNT]; - LineGeometryShader m_lineShader; - PointGeometryShader m_pointShader; - std::vector LocalVBuffer; std::vector LocalIBuffer; }; diff --git a/Source/Core/VideoBackends/D3D/VertexShaderCache.cpp b/Source/Core/VideoBackends/D3D/VertexShaderCache.cpp index 9dfd87691e..54c103c36f 100644 --- a/Source/Core/VideoBackends/D3D/VertexShaderCache.cpp +++ b/Source/Core/VideoBackends/D3D/VertexShaderCache.cpp @@ -115,7 +115,7 @@ void VertexShaderCache::Init() { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, }; - unsigned int cbsize = ((sizeof(VertexShaderConstants))&(~0xf))+0x10; // must be a multiple of 16 + unsigned int cbsize = ROUND_UP(sizeof(VertexShaderConstants), 16); // must be a multiple of 16 D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(cbsize, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); HRESULT hr = D3D::device->CreateBuffer(&cbdesc, nullptr, &vscbuf); CHECK(hr==S_OK, "Create vertex shader constant buffer (size=%u)", cbsize); diff --git a/Source/Core/VideoBackends/D3D/XFBEncoder.cpp b/Source/Core/VideoBackends/D3D/XFBEncoder.cpp index fb56363e31..955fb38bc8 100644 --- a/Source/Core/VideoBackends/D3D/XFBEncoder.cpp +++ b/Source/Core/VideoBackends/D3D/XFBEncoder.cpp @@ -282,6 +282,7 @@ void XFBEncoder::Encode(u8* dst, u32 width, u32 height, const EFBRectangle& srcR D3D::stateman->SetPixelShader(m_pShader); D3D::stateman->SetVertexShader(m_vShader); + D3D::stateman->SetGeometryShader(nullptr); D3D::stateman->PushBlendState(m_xfbEncodeBlendState); D3D::stateman->PushDepthState(m_xfbEncodeDepthState); diff --git a/Source/Core/VideoBackends/D3D/main.cpp b/Source/Core/VideoBackends/D3D/main.cpp index 22782cc41c..6652d6bc57 100644 --- a/Source/Core/VideoBackends/D3D/main.cpp +++ b/Source/Core/VideoBackends/D3D/main.cpp @@ -28,6 +28,7 @@ #include "VideoCommon/BPStructs.h" #include "VideoCommon/CommandProcessor.h" #include "VideoCommon/Fifo.h" +#include "VideoCommon/GeometryShaderManager.h" #include "VideoCommon/IndexGenerator.h" #include "VideoCommon/OnScreenDisplay.h" #include "VideoCommon/OpcodeDecoding.h" @@ -79,7 +80,7 @@ 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 = true; + g_Config.backend_info.bSupportsGeometryShaders = true; g_Config.backend_info.bSupports3DVision = true; IDXGIFactory* factory; @@ -187,6 +188,7 @@ void VideoBackend::Video_Prepare() OpcodeDecoder_Init(); VertexShaderManager::Init(); PixelShaderManager::Init(); + GeometryShaderManager::Init(); CommandProcessor::Init(); PixelEngine::Init(); BBox::Init(); @@ -205,6 +207,7 @@ void VideoBackend::Shutdown() // VideoCommon Fifo_Shutdown(); CommandProcessor::Shutdown(); + GeometryShaderManager::Shutdown(); PixelShaderManager::Shutdown(); VertexShaderManager::Shutdown(); OpcodeDecoder_Shutdown(); diff --git a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp index 439c4c9040..14f5f94c82 100644 --- a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp +++ b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp @@ -13,6 +13,7 @@ #include "VideoCommon/Debugger.h" #include "VideoCommon/DriverDetails.h" +#include "VideoCommon/GeometryShaderManager.h" #include "VideoCommon/ImageWrite.h" #include "VideoCommon/PixelShaderManager.h" #include "VideoCommon/Statistics.h" @@ -71,11 +72,14 @@ void SHADER::SetProgramVariables() GLint PSBlock_id = glGetUniformBlockIndex(glprogid, "PSBlock"); GLint VSBlock_id = glGetUniformBlockIndex(glprogid, "VSBlock"); + GLint GSBlock_id = glGetUniformBlockIndex(glprogid, "GSBlock"); if (PSBlock_id != -1) glUniformBlockBinding(glprogid, PSBlock_id, 1); if (VSBlock_id != -1) glUniformBlockBinding(glprogid, VSBlock_id, 2); + if (GSBlock_id != -1) + glUniformBlockBinding(glprogid, GSBlock_id, 3); // Bind Texture Sampler for (int a = 0; a <= 9; ++a) @@ -133,7 +137,7 @@ void SHADER::Bind() void ProgramShaderCache::UploadConstants() { - if (PixelShaderManager::dirty || VertexShaderManager::dirty) + if (PixelShaderManager::dirty || VertexShaderManager::dirty || GeometryShaderManager::dirty) { auto buffer = s_buffer->Map(s_ubo_buffer_size, s_ubo_align); @@ -143,14 +147,20 @@ void ProgramShaderCache::UploadConstants() memcpy(buffer.first + ROUND_UP(sizeof(PixelShaderConstants), s_ubo_align), &VertexShaderManager::constants, sizeof(VertexShaderConstants)); + memcpy(buffer.first + ROUND_UP(sizeof(PixelShaderConstants), s_ubo_align) + ROUND_UP(sizeof(VertexShaderConstants), s_ubo_align), + &GeometryShaderManager::constants, sizeof(GeometryShaderConstants)); + s_buffer->Unmap(s_ubo_buffer_size); glBindBufferRange(GL_UNIFORM_BUFFER, 1, s_buffer->m_buffer, buffer.second, sizeof(PixelShaderConstants)); glBindBufferRange(GL_UNIFORM_BUFFER, 2, s_buffer->m_buffer, buffer.second + ROUND_UP(sizeof(PixelShaderConstants), s_ubo_align), sizeof(VertexShaderConstants)); + glBindBufferRange(GL_UNIFORM_BUFFER, 3, s_buffer->m_buffer, buffer.second + ROUND_UP(sizeof(PixelShaderConstants), s_ubo_align) + ROUND_UP(sizeof(VertexShaderConstants), s_ubo_align), + sizeof(GeometryShaderConstants)); PixelShaderManager::dirty = false; VertexShaderManager::dirty = false; + GeometryShaderManager::dirty = false; ADDSTAT(stats.thisFrame.bytesUniformStreamed, s_ubo_buffer_size); } @@ -161,10 +171,10 @@ GLuint ProgramShaderCache::GetCurrentProgram() return CurrentProgram; } -SHADER* ProgramShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components) +SHADER* ProgramShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components, u32 primitive_type) { SHADERUID uid; - GetShaderId(&uid, dstAlphaMode, components); + GetShaderId(&uid, dstAlphaMode, components, primitive_type); // Check if the shader is already set if (last_entry) @@ -201,8 +211,8 @@ SHADER* ProgramShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components ShaderCode gcode; GenerateVertexShaderCode(vcode, components, API_OPENGL); GeneratePixelShaderCode(pcode, dstAlphaMode, API_OPENGL, components); - if (g_ActiveConfig.iStereoMode > 0) - GenerateGeometryShaderCode(gcode, components, API_OPENGL); + if (g_ActiveConfig.backend_info.bSupportsGeometryShaders && !IsPassthroughGeometryShader(uid.guid)) + GenerateGeometryShaderCode(gcode, primitive_type, API_OPENGL); if (g_ActiveConfig.bEnableShaderDebugging) { @@ -385,11 +395,11 @@ GLuint ProgramShaderCache::CompileSingleShader(GLuint type, const char* code) return result; } -void ProgramShaderCache::GetShaderId(SHADERUID* uid, DSTALPHA_MODE dstAlphaMode, u32 components) +void ProgramShaderCache::GetShaderId(SHADERUID* uid, DSTALPHA_MODE dstAlphaMode, u32 components, u32 primitive_type) { GetPixelShaderUid(uid->puid, dstAlphaMode, API_OPENGL, components); GetVertexShaderUid(uid->vuid, components, API_OPENGL); - GetGeometryShaderUid(uid->guid, components, API_OPENGL); + GetGeometryShaderUid(uid->guid, primitive_type, API_OPENGL); if (g_ActiveConfig.bEnableShaderDebugging) { @@ -402,7 +412,7 @@ void ProgramShaderCache::GetShaderId(SHADERUID* uid, DSTALPHA_MODE dstAlphaMode, vertex_uid_checker.AddToIndexAndCheck(vcode, uid->vuid, "Vertex", "v"); ShaderCode gcode; - GenerateGeometryShaderCode(gcode, components, API_OPENGL); + GenerateGeometryShaderCode(gcode, primitive_type, API_OPENGL); geometry_uid_checker.AddToIndexAndCheck(gcode, uid->guid, "Geometry", "g"); } } @@ -419,7 +429,7 @@ void ProgramShaderCache::Init() // then the UBO will fail. glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &s_ubo_align); - s_ubo_buffer_size = ROUND_UP(sizeof(PixelShaderConstants), s_ubo_align) + ROUND_UP(sizeof(VertexShaderConstants), s_ubo_align); + s_ubo_buffer_size = ROUND_UP(sizeof(PixelShaderConstants), s_ubo_align) + ROUND_UP(sizeof(VertexShaderConstants), s_ubo_align) + ROUND_UP(sizeof(GeometryShaderConstants), s_ubo_align); // We multiply by *4*4 because we need to get down to basic machine units. // So multiply by four to get how many floats we have from vec4s diff --git a/Source/Core/VideoBackends/OGL/ProgramShaderCache.h b/Source/Core/VideoBackends/OGL/ProgramShaderCache.h index d1e3a5ee54..65eeae2ca0 100644 --- a/Source/Core/VideoBackends/OGL/ProgramShaderCache.h +++ b/Source/Core/VideoBackends/OGL/ProgramShaderCache.h @@ -88,8 +88,8 @@ public: static PCacheEntry GetShaderProgram(); static GLuint GetCurrentProgram(); - static SHADER* SetShader(DSTALPHA_MODE dstAlphaMode, u32 components); - static void GetShaderId(SHADERUID *uid, DSTALPHA_MODE dstAlphaMode, u32 components); + static SHADER* SetShader(DSTALPHA_MODE dstAlphaMode, u32 components, u32 primitive_type); + static void GetShaderId(SHADERUID *uid, DSTALPHA_MODE dstAlphaMode, u32 components, u32 primitive_type); static bool CompileShader(SHADER &shader, const char* vcode, const char* pcode, const char* gcode = nullptr); static GLuint CompileSingleShader(GLuint type, const char *code); diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index 9ee86471ff..cc52c47e03 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -476,6 +476,7 @@ Renderer::Renderer() g_Config.backend_info.bSupportsEarlyZ = GLExtensions::Supports("GL_ARB_shader_image_load_store"); g_Config.backend_info.bSupportsBBox = GLExtensions::Supports("GL_ARB_shader_storage_buffer_object"); g_Config.backend_info.bSupportsGSInstancing = GLExtensions::Supports("GL_ARB_gpu_shader5"); + g_Config.backend_info.bSupportsGeometryShaders = (GLExtensions::Version() >= 320); // Desktop OpenGL supports the binding layout if it supports 420pack // OpenGL ES 3.1 supports it implicitly without an extension @@ -498,7 +499,7 @@ Renderer::Renderer() { g_ogl_config.eSupportedGLSLVersion = GLSLES_300; g_ogl_config.bSupportsAEP = false; - g_Config.backend_info.bSupportsStereoscopy = false; + g_Config.backend_info.bSupportsGeometryShaders = false; } else { @@ -506,7 +507,7 @@ Renderer::Renderer() g_ogl_config.bSupportsAEP = GLExtensions::Supports("GL_ANDROID_extension_pack_es31a"); g_Config.backend_info.bSupportsBindingLayout = true; g_Config.backend_info.bSupportsEarlyZ = true; - g_Config.backend_info.bSupportsStereoscopy = g_ogl_config.bSupportsAEP; + g_Config.backend_info.bSupportsGeometryShaders = g_ogl_config.bSupportsAEP; } } else @@ -522,13 +523,13 @@ Renderer::Renderer() { g_ogl_config.eSupportedGLSLVersion = GLSL_130; g_Config.backend_info.bSupportsEarlyZ = false; // layout keyword is only supported on glsl150+ - g_Config.backend_info.bSupportsStereoscopy = false; // geometry shaders are only supported on glsl150+ + g_Config.backend_info.bSupportsGeometryShaders = false; // geometry shaders are only supported on glsl150+ } else if (strstr(g_ogl_config.glsl_version, "1.40")) { g_ogl_config.eSupportedGLSLVersion = GLSL_140; g_Config.backend_info.bSupportsEarlyZ = false; // layout keyword is only supported on glsl150+ - g_Config.backend_info.bSupportsStereoscopy = false; // geometry shaders are only supported on glsl150+ + g_Config.backend_info.bSupportsGeometryShaders = false; // geometry shaders are only supported on glsl150+ } else { @@ -565,7 +566,7 @@ Renderer::Renderer() bSuccess = false; } - if (g_Config.iStereoMode > 0 && !g_Config.backend_info.bSupportsStereoscopy) + if (g_Config.iStereoMode > 0 && !g_Config.backend_info.bSupportsGeometryShaders) OSD::AddMessage("Stereoscopic 3D isn't supported by your GPU, support for OpenGL 3.2 is required.", 10000); if (!bSuccess) @@ -881,9 +882,6 @@ void Renderer::DrawDebugInfo() GLsizei count = static_cast(stats.efb_regions.size() * 2*6); glDrawArrays(GL_LINES, 0, count); - // Restore Line Size - SetLineWidth(); - // Clear stored regions stats.efb_regions.clear(); } @@ -1901,17 +1899,6 @@ void Renderer::SetDitherMode() glDisable(GL_DITHER); } -void Renderer::SetLineWidth() -{ - float fratio = xfmem.viewport.wd != 0 ? - ((float)Renderer::GetTargetWidth() / EFB_WIDTH) : 1.0f; - if (bpmem.lineptwidth.linesize > 0) - // scale by ratio of widths - glLineWidth((float)bpmem.lineptwidth.linesize * fratio / 6.0f); - if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL && bpmem.lineptwidth.pointsize > 0) - glPointSize((float)bpmem.lineptwidth.pointsize * fratio / 6.0f); -} - void Renderer::SetSamplerState(int stage, int texindex) { auto const& tex = bpmem.tex[texindex]; diff --git a/Source/Core/VideoBackends/OGL/Render.h b/Source/Core/VideoBackends/OGL/Render.h index 98bd424257..db843179a9 100644 --- a/Source/Core/VideoBackends/OGL/Render.h +++ b/Source/Core/VideoBackends/OGL/Render.h @@ -57,7 +57,6 @@ public: void SetDepthMode() override; void SetLogicOpMode() override; void SetDitherMode() override; - void SetLineWidth() override; void SetSamplerState(int stage,int texindex) override; void SetInterlacingMode() override; void SetViewport() override; diff --git a/Source/Core/VideoBackends/OGL/VertexManager.cpp b/Source/Core/VideoBackends/OGL/VertexManager.cpp index e696aca536..1a162b1cde 100644 --- a/Source/Core/VideoBackends/OGL/VertexManager.cpp +++ b/Source/Core/VideoBackends/OGL/VertexManager.cpp @@ -101,9 +101,11 @@ void VertexManager::Draw(u32 stride) { case PRIMITIVE_POINTS: primitive_mode = GL_POINTS; + glDisable(GL_CULL_FACE); break; case PRIMITIVE_LINES: primitive_mode = GL_LINES; + glDisable(GL_CULL_FACE); break; case PRIMITIVE_TRIANGLES: primitive_mode = g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? GL_TRIANGLE_STRIP : GL_TRIANGLES; @@ -120,6 +122,9 @@ void VertexManager::Draw(u32 stride) } INCSTAT(stats.thisFrame.numDrawCalls); + + if (current_primitive_type != PRIMITIVE_TRIANGLES) + ((OGL::Renderer*)g_renderer)->SetGenerationMode(); } void VertexManager::vFlush(bool useDstAlpha) @@ -142,11 +147,11 @@ void VertexManager::vFlush(bool useDstAlpha) // the same pass as regular rendering. if (useDstAlpha && dualSourcePossible) { - ProgramShaderCache::SetShader(DSTALPHA_DUAL_SOURCE_BLEND, nativeVertexFmt->m_components); + ProgramShaderCache::SetShader(DSTALPHA_DUAL_SOURCE_BLEND, nativeVertexFmt->m_components, current_primitive_type); } else { - ProgramShaderCache::SetShader(DSTALPHA_NONE, nativeVertexFmt->m_components); + ProgramShaderCache::SetShader(DSTALPHA_NONE, nativeVertexFmt->m_components, current_primitive_type); } // upload global constants @@ -160,7 +165,7 @@ void VertexManager::vFlush(bool useDstAlpha) // run through vertex groups again to set alpha if (useDstAlpha && !dualSourcePossible) { - ProgramShaderCache::SetShader(DSTALPHA_ALPHA_PASS, nativeVertexFmt->m_components); + ProgramShaderCache::SetShader(DSTALPHA_ALPHA_PASS, nativeVertexFmt->m_components, current_primitive_type); // only update alpha glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); diff --git a/Source/Core/VideoBackends/OGL/main.cpp b/Source/Core/VideoBackends/OGL/main.cpp index eb486c811b..c4c966458e 100644 --- a/Source/Core/VideoBackends/OGL/main.cpp +++ b/Source/Core/VideoBackends/OGL/main.cpp @@ -65,6 +65,7 @@ Make AA apply instantly during gameplay if possible #include "VideoCommon/BPStructs.h" #include "VideoCommon/CommandProcessor.h" #include "VideoCommon/Fifo.h" +#include "VideoCommon/GeometryShaderManager.h" #include "VideoCommon/ImageWrite.h" #include "VideoCommon/IndexGenerator.h" #include "VideoCommon/LookUpTables.h" @@ -138,7 +139,7 @@ static void InitBackendInfo() //g_Config.backend_info.bSupportsDualSourceBlend = true; // is gpu dependent and must be set in renderer //g_Config.backend_info.bSupportsEarlyZ = true; // is gpu dependent and must be set in renderer g_Config.backend_info.bSupportsOversizedViewports = true; - g_Config.backend_info.bSupportsStereoscopy = true; + g_Config.backend_info.bSupportsGeometryShaders = true; g_Config.backend_info.bSupports3DVision = false; g_Config.backend_info.Adapters.clear(); @@ -202,6 +203,7 @@ void VideoBackend::Video_Prepare() IndexGenerator::Init(); VertexShaderManager::Init(); PixelShaderManager::Init(); + GeometryShaderManager::Init(); ProgramShaderCache::Init(); g_texture_cache = new TextureCache(); g_sampler_cache = new SamplerCache(); @@ -243,6 +245,7 @@ void VideoBackend::Video_Cleanup() ProgramShaderCache::Shutdown(); VertexShaderManager::Shutdown(); PixelShaderManager::Shutdown(); + GeometryShaderManager::Shutdown(); delete g_perf_query; g_perf_query = nullptr; delete g_vertex_manager; diff --git a/Source/Core/VideoCommon/BPFunctions.cpp b/Source/Core/VideoCommon/BPFunctions.cpp index 29a6d5b643..604840efdd 100644 --- a/Source/Core/VideoCommon/BPFunctions.cpp +++ b/Source/Core/VideoCommon/BPFunctions.cpp @@ -62,11 +62,6 @@ void SetScissor() g_renderer->SetScissorRect(rc); } -void SetLineWidth() -{ - g_renderer->SetLineWidth(); -} - void SetDepthMode() { g_renderer->SetDepthMode(); diff --git a/Source/Core/VideoCommon/BPFunctions.h b/Source/Core/VideoCommon/BPFunctions.h index ff7e928f8a..01f9bc9bbe 100644 --- a/Source/Core/VideoCommon/BPFunctions.h +++ b/Source/Core/VideoCommon/BPFunctions.h @@ -18,7 +18,6 @@ namespace BPFunctions void FlushPipeline(); void SetGenerationMode(); void SetScissor(); -void SetLineWidth(); void SetDepthMode(); void SetBlendMode(); void SetDitherMode(); diff --git a/Source/Core/VideoCommon/BPStructs.cpp b/Source/Core/VideoCommon/BPStructs.cpp index ec7854bace..6c4ad70331 100644 --- a/Source/Core/VideoCommon/BPStructs.cpp +++ b/Source/Core/VideoCommon/BPStructs.cpp @@ -14,6 +14,7 @@ #include "VideoCommon/BPFunctions.h" #include "VideoCommon/BPStructs.h" #include "VideoCommon/Fifo.h" +#include "VideoCommon/GeometryShaderManager.h" #include "VideoCommon/PerfQueryBase.h" #include "VideoCommon/PixelEngine.h" #include "VideoCommon/PixelShaderManager.h" @@ -125,9 +126,10 @@ static void BPWritten(const BPCmd& bp) case BPMEM_SCISSOROFFSET: // Scissor Offset SetScissor(); VertexShaderManager::SetViewportChanged(); + GeometryShaderManager::SetViewportChanged(); return; case BPMEM_LINEPTWIDTH: // Line Width - SetLineWidth(); + GeometryShaderManager::SetLinePtWidthChanged(); return; case BPMEM_ZMODE: // Depth Control PRIM_LOG("zmode: test=%d, func=%d, upd=%d", (int)bpmem.zmode.testenable, @@ -570,7 +572,10 @@ static void BPWritten(const BPCmd& bp) case BPMEM_SU_SSIZE+14: case BPMEM_SU_TSIZE+14: if (bp.changes) + { PixelShaderManager::SetTexCoordChanged((bp.address - BPMEM_SU_SSIZE) >> 1); + GeometryShaderManager::SetTexCoordChanged((bp.address - BPMEM_SU_SSIZE) >> 1); + } return; // ------------------------ // BPMEM_TX_SETMODE0 - (Texture lookup and filtering mode) LOD/BIAS Clamp, MaxAnsio, LODBIAS, DiagLoad, Min Filter, Mag Filter, Wrap T, S @@ -1366,7 +1371,6 @@ void BPReload() // note that PixelShaderManager is already covered since it has its own DoState. SetGenerationMode(); SetScissor(); - SetLineWidth(); SetDepthMode(); SetLogicOpMode(); SetDitherMode(); diff --git a/Source/Core/VideoCommon/CMakeLists.txt b/Source/Core/VideoCommon/CMakeLists.txt index 0dfd12b732..95ebaf7433 100644 --- a/Source/Core/VideoCommon/CMakeLists.txt +++ b/Source/Core/VideoCommon/CMakeLists.txt @@ -10,6 +10,7 @@ set(SRCS BoundingBox.cpp FPSCounter.cpp FramebufferManagerBase.cpp GeometryShaderGen.cpp + GeometryShaderManager.cpp HiresTextures.cpp ImageWrite.cpp IndexGenerator.cpp diff --git a/Source/Core/VideoCommon/ConstantManager.h b/Source/Core/VideoCommon/ConstantManager.h index 93c228bc98..9bfce8aac1 100644 --- a/Source/Core/VideoCommon/ConstantManager.h +++ b/Source/Core/VideoCommon/ConstantManager.h @@ -43,6 +43,11 @@ struct VertexShaderConstants float4 normalmatrices[32]; float4 posttransformmatrices[64]; float4 pixelcentercorrection; - float4 stereoparams; }; +struct GeometryShaderConstants +{ + float4 stereoparams; + float4 lineptparams; + int4 texoffset; +}; diff --git a/Source/Core/VideoCommon/GeometryShaderGen.cpp b/Source/Core/VideoCommon/GeometryShaderGen.cpp index 57009aedaa..cabdfea191 100644 --- a/Source/Core/VideoCommon/GeometryShaderGen.cpp +++ b/Source/Core/VideoCommon/GeometryShaderGen.cpp @@ -4,15 +4,33 @@ #include +#include "VideoCommon/BPMemory.h" #include "VideoCommon/GeometryShaderGen.h" #include "VideoCommon/LightingShaderGen.h" +#include "VideoCommon/VertexManagerBase.h" #include "VideoCommon/VertexShaderGen.h" #include "VideoCommon/VideoConfig.h" static char text[16384]; +static const char* primitives_ogl[] = +{ + "points", + "lines", + "triangles" +}; + +static const char* primitives_d3d[] = +{ + "point", + "line", + "triangle" +}; + +template static inline void EmitVertex(T& out, const char* vertex, API_TYPE ApiType); + template -static inline void GenerateGeometryShader(T& out, u32 components, API_TYPE ApiType) +static inline void GenerateGeometryShader(T& out, u32 primitive_type, API_TYPE ApiType) { // Non-uid template parameters will write to the dummy data (=> gets optimized out) geometry_shader_uid_data dummy_data; @@ -26,93 +44,154 @@ static inline void GenerateGeometryShader(T& out, u32 components, API_TYPE ApiTy if (is_writing_shadercode) text[sizeof(text) - 1] = 0x7C; // canary - out.Write("//Geometry Shader for 3D stereoscopy\n"); + uid_data->primitive_type = primitive_type; + const unsigned int vertex_in = primitive_type + 1; + const unsigned int vertex_out = primitive_type == PRIMITIVE_TRIANGLES ? 3 : 4; 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); + { + out.Write("layout(%s, invocations = %d) in;\n", primitives_ogl[primitive_type], g_ActiveConfig.iStereoMode > 0 ? 2 : 1); + out.Write("layout(triangle_strip, max_vertices = %d) out;\n", vertex_out); + } 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("layout(%s) in;\n", primitives_ogl[primitive_type]); + out.Write("layout(triangle_strip, max_vertices = %d) out;\n", g_ActiveConfig.iStereoMode > 0 ? vertex_out * 2 : vertex_out); + } } 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" : ""); + out.Write("layout(std140%s) uniform GSBlock {\n", g_ActiveConfig.backend_info.bSupportsBindingLayout ? ", binding = 3" : ""); else - out.Write("cbuffer VSBlock {\n"); - out.Write(s_shader_uniforms); - out.Write("};\n"); + out.Write("cbuffer GSBlock {\n"); + out.Write( + "\tfloat4 " I_STEREOPARAMS";\n" + "\tfloat4 " I_LINEPTPARAMS";\n" + "\tint4 " I_TEXOFFSET";\n" + "};\n"); - uid_data->numTexGens = xfmem.numTexGen.numTexGens; + uid_data->numTexGens = bpmem.genMode.numtexgens; uid_data->pixel_lighting = g_ActiveConfig.bEnablePixelLighting; GenerateVSOutputStruct(out, ApiType); if (ApiType == API_OPENGL) { - out.Write("centroid in VS_OUTPUT o[3];\n"); - out.Write("centroid out VS_OUTPUT vs;\n"); - out.Write("flat out int layer;\n"); + if (g_ActiveConfig.backend_info.bSupportsGSInstancing) + out.Write("#define InstanceID gl_InvocationID\n"); + + out.Write("in VertexData {\n"); + out.Write("\tcentroid VS_OUTPUT o;\n"); + out.Write("} vs[%d];\n", vertex_in); + + out.Write("out VertexData {\n"); + out.Write("\tcentroid VS_OUTPUT o;\n"); + + if (g_ActiveConfig.iStereoMode > 0) + out.Write("\tflat int layer;\n"); + + out.Write("} ps;\n"); out.Write("void main()\n{\n"); } else // D3D { - out.Write("struct GS_OUTPUT {\n"); - out.Write("\tVS_OUTPUT vs;\n"); - out.Write("\tuint layer : SV_RenderTargetArrayIndex;\n"); + out.Write("struct VertexData {\n"); + out.Write("\tVS_OUTPUT o;\n"); + + if (g_ActiveConfig.iStereoMode > 0) + out.Write("\tuint layer : SV_RenderTargetArrayIndex;\n"); + out.Write("};\n"); if (g_ActiveConfig.backend_info.bSupportsGSInstancing) { - out.Write("[maxvertexcount(3)]\n[instance(%d)]\n", g_ActiveConfig.iStereoMode > 0 ? 2 : 1); - out.Write("void main(triangle VS_OUTPUT o[3], inout TriangleStream Output, in uint InstanceID : SV_GSInstanceID)\n{\n"); + out.Write("[maxvertexcount(%d)]\n[instance(%d)]\n", vertex_out, g_ActiveConfig.iStereoMode > 0 ? 2 : 1); + out.Write("void main(%s VS_OUTPUT o[%d], inout TriangleStream output, in uint InstanceID : SV_GSInstanceID)\n{\n", primitives_d3d[primitive_type], vertex_in); } else { - out.Write("[maxvertexcount(6)]\n"); - out.Write("void main(triangle VS_OUTPUT o[3], inout TriangleStream Output)\n{\n"); + out.Write("[maxvertexcount(%d)]\n", g_ActiveConfig.iStereoMode > 0 ? vertex_out * 2 : vertex_out); + out.Write("void main(%s VS_OUTPUT o[%d], inout TriangleStream output)\n{\n", primitives_d3d[primitive_type], vertex_in); } - out.Write("\tGS_OUTPUT gs;\n"); + out.Write("\tVertexData ps;\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. - if (g_ActiveConfig.backend_info.bSupportsGSInstancing) + if (primitive_type == PRIMITIVE_LINES) { if (ApiType == API_OPENGL) - out.Write("\tint eye = gl_InvocationID;\n"); + { + out.Write("\tVS_OUTPUT start = vs[0].o;\n"); + out.Write("\tVS_OUTPUT end = vs[1].o;\n"); + } else - out.Write("\tint eye = InstanceID;\n"); + { + out.Write("\tVS_OUTPUT start = o[0];\n"); + out.Write("\tVS_OUTPUT end = o[1];\n"); + } + + // GameCube/Wii's line drawing algorithm is a little quirky. It does not + // use the correct line caps. Instead, the line caps are vertical or + // horizontal depending the slope of the line. + out.Write( + "\tfloat2 offset;\n" + "\tfloat2 to = abs(end.pos.xy - start.pos.xy);\n" + // FIXME: What does real hardware do when line is at a 45-degree angle? + // FIXME: Lines aren't drawn at the correct width. See Twilight Princess map. + "\tif (" I_LINEPTPARAMS".y * to.y > " I_LINEPTPARAMS".x * to.x) {\n" + // Line is more tall. Extend geometry left and right. + // Lerp LineWidth/2 from [0..VpWidth] to [-1..1] + "\t\toffset = float2(" I_LINEPTPARAMS".z / " I_LINEPTPARAMS".x, 0);\n" + "\t} else {\n" + // Line is more wide. Extend geometry up and down. + // Lerp LineWidth/2 from [0..VpHeight] to [1..-1] + "\t\toffset = float2(0, -" I_LINEPTPARAMS".z / " I_LINEPTPARAMS".y);\n" + "\t}\n"); } - else - out.Write("\tfor (int eye = 0; eye < %d; ++eye) {\n", g_ActiveConfig.iStereoMode > 0 ? 2 : 1); - - out.Write("\tfor (int i = 0; i < 3; ++i) {\n"); - - // Select the output layer - if (ApiType == API_OPENGL) + else if (primitive_type == PRIMITIVE_POINTS) { - out.Write("\t\tgl_Layer = eye;\n"); - out.Write("\t\tlayer = eye;\n"); - } - else - out.Write("\t\tgs.layer = eye;\n"); + if (ApiType == API_OPENGL) + out.Write("\tVS_OUTPUT center = vs[0].o;\n"); + else + out.Write("\tVS_OUTPUT center = o[0];\n"); - out.Write("\t\tf = o[i];\n"); - out.Write("\t\tfloat4 pos = o[i].pos;\n"); + // Offset from center to upper right vertex + // Lerp PointSize/2 from [0,0..VpWidth,VpHeight] to [-1,1..1,-1] + out.Write("\tfloat2 offset = float2(" I_LINEPTPARAMS".w / " I_LINEPTPARAMS".x, -" I_LINEPTPARAMS".w / " I_LINEPTPARAMS".y) * center.pos.w;\n"); + } if (g_ActiveConfig.iStereoMode > 0) { + // 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 eye = InstanceID;\n"); + else + out.Write("\tfor (int eye = 0; eye < 2; ++eye) {\n"); + } + + out.Write("\tfor (int i = 0; i < %d; ++i) {\n", vertex_in); + + if (ApiType == API_OPENGL) + out.Write("\tVS_OUTPUT f = vs[i].o;\n"); + else + out.Write("\tVS_OUTPUT f = o[i];\n"); + + if (g_ActiveConfig.iStereoMode > 0) + { + // Select the output layer + out.Write("\tps.layer = eye;\n"); + if (ApiType == API_OPENGL) + out.Write("\tgl_Layer = eye;\n"); + // 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. @@ -120,30 +199,74 @@ static inline void GenerateGeometryShader(T& out, u32 components, API_TYPE ApiTy // 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"[eye] * (o[i].clipPos.w - " I_STEREOPARAMS"[2]);\n"); - out.Write("\t\tpos.x = o[i].pos.x + " I_STEREOPARAMS"[eye] * (o[i].pos.w - " I_STEREOPARAMS"[2]);\n"); + out.Write("\tf.clipPos.x += " I_STEREOPARAMS"[eye] * (f.clipPos.w - " I_STEREOPARAMS"[2]);\n"); + out.Write("\tf.pos.x += " I_STEREOPARAMS"[eye] * (f.pos.w - " I_STEREOPARAMS"[2]);\n"); } - out.Write("\t\tf.pos.x = pos.x;\n"); + if (primitive_type == PRIMITIVE_LINES) + { + out.Write("\tVS_OUTPUT l = f;\n" + "\tVS_OUTPUT r = f;\n"); - if (ApiType == API_OPENGL) - out.Write("\t\tgl_Position = pos;\n"); + out.Write("\tl.pos.xy -= offset * l.pos.w;\n" + "\tr.pos.xy += offset * r.pos.w;\n"); - out.Write("\t\t%s = f;\n", (ApiType == API_OPENGL) ? "vs" : "gs.vs"); + out.Write("\tif (" I_TEXOFFSET"[2] != 0) {\n"); + out.Write("\tfloat texOffset = 1.0 / float(" I_TEXOFFSET"[2]);\n"); - if (ApiType == API_OPENGL) - out.Write("\t\tEmitVertex();\n"); + for (unsigned int i = 0; i < bpmem.genMode.numtexgens; ++i) + { + out.Write("\tif (((" I_TEXOFFSET"[0] >> %d) & 0x1) != 0)\n", i); + out.Write("\t\tr.tex%d.x += texOffset;\n", i); + } + out.Write("\t}\n"); + + EmitVertex(out, "l", ApiType); + EmitVertex(out, "r", ApiType); + } + else if (primitive_type == PRIMITIVE_POINTS) + { + out.Write("\tVS_OUTPUT ll = f;\n" + "\tVS_OUTPUT lr = f;\n" + "\tVS_OUTPUT ul = f;\n" + "\tVS_OUTPUT ur = f;\n"); + + out.Write("\tll.pos.xy += float2(-1,-1) * offset;\n" + "\tlr.pos.xy += float2(1,-1) * offset;\n" + "\tul.pos.xy += float2(-1,1) * offset;\n" + "\tur.pos.xy += offset;\n"); + + out.Write("\tif (" I_TEXOFFSET"[3] != 0) {\n"); + out.Write("\tfloat2 texOffset = float2(1.0 / float(" I_TEXOFFSET"[3]), 1.0 / float(" I_TEXOFFSET"[3]));\n"); + + for (unsigned int i = 0; i < bpmem.genMode.numtexgens; ++i) + { + out.Write("\tif (((" I_TEXOFFSET"[1] >> %d) & 0x1) != 0) {\n", i); + out.Write("\t\tll.tex%d.xy += float2(0,1) * texOffset;\n", i); + out.Write("\t\tlr.tex%d.xy += texOffset;\n", i); + out.Write("\t\tur.tex%d.xy += float2(1,0) * texOffset;\n", i); + out.Write("\t}\n"); + } + out.Write("\t}\n"); + + EmitVertex(out, "ll", ApiType); + EmitVertex(out, "lr", ApiType); + EmitVertex(out, "ul", ApiType); + EmitVertex(out, "ur", ApiType); + } else - out.Write("\t\tOutput.Append(gs);\n"); + { + EmitVertex(out, "f", ApiType); + } out.Write("\t}\n"); if (ApiType == API_OPENGL) out.Write("\tEndPrimitive();\n"); else - out.Write("\tOutput.RestartStrip();\n"); + out.Write("\toutput.RestartStrip();\n"); - if (!g_ActiveConfig.backend_info.bSupportsGSInstancing) + if (g_ActiveConfig.iStereoMode > 0 && !g_ActiveConfig.backend_info.bSupportsGSInstancing) out.Write("\t}\n"); out.Write("}\n"); @@ -155,12 +278,32 @@ static inline void GenerateGeometryShader(T& out, u32 components, API_TYPE ApiTy } } -void GetGeometryShaderUid(GeometryShaderUid& object, u32 components, API_TYPE ApiType) +template +static inline void EmitVertex(T& out, const char* vertex, API_TYPE ApiType) { - GenerateGeometryShader(object, components, ApiType); + if (ApiType == API_OPENGL) + out.Write("\tgl_Position = %s.pos;\n", vertex); + + out.Write("\tps.o = %s;\n", vertex); + + if (ApiType == API_OPENGL) + out.Write("\tEmitVertex();\n"); + else + out.Write("\toutput.Append(ps);\n"); } -void GenerateGeometryShaderCode(ShaderCode& object, u32 components, API_TYPE ApiType) +void GetGeometryShaderUid(GeometryShaderUid& object, u32 primitive_type, API_TYPE ApiType) { - GenerateGeometryShader(object, components, ApiType); + GenerateGeometryShader(object, primitive_type, ApiType); +} + +void GenerateGeometryShaderCode(ShaderCode& object, u32 primitive_type, API_TYPE ApiType) +{ + GenerateGeometryShader(object, primitive_type, ApiType); +} + +bool IsPassthroughGeometryShader(GeometryShaderUid& object) +{ + geometry_shader_uid_data* uid_data = object.GetUidData(); + return uid_data->primitive_type == PRIMITIVE_TRIANGLES && !uid_data->stereo; } diff --git a/Source/Core/VideoCommon/GeometryShaderGen.h b/Source/Core/VideoCommon/GeometryShaderGen.h index 3f7dc5198b..0f66f7a4f9 100644 --- a/Source/Core/VideoCommon/GeometryShaderGen.h +++ b/Source/Core/VideoCommon/GeometryShaderGen.h @@ -16,11 +16,13 @@ struct geometry_shader_uid_data u32 stereo : 1; u32 numTexGens : 4; u32 pixel_lighting : 1; + u32 primitive_type : 2; }; #pragma pack() typedef ShaderUid GeometryShaderUid; -void GenerateGeometryShaderCode(ShaderCode& object, u32 components, API_TYPE ApiType); -void GetGeometryShaderUid(GeometryShaderUid& object, u32 components, API_TYPE ApiType); +void GenerateGeometryShaderCode(ShaderCode& object, u32 primitive_type, API_TYPE ApiType); +void GetGeometryShaderUid(GeometryShaderUid& object, u32 primitive_type, API_TYPE ApiType); +bool IsPassthroughGeometryShader(GeometryShaderUid& object); diff --git a/Source/Core/VideoCommon/GeometryShaderManager.cpp b/Source/Core/VideoCommon/GeometryShaderManager.cpp new file mode 100644 index 0000000000..09adad56c0 --- /dev/null +++ b/Source/Core/VideoCommon/GeometryShaderManager.cpp @@ -0,0 +1,97 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include +#include + +#include "VideoCommon/BPMemory.h" +#include "VideoCommon/GeometryShaderGen.h" +#include "VideoCommon/GeometryShaderManager.h" +#include "VideoCommon/VideoCommon.h" +#include "VideoCommon/VideoConfig.h" +#include "VideoCommon/XFMemory.h" + +static const int LINE_PT_TEX_OFFSETS[8] = { + 0, 16, 8, 4, 2, 1, 1, 1 +}; + +GeometryShaderConstants GeometryShaderManager::constants; +bool GeometryShaderManager::dirty; + +void GeometryShaderManager::Init() +{ + memset(&constants, 0, sizeof(constants)); + + Dirty(); +} + +void GeometryShaderManager::Shutdown() +{ +} + +void GeometryShaderManager::Dirty() +{ + SetViewportChanged(); + SetProjectionChanged(); + SetLinePtWidthChanged(); + + for (int i = 0; i < 8; i++) + SetTexCoordChanged(i); + + dirty = true; +} + +void GeometryShaderManager::SetViewportChanged() +{ + constants.lineptparams[0] = 2.0f * xfmem.viewport.wd; + constants.lineptparams[1] = -2.0f * xfmem.viewport.ht; + dirty = true; +} + +void GeometryShaderManager::SetProjectionChanged() +{ + 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; +} + +void GeometryShaderManager::SetLinePtWidthChanged() +{ + constants.lineptparams[2] = bpmem.lineptwidth.linesize / 6.f; + constants.lineptparams[3] = bpmem.lineptwidth.pointsize / 6.f; + constants.texoffset[2] = LINE_PT_TEX_OFFSETS[bpmem.lineptwidth.lineoff]; + constants.texoffset[3] = LINE_PT_TEX_OFFSETS[bpmem.lineptwidth.pointoff]; + dirty = true; +} + +void GeometryShaderManager::SetTexCoordChanged(u8 texmapid) +{ + TCoordInfo& tc = bpmem.texcoords[texmapid]; + int bitmask = 1 << texmapid; + constants.texoffset[0] &= ~bitmask; + constants.texoffset[0] |= tc.s.line_offset << texmapid; + constants.texoffset[1] &= ~bitmask; + constants.texoffset[1] |= tc.s.point_offset << texmapid; + dirty = true; +} + +void GeometryShaderManager::DoState(PointerWrap &p) +{ + if (p.GetMode() == PointerWrap::MODE_READ) + { + // Reload current state from global GPU state + // NOTE: This requires that all GPU memory has been loaded already. + Dirty(); + } +} diff --git a/Source/Core/VideoCommon/GeometryShaderManager.h b/Source/Core/VideoCommon/GeometryShaderManager.h new file mode 100644 index 0000000000..eab036fd7e --- /dev/null +++ b/Source/Core/VideoCommon/GeometryShaderManager.h @@ -0,0 +1,28 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "VideoCommon/ConstantManager.h" +#include "VideoCommon/GeometryShaderGen.h" + +class PointerWrap; + +// The non-API dependent parts. +class GeometryShaderManager +{ +public: + static void Init(); + static void Dirty(); + static void Shutdown(); + static void DoState(PointerWrap &p); + + static void SetViewportChanged(); + static void SetProjectionChanged(); + static void SetLinePtWidthChanged(); + static void SetTexCoordChanged(u8 texmapid); + + static GeometryShaderConstants constants; + static bool dirty; +}; diff --git a/Source/Core/VideoCommon/PixelShaderGen.cpp b/Source/Core/VideoCommon/PixelShaderGen.cpp index 48cd5b8fec..77f24d115c 100644 --- a/Source/Core/VideoCommon/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/PixelShaderGen.cpp @@ -317,16 +317,20 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T // is always inside the primitive. // Without MSAA, this flag is defined to have no effect. uid_data->stereo = g_ActiveConfig.iStereoMode > 0; - if (g_ActiveConfig.iStereoMode > 0) + if (g_ActiveConfig.backend_info.bSupportsGeometryShaders) { - out.Write("centroid in VS_OUTPUT vs;\n"); - out.Write("flat in int layer;\n"); + out.Write("in VertexData {\n"); + out.Write("\tcentroid VS_OUTPUT o;\n"); + + if (g_ActiveConfig.iStereoMode > 0) + out.Write("\tflat int layer;\n"); + + out.Write("};\n"); } else { 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) @@ -342,25 +346,25 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T out.Write("void main()\n{\n"); - if (g_ActiveConfig.iStereoMode > 0) + if (g_ActiveConfig.backend_info.bSupportsGeometryShaders) { // 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 = vs.tex%d;\n", i, i); + out.Write("\tfloat3 uv%d = o.tex%d;\n", i, i); } - out.Write("\tfloat4 clipPos = vs.clipPos;\n"); + out.Write("\tfloat4 clipPos = o.clipPos;\n"); if (g_ActiveConfig.bEnablePixelLighting) { - out.Write("\tfloat4 Normal = vs.Normal;\n"); + out.Write("\tfloat4 Normal = o.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) ? "vs.colors_0" : "colors_02"); - out.Write("\tfloat4 colors_1 = %s;\n", (g_ActiveConfig.iStereoMode > 0) ? "vs.colors_1" : "colors_12"); + out.Write("\tfloat4 colors_0 = %s;\n", g_ActiveConfig.backend_info.bSupportsGeometryShaders ? "o.colors_0" : "colors_02"); + out.Write("\tfloat4 colors_1 = %s;\n", g_ActiveConfig.backend_info.bSupportsGeometryShaders ? "o.colors_1" : "colors_12"); out.Write("\tfloat4 rawpos = gl_FragCoord;\n"); } diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h index f59458e523..ef68d665a6 100644 --- a/Source/Core/VideoCommon/RenderBase.h +++ b/Source/Core/VideoCommon/RenderBase.h @@ -57,7 +57,6 @@ public: virtual void SetDepthMode() = 0; virtual void SetLogicOpMode() = 0; virtual void SetDitherMode() = 0; - virtual void SetLineWidth() = 0; virtual void SetSamplerState(int stage,int texindex) = 0; virtual void SetInterlacingMode() = 0; virtual void SetViewport() = 0; diff --git a/Source/Core/VideoCommon/ShaderGenCommon.h b/Source/Core/VideoCommon/ShaderGenCommon.h index 618d262374..444abad82c 100644 --- a/Source/Core/VideoCommon/ShaderGenCommon.h +++ b/Source/Core/VideoCommon/ShaderGenCommon.h @@ -279,7 +279,10 @@ static inline void GenerateVSOutputStruct(T& object, API_TYPE api_type) #define I_NORMALMATRICES "cnmtx" #define I_POSTTRANSFORMMATRICES "cpostmtx" #define I_PIXELCENTERCORRECTION "cpixelcenter" -#define I_STEREOPARAMS "cstereo" + +#define I_STEREOPARAMS "cstereo" +#define I_LINEPTPARAMS "clinept" +#define I_TEXOFFSET "ctexoffset" static const char s_shader_uniforms[] = "\tfloat4 " I_POSNORMALMATRIX"[6];\n" @@ -290,5 +293,4 @@ static const char s_shader_uniforms[] = "\tfloat4 " I_TRANSFORMMATRICES"[64];\n" "\tfloat4 " I_NORMALMATRICES"[32];\n" "\tfloat4 " I_POSTTRANSFORMMATRICES"[64];\n" - "\tfloat4 " I_PIXELCENTERCORRECTION";\n" - "\tfloat4 " I_STEREOPARAMS";\n"; + "\tfloat4 " I_PIXELCENTERCORRECTION";\n"; diff --git a/Source/Core/VideoCommon/VertexManagerBase.cpp b/Source/Core/VideoCommon/VertexManagerBase.cpp index 84e0bb5efe..b1bc049fe5 100644 --- a/Source/Core/VideoCommon/VertexManagerBase.cpp +++ b/Source/Core/VideoCommon/VertexManagerBase.cpp @@ -2,6 +2,7 @@ #include "VideoCommon/BPStructs.h" #include "VideoCommon/Debugger.h" +#include "VideoCommon/GeometryShaderManager.h" #include "VideoCommon/IndexGenerator.h" #include "VideoCommon/MainBase.h" #include "VideoCommon/NativeVertexFormat.h" diff --git a/Source/Core/VideoCommon/VertexShaderGen.cpp b/Source/Core/VideoCommon/VertexShaderGen.cpp index 00db2b0f02..123f137ff2 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/VertexShaderGen.cpp @@ -72,10 +72,11 @@ 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); } - uid_data->stereo = g_ActiveConfig.iStereoMode > 0; - if (g_ActiveConfig.iStereoMode > 0) + if (g_ActiveConfig.backend_info.bSupportsGeometryShaders) { - out.Write("centroid out VS_OUTPUT o;\n"); + out.Write("out VertexData {\n" + "\tcentroid VS_OUTPUT o;\n" + "};\n"); } else { @@ -87,7 +88,6 @@ static inline void GenerateVertexShader(T& out, u32 components, API_TYPE api_typ 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"); @@ -97,7 +97,7 @@ static inline void GenerateVertexShader(T& out, u32 components, API_TYPE api_typ out.Write("void main()\n{\n"); - if (g_ActiveConfig.iStereoMode <= 0) + if (!g_ActiveConfig.backend_info.bSupportsGeometryShaders) out.Write("VS_OUTPUT o;\n"); } else // D3D @@ -384,21 +384,15 @@ static inline void GenerateVertexShader(T& out, u32 components, API_TYPE api_typ if (api_type == API_OPENGL) { - if (g_ActiveConfig.iStereoMode <= 0) + if (!g_ActiveConfig.backend_info.bSupportsGeometryShaders) { - // 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 - + // TODO: Pass structs between shader stages even if geometry shaders + // are not supported, however that will break GL 3.0 and 3.1 support. 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"); - 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"); } diff --git a/Source/Core/VideoCommon/VertexShaderGen.h b/Source/Core/VideoCommon/VertexShaderGen.h index 1f08c1963a..b97f577061 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.h +++ b/Source/Core/VideoCommon/VertexShaderGen.h @@ -37,7 +37,7 @@ struct vertex_shader_uid_data u32 numColorChans : 2; u32 dualTexTrans_enabled : 1; u32 pixel_lighting : 1; - u32 stereo : 1; + u32 pad : 1; u32 texMtxInfo_n_projection : 16; // Stored separately to guarantee that the texMtxInfo struct is 8 bits wide struct { diff --git a/Source/Core/VideoCommon/VertexShaderManager.cpp b/Source/Core/VideoCommon/VertexShaderManager.cpp index 84cf2d2a01..542328e523 100644 --- a/Source/Core/VideoCommon/VertexShaderManager.cpp +++ b/Source/Core/VideoCommon/VertexShaderManager.cpp @@ -512,18 +512,6 @@ void VertexShaderManager::SetConstants() 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 237becb45e..65488aa4fa 100644 --- a/Source/Core/VideoCommon/VideoCommon.vcxproj +++ b/Source/Core/VideoCommon/VideoCommon.vcxproj @@ -61,6 +61,7 @@ + @@ -112,6 +113,7 @@ + diff --git a/Source/Core/VideoCommon/VideoCommon.vcxproj.filters b/Source/Core/VideoCommon/VideoCommon.vcxproj.filters index 971bf59bbf..cd4901f303 100644 --- a/Source/Core/VideoCommon/VideoCommon.vcxproj.filters +++ b/Source/Core/VideoCommon/VideoCommon.vcxproj.filters @@ -146,6 +146,9 @@ Shader Generators + + Shader Managers + @@ -284,6 +287,9 @@ Shader Generators + + Shader Managers + diff --git a/Source/Core/VideoCommon/VideoConfig.cpp b/Source/Core/VideoCommon/VideoConfig.cpp index 2b6025f13e..d0f02dd327 100644 --- a/Source/Core/VideoCommon/VideoConfig.cpp +++ b/Source/Core/VideoCommon/VideoConfig.cpp @@ -214,7 +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; + if (!backend_info.bSupportsGeometryShaders) iStereoMode = 0; } void VideoConfig::Save(const std::string& ini_file) diff --git a/Source/Core/VideoCommon/VideoConfig.h b/Source/Core/VideoCommon/VideoConfig.h index fa5a52772b..f27b1b2116 100644 --- a/Source/Core/VideoCommon/VideoConfig.h +++ b/Source/Core/VideoCommon/VideoConfig.h @@ -151,7 +151,7 @@ struct VideoConfig final bool bSupportsDualSourceBlend; bool bSupportsPrimitiveRestart; bool bSupportsOversizedViewports; - bool bSupportsStereoscopy; + bool bSupportsGeometryShaders; bool bSupports3DVision; bool bSupportsEarlyZ; // needed by PixelShaderGen, so must stay in VideoCommon bool bSupportsBindingLayout; // Needed by ShaderGen, so must stay in VideoCommon diff --git a/Source/Core/VideoCommon/VideoState.cpp b/Source/Core/VideoCommon/VideoState.cpp index a36a5d9d33..337bfd04a0 100644 --- a/Source/Core/VideoCommon/VideoState.cpp +++ b/Source/Core/VideoCommon/VideoState.cpp @@ -8,6 +8,7 @@ #include "VideoCommon/CommandProcessor.h" #include "VideoCommon/CPMemory.h" #include "VideoCommon/Fifo.h" +#include "VideoCommon/GeometryShaderManager.h" #include "VideoCommon/PixelEngine.h" #include "VideoCommon/PixelShaderManager.h" #include "VideoCommon/TextureDecoder.h" @@ -50,6 +51,9 @@ static void DoState(PointerWrap &p) VertexShaderManager::DoState(p); p.DoMarker("VertexShaderManager"); + GeometryShaderManager::DoState(p); + p.DoMarker("GeometryShaderManager"); + VertexManager::DoState(p); p.DoMarker("VertexManager"); diff --git a/Source/Core/VideoCommon/XFStructs.cpp b/Source/Core/VideoCommon/XFStructs.cpp index 927fed8077..34820af640 100644 --- a/Source/Core/VideoCommon/XFStructs.cpp +++ b/Source/Core/VideoCommon/XFStructs.cpp @@ -7,6 +7,7 @@ #include "VideoCommon/CPMemory.h" #include "VideoCommon/DataReader.h" #include "VideoCommon/Fifo.h" +#include "VideoCommon/GeometryShaderManager.h" #include "VideoCommon/PixelShaderManager.h" #include "VideoCommon/VertexManagerBase.h" #include "VideoCommon/VertexShaderManager.h" @@ -110,6 +111,7 @@ static void XFRegWritten(int transferSize, u32 baseAddress, DataReader src) VertexManager::Flush(); VertexShaderManager::SetViewportChanged(); PixelShaderManager::SetViewportChanged(); + GeometryShaderManager::SetViewportChanged(); nextAddress = XFMEM_SETVIEWPORT + 6; break; @@ -123,6 +125,7 @@ static void XFRegWritten(int transferSize, u32 baseAddress, DataReader src) case XFMEM_SETPROJECTION+6: VertexManager::Flush(); VertexShaderManager::SetProjectionChanged(); + GeometryShaderManager::SetProjectionChanged(); nextAddress = XFMEM_SETPROJECTION + 7; break;