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;